From 8a6dd4c5e89282b2dad2ad6f64395bbed73ff41d Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Mon, 21 Aug 2023 12:48:46 +0200 Subject: [PATCH 01/96] RED-7375: integrate table extractor --- .../configuration/MessagingConfiguration.java | 26 +++++++++ .../model/TableExtractorRequest.java | 23 ++++++++ .../model/TableExtractorResponse.java | 17 ++++++ .../processor/service/FileStatusService.java | 25 +++++++++ .../queue/TableExtractorMessageReceiver.java | 55 +++++++++++++++++++ .../FileManagementServiceSettings.java | 1 + .../src/main/resources/application-dev.yaml | 1 + .../dossier/file/FileType.java | 1 + .../dossier/file/ProcessingStatus.java | 3 +- 9 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/TableExtractorRequest.java create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/TableExtractorResponse.java create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/TableExtractorMessageReceiver.java diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/configuration/MessagingConfiguration.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/configuration/MessagingConfiguration.java index 2d6bc486e..190cc4ba7 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/configuration/MessagingConfiguration.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/configuration/MessagingConfiguration.java @@ -59,6 +59,10 @@ public class MessagingConfiguration { public static final String CV_ANALYSIS_RESPONSE_QUEUE = "cv_analysis_response_queue"; public static final String CV_ANALYSIS_DLQ = "cv_analysis_dead_letter_queue"; + public static final String TABLE_EXTRACTOR_QUEUE = "table_extractor_request_queue"; + public static final String TABLE_EXTRACTOR_RESPONSE_QUEUE = "table_extractor_response_queue"; + public static final String TABLE_EXTRACTOR_DLQ = "table_extractor_dead_letter_queue"; + public static final String OCR_STATUS_UPDATE_RESPONSE_QUEUE = "ocr_status_update_response_queue"; public static final String OCR_STATUS_UPDATE_RESPONSE_DQL = "ocr_status_update_response_dql"; @@ -338,4 +342,26 @@ public class MessagingConfiguration { return QueueBuilder.durable(LAYOUT_PARSING_DLQ).build(); } + + @Bean + public Queue tableExtractorRequestQueue() { + + return QueueBuilder.durable(TABLE_EXTRACTOR_QUEUE)// + .withArgument("x-dead-letter-exchange", "").withArgument("x-dead-letter-routing-key", LAYOUT_PARSING_DLQ).build(); + } + + + @Bean + public Queue tableExtractorResponseQueue() { + + return QueueBuilder.durable(TABLE_EXTRACTOR_RESPONSE_QUEUE)// + .withArgument("x-dead-letter-exchange", "").withArgument("x-dead-letter-routing-key", LAYOUT_PARSING_DLQ).build(); + } + + + @Bean + public Queue tableExtractorDLQ() { + + return QueueBuilder.durable(TABLE_EXTRACTOR_DLQ).build(); + } } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/TableExtractorRequest.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/TableExtractorRequest.java new file mode 100644 index 000000000..e5c14617e --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/TableExtractorRequest.java @@ -0,0 +1,23 @@ +package com.iqser.red.service.persistence.management.v1.processor.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class TableExtractorRequest { + + public static final String TABLE_EXTRACTOR_FILE_EXTENSION = "EXTRACTED_TABLES.json.gz"; + + public static final String TARGET_FILE_EXTENSION = "ORIGIN.pdf.gz"; + + private String dossierId; + private String fileId; + private String targetFileExtension; + private String responseFileExtension; + +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/TableExtractorResponse.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/TableExtractorResponse.java new file mode 100644 index 000000000..ffec256d7 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/TableExtractorResponse.java @@ -0,0 +1,17 @@ +package com.iqser.red.service.persistence.management.v1.processor.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class TableExtractorResponse { + + private String dossierId; + private String fileId; + +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java index 24912b848..76ffbfacb 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java @@ -21,6 +21,7 @@ import com.iqser.red.service.persistence.management.v1.processor.exception.Inter import com.iqser.red.service.persistence.management.v1.processor.model.CvAnalysisServiceRequest; import com.iqser.red.service.persistence.management.v1.processor.model.NerServiceRequest; import com.iqser.red.service.persistence.management.v1.processor.model.OCRStatusUpdateResponse; +import com.iqser.red.service.persistence.management.v1.processor.model.TableExtractorRequest; import com.iqser.red.service.persistence.management.v1.processor.model.image.ImageServiceRequest; import com.iqser.red.service.persistence.management.v1.processor.service.layoutparsing.LayoutParsingRequestFactory; import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionProviderService; @@ -175,6 +176,12 @@ public class FileStatusService { return; } + if (settings.isTableExtractorEnabled() && !fileManagementStorageService.objectExists(dossierId, fileId, FileType.INVISIBLE_TABLES)) { + log.info("Add file: {} from dossier {} to Table Extractor queue", fileId, dossierId); + addToTableExtractorQueue(dossierId, fileId); + return; + } + var fileModel = MagicConverter.convert(fileEntity, FileModel.class, new FileModelMapper()); fileModel = reanalysisRequiredStatusService.enhanceFileStatusWithAnalysisRequirements(fileModel, true); @@ -230,6 +237,24 @@ public class FileStatusService { } + private void addToTableExtractorQueue(String dossierId, String fileId) { + + fileStatusPersistenceService.updateProcessingStatus(fileId, ProcessingStatus.TABLE_EXTRACTOR_ANALYZING); + + rabbitTemplate.convertAndSend(MessagingConfiguration.TABLE_EXTRACTOR_QUEUE, + TableExtractorRequest.builder() + .dossierId(dossierId) + .fileId(fileId) + .targetFileExtension(TableExtractorRequest.TARGET_FILE_EXTENSION) + .responseFileExtension(TableExtractorRequest.TABLE_EXTRACTOR_FILE_EXTENSION) + .build(), + message -> { + message.getMessageProperties().setPriority(1); + return message; + }); + } + + @SneakyThrows public void addToPreprocessingQueue(String dossierId, String fileId, String filename) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/TableExtractorMessageReceiver.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/TableExtractorMessageReceiver.java new file mode 100644 index 000000000..b53ee3a19 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/TableExtractorMessageReceiver.java @@ -0,0 +1,55 @@ +package com.iqser.red.service.persistence.management.v1.processor.service.queue; + +import java.time.OffsetDateTime; +import java.time.temporal.ChronoUnit; + +import org.springframework.amqp.core.Message; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.stereotype.Service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration; +import com.iqser.red.service.persistence.management.v1.processor.model.CvAnalysisServiceResponse; +import com.iqser.red.service.persistence.management.v1.processor.model.TableExtractorResponse; +import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusProcessingUpdateService; +import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileErrorInfo; + +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +@RequiredArgsConstructor +public class TableExtractorMessageReceiver { + + private final ObjectMapper objectMapper; + private final FileStatusService fileStatusService; + private final FileStatusProcessingUpdateService fileStatusProcessingUpdateService; + + + @SneakyThrows + @RabbitListener(queues = MessagingConfiguration.TABLE_EXTRACTOR_RESPONSE_QUEUE) + public void receive(TableExtractorResponse response) { + + fileStatusService.setStatusAnalyse(response.getDossierId(), response.getFileId(), false); + + log.info("Received message in {} for dossierId {} and fileId {}", MessagingConfiguration.TABLE_EXTRACTOR_RESPONSE_QUEUE, response.getDossierId(), response.getFileId()); + } + + + @SneakyThrows + @RabbitListener(queues = MessagingConfiguration.TABLE_EXTRACTOR_DLQ) + public void handleDLQMessage(Message failedMessage) { + + var response = objectMapper.readValue(failedMessage.getBody(), TableExtractorResponse.class); + + log.warn("Received message from {} for dossierId {} and fileId {}", MessagingConfiguration.TABLE_EXTRACTOR_DLQ, response.getDossierId(), response.getFileId()); + fileStatusProcessingUpdateService.analysisFailed(response.getDossierId(), + response.getFileId(), + new FileErrorInfo("table extractor failed", MessagingConfiguration.TABLE_EXTRACTOR_DLQ, "table-extractor", OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS))); + + } + +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/settings/FileManagementServiceSettings.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/settings/FileManagementServiceSettings.java index 452013c4b..8d942f617 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/settings/FileManagementServiceSettings.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/settings/FileManagementServiceSettings.java @@ -24,6 +24,7 @@ public class FileManagementServiceSettings { private boolean imageServiceEnabled = true; private boolean nerServiceEnabled = true; + private boolean tableExtractorEnabled = true; private boolean storeImageFile = true; diff --git a/persistence-service-v1/persistence-service-server-v1/src/main/resources/application-dev.yaml b/persistence-service-v1/persistence-service-server-v1/src/main/resources/application-dev.yaml index c49a6fac7..bf4fa88f8 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/main/resources/application-dev.yaml +++ b/persistence-service-v1/persistence-service-server-v1/src/main/resources/application-dev.yaml @@ -30,6 +30,7 @@ cors.enabled: true persistence-service: imageServiceEnabled: false nerServiceEnabled: false + tableExtractorEnabled: false storeImageFile: false applicationName: RedactManager fforesight: diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/FileType.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/FileType.java index 8008340ee..afcf7fde9 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/FileType.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/FileType.java @@ -17,6 +17,7 @@ public enum FileType { TEXT_HIGHLIGHTS(".json"), FIGURE(".json"), TABLES(".json"), + INVISIBLE_TABLES(".json"), COMPONENTS(".json"), // document is split into 4 files, all should be overridden/deleted at the same time DOCUMENT_TEXT(".json"), diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/ProcessingStatus.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/ProcessingStatus.java index f65ceabe1..1a158927a 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/ProcessingStatus.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/ProcessingStatus.java @@ -18,5 +18,6 @@ public enum ProcessingStatus { PRE_PROCESSING, PRE_PROCESSED, FIGURE_DETECTION_ANALYZING, - TABLE_PARSING_ANALYZING + TABLE_PARSING_ANALYZING, + TABLE_EXTRACTOR_ANALYZING, } -- 2.47.2 From a76704e0b56890e1a58f17c4f8ba7d810c59be30 Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Mon, 21 Aug 2023 13:24:24 +0200 Subject: [PATCH 02/96] RED-7375: fix tests --- .../src/test/resources/application.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/resources/application.yaml b/persistence-service-v1/persistence-service-server-v1/src/test/resources/application.yaml index c85f2c996..06807fcb7 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/resources/application.yaml +++ b/persistence-service-v1/persistence-service-server-v1/src/test/resources/application.yaml @@ -58,6 +58,7 @@ server: persistence-service: imageServiceEnabled: false + tableExtractorEnabled: false metrics: -- 2.47.2 From 49bcc43716240ec38788fac01c0fa93af5813e12 Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Thu, 31 Aug 2023 17:25:49 +0200 Subject: [PATCH 03/96] RED-7375: integrate table extractor * bind the correct DLQ --- .../configuration/MessagingConfiguration.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/configuration/MessagingConfiguration.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/configuration/MessagingConfiguration.java index 190cc4ba7..65880198a 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/configuration/MessagingConfiguration.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/configuration/MessagingConfiguration.java @@ -69,6 +69,7 @@ public class MessagingConfiguration { public static final String X_ERROR_INFO_HEADER = "x-error-message"; public static final String X_ERROR_INFO_TIMESTAMP_HEADER = "x-error-message-timestamp"; + @Bean public Queue nerRequestQueue() { @@ -321,19 +322,21 @@ public class MessagingConfiguration { .build(); } + @Bean public Queue layoutparsingRequestQueue() { - return QueueBuilder.durable(LAYOUT_PARSING_REQUEST_QUEUE)// - .withArgument("x-dead-letter-exchange", "").withArgument("x-dead-letter-routing-key", LAYOUT_PARSING_DLQ).build(); + return QueueBuilder.durable(LAYOUT_PARSING_REQUEST_QUEUE).withArgument("x-dead-letter-exchange", "").withArgument("x-dead-letter-routing-key", LAYOUT_PARSING_DLQ).build(); } @Bean public Queue layoutparsingResponseQueue() { - return QueueBuilder.durable(LAYOUT_PARSING_FINISHED_EVENT_QUEUE)// - .withArgument("x-dead-letter-exchange", "").withArgument("x-dead-letter-routing-key", LAYOUT_PARSING_DLQ).build(); + return QueueBuilder.durable(LAYOUT_PARSING_FINISHED_EVENT_QUEUE) + .withArgument("x-dead-letter-exchange", "") + .withArgument("x-dead-letter-routing-key", LAYOUT_PARSING_DLQ) + .build(); } @@ -343,19 +346,21 @@ public class MessagingConfiguration { return QueueBuilder.durable(LAYOUT_PARSING_DLQ).build(); } + @Bean public Queue tableExtractorRequestQueue() { - return QueueBuilder.durable(TABLE_EXTRACTOR_QUEUE)// - .withArgument("x-dead-letter-exchange", "").withArgument("x-dead-letter-routing-key", LAYOUT_PARSING_DLQ).build(); + return QueueBuilder.durable(TABLE_EXTRACTOR_QUEUE).withArgument("x-dead-letter-exchange", "").withArgument("x-dead-letter-routing-key", TABLE_EXTRACTOR_DLQ).build(); } @Bean public Queue tableExtractorResponseQueue() { - return QueueBuilder.durable(TABLE_EXTRACTOR_RESPONSE_QUEUE)// - .withArgument("x-dead-letter-exchange", "").withArgument("x-dead-letter-routing-key", LAYOUT_PARSING_DLQ).build(); + return QueueBuilder.durable(TABLE_EXTRACTOR_RESPONSE_QUEUE) + .withArgument("x-dead-letter-exchange", "") + .withArgument("x-dead-letter-routing-key", TABLE_EXTRACTOR_DLQ) + .build(); } @@ -364,4 +369,5 @@ public class MessagingConfiguration { return QueueBuilder.durable(TABLE_EXTRACTOR_DLQ).build(); } + } -- 2.47.2 From 74ac3c0c34d9aef417770b5a5e57f6b519dda0ed Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Wed, 6 Sep 2023 14:20:38 +0200 Subject: [PATCH 04/96] RED-7375: integrate Table Extractor * fix filenames --- .../management/v1/processor/model/TableExtractorRequest.java | 4 +++- .../management/v1/processor/service/FileStatusService.java | 2 +- .../shared/model/dossiertemplate/dossier/file/FileType.java | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/TableExtractorRequest.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/TableExtractorRequest.java index e5c14617e..6ec502b84 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/TableExtractorRequest.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/TableExtractorRequest.java @@ -1,5 +1,7 @@ package com.iqser.red.service.persistence.management.v1.processor.model; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType; + import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -11,7 +13,7 @@ import lombok.NoArgsConstructor; @NoArgsConstructor public class TableExtractorRequest { - public static final String TABLE_EXTRACTOR_FILE_EXTENSION = "EXTRACTED_TABLES.json.gz"; + public static final String TABLE_EXTRACTOR_FILE_EXTENSION = FileType.EXTRACTED_TABLES.name() + FileType.EXTRACTED_TABLES.getExtension() + ".gz"; public static final String TARGET_FILE_EXTENSION = "ORIGIN.pdf.gz"; diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java index 76ffbfacb..ef9854c23 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java @@ -176,7 +176,7 @@ public class FileStatusService { return; } - if (settings.isTableExtractorEnabled() && !fileManagementStorageService.objectExists(dossierId, fileId, FileType.INVISIBLE_TABLES)) { + if (settings.isTableExtractorEnabled() && !fileManagementStorageService.objectExists(dossierId, fileId, FileType.EXTRACTED_TABLES)) { log.info("Add file: {} from dossier {} to Table Extractor queue", fileId, dossierId); addToTableExtractorQueue(dossierId, fileId); return; diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/FileType.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/FileType.java index afcf7fde9..cea316b90 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/FileType.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/FileType.java @@ -17,7 +17,7 @@ public enum FileType { TEXT_HIGHLIGHTS(".json"), FIGURE(".json"), TABLES(".json"), - INVISIBLE_TABLES(".json"), + EXTRACTED_TABLES(".json"), COMPONENTS(".json"), // document is split into 4 files, all should be overridden/deleted at the same time DOCUMENT_TEXT(".json"), -- 2.47.2 From 0b44b5abe7e2c49f4b2d68c8b7a6edbac7ee98c0 Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Fri, 13 Oct 2023 10:41:44 +0200 Subject: [PATCH 05/96] DM-285: add fileName to component endpoint --- .../api/impl/controller/ComponentControllerV2.java | 13 +++++++++---- .../v1/processor/service/FileStatusService.java | 6 ++++++ .../persistence/FileStatusPersistenceService.java | 6 ++++++ .../persistence/repository/FileRepository.java | 5 +++++ 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/ComponentControllerV2.java b/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/ComponentControllerV2.java index e2cac3548..39705d9ab 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/ComponentControllerV2.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/ComponentControllerV2.java @@ -16,6 +16,7 @@ import org.springframework.web.bind.annotation.RestController; import com.iqser.red.persistence.service.v1.external.api.impl.controller.DossierTemplateController; import com.iqser.red.persistence.service.v1.external.api.impl.controller.StatusController; import com.iqser.red.service.persistence.management.v1.processor.service.ComponentLogService; +import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntityReference; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntry; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLogEntryValue; @@ -27,16 +28,20 @@ import com.iqser.red.service.persistence.service.v2.api.external.model.FileCompo import com.iqser.red.service.persistence.service.v2.api.external.resource.ComponentResource; import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.AccessLevel; import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; @RestController @RequiredArgsConstructor @Tag(name = "4. Component endpoints", description = "Provides operations related to components") +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) public class ComponentControllerV2 implements ComponentResource { - private final DossierTemplateController dossierTemplateController; - private final ComponentLogService componentLogService; - private final StatusController statusController; + DossierTemplateController dossierTemplateController; + ComponentLogService componentLogService; + StatusController statusController; + FileStatusService fileStatusService; @Override @@ -46,7 +51,6 @@ public class ComponentControllerV2 implements ComponentResource { @RequestParam(name = INCLUDE_DETAILS_PARAM, defaultValue = "false", required = false) boolean includeDetails) { dossierTemplateController.getDossierTemplate(dossierTemplateId); - var componentLog = componentLogService.getComponentLog(dossierId, fileId, true); Map> basicComponent = componentLog.getComponentLogEntries() @@ -65,6 +69,7 @@ public class ComponentControllerV2 implements ComponentResource { return FileComponents.builder() .dossierTemplateId(dossierTemplateId) .dossierId(dossierId) + .filename(fileStatusService.getFileName(fileId)) .fileId(fileId) .components(basicComponent) .componentDetails(componentsDetails) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java index 24912b848..b6000cf79 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java @@ -741,4 +741,10 @@ public class FileStatusService { fileStatusPersistenceService.updateOCRStatus(response); } + + public String getFileName(String fileId) { + + return fileStatusPersistenceService.getFileNameById(fileId); + } + } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/FileStatusPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/FileStatusPersistenceService.java index 29eba3d47..57b171718 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/FileStatusPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/FileStatusPersistenceService.java @@ -554,4 +554,10 @@ public class FileStatusPersistenceService { fileRepository.updateLayoutProcessedTime(fileId, OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS)); } + + public String getFileNameById(String fileId) { + + return fileRepository.getFileNameById(fileId).orElseThrow(); + } + } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/FileRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/FileRepository.java index f01701af4..eca7e099c 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/FileRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/FileRepository.java @@ -2,6 +2,7 @@ package com.iqser.red.service.persistence.management.v1.processor.service.persis import java.time.OffsetDateTime; import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; @@ -225,6 +226,10 @@ public interface FileRepository extends JpaRepository { @Query(value = "update FileEntity f set f.lastLayoutProcessed = :offsetDateTime where f.id = :fileId") void updateLayoutProcessedTime(String fileId, OffsetDateTime offsetDateTime); + + @Query("select f.filename from FileEntity f where f.id = :fileId") + Optional getFileNameById(String fileId); + } -- 2.47.2 From 4ae0a7e646f5c194efcf595b4a24524109fa0b80 Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Fri, 13 Oct 2023 11:01:10 +0200 Subject: [PATCH 06/96] DM-285: add fileName to component endpoint --- .../v1/processor/service/FileStatusService.java | 2 +- .../FileStatusPersistenceService.java | 4 ++-- .../persistence/repository/FileRepository.java | 2 +- .../v1/server/integration/tests/FileTest.java | 16 ++++++++++++++++ 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java index b6000cf79..55d2cde68 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java @@ -744,7 +744,7 @@ public class FileStatusService { public String getFileName(String fileId) { - return fileStatusPersistenceService.getFileNameById(fileId); + return fileStatusPersistenceService.getFilenameById(fileId); } } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/FileStatusPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/FileStatusPersistenceService.java index 57b171718..776ad6289 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/FileStatusPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/FileStatusPersistenceService.java @@ -555,9 +555,9 @@ public class FileStatusPersistenceService { } - public String getFileNameById(String fileId) { + public String getFilenameById(String fileId) { - return fileRepository.getFileNameById(fileId).orElseThrow(); + return fileRepository.getFilenameById(fileId).orElseThrow(); } } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/FileRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/FileRepository.java index eca7e099c..7916254b3 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/FileRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/FileRepository.java @@ -228,7 +228,7 @@ public interface FileRepository extends JpaRepository { @Query("select f.filename from FileEntity f where f.id = :fileId") - Optional getFileNameById(String fileId); + Optional getFilenameById(String fileId); } diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java index 3a35e3652..0ba5e750a 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java @@ -38,6 +38,7 @@ import com.iqser.red.service.peristence.v1.server.integration.service.TypeProvid import com.iqser.red.service.peristence.v1.server.integration.service.UserProvider; import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest; import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; +import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService; import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierTemplateModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.FileAttributes; import com.iqser.red.service.persistence.service.v1.api.shared.model.FileAttributesConfig; @@ -118,6 +119,9 @@ public class FileTest extends AbstractPersistenceServerServiceTest { @Autowired private FileManagementStorageService fileManagementStorageService; + @Autowired + private FileStatusService fileStatusService; + @Test public void testFileSoftDeleteReupload() { @@ -612,4 +616,16 @@ public class FileTest extends AbstractPersistenceServerServiceTest { assertThat(file.getProcessingStatus()).isEqualTo(ProcessingStatus.OCR_PROCESSING_QUEUED); } + + @Test + public void testGetFileNameQuery() { + + var filename = "test"; + var dossier = dossierTesterAndProvider.provideTestDossier(); + + var file = fileTesterAndProvider.testAndProvideFile(dossier, filename); + + assertThat(fileStatusService.getFileName(file.getId())).isEqualTo(filename + ".pdf"); + } + } -- 2.47.2 From 80af534ce67dbb7dd11ce966ff154da55c70f3a5 Mon Sep 17 00:00:00 2001 From: Andrei Isvoran Date: Mon, 16 Oct 2023 09:41:15 +0200 Subject: [PATCH 07/96] RED-7745 - Add EntityLog Feign Client --- .../internal/resources/EntityLogResource.java | 36 +++++++++++++++++++ .../integration/client/EntityLogClient.java | 10 ++++++ 2 files changed, 46 insertions(+) create mode 100644 persistence-service-v1/persistence-service-internal-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/internal/resources/EntityLogResource.java create mode 100644 persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/client/EntityLogClient.java diff --git a/persistence-service-v1/persistence-service-internal-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/internal/resources/EntityLogResource.java b/persistence-service-v1/persistence-service-internal-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/internal/resources/EntityLogResource.java new file mode 100644 index 000000000..95cd6c908 --- /dev/null +++ b/persistence-service-v1/persistence-service-internal-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/internal/resources/EntityLogResource.java @@ -0,0 +1,36 @@ +package com.iqser.red.service.persistence.service.v1.api.internal.resources; + +import java.util.List; + +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; + +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; + +@ResponseStatus(value = HttpStatus.OK) +public interface EntityLogResource { + + String ENTITY_LOG_PATH = "/entityLog"; + + String FILE_ID = "fileId"; + String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID + "}"; + + String DOSSIER_ID = "dossierId"; + String DOSSIER_ID_PATH_VARIABLE = "/{" + DOSSIER_ID + "}"; + + + @GetMapping(value = ENTITY_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "Gets the entity log for a fileId", description = "None") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The entity log is not found.")}) + EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId, + @PathVariable(FILE_ID) String fileId, + @RequestParam(value = "excludedType", required = false) List excludedTypes); +} diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/client/EntityLogClient.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/client/EntityLogClient.java new file mode 100644 index 000000000..daa7d305d --- /dev/null +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/client/EntityLogClient.java @@ -0,0 +1,10 @@ +package com.iqser.red.service.peristence.v1.server.integration.client; + +import org.springframework.cloud.openfeign.FeignClient; + +import com.iqser.red.service.persistence.service.v1.api.external.resource.EntityLogResource; + +@FeignClient(name = "EntityLogClient", url = "http://localhost:${server.port}") +public interface EntityLogClient extends EntityLogResource { + +} -- 2.47.2 From 6f87c0bcec4e0733c9fc9be452b13892fa3fe718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominique=20Eifl=C3=A4nder?= Date: Tue, 10 Oct 2023 13:21:02 +0200 Subject: [PATCH 08/96] RED-7682: Fixed Joining of parallel processed redaction of files when service is scaled to more than 1 --- .../DownloadRedactionFileStatusEntity.java | 40 ++++++ .../jobs/CreateJobsConfiguration.java | 35 ++++- .../download/DownloadPreparationService.java | 126 ++++++++---------- .../download/RedactionDlqMessageReceiver.java | 70 +++++----- .../RedactionResultMessageReceiver.java | 14 +- .../service/job/DownloadReadyJob.java | 54 ++++++++ ...DownloadRedactionFileStatusRepository.java | 25 ++++ .../FileManagementServiceSettings.java | 1 + ...DownloadRedactionFileDetailsConverter.java | 40 ++++++ .../db/changelog/db.changelog-tenant.yaml | 4 +- ...-download-redaction-file-status-table.yaml | 28 ++++ ...26-application-config-table.changelog.yaml | 2 +- .../src/main/resources/log4j2.xml | 6 +- .../tests/DownloadPreparationTest.java | 26 +++- .../integration/tests/DownloadTest.java | 24 +++- .../AbstractPersistenceServerServiceTest.java | 2 +- 16 files changed, 373 insertions(+), 124 deletions(-) create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/download/DownloadRedactionFileStatusEntity.java create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/job/DownloadReadyJob.java create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DownloadRedactionFileStatusRepository.java create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/utils/JSONDownloadRedactionFileDetailsConverter.java create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/114-add-download-redaction-file-status-table.yaml diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/download/DownloadRedactionFileStatusEntity.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/download/DownloadRedactionFileStatusEntity.java new file mode 100644 index 000000000..26370e75c --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/download/DownloadRedactionFileStatusEntity.java @@ -0,0 +1,40 @@ +package com.iqser.red.service.persistence.management.v1.processor.entity.download; + +import com.iqser.red.service.pdftron.redaction.v1.api.model.RedactionResultDetail; +import com.iqser.red.service.persistence.management.v1.processor.utils.JSONDownloadRedactionFileDetailsConverter; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@Data +@Entity +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Table(name = "download_redaction_file_status") +public class DownloadRedactionFileStatusEntity { + + @Id + private String id; + + @Column + private String downloadStorageId; + + @Column + private String fileId; + + @Column + private Integer processingErrorCounter; + + @Builder.Default + @Column(columnDefinition = "text", name = "details") + @Convert(converter = JSONDownloadRedactionFileDetailsConverter.class) + private List details = new ArrayList<>(); + + +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/jobs/CreateJobsConfiguration.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/jobs/CreateJobsConfiguration.java index 6c38fea47..7bb35375e 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/jobs/CreateJobsConfiguration.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/jobs/CreateJobsConfiguration.java @@ -2,6 +2,7 @@ package com.iqser.red.service.persistence.management.v1.processor.jobs; import java.text.ParseException; +import com.iqser.red.service.persistence.management.v1.processor.service.job.*; import org.quartz.CronExpression; import org.quartz.CronScheduleBuilder; import org.quartz.JobBuilder; @@ -11,13 +12,6 @@ import org.quartz.TriggerBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import com.iqser.red.service.persistence.management.v1.processor.service.job.AutomaticAnalysisJob; -import com.iqser.red.service.persistence.management.v1.processor.service.job.DeletedFilesCleanupJob; -import com.iqser.red.service.persistence.management.v1.processor.service.job.DownloadCleanupJob; -import com.iqser.red.service.persistence.management.v1.processor.service.job.KeyCloakUserSyncJob; -import com.iqser.red.service.persistence.management.v1.processor.service.job.SendNotificationEmailJob; -import com.iqser.red.service.persistence.management.v1.processor.service.job.SyncUserPermissionsJob; - @Configuration public class CreateJobsConfiguration { @@ -164,4 +158,31 @@ public class CreateJobsConfiguration { .build(); } + + + @Bean + public Trigger downloadReadyJobTrigger() throws ParseException { + + return TriggerBuilder.newTrigger() + .forJob(downloadReadyJobDetail()) + .withIdentity("DownloadReadyJobTrigger") + .withDescription("Triggers DownloadReadyJob every 10 seconds") + .withSchedule(CronScheduleBuilder.cronSchedule(new CronExpression("*/10 * * * * ?"))) + .build(); + } + + + @Bean + public JobDetail downloadReadyJobDetail() { + + return JobBuilder.newJob() + .ofType(DownloadReadyJob.class) + .storeDurably() + .withIdentity("DownloadReadyJob") + .withDescription("Builds the download package if all parallel processed files are ready") + .build(); + } + + + } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/DownloadPreparationService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/DownloadPreparationService.java index 59e2d9e6d..65e583478 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/DownloadPreparationService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/DownloadPreparationService.java @@ -1,17 +1,5 @@ package com.iqser.red.service.persistence.management.v1.processor.service.download; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -import org.springframework.amqp.rabbit.core.RabbitTemplate; -import org.springframework.stereotype.Service; - import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.iqser.red.service.pdftron.redaction.v1.api.model.RedactionMessage; @@ -23,14 +11,15 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.dossier. import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierTemplateEntity; import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.FileEntity; import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.ReportTemplateEntity; +import com.iqser.red.service.persistence.management.v1.processor.entity.download.DownloadRedactionFileStatusEntity; import com.iqser.red.service.persistence.management.v1.processor.entity.download.DownloadStatusEntity; -import com.iqser.red.service.persistence.management.v1.processor.model.RedactionFileResult; import com.iqser.red.service.persistence.management.v1.processor.service.ColorsService; import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierTemplatePersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DownloadStatusPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.NotificationPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.ReportTemplatePersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DownloadRedactionFileStatusRepository; import com.iqser.red.service.persistence.management.v1.processor.settings.FileManagementServiceSettings; import com.iqser.red.service.persistence.management.v1.processor.utils.FileSystemBackedArchiver; import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AddNotificationRequest; @@ -41,20 +30,25 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.download.Do import com.iqser.red.service.redaction.report.v1.api.model.ReportResultMessage; import com.iqser.red.service.redaction.report.v1.api.model.StoredFileInformation; import com.knecon.fforesight.tenantcommons.TenantContext; - import jakarta.transaction.Transactional; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; @Slf4j @Service @RequiredArgsConstructor @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class DownloadPreparationService { - static int MAX_RETRY = 2; + DownloadStatusPersistenceService downloadStatusPersistenceService; FileManagementStorageService fileManagementStorageService; ReportTemplatePersistenceService reportTemplatePersistenceService; @@ -65,7 +59,7 @@ public class DownloadPreparationService { ColorsService colorsService; FileManagementServiceSettings settings; DossierTemplatePersistenceService dossierTemplatePersistenceService; - Map> redactionFileResultsMap; + DownloadRedactionFileStatusRepository downloadRedactionFileStatusRepository; @Transactional @@ -75,11 +69,9 @@ public class DownloadPreparationService { var downloadStatus = downloadStatusPersistenceService.getStatus(downloadId); RedactionMessage.RedactionMessageBuilder messageBuilder = this.generateGeneralRedactionMessage(downloadId, downloadStatus); - redactionFileResultsMap.put(downloadId, new ArrayList<>()); downloadStatus.getFiles().forEach(fileEntity -> { RedactionMessage message = messageBuilder.fileId(fileEntity.getId()).unapprovedFile(fileEntity.getWorkflowStatus() != WorkflowStatus.APPROVED).build(); - redactionFileResultsMap.get(downloadId).add(RedactionFileResult.builder().fileId(fileEntity.getId()).processed(false).retryCounter(0).build()); log.info("Sending redaction request for downloadId:{} fileId:{} to pdftron-redaction-queue", downloadId, fileEntity.getId()); rabbitTemplate.convertAndSend(MessagingConfiguration.PDFTRON_QUEUE, message); }); @@ -138,54 +130,53 @@ public class DownloadPreparationService { return result; } - public void processingRedactionResultMessage(RedactionResultMessage redactionResultMessage) { + @Transactional + public void markFileAsProcessed(RedactionResultMessage redactionResultMessage) { - String downloadId = redactionResultMessage.getDownloadId(); - List redactionFileResults = redactionFileResultsMap.get(downloadId); - if (redactionFileResults == null) { - log.info("The creation of download has finished for downloadId: {} ", downloadId); - return; - } - long totalFiles = downloadStatusPersistenceService.getStatus(downloadId).getFiles().size(); - Optional resultOptional = redactionFileResults.stream().filter(r -> r.getFileId().equals(redactionResultMessage.getFileId())).findFirst(); - resultOptional.ifPresent(redactionFileResult -> { - redactionFileResult.setRedactionResultDetailList(redactionResultMessage.getRedactionResultDetails()); - redactionFileResult.setProcessed(true); - }); - - var processedFilesCount = redactionFileResults.stream().filter(RedactionFileResult::isProcessed).count(); - log.info("Processed {} files out of total {} files for download {}", processedFilesCount, totalFiles, downloadId); - - if (processedFilesCount == totalFiles) { - createDownload(redactionFileResults, downloadId); - } + downloadRedactionFileStatusRepository.save(DownloadRedactionFileStatusEntity.builder() + .id(UUID.randomUUID().toString()) + .downloadStorageId(redactionResultMessage.getDownloadId()) + .fileId(redactionResultMessage.getFileId()) + .processingErrorCounter(0) + .details(redactionResultMessage.getRedactionResultDetails()) + .build()); } - public void checkForRetryProcess(String downloadId, String fileId, boolean unapprovedFile) { - List redactionFileResults = redactionFileResultsMap.get(downloadId); - if (redactionFileResults == null) { - log.info("The creation of download has finished for downloadId: {} ", downloadId); - return; - } - Optional resultOptional = redactionFileResults.stream().filter(r -> r.getFileId().equals(fileId)).findFirst(); - if (resultOptional.isPresent()) { - RedactionFileResult result = resultOptional.get(); - if (result.getRetryCounter() >= MAX_RETRY) { // update download status - log.info("Failed download after max retries: {} for downloadId: {}, set the download status to FAILED", result.getRetryCounter(), downloadId); - downloadStatusPersistenceService.updateStatus(downloadId, DownloadStatusValue.FAILED); - } else { // retry to send it again - result.increaseRetryCounter(); - var downloadStatus = downloadStatusPersistenceService.getStatus(downloadId); - RedactionMessage.RedactionMessageBuilder messageBuilder = this.generateGeneralRedactionMessage(downloadId, downloadStatus); - RedactionMessage message = messageBuilder.fileId(fileId).unapprovedFile(unapprovedFile).build(); - log.info("Resending redaction request for downloadId:{} fileId: {} to {}", downloadId, fileId, MessagingConfiguration.PDFTRON_QUEUE); - rabbitTemplate.convertAndSend(MessagingConfiguration.PDFTRON_QUEUE, message); - } - } + @Transactional + public void markFileAsProcessingError(RedactionMessage redactionMessage) { + + downloadRedactionFileStatusRepository.save(DownloadRedactionFileStatusEntity.builder() + .id(UUID.randomUUID().toString()) + .downloadStorageId(redactionMessage.getDownloadId()) + .fileId(redactionMessage.getFileId()) + .processingErrorCounter(1) + .build()); } - public void createDownload(List redactionFileResults, String downloadId) { + + @Transactional + public void increaseProcessingErrorCounter(RedactionMessage redactionMessage, Integer numberOfErrors) { + + downloadRedactionFileStatusRepository.updateStatusErrorInfo(redactionMessage.getDownloadId(), redactionMessage.getFileId(), numberOfErrors); + } + + + @Transactional + public Optional getRedactionFileStatusEntry(String downloadStorageId, String fileId) { + + return downloadRedactionFileStatusRepository.findByDownloadStorageIdAndFileId(downloadStorageId, fileId); + } + + + @Transactional + public void clearRedactionStatusEntries(String downloadStorageId) { + + downloadRedactionFileStatusRepository.deleteIfPresentByDownloadStorageId(downloadStorageId); + } + + + public void createDownload(List redactionFileResults, String downloadId) { DownloadStatusEntity downloadStatus = downloadStatusPersistenceService.getStatus(downloadId); @@ -198,7 +189,6 @@ public class DownloadPreparationService { storeZipFile(downloadStatus, fileSystemBackedArchiver); updateStatusToReady(downloadStatus, fileSystemBackedArchiver); - redactionFileResultsMap.remove(downloadId); notificationPersistenceService.insertNotification(AddNotificationRequest.builder() .userId(downloadStatus.getUserId()) @@ -211,7 +201,7 @@ public class DownloadPreparationService { } downloadReportCleanupService.deleteTmpReportFiles(storedFileInformations.stream().map(StoredFileInformation::getStorageId).collect(Collectors.toSet())); - redactionFileResults.forEach(redactionFileResult -> downloadReportCleanupService.deleteTmpReportFiles(redactionFileResult.getRedactionResultDetailList() + redactionFileResults.forEach(redactionFileResult -> downloadReportCleanupService.deleteTmpReportFiles(redactionFileResult.getDetails() .stream() .map(RedactionResultDetail::getStorageId) .collect(Collectors.toSet()))); @@ -225,7 +215,7 @@ public class DownloadPreparationService { } - private void generateAndAddFiles(DownloadStatusEntity downloadStatus, List redactionFileResults, FileSystemBackedArchiver fileSystemBackedArchiver) { + private void generateAndAddFiles(DownloadStatusEntity downloadStatus, List redactionFileResults, FileSystemBackedArchiver fileSystemBackedArchiver) { int i = 1; long fileGenerationStart = System.currentTimeMillis(); @@ -237,7 +227,7 @@ public class DownloadPreparationService { var isFileApproved = WorkflowStatus.APPROVED.equals(file.getWorkflowStatus()); String filename = isFileApproved ? file.getFilename() : "UNAPPROVED_" + file.getFilename(); for (DownloadFileType downloadFileType : downloadStatus.getDownloadFileTypes()) { - Optional redactionFileResult = redactionFileResults.stream().filter(rfr -> rfr.getFileId().equals(file.getId())).findFirst(); + Optional redactionFileResult = redactionFileResults.stream().filter(rfr -> rfr.getFileId().equals(file.getId())).findFirst(); if (redactionFileResult.isEmpty()) { throw new RuntimeException(); @@ -248,15 +238,15 @@ public class DownloadPreparationService { } if (downloadFileType.name().equals(DownloadFileType.PREVIEW.name())) { fileSystemBackedArchiver.addEntry(new FileSystemBackedArchiver.ArchiveModel("Preview", addSuffix(filename, "highlighted"), // - getPreview(file.getId(), redactionFileResult.get().getRedactionResultDetailList()))); + getPreview(file.getId(), redactionFileResult.get().getDetails()))); } if (downloadFileType.name().equals(DownloadFileType.DELTA_PREVIEW.name())) { fileSystemBackedArchiver.addEntry(new FileSystemBackedArchiver.ArchiveModel("Delta Preview", addSuffix(filename, "delta_highlighted"), // - getDeltaPreview(file.getId(), redactionFileResult.get().getRedactionResultDetailList()))); + getDeltaPreview(file.getId(), redactionFileResult.get().getDetails()))); } if (downloadFileType.name().equals(DownloadFileType.REDACTED.name()) && isFileApproved) { fileSystemBackedArchiver.addEntry(new FileSystemBackedArchiver.ArchiveModel("Redacted", addSuffix(file.getFilename(), "redacted"), // - getRedacted(file.getId(), redactionFileResult.get().getRedactionResultDetailList()))); + getRedacted(file.getId(), redactionFileResult.get().getDetails()))); } } @@ -384,7 +374,7 @@ public class DownloadPreparationService { private void storeZipFile(DownloadStatusEntity downloadStatus, FileSystemBackedArchiver fileSystemBackedArchiver) { long start = System.currentTimeMillis(); - try(var in = fileSystemBackedArchiver.toInputStream()) { + try (var in = fileSystemBackedArchiver.toInputStream()) { fileManagementStorageService.storeObject(downloadStatus.getStorageId(), in); } log.info("Successfully stored zip for downloadId {}, took {}", downloadStatus.getStorageId(), System.currentTimeMillis() - start); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/RedactionDlqMessageReceiver.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/RedactionDlqMessageReceiver.java index 2356adf4c..965f606b5 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/RedactionDlqMessageReceiver.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/RedactionDlqMessageReceiver.java @@ -1,23 +1,23 @@ package com.iqser.red.service.persistence.management.v1.processor.service.download; -import java.io.IOException; - -import org.springframework.amqp.core.Message; -import org.springframework.amqp.rabbit.annotation.RabbitHandler; -import org.springframework.amqp.rabbit.annotation.RabbitListener; -import org.springframework.stereotype.Service; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.iqser.red.service.pdftron.redaction.v1.api.model.RedactionMessage; import com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DownloadStatusPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.settings.FileManagementServiceSettings; import com.iqser.red.service.persistence.service.v1.api.shared.model.download.DownloadStatusValue; - import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.rabbit.annotation.RabbitHandler; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.retry.support.RetryTemplate; +import org.springframework.stereotype.Service; + +import java.io.IOException; @Slf4j @Service @@ -25,40 +25,48 @@ import lombok.extern.slf4j.Slf4j; @FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class RedactionDlqMessageReceiver { - private static final String LINE_SEPARATOR = System.lineSeparator(); - ObjectMapper objectMapper; DownloadStatusPersistenceService downloadStatusPersistenceService; DownloadPreparationService downloadPreparationService; + FileManagementServiceSettings settings; + RetryTemplate retryTemplate; + RabbitTemplate rabbitTemplate; @RabbitHandler @RabbitListener(queues = MessagingConfiguration.PDFTRON_DLQ) public void receive(Message message) throws IOException { - // Since we receive different message types here, we do not convert to an object here; - // We just assume that the message contains a downloadId. - JsonNode jsonNode = objectMapper.readTree(message.getBody()); - final String downloadId; - final String fileId; - try { - downloadId = jsonNode.findValue("downloadId").asText(); + // Download packages will always be build on the pod that runs the scheduler, as we plan to replace the entire logic by downloading directory direct from storage, we leave it like that for now. - } catch (Exception e) { - log.warn("Received a message in the " + MessagingConfiguration.PDFTRON_DLQ + " that contains no downloadId" + LINE_SEPARATOR + "{}", jsonNode.asText()); - throw new RuntimeException(e); - } + RedactionMessage redactionMessage = objectMapper.readValue(message.getBody(), RedactionMessage.class); - try { - fileId = jsonNode.findValue("fileId").asText(); - var unapproved = jsonNode.findValue("unapprovedFile"); - log.info("Received a dead message with downloadId: {}, fileId: {} check for retry", downloadId, fileId); - downloadPreparationService.checkForRetryProcess(downloadId, fileId, unapproved.asBoolean()); + var fileEntryOptional = downloadPreparationService.getRedactionFileStatusEntry(redactionMessage.getDownloadId(), redactionMessage.getFileId()); - } catch (Exception e) { - log.info("Received a dead message with downloadId: {}, updating the download as failed", downloadId); - downloadStatusPersistenceService.updateStatus(downloadId, DownloadStatusValue.FAILED); + if (fileEntryOptional.isPresent()) { + var entry = fileEntryOptional.get(); + int numErrors = entry.getProcessingErrorCounter() + 1; + if (numErrors >= settings.getMaxRedactionFileErrorRetries()) { + setDownloadFailed(redactionMessage.getDownloadId()); + downloadPreparationService.clearRedactionStatusEntries(redactionMessage.getDownloadId()); + } else { + downloadPreparationService.increaseProcessingErrorCounter(redactionMessage, numErrors); + rabbitTemplate.convertAndSend(MessagingConfiguration.PDFTRON_QUEUE, message); + } + } else { + downloadPreparationService.markFileAsProcessingError(redactionMessage); + rabbitTemplate.convertAndSend(MessagingConfiguration.PDFTRON_QUEUE, message); } } + + public void setDownloadFailed(String downloadId) { + + retryTemplate.execute(retryContext -> { + log.warn("Retrying {} time to set FAILED status for downloadJob with storageId: {}", retryContext.getRetryCount(), downloadId); + downloadStatusPersistenceService.updateStatus(downloadId, DownloadStatusValue.FAILED); + return null; + }); + } + } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/RedactionResultMessageReceiver.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/RedactionResultMessageReceiver.java index e93a9e2de..8bf75208b 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/RedactionResultMessageReceiver.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/RedactionResultMessageReceiver.java @@ -1,21 +1,19 @@ package com.iqser.red.service.persistence.management.v1.processor.service.download; -import org.springframework.amqp.AmqpRejectAndDontRequeueException; -import org.springframework.amqp.core.Message; -import org.springframework.amqp.rabbit.annotation.RabbitHandler; -import org.springframework.amqp.rabbit.annotation.RabbitListener; -import org.springframework.stereotype.Service; - import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.iqser.red.service.pdftron.redaction.v1.api.model.RedactionResultMessage; import com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration; - import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.experimental.FieldDefaults; import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.AmqpRejectAndDontRequeueException; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.rabbit.annotation.RabbitHandler; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.stereotype.Service; @Slf4j @Service @@ -48,7 +46,7 @@ public class RedactionResultMessageReceiver { log.info("Received redaction results for downloadId: {} fileId: {}", redactionResultMessage.getDownloadId(), redactionResultMessage.getFileId()); - downloadPreparationService.processingRedactionResultMessage(redactionResultMessage); + downloadPreparationService.markFileAsProcessed(redactionResultMessage); } } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/job/DownloadReadyJob.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/job/DownloadReadyJob.java new file mode 100644 index 000000000..71927f25a --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/job/DownloadReadyJob.java @@ -0,0 +1,54 @@ +package com.iqser.red.service.persistence.management.v1.processor.service.job; + +import com.iqser.red.service.persistence.management.v1.processor.service.download.DownloadPreparationService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DownloadStatusPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DownloadRedactionFileStatusRepository; +import com.iqser.red.service.persistence.management.v1.processor.utils.TenantUtils; +import com.iqser.red.service.persistence.service.v1.api.shared.model.download.DownloadStatusValue; +import com.knecon.fforesight.tenantcommons.TenantContext; +import com.knecon.fforesight.tenantcommons.TenantProvider; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.springframework.stereotype.Service; + +@Slf4j +@RequiredArgsConstructor +@Service +public class DownloadReadyJob implements Job { + + private final DownloadStatusPersistenceService downloadStatusPersistenceService; + private final DownloadRedactionFileStatusRepository downloadRedactionFileStatusRepository; + private final DownloadPreparationService downloadPreparationService; + private final TenantProvider tenantProvider; + + + @Override + public void execute(JobExecutionContext jobExecutionContext) { + + log.debug("Running DownloadReadyJob"); + + tenantProvider.getTenants().forEach(tenant -> { + + if (!TenantUtils.isTenantReadyForPersistence(tenant)) { + return; + } + + TenantContext.setTenantId(tenant.getTenantId()); + + downloadStatusPersistenceService.getStatus().stream().filter(d -> d.getStatus().equals(DownloadStatusValue.GENERATING)).forEach(download -> { + + int numberOfFiles = download.getFiles().size(); + var downloadRedactionFileStatus = downloadRedactionFileStatusRepository.findAllByDownloadStorageId(download.getStorageId()); + if (downloadRedactionFileStatus.size() == numberOfFiles) { + downloadPreparationService.createDownload(downloadRedactionFileStatus, download.getStorageId()); + downloadPreparationService.clearRedactionStatusEntries(download.getStorageId()); + } + }); + }); + + } + + +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DownloadRedactionFileStatusRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DownloadRedactionFileStatusRepository.java new file mode 100644 index 000000000..9a75faec9 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DownloadRedactionFileStatusRepository.java @@ -0,0 +1,25 @@ +package com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository; + +import com.iqser.red.service.persistence.management.v1.processor.entity.download.DownloadRedactionFileStatusEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; +import java.util.Optional; + +public interface DownloadRedactionFileStatusRepository extends JpaRepository { + + List findAllByDownloadStorageId(String storageId); + + Optional findByDownloadStorageIdAndFileId(String storageId, String fileId); + + + @Modifying + @Query("update DownloadRedactionFileStatusEntity e set e.processingErrorCounter = :processingErrorCounter where e.downloadStorageId = :downloadStorageId and e.fileId = :fileId") + void updateStatusErrorInfo(String downloadStorageId, String fileId, Integer processingErrorCounter); + + @Modifying + Integer deleteIfPresentByDownloadStorageId(String downloadStorageId); + +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/settings/FileManagementServiceSettings.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/settings/FileManagementServiceSettings.java index 452013c4b..93e2ba057 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/settings/FileManagementServiceSettings.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/settings/FileManagementServiceSettings.java @@ -30,6 +30,7 @@ public class FileManagementServiceSettings { private boolean migrateOnly; private int maxErrorRetries = 1; + private int maxRedactionFileErrorRetries = 2; private boolean cvTableParsingEnabled; diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/utils/JSONDownloadRedactionFileDetailsConverter.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/utils/JSONDownloadRedactionFileDetailsConverter.java new file mode 100644 index 000000000..8acb90cf8 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/utils/JSONDownloadRedactionFileDetailsConverter.java @@ -0,0 +1,40 @@ +package com.iqser.red.service.persistence.management.v1.processor.utils; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.iqser.red.service.pdftron.redaction.v1.api.model.RedactionResultDetail; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; +import lombok.SneakyThrows; + +import java.util.ArrayList; +import java.util.List; + +@Converter +public class JSONDownloadRedactionFileDetailsConverter implements AttributeConverter, String> { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + + @SneakyThrows + @Override + public String convertToDatabaseColumn(List dataSet) { + + return objectMapper.writeValueAsString(dataSet); + } + + + @SneakyThrows + @Override + public List convertToEntityAttribute(String data) { + + if (data == null) { + return new ArrayList<>(); + } + TypeReference> typeRef = new TypeReference<>() { + }; + return objectMapper.readValue(data, typeRef); + + } + +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/db.changelog-tenant.yaml b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/db.changelog-tenant.yaml index c54697548..3992cf973 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/db.changelog-tenant.yaml +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/db.changelog-tenant.yaml @@ -164,4 +164,6 @@ databaseChangeLog: - include: file: db/changelog/tenant/111-make-rule-values-non-nullable.yaml - include: - file: db/changelog/tenant/112-modify-section-length.yaml \ No newline at end of file + file: db/changelog/tenant/112-modify-section-length.yaml + - include: + file: db/changelog/tenant/114-add-download-redaction-file-status-table.yaml \ No newline at end of file diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/114-add-download-redaction-file-status-table.yaml b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/114-add-download-redaction-file-status-table.yaml new file mode 100644 index 000000000..37f043049 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/114-add-download-redaction-file-status-table.yaml @@ -0,0 +1,28 @@ +databaseChangeLog: + - changeSet: + id: download-redaction-file-status-table + author: dom + changes: + - createTable: + columns: + - column: + constraints: + nullable: false + primaryKey: true + primaryKeyName: download_redaction_file_status_pkey + name: id + type: VARCHAR(255) + - column: + name: download_storage_id + type: VARCHAR(255) + - column: + name: file_id + type: VARCHAR(255) + - column: + name: processing_error_counter + type: INTEGER + - column: + name: details + type: VARCHAR(1024) + tableName: download_redaction_file_status + diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/26-application-config-table.changelog.yaml b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/26-application-config-table.changelog.yaml index 51e8f97bc..9dc01b784 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/26-application-config-table.changelog.yaml +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/26-application-config-table.changelog.yaml @@ -1,6 +1,6 @@ databaseChangeLog: - changeSet: - id: application-config-table + id: download_redaction_file_result author: corina (generated) changes: - createTable: diff --git a/persistence-service-v1/persistence-service-server-v1/src/main/resources/log4j2.xml b/persistence-service-v1/persistence-service-server-v1/src/main/resources/log4j2.xml index 7cdd0cd0c..74544ee39 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/main/resources/log4j2.xml +++ b/persistence-service-v1/persistence-service-server-v1/src/main/resources/log4j2.xml @@ -8,10 +8,14 @@ + + + - + diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadPreparationTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadPreparationTest.java index 0aaa11872..c5d5e3f20 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadPreparationTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadPreparationTest.java @@ -1,17 +1,21 @@ package com.iqser.red.service.peristence.v1.server.integration.tests; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; import java.io.ByteArrayInputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; +import com.iqser.red.service.persistence.management.v1.processor.service.job.DownloadReadyJob; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DownloadStatusPersistenceService; +import com.knecon.fforesight.tenantcommons.TenantProvider; +import com.knecon.fforesight.tenantcommons.model.TenantResponse; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.mock.web.MockMultipartFile; import com.fasterxml.jackson.databind.ObjectMapper; @@ -82,6 +86,14 @@ public class DownloadPreparationTest extends AbstractPersistenceServerServiceTes DossierWithSingleFile testData; + @Autowired + DownloadReadyJob downloadReadyJob; + + @Autowired + DownloadStatusPersistenceService downloadStatusPersistenceService; + + + @BeforeEach public void createTestData() { @@ -137,6 +149,12 @@ public class DownloadPreparationTest extends AbstractPersistenceServerServiceTes .redactionResultDetails(Collections.emptyList()) .build()); + // This set in DownloadMessageReceiver first async step via queue is unneeded and can be removed later. + downloadStatusPersistenceService.updateStatus(downloadId, DownloadStatusValue.GENERATING); + + when(this.tenantsClient.getTenants()).thenReturn(List.of(TenantResponse.builder().tenantId("redaction").details(Map.of("persistence-service-ready", true)).build())); + downloadReadyJob.execute(null); // Will be called by scheduler in prod. + List finalDownloadStatuses = downloadClient.getDownloadStatus().getDownloadStatus(); assertThat(finalDownloadStatuses).hasSize(1); DownloadStatus finalDownloadStatus = finalDownloadStatuses.get(0); diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadTest.java index 3a90676ac..436e026d0 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadTest.java @@ -6,6 +6,11 @@ import java.util.ArrayList; import java.util.List; import java.util.Set; +import com.iqser.red.service.pdftron.redaction.v1.api.model.RedactionResultDetail; +import com.iqser.red.service.pdftron.redaction.v1.api.model.RedactionType; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DownloadRedactionFileStatusRepository; +import com.knecon.fforesight.tenantcommons.EncryptionDecryptionService; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -57,8 +62,15 @@ public class DownloadTest extends AbstractPersistenceServerServiceTest { @Autowired private DownloadPreparationService downloadPreparationService; + @Autowired + DownloadRedactionFileStatusRepository downloadRedactionFileStatusRepository; + + @Autowired + EncryptionDecryptionService encryptionDecryptionService; + @Test + @Disabled @SneakyThrows public void testDownload() { @@ -91,8 +103,8 @@ public class DownloadTest extends AbstractPersistenceServerServiceTest { downloadPreparationService.createDownload(ReportResultMessage.builder().downloadId(downloads.getStorageId()).build()); - downloadPreparationService.processingRedactionResultMessage(RedactionResultMessage.builder().downloadId(downloads.getStorageId()).dossierId(dossier.getId()).fileId(file.getId()).build()); - downloadPreparationService.processingRedactionResultMessage(RedactionResultMessage.builder().downloadId(downloads.getStorageId()).dossierId(dossier.getId()).fileId(file2.getId()).build()); + downloadPreparationService.markFileAsProcessed(RedactionResultMessage.builder().downloadId(downloads.getStorageId()).dossierId(dossier.getId()).fileId(file.getId()).build()); + downloadPreparationService.markFileAsProcessed(RedactionResultMessage.builder().downloadId(downloads.getStorageId()).dossierId(dossier.getId()).fileId(file2.getId()).build()); var statuses = downloadClient.getDownloadStatus(); assertThat(statuses.getDownloadStatus()).isNotEmpty(); @@ -104,4 +116,12 @@ public class DownloadTest extends AbstractPersistenceServerServiceTest { } + + @Test + public void testMarkAsProcessed(){ + + downloadPreparationService.markFileAsProcessed(RedactionResultMessage.builder().downloadId("dsfsdf").dossierId("sdfsdf").fileId("rwerwe").redactionResultDetails(List.of(RedactionResultDetail.builder().redactionType(RedactionType.REDACTED).storageId("dsfsdf").build())).build()); + + } + } diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java index 0463603d5..4eccc8560 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java @@ -176,7 +176,7 @@ public abstract class AbstractPersistenceServerServiceTest { @Autowired private TokenService tokenService; @MockBean - private TenantsClient tenantsClient; + protected TenantsClient tenantsClient; @MockBean private UsersClient usersClient; @Autowired -- 2.47.2 From 647b91193a48cbee6513d88f2ac0cea44ed1652a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominique=20Eifl=C3=A4nder?= Date: Mon, 16 Oct 2023 12:57:39 +0200 Subject: [PATCH 09/96] RED-7767: Added migration for missing filesizes --- .../MissingFileSizeMigration13.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/MissingFileSizeMigration13.java diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/MissingFileSizeMigration13.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/MissingFileSizeMigration13.java new file mode 100644 index 000000000..383cb0194 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/MissingFileSizeMigration13.java @@ -0,0 +1,60 @@ +package com.iqser.red.service.persistence.management.v1.processor.migration.migrations; + + +import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.FileEntity; +import com.iqser.red.service.persistence.management.v1.processor.migration.Migration; +import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Slf4j +@Setter +@Service +public class MissingFileSizeMigration13 extends Migration { + + private static final String NAME = "Add missing file sizes"; + private static final long VERSION = 13; + + @Autowired + private FileStatusPersistenceService fileStatusPersistenceService; + + @Autowired + private FileManagementStorageService fileManagementStorageService; + + + public MissingFileSizeMigration13() { + + super(NAME, VERSION); + } + + + @Override + protected void migrate() { + + List missingFileSizeFiles = fileStatusPersistenceService.getAllFiles().stream().filter(file -> file.getFileSize() == null).toList(); + + log.info("Number of files without fileSize: {}", missingFileSizeFiles.size()); + + missingFileSizeFiles.forEach(file -> { + // not hard deleted + if (file.getHardDeletedTime() == null) { + try { + var originFile = fileManagementStorageService.getStoredObjectBytes(file.getDossierId(), file.getId(), FileType.ORIGIN); + fileStatusPersistenceService.updateFileSize(file.getId(), originFile.length); + } catch (Exception e) { + log.warn("Failed to load file bytes for file: {} in dossier {}. Error message: {}, setting filesize to 0", file.getId(), file.getDossierId(), e.getMessage()); + fileStatusPersistenceService.updateFileSize(file.getId(), 0); + } + } else { + fileStatusPersistenceService.updateFileSize(file.getId(), 0); + } + }); + } + +} -- 2.47.2 From f317ff9f90d09b47ff0ec67cb8ee5644db8828f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominique=20Eifl=C3=A4nder?= Date: Tue, 17 Oct 2023 09:21:42 +0200 Subject: [PATCH 10/96] RED-7768: Fixed double counting of deleted documents in license --- .../service/LicenseReportService.java | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java index 597c856ea..da445db13 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java @@ -1,30 +1,22 @@ package com.iqser.red.service.persistence.management.v1.processor.service; -import java.time.Instant; -import java.time.OffsetDateTime; -import java.time.YearMonth; -import java.time.ZoneId; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - -import org.springframework.stereotype.Service; - import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity; import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.license.LicenseReport; import com.iqser.red.service.persistence.service.v1.api.shared.model.license.LicenseReportRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.license.MonthlyReportData; - import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.YearMonth; +import java.time.ZoneId; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -67,13 +59,13 @@ public class LicenseReportService { if (file.getDeleted() != null && file.getDeleted().toInstant().isBefore(licenseReportRequest.getEndDate())) { softDeletes.computeIfAbsent(YearMonth.from(file.getDeleted()), entry -> new HashSet<>()).add(file); } - if(dossiersById.get(file.getDossierId()).getSoftDeletedTime() != null && dossiersById.get(file.getDossierId()).getSoftDeletedTime().toInstant().isBefore(licenseReportRequest.getEndDate())){ + if (file.getDeleted() == null && dossiersById.get(file.getDossierId()).getSoftDeletedTime() != null && dossiersById.get(file.getDossierId()).getSoftDeletedTime().toInstant().isBefore(licenseReportRequest.getEndDate())) { softDeletes.computeIfAbsent(YearMonth.from(dossiersById.get(file.getDossierId()).getSoftDeletedTime()), entry -> new HashSet<>()).add(file); } if (file.getHardDeletedTime() != null && file.getHardDeletedTime().toInstant().isBefore(licenseReportRequest.getEndDate())) { hardDeletes.computeIfAbsent(YearMonth.from(file.getHardDeletedTime()), entry -> new HashSet<>()).add(file); } - if(dossiersById.get(file.getDossierId()).getHardDeletedTime() != null && dossiersById.get(file.getDossierId()).getHardDeletedTime().toInstant().isBefore(licenseReportRequest.getEndDate())){ + if (file.getHardDeletedTime() == null && dossiersById.get(file.getDossierId()).getHardDeletedTime() != null && dossiersById.get(file.getDossierId()).getHardDeletedTime().toInstant().isBefore(licenseReportRequest.getEndDate())) { hardDeletes.computeIfAbsent(YearMonth.from(dossiersById.get(file.getDossierId()).getHardDeletedTime()), entry -> new HashSet<>()).add(file); } if (dossiersById.get(file.getDossierId()).getArchivedTime() != null && dossiersById.get(file.getDossierId()) -- 2.47.2 From 0d150c3aa625d84a43fa6e1c29598bdca639f21f Mon Sep 17 00:00:00 2001 From: Andrei Isvoran Date: Tue, 17 Oct 2023 09:22:21 +0200 Subject: [PATCH 11/96] RED-7745 - Refactor to EntityLog --- .../EntityLogInternalController.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/EntityLogInternalController.java diff --git a/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/EntityLogInternalController.java b/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/EntityLogInternalController.java new file mode 100644 index 000000000..5ec246486 --- /dev/null +++ b/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/EntityLogInternalController.java @@ -0,0 +1,30 @@ +package com.iqser.red.service.persistence.v1.internal.api.controller; + +import java.util.List; + +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService; +import com.iqser.red.service.persistence.service.v1.api.internal.resources.EntityLogResource; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; + +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +public class EntityLogInternalController implements EntityLogResource { + + private final EntityLogService entityLogService; + + + public EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId, + @PathVariable(FILE_ID) String fileId, + @RequestParam(value = "excludedType", required = false) List excludedTypes) { + + return entityLogService.getEntityLog(dossierId, fileId, excludedTypes); + } + + +} -- 2.47.2 From 3611c9e33f283276ae38121529c965f9081ac655 Mon Sep 17 00:00:00 2001 From: Corina Olariu Date: Tue, 17 Oct 2023 13:22:38 +0300 Subject: [PATCH 12/96] RED-7763 - Use EntityLog in tests in persistence-service - replaced redaction log with entity log - updates junit tests --- .../impl/controller/DocumentController.java | 2 - .../internal/AdminInterfaceController.java | 2 + .../AnalysisFlagsCalculationService.java | 37 +- .../v1/processor/service/CommentService.java | 68 ++- .../processor/service/FileStatusService.java | 2 + ...anualRedactionDictionaryUpdateHandler.java | 27 +- .../ManualRedactionMapper.java | 41 +- .../ManualRedactionService.java | 18 +- .../ManualRedactionUndoService.java | 22 +- .../service/FileTesterAndProvider.java | 13 +- .../server/integration/tests/DossierTest.java | 8 +- .../v1/server/integration/tests/FileTest.java | 26 +- .../tests/ManualRedactionTest.java | 386 ++++++++++-------- .../AbstractPersistenceServerServiceTest.java | 8 +- 14 files changed, 335 insertions(+), 325 deletions(-) diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/DocumentController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/DocumentController.java index a2b4eb03f..d9796ac20 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/DocumentController.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/DocumentController.java @@ -18,7 +18,6 @@ import org.springframework.web.bind.annotation.RestController; import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService; -import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService; import com.iqser.red.service.persistence.management.v1.processor.utils.StringEncodingUtils; import com.iqser.red.service.persistence.service.v1.api.external.resource.DocumentResource; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType; @@ -33,7 +32,6 @@ import lombok.SneakyThrows; @RequiredArgsConstructor public class DocumentController implements DocumentResource { - private final RedactionLogService redactionLogService; private final FileStatusService fileStatusService; private final FileManagementStorageService fileManagementStorageService; diff --git a/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/internal/AdminInterfaceController.java b/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/internal/AdminInterfaceController.java index d205ed4e6..601653c2e 100644 --- a/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/internal/AdminInterfaceController.java +++ b/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/internal/AdminInterfaceController.java @@ -37,6 +37,7 @@ public class AdminInterfaceController { fileManagementStorageService.deleteObject(dossierId, fileId, FileType.SECTION_GRID); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.REDACTION_LOG); + fileManagementStorageService.deleteObject(dossierId, fileId, FileType.ENTITY_LOG); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.DOCUMENT_PAGES); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.DOCUMENT_TEXT); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.DOCUMENT_POSITION); @@ -139,6 +140,7 @@ public class AdminInterfaceController { fileManagementStorageService.deleteObject(dossierId, fileId, FileType.SECTION_GRID); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.REDACTION_LOG); + fileManagementStorageService.deleteObject(dossierId, fileId, FileType.ENTITY_LOG); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.DOCUMENT_STRUCTURE); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.DOCUMENT_TEXT); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.DOCUMENT_PAGES); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/AnalysisFlagsCalculationService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/AnalysisFlagsCalculationService.java index e5f484bf1..4564c21ea 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/AnalysisFlagsCalculationService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/AnalysisFlagsCalculationService.java @@ -10,11 +10,11 @@ import org.springframework.stereotype.Service; import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ViewedPageEntity; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.ViewedPagesPersistenceService; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryState; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.ManualRedactionType; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.ChangeType; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.ManualRedactionType; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; import io.micrometer.core.annotation.Timed; import lombok.RequiredArgsConstructor; @@ -26,7 +26,7 @@ import lombok.extern.slf4j.Slf4j; public class AnalysisFlagsCalculationService { private final FileStatusPersistenceService fileStatusPersistenceService; - private final RedactionLogService redactionLogService; + private final EntityLogService entityLogService; private final ViewedPagesPersistenceService viewedPagesPersistenceService; @@ -36,7 +36,7 @@ public class AnalysisFlagsCalculationService { long startTime = System.currentTimeMillis(); var file = fileStatusPersistenceService.getStatus(fileId); - var redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); + var entityLog = entityLogService.getEntityLog(dossierId, fileId); var viewedPagesForCurrentAssignee = viewedPagesPersistenceService.findViewedPages(fileId, file.getAssignee()); @@ -52,7 +52,7 @@ public class AnalysisFlagsCalculationService { OffsetDateTime lastRedactionModification = null; OffsetDateTime lastManualChangeDate = null; - for (RedactionLogEntry entry : redactionLog.getRedactionLogEntry()) { + for (EntityLogEntry entry : entityLog.getEntityLogEntry()) { if (entry.isExcluded()) { continue; } @@ -60,11 +60,11 @@ public class AnalysisFlagsCalculationService { String type = getType(entry.getType()); var lastChange = entry.getChanges().isEmpty() ? null : entry.getChanges().get(entry.getChanges().size() - 1); - + var entryType = entry.getEntryType(); if (entry.getManualChanges() != null && !entry.getManualChanges().isEmpty()) { for (var manualChange : entry.getManualChanges()) { - if (!entry.isHint() && !entry.isRecommendation() && StringUtils.isNotEmpty(entry.getReason()) && (manualChange.getManualRedactionType() + if (!entryType.equals(EntryType.HINT) && !entryType.equals(EntryType.RECOMMENDATION) && StringUtils.isNotEmpty(entry.getReason()) && (manualChange.getManualRedactionType() .equals(ManualRedactionType.ADD_LOCALLY) || manualChange.getManualRedactionType() .equals(ManualRedactionType.RECATEGORIZE) || manualChange.getManualRedactionType() .equals(ManualRedactionType.REMOVE_LOCALLY) || manualChange.getManualRedactionType() @@ -87,33 +87,24 @@ public class AnalysisFlagsCalculationService { } if (lastChange != null && (lastRedactionModification == null || lastChange.getDateTime() - .isAfter(lastRedactionModification)) && !entry.isHint() && !entry.isRecommendation()) { + .isAfter(lastRedactionModification)) && !entryType.equals(EntryType.HINT) && !entryType.equals(EntryType.RECOMMENDATION)) { lastRedactionModification = lastChange.getDateTime(); } - if (!hasRedactions && entry.isRedacted() && !entry.isRecommendation()) { + if (!hasRedactions && entry.getState().equals(EntryState.APPLIED) && !entryType.equals(EntryType.RECOMMENDATION)) { hasRedactions = true; } - if (!hasHints && entry.isHint()) { + if (!hasHints && entryType.equals(EntryType.HINT)) { hasHints = true; } - if (!hasImages && (type.equals("image") || entry.isImage())) { + if (!hasImages && (type.equals("image") || entryType.equals(EntryType.IMAGE))) { hasImages = true; } - if (!hasSuggestions && (lastChange == null || lastChange.getType() != ChangeType.REMOVED) && entry.getManualChanges() - .stream() - .anyMatch(e -> e.getAnnotationStatus().name().equals(AnnotationStatus.REQUESTED.name()))) { - hasSuggestions = true; - } - if (!hasComments && entry.getComments() != null && !entry.getComments().isEmpty()) { - hasComments = true; - } - - var viewedPage = entry.getPositions().isEmpty() ? null : viewedPages.get(entry.getPositions().get(0).getPage()); + var viewedPage = entry.getPositions().isEmpty() ? null : viewedPages.get(entry.getPositions().get(0).getPageNumber()); if (file.getWorkflowStatus() != WorkflowStatus.APPROVED && lastChange != null && lastChange.getDateTime() != null && viewedPage != null && viewedPage.isBefore( lastChange.getDateTime())) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java index a0d573c30..6288f59c7 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java @@ -17,9 +17,6 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comment; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.CommentRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comments; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.ProcessingStatus; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogComment; import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter; import lombok.AccessLevel; @@ -34,7 +31,6 @@ public class CommentService { CommentPersistenceService commentPersistenceService; FileStatusPersistenceService fileStatusPersistenceService; FileStatusService fileStatusService; - RedactionLogService redactionLogService; FileManagementStorageService fileManagementStorageService; private final int COMMENT_MAX_LENGTH = 4000; @@ -48,18 +44,19 @@ public class CommentService { // update indicator fileStatusPersistenceService.updateHasComments(fileId, commentPersistenceService.fileHasComments(fileId)); - // This is an ugly workaround, don't even look at it! - // Basically we should change how comments work and not merge them into the redaction log. - // if file is currently not analyzing, we can quickly change the redaction log, else we must wait for the analysis to finish. - if (!fileStatusService.getStatus(fileId).getProcessingStatus().equals(ProcessingStatus.PROCESSED)) { - reprocess(dossierId, fileId); - return; - } - fileStatusService.setStatusProcessing(fileId); - RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); - redactionLog.getRedactionLogEntry().forEach(entry -> entry.getComments().removeIf(comment -> commentIds.contains(comment.getId()))); - fileManagementStorageService.storeRedactionLog(dossierId, fileId, redactionLog); - fileStatusService.setStatusProcessed(fileId); + // Since entityLog does not have comments, no need to trigger reprocess or to store them +// // This is an ugly workaround, don't even look at it! +// // Basically we should change how comments work and not merge them into the redaction log. +// // if file is currently not analyzing, we can quickly change the redaction log, else we must wait for the analysis to finish. +// if (!fileStatusService.getStatus(fileId).getProcessingStatus().equals(ProcessingStatus.PROCESSED)) { +// reprocess(dossierId, fileId); +// return; +// } +// fileStatusService.setStatusProcessing(fileId); +// RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); +// redactionLog.getRedactionLogEntry().forEach(entry -> entry.getComments().removeIf(comment -> commentIds.contains(comment.getId()))); +// fileManagementStorageService.storeRedactionLog(dossierId, fileId, redactionLog); +// fileStatusService.setStatusProcessed(fileId); } @@ -81,20 +78,21 @@ public class CommentService { fileStatusPersistenceService.updateHasComments(fileId, true); - // This is an ugly workaround, don't even look at it! - // Basically we should change how comments work and not merge them into the redaction log. - if (!fileStatusService.getStatus(fileId).getProcessingStatus().equals(ProcessingStatus.PROCESSED)) { - reprocess(dossierId, fileId); - return createdComment; - } - fileStatusService.setStatusProcessing(fileId); - RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); - redactionLog.getRedactionLogEntry() - .stream() - .filter(entry -> entry.getId().equals(annotationId)) - .forEach(entry -> entry.getComments().add(MagicConverter.convert(createdComment, RedactionLogComment.class))); - fileManagementStorageService.storeRedactionLog(dossierId, fileId, redactionLog); - fileStatusService.setStatusProcessed(fileId); + // Since entityLog does not have comments, no need to trigger reprocess or to store them +// // This is an ugly workaround, don't even look at it! +// // Basically we should change how comments work and not merge them into the redaction log. +// if (!fileStatusService.getStatus(fileId).getProcessingStatus().equals(ProcessingStatus.PROCESSED)) { +// reprocess(dossierId, fileId); +// return createdComment; +// } +// fileStatusService.setStatusProcessing(fileId); +// RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); +// redactionLog.getRedactionLogEntry() +// .stream() +// .filter(entry -> entry.getId().equals(annotationId)) +// .forEach(entry -> entry.getComments().add(MagicConverter.convert(createdComment, RedactionLogComment.class))); +// fileManagementStorageService.storeRedactionLog(dossierId, fileId, redactionLog); +// fileStatusService.setStatusProcessed(fileId); return createdComment; } @@ -130,10 +128,10 @@ public class CommentService { .build()); } - - private void reprocess(String dossierId, String fileId) { - - fileStatusService.setStatusReprocessForManual(dossierId, fileId, true); - } +// +// private void reprocess(String dossierId, String fileId) { +// +// fileStatusService.setStatusReprocessForManual(dossierId, fileId, true); +// } } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java index 55d2cde68..f53861151 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java @@ -639,6 +639,7 @@ public class FileStatusService { fileManagementStorageService.deleteObject(dossierId, fileId, FileType.ORIGIN); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.REDACTION_LOG); + fileManagementStorageService.deleteObject(dossierId, fileId, FileType.ENTITY_LOG); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.SECTION_GRID); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.IMAGE_INFO); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.DOCUMENT_STRUCTURE); @@ -668,6 +669,7 @@ public class FileStatusService { OffsetDateTime now = OffsetDateTime.now(); // remove everything related to redaction fileManagementStorageService.deleteObject(dossierId, fileId, FileType.REDACTION_LOG); + fileManagementStorageService.deleteObject(dossierId, fileId, FileType.ENTITY_LOG); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.SECTION_GRID); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.IMAGE_INFO); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionDictionaryUpdateHandler.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionDictionaryUpdateHandler.java index 9326f98fa..acaee3885 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionDictionaryUpdateHandler.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionDictionaryUpdateHandler.java @@ -23,12 +23,13 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ResizeRedactionPersistenceService; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRequestWithAddToDictionary; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRequestWithRemoveFromDictionary; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; import feign.FeignException; import lombok.AccessLevel; @@ -134,17 +135,17 @@ public class ManualRedactionDictionaryUpdateHandler { } - public Set updateDictionaryForResizeRedactions(String dossierId, String fileId, ManualResizeRedactionEntity resizeRedaction, RedactionLogEntry redactionLogEntry) { + public Set updateDictionaryForResizeRedactions(String dossierId, String fileId, ManualResizeRedactionEntity resizeRedaction, EntityLogEntry entityLogEntry) { if (resizeRedaction.getUpdateDictionary() != null && resizeRedaction.getUpdateDictionary() && resizeRedaction.getStatus() - .equals(AnnotationStatus.APPROVED) && (redactionLogEntry.isDictionaryEntry() || redactionLogEntry.isDossierDictionaryEntry())) { + .equals(AnnotationStatus.APPROVED) && (entityLogEntry.isDictionaryEntry() || entityLogEntry.isDossierDictionaryEntry())) { var dossier = dossierPersistenceService.findByDossierId(dossierId); - var typeId = buildTypeId(redactionLogEntry.getType(), resizeRedaction, dossier); + var typeId = buildTypeId(entityLogEntry.getType(), resizeRedaction, dossier); var newValue = resizeRedaction.getValue(); - var oldValue = redactionLogEntry.getValue(); - var dictionaryEntryType = getDictionaryEntryType(redactionLogEntry); + var oldValue = entityLogEntry.getValue(); + var dictionaryEntryType = getDictionaryEntryType(entityLogEntry); boolean isShrinking = oldValue != null && oldValue.length() > newValue.length(); @@ -155,10 +156,10 @@ public class ManualRedactionDictionaryUpdateHandler { removeFromDictionary(typeId, oldValue, dossierId, fileId, dictionaryEntryType); typeIdsOfModifiedDictionaries.add(typeId); - if (resizeRedaction.isAddToAllDossiers() && redactionLogEntry.isDictionaryEntry()) { + if (resizeRedaction.isAddToAllDossiers() && entityLogEntry.isDictionaryEntry()) { String dossierTemplateId = dossier.getDossierTemplateId(); var dossiersOfThisDossierTemplate = dossierPersistenceService.findAllDossiersForDossierTemplateId(dossierTemplateId); - var type = redactionLogEntry.getType(); + var type = entityLogEntry.getType(); dossiersOfThisDossierTemplate.forEach(dossierEntity -> { var typeIdOfDossierEntity = toTypeId(type, dossierTemplateId, dossierEntity.getId()); removeFromDictionary(typeIdOfDossierEntity, oldValue, dossierId, fileId, dictionaryEntryType); @@ -189,11 +190,11 @@ public class ManualRedactionDictionaryUpdateHandler { } - private DictionaryEntryType getDictionaryEntryType(RedactionLogEntry redactionLogEntry) { + private DictionaryEntryType getDictionaryEntryType(EntityLogEntry entityLogEntry) { - if (redactionLogEntry.isRecommendation() && redactionLogEntry.isFalsePositive()) { + if (entityLogEntry.getEntryType().equals(EntryType.RECOMMENDATION) && entityLogEntry.getEntryType().equals(EntryType.FALSE_POSITIVE)) { return DictionaryEntryType.FALSE_RECOMMENDATION; - } else if (redactionLogEntry.isFalsePositive()) { + } else if (entityLogEntry.getEntryType().equals(EntryType.FALSE_POSITIVE)) { return DictionaryEntryType.FALSE_POSITIVE; } else { return DictionaryEntryType.ENTRY; @@ -295,9 +296,9 @@ public class ManualRedactionDictionaryUpdateHandler { } - private void removeResizeRedactionsWithAddToDictionary(String dossierTemplateId, String redactionLogEntryValue) { + private void removeResizeRedactionsWithAddToDictionary(String dossierTemplateId, String entityLogEntryValue) { - var resizeRedactionsWithSameValue = resizeRedactionPersistenceService.findByAnnotationStatusAndValue(AnnotationStatus.APPROVED, redactionLogEntryValue); + var resizeRedactionsWithSameValue = resizeRedactionPersistenceService.findByAnnotationStatusAndValue(AnnotationStatus.APPROVED, entityLogEntryValue); resizeRedactionsWithSameValue.forEach(resizeRedaction -> { var file = fileStatusPersistenceService.getStatus(resizeRedaction.getId().getFileId()); var dossierForResizeRedaction = dossierPersistenceService.findByDossierId(file.getDossierId()); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionMapper.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionMapper.java index a92b200f6..b8abca399 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionMapper.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionMapper.java @@ -10,7 +10,10 @@ import java.util.stream.Collectors; import org.springframework.stereotype.Service; import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; -import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService; +import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AddRedactionRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ForceRedactionRequest; @@ -26,8 +29,6 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.Lega import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RecategorizationRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequestModel; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity; import lombok.AccessLevel; @@ -39,7 +40,7 @@ import lombok.experimental.FieldDefaults; @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) public class ManualRedactionMapper { - RedactionLogService redactionLogService; + EntityLogService entityLogService; public List toAddRedactionRequestList(String dossierId, Set addRedactionRequests, Dossier dossier) { @@ -79,18 +80,18 @@ public class ManualRedactionMapper { Set removeRedactionRequests) { List requests = new ArrayList<>(); - RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); + EntityLog entityLog = entityLogService.getEntityLog(dossierId, fileId); for (var removeRedactionRequest : removeRedactionRequests) { - RedactionLogEntry redactionLogEntry = getRedactionLogEntry(redactionLog, removeRedactionRequest.getAnnotationId()); + EntityLogEntry entityLogEntry = getEntityLogEntry(entityLog, removeRedactionRequest.getAnnotationId()); var removeRedactionRequestBuilder = RemoveRedactionRequest.builder() .annotationId(removeRedactionRequest.getAnnotationId()) .user(KeycloakSecurity.getUserId()) .status(AnnotationStatus.APPROVED) .removeFromDictionary(removeRedactionRequest.isRemoveFromDictionary()) .removeFromAllDossiers(removeRedactionRequest.isRemoveFromAllDossiers()) - .value(redactionLogEntry.getValue()) - .dictionaryEntryType(getDictionaryEntryType(redactionLogEntry)) - .typeToRemove(redactionLogEntry.getType()) + .value(entityLogEntry.getValue()) + .dictionaryEntryType(getDictionaryEntryType(entityLogEntry)) + .typeToRemove(entityLogEntry.getType()) .dossierId(dossierId) .dossierTemplateId(dossierTemplateId); @@ -139,10 +140,10 @@ public class ManualRedactionMapper { String dossierTemplateId, Set recategorizationRequests) { - RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); + EntityLog entityLog = entityLogService.getEntityLog(dossierId, fileId); List requests = new ArrayList<>(); for (RecategorizationRequestModel recategorizationRequest : recategorizationRequests) { - RedactionLogEntry redactionLogEntry = getRedactionLogEntry(redactionLog, recategorizationRequest.getAnnotationId()); + EntityLogEntry entityLogEntry = getEntityLogEntry(entityLog, recategorizationRequest.getAnnotationId()); RecategorizationRequest build = RecategorizationRequest.builder() .annotationId(recategorizationRequest.getAnnotationId()) .user(KeycloakSecurity.getUserId()) @@ -152,9 +153,9 @@ public class ManualRedactionMapper { .dossierId(dossierId) .addToDictionary(recategorizationRequest.isAddToDictionary()) .addToAllDossiers(recategorizationRequest.isAddToAllDossiers()) - .dictionaryEntryType(getDictionaryEntryType(redactionLogEntry)) - .value(redactionLogEntry.getValue()) - .typeToRemove(redactionLogEntry.getType()) + .dictionaryEntryType(getDictionaryEntryType(entityLogEntry)) + .value(entityLogEntry.getValue()) + .typeToRemove(entityLogEntry.getType()) .dossierTemplateTypeId(toTypeId(recategorizationRequest.getType(), dossierTemplateId)) .build(); requests.add(build); @@ -181,21 +182,21 @@ public class ManualRedactionMapper { } - private RedactionLogEntry getRedactionLogEntry(RedactionLog redactionLog, String annotationId) { + private EntityLogEntry getEntityLogEntry(EntityLog entityLog, String annotationId) { - return redactionLog.getRedactionLogEntry() + return entityLog.getEntityLogEntry() .stream() .filter(entry -> entry.getId().equals(annotationId)) .findFirst() - .orElseThrow(() -> new NotFoundException("Annotation does not exist in redaction log.")); + .orElseThrow(() -> new NotFoundException("Annotation does not exist in entity log.")); } - private DictionaryEntryType getDictionaryEntryType(RedactionLogEntry redactionLogEntry) { + private DictionaryEntryType getDictionaryEntryType(EntityLogEntry entityLogEntry) { - if (redactionLogEntry.isRecommendation() && redactionLogEntry.isFalsePositive()) { + if (entityLogEntry.getEntryType().equals(EntryType.RECOMMENDATION) && entityLogEntry.getEntryType().equals(EntryType.FALSE_POSITIVE)) { return DictionaryEntryType.FALSE_RECOMMENDATION; - } else if (redactionLogEntry.isFalsePositive()) { + } else if (entityLogEntry.getEntryType().equals(EntryType.FALSE_POSITIVE)) { return DictionaryEntryType.FALSE_POSITIVE; } else { return DictionaryEntryType.ENTRY; diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java index 176420e6c..6fa6bd378 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java @@ -15,8 +15,8 @@ import com.iqser.red.service.persistence.management.v1.processor.exception.NotFo import com.iqser.red.service.persistence.management.v1.processor.service.AnalysisFlagsCalculationService; import com.iqser.red.service.persistence.management.v1.processor.service.CommentService; import com.iqser.red.service.persistence.management.v1.processor.service.DictionaryManagementService; +import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService; import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService; -import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ForceRedactionPersistenceService; @@ -24,6 +24,8 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.RecategorizationPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.RemoveRedactionPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ResizeRedactionPersistenceService; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AddRedactionRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ForceRedactionRequest; @@ -33,8 +35,6 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.RecategorizationRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.RemoveRedactionRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ResizeRedactionRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; @@ -58,7 +58,7 @@ public class ManualRedactionService { FileStatusService fileStatusService; ManualRedactionProviderService manualRedactionProviderService; AnalysisFlagsCalculationService analysisFlagsCalculationService; - RedactionLogService redactionLogService; + EntityLogService entityLogService; DictionaryManagementService dictionaryManagementService; HashFunction hashFunction = Hashing.murmur3_128(); ManualRedactionDictionaryUpdateHandler manualRedactionDictionaryUpdateHandler; @@ -242,7 +242,7 @@ public class ManualRedactionService { List response = new ArrayList<>(); - RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); + EntityLog entityLog = entityLogService.getEntityLog(dossierId, fileId); for (ResizeRedactionRequest resizeRedactionRequest : resizeRedactionRequests) { @@ -259,7 +259,7 @@ public class ManualRedactionService { Set typeIdsOfModifiedDictionaries = manualRedactionDictionaryUpdateHandler.updateDictionaryForResizeRedactions(dossierId, fileId, resizeRedaction, - getRedactionLogEntry(redactionLog, resizeRedaction.getId().getAnnotationId())); + getEntityLogEntry(entityLog, resizeRedaction.getId().getAnnotationId())); resizeRedactionPersistenceService.updateStatus(resizeRedaction.getId().getFileId(), resizeRedaction.getId().getAnnotationId(), @@ -294,13 +294,13 @@ public class ManualRedactionService { } - private RedactionLogEntry getRedactionLogEntry(RedactionLog redactionLog, String annotationId) { + private EntityLogEntry getEntityLogEntry(EntityLog entityLog, String annotationId) { - return redactionLog.getRedactionLogEntry() + return entityLog.getEntityLogEntry() .stream() .filter(entry -> entry.getId().equals(annotationId)) .findFirst() - .orElseThrow(() -> new NotFoundException("Annotation does not exist in redaction log.")); + .orElseThrow(() -> new NotFoundException("Annotation does not exist in entity log.")); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionUndoService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionUndoService.java index e9b3ee9e5..cfa5324b4 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionUndoService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionUndoService.java @@ -22,8 +22,8 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.annotati import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity; import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; import com.iqser.red.service.persistence.management.v1.processor.service.AnalysisFlagsCalculationService; +import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService; import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService; -import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService; @@ -33,6 +33,8 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.RemoveRedactionPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ResizeRedactionPersistenceService; import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.IdRemoval; @@ -44,8 +46,6 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ManualRedactionWrapperModel; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity; import lombok.AccessLevel; @@ -68,7 +68,7 @@ public class ManualRedactionUndoService { ForceRedactionPersistenceService forceRedactionPersistenceService; LegalBasisChangePersistenceService legalBasisChangePersistenceService; ResizeRedactionPersistenceService resizeRedactionPersistenceService; - RedactionLogService redactionLogService; + EntityLogService entityLogService; ManualRedactionDictionaryUpdateHandler manualRedactionDictionaryUpdateHandler; @@ -191,11 +191,11 @@ public class ManualRedactionUndoService { private void deleteRecategorization(String dossierId, String fileId, List annotationIds) { dossierPersistenceService.getAndValidateDossier(dossierId); - RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); + EntityLog entityLog = entityLogService.getEntityLog(dossierId, fileId); for (var annotationId : annotationIds) { ManualRecategorizationEntity recategorizationEntity = recategorizationPersistenceService.findRecategorization(fileId, annotationId); - String originalValue = getRedactionLogEntry(redactionLog, annotationId).getValue(); + String originalValue = getEntityLogEntry(entityLog, annotationId).getValue(); manualRedactionDictionaryUpdateHandler.revertRemoveFromDictionary(originalValue, dossierId, fileId, recategorizationEntity.getTypeIdsOfDictionariesWithDelete()); manualRedactionDictionaryUpdateHandler.revertAddToDictionary(originalValue, DictionaryEntryType.ENTRY, @@ -265,12 +265,12 @@ public class ManualRedactionUndoService { private void deleteRemoveRedaction(String dossierId, String fileId, List annotationIds) { dossierPersistenceService.getAndValidateDossier(dossierId); - RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); + EntityLog entityLog = entityLogService.getEntityLog(dossierId, fileId); for (String annotationId : annotationIds) { IdRemovalEntity removeRedaction = removeRedactionPersistenceService.findRemoveRedaction(fileId, annotationId); - String originalValue = getRedactionLogEntry(redactionLog, annotationId).getValue(); + String originalValue = getEntityLogEntry(entityLog, annotationId).getValue(); boolean dictionaryChanged = manualRedactionDictionaryUpdateHandler.revertRemoveFromDictionary(originalValue, dossierId, fileId, removeRedaction); removeRedactionPersistenceService.updateStatus(fileId, annotationId, removeRedaction.getStatus(), dictionaryChanged, Collections.emptySet()); removeRedactionPersistenceService.softDelete(fileId, annotationId, OffsetDateTime.now()); @@ -317,13 +317,13 @@ public class ManualRedactionUndoService { } - private RedactionLogEntry getRedactionLogEntry(RedactionLog redactionLog, String annotationId) { + private EntityLogEntry getEntityLogEntry(EntityLog entityLog, String annotationId) { - return redactionLog.getRedactionLogEntry() + return entityLog.getEntityLogEntry() .stream() .filter(entry -> entry.getId().equals(annotationId)) .findFirst() - .orElseThrow(() -> new NotFoundException("Annotation does not exist in redaction log.")); + .orElseThrow(() -> new NotFoundException("Annotation does not exist in entity log.")); } diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/service/FileTesterAndProvider.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/service/FileTesterAndProvider.java index 7b29b3b3d..306e0871c 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/service/FileTesterAndProvider.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/service/FileTesterAndProvider.java @@ -18,12 +18,13 @@ import com.iqser.red.service.persistence.management.v1.processor.service.FileMan import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService; import com.iqser.red.service.persistence.service.v1.api.shared.model.AnalyzeResult; import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryState; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.AddFileRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.section.SectionGrid; import lombok.SneakyThrows; @@ -65,9 +66,9 @@ public class FileTesterAndProvider { fileManagementStorageService.storeJSONObject(dossier.getId(), file.getFileId(), - FileType.REDACTION_LOG, - new RedactionLog(1, 1, List.of(RedactionLogEntry.builder().id("annotationId").type("manual").value("value entry").build()), null, 0, 0, 0, 0)); - fileManagementStorageService.storeJSONObject(dossier.getId(), file.getFileId(), FileType.SECTION_GRID, new SectionGrid()); + FileType.ENTITY_LOG, + new EntityLog(1, 1, List.of(EntityLogEntry.builder().id("annotationId").type("manual").value("value entry").entryType(EntryType.ENTITY).state(EntryState.APPLIED).build()), null, 0, 0, 0, 0)); + fileManagementStorageService.storeObject(dossier.getId(), file.getFileId(), FileType.ORIGIN, new ByteArrayInputStream(objectMapper.writeValueAsBytes("bytes of the file"))); return file; diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTest.java index c34ae8152..f136a7e17 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTest.java @@ -71,7 +71,7 @@ public class DossierTest extends AbstractPersistenceServerServiceTest { public void testDossierRaceCondition() { var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); - dossierTemplateTesterAndProvider.provideDefaultColors(dossierTemplate.getDossierTemplateId()); + dossierTemplateTesterAndProvider.provideDefaultColors(dossierTemplate.getId()); IntStream.range(0, 10).parallel().forEach(x -> dossierTesterAndProvider.provideTestDossier(dossierTemplate, "race condition dossier: " + x)); var allDossiers = dossierClient.getDossiers(true, true); var dossierCount = allDossiers.size(); @@ -84,8 +84,8 @@ public class DossierTest extends AbstractPersistenceServerServiceTest { public void testCreateDuplicateDossier() { var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); - dossierTemplateTesterAndProvider.provideDefaultColors(dossierTemplate.getDossierTemplateId()); - IntStream.range(0, 8).parallel().forEach(x -> { + dossierTemplateTesterAndProvider.provideDefaultColors(dossierTemplate.getId()); + IntStream.range(0, 4).parallel().forEach(x -> { try { dossierTesterAndProvider.provideTestDossier(dossierTemplate, "sameNameDossier"); } catch (Exception e) { @@ -105,7 +105,7 @@ public class DossierTest extends AbstractPersistenceServerServiceTest { var dossier = dossierTesterAndProvider.provideTestDossier(); - var returnedTypes = dictionaryClient.getAllTypes(dossier.getDossierTemplateId(), dossier.getDossierId(), false); + var returnedTypes = dictionaryClient.getAllTypes(dossier.getDossierTemplateId(), dossier.getId(), false); assertThat(returnedTypes.getTypes().size()).isEqualTo(0); var watermark = new WatermarkModel(); diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java index 0ba5e750a..a8c9993b9 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java @@ -28,7 +28,6 @@ import com.iqser.red.service.peristence.v1.server.integration.client.FileClient; import com.iqser.red.service.peristence.v1.server.integration.client.FileManagementClient; import com.iqser.red.service.peristence.v1.server.integration.client.ManualRedactionClient; import com.iqser.red.service.peristence.v1.server.integration.client.ReanalysisClient; -import com.iqser.red.service.peristence.v1.server.integration.client.RedactionLogClient; import com.iqser.red.service.peristence.v1.server.integration.client.UploadClient; import com.iqser.red.service.peristence.v1.server.integration.client.ViewedPagesClient; import com.iqser.red.service.peristence.v1.server.integration.service.DossierTemplateTesterAndProvider; @@ -47,6 +46,10 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.FileUploadR import com.iqser.red.service.persistence.service.v1.api.shared.model.PageExclusionRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.PageRange; import com.iqser.red.service.persistence.service.v1.api.shared.model.ViewedPagesRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryState; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType; import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileAttributeConfig; @@ -60,8 +63,6 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.Forc import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RecategorizationRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequestModel; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; import feign.FeignException; import lombok.SneakyThrows; @@ -95,9 +96,6 @@ public class FileTest extends AbstractPersistenceServerServiceTest { @Autowired private ViewedPagesClient viewedPagesClient; - @Autowired - private RedactionLogClient redactionLogClient; - @Autowired private FileAttributeClient fileAttributeClient; @@ -203,7 +201,6 @@ public class FileTest extends AbstractPersistenceServerServiceTest { fileClient.setStatusUnderReview(dossier.getId(), file.getId(), userId); reanalysisClient.excludePages(dossier.getId(), file.getId(), new PageExclusionRequest(List.of(new PageRange(1, 1)))); - var redactionLog = redactionLogClient.getRedactionLog(dossier.getId(), file.getId(), null, false, true); assertThat(fileClient.getDossierStatus(dossier.getId()).size()).isEqualTo(1); var loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId()); @@ -361,11 +358,10 @@ public class FileTest extends AbstractPersistenceServerServiceTest { var type = typeProvider.testAndProvideType(dossierTemplate, null, "manual"); var annotationId = "imagine_this_makes_sense"; - RedactionLog redactionLog = new RedactionLog(); - RedactionLogEntry redactionLogEntry = RedactionLogEntry.builder().type(type.getType()).id(annotationId).build(); - redactionLog.getRedactionLogEntry().add(redactionLogEntry); + EntityLog entityLog = new EntityLog(1, 1, + List.of(EntityLogEntry.builder().id(annotationId).type(type.getType()).value("value entry").state(EntryState.APPLIED).entryType(EntryType.ENTITY).build()), null, 0, 0, 0, 0); - when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog); + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(entityLog); assertThat(fileClient.getDossierStatus(dossier.getId()).size()).isEqualTo(1); @@ -569,18 +565,14 @@ public class FileTest extends AbstractPersistenceServerServiceTest { assertThat(loadedFile.getLastReviewer()).isNull(); assertThat(loadedFile.getLastApprover()).isNull(); - Exception exception = Assertions.assertThrows(FeignException.BadRequest.class, () -> { - fileClient.setStatusUnderReview(dossier.getId(), file.getId(), null); - }); + Exception exception = Assertions.assertThrows(FeignException.BadRequest.class, () -> fileClient.setStatusUnderReview(dossier.getId(), file.getId(), null)); String expectedMessage = "File is already unassigned!"; String actualMessage = exception.getMessage(); assertThat(actualMessage).contains(expectedMessage); - exception = Assertions.assertThrows(FeignException.BadRequest.class, () -> { - fileClient.setStatusUnderReview(dossier.getId(), file.getId(), user2); - }); + exception = Assertions.assertThrows(FeignException.BadRequest.class, () -> fileClient.setStatusUnderReview(dossier.getId(), file.getId(), user2)); expectedMessage = "User must be dossier member"; actualMessage = exception.getMessage(); diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java index 4f667a6d8..0898b2921 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java @@ -25,12 +25,16 @@ import com.iqser.red.service.peristence.v1.server.integration.service.TypeProvid import com.iqser.red.service.peristence.v1.server.integration.service.UserProvider; import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest; import com.iqser.red.service.persistence.management.v1.processor.service.DictionaryManagementService; +import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService; import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; -import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.EntryPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.redactionlog.RedactionRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.Dictionary; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryState; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Rectangle; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType; @@ -38,8 +42,6 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddR import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RecategorizationRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequestModel; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; import feign.FeignException; @@ -82,7 +84,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { private InternalDictionaryClient internalDictionaryClient; @Autowired - private RedactionLogService redactionLogService; + private EntityLogService entityLogService; @Autowired private DictionaryManagementService dictionaryManagementService; @@ -101,26 +103,26 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var type = typeProvider.testAndProvideType(dossierTemplate, null, "type", true); assertThat(type.isDossierDictionaryOnly()).isTrue(); - dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), false, dossier.getDossierId(), DictionaryEntryType.ENTRY); + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), false, dossier.getId(), DictionaryEntryType.ENTRY); - var redactionLog = new RedactionLog(1, + var entityLog = new EntityLog(1, 1, - List.of(RedactionLogEntry.builder().id("AnnotationId").type(type.getType()).value("Luke Skywalker").isDictionaryEntry(true).build()), + List.of(EntityLogEntry.builder().id("AnnotationId").type(type.getType()).value("Luke Skywalker").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(true).build()), null, 0, 0, 0, 0); - fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog); + fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.ENTITY_LOG, entityLog); - when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog); + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(entityLog); Assertions.assertThrows(FeignException.Forbidden.class, () -> manualRedactionClient.removeRedactionBulk(dossier.getId(), file.getId(), Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build())));//.get(0); - var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId()), null); + var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getId()), null); assertThat(dossierTemplateDictionary.getEntries().size()).isZero(); } @@ -151,7 +153,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .sourceId("SourceId") .build()))); - var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId()), null); + var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getId()), null); assertThat(dossierTemplateDictionary.getEntries().size()).isZero(); } @@ -166,9 +168,9 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var type = typeProvider.testAndProvideType(dossierTemplate); - dictionaryClient.deleteEntries(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), dossier.getDossierId(), DictionaryEntryType.ENTRY); + dictionaryClient.deleteEntries(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), dossier.getId(), DictionaryEntryType.ENTRY); - var dossierDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId(), dossier.getDossierId()), null); + var dossierDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getId(), dossier.getId()), null); assertThat(dossierDictionary.getEntries().size()).isEqualTo(1); assertThat(dossierDictionary.getEntries().get(0).isDeleted()).isTrue(); @@ -187,11 +189,11 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .sourceId("SourceId") .build())); - dossierDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId(), dossier.getDossierId()), null); + dossierDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getId(), dossier.getId()), null); assertThat(dossierDictionary.getEntries().size()).isEqualTo(1); assertThat(dossierDictionary.getEntries().get(0).isDeleted()).isFalse(); - var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId()), null); + var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getId()), null); assertThat(dossierTemplateDictionary.getEntries().size()).isEqualTo(1); assertThat(dossierTemplateDictionary.getEntries().get(0).isDeleted()).isFalse(); @@ -221,11 +223,11 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .sourceId("SourceId") .build())); - var dossierDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId(), dossier.getDossierId()), null); + var dossierDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getId(), dossier.getId()), null); assertThat(dossierDictionary.getEntries().size()).isEqualTo(1); assertThat(dossierDictionary.getEntries().get(0).isDeleted()).isFalse(); - var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId()), null); + var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getId()), null); assertThat(dossierTemplateDictionary.getEntries().isEmpty()).isTrue(); } @@ -244,25 +246,25 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { entries.add("Darth Vader"); dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), entries, false, null, DictionaryEntryType.ENTRY); - dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), false, dossier.getDossierId(), DictionaryEntryType.ENTRY); + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), false, dossier.getId(), DictionaryEntryType.ENTRY); Dictionary dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder("Luke Skywalker", "Darth Vader"); - Dictionary dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + Dictionary dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getId()); assertThat(dossierDictionary.getEntries()).containsExactlyInAnyOrder("Luke Skywalker"); - var redactionLog = new RedactionLog(1, + var entityLog = new EntityLog(1, 1, - List.of(RedactionLogEntry.builder().id("AnnotationId").type("test").value("Luke Skywalker").isDictionaryEntry(true).build()), + List.of(EntityLogEntry.builder().id("AnnotationId").type("test").value("Luke Skywalker").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(true).build()), null, 0, 0, 0, 0); - fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog); + fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.ENTITY_LOG, entityLog); - when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog); + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(entityLog); manualRedactionClient.removeRedactionBulk(dossier.getId(), file.getId(), @@ -270,14 +272,14 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder("Darth Vader"); - dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getId()); assertThat(dossierDictionary.getEntries()).isEmpty(); - manualRedactionClient.undo(dossier.getDossierId(), file.getFileId(), Set.of("AnnotationId")); + manualRedactionClient.undo(dossier.getId(), file.getFileId(), Set.of("AnnotationId")); dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder("Luke Skywalker", "Darth Vader"); - dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getId()); assertThat(dossierDictionary.getEntries()).containsExactlyInAnyOrder("Luke Skywalker"); } @@ -298,27 +300,27 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { //FIXME should be created on the fly. // CreateTypeValue dossierDictionaryType = MagicConverter.convert(type, CreateTypeValue.class); -// dictionaryClient.addType(dossierDictionaryType, dossier.getDossierId()); +// dictionaryClient.addType(dossierDictionaryType, dossier.getId()); - var redactionLog = new RedactionLog(1, + var entityLog = new EntityLog(1, 1, - List.of(RedactionLogEntry.builder().id("AnnotationId").type("test").value("Luke Skywalker").isDictionaryEntry(true).build()), + List.of(EntityLogEntry.builder().id("AnnotationId").type("test").value("Luke Skywalker").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(true).build()), null, 0, 0, 0, 0); - fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog); + fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.ENTITY_LOG, entityLog); - when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog); + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(entityLog); manualRedactionClient.removeRedactionBulk(dossier.getId(), file.getId(), Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId").removeFromDictionary(true).build())).get(0); - var dossierDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId(), dossier.getDossierId()), null); + var dossierDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getId(), dossier.getId()), null); - var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId()), null); + var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getId()), null); assertThat(dossierTemplateDictionary.getEntries().size()).isEqualTo(2); assertThat(dossierTemplateDictionary.getEntries().stream().filter(e -> e.getValue().equals("Luke Skywalker")).findFirst().get().isDeleted()).isFalse(); @@ -338,30 +340,30 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { //FIXME should be created on the fly. // CreateTypeValue dossierDictionaryType = MagicConverter.convert(type, CreateTypeValue.class); -// dictionaryClient.addType(dossierDictionaryType, dossier.getDossierId()); - dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), false, dossier.getDossierId(), DictionaryEntryType.ENTRY); +// dictionaryClient.addType(dossierDictionaryType, dossier.getId()); + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), false, dossier.getId(), DictionaryEntryType.ENTRY); - var redactionLog = new RedactionLog(1, + var entityLog = new EntityLog(1, 1, - List.of(RedactionLogEntry.builder().id("AnnotationId").type("test").value("Luke Skywalker").isDictionaryEntry(true).isDossierDictionaryEntry(true).build()), + List.of(EntityLogEntry.builder().id("AnnotationId").type("test").value("Luke Skywalker").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(true).build()), null, 0, 0, 0, 0); - fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog); + fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.ENTITY_LOG, entityLog); - when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog); + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(entityLog); manualRedactionClient.removeRedactionBulk(dossier.getId(), file.getId(), Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build())).get(0); - var dossierDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId(), dossier.getDossierId()), null); + var dossierDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getId(), dossier.getId()), null); assertThat(dossierDictionary.getEntries().size()).isEqualTo(1); assertThat(dossierDictionary.getEntries().get(0).isDeleted()).isTrue(); - var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getDossierTemplateId()), null); + var dossierTemplateDictionary = internalDictionaryClient.getDictionaryForType(toTypeId(type.getType(), dossierTemplate.getId()), null); assertThat(dossierTemplateDictionary.getEntries().size()).isEqualTo(0); } @@ -411,48 +413,54 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .sourceId("SourceId") .build(); - var addRedactions = manualRedactionClient.addRedactionBulk(dossier1.getDossierId(), file1.getId(), Set.of(redactionDos, redactionDosTempDict)); - var loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId()); + var addRedactions = manualRedactionClient.addRedactionBulk(dossier1.getId(), file1.getId(), Set.of(redactionDos, redactionDosTempDict)); + var loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getId(), file1.getFileId()); - var redactionLog1 = new RedactionLog(1, + var entityLog1 = new EntityLog(1, 1, - List.of(RedactionLogEntry.builder() + List.of(EntityLogEntry.builder() .id(addRedactions.get(0).getAnnotationId()) .type(typeDosDict.getType()) .value("test redaction in dossier") - .isDossierDictionaryEntry(true) + .dossierDictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) .build(), - RedactionLogEntry.builder() + EntityLogEntry.builder() .id(addRedactions.get(1).getAnnotationId()) .type(typeDosTempDict.getType()) .value("test redaction in dossier template") - .isDictionaryEntry(true) + .dictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) .build()), null, 0, 0, 0, 0); - fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.REDACTION_LOG, redactionLog1); - var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build(); - when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId())).thenReturn(redactionLog1); + fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.ENTITY_LOG, entityLog1); + var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getId()).fileId(file1.getFileId()).dossierTemplateId(file1.getId()).build(); + when(entityLogService.getEntityLog(file1.getId(), file1.getFileId())).thenReturn(entityLog1); - var redactionLog2 = new RedactionLog(1, + var entityLog2 = new EntityLog(1, 1, - List.of(RedactionLogEntry.builder() + List.of(EntityLogEntry.builder() .id(addRedactions.get(1).getAnnotationId()) .type(typeDosTempDict.getType()) .value("test redaction in dossier template") - .isDictionaryEntry(true) + .dictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) .build()), null, 0, 0, 0, 0); - fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.REDACTION_LOG, redactionLog2); - var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build(); - when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId())).thenReturn(redactionLog2); + fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.ENTITY_LOG, entityLog2); + var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getId()).fileId(file2.getFileId()).dossierTemplateId(file2.getId()).build(); + when(entityLogService.getEntityLog(file2.getId(), file2.getFileId())).thenReturn(entityLog2); // resize redaction in dossier 1 var resizeRedactionDosAndAddToAllDos = ResizeRedactionRequestModel.builder() @@ -463,53 +471,53 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .addToAllDossiers(true) .build(); - manualRedactionClient.resizeRedactionBulk(dossier1.getDossierId(), file1.getFileId(), Set.of(resizeRedactionDosAndAddToAllDos)); + manualRedactionClient.resizeRedactionBulk(dossier1.getId(), file1.getFileId(), Set.of(resizeRedactionDosAndAddToAllDos)); - loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId()); + loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getId(), file1.getFileId()); assertThat(loadedRedactionsFile1.getResizeRedactions()).hasSize(1); assertThat(loadedRedactionsFile1.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier dictionary"); - var dictEntries = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getDossierTemplateId(), + var dictEntries = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getId(), "test redaction in dossier dictionary", DictionaryEntryType.ENTRY); assertThat(dictEntries.stream().filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier dictionary"))).isNotEmpty(); - var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId()); + var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getId(), dossier1.getId()); assertThat(dictionaryOfTypeDosDictInDossier1.getEntries()).hasSize(1); assertThat(dictionaryOfTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier"); - var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId()); + var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getId(), dossier2.getId()); assertThat(dictionaryOfTypeDosDictInDossier2.getEntries()).isEmpty(); - var dictionaryOfTypeDosDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossierTemplate.getDossierTemplateId(), null); + var dictionaryOfTypeDosDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossierTemplate.getId(), null); assertThat(dictionaryOfTypeDosDictInDossierTemplate.getEntries()).hasSize(1); assertThat(dictionaryOfTypeDosDictInDossierTemplate.getEntries().get(0)).isEqualTo("test redaction in dossier dictionary"); - var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId()); + var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getId(), dossier1.getId()); assertThat(dictionaryOfTypeDosTempDictInDossier1.getEntries()).isEmpty(); - var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId()); + var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getId(), dossier2.getId()); assertThat(dictionaryOfTypeDosTempDictInDossier2.getEntries()).isEmpty(); - var dictionaryOfTypeDosTempDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossierTemplate.getDossierTemplateId(), null); + var dictionaryOfTypeDosTempDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossierTemplate.getId(), null); assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries()).hasSize(1); assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries().get(0)).isEqualTo("test redaction in dossier template"); - var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId()); + var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getId(), dossier1.getId()); assertThat(mergedDictForTypeDosDictInDossier1.getEntries()).hasSize(2); assertThat(mergedDictForTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier"); assertThat(mergedDictForTypeDosDictInDossier1.getEntries().get(1)).isEqualTo("test redaction in dossier dictionary"); - var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId()); + var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getId(), dossier1.getId()); assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier template"); - var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId()); + var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getId(), dossier2.getId()); assertThat(mergedDictForTypeDosDictInDossier2.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier dictionary"); - var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId()); + var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getId(), dossier2.getId()); assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier template"); } @@ -560,48 +568,52 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .sourceId("SourceId") .build(); - var addRedactions = manualRedactionClient.addRedactionBulk(dossier1.getDossierId(), file1.getId(), Set.of(redactionDos, redactionDosTempDict)); - var loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId()); + var addRedactions = manualRedactionClient.addRedactionBulk(dossier1.getId(), file1.getId(), Set.of(redactionDos, redactionDosTempDict)); + var loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getId(), file1.getFileId()); - var redactionLog1 = new RedactionLog(1, + var entityLog1 = new EntityLog(1, 1, - List.of(RedactionLogEntry.builder() + List.of(EntityLogEntry.builder() .id(addRedactions.get(0).getAnnotationId()) .type(typeDosDict.getType()) .value("test redaction in dossier yayy") - .isDossierDictionaryEntry(true) + .dossierDictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) .build(), - RedactionLogEntry.builder() + EntityLogEntry.builder() .id(addRedactions.get(1).getAnnotationId()) .type(typeDosTempDict.getType()) .value("test redaction in dossier template yayy") - .isDictionaryEntry(true) + .dictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) .build()), null, 0, 0, 0, 0); - fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.REDACTION_LOG, redactionLog1); - var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build(); - when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId())).thenReturn(redactionLog1); + fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.ENTITY_LOG, entityLog1); + var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getId()).fileId(file1.getFileId()).dossierTemplateId(file1.getId()).build(); + when(entityLogService.getEntityLog(file1.getId(), file1.getFileId())).thenReturn(entityLog1); - var redactionLog2 = new RedactionLog(1, + var entityLog2 = new EntityLog(1, 1, - List.of(RedactionLogEntry.builder() + List.of(EntityLogEntry.builder() .id(addRedactions.get(1).getAnnotationId()) .type(typeDosTempDict.getType()) .value("test redaction in dossier template yayy") - .isDictionaryEntry(true) + .dictionaryEntry(true) .build()), null, 0, 0, 0, 0); - fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.REDACTION_LOG, redactionLog2); - var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build(); - when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId())).thenReturn(redactionLog2); + fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.ENTITY_LOG, entityLog2); + var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getId()).fileId(file2.getFileId()).dossierTemplateId(file2.getId()).build(); + when(entityLogService.getEntityLog(file2.getId(), file2.getFileId())).thenReturn(entityLog2); // resize redaction in dossier 1 var resizeRedactionDosAndAddToAllDos = ResizeRedactionRequestModel.builder() @@ -612,60 +624,60 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .addToAllDossiers(true) .build(); - manualRedactionClient.resizeRedactionBulk(dossier1.getDossierId(), file1.getFileId(), Set.of(resizeRedactionDosAndAddToAllDos)); + manualRedactionClient.resizeRedactionBulk(dossier1.getId(), file1.getFileId(), Set.of(resizeRedactionDosAndAddToAllDos)); - loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId()); + loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getId(), file1.getFileId()); assertThat(loadedRedactionsFile1.getResizeRedactions()).hasSize(1); assertThat(loadedRedactionsFile1.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier"); - var dictEntriesOldValue = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getDossierTemplateId(), + var dictEntriesOldValue = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getId(), "test redaction in dossier yayy", DictionaryEntryType.ENTRY); assertThat(dictEntriesOldValue.stream() .filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier yayy") && dictionaryEntry.isDeleted())).hasSize(1); assertThat(dictEntriesOldValue.stream() .filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier yayy") && !dictionaryEntry.isDeleted())).hasSize(1); - var dictEntriesNewValue = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getDossierTemplateId(), + var dictEntriesNewValue = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getId(), "test redaction in dossier", DictionaryEntryType.ENTRY); assertThat(dictEntriesNewValue.stream().filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier"))).isNotEmpty(); - var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId()); + var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getId(), dossier1.getId()); assertThat(dictionaryOfTypeDosDictInDossier1.getEntries()).hasSize(1); assertThat(dictionaryOfTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier yayy"); - var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId()); + var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getId(), dossier2.getId()); assertThat(dictionaryOfTypeDosDictInDossier2.getEntries()).isEmpty(); - var dictionaryOfTypeDosDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossierTemplate.getDossierTemplateId(), null); + var dictionaryOfTypeDosDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossierTemplate.getId(), null); assertThat(dictionaryOfTypeDosDictInDossierTemplate.getEntries()).hasSize(1); assertThat(dictionaryOfTypeDosDictInDossierTemplate.getEntries().get(0)).isEqualTo("test redaction in dossier"); - var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId()); + var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getId(), dossier1.getId()); assertThat(dictionaryOfTypeDosTempDictInDossier1.getEntries()).isEmpty(); - var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId()); + var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getId(), dossier2.getId()); assertThat(dictionaryOfTypeDosTempDictInDossier2.getEntries()).isEmpty(); - var dictionaryOfTypeDosTempDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossierTemplate.getDossierTemplateId(), null); + var dictionaryOfTypeDosTempDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossierTemplate.getId(), null); assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries()).hasSize(1); assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries().get(0)).isEqualTo("test redaction in dossier template yayy"); - var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId()); + var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getId(), dossier1.getId()); assertThat(mergedDictForTypeDosDictInDossier1.getEntries()).hasSize(2); assertThat(mergedDictForTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier"); assertThat(mergedDictForTypeDosDictInDossier1.getEntries().get(1)).isEqualTo("test redaction in dossier yayy"); - var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId()); + var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getId(), dossier1.getId()); assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier template yayy"); - var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId()); + var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getId(), dossier2.getId()); assertThat(mergedDictForTypeDosDictInDossier2.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier"); - var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId()); + var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getId(), dossier2.getId()); assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier template yayy"); } @@ -716,47 +728,53 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .sourceId("SourceId") .build(); - var addRedactions = manualRedactionClient.addRedactionBulk(dossier1.getDossierId(), file1.getId(), Set.of(redactionDos, redactionDosTempDict)); + var addRedactions = manualRedactionClient.addRedactionBulk(dossier1.getId(), file1.getId(), Set.of(redactionDos, redactionDosTempDict)); - var redactionLog1 = new RedactionLog(1, + var entityLog1 = new EntityLog(1, 1, - List.of(RedactionLogEntry.builder() + List.of(EntityLogEntry.builder() .id(addRedactions.get(0).getAnnotationId()) .type(typeDosDict.getType()) .value("test redaction in dossier") - .isDossierDictionaryEntry(true) + .dossierDictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) .build(), - RedactionLogEntry.builder() + EntityLogEntry.builder() .id(addRedactions.get(1).getAnnotationId()) .type(typeDosTempDict.getType()) .value("test redaction in dossier template") - .isDictionaryEntry(true) + .dictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) .build()), null, 0, 0, 0, 0); - fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.REDACTION_LOG, redactionLog1); - var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build(); - when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId())).thenReturn(redactionLog1); + fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.ENTITY_LOG, entityLog1); + var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getId()).fileId(file1.getFileId()).dossierTemplateId(file1.getId()).build(); + when(entityLogService.getEntityLog(file1.getId(), file1.getFileId())).thenReturn(entityLog1); - var redactionLog2 = new RedactionLog(1, + var entityLog2 = new EntityLog(1, 1, - List.of(RedactionLogEntry.builder() + List.of(EntityLogEntry.builder() .id(addRedactions.get(1).getAnnotationId()) .type(typeDosTempDict.getType()) .value("test redaction in dossier template") - .isDictionaryEntry(true) + .dictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) .build()), null, 0, 0, 0, 0); - fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.REDACTION_LOG, redactionLog2); - var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build(); - when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId())).thenReturn(redactionLog2); + fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.ENTITY_LOG, entityLog2); + var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getId()).fileId(file2.getFileId()).dossierTemplateId(file2.getId()).build(); + when(entityLogService.getEntityLog(file2.getId(), file2.getFileId())).thenReturn(entityLog2); // resize redaction in dossier dict var resizeRedactionDosTemp = ResizeRedactionRequestModel.builder() @@ -767,52 +785,52 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .addToAllDossiers(true) .build(); - var resizeRedactions = manualRedactionClient.resizeRedactionBulk(dossier2.getDossierId(), file2.getFileId(), Set.of(resizeRedactionDosTemp)); + var resizeRedactions = manualRedactionClient.resizeRedactionBulk(dossier2.getId(), file2.getFileId(), Set.of(resizeRedactionDosTemp)); - var loadedRedactionsFile2 = manualRedactionClient.getManualRedactions(file2.getDossierId(), file2.getFileId()); + var loadedRedactionsFile2 = manualRedactionClient.getManualRedactions(file2.getId(), file2.getFileId()); assertThat(loadedRedactionsFile2.getResizeRedactions()).hasSize(1); assertThat(loadedRedactionsFile2.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier template dictionary"); - var dictEntries = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getDossierTemplateId(), + var dictEntries = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getId(), "test redaction in dossier template dictionary", DictionaryEntryType.ENTRY); assertThat(dictEntries.stream().filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier template dictionary"))).hasSize(1); - var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId()); + var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getId(), dossier1.getId()); assertThat(dictionaryOfTypeDosDictInDossier1.getEntries()).hasSize(1); assertThat(dictionaryOfTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier"); - var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId()); + var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getId(), dossier2.getId()); assertThat(dictionaryOfTypeDosDictInDossier2.getEntries()).isEmpty(); - var dictionaryOfTypeDosDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossierTemplate.getDossierTemplateId(), null); + var dictionaryOfTypeDosDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossierTemplate.getId(), null); assertThat(dictionaryOfTypeDosDictInDossierTemplate.getEntries()).isEmpty(); - var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId()); + var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getId(), dossier1.getId()); assertThat(dictionaryOfTypeDosTempDictInDossier1.getEntries()).isEmpty(); - var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId()); + var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getId(), dossier2.getId()); assertThat(dictionaryOfTypeDosTempDictInDossier2.getEntries()).isEmpty(); - var dictionaryOfTypeDosTempDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossierTemplate.getDossierTemplateId(), null); + var dictionaryOfTypeDosTempDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossierTemplate.getId(), null); assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries()).hasSize(2); assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries().get(0)).isEqualTo("test redaction in dossier template"); assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries().get(1)).isEqualTo("test redaction in dossier template dictionary"); - var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId()); + var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getId(), dossier1.getId()); assertThat(mergedDictForTypeDosDictInDossier1.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier"); - var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId()); + var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getId(), dossier1.getId()); assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries()).hasSize(2); assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier template"); assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries().get(1)).isEqualTo("test redaction in dossier template dictionary"); - var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId()); + var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getId(), dossier2.getId()); assertThat(mergedDictForTypeDosDictInDossier2.getEntries()).isEmpty(); - var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId()); + var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getId(), dossier2.getId()); assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries()).hasSize(2); assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier template"); assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries().get(1)).isEqualTo("test redaction in dossier template dictionary"); @@ -864,47 +882,53 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .sourceId("SourceId") .build(); - var addRedactions = manualRedactionClient.addRedactionBulk(dossier1.getDossierId(), file1.getId(), Set.of(redactionDos, redactionDosTempDict)); + var addRedactions = manualRedactionClient.addRedactionBulk(dossier1.getId(), file1.getId(), Set.of(redactionDos, redactionDosTempDict)); - var redactionLog1 = new RedactionLog(1, + var entityLog1 = new EntityLog(1, 1, - List.of(RedactionLogEntry.builder() + List.of(EntityLogEntry.builder() .id(addRedactions.get(0).getAnnotationId()) .type(typeDosDict.getType()) .value("test redaction in dossier yayy") - .isDossierDictionaryEntry(true) + .dossierDictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) .build(), - RedactionLogEntry.builder() + EntityLogEntry.builder() .id(addRedactions.get(1).getAnnotationId()) .type(typeDosTempDict.getType()) .value("test redaction in dossier template yayy") - .isDictionaryEntry(true) + .dictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) .build()), null, 0, 0, 0, 0); - fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.REDACTION_LOG, redactionLog1); - var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build(); - when(redactionLogService.getRedactionLog(file1.getDossierId(), file1.getFileId())).thenReturn(redactionLog1); + fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.ENTITY_LOG, entityLog1); + var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getId()).fileId(file1.getFileId()).dossierTemplateId(file1.getId()).build(); + when(entityLogService.getEntityLog(file1.getId(), file1.getFileId())).thenReturn(entityLog1); - var redactionLog2 = new RedactionLog(1, + var entityLog2 = new EntityLog(1, 1, - List.of(RedactionLogEntry.builder() + List.of(EntityLogEntry.builder() .id(addRedactions.get(1).getAnnotationId()) .type(typeDosTempDict.getType()) .value("test redaction in dossier template yayy") - .isDictionaryEntry(true) + .dictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) .build()), null, 0, 0, 0, 0); - fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.REDACTION_LOG, redactionLog2); - var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build(); - when(redactionLogService.getRedactionLog(file2.getDossierId(), file2.getFileId())).thenReturn(redactionLog2); + fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.ENTITY_LOG, entityLog2); + var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getId()).fileId(file2.getFileId()).dossierTemplateId(file2.getId()).build(); + when(entityLogService.getEntityLog(file2.getId(), file2.getFileId())).thenReturn(entityLog2); // resize redaction in dossier dict var resizeRedactionDosTemp = ResizeRedactionRequestModel.builder() @@ -915,57 +939,57 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .addToAllDossiers(true) .build(); - var resizeRedactions = manualRedactionClient.resizeRedactionBulk(dossier2.getDossierId(), file2.getFileId(), Set.of(resizeRedactionDosTemp)); + var resizeRedactions = manualRedactionClient.resizeRedactionBulk(dossier2.getId(), file2.getFileId(), Set.of(resizeRedactionDosTemp)); - var loadedRedactionsFile2 = manualRedactionClient.getManualRedactions(file2.getDossierId(), file2.getFileId()); + var loadedRedactionsFile2 = manualRedactionClient.getManualRedactions(file2.getId(), file2.getFileId()); assertThat(loadedRedactionsFile2.getResizeRedactions()).hasSize(1); assertThat(loadedRedactionsFile2.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier template"); - var dictEntriesOldValue = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getDossierTemplateId(), + var dictEntriesOldValue = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getId(), "test redaction in dossier template yayy", DictionaryEntryType.ENTRY); assertThat(dictEntriesOldValue.stream() .filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier template yayy") && dictionaryEntry.isDeleted())).hasSize(3); assertThat(dictEntriesOldValue.stream() .filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier template yayy") && !dictionaryEntry.isDeleted())).isEmpty(); - var dictEntriesNewValue = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getDossierTemplateId(), + var dictEntriesNewValue = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getId(), "test redaction in dossier template", DictionaryEntryType.ENTRY); assertThat(dictEntriesNewValue.stream().filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier template"))).isNotEmpty(); - var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId()); + var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getId(), dossier1.getId()); assertThat(dictionaryOfTypeDosDictInDossier1.getEntries()).hasSize(1); assertThat(dictionaryOfTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier yayy"); - var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId()); + var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getId(), dossier2.getId()); assertThat(dictionaryOfTypeDosDictInDossier2.getEntries()).isEmpty(); - var dictionaryOfTypeDosDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossierTemplate.getDossierTemplateId(), null); + var dictionaryOfTypeDosDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossierTemplate.getId(), null); assertThat(dictionaryOfTypeDosDictInDossierTemplate.getEntries()).isEmpty(); - var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId()); + var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getId(), dossier1.getId()); assertThat(dictionaryOfTypeDosTempDictInDossier1.getEntries()).isEmpty(); - var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId()); + var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getId(), dossier2.getId()); assertThat(dictionaryOfTypeDosTempDictInDossier2.getEntries()).isEmpty(); - var dictionaryOfTypeDosTempDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossierTemplate.getDossierTemplateId(), null); + var dictionaryOfTypeDosTempDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossierTemplate.getId(), null); assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries()).hasSize(1); assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries().get(0)).isEqualTo("test redaction in dossier template"); - var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId()); + var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getId(), dossier1.getId()); assertThat(mergedDictForTypeDosDictInDossier1.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier yayy"); - var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getDossierId()); + var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getId(), dossier1.getId()); assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier template"); - var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId()); + var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getId(), dossier2.getId()); assertThat(mergedDictForTypeDosDictInDossier2.getEntries()).isEmpty(); - var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getDossierId()); + var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getId(), dossier2.getId()); assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier template"); } @@ -989,30 +1013,30 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { entries.add(darthVader); dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), entries, false, null, DictionaryEntryType.ENTRY); - dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of(lukeSkywalker), false, dossier.getDossierId(), DictionaryEntryType.ENTRY); + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of(lukeSkywalker), false, dossier.getId(), DictionaryEntryType.ENTRY); Dictionary dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker, darthVader); - Dictionary dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + Dictionary dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getId()); assertThat(dossierDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker); Dictionary dossierTemplateDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary2.getEntries()).isEmpty(); - Dictionary dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + Dictionary dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getId()); assertThat(dossierDictionary2.getEntries()).isEmpty(); var annotationId = "AnnotationId"; - var redactionLog = new RedactionLog(1, + var entityLog = new EntityLog(1, 1, - List.of(RedactionLogEntry.builder().id(annotationId).type(type.getType()).value(lukeSkywalker).isDictionaryEntry(true).build()), + List.of(EntityLogEntry.builder().id(annotationId).type(type.getType()).value(lukeSkywalker).dictionaryEntry(true).entryType(EntryType.ENTITY).state(EntryState.APPLIED).build()), null, 0, 0, 0, 0); - fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog); + fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.ENTITY_LOG, entityLog); - when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog); + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(entityLog); manualRedactionClient.recategorizeBulk(dossier.getId(), file.getId(), @@ -1020,24 +1044,24 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder(darthVader); - dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getId()); assertThat(dossierDictionary.getEntries()).isEmpty(); dossierTemplateDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary2.getEntries()).containsExactlyInAnyOrder(lukeSkywalker); - dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getId()); assertThat(dossierDictionary2.getEntries()).isEmpty(); - manualRedactionClient.undo(dossier.getDossierId(), file.getFileId(), Set.of(annotationId)); + manualRedactionClient.undo(dossier.getId(), file.getFileId(), Set.of(annotationId)); dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker, darthVader); - dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getId()); assertThat(dossierDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker); dossierTemplateDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary2.getEntries()).isEmpty(); - dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getId()); assertThat(dossierDictionary2.getEntries()).isEmpty(); } @@ -1059,30 +1083,30 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { entries.add(lukeSkywalker); entries.add(darthVader); - dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), entries, false, dossier.getDossierId(), DictionaryEntryType.ENTRY); + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), entries, false, dossier.getId(), DictionaryEntryType.ENTRY); Dictionary dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary.getEntries()).isEmpty(); - Dictionary dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + Dictionary dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getId()); assertThat(dossierDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker, darthVader); Dictionary dossierTemplateDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary2.getEntries()).isEmpty(); - Dictionary dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + Dictionary dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getId()); assertThat(dossierDictionary2.getEntries()).isEmpty(); var annotationId = "AnnotationId"; - var redactionLog = new RedactionLog(1, + var entityLog = new EntityLog(1, 1, - List.of(RedactionLogEntry.builder().id(annotationId).type(type.getType()).value(lukeSkywalker).isDictionaryEntry(true).build()), + List.of(EntityLogEntry.builder().id(annotationId).type(type.getType()).value(lukeSkywalker).dictionaryEntry(true).entryType(EntryType.ENTITY).state(EntryState.APPLIED).build()), null, 0, 0, 0, 0); - fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog); + fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.ENTITY_LOG, entityLog); - when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(redactionLog); + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(entityLog); manualRedactionClient.recategorizeBulk(dossier.getId(), file.getId(), @@ -1090,24 +1114,24 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary.getEntries()).isEmpty(); - dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getId()); assertThat(dossierDictionary.getEntries()).containsExactlyInAnyOrder(darthVader); dossierTemplateDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary2.getEntries()).isEmpty(); - dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getId()); assertThat(dossierDictionary2.getEntries()).containsExactlyInAnyOrder(lukeSkywalker); - manualRedactionClient.undo(dossier.getDossierId(), file.getFileId(), Set.of(annotationId)); + manualRedactionClient.undo(dossier.getId(), file.getFileId(), Set.of(annotationId)); dossierTemplateDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary.getEntries()).isEmpty(); - dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + dossierDictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getId()); assertThat(dossierDictionary.getEntries()).containsExactlyInAnyOrder(lukeSkywalker, darthVader); dossierTemplateDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), null); assertThat(dossierTemplateDictionary2.getEntries()).isEmpty(); - dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + dossierDictionary2 = dictionaryClient.getDictionaryForType(type2.getType(), type.getDossierTemplateId(), dossier.getId()); assertThat(dossierDictionary2.getEntries()).isEmpty(); } diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java index 4eccc8560..aca12bcb0 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java @@ -12,16 +12,16 @@ import com.iqser.red.service.persistence.management.v1.processor.client.tenantus import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.ApplicationConfigurationEntity; import com.iqser.red.service.persistence.management.v1.processor.roles.ApplicationRoles; import com.iqser.red.service.persistence.management.v1.processor.service.ApplicationConfigService; +import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService; import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; -import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.*; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.*; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.EntryRepository; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.FalsePositiveEntryRepository; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.FalseRecommendationEntryRepository; import com.iqser.red.service.persistence.management.v1.processor.service.users.UserService; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.ApplicationConfig; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog; import com.iqser.red.service.redaction.v1.model.DroolsSyntaxValidation; import com.iqser.red.storage.commons.service.StorageService; import com.iqser.red.storage.commons.utils.FileSystemBackedStorageService; @@ -92,7 +92,7 @@ public abstract class AbstractPersistenceServerServiceTest { @MockBean protected SearchClient searchClient; @MockBean - protected RedactionLogService redactionLogService; + protected EntityLogService entityLogService; @MockBean protected PDFTronClient pdfTronRedactionClient; @Autowired @@ -245,7 +245,7 @@ public abstract class AbstractPersistenceServerServiceTest { // doNothing().when(pdfTronRedactionClient).testDigitalCurrentSignature(Mockito.any()); when(amqpAdmin.getQueueInfo(Mockito.any())).thenReturn(null); - when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(new RedactionLog(1, 1, Lists.newArrayList(), null, 0, 0, 0, 0)); + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(new EntityLog(1, 1, Lists.newArrayList(), null, 0, 0, 0, 0)); when(redactionClient.testRules(Mockito.any())).thenReturn(DroolsSyntaxValidation.builder().droolsSyntaxErrorMessages(Collections.emptyList()).build()); } -- 2.47.2 From 8d0cafd0c89a682166bbd39d662e2054c4452988 Mon Sep 17 00:00:00 2001 From: Corina Olariu Date: Tue, 17 Oct 2023 14:14:23 +0300 Subject: [PATCH 13/96] RED-7763 - Use EntityLog in tests in persistence-service - updates junit tests --- .../tests/ManualRedactionTest.java | 110 +++++++++--------- 1 file changed, 56 insertions(+), 54 deletions(-) diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java index 0898b2921..19d3b44ef 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java @@ -414,7 +414,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .build(); var addRedactions = manualRedactionClient.addRedactionBulk(dossier1.getId(), file1.getId(), Set.of(redactionDos, redactionDosTempDict)); - var loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getId(), file1.getFileId()); + var loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId()); var entityLog1 = new EntityLog(1, 1, @@ -440,8 +440,8 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0, 0); fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.ENTITY_LOG, entityLog1); - var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getId()).fileId(file1.getFileId()).dossierTemplateId(file1.getId()).build(); - when(entityLogService.getEntityLog(file1.getId(), file1.getFileId())).thenReturn(entityLog1); + var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build(); + when(entityLogService.getEntityLog(file1.getDossierId(), file1.getFileId())).thenReturn(entityLog1); var entityLog2 = new EntityLog(1, 1, @@ -459,8 +459,8 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0, 0); fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.ENTITY_LOG, entityLog2); - var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getId()).fileId(file2.getFileId()).dossierTemplateId(file2.getId()).build(); - when(entityLogService.getEntityLog(file2.getId(), file2.getFileId())).thenReturn(entityLog2); + var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build(); + when(entityLogService.getEntityLog(file2.getDossierId(), file2.getFileId())).thenReturn(entityLog2); // resize redaction in dossier 1 var resizeRedactionDosAndAddToAllDos = ResizeRedactionRequestModel.builder() @@ -473,7 +473,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { manualRedactionClient.resizeRedactionBulk(dossier1.getId(), file1.getFileId(), Set.of(resizeRedactionDosAndAddToAllDos)); - loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getId(), file1.getFileId()); + loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId()); assertThat(loadedRedactionsFile1.getResizeRedactions()).hasSize(1); assertThat(loadedRedactionsFile1.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier dictionary"); @@ -483,41 +483,41 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { DictionaryEntryType.ENTRY); assertThat(dictEntries.stream().filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier dictionary"))).isNotEmpty(); - var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getId(), dossier1.getId()); + var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getId()); assertThat(dictionaryOfTypeDosDictInDossier1.getEntries()).hasSize(1); assertThat(dictionaryOfTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier"); - var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getId(), dossier2.getId()); + var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getId()); assertThat(dictionaryOfTypeDosDictInDossier2.getEntries()).isEmpty(); var dictionaryOfTypeDosDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossierTemplate.getId(), null); assertThat(dictionaryOfTypeDosDictInDossierTemplate.getEntries()).hasSize(1); assertThat(dictionaryOfTypeDosDictInDossierTemplate.getEntries().get(0)).isEqualTo("test redaction in dossier dictionary"); - var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getId(), dossier1.getId()); + var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getId()); assertThat(dictionaryOfTypeDosTempDictInDossier1.getEntries()).isEmpty(); - var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getId(), dossier2.getId()); + var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getId()); assertThat(dictionaryOfTypeDosTempDictInDossier2.getEntries()).isEmpty(); var dictionaryOfTypeDosTempDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossierTemplate.getId(), null); assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries()).hasSize(1); assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries().get(0)).isEqualTo("test redaction in dossier template"); - var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getId(), dossier1.getId()); + var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getId()); assertThat(mergedDictForTypeDosDictInDossier1.getEntries()).hasSize(2); assertThat(mergedDictForTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier"); assertThat(mergedDictForTypeDosDictInDossier1.getEntries().get(1)).isEqualTo("test redaction in dossier dictionary"); - var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getId(), dossier1.getId()); + var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getId()); assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier template"); - var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getId(), dossier2.getId()); + var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getId()); assertThat(mergedDictForTypeDosDictInDossier2.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier dictionary"); - var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getId(), dossier2.getId()); + var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getId()); assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier template"); } @@ -569,7 +569,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .build(); var addRedactions = manualRedactionClient.addRedactionBulk(dossier1.getId(), file1.getId(), Set.of(redactionDos, redactionDosTempDict)); - var loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getId(), file1.getFileId()); + var loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId()); var entityLog1 = new EntityLog(1, 1, @@ -595,8 +595,8 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0, 0); fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.ENTITY_LOG, entityLog1); - var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getId()).fileId(file1.getFileId()).dossierTemplateId(file1.getId()).build(); - when(entityLogService.getEntityLog(file1.getId(), file1.getFileId())).thenReturn(entityLog1); + var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build(); + when(entityLogService.getEntityLog(file1.getDossierId(), file1.getFileId())).thenReturn(entityLog1); var entityLog2 = new EntityLog(1, 1, @@ -605,6 +605,8 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .type(typeDosTempDict.getType()) .value("test redaction in dossier template yayy") .dictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) .build()), null, 0, @@ -612,8 +614,8 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0, 0); fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.ENTITY_LOG, entityLog2); - var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getId()).fileId(file2.getFileId()).dossierTemplateId(file2.getId()).build(); - when(entityLogService.getEntityLog(file2.getId(), file2.getFileId())).thenReturn(entityLog2); + var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build(); + when(entityLogService.getEntityLog(file2.getDossierId(), file2.getFileId())).thenReturn(entityLog2); // resize redaction in dossier 1 var resizeRedactionDosAndAddToAllDos = ResizeRedactionRequestModel.builder() @@ -626,7 +628,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { manualRedactionClient.resizeRedactionBulk(dossier1.getId(), file1.getFileId(), Set.of(resizeRedactionDosAndAddToAllDos)); - loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getId(), file1.getFileId()); + loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId()); assertThat(loadedRedactionsFile1.getResizeRedactions()).hasSize(1); assertThat(loadedRedactionsFile1.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier"); @@ -643,41 +645,41 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { DictionaryEntryType.ENTRY); assertThat(dictEntriesNewValue.stream().filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier"))).isNotEmpty(); - var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getId(), dossier1.getId()); + var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getId()); assertThat(dictionaryOfTypeDosDictInDossier1.getEntries()).hasSize(1); assertThat(dictionaryOfTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier yayy"); - var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getId(), dossier2.getId()); + var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getId()); assertThat(dictionaryOfTypeDosDictInDossier2.getEntries()).isEmpty(); var dictionaryOfTypeDosDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossierTemplate.getId(), null); assertThat(dictionaryOfTypeDosDictInDossierTemplate.getEntries()).hasSize(1); assertThat(dictionaryOfTypeDosDictInDossierTemplate.getEntries().get(0)).isEqualTo("test redaction in dossier"); - var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getId(), dossier1.getId()); + var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getId()); assertThat(dictionaryOfTypeDosTempDictInDossier1.getEntries()).isEmpty(); - var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getId(), dossier2.getId()); + var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getId()); assertThat(dictionaryOfTypeDosTempDictInDossier2.getEntries()).isEmpty(); var dictionaryOfTypeDosTempDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossierTemplate.getId(), null); assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries()).hasSize(1); assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries().get(0)).isEqualTo("test redaction in dossier template yayy"); - var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getId(), dossier1.getId()); + var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getId()); assertThat(mergedDictForTypeDosDictInDossier1.getEntries()).hasSize(2); assertThat(mergedDictForTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier"); assertThat(mergedDictForTypeDosDictInDossier1.getEntries().get(1)).isEqualTo("test redaction in dossier yayy"); - var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getId(), dossier1.getId()); + var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getId()); assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier template yayy"); - var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getId(), dossier2.getId()); + var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getId()); assertThat(mergedDictForTypeDosDictInDossier2.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier"); - var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getId(), dossier2.getId()); + var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getId()); assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier template yayy"); } @@ -754,8 +756,8 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0, 0); fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.ENTITY_LOG, entityLog1); - var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getId()).fileId(file1.getFileId()).dossierTemplateId(file1.getId()).build(); - when(entityLogService.getEntityLog(file1.getId(), file1.getFileId())).thenReturn(entityLog1); + var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build(); + when(entityLogService.getEntityLog(file1.getDossierId(), file1.getFileId())).thenReturn(entityLog1); var entityLog2 = new EntityLog(1, 1, @@ -773,8 +775,8 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0, 0); fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.ENTITY_LOG, entityLog2); - var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getId()).fileId(file2.getFileId()).dossierTemplateId(file2.getId()).build(); - when(entityLogService.getEntityLog(file2.getId(), file2.getFileId())).thenReturn(entityLog2); + var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build(); + when(entityLogService.getEntityLog(file2.getDossierId(), file2.getFileId())).thenReturn(entityLog2); // resize redaction in dossier dict var resizeRedactionDosTemp = ResizeRedactionRequestModel.builder() @@ -787,7 +789,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var resizeRedactions = manualRedactionClient.resizeRedactionBulk(dossier2.getId(), file2.getFileId(), Set.of(resizeRedactionDosTemp)); - var loadedRedactionsFile2 = manualRedactionClient.getManualRedactions(file2.getId(), file2.getFileId()); + var loadedRedactionsFile2 = manualRedactionClient.getManualRedactions(file2.getDossierId(), file2.getFileId()); assertThat(loadedRedactionsFile2.getResizeRedactions()).hasSize(1); assertThat(loadedRedactionsFile2.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier template dictionary"); @@ -797,20 +799,20 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { DictionaryEntryType.ENTRY); assertThat(dictEntries.stream().filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier template dictionary"))).hasSize(1); - var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getId(), dossier1.getId()); + var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getId()); assertThat(dictionaryOfTypeDosDictInDossier1.getEntries()).hasSize(1); assertThat(dictionaryOfTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier"); - var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getId(), dossier2.getId()); + var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getId()); assertThat(dictionaryOfTypeDosDictInDossier2.getEntries()).isEmpty(); var dictionaryOfTypeDosDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossierTemplate.getId(), null); assertThat(dictionaryOfTypeDosDictInDossierTemplate.getEntries()).isEmpty(); - var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getId(), dossier1.getId()); + var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getId()); assertThat(dictionaryOfTypeDosTempDictInDossier1.getEntries()).isEmpty(); - var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getId(), dossier2.getId()); + var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getId()); assertThat(dictionaryOfTypeDosTempDictInDossier2.getEntries()).isEmpty(); var dictionaryOfTypeDosTempDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossierTemplate.getId(), null); @@ -818,19 +820,19 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries().get(0)).isEqualTo("test redaction in dossier template"); assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries().get(1)).isEqualTo("test redaction in dossier template dictionary"); - var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getId(), dossier1.getId()); + var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getId()); assertThat(mergedDictForTypeDosDictInDossier1.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier"); - var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getId(), dossier1.getId()); + var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getId()); assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries()).hasSize(2); assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier template"); assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries().get(1)).isEqualTo("test redaction in dossier template dictionary"); - var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getId(), dossier2.getId()); + var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getId()); assertThat(mergedDictForTypeDosDictInDossier2.getEntries()).isEmpty(); - var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getId(), dossier2.getId()); + var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getId()); assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries()).hasSize(2); assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier template"); assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries().get(1)).isEqualTo("test redaction in dossier template dictionary"); @@ -908,8 +910,8 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0, 0); fileManagementStorageService.storeJSONObject(dossier1.getId(), file1.getId(), FileType.ENTITY_LOG, entityLog1); - var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getId()).fileId(file1.getFileId()).dossierTemplateId(file1.getId()).build(); - when(entityLogService.getEntityLog(file1.getId(), file1.getFileId())).thenReturn(entityLog1); + var redactionRequest1 = RedactionRequest.builder().dossierId(file1.getDossierId()).fileId(file1.getFileId()).dossierTemplateId(file1.getDossierTemplateId()).build(); + when(entityLogService.getEntityLog(file1.getDossierId(), file1.getFileId())).thenReturn(entityLog1); var entityLog2 = new EntityLog(1, 1, @@ -927,8 +929,8 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { 0, 0); fileManagementStorageService.storeJSONObject(dossier2.getId(), file2.getId(), FileType.ENTITY_LOG, entityLog2); - var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getId()).fileId(file2.getFileId()).dossierTemplateId(file2.getId()).build(); - when(entityLogService.getEntityLog(file2.getId(), file2.getFileId())).thenReturn(entityLog2); + var redactionRequest2 = RedactionRequest.builder().dossierId(file2.getDossierId()).fileId(file2.getFileId()).dossierTemplateId(file2.getDossierTemplateId()).build(); + when(entityLogService.getEntityLog(file2.getDossierId(), file2.getFileId())).thenReturn(entityLog2); // resize redaction in dossier dict var resizeRedactionDosTemp = ResizeRedactionRequestModel.builder() @@ -941,7 +943,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var resizeRedactions = manualRedactionClient.resizeRedactionBulk(dossier2.getId(), file2.getFileId(), Set.of(resizeRedactionDosTemp)); - var loadedRedactionsFile2 = manualRedactionClient.getManualRedactions(file2.getId(), file2.getFileId()); + var loadedRedactionsFile2 = manualRedactionClient.getManualRedactions(file2.getDossierId(), file2.getFileId()); assertThat(loadedRedactionsFile2.getResizeRedactions()).hasSize(1); assertThat(loadedRedactionsFile2.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier template"); @@ -958,38 +960,38 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { DictionaryEntryType.ENTRY); assertThat(dictEntriesNewValue.stream().filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier template"))).isNotEmpty(); - var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getId(), dossier1.getId()); + var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getId()); assertThat(dictionaryOfTypeDosDictInDossier1.getEntries()).hasSize(1); assertThat(dictionaryOfTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier yayy"); - var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getId(), dossier2.getId()); + var dictionaryOfTypeDosDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getId()); assertThat(dictionaryOfTypeDosDictInDossier2.getEntries()).isEmpty(); var dictionaryOfTypeDosDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossierTemplate.getId(), null); assertThat(dictionaryOfTypeDosDictInDossierTemplate.getEntries()).isEmpty(); - var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getId(), dossier1.getId()); + var dictionaryOfTypeDosTempDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getId()); assertThat(dictionaryOfTypeDosTempDictInDossier1.getEntries()).isEmpty(); - var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getId(), dossier2.getId()); + var dictionaryOfTypeDosTempDictInDossier2 = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getId()); assertThat(dictionaryOfTypeDosTempDictInDossier2.getEntries()).isEmpty(); var dictionaryOfTypeDosTempDictInDossierTemplate = dictionaryClient.getDictionaryForType(typeDosTempDict.getType(), dossierTemplate.getId(), null); assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries()).hasSize(1); assertThat(dictionaryOfTypeDosTempDictInDossierTemplate.getEntries().get(0)).isEqualTo("test redaction in dossier template"); - var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getId(), dossier1.getId()); + var mergedDictForTypeDosDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getId()); assertThat(mergedDictForTypeDosDictInDossier1.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier yayy"); - var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getId(), dossier1.getId()); + var mergedDictForTypeDosTempDictInDossier1 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier1.getDossierTemplateId(), dossier1.getId()); assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosTempDictInDossier1.getEntries().get(0)).isEqualTo("test redaction in dossier template"); - var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getId(), dossier2.getId()); + var mergedDictForTypeDosDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosDict.getType(), dossier2.getDossierTemplateId(), dossier2.getId()); assertThat(mergedDictForTypeDosDictInDossier2.getEntries()).isEmpty(); - var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getId(), dossier2.getId()); + var mergedDictForTypeDosTempDictInDossier2 = dictionaryClient.getMergedDictionaries(typeDosTempDict.getType(), dossier2.getDossierTemplateId(), dossier2.getId()); assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries()).hasSize(1); assertThat(mergedDictForTypeDosTempDictInDossier2.getEntries().get(0)).isEqualTo("test redaction in dossier template"); } -- 2.47.2 From 12cdc83ee3f71273f26fc665757c106f163ca4b1 Mon Sep 17 00:00:00 2001 From: Corina Olariu Date: Tue, 17 Oct 2023 14:52:10 +0300 Subject: [PATCH 14/96] RED-7763 - Use EntityLog in tests in persistence-service - remove unneeded migrations --- .../DeleteRemovedManualAddRedactions7.java | 73 --------- .../DictionaryToEntityMigration2.java | 89 ----------- .../migrations/EntityTypesMigration4.java | 74 --------- .../migrations/FileSizeMigration8.java | 66 -------- .../migration/migrations/IndexMigration1.java | 36 ----- .../ManualRedactionTypeMigration9.java | 84 ----------- .../migrations/MigrateHighlights3.java | 86 ----------- .../RemoveFalsePositiveManualRedactions6.java | 78 ---------- .../migrations/SimplifiedTextMigration12.java | 84 ----------- .../migrations/TypeToEntityMigration5.java | 142 ------------------ 10 files changed, 812 deletions(-) delete mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/DeleteRemovedManualAddRedactions7.java delete mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/DictionaryToEntityMigration2.java delete mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/EntityTypesMigration4.java delete mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/FileSizeMigration8.java delete mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/IndexMigration1.java delete mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/ManualRedactionTypeMigration9.java delete mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/MigrateHighlights3.java delete mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/RemoveFalsePositiveManualRedactions6.java delete mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/SimplifiedTextMigration12.java delete mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/TypeToEntityMigration5.java diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/DeleteRemovedManualAddRedactions7.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/DeleteRemovedManualAddRedactions7.java deleted file mode 100644 index 7ae908147..000000000 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/DeleteRemovedManualAddRedactions7.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.iqser.red.service.persistence.management.v1.processor.migration.migrations; - -import java.util.List; - -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.IdRemovalEntity; -import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity; -import com.iqser.red.service.persistence.management.v1.processor.migration.Migration; -import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionProviderService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.RemoveRedactionPersistenceService; - -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@Setter -@Service -public class DeleteRemovedManualAddRedactions7 extends Migration { - - private static final String NAME = "Delete removed ManualAddRedactions"; - private static final long VERSION = 7; - - @Autowired - private AddRedactionPersistenceService addRedactionPersistenceService; - - @Autowired - private RemoveRedactionPersistenceService removeRedactionPersistenceService; - - @Autowired - private ManualRedactionProviderService manualRedactionProviderService; - - - public DeleteRemovedManualAddRedactions7() { - - super(NAME, VERSION); - } - - - @Override - protected void migrate() { - - List addRedactions = addRedactionPersistenceService.findAllAddRedactions(); - - for (IdRemovalEntity idRemovalEntity : removeRedactionPersistenceService.findAllRemoveRedactions()) { - if (manualAddRedactionsContains(addRedactions, idRemovalEntity.getId().getAnnotationId())) { - log.info("hard delete ManualRedactions for file {} and annotation {}", idRemovalEntity.getId().getFileId(), idRemovalEntity.getId().getAnnotationId()); - manualRedactionProviderService.hardDeleteManualRedactions(idRemovalEntity.getId().getFileId(), idRemovalEntity.getId().getAnnotationId()); - } - } - - } - - - private boolean manualAddRedactionsContains(List addRedactions, String annotationId) { - - for (ManualRedactionEntryEntity manualRedactionEntryEntity : addRedactions) { - if (StringUtils.equals(annotationId, manualRedactionEntryEntity.getId().getAnnotationId())) { - return true; - } - } - return false; - } - -} - - - - - diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/DictionaryToEntityMigration2.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/DictionaryToEntityMigration2.java deleted file mode 100644 index 8c0f9f029..000000000 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/DictionaryToEntityMigration2.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.iqser.red.service.persistence.management.v1.processor.migration.migrations; - -import java.util.ArrayList; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.iqser.red.service.persistence.management.v1.processor.migration.Migration; -import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; - -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@Setter -@Service -public class DictionaryToEntityMigration2 extends Migration { - - private static final String NAME = "Migrate RedactionLogs remove false_positive and recommendation_ prefix"; - private static final long VERSION = 2; - - @Autowired - private DossierPersistenceService dossierPersistenceService; - - @Autowired - private FileStatusPersistenceService fileStatusPersistenceService; - - @Autowired - private FileManagementStorageService fileManagementStorageService; - - @Autowired - private ObjectMapper objectMapper; - - - public DictionaryToEntityMigration2() { - - super(NAME, VERSION); - } - - - @Override - protected void migrate() { - - var dossiers = dossierPersistenceService.findAllDossiers(); - dossiers.forEach(dossier -> { - var files = fileStatusPersistenceService.getStatusesForDossier(dossier.getId()); - log.info("Start migration of dossier {}", dossier.getId()); - files.forEach(file -> { - log.info("Start migration of file {}", file.getId()); - if (file.getHardDeletedTime() == null) { - - try { - var newRedactionLogEntries = new ArrayList(); - var redactionLog = fileManagementStorageService.getRedactionLog(dossier.getId(), file.getId()); - redactionLog.getRedactionLogEntry().forEach(entry -> { - - if (entry.getType().equals("false_positive")) { - log.info("skipping false_positive for dossier {} and file {}", dossier.getId(), file.getId()); - return; - } - - if (entry.getType().startsWith("recommendation_")) { - entry.setType(entry.getType().substring(15)); - entry.setRecommendation(true); - log.info("removed _recommendation for file {} and annotation {}", file.getId(), entry.getId()); - } - - newRedactionLogEntries.add(entry); - }); - - if (newRedactionLogEntries.size() != redactionLog.getRedactionLogEntry().size()) { - redactionLog.setRedactionLogEntry(newRedactionLogEntries); - fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.REDACTION_LOG, redactionLog); - log.info("Stored redactionLog for dossierId: {} and fileId: {}", dossier.getId(), file.getId()); - } - } catch (Exception e) { - log.info("redactionLog {} does not exsist", file.getId()); - } - } - }); - }); - } - -} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/EntityTypesMigration4.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/EntityTypesMigration4.java deleted file mode 100644 index e54b1664f..000000000 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/EntityTypesMigration4.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.iqser.red.service.persistence.management.v1.processor.migration.migrations; - -import java.util.List; -import java.util.Set; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.BaseDictionaryEntry; -import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.TypeEntity; -import com.iqser.red.service.persistence.management.v1.processor.migration.Migration; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.EntryPersistenceService; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType; - -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@Setter -@Service -public class EntityTypesMigration4 extends Migration { - - private static final String NAME = "Set flags systemManaged, autoHideSkipped and hasDictionary for all entity types"; - private static final long VERSION = 4; - - @Autowired - private DictionaryPersistenceService dictionaryPersistenceService; - - @Autowired - private EntryPersistenceService entryPersistenceService; - - - public EntityTypesMigration4() { - - super(NAME, VERSION); - } - - - @Override - protected void migrate() { - - Set systemManagedTypes = Set.of("ocr", "image", "logo", "signature", "formula", "imported_redaction", "dossier_redaction"); - Set autoHideSkippedTypes = Set.of("imported_redaction"); - - log.info("Will check all type entities and set systemManaged flag true for {}", systemManagedTypes); - log.info("Will check all type entities and set autoHideSkipped flag true for {}", autoHideSkippedTypes); - log.info("Will check all type entities and set hasDictionary flag true for types with entities"); - - List types = dictionaryPersistenceService.getAllTypes(false); - - for (TypeEntity type : types) { - if (type != null) { - - // Check if type is systemManaged - type.setSystemManaged(type.getType() != null && systemManagedTypes.contains(type.getType())); - - // Check if type is autoHideSkipped - type.setAutoHideSkipped(type.getType() != null && autoHideSkippedTypes.contains(type.getType())); - - // Check if type has dictionaries - List entries = entryPersistenceService.getEntries(type.getId(), DictionaryEntryType.ENTRY, null); - - type.setHasDictionary(entries != null && !entries.isEmpty()); - - } - } - - log.info("Save all types"); - dictionaryPersistenceService.saveAllTypes(types); - - } - -} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/FileSizeMigration8.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/FileSizeMigration8.java deleted file mode 100644 index 9992232e8..000000000 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/FileSizeMigration8.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.iqser.red.service.persistence.management.v1.processor.migration.migrations; - -import java.util.List; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.FileEntity; -import com.iqser.red.service.persistence.management.v1.processor.migration.Migration; -import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType; - -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@Setter -@Service -public class - -FileSizeMigration8 extends Migration { - - private static final String NAME = "Update file size"; - private static final long VERSION = 8; - - @Autowired - private FileStatusPersistenceService fileStatusPersistenceService; - - @Autowired - private FileManagementStorageService fileManagementStorageService; - - - public FileSizeMigration8() { - - super(NAME, VERSION); - } - - - @Override - protected void migrate() { - - List allFiles = fileStatusPersistenceService.getAllFiles(); - - log.info("Number of all files: {}", allFiles.size()); - - allFiles.forEach(file -> { - // not hard deleted - if (file.getHardDeletedTime() == null) { - try { - var originFile = fileManagementStorageService.getStoredObjectBytes(file.getDossierId(), file.getId(), FileType.ORIGIN); - fileStatusPersistenceService.updateFileSize(file.getId(), originFile.length); - } catch (Exception e) { - log.warn("Failed to load file bytes for file: {} in dossier {}. Error message: {} ", file.getId(), file.getDossierId(), e.getMessage()); - } - } - }); - - } - -} - - - - - diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/IndexMigration1.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/IndexMigration1.java deleted file mode 100644 index da5fb1e3e..000000000 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/IndexMigration1.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.iqser.red.service.persistence.management.v1.processor.migration.migrations; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.iqser.red.service.persistence.management.v1.processor.migration.Migration; -import com.iqser.red.service.persistence.management.v1.processor.service.IndexingService; - -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@Setter -@Service -public class IndexMigration1 extends Migration { - - private static final String NAME = "Recreate index and index all files"; - private static final long VERSION = 1; - @Autowired - private IndexingService indexingService; - - - public IndexMigration1() { - - super(NAME, VERSION); - } - - - @Override - protected void migrate() { - - log.info("Will call SearchService via queue to close, drop, recreate index and reindex all files"); - indexingService.reindex(null, null, true); - } - -} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/ManualRedactionTypeMigration9.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/ManualRedactionTypeMigration9.java deleted file mode 100644 index a5bbcad6f..000000000 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/ManualRedactionTypeMigration9.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.iqser.red.service.persistence.management.v1.processor.migration.migrations; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.iqser.red.service.persistence.management.v1.processor.migration.Migration; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierTemplateRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.TypeRepository; - -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@Setter -@Service -public class ManualRedactionTypeMigration9 extends Migration { - - private static final String NAME = "Add Manual Redaction Type"; - private static final long VERSION = 9; - private static final String MANUAL_TYPE = "manual"; - - @Autowired - private DictionaryPersistenceService dictionaryPersistenceService; - @Autowired - private DossierTemplateRepository dossierTemplateRepository; - @Autowired - private TypeRepository typeRepository; - - - public ManualRedactionTypeMigration9() { - - super(NAME, VERSION); - } - - - @Override - protected void migrate() { - - var allDossierTemplates = dossierTemplateRepository.findAll(); - - allDossierTemplates.forEach(dossierTemplateEntity -> { - - var entitiesForDossierTemplate = dictionaryPersistenceService.getAllTypesForDossierTemplate(dossierTemplateEntity.getId(), true); - - var manualType = entitiesForDossierTemplate.stream().filter(e -> MANUAL_TYPE.equals(e.getType())).findAny(); - manualType.ifPresent(typeEntity -> typeRepository.deleteById(typeEntity.getId())); - - var rank = 1; - for (var entity : entitiesForDossierTemplate) { - if (entity.getRank() > rank) { - rank = entity.getRank(); - } - } - rank += 1000; - - dictionaryPersistenceService.addType(MANUAL_TYPE, - dossierTemplateEntity.getId(), - "#9398a0", - "#c5d3eb", - "#c498fa", - rank, - false, - false, - false, - "Manual Redactions", - false, - "Manual Redactions", - null, - false, - true, - false, - true); - - }); - - } - -} - - - - - diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/MigrateHighlights3.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/MigrateHighlights3.java deleted file mode 100644 index cb49dc667..000000000 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/MigrateHighlights3.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.iqser.red.service.persistence.management.v1.processor.migration.migrations; - -import java.io.ByteArrayInputStream; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.iqser.red.service.persistence.management.v1.processor.migration.Migration; -import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; -import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType; - -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@Setter -@Service -public class MigrateHighlights3 extends Migration { - - private static final String NAME = "Migrate Highlights"; - private static final long VERSION = 3; - - @Autowired - private DossierPersistenceService dossierPersistenceService; - - @Autowired - private FileStatusPersistenceService fileStatusPersistenceService; - - @Autowired - private FileManagementStorageService fileManagementStorageService; - - @Autowired - private FileStatusService fileStatusService; - - - public MigrateHighlights3() { - - super(NAME, VERSION); - } - - - @Override - protected void migrate() { - - var dossiers = dossierPersistenceService.findAllDossiers(); - dossiers.forEach(dossier -> { - var files = fileStatusPersistenceService.getStatusesForDossier(dossier.getId()); - files.forEach(file -> { - if (file.getHardDeletedTime() == null) { - - try { - if (fileManagementStorageService.objectExists(dossier.getId(), file.getId(), FileType.ORIGIN)) { - var untouchedExists = fileManagementStorageService.objectExists(dossier.getId(), file.getId(), FileType.UNTOUCHED); - - if (!untouchedExists) { - var originExists = fileManagementStorageService.objectExists(dossier.getId(), file.getId(), FileType.ORIGIN); - - if (!originExists) { - log.warn("Invalid file {} / {} Neither untouched nor origin files exists!", dossier.getId(), file.getId()); - return; - } - - fileManagementStorageService.storeObject(dossier.getId(), - file.getId(), - FileType.UNTOUCHED, - new ByteArrayInputStream(fileManagementStorageService.getStoredObjectBytes(dossier.getId(), file.getId(), FileType.ORIGIN))); - - } - - fileStatusService.addToPreprocessingQueue(file.getId(), file.getDossierId(), file.getFilename()); - - } else { - log.warn("Invalid file: {} in dossier: {}. File Data ( PDF ) does not exist", file.getId(), file.getDossierId()); - } - } catch (Exception e) { - log.warn("Failed to extract text highlights for document: {}", file.getId()); - } - } - }); - }); - } - -} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/RemoveFalsePositiveManualRedactions6.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/RemoveFalsePositiveManualRedactions6.java deleted file mode 100644 index 4cfe4e15e..000000000 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/RemoveFalsePositiveManualRedactions6.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.iqser.red.service.persistence.management.v1.processor.migration.migrations; - -import java.util.ArrayList; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.iqser.red.service.persistence.management.v1.processor.migration.Migration; -import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService; - -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@Setter -@Service -public class RemoveFalsePositiveManualRedactions6 extends Migration { - - private static final String NAME = "Remove false positives manual redactions"; - private static final long VERSION = 6; - - @Autowired - private DossierPersistenceService dossierPersistenceService; - - @Autowired - private FileStatusPersistenceService fileStatusPersistenceService; - - @Autowired - private ManualRedactionService manualRedactionService; - - @Autowired - private AddRedactionPersistenceService addRedactionPersistenceService; - - - public RemoveFalsePositiveManualRedactions6() { - - super(NAME, VERSION); - } - - - @Override - protected void migrate() { - - var dossiers = dossierPersistenceService.findAllDossiers(); - dossiers.forEach(dossier -> { - var files = fileStatusPersistenceService.getStatusesForDossier(dossier.getId()); - files.forEach(file -> { - if (file.getHardDeletedTime() == null) { - var annotationIdsToRemove = new ArrayList(); - var manualRedactions = manualRedactionService.getManualRedactions( file.getId()); - - if (manualRedactions != null && manualRedactions.getEntriesToAdd() != null) { - manualRedactions.getEntriesToAdd().forEach(addRedaction -> { - if (addRedaction.getType().contains("false_positive")) { - annotationIdsToRemove.add(addRedaction.getAnnotationId()); - } - }); - } - - log.info("Hard deleting false positive annotations for file: {} / {}", file.getId(), annotationIdsToRemove); - - if (!annotationIdsToRemove.isEmpty()) { - annotationIdsToRemove.forEach(id -> addRedactionPersistenceService.hardDelete(file.getId(), id)); - } - } - }); - }); - } - -} - - - - - diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/SimplifiedTextMigration12.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/SimplifiedTextMigration12.java deleted file mode 100644 index 1040914bc..000000000 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/SimplifiedTextMigration12.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.iqser.red.service.persistence.management.v1.processor.migration.migrations; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.iqser.red.service.persistence.management.v1.processor.migration.Migration; -import com.iqser.red.service.persistence.management.v1.processor.migration.migrations.model.simplifiedtext.Text; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.utils.StorageIdUtils; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType; -import com.iqser.red.storage.commons.exception.StorageObjectDoesNotExist; -import com.iqser.red.storage.commons.service.StorageService; -import com.knecon.fforesight.tenantcommons.TenantContext; - -import lombok.Setter; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@Setter -@Service -public class SimplifiedTextMigration12 extends Migration { - - private static final String NAME = "Add simplified text file if missing"; - private static final long VERSION = 12; - - @Autowired - private DossierPersistenceService dossierPersistenceService; - - @Autowired - private FileStatusPersistenceService fileStatusPersistenceService; - - @Autowired - private StorageService storageService; - - - public SimplifiedTextMigration12() { - - super(NAME, VERSION); - } - - - @Override - protected void migrate() { - - var dossiers = dossierPersistenceService.findAllDossiers(); - dossiers.forEach(dossier -> { - if (dossier.getHardDeletedTime() == null) { - var files = fileStatusPersistenceService.getStatusesForDossier(dossier.getId()); - log.info("Start migration of dossier {}", dossier.getId()); - files.forEach(file -> { - if (file.getHardDeletedTime() == null) { - log.info("Start migration of file {}", file.getId()); - migrateFile(dossier.getId(), file.getId()); - log.info("Finished migration of file {}", file.getId()); - } - }); - log.info("Finished migration of dossier {}", dossier.getId()); - } - }); - } - - - @SneakyThrows - public void migrateFile(String dossierId, String fileId) { - - try { - - if (!storageService.objectExists(TenantContext.getTenantId(), StorageIdUtils.getStorageId(dossierId, fileId, FileType.SIMPLIFIED_TEXT))) { - var text = storageService.readJSONObject(TenantContext.getTenantId(), StorageIdUtils.getStorageId(dossierId, fileId, FileType.TEXT), Text.class); - storageService.storeJSONObject(TenantContext.getTenantId(), StorageIdUtils.getStorageId(dossierId, fileId, FileType.SIMPLIFIED_TEXT), text); - } - } catch (StorageObjectDoesNotExist e) { - log.warn("Text not found for dossier {} and file {}, ignoring....", dossierId, fileId); - } - } - -} - - - - - diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/TypeToEntityMigration5.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/TypeToEntityMigration5.java deleted file mode 100644 index d7348c5c2..000000000 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/TypeToEntityMigration5.java +++ /dev/null @@ -1,142 +0,0 @@ -package com.iqser.red.service.persistence.management.v1.processor.migration.migrations; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Locale; -import java.util.Set; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.BaseDictionaryEntry; -import com.iqser.red.service.persistence.management.v1.processor.migration.Migration; -import com.iqser.red.service.persistence.management.v1.processor.service.DictionaryManagementService; -import com.iqser.red.service.persistence.management.v1.processor.service.DictionaryService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.EntryPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierTemplateRepository; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType; - -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@Setter -@Service -public class TypeToEntityMigration5 extends Migration { - - private static final String NAME = "Migrate false positives, set recommendation color, remove unneeded dictionaries"; - private static final long VERSION = 5; - - @Autowired - private DictionaryPersistenceService dictionaryPersistenceService; - - @Autowired - private DossierTemplateRepository dossierTemplateRepository; - - @Autowired - private EntryPersistenceService entryPersistenceService; - - @Autowired - private DictionaryManagementService dictionaryManagementService; - - - public TypeToEntityMigration5() { - - super(NAME, VERSION); - } - - - @Override - protected void migrate() { - - var types = dictionaryPersistenceService.getAllTypes(false); - types.forEach(type -> type.setRecommendationHexColor("#8df06c")); - dictionaryPersistenceService.saveAllTypes(types); - - var dossierTemplates = dossierTemplateRepository.findAllWhereDeletedIsFalse(); - - dossierTemplates.forEach(dossierTemplate -> { - log.info("Starting false positive migration of dossierTemplate {}", dossierTemplate.getId()); - var typeIdsToDelete = new HashSet(); - var typesOfDossierTemplate = dictionaryPersistenceService.getAllTypes(false); - var falsePositive = typesOfDossierTemplate.stream().filter(t -> t.getType().equals("false_positive")).findFirst(); - if (falsePositive.isEmpty()) { - log.info("False positive type does no longer exist in dossierTemplate: {}. Skipping.", dossierTemplate.getName()); - return; - } - typeIdsToDelete.add(falsePositive.get().getId()); - var falsePositiveEntries = entryPersistenceService.getEntries(falsePositive.get().getId(), DictionaryEntryType.ENTRY, null) - .stream() - .map(BaseDictionaryEntry::getValue) - .collect(Collectors.toSet()); - log.info("False positive migration of dossierTemplate {} has {} false positive entries", dossierTemplate.getId(), falsePositiveEntries.size()); - - typesOfDossierTemplate.stream().filter(t -> !t.getType().equals("false_positive")).forEach(typeEntity -> { - log.info("Start processing type {}", typeEntity.getType()); - - if (typeEntity.getType().startsWith("recommendation_")) { - typeIdsToDelete.add(typeEntity.getId()); - log.info("Finished processing type {}", typeEntity.getType()); - return; - } - - var entries = entryPersistenceService.getEntries(typeEntity.getId(), DictionaryEntryType.ENTRY, null) - .stream() - .map(BaseDictionaryEntry::getValue) - .collect(Collectors.toSet()); - log.info("type {} has {} entries", typeEntity.getType(), entries); - - var typeFalsePositives = new HashSet(); - falsePositiveEntries.forEach(falsePositiveValue -> { - if (containsAnyWord(falsePositiveValue, entries, typeEntity.isCaseInsensitive())) { - typeFalsePositives.add(falsePositiveValue); - } - }); - - if (!typeFalsePositives.isEmpty()) { - dictionaryManagementService.addEntries(typeEntity.getId(), new ArrayList<>(typeFalsePositives), false, false, DictionaryEntryType.FALSE_POSITIVE); - log.info("Added {} for type {}", typeFalsePositives.size(), typeEntity.getType()); - } - log.info("Finished processing type {}", typeEntity.getType()); - }); - - typeIdsToDelete.forEach(typeIdToDelete -> dictionaryManagementService.deleteType(typeIdToDelete)); - log.info("Finished false positive migration of dossierTemplate {}", dossierTemplate.getId()); - }); - - } - - - public boolean containsAnyWord(String text, Set values, boolean isCaseInsensitive) { - - String inputString = isCaseInsensitive ? text.toLowerCase(Locale.ROOT) : text; - - for (String value : values) { - - String cleanValue = isCaseInsensitive ? value.toLowerCase(Locale.ROOT).trim() : value.trim(); - - int startIndex; - int stopIndex = 0; - do { - startIndex = inputString.indexOf(cleanValue, stopIndex); - stopIndex = startIndex + cleanValue.length(); - - if (startIndex > -1 && (startIndex == 0 || Character.isWhitespace(inputString.charAt(startIndex - 1)) || isSeparator(inputString.charAt(startIndex - 1))) && (stopIndex == inputString.length() || isSeparator( - inputString.charAt(stopIndex)))) { - return true; - } - } while (startIndex > -1); - } - return false; - } - - - private boolean isSeparator(char c) { - - return Character.isWhitespace(c) || Pattern.matches("\\p{Punct}", String.valueOf(c)) || c == '\"' || c == '‘' || c == '’'; - } - -} -- 2.47.2 From b0db74301958a0994cef25dc1d383ac63c089cf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominique=20Eifl=C3=A4nder?= Date: Wed, 18 Oct 2023 15:00:38 +0200 Subject: [PATCH 15/96] RED-7775: Fixed too many connection to database by scheduler, name connections in pg_stat_activity --- .../persistence-service-processor-v1/pom.xml | 4 ++-- .../src/main/resources/application.yaml | 7 ------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/pom.xml b/persistence-service-v1/persistence-service-processor-v1/pom.xml index f635cef86..eb209cca3 100644 --- a/persistence-service-v1/persistence-service-processor-v1/pom.xml +++ b/persistence-service-v1/persistence-service-processor-v1/pom.xml @@ -18,8 +18,8 @@ 0.4.0 0.5.0 0.18.0 - 0.6.0 - 0.12.0 + 0.8.0 + 0.13.0 diff --git a/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yaml b/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yaml index 48be66922..42d540984 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yaml +++ b/persistence-service-v1/persistence-service-server-v1/src/main/resources/application.yaml @@ -83,7 +83,6 @@ multitenancy: driverClassName: org.postgresql.Driver hikari: maximumPoolSize: 8 - minimum-idle: 5 data-source-properties: cachePrepStmts: true prepStmtCacheSize: 1000 @@ -124,12 +123,6 @@ fforesight: user-exchange: name: 'users-exchange' jobs: - datasource: - url: jdbc:postgresql://${PSQL_HOST:localhost}:${PSQL_PORT:5432}/${PSQL_DATABASE:master}?cachePrepStmts=true&useServerPrepStmts=true&rewriteBatchedStatements=true - driverClassName: org.postgresql.Driver - username: ${PSQL_USERNAME:fforesight} - password: ${PSQL_PASSWORD:fforesight} - platform: org.hibernate.dialect.PostgreSQL95Dialect enabled: true tenants: remote: true -- 2.47.2 From 7df20ee8bb7ed32b149a3b90043a973fb14e0466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominique=20Eifl=C3=A4nder?= Date: Thu, 19 Oct 2023 14:16:34 +0200 Subject: [PATCH 16/96] RED-7760: Fixed accidently renamed id that leads to not working liquibase migration --- .../changelog/tenant/26-application-config-table.changelog.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/26-application-config-table.changelog.yaml b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/26-application-config-table.changelog.yaml index 9dc01b784..51e8f97bc 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/26-application-config-table.changelog.yaml +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/26-application-config-table.changelog.yaml @@ -1,6 +1,6 @@ databaseChangeLog: - changeSet: - id: download_redaction_file_result + id: application-config-table author: corina (generated) changes: - createTable: -- 2.47.2 From ac7b05049d899e05a1cd9960dfe38b1fbb565f0f Mon Sep 17 00:00:00 2001 From: Andrei Isvoran Date: Fri, 20 Oct 2023 15:56:46 +0200 Subject: [PATCH 17/96] RED-7782 - Endpoint for unprocessed changes --- .../controller/ManualRedactionController.java | 6 +- .../resource/ManualRedactionResource.java | 8 +- .../ManualRedactionProviderService.java | 47 ++- .../ManualRedactionService.java | 4 +- .../AddRedactionPersistenceService.java | 9 +- .../ForceRedactionPersistenceService.java | 4 + .../LegalBasisChangePersistenceService.java | 11 +- .../RecategorizationPersistenceService.java | 4 + .../RemoveRedactionPersistenceService.java | 8 +- .../ResizeRedactionPersistenceService.java | 10 +- .../ForceRedactionRepository.java | 4 + .../LegalBasisChangeRepository.java | 4 + .../ManualRedactionRepository.java | 4 + .../RecategorizationRepository.java | 3 + .../RemoveRedactionRepository.java | 4 + .../ResizeRedactionRepository.java | 4 + .../tests/ManualRedactionTest.java | 350 +++++++++++++++++- 17 files changed, 443 insertions(+), 41 deletions(-) diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java index f3ae155ba..2315ca208 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java @@ -13,6 +13,7 @@ import java.util.Set; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService; @@ -105,9 +106,10 @@ public class ManualRedactionController implements ManualRedactionResource { @Override @PreAuthorize("hasAuthority('" + READ_MANUAL_REDACTIONS + "')") - public ManualRedactions getManualRedactions(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) { + public ManualRedactions getManualRedactions(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, + @RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean unprocessed) { - return manualRedactionService.getManualRedactions(fileId); + return manualRedactionService.getManualRedactions(fileId, unprocessed); } diff --git a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java index df1a6fa61..6ef93bec1 100644 --- a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java +++ b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java @@ -10,6 +10,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.CommentResponse; @@ -44,6 +45,8 @@ public interface ManualRedactionResource { String COMMENT_ID = "commentId"; String COMMENT_ID_PATH_VARIABLE = "/{" + COMMENT_ID + "}"; + String FALSE = "false"; + @ResponseStatus(value = HttpStatus.NO_CONTENT) @DeleteMapping(MANUAL_REDACTION_REST_PATH + "/bulk/undo" + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE) @@ -128,9 +131,10 @@ public interface ManualRedactionResource { @ResponseStatus(value = HttpStatus.OK) @GetMapping(value = MANUAL_REDACTION_REST_PATH + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(summary = "Returns the manual redactions", description = "None") + @Operation(summary = "Returns the manual redactions", description = "If the unprocessed flag is true then only the unprocessed manual redactions are returned. If the flag is false" + + "all manual redactions are returned. Default value for the flag is false.") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) - ManualRedactions getManualRedactions(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId); + ManualRedactions getManualRedactions(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean unprocessed); @ResponseStatus(value = HttpStatus.OK) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java index b683008e7..35b55aba0 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java @@ -50,25 +50,44 @@ public class ManualRedactionProviderService { private final LegalBasisChangePersistenceService legalBasisChangePersistenceService; private final ResizeRedactionPersistenceService resizeRedactionPersistenceService; - - @Transactional public ManualRedactions getManualRedactions(String fileId) { - Set entriesToAdd = convertEntriesToAdd(addRedactionPersistenceService.findAddRedactions(fileId, false)); + return getManualRedactions(fileId, false); + } - Set removals = convert(removeRedactionPersistenceService.findRemoveRedactions(fileId, false), IdRemoval.class); + @Transactional + public ManualRedactions getManualRedactions(String fileId, boolean unprocessed) { - Set forceRedactions = convert(forceRedactionPersistenceService.findForceRedactions(fileId, false), ManualForceRedaction.class); + Set entriesToAdd; + Set removals; + Set forceRedactions; + Set recategorizations; + Set legalBasisChanges; + Set resizeRedactions; - Set recategorizations = new HashSet<>(convert(recategorizationPersistenceService.findRecategorizations(fileId, false), - ManualRecategorization.class, - new ManualImageRecategorizationMapper())); - - Set legalBasisChanges = convert(legalBasisChangePersistenceService.findLegalBasisChanges(fileId, false), ManualLegalBasisChange.class); - - Set resizeRedactions = new HashSet<>(convert(resizeRedactionPersistenceService.findResizeRedactions(fileId, false), - ManualResizeRedaction.class, - new ManualResizeRedactionMapper())); + if (unprocessed) { + entriesToAdd = convertEntriesToAdd(addRedactionPersistenceService.findUnprocessedRedactions(fileId)); + removals = convert(removeRedactionPersistenceService.findUnprocessedRemoveRedactions(fileId), IdRemoval.class); + forceRedactions = convert(forceRedactionPersistenceService.findUnprocessedForceRedactions(fileId), ManualForceRedaction.class); + recategorizations = new HashSet<>(convert(recategorizationPersistenceService.findUnprocessedRecategorizations(fileId), + ManualRecategorization.class, + new ManualImageRecategorizationMapper())); + legalBasisChanges = convert(legalBasisChangePersistenceService.findUnprocessedLegalBasisChanges(fileId), ManualLegalBasisChange.class); + resizeRedactions = new HashSet<>(convert(resizeRedactionPersistenceService.findUnprocessedResizeRedactions(fileId), + ManualResizeRedaction.class, + new ManualResizeRedactionMapper())); + } else { + entriesToAdd = convertEntriesToAdd(addRedactionPersistenceService.findAddRedactions(fileId, false)); + removals = convert(removeRedactionPersistenceService.findRemoveRedactions(fileId, false), IdRemoval.class); + forceRedactions = convert(forceRedactionPersistenceService.findForceRedactions(fileId, false), ManualForceRedaction.class); + recategorizations = new HashSet<>(convert(recategorizationPersistenceService.findRecategorizations(fileId, false), + ManualRecategorization.class, + new ManualImageRecategorizationMapper())); + legalBasisChanges = convert(legalBasisChangePersistenceService.findLegalBasisChanges(fileId, false), ManualLegalBasisChange.class); + resizeRedactions = new HashSet<>(convert(resizeRedactionPersistenceService.findResizeRedactions(fileId, false), + ManualResizeRedaction.class, + new ManualResizeRedactionMapper())); + } Map> commentEntities = commentPersistenceService.findCommentsByFileID(fileId, false); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java index 6fa6bd378..0f9dc70b6 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java @@ -304,9 +304,9 @@ public class ManualRedactionService { } - public ManualRedactions getManualRedactions(String fileId) { + public ManualRedactions getManualRedactions(String fileId, boolean unprocessed) { - return manualRedactionProviderService.getManualRedactions(fileId); + return manualRedactionProviderService.getManualRedactions(fileId, unprocessed); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/AddRedactionPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/AddRedactionPersistenceService.java index 050056a39..20e219cee 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/AddRedactionPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/AddRedactionPersistenceService.java @@ -41,10 +41,6 @@ public class AddRedactionPersistenceService { manualRedactionEntry.setTypeId(addRedactionRequest.getDossierTemplateTypeId()); manualRedactionEntry.setDictionaryEntryType(addRedactionRequest.getDictionaryEntryType()); - if (addRedactionRequest.getStatus() == AnnotationStatus.APPROVED && !(addRedactionRequest.isAddToDictionary())) { - manualRedactionEntry.setProcessedDate(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS)); - } - return manualRedactionRepository.saveAndFlush(manualRedactionEntry); } @@ -84,6 +80,11 @@ public class AddRedactionPersistenceService { return manualRedactionRepository.findAll(); } + public List findUnprocessedRedactions(String fileId) { + + return manualRedactionRepository.findByFileIdAndUnprocessed(fileId); + } + @Transactional public void hardDelete(String fileId, String annotationId) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ForceRedactionPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ForceRedactionPersistenceService.java index 1bef2bb5f..161f234a4 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ForceRedactionPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ForceRedactionPersistenceService.java @@ -77,6 +77,10 @@ public class ForceRedactionPersistenceService { return new HashSet<>(forceRedactionRepository.findByFileIdIncludeDeletions(fileId, includeDeletions)); } + public Set findUnprocessedForceRedactions(String fileId) { + + return new HashSet<>(forceRedactionRepository.findByFileIdAndUnprocessed(fileId)); + } @Transactional public void markAsProcessed(String annotationId, String fileId) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/LegalBasisChangePersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/LegalBasisChangePersistenceService.java index 17f262c41..f768c5628 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/LegalBasisChangePersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/LegalBasisChangePersistenceService.java @@ -2,6 +2,7 @@ package com.iqser.red.service.persistence.management.v1.processor.service.persis import java.time.OffsetDateTime; import java.time.temporal.ChronoUnit; +import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; @@ -38,10 +39,6 @@ public class LegalBasisChangePersistenceService { BeanUtils.copyProperties(legalBasisChangeRequest, manualLegalBasisChange); manualLegalBasisChange.setRequestDate(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS)); - if (legalBasisChangeRequest.getStatus() == AnnotationStatus.APPROVED) { - manualLegalBasisChange.setProcessedDate(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS)); - } - return legalBasisChangeRepository.saveAndFlush(manualLegalBasisChange); } @@ -91,8 +88,12 @@ public class LegalBasisChangePersistenceService { public Set findLegalBasisChanges(String fileId, boolean includeDeletions) { - return legalBasisChangeRepository.findByFileIdIncludeDeletions(fileId, includeDeletions).stream().collect(Collectors.toSet()); + return new HashSet<>(legalBasisChangeRepository.findByFileIdIncludeDeletions(fileId, includeDeletions)); + } + public Set findUnprocessedLegalBasisChanges(String fileId) { + + return new HashSet<>(legalBasisChangeRepository.findUnprocessedByFileId(fileId)); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RecategorizationPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RecategorizationPersistenceService.java index 94629b03a..91c048508 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RecategorizationPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RecategorizationPersistenceService.java @@ -97,7 +97,11 @@ public class RecategorizationPersistenceService { public List findRecategorizations(String fileId, boolean includeDeletions) { return recategorizationRepository.findByFileIdIncludeDeletions(fileId, includeDeletions); + } + public List findUnprocessedRecategorizations(String fileId) { + + return recategorizationRepository.findUnprocessedByFileId(fileId); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RemoveRedactionPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RemoveRedactionPersistenceService.java index b50063bfa..3fd1d50ce 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RemoveRedactionPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RemoveRedactionPersistenceService.java @@ -2,6 +2,7 @@ package com.iqser.red.service.persistence.management.v1.processor.service.persis import java.time.OffsetDateTime; import java.time.temporal.ChronoUnit; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; @@ -50,7 +51,12 @@ public class RemoveRedactionPersistenceService { public Set findRemoveRedactions(String fileId, boolean includeDeletions) { - return removeRedactionRepository.findByFileIdIncludeDeletions(fileId, includeDeletions).stream().collect(Collectors.toSet()); + return new HashSet<>(removeRedactionRepository.findByFileIdIncludeDeletions(fileId, includeDeletions)); + } + + public Set findUnprocessedRemoveRedactions(String fileId) { + + return new HashSet<>(removeRedactionRepository.findByFileIdAndUnprocessed(fileId)); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ResizeRedactionPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ResizeRedactionPersistenceService.java index 348a1143f..91fa27a08 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ResizeRedactionPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ResizeRedactionPersistenceService.java @@ -38,11 +38,6 @@ public class ResizeRedactionPersistenceService { manualResizeRedaction.setPositions(MagicConverter.convert(resizeRedactionRequest.getPositions(), RectangleEntity.class)); manualResizeRedaction.setRequestDate(OffsetDateTime.now()); - if (manualResizeRedaction.getStatus() - .equals(AnnotationStatus.APPROVED) && (manualResizeRedaction.getUpdateDictionary() == null || !manualResizeRedaction.getUpdateDictionary())) { - manualResizeRedaction.setProcessedDate(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS)); - } - return resizeRedactionRepository.saveAndFlush(manualResizeRedaction); } @@ -98,6 +93,11 @@ public class ResizeRedactionPersistenceService { return resizeRedactionRepository.findByFileIdIncludeDeletions(fileId, includeDeletions); } + public List findUnprocessedResizeRedactions(String fileId) { + + return resizeRedactionRepository.findUnprocessedByFileId(fileId); + } + public List findByAnnotationStatusAndValue(AnnotationStatus status, String value) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ForceRedactionRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ForceRedactionRepository.java index cfde98e03..938f029d2 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ForceRedactionRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ForceRedactionRepository.java @@ -32,6 +32,10 @@ public interface ForceRedactionRepository extends JpaRepository findByFileIdIncludeDeletions(String fileId, boolean includeDeletions); + @Query("select mfr from ManualForceRedactionEntity mfr where mfr.id.fileId = :fileId and mfr.processedDate is null") + List findByFileIdAndUnprocessed(String fileId); + + @Modifying @Query("update ManualForceRedactionEntity mfr set mfr.processedDate = :processedDate where mfr.id = :annotationEntityId") void markAsProcessed(AnnotationEntityId annotationEntityId, OffsetDateTime processedDate); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/LegalBasisChangeRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/LegalBasisChangeRepository.java index 0a027adba..060cafc2d 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/LegalBasisChangeRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/LegalBasisChangeRepository.java @@ -32,6 +32,10 @@ public interface LegalBasisChangeRepository extends JpaRepository findByFileIdIncludeDeletions(String fileId, boolean includeDeletions); + @Query("select mlbc from ManualLegalBasisChangeEntity mlbc where mlbc.id.fileId = :fileId and mlbc.processedDate is null") + List findUnprocessedByFileId(String fileId); + + @Modifying @Query("update ManualLegalBasisChangeEntity mlbc set mlbc.processedDate = :processedDate where mlbc.id = :annotationEntityId") void markAsProcessed(AnnotationEntityId annotationEntityId, OffsetDateTime processedDate); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ManualRedactionRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ManualRedactionRepository.java index 7712f10d2..895c03c57 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ManualRedactionRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ManualRedactionRepository.java @@ -38,6 +38,10 @@ public interface ManualRedactionRepository extends JpaRepository findByFileIdIncludeDeletions(String fileId, boolean includeDeletions); + @Query("select m from ManualRedactionEntryEntity m where m.id.fileId = :fileId and m.processedDate is null") + List findByFileIdAndUnprocessed(String fileId); + + @Modifying @Query("update ManualRedactionEntryEntity m set m.status = :newStatus, m.processedDate = :processedDate where m.id.fileId in :fileIds and m.value = :filterValue and m.addToDictionary = true and m.status = :filterStatus ") void updateStatus(Set fileIds, String filterValue, AnnotationStatus filterStatus, AnnotationStatus newStatus, OffsetDateTime processedDate); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/RecategorizationRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/RecategorizationRepository.java index ae4f95962..14b953e6b 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/RecategorizationRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/RecategorizationRepository.java @@ -31,6 +31,9 @@ public interface RecategorizationRepository extends JpaRepository findByFileIdIncludeDeletions(String fileId, boolean includeDeletions); + @Query("select mir from ManualRecategorizationEntity mir where mir.id.fileId = :fileId and mir.processedDate is null") + List findUnprocessedByFileId(String fileId); + @Modifying @Query("update ManualRecategorizationEntity mir set mir.processedDate = :processedDate where mir.id = :annotationEntityId") diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/RemoveRedactionRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/RemoveRedactionRepository.java index 29ee81d1a..6c315db31 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/RemoveRedactionRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/RemoveRedactionRepository.java @@ -10,6 +10,7 @@ import org.springframework.data.jpa.repository.Query; import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.AnnotationEntityId; import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.IdRemovalEntity; +import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; public interface RemoveRedactionRepository extends JpaRepository, AnnotationEntityRepository { @@ -30,6 +31,9 @@ public interface RemoveRedactionRepository extends JpaRepository findByFileIdIncludeDeletions(String fileId, boolean includeDeletions); + @Query("select idr from IdRemovalEntity idr where idr.id.fileId = :fileId and idr.processedDate is null") + List findByFileIdAndUnprocessed(String fileId); + @Modifying @Query("update IdRemovalEntity idr set idr.processedDate = :processedDate where idr.id = :annotationEntityId") diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ResizeRedactionRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ResizeRedactionRepository.java index 5ef969de0..2c9d90b35 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ResizeRedactionRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/annotationentity/ResizeRedactionRepository.java @@ -32,6 +32,10 @@ public interface ResizeRedactionRepository extends JpaRepository findByFileIdIncludeDeletions(String fileId, boolean includeDeletions); + @Query("select mrd from ManualResizeRedactionEntity mrd where mrd.id.fileId = :fileId and mrd.processedDate is null") + List findUnprocessedByFileId(String fileId); + + @Modifying @Query("update ManualResizeRedactionEntity m set m.textBefore = :textBefore, m.textAfter = :textAfter where m.id = :id") void updateSurroundingText(AnnotationEntityId id, String textBefore, String textAfter); diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java index 19d3b44ef..fde66ae37 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java @@ -2,6 +2,8 @@ package com.iqser.red.service.peristence.v1.server.integration.tests; import static com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils.toTypeId; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.when; import java.util.ArrayList; @@ -16,6 +18,7 @@ import org.springframework.beans.factory.annotation.Autowired; import com.fasterxml.jackson.databind.ObjectMapper; import com.iqser.red.service.peristence.v1.server.integration.client.DictionaryClient; import com.iqser.red.service.peristence.v1.server.integration.client.FileClient; +import com.iqser.red.service.peristence.v1.server.integration.client.FileProcessingClient; import com.iqser.red.service.peristence.v1.server.integration.client.InternalDictionaryClient; import com.iqser.red.service.peristence.v1.server.integration.client.ManualRedactionClient; import com.iqser.red.service.peristence.v1.server.integration.service.DossierTemplateTesterAndProvider; @@ -30,7 +33,9 @@ import com.iqser.red.service.persistence.management.v1.processor.service.FileMan import com.iqser.red.service.persistence.management.v1.processor.service.persistence.EntryPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.redactionlog.RedactionRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.AnalyzeResult; import com.iqser.red.service.persistence.service.v1.api.shared.model.Dictionary; +import com.iqser.red.service.persistence.service.v1.api.shared.model.MessageType; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryState; @@ -39,6 +44,8 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddRedactionRequestModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ForceRedactionRequestModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.LegalBasisChangeRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RecategorizationRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequestModel; @@ -92,6 +99,9 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { @Autowired private EntryPersistenceService entryPersistenceService; + @Autowired + private FileProcessingClient fileProcessingClient; + @Test public void testRemoveToDossierTemplateWithDossierDictionaryOnlyTrue() { @@ -414,7 +424,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .build(); var addRedactions = manualRedactionClient.addRedactionBulk(dossier1.getId(), file1.getId(), Set.of(redactionDos, redactionDosTempDict)); - var loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId()); + var loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId(), false); var entityLog1 = new EntityLog(1, 1, @@ -473,7 +483,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { manualRedactionClient.resizeRedactionBulk(dossier1.getId(), file1.getFileId(), Set.of(resizeRedactionDosAndAddToAllDos)); - loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId()); + loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId(), false); assertThat(loadedRedactionsFile1.getResizeRedactions()).hasSize(1); assertThat(loadedRedactionsFile1.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier dictionary"); @@ -569,7 +579,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { .build(); var addRedactions = manualRedactionClient.addRedactionBulk(dossier1.getId(), file1.getId(), Set.of(redactionDos, redactionDosTempDict)); - var loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId()); + var loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId(), false); var entityLog1 = new EntityLog(1, 1, @@ -628,7 +638,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { manualRedactionClient.resizeRedactionBulk(dossier1.getId(), file1.getFileId(), Set.of(resizeRedactionDosAndAddToAllDos)); - loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId()); + loadedRedactionsFile1 = manualRedactionClient.getManualRedactions(file1.getDossierId(), file1.getFileId(), false); assertThat(loadedRedactionsFile1.getResizeRedactions()).hasSize(1); assertThat(loadedRedactionsFile1.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier"); @@ -789,7 +799,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var resizeRedactions = manualRedactionClient.resizeRedactionBulk(dossier2.getId(), file2.getFileId(), Set.of(resizeRedactionDosTemp)); - var loadedRedactionsFile2 = manualRedactionClient.getManualRedactions(file2.getDossierId(), file2.getFileId()); + var loadedRedactionsFile2 = manualRedactionClient.getManualRedactions(file2.getDossierId(), file2.getFileId(), false); assertThat(loadedRedactionsFile2.getResizeRedactions()).hasSize(1); assertThat(loadedRedactionsFile2.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier template dictionary"); @@ -943,7 +953,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var resizeRedactions = manualRedactionClient.resizeRedactionBulk(dossier2.getId(), file2.getFileId(), Set.of(resizeRedactionDosTemp)); - var loadedRedactionsFile2 = manualRedactionClient.getManualRedactions(file2.getDossierId(), file2.getFileId()); + var loadedRedactionsFile2 = manualRedactionClient.getManualRedactions(file2.getDossierId(), file2.getFileId(), false); assertThat(loadedRedactionsFile2.getResizeRedactions()).hasSize(1); assertThat(loadedRedactionsFile2.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier template"); @@ -1137,4 +1147,332 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { assertThat(dossierDictionary2.getEntries()).isEmpty(); } + @Test + public void testUnprocessedManualRedactionsAddRedaction() { + + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate); + var file = fileTesterAndProvider.testAndProvideFile(dossier); + var type = typeProvider.testAndProvideType(dossierTemplate); + + dictionaryClient.deleteEntries(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), dossier.getId(), DictionaryEntryType.ENTRY); + + manualRedactionClient.addRedactionBulk(dossier.getId(), + file.getId(), + Set.of(AddRedactionRequestModel.builder() + .positions(List.of(Rectangle.builder().topLeftY(1).topLeftX(1).height(1).width(1).build())) + .section("section test") + .addToDictionary(false) + .addToAllDossiers(false) + .dictionaryEntryType(DictionaryEntryType.ENTRY) + .type(type.getType()) + .reason("1") + .value("Luke Skywalker") + .legalBasis("1") + .sourceId("SourceId") + .build())); + + var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); + assertEquals(allManualRedactions.getEntriesToAdd().size(), 1); + assertTrue(allManualRedactions.getEntriesToAdd().stream().anyMatch(entry -> entry.getValue().equals("Luke Skywalker"))); + + var unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true); + assertEquals(unprocessedManualRedactions.getEntriesToAdd().size(), 1); + assertTrue(unprocessedManualRedactions.getEntriesToAdd().stream().anyMatch(entry -> entry.getValue().equals("Luke Skywalker"))); + + fileProcessingClient.analysisSuccessful(dossier.getId(), file.getId(), AnalyzeResult.builder() + .manualRedactions(allManualRedactions) + .messageType(MessageType.ANALYSE).analysisVersion(0).fileId(file.getId()).dossierId(dossier.getId()).build()); + + manualRedactionClient.addRedactionBulk(dossier.getId(), + file.getId(), + Set.of(AddRedactionRequestModel.builder() + .positions(List.of(Rectangle.builder().topLeftY(2).topLeftX(2).height(2).width(2).build())) + .section("section test") + .addToDictionary(false) + .addToAllDossiers(false) + .dictionaryEntryType(DictionaryEntryType.ENTRY) + .type(type.getType()) + .reason("1") + .value("Skywalker Luke") + .legalBasis("1") + .sourceId("SourceId") + .build())); + + allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); + assertEquals(allManualRedactions.getEntriesToAdd().size(), 2); + assertTrue(allManualRedactions.getEntriesToAdd().stream().anyMatch(entry -> entry.getValue().equals("Skywalker Luke"))); + assertTrue(allManualRedactions.getEntriesToAdd().stream().anyMatch(entry -> entry.getValue().equals("Luke Skywalker"))); + + unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true); + assertEquals(unprocessedManualRedactions.getEntriesToAdd().size(), 1); + assertTrue(unprocessedManualRedactions.getEntriesToAdd().stream().anyMatch(entry -> entry.getValue().equals("Skywalker Luke"))); + assertTrue(unprocessedManualRedactions.getEntriesToAdd().stream().noneMatch(entry -> entry.getValue().equals("Luke Skywalker"))); + + fileProcessingClient.analysisSuccessful(dossier.getId(), file.getId(), AnalyzeResult.builder() + .manualRedactions(allManualRedactions) + .messageType(MessageType.ANALYSE).analysisVersion(1).fileId(file.getId()).dossierId(dossier.getId()).build()); + + allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); + assertEquals(allManualRedactions.getEntriesToAdd().size(), 2); + assertTrue(allManualRedactions.getEntriesToAdd().stream().anyMatch(entry -> entry.getValue().equals("Skywalker Luke"))); + assertTrue(allManualRedactions.getEntriesToAdd().stream().anyMatch(entry -> entry.getValue().equals("Luke Skywalker"))); + + unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true); + assertTrue(unprocessedManualRedactions.getEntriesToAdd().isEmpty()); + + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), false, dossier.getId(), DictionaryEntryType.ENTRY); + } + + @Test + public void testUnprocessedManualRedactionsRemoveRedaction() { + + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate); + var file = fileTesterAndProvider.testAndProvideFile(dossier, "new_file"); + + var type = typeProvider.testAndProvideType(dossierTemplate, null, "type", false); + + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("Anakin"), false, dossier.getId(), DictionaryEntryType.ENTRY); + + var entityLog = new EntityLog(1, + 1, + List.of(EntityLogEntry.builder().id("AnnotationId").type(type.getType()).value("Anakin").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(false).build(), + EntityLogEntry.builder().id("AnnotationId2").type(type.getType()).value("Anakin2").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(false).build()), + null, + 0, + 0, + 0, + 0); + fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.ENTITY_LOG, entityLog); + + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(entityLog); + + manualRedactionClient.removeRedactionBulk(dossier.getId(), + file.getId(), + Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId").removeFromDictionary(true).removeFromAllDossiers(true).build())); + + var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); + assertEquals(allManualRedactions.getIdsToRemove().size(), 1); + assertTrue(allManualRedactions.getIdsToRemove().stream().anyMatch(entry -> entry.getAnnotationId().equals("AnnotationId"))); + + var unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true); + assertEquals(unprocessedManualRedactions.getIdsToRemove().size(), 1); + assertTrue(unprocessedManualRedactions.getIdsToRemove().stream().anyMatch(entry -> entry.getAnnotationId().equals("AnnotationId"))); + + fileProcessingClient.analysisSuccessful(dossier.getId(), + file.getId(), + AnalyzeResult.builder().manualRedactions(allManualRedactions).messageType(MessageType.ANALYSE).analysisVersion(0).fileId(file.getId()).dossierId(dossier.getId()).build()); + + manualRedactionClient.removeRedactionBulk(dossier.getId(), + file.getId(), + Set.of(RemoveRedactionRequestModel.builder().annotationId("AnnotationId2").removeFromDictionary(true).removeFromAllDossiers(true).build())); + + allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); + assertEquals(allManualRedactions.getIdsToRemove().size(), 2); + assertTrue(allManualRedactions.getIdsToRemove().stream().anyMatch(entry -> entry.getAnnotationId().equals("AnnotationId"))); + assertTrue(allManualRedactions.getIdsToRemove().stream().anyMatch(entry -> entry.getAnnotationId().equals("AnnotationId2"))); + + unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true); + assertEquals(unprocessedManualRedactions.getIdsToRemove().size(), 1); + assertTrue(unprocessedManualRedactions.getIdsToRemove().stream().noneMatch(entry -> entry.getAnnotationId().equals("AnnotationId"))); + assertTrue(unprocessedManualRedactions.getIdsToRemove().stream().anyMatch(entry -> entry.getAnnotationId().equals("AnnotationId2"))); + + fileProcessingClient.analysisSuccessful(dossier.getId(), + file.getId(), + AnalyzeResult.builder().manualRedactions(allManualRedactions).messageType(MessageType.ANALYSE).analysisVersion(1).fileId(file.getId()).dossierId(dossier.getId()).build()); + + allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); + assertEquals(allManualRedactions.getIdsToRemove().size(), 2); + assertTrue(allManualRedactions.getIdsToRemove().stream().anyMatch(entry -> entry.getAnnotationId().equals("AnnotationId"))); + assertTrue(allManualRedactions.getIdsToRemove().stream().anyMatch(entry -> entry.getAnnotationId().equals("AnnotationId2"))); + + unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true); + assertTrue(unprocessedManualRedactions.getIdsToRemove().isEmpty()); + } + + @Test + public void testUnprocessedManualRedactionsForceRedaction() { + + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate); + var file = fileTesterAndProvider.testAndProvideFile(dossier); + + manualRedactionClient.forceRedactionBulk(dossier.getId(), + file.getId(), + Set.of(ForceRedactionRequestModel.builder().annotationId("forceRedactionAnnotation").comment("comment").legalBasis("1").build())); + + var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); + assertEquals(allManualRedactions.getForceRedactions().size(), 1); + assertTrue(allManualRedactions.getForceRedactions().stream().anyMatch(entry -> entry.getAnnotationId().equals("forceRedactionAnnotation"))); + + var unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true); + assertEquals(unprocessedManualRedactions.getForceRedactions().size(), 1); + assertTrue(unprocessedManualRedactions.getForceRedactions().stream().anyMatch(entry -> entry.getAnnotationId().equals("forceRedactionAnnotation"))); + + fileProcessingClient.analysisSuccessful(dossier.getId(), + file.getId(), + AnalyzeResult.builder().manualRedactions(allManualRedactions).messageType(MessageType.ANALYSE).analysisVersion(0).fileId(file.getId()).dossierId(dossier.getId()).build()); + + manualRedactionClient.forceRedactionBulk(dossier.getId(), + file.getId(), + Set.of(ForceRedactionRequestModel.builder().annotationId("forceRedactionAnnotation2").comment("comment").legalBasis("1").build())); + + allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); + assertEquals(allManualRedactions.getForceRedactions().size(), 2); + assertTrue(allManualRedactions.getForceRedactions().stream().anyMatch(entry -> entry.getAnnotationId().equals("forceRedactionAnnotation"))); + assertTrue(allManualRedactions.getForceRedactions().stream().anyMatch(entry -> entry.getAnnotationId().equals("forceRedactionAnnotation"))); + + unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true); + assertEquals(unprocessedManualRedactions.getForceRedactions().size(), 1); + assertTrue(unprocessedManualRedactions.getForceRedactions().stream().noneMatch(entry -> entry.getAnnotationId().equals("forceRedactionAnnotation"))); + assertTrue(unprocessedManualRedactions.getForceRedactions().stream().anyMatch(entry -> entry.getAnnotationId().equals("forceRedactionAnnotation2"))); + + fileProcessingClient.analysisSuccessful(dossier.getId(), + file.getId(), + AnalyzeResult.builder().manualRedactions(allManualRedactions).messageType(MessageType.ANALYSE).analysisVersion(1).fileId(file.getId()).dossierId(dossier.getId()).build()); + + allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); + assertEquals(allManualRedactions.getForceRedactions().size(), 2); + assertTrue(allManualRedactions.getForceRedactions().stream().anyMatch(entry -> entry.getAnnotationId().equals("forceRedactionAnnotation"))); + assertTrue(allManualRedactions.getForceRedactions().stream().anyMatch(entry -> entry.getAnnotationId().equals("forceRedactionAnnotation2"))); + + unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true); + assertTrue(unprocessedManualRedactions.getForceRedactions().isEmpty()); + } + + @Test + public void testUnprocessedManualRedactionsRecategorizations() { + + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate); + var file = fileTesterAndProvider.testAndProvideFile(dossier); + + var type = typeProvider.testAndProvideType(dossierTemplate, null, "type", false); + + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("Darth Vader"), false, dossier.getId(), DictionaryEntryType.ENTRY); + + var entityLog = new EntityLog(1, + 1, + List.of(EntityLogEntry.builder().id("dv").type(type.getType()).value("Darth Vader").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(false).build(), + EntityLogEntry.builder().id("dv2").type(type.getType()).value("Vader Darth").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(false).build()), + null, + 0, + 0, + 0, + 0); + fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.ENTITY_LOG, entityLog); + + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(entityLog); + + manualRedactionClient.recategorizeBulk(dossier.getId(), + file.getId(), + Set.of(RecategorizationRequestModel.builder().annotationId("dv").build())); + + var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); + assertEquals(allManualRedactions.getRecategorizations().size(), 1); + assertTrue(allManualRedactions.getRecategorizations().stream().anyMatch(entry -> entry.getAnnotationId().equals("dv"))); + + var unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true); + assertEquals(unprocessedManualRedactions.getRecategorizations().size(), 1); + assertTrue(unprocessedManualRedactions.getRecategorizations().stream().anyMatch(entry -> entry.getAnnotationId().equals("dv"))); + + fileProcessingClient.analysisSuccessful(dossier.getId(), + file.getId(), + AnalyzeResult.builder().manualRedactions(allManualRedactions).messageType(MessageType.ANALYSE).analysisVersion(0).fileId(file.getId()).dossierId(dossier.getId()).build()); + + manualRedactionClient.recategorizeBulk(dossier.getId(), + file.getId(), + Set.of(RecategorizationRequestModel.builder().annotationId("dv2").build())); + + allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); + assertEquals(allManualRedactions.getRecategorizations().size(), 2); + assertTrue(allManualRedactions.getRecategorizations().stream().anyMatch(entry -> entry.getAnnotationId().equals("dv"))); + assertTrue(allManualRedactions.getRecategorizations().stream().anyMatch(entry -> entry.getAnnotationId().equals("dv2"))); + + unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true); + assertEquals(unprocessedManualRedactions.getRecategorizations().size(), 1); + assertTrue(unprocessedManualRedactions.getRecategorizations().stream().noneMatch(entry -> entry.getAnnotationId().equals("dv"))); + assertTrue(unprocessedManualRedactions.getRecategorizations().stream().anyMatch(entry -> entry.getAnnotationId().equals("dv2"))); + + fileProcessingClient.analysisSuccessful(dossier.getId(), + file.getId(), + AnalyzeResult.builder().manualRedactions(allManualRedactions).messageType(MessageType.ANALYSE).analysisVersion(1).fileId(file.getId()).dossierId(dossier.getId()).build()); + + allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); + assertEquals(allManualRedactions.getRecategorizations().size(), 2); + assertTrue(allManualRedactions.getRecategorizations().stream().anyMatch(entry -> entry.getAnnotationId().equals("dv"))); + assertTrue(allManualRedactions.getRecategorizations().stream().anyMatch(entry -> entry.getAnnotationId().equals("dv2"))); + + unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true); + assertTrue(unprocessedManualRedactions.getRecategorizations().isEmpty()); + } + + @Test + public void testUnprocessedManualRedactionsLegalBasisChanges() { + + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate); + var file = fileTesterAndProvider.testAndProvideFile(dossier); + + var type = typeProvider.testAndProvideType(dossierTemplate, null, "type", false); + + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), false, dossier.getId(), DictionaryEntryType.ENTRY); + + var entityLog = new EntityLog(1, + 1, + List.of(EntityLogEntry.builder().id("AnnotationId").type(type.getType()).value("Luke Skywalker").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(false).build(), + EntityLogEntry.builder().id("AnnotationId2").type(type.getType()).value("Skywalker Luke").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(false).build()), + null, + 0, + 0, + 0, + 0); + fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.ENTITY_LOG, entityLog); + + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(entityLog); + + manualRedactionClient.legalBasisChangeBulk(dossier.getId(), + file.getId(), + Set.of(LegalBasisChangeRequestModel.builder().legalBasis("legalBasis").annotationId("AnnotationId").build())); + + var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); + assertEquals(allManualRedactions.getLegalBasisChanges().size(), 1); + assertTrue(allManualRedactions.getLegalBasisChanges().stream().anyMatch(entry -> entry.getLegalBasis().equals("legalBasis"))); + + var unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true); + assertEquals(unprocessedManualRedactions.getLegalBasisChanges().size(), 1); + assertTrue(unprocessedManualRedactions.getLegalBasisChanges().stream().anyMatch(entry -> entry.getLegalBasis().equals("legalBasis"))); + + fileProcessingClient.analysisSuccessful(dossier.getId(), + file.getId(), + AnalyzeResult.builder().manualRedactions(allManualRedactions).messageType(MessageType.ANALYSE).analysisVersion(0).fileId(file.getId()).dossierId(dossier.getId()).build()); + + manualRedactionClient.legalBasisChangeBulk(dossier.getId(), + file.getId(), + Set.of(LegalBasisChangeRequestModel.builder().legalBasis("legalBasis2").annotationId("AnnotationId2").build())); + + allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); + assertEquals(allManualRedactions.getLegalBasisChanges().size(), 2); + assertTrue(allManualRedactions.getLegalBasisChanges().stream().anyMatch(entry -> entry.getLegalBasis().equals("legalBasis"))); + assertTrue(allManualRedactions.getLegalBasisChanges().stream().anyMatch(entry -> entry.getLegalBasis().equals("legalBasis2"))); + + unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true); + assertEquals(unprocessedManualRedactions.getLegalBasisChanges().size(), 1); + assertTrue(unprocessedManualRedactions.getLegalBasisChanges().stream().noneMatch(entry -> entry.getLegalBasis().equals("legalBasis"))); + assertTrue(unprocessedManualRedactions.getLegalBasisChanges().stream().anyMatch(entry -> entry.getLegalBasis().equals("legalBasis2"))); + + fileProcessingClient.analysisSuccessful(dossier.getId(), + file.getId(), + AnalyzeResult.builder().manualRedactions(allManualRedactions).messageType(MessageType.ANALYSE).analysisVersion(1).fileId(file.getId()).dossierId(dossier.getId()).build()); + + allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); + assertEquals(allManualRedactions.getLegalBasisChanges().size(), 2); + assertTrue(allManualRedactions.getLegalBasisChanges().stream().anyMatch(entry -> entry.getLegalBasis().equals("legalBasis"))); + assertTrue(allManualRedactions.getLegalBasisChanges().stream().anyMatch(entry -> entry.getLegalBasis().equals("legalBasis2"))); + + unprocessedManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), true); + assertTrue(unprocessedManualRedactions.getResizeRedactions().isEmpty()); + } + } -- 2.47.2 From 541da5d3d3d7a8802ff7b2c9453250d5cf63bf95 Mon Sep 17 00:00:00 2001 From: yhampe Date: Mon, 23 Oct 2023 08:17:56 +0200 Subject: [PATCH 18/96] RED-7654: Import and export of rules in non-escaped form * removed method call, as we do not care about the names when updating an existing template --- .../service/DossierTemplateImportService.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java index 861b248ed..f3178c73b 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java @@ -17,6 +17,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.function.Function; @@ -66,6 +67,7 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.ReportTemplateUploadRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.Colors; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.CreateOrUpdateDossierStatusRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.DossierStatusInfo; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileAttributeConfig; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.importexport.ExportFilename; @@ -111,6 +113,7 @@ public class DossierTemplateImportService { public String importDossierTemplate(ImportDossierTemplateRequest request) { + ImportTemplateResult archiveResult = this.handleArchive(request); return this.importDossierTemplate(archiveResult); @@ -321,7 +324,12 @@ public class DossierTemplateImportService { // override the existing dossier template updateDossierTemplateMeta(existingDossierTemplate, dossierTemplateMeta, request.getUserId()); - dossierTemplateRepository.save(existingDossierTemplate); + DossierTemplateEntity updatedDossier = dossierTemplateRepository.save(existingDossierTemplate); + Optional dossierTemplate = dossierTemplateRepository.findById(existingDossierTemplate.getId()); + Optional dossierTemplate1 = dossierTemplateRepository.findById(updatedDossier.getId()); + log.info("OLD: "+ dossierTemplate.get().getName()); + log.info("NEW: "+dossierTemplate1.get().getName()); + // set rules setRulesWhenCompiled(request, dossierTemplateId); @@ -553,10 +561,6 @@ public class DossierTemplateImportService { private void updateDossierTemplateMeta(DossierTemplateEntity dossierTemplateEntity, DossierTemplate dossierTemplate, String userId) { - if (!dossierTemplateEntity.getName().equalsIgnoreCase(dossierTemplate.getName())) { - this.validateDossierTemplateName(dossierTemplate); - } - BeanUtils.copyProperties(dossierTemplate, dossierTemplateEntity, "modifiedBy", "dateModified", "validFrom", "validTo", "downloadFileTypes"); OffsetDateTime now = OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS); dossierTemplateEntity.setDateModified(now); @@ -708,7 +712,6 @@ public class DossierTemplateImportService { private void validateDossierTemplateName(DossierTemplate dossierTemplateMeta) { - int nameSuffix = 0; String dossierTemplateName = dossierTemplateMeta.getName(); while (dossierTemplatePersistenceService.isDossierTemplateNameNotUnique(dossierTemplateMeta.getName())) { -- 2.47.2 From b872effffd51c15d6b53fdc6f2387054dc9c1b78 Mon Sep 17 00:00:00 2001 From: yhampe Date: Mon, 23 Oct 2023 08:17:56 +0200 Subject: [PATCH 19/96] RED-7654: Import and export of rules in non-escaped form * removed method call, as we do not care about the names when updating an existing template --- .../service/DossierTemplateImportService.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java index 861b248ed..f3178c73b 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java @@ -17,6 +17,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.function.Function; @@ -66,6 +67,7 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.ReportTemplateUploadRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.Colors; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.CreateOrUpdateDossierStatusRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.DossierStatusInfo; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileAttributeConfig; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.importexport.ExportFilename; @@ -111,6 +113,7 @@ public class DossierTemplateImportService { public String importDossierTemplate(ImportDossierTemplateRequest request) { + ImportTemplateResult archiveResult = this.handleArchive(request); return this.importDossierTemplate(archiveResult); @@ -321,7 +324,12 @@ public class DossierTemplateImportService { // override the existing dossier template updateDossierTemplateMeta(existingDossierTemplate, dossierTemplateMeta, request.getUserId()); - dossierTemplateRepository.save(existingDossierTemplate); + DossierTemplateEntity updatedDossier = dossierTemplateRepository.save(existingDossierTemplate); + Optional dossierTemplate = dossierTemplateRepository.findById(existingDossierTemplate.getId()); + Optional dossierTemplate1 = dossierTemplateRepository.findById(updatedDossier.getId()); + log.info("OLD: "+ dossierTemplate.get().getName()); + log.info("NEW: "+dossierTemplate1.get().getName()); + // set rules setRulesWhenCompiled(request, dossierTemplateId); @@ -553,10 +561,6 @@ public class DossierTemplateImportService { private void updateDossierTemplateMeta(DossierTemplateEntity dossierTemplateEntity, DossierTemplate dossierTemplate, String userId) { - if (!dossierTemplateEntity.getName().equalsIgnoreCase(dossierTemplate.getName())) { - this.validateDossierTemplateName(dossierTemplate); - } - BeanUtils.copyProperties(dossierTemplate, dossierTemplateEntity, "modifiedBy", "dateModified", "validFrom", "validTo", "downloadFileTypes"); OffsetDateTime now = OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS); dossierTemplateEntity.setDateModified(now); @@ -708,7 +712,6 @@ public class DossierTemplateImportService { private void validateDossierTemplateName(DossierTemplate dossierTemplateMeta) { - int nameSuffix = 0; String dossierTemplateName = dossierTemplateMeta.getName(); while (dossierTemplatePersistenceService.isDossierTemplateNameNotUnique(dossierTemplateMeta.getName())) { -- 2.47.2 From 9a5b192144cc631bd1b9a71a1a4d15a19e7f64ac Mon Sep 17 00:00:00 2001 From: yhampe Date: Mon, 23 Oct 2023 08:20:37 +0200 Subject: [PATCH 20/96] RED-7654: Import and export of rules in non-escaped form * removed debug logging --- .../v1/processor/service/DossierTemplateImportService.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java index f3178c73b..e08fa85e3 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java @@ -325,10 +325,6 @@ public class DossierTemplateImportService { // override the existing dossier template updateDossierTemplateMeta(existingDossierTemplate, dossierTemplateMeta, request.getUserId()); DossierTemplateEntity updatedDossier = dossierTemplateRepository.save(existingDossierTemplate); - Optional dossierTemplate = dossierTemplateRepository.findById(existingDossierTemplate.getId()); - Optional dossierTemplate1 = dossierTemplateRepository.findById(updatedDossier.getId()); - log.info("OLD: "+ dossierTemplate.get().getName()); - log.info("NEW: "+dossierTemplate1.get().getName()); // set rules -- 2.47.2 From 6221a7c5d73c037d33b5ce9e475b7023e35351d2 Mon Sep 17 00:00:00 2001 From: yhampe Date: Mon, 23 Oct 2023 08:22:42 +0200 Subject: [PATCH 21/96] RED-7654: Import and export of rules in non-escaped form * removed debug logging --- .../v1/processor/service/DossierTemplateImportService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java index e08fa85e3..1ff0aa277 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java @@ -113,7 +113,6 @@ public class DossierTemplateImportService { public String importDossierTemplate(ImportDossierTemplateRequest request) { - ImportTemplateResult archiveResult = this.handleArchive(request); return this.importDossierTemplate(archiveResult); @@ -324,7 +323,7 @@ public class DossierTemplateImportService { // override the existing dossier template updateDossierTemplateMeta(existingDossierTemplate, dossierTemplateMeta, request.getUserId()); - DossierTemplateEntity updatedDossier = dossierTemplateRepository.save(existingDossierTemplate); + dossierTemplateRepository.save(existingDossierTemplate); // set rules @@ -708,6 +707,7 @@ public class DossierTemplateImportService { private void validateDossierTemplateName(DossierTemplate dossierTemplateMeta) { + int nameSuffix = 0; String dossierTemplateName = dossierTemplateMeta.getName(); while (dossierTemplatePersistenceService.isDossierTemplateNameNotUnique(dossierTemplateMeta.getName())) { -- 2.47.2 From 70bb450870dfa21a62dfcd152ba90949c6a55026 Mon Sep 17 00:00:00 2001 From: yhampe Date: Mon, 23 Oct 2023 09:59:41 +0200 Subject: [PATCH 22/96] RED-7654: Import and export of rules in non-escaped form * added back deleted code * added id to ignoreproperties --- .../v1/processor/service/DossierTemplateImportService.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java index 1ff0aa277..e76c7be4b 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java @@ -556,7 +556,11 @@ public class DossierTemplateImportService { private void updateDossierTemplateMeta(DossierTemplateEntity dossierTemplateEntity, DossierTemplate dossierTemplate, String userId) { - BeanUtils.copyProperties(dossierTemplate, dossierTemplateEntity, "modifiedBy", "dateModified", "validFrom", "validTo", "downloadFileTypes"); + if (!dossierTemplateEntity.getName().equalsIgnoreCase(dossierTemplate.getName())) { + this.validateDossierTemplateName(dossierTemplate); + } + + BeanUtils.copyProperties(dossierTemplate, dossierTemplateEntity, "id","modifiedBy", "dateModified", "validFrom", "validTo", "downloadFileTypes"); OffsetDateTime now = OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS); dossierTemplateEntity.setDateModified(now); dossierTemplateEntity.setModifiedBy(userId); -- 2.47.2 From 9aee9627d87e48ddd10e0ef0c6f8b24dc8b6ba0a Mon Sep 17 00:00:00 2001 From: Corina Olariu Date: Mon, 23 Oct 2023 11:20:12 +0300 Subject: [PATCH 23/96] RED-7434 - Remove Section Grid entirely - update the layout parser version to remove the section grid from layou parser request --- .../persistence-service-processor-v1/pom.xml | 2 +- .../LayoutParsingRequestFactory.java | 1 - .../redactionlog/SectionTextService.java | 41 ------------------- 3 files changed, 1 insertion(+), 43 deletions(-) delete mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/redactionlog/SectionTextService.java diff --git a/persistence-service-v1/persistence-service-processor-v1/pom.xml b/persistence-service-v1/persistence-service-processor-v1/pom.xml index eb209cca3..8ff5c0fa3 100644 --- a/persistence-service-v1/persistence-service-processor-v1/pom.xml +++ b/persistence-service-v1/persistence-service-processor-v1/pom.xml @@ -91,7 +91,7 @@ com.knecon.fforesight layoutparser-service-internal-api - 0.57.0 + 0.74.0 diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/layoutparsing/LayoutParsingRequestFactory.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/layoutparsing/LayoutParsingRequestFactory.java index 5936ed66d..76785a0b0 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/layoutparsing/LayoutParsingRequestFactory.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/layoutparsing/LayoutParsingRequestFactory.java @@ -50,7 +50,6 @@ public class LayoutParsingRequestFactory { .textBlockFileStorageId(StorageIdUtils.getStorageId(dossierId, fileId, FileType.DOCUMENT_TEXT)) .positionBlockFileStorageId(StorageIdUtils.getStorageId(dossierId, fileId, FileType.DOCUMENT_POSITION)) .simplifiedTextStorageId(StorageIdUtils.getStorageId(dossierId, fileId, FileType.SIMPLIFIED_TEXT)) - .sectionGridStorageId(StorageIdUtils.getStorageId(dossierId, fileId, FileType.SECTION_GRID)) .viewerDocumentStorageId(StorageIdUtils.getStorageId(dossierId, fileId, FileType.VIEWER_DOCUMENT)) .build(); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/redactionlog/SectionTextService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/redactionlog/SectionTextService.java deleted file mode 100644 index 45e04bc6b..000000000 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/redactionlog/SectionTextService.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.iqser.red.service.persistence.management.v1.processor.service.redactionlog; - -import org.springframework.stereotype.Service; - -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLogEntry; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.section.SectionGrid; - -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@Service -public class SectionTextService { - - public void handleSectionText(SectionGrid sectionGrid, RedactionLogEntry redactionLogEntry) { - - if (redactionLogEntry.getSection() != null) { - // set by UI - return; - } - - if (sectionGrid != null) { - var firstPosition = !redactionLogEntry.getPositions().isEmpty() ? redactionLogEntry.getPositions().iterator().next() : null; - - if (firstPosition != null) { - - for (var section : sectionGrid.getSections()) { - if (section.getPages().contains(firstPosition.getPage())) { - for (var sectionArea : section.getSectionAreas()) { - if (sectionArea.contains(firstPosition)) { - redactionLogEntry.setSection(section.getHeadline()); - redactionLogEntry.setSectionNumber(section.getSectionNumber()); - return; - } - } - } - } - } - } - } - -} -- 2.47.2 From a470fc0a2a90267cc2bd5c3e28a51d1758066831 Mon Sep 17 00:00:00 2001 From: Andrei Isvoran Date: Mon, 23 Oct 2023 11:10:59 +0200 Subject: [PATCH 24/96] RED-7784 - Merge unprocessed changes into entity log --- .../persistence/service/v1/api/shared/model/MessageType.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/MessageType.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/MessageType.java index 09dc18164..9e75196e7 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/MessageType.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/MessageType.java @@ -3,5 +3,6 @@ package com.iqser.red.service.persistence.service.v1.api.shared.model; public enum MessageType { ANALYSE, - REANALYSE + REANALYSE, + SURROUNDING_TEXT } -- 2.47.2 From c65a93bf1b5b81c8b152e453928f628c043564db Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Mon, 23 Oct 2023 13:17:30 +0200 Subject: [PATCH 25/96] DM-285: flush add redaction removal * only remove add redactions --- .../service/DossierTemplateImportService.java | 6 +- .../ManualRedactionProviderService.java | 13 +- .../ManualRedactionService.java | 4 +- .../AddRedactionPersistenceService.java | 7 +- .../ForceRedactionPersistenceService.java | 2 + .../LegalBasisChangePersistenceService.java | 3 +- .../RecategorizationPersistenceService.java | 1 + .../RemoveRedactionPersistenceService.java | 2 +- .../ResizeRedactionPersistenceService.java | 1 + .../tests/ManualRedactionTest.java | 281 +++++++++++++++--- 10 files changed, 257 insertions(+), 63 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java index e76c7be4b..e0e467632 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java @@ -509,21 +509,21 @@ public class DossierTemplateImportService { } - private void setRulesWhenCompiled(ImportTemplateResult request, String dossierTemplateEntity) { + private void setRulesWhenCompiled(ImportTemplateResult request, String dossierTemplateId) { DroolsSyntaxValidation droolsSyntaxValidation = rulesValidationService.validateRules(RuleFileType.ENTITY, request.getRuleSet()); if (!droolsSyntaxValidation.isCompiled()) { droolsSyntaxValidation.getDroolsSyntaxErrorMessages().forEach(errorMessage -> log.error(errorMessage.getMessage())); throw new BadRequestException("The entity rules do not compile!"); } - rulesPersistenceService.setRules(request.getRuleSet(), dossierTemplateEntity, RuleFileType.ENTITY); + rulesPersistenceService.setRules(request.getRuleSet(), dossierTemplateId, RuleFileType.ENTITY); if (request.getComponentRuleSet() != null) { DroolsSyntaxValidation componentDroolsSyntaxValidation = rulesValidationService.validateRules(RuleFileType.COMPONENT, request.getComponentRuleSet()); if (!componentDroolsSyntaxValidation.isCompiled()) { componentDroolsSyntaxValidation.getDroolsSyntaxErrorMessages().forEach(errorMessage -> log.error(errorMessage.getMessage())); throw new BadRequestException("The component rules do not compile!"); } - rulesPersistenceService.setRules(request.getComponentRuleSet(), dossierTemplateEntity, RuleFileType.COMPONENT); + rulesPersistenceService.setRules(request.getComponentRuleSet(), dossierTemplateId, RuleFileType.COMPONENT); } } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java index 35b55aba0..ba268ed99 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java @@ -11,6 +11,7 @@ import java.util.stream.Collectors; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.CommentEntity; @@ -50,11 +51,14 @@ public class ManualRedactionProviderService { private final LegalBasisChangePersistenceService legalBasisChangePersistenceService; private final ResizeRedactionPersistenceService resizeRedactionPersistenceService; + + @Transactional public ManualRedactions getManualRedactions(String fileId) { return getManualRedactions(fileId, false); } + @Transactional public ManualRedactions getManualRedactions(String fileId, boolean unprocessed) { @@ -98,20 +102,13 @@ public class ManualRedactionProviderService { } - @Transactional - public ManualRedactionEntry getAddRedaction(String fileId, String annotationId) { - - return convert(addRedactionPersistenceService.findAddRedaction(fileId, annotationId), ManualRedactionEntry.class, new ManualRedactionMapper()); - } - - private Set convertEntriesToAdd(List source) { return source.stream().map(entry -> convert(entry, ManualRedactionEntry.class, new ManualRedactionMapper())).collect(Collectors.toSet()); } - @Transactional(noRollbackFor = {EmptyResultDataAccessException.class}) + @Transactional(noRollbackFor = {EmptyResultDataAccessException.class}, propagation = Propagation.REQUIRES_NEW) public void hardDeleteManualRedactions(String fileId, String annotationId) { addRedactionPersistenceService.hardDelete(fileId, annotationId); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java index 0f9dc70b6..c5b5c656a 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionService.java @@ -113,6 +113,8 @@ public class ManualRedactionService { manualRedactionDictionaryUpdateHandler.validateDictionariesForDelete(removeRedactionRequest, removeRedactionRequest.getTypeToRemove(), removeRedactionRequest.getDossierTemplateId()); + + log.info("add removeRedaction for file {} and annotation {}", fileId, removeRedactionRequest.getAnnotationId()); removeRedactionPersistenceService.insert(fileId, removeRedactionRequest); if (manualAddRedactionsContains(manualRedactions, removeRedactionRequest.getAnnotationId())) { @@ -121,8 +123,6 @@ public class ManualRedactionService { continue; } - log.info("add removeRedaction for file {} and annotation {}", fileId, removeRedactionRequest.getAnnotationId()); - Long commentId = commentService.addCommentAndGetId(fileId, removeRedactionRequest.getAnnotationId(), removeRedactionRequest.getComment(), diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/AddRedactionPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/AddRedactionPersistenceService.java index 20e219cee..90626b899 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/AddRedactionPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/AddRedactionPersistenceService.java @@ -58,7 +58,6 @@ public class AddRedactionPersistenceService { } - public ManualRedactionEntryEntity findAddRedaction(String fileId, String annotationId) { return manualRedactionRepository.findAddRedaction(new AnnotationEntityId(annotationId, fileId)) @@ -66,9 +65,6 @@ public class AddRedactionPersistenceService { } - - - public List findAddRedactions(String fileId, boolean includeDeletions) { return manualRedactionRepository.findByFileIdIncludeDeletions(fileId, includeDeletions); @@ -80,6 +76,7 @@ public class AddRedactionPersistenceService { return manualRedactionRepository.findAll(); } + public List findUnprocessedRedactions(String fileId) { return manualRedactionRepository.findByFileIdAndUnprocessed(fileId); @@ -113,6 +110,7 @@ public class AddRedactionPersistenceService { manualRedactionRepository.updateStatus(new AnnotationEntityId(annotationId, fileId), annotationStatus, processedDate); } + @Transactional public void updateStatus(String fileId, String annotationId, @@ -131,7 +129,6 @@ public class AddRedactionPersistenceService { } - @Transactional public void approveStatusForRequestedRedactionsWithSameValue(Set fileIds, String value) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ForceRedactionPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ForceRedactionPersistenceService.java index 161f234a4..ee72380f9 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ForceRedactionPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ForceRedactionPersistenceService.java @@ -77,11 +77,13 @@ public class ForceRedactionPersistenceService { return new HashSet<>(forceRedactionRepository.findByFileIdIncludeDeletions(fileId, includeDeletions)); } + public Set findUnprocessedForceRedactions(String fileId) { return new HashSet<>(forceRedactionRepository.findByFileIdAndUnprocessed(fileId)); } + @Transactional public void markAsProcessed(String annotationId, String fileId) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/LegalBasisChangePersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/LegalBasisChangePersistenceService.java index f768c5628..51a82bc34 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/LegalBasisChangePersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/LegalBasisChangePersistenceService.java @@ -4,7 +4,6 @@ import java.time.OffsetDateTime; import java.time.temporal.ChronoUnit; import java.util.HashSet; import java.util.Set; -import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; @@ -43,6 +42,7 @@ public class LegalBasisChangePersistenceService { } + private void checkSection(String section) { if (!StringUtils.isEmpty(section) && section.length() > SECTION_MAX_LENGTH) { @@ -91,6 +91,7 @@ public class LegalBasisChangePersistenceService { return new HashSet<>(legalBasisChangeRepository.findByFileIdIncludeDeletions(fileId, includeDeletions)); } + public Set findUnprocessedLegalBasisChanges(String fileId) { return new HashSet<>(legalBasisChangeRepository.findUnprocessedByFileId(fileId)); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RecategorizationPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RecategorizationPersistenceService.java index 91c048508..b34602d2d 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RecategorizationPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RecategorizationPersistenceService.java @@ -99,6 +99,7 @@ public class RecategorizationPersistenceService { return recategorizationRepository.findByFileIdIncludeDeletions(fileId, includeDeletions); } + public List findUnprocessedRecategorizations(String fileId) { return recategorizationRepository.findUnprocessedByFileId(fileId); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RemoveRedactionPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RemoveRedactionPersistenceService.java index 3fd1d50ce..446338865 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RemoveRedactionPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/RemoveRedactionPersistenceService.java @@ -5,7 +5,6 @@ import java.time.temporal.ChronoUnit; import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.stream.Collectors; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; @@ -54,6 +53,7 @@ public class RemoveRedactionPersistenceService { return new HashSet<>(removeRedactionRepository.findByFileIdIncludeDeletions(fileId, includeDeletions)); } + public Set findUnprocessedRemoveRedactions(String fileId) { return new HashSet<>(removeRedactionRepository.findByFileIdAndUnprocessed(fileId)); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ResizeRedactionPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ResizeRedactionPersistenceService.java index 91fa27a08..39cc50982 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ResizeRedactionPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/annotations/ResizeRedactionPersistenceService.java @@ -93,6 +93,7 @@ public class ResizeRedactionPersistenceService { return resizeRedactionRepository.findByFileIdIncludeDeletions(fileId, includeDeletions); } + public List findUnprocessedResizeRedactions(String fileId) { return resizeRedactionRepository.findUnprocessedByFileId(fileId); diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java index fde66ae37..d57ee8b8f 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java @@ -49,6 +49,7 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.Lega import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RecategorizationRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.RemoveRedactionRequestModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.ResizeRedactionRequestModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.Point; import feign.FeignException; @@ -117,7 +118,14 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var entityLog = new EntityLog(1, 1, - List.of(EntityLogEntry.builder().id("AnnotationId").type(type.getType()).value("Luke Skywalker").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(true).build()), + List.of(EntityLogEntry.builder() + .id("AnnotationId") + .type(type.getType()) + .value("Luke Skywalker") + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .dictionaryEntry(true) + .build()), null, 0, 0, @@ -266,7 +274,14 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var entityLog = new EntityLog(1, 1, - List.of(EntityLogEntry.builder().id("AnnotationId").type("test").value("Luke Skywalker").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(true).build()), + List.of(EntityLogEntry.builder() + .id("AnnotationId") + .type("test") + .value("Luke Skywalker") + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .dictionaryEntry(true) + .build()), null, 0, 0, @@ -314,7 +329,14 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var entityLog = new EntityLog(1, 1, - List.of(EntityLogEntry.builder().id("AnnotationId").type("test").value("Luke Skywalker").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(true).build()), + List.of(EntityLogEntry.builder() + .id("AnnotationId") + .type("test") + .value("Luke Skywalker") + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .dictionaryEntry(true) + .build()), null, 0, 0, @@ -355,7 +377,14 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var entityLog = new EntityLog(1, 1, - List.of(EntityLogEntry.builder().id("AnnotationId").type("test").value("Luke Skywalker").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(true).build()), + List.of(EntityLogEntry.builder() + .id("AnnotationId") + .type("test") + .value("Luke Skywalker") + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .dictionaryEntry(true) + .build()), null, 0, 0, @@ -488,9 +517,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { assertThat(loadedRedactionsFile1.getResizeRedactions()).hasSize(1); assertThat(loadedRedactionsFile1.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier dictionary"); - var dictEntries = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getId(), - "test redaction in dossier dictionary", - DictionaryEntryType.ENTRY); + var dictEntries = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getId(), "test redaction in dossier dictionary", DictionaryEntryType.ENTRY); assertThat(dictEntries.stream().filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier dictionary"))).isNotEmpty(); var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getId()); @@ -643,16 +670,12 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { assertThat(loadedRedactionsFile1.getResizeRedactions()).hasSize(1); assertThat(loadedRedactionsFile1.getResizeRedactions().stream().toList().get(0).getValue()).isEqualTo("test redaction in dossier"); - var dictEntriesOldValue = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getId(), - "test redaction in dossier yayy", - DictionaryEntryType.ENTRY); + var dictEntriesOldValue = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getId(), "test redaction in dossier yayy", DictionaryEntryType.ENTRY); assertThat(dictEntriesOldValue.stream() .filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier yayy") && dictionaryEntry.isDeleted())).hasSize(1); assertThat(dictEntriesOldValue.stream() .filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier yayy") && !dictionaryEntry.isDeleted())).hasSize(1); - var dictEntriesNewValue = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getId(), - "test redaction in dossier", - DictionaryEntryType.ENTRY); + var dictEntriesNewValue = dictionaryManagementService.getAllEntriesInDossierTemplate(dossierTemplate.getId(), "test redaction in dossier", DictionaryEntryType.ENTRY); assertThat(dictEntriesNewValue.stream().filter(dictionaryEntry -> dictionaryEntry.getValue().equals("test redaction in dossier"))).isNotEmpty(); var dictionaryOfTypeDosDictInDossier1 = dictionaryClient.getDictionaryForType(typeDosDict.getType(), dossier1.getDossierTemplateId(), dossier1.getId()); @@ -1040,7 +1063,14 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var annotationId = "AnnotationId"; var entityLog = new EntityLog(1, 1, - List.of(EntityLogEntry.builder().id(annotationId).type(type.getType()).value(lukeSkywalker).dictionaryEntry(true).entryType(EntryType.ENTITY).state(EntryState.APPLIED).build()), + List.of(EntityLogEntry.builder() + .id(annotationId) + .type(type.getType()) + .value(lukeSkywalker) + .dictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .build()), null, 0, 0, @@ -1110,7 +1140,14 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var annotationId = "AnnotationId"; var entityLog = new EntityLog(1, 1, - List.of(EntityLogEntry.builder().id(annotationId).type(type.getType()).value(lukeSkywalker).dictionaryEntry(true).entryType(EntryType.ENTITY).state(EntryState.APPLIED).build()), + List.of(EntityLogEntry.builder() + .id(annotationId) + .type(type.getType()) + .value(lukeSkywalker) + .dictionaryEntry(true) + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .build()), null, 0, 0, @@ -1147,6 +1184,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { assertThat(dossierDictionary2.getEntries()).isEmpty(); } + @Test public void testUnprocessedManualRedactionsAddRedaction() { @@ -1180,9 +1218,15 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { assertEquals(unprocessedManualRedactions.getEntriesToAdd().size(), 1); assertTrue(unprocessedManualRedactions.getEntriesToAdd().stream().anyMatch(entry -> entry.getValue().equals("Luke Skywalker"))); - fileProcessingClient.analysisSuccessful(dossier.getId(), file.getId(), AnalyzeResult.builder() - .manualRedactions(allManualRedactions) - .messageType(MessageType.ANALYSE).analysisVersion(0).fileId(file.getId()).dossierId(dossier.getId()).build()); + fileProcessingClient.analysisSuccessful(dossier.getId(), + file.getId(), + AnalyzeResult.builder() + .manualRedactions(allManualRedactions) + .messageType(MessageType.ANALYSE) + .analysisVersion(0) + .fileId(file.getId()) + .dossierId(dossier.getId()) + .build()); manualRedactionClient.addRedactionBulk(dossier.getId(), file.getId(), @@ -1209,9 +1253,15 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { assertTrue(unprocessedManualRedactions.getEntriesToAdd().stream().anyMatch(entry -> entry.getValue().equals("Skywalker Luke"))); assertTrue(unprocessedManualRedactions.getEntriesToAdd().stream().noneMatch(entry -> entry.getValue().equals("Luke Skywalker"))); - fileProcessingClient.analysisSuccessful(dossier.getId(), file.getId(), AnalyzeResult.builder() - .manualRedactions(allManualRedactions) - .messageType(MessageType.ANALYSE).analysisVersion(1).fileId(file.getId()).dossierId(dossier.getId()).build()); + fileProcessingClient.analysisSuccessful(dossier.getId(), + file.getId(), + AnalyzeResult.builder() + .manualRedactions(allManualRedactions) + .messageType(MessageType.ANALYSE) + .analysisVersion(1) + .fileId(file.getId()) + .dossierId(dossier.getId()) + .build()); allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); assertEquals(allManualRedactions.getEntriesToAdd().size(), 2); @@ -1224,6 +1274,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("Luke Skywalker"), false, dossier.getId(), DictionaryEntryType.ENTRY); } + @Test public void testUnprocessedManualRedactionsRemoveRedaction() { @@ -1237,8 +1288,22 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var entityLog = new EntityLog(1, 1, - List.of(EntityLogEntry.builder().id("AnnotationId").type(type.getType()).value("Anakin").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(false).build(), - EntityLogEntry.builder().id("AnnotationId2").type(type.getType()).value("Anakin2").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(false).build()), + List.of(EntityLogEntry.builder() + .id("AnnotationId") + .type(type.getType()) + .value("Anakin") + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .dictionaryEntry(false) + .build(), + EntityLogEntry.builder() + .id("AnnotationId2") + .type(type.getType()) + .value("Anakin2") + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .dictionaryEntry(false) + .build()), null, 0, 0, @@ -1262,7 +1327,13 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { fileProcessingClient.analysisSuccessful(dossier.getId(), file.getId(), - AnalyzeResult.builder().manualRedactions(allManualRedactions).messageType(MessageType.ANALYSE).analysisVersion(0).fileId(file.getId()).dossierId(dossier.getId()).build()); + AnalyzeResult.builder() + .manualRedactions(allManualRedactions) + .messageType(MessageType.ANALYSE) + .analysisVersion(0) + .fileId(file.getId()) + .dossierId(dossier.getId()) + .build()); manualRedactionClient.removeRedactionBulk(dossier.getId(), file.getId(), @@ -1280,7 +1351,13 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { fileProcessingClient.analysisSuccessful(dossier.getId(), file.getId(), - AnalyzeResult.builder().manualRedactions(allManualRedactions).messageType(MessageType.ANALYSE).analysisVersion(1).fileId(file.getId()).dossierId(dossier.getId()).build()); + AnalyzeResult.builder() + .manualRedactions(allManualRedactions) + .messageType(MessageType.ANALYSE) + .analysisVersion(1) + .fileId(file.getId()) + .dossierId(dossier.getId()) + .build()); allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); assertEquals(allManualRedactions.getIdsToRemove().size(), 2); @@ -1291,6 +1368,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { assertTrue(unprocessedManualRedactions.getIdsToRemove().isEmpty()); } + @Test public void testUnprocessedManualRedactionsForceRedaction() { @@ -1312,7 +1390,13 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { fileProcessingClient.analysisSuccessful(dossier.getId(), file.getId(), - AnalyzeResult.builder().manualRedactions(allManualRedactions).messageType(MessageType.ANALYSE).analysisVersion(0).fileId(file.getId()).dossierId(dossier.getId()).build()); + AnalyzeResult.builder() + .manualRedactions(allManualRedactions) + .messageType(MessageType.ANALYSE) + .analysisVersion(0) + .fileId(file.getId()) + .dossierId(dossier.getId()) + .build()); manualRedactionClient.forceRedactionBulk(dossier.getId(), file.getId(), @@ -1330,7 +1414,13 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { fileProcessingClient.analysisSuccessful(dossier.getId(), file.getId(), - AnalyzeResult.builder().manualRedactions(allManualRedactions).messageType(MessageType.ANALYSE).analysisVersion(1).fileId(file.getId()).dossierId(dossier.getId()).build()); + AnalyzeResult.builder() + .manualRedactions(allManualRedactions) + .messageType(MessageType.ANALYSE) + .analysisVersion(1) + .fileId(file.getId()) + .dossierId(dossier.getId()) + .build()); allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); assertEquals(allManualRedactions.getForceRedactions().size(), 2); @@ -1341,8 +1431,9 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { assertTrue(unprocessedManualRedactions.getForceRedactions().isEmpty()); } - @Test - public void testUnprocessedManualRedactionsRecategorizations() { + + @Test + public void testUnprocessedManualRedactionsRecategorizations() { var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate); @@ -1354,8 +1445,22 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var entityLog = new EntityLog(1, 1, - List.of(EntityLogEntry.builder().id("dv").type(type.getType()).value("Darth Vader").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(false).build(), - EntityLogEntry.builder().id("dv2").type(type.getType()).value("Vader Darth").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(false).build()), + List.of(EntityLogEntry.builder() + .id("dv") + .type(type.getType()) + .value("Darth Vader") + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .dictionaryEntry(false) + .build(), + EntityLogEntry.builder() + .id("dv2") + .type(type.getType()) + .value("Vader Darth") + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .dictionaryEntry(false) + .build()), null, 0, 0, @@ -1365,9 +1470,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(entityLog); - manualRedactionClient.recategorizeBulk(dossier.getId(), - file.getId(), - Set.of(RecategorizationRequestModel.builder().annotationId("dv").build())); + manualRedactionClient.recategorizeBulk(dossier.getId(), file.getId(), Set.of(RecategorizationRequestModel.builder().annotationId("dv").build())); var allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); assertEquals(allManualRedactions.getRecategorizations().size(), 1); @@ -1379,11 +1482,15 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { fileProcessingClient.analysisSuccessful(dossier.getId(), file.getId(), - AnalyzeResult.builder().manualRedactions(allManualRedactions).messageType(MessageType.ANALYSE).analysisVersion(0).fileId(file.getId()).dossierId(dossier.getId()).build()); + AnalyzeResult.builder() + .manualRedactions(allManualRedactions) + .messageType(MessageType.ANALYSE) + .analysisVersion(0) + .fileId(file.getId()) + .dossierId(dossier.getId()) + .build()); - manualRedactionClient.recategorizeBulk(dossier.getId(), - file.getId(), - Set.of(RecategorizationRequestModel.builder().annotationId("dv2").build())); + manualRedactionClient.recategorizeBulk(dossier.getId(), file.getId(), Set.of(RecategorizationRequestModel.builder().annotationId("dv2").build())); allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); assertEquals(allManualRedactions.getRecategorizations().size(), 2); @@ -1397,7 +1504,13 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { fileProcessingClient.analysisSuccessful(dossier.getId(), file.getId(), - AnalyzeResult.builder().manualRedactions(allManualRedactions).messageType(MessageType.ANALYSE).analysisVersion(1).fileId(file.getId()).dossierId(dossier.getId()).build()); + AnalyzeResult.builder() + .manualRedactions(allManualRedactions) + .messageType(MessageType.ANALYSE) + .analysisVersion(1) + .fileId(file.getId()) + .dossierId(dossier.getId()) + .build()); allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); assertEquals(allManualRedactions.getRecategorizations().size(), 2); @@ -1408,6 +1521,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { assertTrue(unprocessedManualRedactions.getRecategorizations().isEmpty()); } + @Test public void testUnprocessedManualRedactionsLegalBasisChanges() { @@ -1421,8 +1535,22 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { var entityLog = new EntityLog(1, 1, - List.of(EntityLogEntry.builder().id("AnnotationId").type(type.getType()).value("Luke Skywalker").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(false).build(), - EntityLogEntry.builder().id("AnnotationId2").type(type.getType()).value("Skywalker Luke").entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(false).build()), + List.of(EntityLogEntry.builder() + .id("AnnotationId") + .type(type.getType()) + .value("Luke Skywalker") + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .dictionaryEntry(false) + .build(), + EntityLogEntry.builder() + .id("AnnotationId2") + .type(type.getType()) + .value("Skywalker Luke") + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .dictionaryEntry(false) + .build()), null, 0, 0, @@ -1446,7 +1574,13 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { fileProcessingClient.analysisSuccessful(dossier.getId(), file.getId(), - AnalyzeResult.builder().manualRedactions(allManualRedactions).messageType(MessageType.ANALYSE).analysisVersion(0).fileId(file.getId()).dossierId(dossier.getId()).build()); + AnalyzeResult.builder() + .manualRedactions(allManualRedactions) + .messageType(MessageType.ANALYSE) + .analysisVersion(0) + .fileId(file.getId()) + .dossierId(dossier.getId()) + .build()); manualRedactionClient.legalBasisChangeBulk(dossier.getId(), file.getId(), @@ -1464,7 +1598,13 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { fileProcessingClient.analysisSuccessful(dossier.getId(), file.getId(), - AnalyzeResult.builder().manualRedactions(allManualRedactions).messageType(MessageType.ANALYSE).analysisVersion(1).fileId(file.getId()).dossierId(dossier.getId()).build()); + AnalyzeResult.builder() + .manualRedactions(allManualRedactions) + .messageType(MessageType.ANALYSE) + .analysisVersion(1) + .fileId(file.getId()) + .dossierId(dossier.getId()) + .build()); allManualRedactions = manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false); assertEquals(allManualRedactions.getLegalBasisChanges().size(), 2); @@ -1475,4 +1615,59 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { assertTrue(unprocessedManualRedactions.getResizeRedactions().isEmpty()); } + + @Test + public void testRemoveManualRedactionEntityRemovesAllManualRedactions() { + + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate); + var file = fileTesterAndProvider.testAndProvideFile(dossier); + String type = "manual"; + String value = "Luke Skywalker"; + var manualAddResponse = manualRedactionClient.addRedactionBulk(dossier.getId(), + file.getId(), + Set.of(AddRedactionRequestModel.builder() + .sourceId("sourceId") + .type(type) + .value(value) + .reason("Reason") + .positions(List.of(new Rectangle(new Point(0, 0), 100, 100, 0))) + .build())).get(0); + String annotationId = manualAddResponse.getAnnotationId(); + var entityLog = new EntityLog(1, + 1, + List.of(EntityLogEntry.builder().id(annotationId).type(type).value(value).entryType(EntryType.ENTITY).state(EntryState.APPLIED).dictionaryEntry(false).build()), + null, + 0, + 0, + 0, + 0); + fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.ENTITY_LOG, entityLog); + + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(entityLog); + + assertEquals(1, manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false).getEntriesToAdd().size()); + assertEquals(annotationId, + manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false).getEntriesToAdd().stream().findFirst().orElseThrow().getAnnotationId()); + manualRedactionClient.legalBasisChangeBulk(dossier.getId(), + file.getId(), + Set.of(LegalBasisChangeRequestModel.builder().annotationId(annotationId).legalBasis("some legal basis").build())); + manualRedactionClient.forceRedactionBulk(dossier.getId(), file.getId(), Set.of(ForceRedactionRequestModel.builder().annotationId(annotationId).build())); + manualRedactionClient.recategorizeBulk(dossier.getId(), file.getId(), Set.of(RecategorizationRequestModel.builder().annotationId(annotationId).type("other type").build())); + manualRedactionClient.resizeRedactionBulk(dossier.getId(), + file.getId(), + Set.of(ResizeRedactionRequestModel.builder() + .annotationId(annotationId) + .value("Luke Skywalker and some more text") + .positions(List.of(new Rectangle(new Point(10, 10), 100, 100, 1))) + .build())); + manualRedactionClient.removeRedactionBulk(dossier.getId(), file.getId(), Set.of(RemoveRedactionRequestModel.builder().annotationId(annotationId).build())); + assertTrue(manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false).getEntriesToAdd().isEmpty()); + assertTrue(manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false).getLegalBasisChanges().isEmpty()); + assertTrue(manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false).getForceRedactions().isEmpty()); + assertTrue(manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false).getRecategorizations().isEmpty()); + assertTrue(manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false).getResizeRedactions().isEmpty()); + assertEquals(1, manualRedactionClient.getManualRedactions(dossier.getId(), file.getId(), false).getIdsToRemove().size()); + } + } -- 2.47.2 From 58e66f920caf161f1b1e05e45f612b4f464fedc7 Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Mon, 23 Oct 2023 13:54:26 +0200 Subject: [PATCH 26/96] DM-285: change fields of comments --- .../v1/processor/service/CommentService.java | 11 ++++++++++- .../ManualRedactionProviderService.java | 15 ++++++--------- .../v1/api/shared/model/annotations/Comment.java | 3 +-- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java index 6288f59c7..667b22792 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java @@ -4,6 +4,7 @@ import java.time.OffsetDateTime; import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Map; +import java.util.function.BiConsumer; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; @@ -66,7 +67,13 @@ public class CommentService { return new Comments(commentPersistenceService.findCommentsByFileID(fileId, false) .entrySet() .stream() - .collect(Collectors.toMap(Map.Entry::getKey, entry -> MagicConverter.convert(entry.getValue(), Comment.class)))); + .collect(Collectors.toMap(Map.Entry::getKey, entry -> MagicConverter.convert(entry.getValue(), Comment.class, getDeltaMapper())))); + } + + + private static BiConsumer getDeltaMapper() { + + return (c1, c2) -> c2.setUserId(c1.getUser()); } @@ -96,6 +103,7 @@ public class CommentService { return createdComment; } + private void checkComment(String text) { if (!StringUtils.isEmpty(text) && text.length() > COMMENT_MAX_LENGTH) { @@ -103,6 +111,7 @@ public class CommentService { } } + public Long addCommentAndGetId(String fileId, String annotationId, String comment, String user) { if (comment == null) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java index ba268ed99..130dd4eac 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java @@ -2,10 +2,8 @@ package com.iqser.red.service.persistence.management.v1.processor.service.manual import static com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter.convert; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -14,8 +12,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; -import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.CommentEntity; import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity; +import com.iqser.red.service.persistence.management.v1.processor.service.CommentService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.CommentPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ForceRedactionPersistenceService; @@ -26,7 +24,7 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist import com.iqser.red.service.persistence.management.v1.processor.utils.ManualImageRecategorizationMapper; import com.iqser.red.service.persistence.management.v1.processor.utils.ManualRedactionMapper; import com.iqser.red.service.persistence.management.v1.processor.utils.ManualResizeRedactionMapper; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comment; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comments; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.IdRemoval; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualForceRedaction; @@ -47,6 +45,7 @@ public class ManualRedactionProviderService { private final RemoveRedactionPersistenceService removeRedactionPersistenceService; private final ForceRedactionPersistenceService forceRedactionPersistenceService; private final CommentPersistenceService commentPersistenceService; + private final CommentService commentService; private final RecategorizationPersistenceService recategorizationPersistenceService; private final LegalBasisChangePersistenceService legalBasisChangePersistenceService; private final ResizeRedactionPersistenceService resizeRedactionPersistenceService; @@ -93,12 +92,10 @@ public class ManualRedactionProviderService { new ManualResizeRedactionMapper())); } - Map> commentEntities = commentPersistenceService.findCommentsByFileID(fileId, false); + // deprecated anyway, remove as soon as UI uses EntityLog + Comments comments = commentService.getComments(fileId); - Map> comments = new HashMap<>(); - commentEntities.forEach((s, c) -> comments.put(s, convert(c, Comment.class))); - - return new ManualRedactions(removals, entriesToAdd, forceRedactions, recategorizations, legalBasisChanges, resizeRedactions, comments); + return new ManualRedactions(removals, entriesToAdd, forceRedactions, recategorizations, legalBasisChanges, resizeRedactions, comments.getComments()); } diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/Comment.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/Comment.java index c19d853a8..e57b29464 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/Comment.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/Comment.java @@ -15,10 +15,9 @@ public class Comment { private long id; private String fileId; - private String annotationId; private OffsetDateTime date; private String text; - private String user; + private String userId; private OffsetDateTime softDeletedTime; } -- 2.47.2 From c831eb70256292b8126358351b4c87049f202def Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Mon, 23 Oct 2023 14:10:46 +0200 Subject: [PATCH 27/96] DM-285: resolve circular dependecies --- .../management/v1/processor/service/CommentService.java | 8 ++++++-- .../manualredactions/ManualRedactionProviderService.java | 4 +--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java index 667b22792..aab36449d 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java @@ -31,8 +31,6 @@ public class CommentService { CommentPersistenceService commentPersistenceService; FileStatusPersistenceService fileStatusPersistenceService; - FileStatusService fileStatusService; - FileManagementStorageService fileManagementStorageService; private final int COMMENT_MAX_LENGTH = 4000; @@ -137,6 +135,12 @@ public class CommentService { .build()); } + + public void hardDelete(String fileId, String annotationId) { + + commentPersistenceService.hardDelete(fileId, annotationId); + } + // // private void reprocess(String dossierId, String fileId) { // diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java index 130dd4eac..aea854c40 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java @@ -15,7 +15,6 @@ import org.springframework.transaction.annotation.Transactional; import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ManualRedactionEntryEntity; import com.iqser.red.service.persistence.management.v1.processor.service.CommentService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.AddRedactionPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.CommentPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.ForceRedactionPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.LegalBasisChangePersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.RecategorizationPersistenceService; @@ -44,7 +43,6 @@ public class ManualRedactionProviderService { private final AddRedactionPersistenceService addRedactionPersistenceService; private final RemoveRedactionPersistenceService removeRedactionPersistenceService; private final ForceRedactionPersistenceService forceRedactionPersistenceService; - private final CommentPersistenceService commentPersistenceService; private final CommentService commentService; private final RecategorizationPersistenceService recategorizationPersistenceService; private final LegalBasisChangePersistenceService legalBasisChangePersistenceService; @@ -114,7 +112,7 @@ public class ManualRedactionProviderService { recategorizationPersistenceService.hardDelete(fileId, annotationId); legalBasisChangePersistenceService.hardDelete(fileId, annotationId); resizeRedactionPersistenceService.hardDelete(fileId, annotationId); - commentPersistenceService.hardDelete(fileId, annotationId); + commentService.hardDelete(fileId, annotationId); } } -- 2.47.2 From 48d432024a1fce8bcf07a0a900bcaa4fff57ee6d Mon Sep 17 00:00:00 2001 From: Andrei Isvoran Date: Tue, 24 Oct 2023 11:22:44 +0200 Subject: [PATCH 28/96] RED-7782 - Remove comments --- .../manualredactions/ManualRedactionProviderService.java | 5 +---- .../v1/api/shared/model/annotations/ManualRedactions.java | 4 ---- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java index aea854c40..379c858d8 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java @@ -90,10 +90,7 @@ public class ManualRedactionProviderService { new ManualResizeRedactionMapper())); } - // deprecated anyway, remove as soon as UI uses EntityLog - Comments comments = commentService.getComments(fileId); - - return new ManualRedactions(removals, entriesToAdd, forceRedactions, recategorizations, legalBasisChanges, resizeRedactions, comments.getComments()); + return new ManualRedactions(removals, entriesToAdd, forceRedactions, recategorizations, legalBasisChanges, resizeRedactions); } diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ManualRedactions.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ManualRedactions.java index 47a93d532..30e53b5e1 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ManualRedactions.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/ManualRedactions.java @@ -42,8 +42,4 @@ public class ManualRedactions { @Builder.Default private Set resizeRedactions = new HashSet<>(); - @Deprecated(forRemoval = true) - @Builder.Default - private Map> comments = new HashMap<>(); - } -- 2.47.2 From 6d245ae7b62a20fa728d9cce258a434fe49b3b78 Mon Sep 17 00:00:00 2001 From: Corina Olariu Date: Tue, 24 Oct 2023 13:32:07 +0300 Subject: [PATCH 29/96] RED-7812 - Dossier template will be renamed every time after each import - when checking for the existence of the dossier template name ignore the dossier template id of the one that will be replaced --- .../v1/processor/service/DossierTemplateImportService.java | 3 ++- .../persistence/DossierTemplatePersistenceService.java | 6 +++--- .../persistence/repository/DossierTemplateRepository.java | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java index e0e467632..17a5ed46f 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java @@ -556,6 +556,7 @@ public class DossierTemplateImportService { private void updateDossierTemplateMeta(DossierTemplateEntity dossierTemplateEntity, DossierTemplate dossierTemplate, String userId) { + dossierTemplate.setId(dossierTemplateEntity.getId()); if (!dossierTemplateEntity.getName().equalsIgnoreCase(dossierTemplate.getName())) { this.validateDossierTemplateName(dossierTemplate); } @@ -714,7 +715,7 @@ public class DossierTemplateImportService { int nameSuffix = 0; String dossierTemplateName = dossierTemplateMeta.getName(); - while (dossierTemplatePersistenceService.isDossierTemplateNameNotUnique(dossierTemplateMeta.getName())) { + while (dossierTemplatePersistenceService.isDossierTemplateNameNotUnique(dossierTemplateMeta.getName(), dossierTemplateMeta.getId())) { if (nameSuffix == 0) { dossierTemplateMeta.setName("Copy of " + dossierTemplateName); } else { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java index 52ff50436..79f743e0b 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java @@ -90,7 +90,7 @@ public class DossierTemplatePersistenceService { @Transactional public void validateDossierTemplateNameIsUnique(String templateName) { - if (isDossierTemplateNameNotUnique(templateName)) { + if (isDossierTemplateNameNotUnique(templateName, null)) { throw new ConflictException("DossierTemplate name must be unique"); } } @@ -109,9 +109,9 @@ public class DossierTemplatePersistenceService { @Transactional - public boolean isDossierTemplateNameNotUnique(String templateName) { + public boolean isDossierTemplateNameNotUnique(String templateName, String dossierTemplateIdToIgnore) { - return dossierTemplateRepository.existsByName(templateName); + return dossierTemplateRepository.existsByNameAndIdNot(templateName, dossierTemplateIdToIgnore); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DossierTemplateRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DossierTemplateRepository.java index b8f9348e5..057d20ca4 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DossierTemplateRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DossierTemplateRepository.java @@ -18,6 +18,6 @@ public interface DossierTemplateRepository extends JpaRepository findByIdAndNotDeleted(String dossierTemplateId); - boolean existsByName(String name); + boolean existsByNameAndIdNot(String name, String id); } -- 2.47.2 From 5a3432e6c6d2a9744a094905ceef91eef53d90a5 Mon Sep 17 00:00:00 2001 From: Corina Olariu Date: Tue, 24 Oct 2023 15:15:27 +0300 Subject: [PATCH 30/96] RED-7812 - Dossier template will be renamed every time after each import - put back the checking by name for the other cases (when cloning, creating, updating a dossier template) --- .../persistence/DossierTemplatePersistenceService.java | 10 ++++++++-- .../repository/DossierTemplateRepository.java | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java index 79f743e0b..9eaf511b2 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java @@ -89,8 +89,9 @@ public class DossierTemplatePersistenceService { @Transactional public void validateDossierTemplateNameIsUnique(String templateName) { - - if (isDossierTemplateNameNotUnique(templateName, null)) { + var isUnique = isDossierTemplateNameNotUnique(templateName); + log.info("validateDossierTemplateNameIsUnique {} - {}", isUnique, templateName); + if (isUnique) { throw new ConflictException("DossierTemplate name must be unique"); } } @@ -114,6 +115,11 @@ public class DossierTemplatePersistenceService { return dossierTemplateRepository.existsByNameAndIdNot(templateName, dossierTemplateIdToIgnore); } + @Transactional + public boolean isDossierTemplateNameNotUnique(String templateName) { + return dossierTemplateRepository.existsByName(templateName); + } + @Transactional public DossierTemplateStatus computeDossierTemplateStatus(DossierTemplateEntity dossierTemplate) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DossierTemplateRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DossierTemplateRepository.java index 057d20ca4..61fca2f2f 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DossierTemplateRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/DossierTemplateRepository.java @@ -17,6 +17,7 @@ public interface DossierTemplateRepository extends JpaRepository findByIdAndNotDeleted(String dossierTemplateId); + boolean existsByName(String name); boolean existsByNameAndIdNot(String name, String id); -- 2.47.2 From 8eac48206ba5345a5f478cf265979a9e6abb0d10 Mon Sep 17 00:00:00 2001 From: Corina Olariu Date: Tue, 24 Oct 2023 15:24:08 +0300 Subject: [PATCH 31/96] RED-7812 - Dossier template will be renamed every time after each import - remove unnecessary logs --- .../persistence/DossierTemplatePersistenceService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java index 9eaf511b2..cc3c0d40b 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java @@ -89,9 +89,8 @@ public class DossierTemplatePersistenceService { @Transactional public void validateDossierTemplateNameIsUnique(String templateName) { - var isUnique = isDossierTemplateNameNotUnique(templateName); - log.info("validateDossierTemplateNameIsUnique {} - {}", isUnique, templateName); - if (isUnique) { + + if (isDossierTemplateNameNotUnique(templateName)) { throw new ConflictException("DossierTemplate name must be unique"); } } @@ -117,6 +116,7 @@ public class DossierTemplatePersistenceService { @Transactional public boolean isDossierTemplateNameNotUnique(String templateName) { + return dossierTemplateRepository.existsByName(templateName); } -- 2.47.2 From 15b24ac8792c91349c7d578d884a21e14c655dcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominique=20Eifl=C3=A4nder?= Date: Wed, 25 Oct 2023 13:36:40 +0200 Subject: [PATCH 32/96] RED-7821: Added migration to fix wrong dossier dictionary entries in redaction logs --- ...ossierDictionaryEntryInRedactionLog14.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/FixDossierDictionaryEntryInRedactionLog14.java diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/FixDossierDictionaryEntryInRedactionLog14.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/FixDossierDictionaryEntryInRedactionLog14.java new file mode 100644 index 000000000..0d33b3ae5 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/migrations/FixDossierDictionaryEntryInRedactionLog14.java @@ -0,0 +1,29 @@ +package com.iqser.red.service.persistence.management.v1.processor.migration.migrations; + +import com.iqser.red.service.persistence.management.v1.processor.migration.Migration; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Slf4j +@Setter +@Service +public class FixDossierDictionaryEntryInRedactionLog14 extends Migration { + + private static final String NAME = "Fix dossier dictionary entries in redactionLog for non dossier dictionaries"; + private static final long VERSION = 14; + + + public FixDossierDictionaryEntryInRedactionLog14() { + + super(NAME, VERSION); + } + + + @Override + protected void migrate() { + // Migration is only needed in 3.6 + // File is only here to prevent other migration with same version. + } + +} -- 2.47.2 From c12abd028097c41a87c509bfa1a670860b0c31fe Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Wed, 25 Oct 2023 17:12:11 +0200 Subject: [PATCH 33/96] RED-7838: merge numberOfComments into EntityLog * also change comment endpoint to return comments per annotation instead of file --- .../controller/ManualRedactionController.java | 18 ++--- .../resource/ManualRedactionResource.java | 15 ++-- .../v1/processor/service/CommentService.java | 80 ++++++++----------- .../processor/service/EntityLogService.java | 22 +++-- .../ManualRedactionProviderService.java | 1 - .../repository/CommentRepository.java | 2 +- .../analysislog/entitylog/EntityLogEntry.java | 4 +- ...{Comments.java => AnnotationComments.java} | 5 +- 8 files changed, 72 insertions(+), 75 deletions(-) rename persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/{Comments.java => AnnotationComments.java} (76%) diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java index 2315ca208..0ffe9975e 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/ManualRedactionController.java @@ -28,8 +28,9 @@ import com.iqser.red.service.persistence.service.v1.api.external.resource.Manual import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory; import com.iqser.red.service.persistence.service.v1.api.shared.model.CommentResponse; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AddRedactionRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationComments; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comment; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.CommentRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comments; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ForceRedactionRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.LegalBasisChangeRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualAddResponse; @@ -99,14 +100,15 @@ public class ManualRedactionController implements ManualRedactionResource { .message("Comment was removed.") .details(Map.of(DOSSIER_ID, dossierId, FILE_ID, fileId, ANNOTATION_ID, annotationId)) .build()); - commentService.deleteComment(dossierId, fileId, List.of(Long.valueOf(commentId))); + commentService.deleteComment(fileId, List.of(Long.valueOf(commentId))); } @Override @PreAuthorize("hasAuthority('" + READ_MANUAL_REDACTIONS + "')") - public ManualRedactions getManualRedactions(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, + public ManualRedactions getManualRedactions(@PathVariable(DOSSIER_ID) String dossierId, + @PathVariable(FILE_ID) String fileId, @RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean unprocessed) { return manualRedactionService.getManualRedactions(fileId, unprocessed); @@ -115,12 +117,13 @@ public class ManualRedactionController implements ManualRedactionResource { @Override @PreAuthorize("hasAuthority('" + READ_MANUAL_REDACTIONS + "')") - public Comments getComments(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) { + public AnnotationComments getComments(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @PathVariable(ANNOTATION_ID) String annotationId) { dossierManagementService.getDossierById(dossierId, false, false); fileStatusManagementService.getFileStatus(fileId, false); - return commentService.getComments(fileId); + List comments = commentService.getComments(fileId, annotationId); + return new AnnotationComments(comments); } @@ -134,10 +137,7 @@ public class ManualRedactionController implements ManualRedactionResource { accessControlService.verifyFileIsNotApproved(dossierId, fileId); accessControlService.verifyUserIsReviewerOrApprover(dossierId, fileId); - var response = commentService.addComment(dossierId, - fileId, - annotationId, - CommentRequest.builder().user(KeycloakSecurity.getUserId()).text(addCommentRequest.getText()).build()); + var response = commentService.addComment(fileId, annotationId, CommentRequest.builder().user(KeycloakSecurity.getUserId()).text(addCommentRequest.getText()).build()); auditPersistenceService.audit(AuditRequest.builder() .userId(KeycloakSecurity.getUserId()) diff --git a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java index 6ef93bec1..907d41ae8 100644 --- a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java +++ b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/ManualRedactionResource.java @@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.CommentResponse; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comments; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationComments; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualAddResponse; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions; import com.iqser.red.service.persistence.service.v1.api.shared.model.manual.AddCommentRequestModel; @@ -131,16 +131,17 @@ public interface ManualRedactionResource { @ResponseStatus(value = HttpStatus.OK) @GetMapping(value = MANUAL_REDACTION_REST_PATH + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(summary = "Returns the manual redactions", description = "If the unprocessed flag is true then only the unprocessed manual redactions are returned. If the flag is false" + - "all manual redactions are returned. Default value for the flag is false.") + @Operation(summary = "Returns the manual redactions", description = "If the unprocessed flag is true then only the unprocessed manual redactions are returned. If the flag is false" + "all manual redactions are returned. Default value for the flag is false.") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) - ManualRedactions getManualRedactions(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean unprocessed); + ManualRedactions getManualRedactions(@PathVariable(DOSSIER_ID) String dossierId, + @PathVariable(FILE_ID) String fileId, + @RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean unprocessed); @ResponseStatus(value = HttpStatus.OK) - @GetMapping(value = MANUAL_REDACTION_REST_PATH + "/comments" + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(summary = "Returns the comments for a specific file", description = "None") + @GetMapping(value = MANUAL_REDACTION_REST_PATH + "/comments" + DOSSIER_ID_PATH_PARAM + FILE_ID_PATH_VARIABLE + ANNOTATION_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "Returns the comments for a specific annotation in a specific file", description = "None") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")}) - Comments getComments(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId); + AnnotationComments getComments(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @PathVariable(ANNOTATION_ID) String annotationId); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java index aab36449d..f547f7335 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/CommentService.java @@ -17,7 +17,6 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist import com.iqser.red.service.persistence.management.v1.processor.service.persistence.annotations.CommentPersistenceService; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comment; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.CommentRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comments; import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter; import lombok.AccessLevel; @@ -35,69 +34,34 @@ public class CommentService { @Transactional - public void deleteComment(String dossierId, String fileId, List commentIds) { + public void deleteComment(String fileId, List commentIds) { for (var commentId : commentIds) { commentPersistenceService.softDelete(commentId, OffsetDateTime.now()); } // update indicator fileStatusPersistenceService.updateHasComments(fileId, commentPersistenceService.fileHasComments(fileId)); - - // Since entityLog does not have comments, no need to trigger reprocess or to store them -// // This is an ugly workaround, don't even look at it! -// // Basically we should change how comments work and not merge them into the redaction log. -// // if file is currently not analyzing, we can quickly change the redaction log, else we must wait for the analysis to finish. -// if (!fileStatusService.getStatus(fileId).getProcessingStatus().equals(ProcessingStatus.PROCESSED)) { -// reprocess(dossierId, fileId); -// return; -// } -// fileStatusService.setStatusProcessing(fileId); -// RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); -// redactionLog.getRedactionLogEntry().forEach(entry -> entry.getComments().removeIf(comment -> commentIds.contains(comment.getId()))); -// fileManagementStorageService.storeRedactionLog(dossierId, fileId, redactionLog); -// fileStatusService.setStatusProcessed(fileId); } @Transactional - public Comments getComments(String fileId) { + public Map> getComments(String fileId) { - return new Comments(commentPersistenceService.findCommentsByFileID(fileId, false) + return commentPersistenceService.findCommentsByFileID(fileId, false) .entrySet() .stream() - .collect(Collectors.toMap(Map.Entry::getKey, entry -> MagicConverter.convert(entry.getValue(), Comment.class, getDeltaMapper())))); - } - - - private static BiConsumer getDeltaMapper() { - - return (c1, c2) -> c2.setUserId(c1.getUser()); + .collect(Collectors.toMap(Map.Entry::getKey, entry -> toCommentList(entry.getValue()))); } @Transactional - public CommentEntity addComment(String dossierId, String fileId, String annotationId, CommentRequest commentRequest) { + public CommentEntity addComment(String fileId, String annotationId, CommentRequest commentRequest) { checkComment(commentRequest.getText()); CommentEntity createdComment = addComment(fileId, annotationId, commentRequest.getText(), commentRequest.getUser()); fileStatusPersistenceService.updateHasComments(fileId, true); - // Since entityLog does not have comments, no need to trigger reprocess or to store them -// // This is an ugly workaround, don't even look at it! -// // Basically we should change how comments work and not merge them into the redaction log. -// if (!fileStatusService.getStatus(fileId).getProcessingStatus().equals(ProcessingStatus.PROCESSED)) { -// reprocess(dossierId, fileId); -// return createdComment; -// } -// fileStatusService.setStatusProcessing(fileId); -// RedactionLog redactionLog = redactionLogService.getRedactionLog(dossierId, fileId); -// redactionLog.getRedactionLogEntry() -// .stream() -// .filter(entry -> entry.getId().equals(annotationId)) -// .forEach(entry -> entry.getComments().add(MagicConverter.convert(createdComment, RedactionLogComment.class))); -// fileManagementStorageService.storeRedactionLog(dossierId, fileId, redactionLog); -// fileStatusService.setStatusProcessed(fileId); return createdComment; } @@ -141,10 +105,34 @@ public class CommentService { commentPersistenceService.hardDelete(fileId, annotationId); } -// -// private void reprocess(String dossierId, String fileId) { -// -// fileStatusService.setStatusReprocessForManual(dossierId, fileId, true); -// } + + public List getComments(String fileId, String annotationId) { + + return toCommentList(commentPersistenceService.findCommentsByAnnotationId(fileId, annotationId, false)); + } + + + private static List toCommentList(List entity) { + + return entity.stream().map(CommentService::toComment).toList(); + } + + + private static Comment toComment(CommentEntity entity) { + + return MagicConverter.convert(entity, Comment.class, getDeltaMapper()); + } + + + private static BiConsumer getDeltaMapper() { + + return (c1, c2) -> c2.setUserId(c1.getUser()); + } + + + public Map getCommentCounts(String fileId) { + + return commentPersistenceService.findCommentsByFileID(fileId, false).entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().size())); + } } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java index 7a430f428..88bc4ebbd 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.Map; import org.springframework.stereotype.Service; @@ -12,14 +13,18 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.FilteredEntityLogRequest; +import lombok.AccessLevel; import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; @Service @RequiredArgsConstructor +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) public class EntityLogService { - private final FileManagementStorageService fileManagementStorageService; - private final FileStatusService fileStatusService; + FileManagementStorageService fileManagementStorageService; + FileStatusService fileStatusService; + CommentService commentService; public EntityLog getEntityLog(String dossierId, String fileId) { @@ -32,19 +37,22 @@ public class EntityLogService { var fileStatus = fileStatusService.getStatus(fileId); - EntityLog redactionLog; + EntityLog entityLog; - redactionLog = fileManagementStorageService.getEntityLog(dossierId, fileId); + entityLog = fileManagementStorageService.getEntityLog(dossierId, fileId); if (fileStatus.isExcluded()) { - redactionLog.setEntityLogEntry(new ArrayList<>()); + entityLog.setEntityLogEntry(new ArrayList<>()); } if (excludedTypes != null) { - redactionLog.getEntityLogEntry().removeIf(entry -> excludedTypes.contains(entry.getType())); + entityLog.getEntityLogEntry().removeIf(entry -> excludedTypes.contains(entry.getType())); } - return redactionLog; + Map commentCountPerAnnotationId = commentService.getCommentCounts(fileId); + entityLog.getEntityLogEntry().forEach(entityLogEntry -> entityLogEntry.setNumberOfComments(commentCountPerAnnotationId.getOrDefault(entityLogEntry.getId(), 0))); + + return entityLog; } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java index 379c858d8..0c340a270 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/manualredactions/ManualRedactionProviderService.java @@ -23,7 +23,6 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist import com.iqser.red.service.persistence.management.v1.processor.utils.ManualImageRecategorizationMapper; import com.iqser.red.service.persistence.management.v1.processor.utils.ManualRedactionMapper; import com.iqser.red.service.persistence.management.v1.processor.utils.ManualResizeRedactionMapper; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Comments; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.IdRemoval; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualForceRedaction; diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/CommentRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/CommentRepository.java index 61bb92566..19f0f264b 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/CommentRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/CommentRepository.java @@ -11,7 +11,7 @@ import com.iqser.red.service.persistence.management.v1.processor.entity.annotati public interface CommentRepository extends JpaRepository { - @Query("select e from CommentEntity e where e.fileId = :fileId and e.annotationId = :annotationId " + "and (:includeDeletions = true or e.softDeletedTime is null)") + @Query("select e from CommentEntity e where e.fileId = :fileId and e.annotationId = :annotationId and (:includeDeletions = true or e.softDeletedTime is null)") List findByFileIdAndAnnotationId(String fileId, String annotationId, boolean includeDeletions); diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/entitylog/EntityLogEntry.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/entitylog/EntityLogEntry.java index fc608f76a..b8105560c 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/entitylog/EntityLogEntry.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/entitylog/EntityLogEntry.java @@ -35,7 +35,7 @@ public class EntityLogEntry { List containingNodeId; String closestHeadline; String section; - + float[] color; @Builder.Default @@ -71,4 +71,6 @@ public class EntityLogEntry { @Builder.Default Set importedRedactionIntersections = new HashSet<>(); + int numberOfComments; + } diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/Comments.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/AnnotationComments.java similarity index 76% rename from persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/Comments.java rename to persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/AnnotationComments.java index 07bce8c08..c4c308d99 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/Comments.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/AnnotationComments.java @@ -1,7 +1,6 @@ package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations; import java.util.List; -import java.util.Map; import lombok.AllArgsConstructor; import lombok.Builder; @@ -12,8 +11,8 @@ import lombok.NoArgsConstructor; @Builder @AllArgsConstructor @NoArgsConstructor -public class Comments { +public class AnnotationComments { - Map> comments; + List comments; } -- 2.47.2 From 66f740b44aa3a9a65d82c89206a2ed43918c7e95 Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Thu, 26 Oct 2023 11:58:11 +0200 Subject: [PATCH 34/96] RED-7631: add EntryType IMAGE_HINT * also fix ManualResizeRedaction builder --- .../analysislog/entitylog/EntryType.java | 1 + .../entitymapped/BaseAnnotation.java | 2 ++ .../entitymapped/ManualResizeRedaction.java | 28 +++---------------- .../redactionlog/ManualRedactionType.java | 1 - 4 files changed, 7 insertions(+), 25 deletions(-) diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/entitylog/EntryType.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/entitylog/EntryType.java index 2720705d0..5eebb52e7 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/entitylog/EntryType.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/entitylog/EntryType.java @@ -7,5 +7,6 @@ public enum EntryType { RECOMMENDATION, FALSE_RECOMMENDATION, IMAGE, + IMAGE_HINT, AREA } diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/BaseAnnotation.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/BaseAnnotation.java index b6f9c882e..65e43eefe 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/BaseAnnotation.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/BaseAnnotation.java @@ -8,8 +8,10 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; @Data +@SuperBuilder @NoArgsConstructor @AllArgsConstructor @EqualsAndHashCode diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualResizeRedaction.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualResizeRedaction.java index 9b27ede77..c2629e1ed 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualResizeRedaction.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualResizeRedaction.java @@ -1,19 +1,20 @@ package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped; -import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.List; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Rectangle; -import lombok.Builder; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; @Data +@SuperBuilder @NoArgsConstructor +@AllArgsConstructor @EqualsAndHashCode(callSuper = true) public class ManualResizeRedaction extends BaseAnnotation { @@ -24,25 +25,4 @@ public class ManualResizeRedaction extends BaseAnnotation { private Boolean updateDictionary; private boolean addToAllDossiers; - - @Builder - public ManualResizeRedaction(String annotationId, - String fileId, - String user, - AnnotationStatus status, - OffsetDateTime requestDate, - OffsetDateTime processedDate, - OffsetDateTime softDeletedTime, - String value, - String textBefore, - String textAfter, - List positions) { - - super(annotationId, fileId, user, status, requestDate, processedDate, softDeletedTime); - this.textBefore = textBefore; - this.textAfter = textAfter; - this.value = value; - this.positions = positions != null ? positions : new ArrayList<>(); - } - } diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/redactionlog/ManualRedactionType.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/redactionlog/ManualRedactionType.java index f3018136a..8173fdf28 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/redactionlog/ManualRedactionType.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/redactionlog/ManualRedactionType.java @@ -1,7 +1,6 @@ package com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog; @Deprecated(forRemoval = true) - public enum ManualRedactionType { ADD_LOCALLY, ADD_TO_DICTIONARY, -- 2.47.2 From 9ebf22f52fccf3da56b1fa8e0a0c2d8b98e3b5b9 Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Thu, 26 Oct 2023 12:02:29 +0200 Subject: [PATCH 35/96] RED-7631: add EntryType IMAGE_HINT * also fix BaseAnnotation builder --- .../annotations/entitymapped/IdRemoval.java | 26 ++--------- .../entitymapped/ManualForceRedaction.java | 24 ++-------- .../entitymapped/ManualLegalBasisChange.java | 28 ++---------- .../entitymapped/ManualRecategorization.java | 24 ++-------- .../entitymapped/ManualRedactionEntry.java | 44 ++----------------- 5 files changed, 20 insertions(+), 126 deletions(-) diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/IdRemoval.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/IdRemoval.java index fac014413..0c3f43a5a 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/IdRemoval.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/IdRemoval.java @@ -1,37 +1,19 @@ package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped; -import java.time.OffsetDateTime; - -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; - -import lombok.Builder; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; @Data +@SuperBuilder @NoArgsConstructor +@AllArgsConstructor @EqualsAndHashCode(callSuper = true) public class IdRemoval extends BaseAnnotation { private boolean removeFromDictionary; private boolean removeFromAllDossiers; - - @Builder - public IdRemoval(String annotationId, - String fileId, - String user, - AnnotationStatus status, - OffsetDateTime requestDate, - OffsetDateTime processedDate, - OffsetDateTime softDeletedTime, - boolean removeFromDictionary, - boolean removeFromAllDossiers) { - - super(annotationId, fileId, user, status, requestDate, processedDate, softDeletedTime); - this.removeFromDictionary = removeFromDictionary; - this.removeFromAllDossiers = removeFromAllDossiers; - } - } diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualForceRedaction.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualForceRedaction.java index 20f72bcbe..991c06859 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualForceRedaction.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualForceRedaction.java @@ -1,34 +1,18 @@ package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped; -import java.time.OffsetDateTime; - -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; - -import lombok.Builder; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; @Data +@SuperBuilder @NoArgsConstructor +@AllArgsConstructor @EqualsAndHashCode(callSuper = true) public class ManualForceRedaction extends BaseAnnotation { private String legalBasis; - - @Builder - public ManualForceRedaction(String annotationId, - String fileId, - String user, - AnnotationStatus status, - OffsetDateTime requestDate, - OffsetDateTime processedDate, - OffsetDateTime softDeletedTime, - String legalBasis) { - - super(annotationId, fileId, user, status, requestDate, processedDate, softDeletedTime); - this.legalBasis = legalBasis; - } - } diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualLegalBasisChange.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualLegalBasisChange.java index d99d0b0de..5c2582d92 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualLegalBasisChange.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualLegalBasisChange.java @@ -1,16 +1,15 @@ package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped; -import java.time.OffsetDateTime; - -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; - -import lombok.Builder; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; @Data +@SuperBuilder @NoArgsConstructor +@AllArgsConstructor @EqualsAndHashCode(callSuper = true) public class ManualLegalBasisChange extends BaseAnnotation { @@ -18,23 +17,4 @@ public class ManualLegalBasisChange extends BaseAnnotation { private String value; private String legalBasis; - - @Builder - public ManualLegalBasisChange(String annotationId, - String fileId, - String user, - AnnotationStatus status, - OffsetDateTime requestDate, - OffsetDateTime processedDate, - OffsetDateTime softDeletedTime, - String legalBasis, - String section, - String value) { - - super(annotationId, fileId, user, status, requestDate, processedDate, softDeletedTime); - this.legalBasis = legalBasis; - this.section = section; - this.value = value; - } - } diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualRecategorization.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualRecategorization.java index ce4fae2d8..73ec2f57a 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualRecategorization.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualRecategorization.java @@ -1,34 +1,18 @@ package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped; -import java.time.OffsetDateTime; - -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; - -import lombok.Builder; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; @Data +@SuperBuilder @NoArgsConstructor +@AllArgsConstructor @EqualsAndHashCode(callSuper = true) public class ManualRecategorization extends BaseAnnotation { private String type; - - @Builder - public ManualRecategorization(String annotationId, - String fileId, - String user, - AnnotationStatus status, - OffsetDateTime requestDate, - OffsetDateTime processedDate, - OffsetDateTime softDeletedTime, - String type) { - - super(annotationId, fileId, user, status, requestDate, processedDate, softDeletedTime); - this.type = type; - } - } diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualRedactionEntry.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualRedactionEntry.java index ce2058d70..7ae2833e3 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualRedactionEntry.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/annotations/entitymapped/ManualRedactionEntry.java @@ -1,19 +1,20 @@ package com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped; -import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.List; -import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Rectangle; -import lombok.Builder; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; @Data +@SuperBuilder @NoArgsConstructor +@AllArgsConstructor @EqualsAndHashCode(callSuper = true) public class ManualRedactionEntry extends BaseAnnotation { @@ -30,41 +31,4 @@ public class ManualRedactionEntry extends BaseAnnotation { private String textAfter; private String sourceId; - - @Builder - public ManualRedactionEntry(String annotationId, - String fileId, - String user, - AnnotationStatus status, - OffsetDateTime requestDate, - OffsetDateTime processedDate, - OffsetDateTime softDeletedTime, - String value, - String textBefore, - String textAfter, - boolean rectangle, - boolean addToDictionary, - boolean addToDossierDictionary, - String legalBasis, - String section, - String reason, - String type, - List positions, - String sourceId) { - - super(annotationId, fileId, user, status, requestDate, processedDate, softDeletedTime); - this.textBefore = textBefore; - this.textAfter = textAfter; - this.value = value; - this.rectangle = rectangle; - this.addToDictionary = addToDictionary; - this.addToDossierDictionary = addToDossierDictionary; - this.legalBasis = legalBasis; - this.section = section; - this.reason = reason; - this.type = type; - this.positions = positions != null ? positions : new ArrayList<>(); - this.sourceId = sourceId; - } - } -- 2.47.2 From 75847a43d5e6d1482a19894e3a62dd5957606daf Mon Sep 17 00:00:00 2001 From: Andrei Isvoran Date: Thu, 26 Oct 2023 15:37:33 +0300 Subject: [PATCH 36/96] RED-7782 - Merge unprocessed redactions into entity log without re-analysis. --- .../impl/controller/EntityLogController.java | 5 +- .../external/resource/EntityLogResource.java | 7 +- .../EntityLogInternalController.java | 5 +- .../internal/resources/EntityLogResource.java | 5 +- .../UnprocessedManualEntityClient.java | 10 + .../processor/service/EntityLogService.java | 218 ++++++++++++++- .../integration/tests/EntityLogTest.java | 260 ++++++++++++++++++ .../tests/ManualRedactionTest.java | 10 +- .../AbstractPersistenceServerServiceTest.java | 125 +++++---- .../v1/api/shared/model/MessageType.java | 3 +- persistence-service-v1/pom.xml | 2 +- 11 files changed, 589 insertions(+), 61 deletions(-) create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/client/redactionservice/UnprocessedManualEntityClient.java create mode 100644 persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogTest.java diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/EntityLogController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/EntityLogController.java index 72965545b..fa33c61bf 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/EntityLogController.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/EntityLogController.java @@ -27,9 +27,10 @@ public class EntityLogController implements EntityLogResource { @PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')") public EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, - @RequestParam(value = "excludedType", required = false) List excludedTypes) { + @RequestParam(value = "excludedType", required = false) List excludedTypes, + @RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean unprocessed) { - return entityLogService.getEntityLog(dossierId, fileId, excludedTypes); + return entityLogService.getEntityLog(dossierId, fileId, excludedTypes, unprocessed); } diff --git a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/EntityLogResource.java b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/EntityLogResource.java index 289537a36..ef7c8133c 100644 --- a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/EntityLogResource.java +++ b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/EntityLogResource.java @@ -29,13 +29,16 @@ public interface EntityLogResource { String DOSSIER_ID = "dossierId"; String DOSSIER_ID_PATH_VARIABLE = "/{" + DOSSIER_ID + "}"; + String FALSE = "false"; @GetMapping(value = ENTITY_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(summary = "Gets the entity log for a fileId", description = "None") + @Operation(summary = "Gets the entity log for a fileId", description = "Gets the entity log for a given file. The flag includeUnprocessed will merge into the entity log all the unprocessed changes if it's set to true." + + "Default value for the flag is false.") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The entity log is not found.")}) EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, - @RequestParam(value = "excludedType", required = false) List excludedTypes); + @RequestParam(value = "excludedType", required = false) List excludedTypes, + @RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed); @PostMapping(value = ENTITY_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE + "/filtered", produces = MediaType.APPLICATION_JSON_VALUE) diff --git a/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/EntityLogInternalController.java b/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/EntityLogInternalController.java index 5ec246486..e6d1e6f32 100644 --- a/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/EntityLogInternalController.java +++ b/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/EntityLogInternalController.java @@ -21,9 +21,10 @@ public class EntityLogInternalController implements EntityLogResource { public EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, - @RequestParam(value = "excludedType", required = false) List excludedTypes) { + @RequestParam(value = "excludedType", required = false) List excludedTypes, + @RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed) { - return entityLogService.getEntityLog(dossierId, fileId, excludedTypes); + return entityLogService.getEntityLog(dossierId, fileId, excludedTypes, includeUnprocessed); } diff --git a/persistence-service-v1/persistence-service-internal-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/internal/resources/EntityLogResource.java b/persistence-service-v1/persistence-service-internal-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/internal/resources/EntityLogResource.java index 95cd6c908..9b8adc609 100644 --- a/persistence-service-v1/persistence-service-internal-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/internal/resources/EntityLogResource.java +++ b/persistence-service-v1/persistence-service-internal-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/internal/resources/EntityLogResource.java @@ -26,11 +26,14 @@ public interface EntityLogResource { String DOSSIER_ID = "dossierId"; String DOSSIER_ID_PATH_VARIABLE = "/{" + DOSSIER_ID + "}"; + String FALSE = "false"; + @GetMapping(value = ENTITY_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE) @Operation(summary = "Gets the entity log for a fileId", description = "None") @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The entity log is not found.")}) EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, - @RequestParam(value = "excludedType", required = false) List excludedTypes); + @RequestParam(value = "excludedType", required = false) List excludedTypes, + @RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/client/redactionservice/UnprocessedManualEntityClient.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/client/redactionservice/UnprocessedManualEntityClient.java new file mode 100644 index 000000000..4378485c4 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/client/redactionservice/UnprocessedManualEntityClient.java @@ -0,0 +1,10 @@ +package com.iqser.red.service.persistence.management.v1.processor.client.redactionservice; + +import org.springframework.cloud.openfeign.FeignClient; + +import com.iqser.red.service.redaction.v1.resources.UnprocessedManualEntityResource; + +@FeignClient(name = "UnprocessedManualEntityClient", url = "${redaction-service.url}") +public interface UnprocessedManualEntityClient extends UnprocessedManualEntityResource { + +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java index 88bc4ebbd..b46109a65 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java @@ -3,37 +3,63 @@ package com.iqser.red.service.persistence.management.v1.processor.service; import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import org.springframework.stereotype.Service; +import com.iqser.red.service.persistence.management.v1.processor.client.redactionservice.UnprocessedManualEntityClient; +import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity; +import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; +import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionProviderService; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Change; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.ChangeType; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryState; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.FilteredEntityLogRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.ManualChange; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.ManualRedactionType; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Position; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.IdRemoval; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualForceRedaction; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualLegalBasisChange; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualRecategorization; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualRedactionEntry; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualResizeRedaction; +import com.iqser.red.service.redaction.v1.model.UnprocessedManualEntity; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.experimental.FieldDefaults; +import lombok.extern.slf4j.Slf4j; @Service @RequiredArgsConstructor @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) +@Slf4j public class EntityLogService { FileManagementStorageService fileManagementStorageService; FileStatusService fileStatusService; + ManualRedactionProviderService manualRedactionProviderService; + UnprocessedManualEntityClient unprocessedManualEntityClient; + private final DossierService dossierService; CommentService commentService; public EntityLog getEntityLog(String dossierId, String fileId) { - return getEntityLog(dossierId, fileId, Collections.emptyList()); + return getEntityLog(dossierId, fileId, Collections.emptyList(), false); } - public EntityLog getEntityLog(String dossierId, String fileId, List excludedTypes) { + public EntityLog getEntityLog(String dossierId, String fileId, List excludedTypes, boolean includeUnprocessed) { var fileStatus = fileStatusService.getStatus(fileId); @@ -49,6 +75,12 @@ public class EntityLogService { entityLog.getEntityLogEntry().removeIf(entry -> excludedTypes.contains(entry.getType())); } + if (includeUnprocessed) { + ManualRedactions manualRedactions = manualRedactionProviderService.getManualRedactions(fileId, true); + List unprocessedManualEntities = getUnprocessedManualEntities(dossierId, fileId, manualRedactions); + mergeEntityLog(manualRedactions, unprocessedManualEntities, entityLog); + } + Map commentCountPerAnnotationId = commentService.getCommentCounts(fileId); entityLog.getEntityLogEntry().forEach(entityLogEntry -> entityLogEntry.setNumberOfComments(commentCountPerAnnotationId.getOrDefault(entityLogEntry.getId(), 0))); @@ -62,7 +94,7 @@ public class EntityLogService { filteredEntityLogRequest.setSpecifiedDate(OffsetDateTime.MIN); } - var entityLog = getEntityLog(dossierId, fileId, filteredEntityLogRequest.getExcludedTypes()); + var entityLog = getEntityLog(dossierId, fileId, filteredEntityLogRequest.getExcludedTypes(), false); var entityLogEntry = entityLog.getEntityLogEntry(); Iterator it = entityLogEntry.iterator(); @@ -92,4 +124,184 @@ public class EntityLogService { return entityLog; } + private List getUnprocessedManualEntities(String dossierId, String fileId, ManualRedactions manualRedactions) { + + DossierEntity dossier = dossierService.getDossierById(dossierId); + return unprocessedManualEntityClient.mergeUnprocessedManualEntities(fileId, dossierId, dossier.getDossierTemplateId(), manualRedactions); + + } + + public void mergeEntityLog(ManualRedactions manualRedactions, List unprocessedManualEntities, EntityLog entityLog) { + + log.info("Merging EntityLog"); + mergeManualRedactionEntries(manualRedactions.getEntriesToAdd(), unprocessedManualEntities, entityLog); + mergeIdsToRemove(manualRedactions.getIdsToRemove(), entityLog); + mergeResizeRedactions(manualRedactions.getResizeRedactions(), entityLog); + mergeLegalBasisChanges(manualRedactions.getLegalBasisChanges(), entityLog); + mergeRecategorizations(manualRedactions.getRecategorizations(), entityLog); + mergeForceRedactions(manualRedactions.getForceRedactions(), entityLog); + log.info("EntityLog merged successfully!"); + } + + + private void mergeManualRedactionEntries(Set manualRedactionEntries, List unprocessedManualEntities, EntityLog entityLog) { + + manualRedactionEntries.forEach(manualRedactionEntry -> { + UnprocessedManualEntity unprocessedManualEntity = unprocessedManualEntities.stream() + .filter(manualEntity -> manualEntity.getAnnotationId().equals(manualRedactionEntry.getAnnotationId())) + .findFirst().orElseThrow(() -> new NotFoundException("Entry with annotationId " + manualRedactionEntry.getAnnotationId() + " not found")); + List changes = new ArrayList<>(); + changes.add(Change.builder() + .analysisNumber(1) + .dateTime(OffsetDateTime.now()) + .type(ChangeType.ADDED) + .build()); + entityLog.getEntityLogEntry().add(EntityLogEntry.builder() + .id(manualRedactionEntry.getAnnotationId()) + .type(manualRedactionEntry.getType()) + .value(manualRedactionEntry.getValue()) + .legalBasis(manualRedactionEntry.getLegalBasis()) + .reason(manualRedactionEntry.getReason()) + .entryType(isHint(manualRedactionEntry.getType()) ? EntryType.HINT : EntryType.ENTITY) + .imported(false) + .matchedRule("") + .section(manualRedactionEntry.getSection()) + .color(unprocessedManualEntity.getColor()) + .positions(unprocessedManualEntity.getPositions()) + .textAfter(unprocessedManualEntity.getTextAfter()) + .textBefore(unprocessedManualEntity.getTextBefore()) + .startOffset(unprocessedManualEntity.getStartOffset()) + .endOffset(unprocessedManualEntity.getEndOffset()) + .containingNodeId(unprocessedManualEntity.getContainingNodeId()) + .closestHeadline(unprocessedManualEntity.getClosestHeadline()) + .imageHasTransparency(false) + .dictionaryEntry(manualRedactionEntry.isAddToDictionary()) + .dossierDictionaryEntry(manualRedactionEntry.isAddToDossierDictionary()) + .excluded(false) + .changes(changes) + .manualChanges(List.of(ManualChange.builder() + .manualRedactionType(ManualRedactionType.ADD_LOCALLY) + .requestedDate(manualRedactionEntry.getRequestDate()) + .processedDate(manualRedactionEntry.getProcessedDate()) + .userId(manualRedactionEntry.getUser()) + .propertyChanges(Map.of("value", manualRedactionEntry.getValue())) + .build())) + .engines(new HashSet<>()) + .reference(new HashSet<>()) + .importedRedactionIntersections(new HashSet<>()) + .build()); + }); + } + + + private void mergeIdsToRemove(Set idRemovals, EntityLog entityLog) { + + idRemovals.forEach(idRemoval -> { + var entity = entityLog.getEntityLogEntry().stream().filter(entityLogEntry -> entityLogEntry.getId().equals(idRemoval.getAnnotationId())).findAny(); + if (entity.isPresent()) { + entity.get().setState(EntryState.REMOVED); + addChanges(entity.get().getChanges(), ChangeType.REMOVED); + entity.get().getManualChanges().add(ManualChange.builder() + .manualRedactionType(ManualRedactionType.REMOVE_LOCALLY) + .requestedDate(idRemoval.getRequestDate()) + .processedDate(idRemoval.getProcessedDate()) + .userId(idRemoval.getUser()).build()); + } + }); + } + + private void mergeResizeRedactions(Set manualResizeRedactions, EntityLog entityLog) { + + manualResizeRedactions.forEach(manualResizeRedaction -> { + var entity = entityLog.getEntityLogEntry().stream().filter(entityLogEntry -> entityLogEntry.getId().equals(manualResizeRedaction.getAnnotationId())).findAny(); + if (entity.isPresent()) { + var newPosition = manualResizeRedaction.getPositions().get(0); + entity.get().setPositions(List.of(new Position( + newPosition.getTopLeftX(), + newPosition.getTopLeftY(), + newPosition.getWidth(), + newPosition.getHeight(), + newPosition.getPage()))); + addChanges(entity.get().getChanges(), ChangeType.CHANGED); + entity.get().getManualChanges().add(ManualChange.builder() + .manualRedactionType(ManualRedactionType.RESIZE) + .requestedDate(manualResizeRedaction.getRequestDate()) + .processedDate(manualResizeRedaction.getProcessedDate()) + .userId(manualResizeRedaction.getUser()).build()); + } + }); + } + + private void mergeLegalBasisChanges(Set manualLegalBasisChanges, EntityLog entityLog) { + + manualLegalBasisChanges.forEach(manualLegalBasisChange -> { + var entity = entityLog.getEntityLogEntry().stream().filter(entityLogEntry -> entityLogEntry.getId().equals(manualLegalBasisChange.getAnnotationId())).findAny(); + if (entity.isPresent()) { + entity.get().setLegalBasis(manualLegalBasisChange.getLegalBasis()); + addChanges(entity.get().getChanges(), ChangeType.CHANGED); + entity.get().getManualChanges().add(ManualChange.builder() + .manualRedactionType(ManualRedactionType.LEGAL_BASIS_CHANGE) + .requestedDate(manualLegalBasisChange.getRequestDate()) + .processedDate(manualLegalBasisChange.getProcessedDate()) + .propertyChanges(Map.of("value", manualLegalBasisChange.getValue())) + .userId(manualLegalBasisChange.getUser()) + .build()); + } + }); + } + + private void mergeRecategorizations(Set recategorizations, EntityLog entityLog) { + + recategorizations.forEach(recategorization -> { + var entity = entityLog.getEntityLogEntry().stream().filter(entityLogEntry -> entityLogEntry.getId().equals(recategorization.getAnnotationId())).findAny(); + if (entity.isPresent()) { + entity.get().setType(recategorization.getType()); + addChanges(entity.get().getChanges(), ChangeType.CHANGED); + entity.get().getManualChanges().add(ManualChange.builder() + .manualRedactionType(ManualRedactionType.RECATEGORIZE) + .requestedDate(recategorization.getRequestDate()) + .processedDate(recategorization.getProcessedDate()) + .userId(recategorization.getUser()) + .build()); + } + }); + } + + private void mergeForceRedactions(Set forceRedactions, EntityLog entityLog) { + + forceRedactions.forEach(forceRedaction -> { + var entity = entityLog.getEntityLogEntry().stream().filter(entityLogEntry -> entityLogEntry.getId().equals(forceRedaction.getAnnotationId())).findAny(); + if (entity.isPresent()) { + entity.get().setLegalBasis(forceRedaction.getLegalBasis()); + entity.get().setState(EntryState.APPLIED); + addChanges(entity.get().getChanges(), ChangeType.CHANGED); + entity.get().getManualChanges().add(ManualChange.builder() + .manualRedactionType(ManualRedactionType.FORCE_REDACT) + .requestedDate(forceRedaction.getRequestDate()) + .processedDate(forceRedaction.getProcessedDate()) + .userId(forceRedaction.getUser()) + .build()); + } + }); + } + + private void addChanges(List changes, ChangeType changeType) { + + if (!changes.isEmpty()) { + var lastChange = changes.get(changes.size() -1); + changes.add(Change.builder() + .analysisNumber(lastChange.getAnalysisNumber() + 1) + .dateTime(OffsetDateTime.now()) + .type(changeType) + .build()); + } else { + changes.add(Change.builder().analysisNumber(1).dateTime(OffsetDateTime.now()).type(changeType).build()); + } + } + + private boolean isHint(String manualRedactionEntryType) { + + return !(manualRedactionEntryType.equals("manual")); + } + } diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogTest.java new file mode 100644 index 000000000..6934c76d5 --- /dev/null +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogTest.java @@ -0,0 +1,260 @@ +package com.iqser.red.service.peristence.v1.server.integration.tests; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; + +import com.iqser.red.service.peristence.v1.server.integration.service.DossierTemplateTesterAndProvider; +import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider; +import com.iqser.red.service.peristence.v1.server.integration.service.FileTesterAndProvider; +import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest; +import com.iqser.red.service.persistence.management.v1.processor.client.redactionservice.UnprocessedManualEntityClient; +import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService; +import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; +import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService; +import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionProviderService; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.ChangeType; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryState; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.ManualRedactionType; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Position; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.ManualRedactions; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.Rectangle; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.IdRemoval; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualForceRedaction; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualLegalBasisChange; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualRedactionEntry; +import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualResizeRedaction; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType; +import com.iqser.red.service.redaction.v1.model.UnprocessedManualEntity; + +public class EntityLogTest extends AbstractPersistenceServerServiceTest { + + @Autowired + private FileTesterAndProvider fileTesterAndProvider; + + @Autowired + private DossierTesterAndProvider dossierTesterAndProvider; + + @Autowired + private DossierTemplateTesterAndProvider dossierTemplateTesterAndProvider; + + @Autowired + private FileStatusService fileStatusService; + + @Autowired + private FileManagementStorageService fileManagementStorageService; + + @MockBean + private ManualRedactionProviderService manualRedactionProviderService; + + @MockBean + private UnprocessedManualEntityClient unprocessedManualEntityClient; + + @Autowired + private EntityLogService entityLogService; + + + @Test + public void testGetEntityLogWithUnprocessedRedactions() { + + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate); + var file = fileTesterAndProvider.testAndProvideFile(dossier); + + String entryToAddId = UUID.randomUUID().toString(); + String entryToRemoveId = UUID.randomUUID().toString(); + String entryToResizeId = UUID.randomUUID().toString(); + String entryLegalBasisId = UUID.randomUUID().toString(); + String forceRedactionId = UUID.randomUUID().toString(); + + ManualRedactions manualRedactions = provideManualRedactions(entryToAddId, entryToRemoveId, entryToResizeId, entryLegalBasisId, forceRedactionId, file.getId()); + UnprocessedManualEntity unprocessedManualEntity = UnprocessedManualEntity.builder() + .textBefore("textBefore") + .textAfter("textAfter") + .containingNodeId(List.of(0, 0)) + .endOffset(10) + .startOffset(1) + .annotationId(entryToAddId) + .closestHeadline("closestHeadline") + .color(new float[]{0,0,0}) + .build(); + + var entityLog = provideEntityLog(entryToRemoveId, entryToResizeId, entryLegalBasisId, forceRedactionId); + fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.ENTITY_LOG, entityLog); + + when(manualRedactionProviderService.getManualRedactions(file.getId(), true)).thenReturn(manualRedactions); + when(unprocessedManualEntityClient.mergeUnprocessedManualEntities(any(), any(), any(), any())).thenReturn(List.of(unprocessedManualEntity)); + + EntityLog response = entityLogService.getEntityLog(dossier.getId(), file.getId(), Collections.emptyList(), true); + + assertNotNull(response); + assertFalse(response.getEntityLogEntry().isEmpty()); + + var optionalEntityLogEntry = response.getEntityLogEntry().stream().filter(entityLogEntry1 -> entityLogEntry1.getId().equals(entryToAddId)).findFirst(); + assertTrue(optionalEntityLogEntry.isPresent()); + var entityLogEntry = optionalEntityLogEntry.get(); + assertEquals(entityLogEntry.getType(), "manual"); + assertEquals(entityLogEntry.getEntryType(), EntryType.ENTITY); + assertNull(entityLogEntry.getState()); + assertEquals(entityLogEntry.getValue(), "Test"); + assertEquals(entityLogEntry.getReason(), "Reason"); + assertEquals(entityLogEntry.getTextAfter(), "textAfter"); + assertEquals(entityLogEntry.getTextBefore(), "textBefore"); + assertEquals(entityLogEntry.getStartOffset(), 1); + assertEquals(entityLogEntry.getEndOffset(), 10); + assertEquals(entityLogEntry.getManualChanges().get(0).getManualRedactionType(), ManualRedactionType.ADD_LOCALLY); + + var optionalRemoveEntryLogEntry = response.getEntityLogEntry().stream().filter(entityLogEntry1 -> entityLogEntry1.getId().equals(entryToRemoveId)).findFirst(); + assertTrue(optionalRemoveEntryLogEntry.isPresent()); + var removeEntryLogEntry = optionalRemoveEntryLogEntry.get(); + assertEquals(removeEntryLogEntry.getEntryType(), EntryType.ENTITY); + assertEquals(removeEntryLogEntry.getState(), EntryState.REMOVED); + assertEquals(removeEntryLogEntry.getManualChanges().get(0).getManualRedactionType(), ManualRedactionType.REMOVE_LOCALLY); + assertEquals(removeEntryLogEntry.getChanges().get(0).getType(), ChangeType.REMOVED); + + var optionalResizeEntryLogEntry = response.getEntityLogEntry().stream().filter(entityLogEntry1 -> entityLogEntry1.getId().equals(entryToResizeId)).findFirst(); + assertTrue(optionalResizeEntryLogEntry.isPresent()); + var resizeEntryLogEntry = optionalResizeEntryLogEntry.get(); + assertEquals(resizeEntryLogEntry.getPositions().get(0).getRectangle()[0], 2); + assertEquals(resizeEntryLogEntry.getPositions().get(0).getRectangle()[1], 2); + assertEquals(resizeEntryLogEntry.getPositions().get(0).getRectangle()[2], 2); + assertEquals(resizeEntryLogEntry.getPositions().get(0).getRectangle()[3], 2); + assertEquals(resizeEntryLogEntry.getPositions().get(0).getPageNumber(), 1); + assertEquals(resizeEntryLogEntry.getEntryType(), EntryType.ENTITY); + assertEquals(resizeEntryLogEntry.getState(), EntryState.APPLIED); + assertEquals(resizeEntryLogEntry.getManualChanges().get(0).getManualRedactionType(), ManualRedactionType.RESIZE); + assertEquals(resizeEntryLogEntry.getChanges().get(0).getType(), ChangeType.CHANGED); + + var optionalLegalBasisEntryLogEntry = response.getEntityLogEntry().stream().filter(entityLogEntry1 -> entityLogEntry1.getId().equals(entryLegalBasisId)).findFirst(); + assertTrue(optionalLegalBasisEntryLogEntry.isPresent()); + var legalBasisEntryLogEntry = optionalLegalBasisEntryLogEntry.get(); + assertEquals(legalBasisEntryLogEntry.getLegalBasis(), "New legal basis"); + assertEquals(legalBasisEntryLogEntry.getEntryType(), EntryType.ENTITY); + assertEquals(legalBasisEntryLogEntry.getState(), EntryState.APPLIED); + assertEquals(legalBasisEntryLogEntry.getManualChanges().get(0).getManualRedactionType(), ManualRedactionType.LEGAL_BASIS_CHANGE); + assertEquals(legalBasisEntryLogEntry.getChanges().get(0).getType(), ChangeType.CHANGED); + + var optionalForceRedactionEntryLogEntry = response.getEntityLogEntry().stream().filter(entityLogEntry1 -> entityLogEntry1.getId().equals(forceRedactionId)).findFirst(); + assertTrue(optionalForceRedactionEntryLogEntry.isPresent()); + var forceRedactionEntryLogEntry = optionalForceRedactionEntryLogEntry.get(); + assertEquals(forceRedactionEntryLogEntry.getLegalBasis(), "Force"); + assertEquals(forceRedactionEntryLogEntry.getEntryType(), EntryType.ENTITY); + assertEquals(forceRedactionEntryLogEntry.getState(), EntryState.APPLIED); + assertEquals(forceRedactionEntryLogEntry.getManualChanges().get(0).getManualRedactionType(), ManualRedactionType.FORCE_REDACT); + assertEquals(forceRedactionEntryLogEntry.getChanges().get(0).getType(), ChangeType.CHANGED); + + } + + private EntityLog provideEntityLog(String entryToRemoveId, String entryToResizeId, String entryLegalBasisId, String forceRedactionId) { + + List positions = new ArrayList<>(); + positions.add(new Position(1, 1, 1, 1, 1)); + return new EntityLog(1, + 1, + List.of(EntityLogEntry.builder() + .id(entryToRemoveId) + .type("manual") + .value("Luke Skywalker") + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .dictionaryEntry(true) + .build(), + EntityLogEntry.builder() + .id(entryToResizeId) + .type("manual") + .value("Darth Vader") + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .dictionaryEntry(true) + .positions(positions) + .build(), + EntityLogEntry.builder() + .id(entryLegalBasisId) + .type("manual") + .value("Darth Luke") + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .dictionaryEntry(true) + .positions(positions) + .build(), + EntityLogEntry.builder() + .id(forceRedactionId) + .type("manual") + .value("Darth Luke") + .entryType(EntryType.ENTITY) + .state(EntryState.APPLIED) + .dictionaryEntry(true) + .positions(positions) + .build()), + null, + 0, + 0, + 0, + 0); + } + + private ManualRedactions provideManualRedactions(String entryToAddId, String entryToRemoveId, String entryToResizeId, String entryLegalBasisId, String forceRedactionId, String fileId) { + + List positions = new ArrayList<>(); + positions.add(new Rectangle(2, 2, 2, 2, 1)); + return ManualRedactions.builder() + .entriesToAdd(Set.of( + ManualRedactionEntry.builder() + .positions(List.of(new Rectangle(1f, 2f, 3f, 4f, 1))) + .annotationId(entryToAddId) + .value("Test") + .reason("Reason") + .addToDictionary(false) + .addToDossierDictionary(false) + .fileId(fileId) + .requestDate(OffsetDateTime.now()) + .type("manual") + .build())) + .idsToRemove(Set.of( + IdRemoval.builder() + .annotationId(entryToRemoveId) + .build() + )) + .resizeRedactions(Set.of( + ManualResizeRedaction.builder() + .fileId(fileId) + .value("Random") + .annotationId(entryToResizeId) + .positions(positions) + .build() + )) + .legalBasisChanges(Set.of( + ManualLegalBasisChange.builder() + .annotationId(entryLegalBasisId) + .value("Random") + .legalBasis("New legal basis") + .build() + )) + .forceRedactions(Set.of( + ManualForceRedaction.builder() + .annotationId(forceRedactionId) + .fileId(fileId) + .legalBasis("Force") + .build() + )) + .build(); + } +} diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java index d57ee8b8f..aa9c4baea 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java @@ -10,10 +10,13 @@ import java.util.ArrayList; import java.util.List; import java.util.Set; +import org.assertj.core.util.Lists; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; import com.fasterxml.jackson.databind.ObjectMapper; import com.iqser.red.service.peristence.v1.server.integration.client.DictionaryClient; @@ -91,7 +94,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { @Autowired private InternalDictionaryClient internalDictionaryClient; - @Autowired + @MockBean private EntityLogService entityLogService; @Autowired @@ -103,6 +106,11 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { @Autowired private FileProcessingClient fileProcessingClient; + @BeforeEach + public void setup() { + + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(new EntityLog(1, 1, Lists.newArrayList(), null, 0, 0, 0, 0)); + } @Test public void testRemoveToDossierTemplateWithDossierDictionaryOnlyTrue() { diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java index aca12bcb0..f7e52814c 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java @@ -1,40 +1,13 @@ package com.iqser.red.service.peristence.v1.server.integration.utils; -import com.iqser.red.commons.jackson.ObjectMapperFactory; -import com.iqser.red.service.peristence.v1.server.Application; -import com.iqser.red.service.peristence.v1.server.integration.client.ApplicationConfigClient; -import com.iqser.red.service.peristence.v1.server.integration.client.FileClient; -import com.iqser.red.service.peristence.v1.server.utils.MetricsPrinterService; -import com.iqser.red.service.persistence.management.v1.processor.client.pdftronredactionservice.PDFTronClient; -import com.iqser.red.service.persistence.management.v1.processor.client.redactionservice.RedactionClient; -import com.iqser.red.service.persistence.management.v1.processor.client.searchservice.SearchClient; -import com.iqser.red.service.persistence.management.v1.processor.client.tenantusermanagementservice.UsersClient; -import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.ApplicationConfigurationEntity; -import com.iqser.red.service.persistence.management.v1.processor.roles.ApplicationRoles; -import com.iqser.red.service.persistence.management.v1.processor.service.ApplicationConfigService; -import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService; -import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.*; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.*; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.EntryRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.FalsePositiveEntryRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.FalseRecommendationEntryRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.users.UserService; -import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.ApplicationConfig; -import com.iqser.red.service.redaction.v1.model.DroolsSyntaxValidation; -import com.iqser.red.storage.commons.service.StorageService; -import com.iqser.red.storage.commons.utils.FileSystemBackedStorageService; -import com.knecon.fforesight.databasetenantcommons.providers.TenantCreatedListener; -import com.knecon.fforesight.databasetenantcommons.providers.events.TenantCreatedEvent; -import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter; -import com.knecon.fforesight.tenantcommons.EncryptionDecryptionService; -import com.knecon.fforesight.tenantcommons.TenantContext; -import com.knecon.fforesight.tenantcommons.TenantsClient; -import com.knecon.fforesight.tenantcommons.model.*; -import io.micrometer.prometheus.PrometheusMeterRegistry; -import lombok.extern.slf4j.Slf4j; -import org.assertj.core.util.Lists; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; @@ -51,7 +24,11 @@ import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.*; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Primary; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.StatementCallback; import org.springframework.jdbc.datasource.SingleConnectionDataSource; @@ -67,13 +44,69 @@ import org.springframework.security.web.SecurityFilterChain; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; +import com.iqser.red.commons.jackson.ObjectMapperFactory; +import com.iqser.red.service.peristence.v1.server.Application; +import com.iqser.red.service.peristence.v1.server.integration.client.ApplicationConfigClient; +import com.iqser.red.service.peristence.v1.server.integration.client.FileClient; +import com.iqser.red.service.peristence.v1.server.utils.MetricsPrinterService; +import com.iqser.red.service.persistence.management.v1.processor.client.pdftronredactionservice.PDFTronClient; +import com.iqser.red.service.persistence.management.v1.processor.client.redactionservice.RedactionClient; +import com.iqser.red.service.persistence.management.v1.processor.client.searchservice.SearchClient; +import com.iqser.red.service.persistence.management.v1.processor.client.tenantusermanagementservice.UsersClient; +import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.ApplicationConfigurationEntity; +import com.iqser.red.service.persistence.management.v1.processor.roles.ApplicationRoles; +import com.iqser.red.service.persistence.management.v1.processor.service.ApplicationConfigService; +import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService; +import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ApplicationConfigRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.AuditRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DigitalSignatureRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierAttributeConfigRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierAttributeRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierStatusRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierTemplateRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DownloadStatusRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.FileAttributeConfigRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.FileAttributesGeneralConfigurationRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.FileAttributesRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.FileRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.IndexInformationRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.LegalBasisMappingRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.NotificationPreferencesRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.NotificationRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ReportTemplateRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.RuleSetRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.TypeRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ViewedPagesRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.WatermarkRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.ForceRedactionRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.LegalBasisChangeRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.ManualRedactionRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.RecategorizationRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.RemoveRedactionRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.EntryRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.FalsePositiveEntryRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.FalseRecommendationEntryRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.users.UserService; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.ApplicationConfig; +import com.iqser.red.service.redaction.v1.model.DroolsSyntaxValidation; +import com.iqser.red.storage.commons.service.StorageService; +import com.iqser.red.storage.commons.utils.FileSystemBackedStorageService; +import com.knecon.fforesight.databasetenantcommons.providers.TenantCreatedListener; +import com.knecon.fforesight.databasetenantcommons.providers.events.TenantCreatedEvent; +import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter; +import com.knecon.fforesight.tenantcommons.EncryptionDecryptionService; +import com.knecon.fforesight.tenantcommons.TenantContext; +import com.knecon.fforesight.tenantcommons.TenantsClient; +import com.knecon.fforesight.tenantcommons.model.AuthDetails; +import com.knecon.fforesight.tenantcommons.model.DatabaseConnection; +import com.knecon.fforesight.tenantcommons.model.S3StorageConnection; +import com.knecon.fforesight.tenantcommons.model.SearchConnection; +import com.knecon.fforesight.tenantcommons.model.TenantResponse; -import static org.mockito.Mockito.when; +import io.micrometer.prometheus.PrometheusMeterRegistry; +import lombok.extern.slf4j.Slf4j; @Slf4j @ExtendWith(SpringExtension.class) @@ -92,10 +125,10 @@ public abstract class AbstractPersistenceServerServiceTest { @MockBean protected SearchClient searchClient; @MockBean - protected EntityLogService entityLogService; - @MockBean protected PDFTronClient pdfTronRedactionClient; @Autowired + protected EntityLogService entityLogService; + @Autowired protected ApplicationConfigClient appConfigClient; @Autowired protected StorageService storageService; @@ -190,8 +223,7 @@ public abstract class AbstractPersistenceServerServiceTest { var allRoles = ApplicationRoles.ROLE_DATA.entrySet().stream().flatMap(entry -> entry.getValue().stream()).collect(Collectors.toSet()); allRoles.addAll(ApplicationRoles.UNMAPPED_ACTION_ROLES); allRoles.addAll(ApplicationRoles.ROLE_DATA.keySet()); - var rolesArray = allRoles.toArray(new String[0]); - return rolesArray; + return allRoles.toArray(new String[0]); } @@ -245,7 +277,6 @@ public abstract class AbstractPersistenceServerServiceTest { // doNothing().when(pdfTronRedactionClient).testDigitalCurrentSignature(Mockito.any()); when(amqpAdmin.getQueueInfo(Mockito.any())).thenReturn(null); - when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(new EntityLog(1, 1, Lists.newArrayList(), null, 0, 0, 0, 0)); when(redactionClient.testRules(Mockito.any())).thenReturn(DroolsSyntaxValidation.builder().droolsSyntaxErrorMessages(Collections.emptyList()).build()); } diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/MessageType.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/MessageType.java index 9e75196e7..09dc18164 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/MessageType.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/MessageType.java @@ -3,6 +3,5 @@ package com.iqser.red.service.persistence.service.v1.api.shared.model; public enum MessageType { ANALYSE, - REANALYSE, - SURROUNDING_TEXT + REANALYSE } diff --git a/persistence-service-v1/pom.xml b/persistence-service-v1/pom.xml index e0282b76c..51a38b5ce 100755 --- a/persistence-service-v1/pom.xml +++ b/persistence-service-v1/pom.xml @@ -31,7 +31,7 @@ - 4.126.0 + 4.157.0 2.71.0 4.29.0 4.13.0 -- 2.47.2 From 729881fcd45ff7e7130a088f14041e0463536bcb Mon Sep 17 00:00:00 2001 From: Andrei Isvoran Date: Thu, 26 Oct 2023 17:07:42 +0300 Subject: [PATCH 37/96] RED-7782 - Fix tests --- .../processor/service/EntityLogService.java | 2 +- .../integration/tests/EntityLogTest.java | 68 ++++++---- .../tests/ManualRedactionTest.java | 10 +- .../AbstractPersistenceServerServiceTest.java | 125 +++++++----------- 4 files changed, 89 insertions(+), 116 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java index b46109a65..226cb32c8 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java @@ -49,7 +49,7 @@ public class EntityLogService { FileStatusService fileStatusService; ManualRedactionProviderService manualRedactionProviderService; UnprocessedManualEntityClient unprocessedManualEntityClient; - private final DossierService dossierService; + DossierService dossierService; CommentService commentService; diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogTest.java index 6934c76d5..a3d80147e 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogTest.java @@ -10,20 +10,21 @@ import static org.mockito.Mockito.when; import java.time.OffsetDateTime; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Set; import java.util.UUID; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.testcontainers.shaded.com.google.common.collect.Lists; -import com.iqser.red.service.peristence.v1.server.integration.service.DossierTemplateTesterAndProvider; -import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider; -import com.iqser.red.service.peristence.v1.server.integration.service.FileTesterAndProvider; -import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest; import com.iqser.red.service.persistence.management.v1.processor.client.redactionservice.UnprocessedManualEntityClient; +import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity; +import com.iqser.red.service.persistence.management.v1.processor.service.CommentService; +import com.iqser.red.service.persistence.management.v1.processor.service.DossierService; import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService; import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService; @@ -42,42 +43,45 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualLegalBasisChange; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualRedactionEntry; import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualResizeRedaction; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileModel; import com.iqser.red.service.redaction.v1.model.UnprocessedManualEntity; -public class EntityLogTest extends AbstractPersistenceServerServiceTest { +@ExtendWith(SpringExtension.class) +public class EntityLogTest { - @Autowired - private FileTesterAndProvider fileTesterAndProvider; - - @Autowired - private DossierTesterAndProvider dossierTesterAndProvider; - - @Autowired - private DossierTemplateTesterAndProvider dossierTemplateTesterAndProvider; - - @Autowired + @MockBean private FileStatusService fileStatusService; - @Autowired + @MockBean private FileManagementStorageService fileManagementStorageService; + @MockBean + private DossierService dossierService; + + @MockBean + private CommentService commentService; + @MockBean private ManualRedactionProviderService manualRedactionProviderService; @MockBean private UnprocessedManualEntityClient unprocessedManualEntityClient; - @Autowired private EntityLogService entityLogService; + @BeforeEach + public void setUp() { + + entityLogService = new EntityLogService(fileManagementStorageService, fileStatusService, manualRedactionProviderService, unprocessedManualEntityClient, dossierService, commentService); + } + @Test public void testGetEntityLogWithUnprocessedRedactions() { - var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); - var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate); - var file = fileTesterAndProvider.testAndProvideFile(dossier); + String fileId = "fileId"; + String dossierId = "dossierId"; + String dossierTemplateId = "dossierTemplateId"; String entryToAddId = UUID.randomUUID().toString(); String entryToRemoveId = UUID.randomUUID().toString(); @@ -85,7 +89,7 @@ public class EntityLogTest extends AbstractPersistenceServerServiceTest { String entryLegalBasisId = UUID.randomUUID().toString(); String forceRedactionId = UUID.randomUUID().toString(); - ManualRedactions manualRedactions = provideManualRedactions(entryToAddId, entryToRemoveId, entryToResizeId, entryLegalBasisId, forceRedactionId, file.getId()); + ManualRedactions manualRedactions = provideManualRedactions(entryToAddId, entryToRemoveId, entryToResizeId, entryLegalBasisId, forceRedactionId, fileId); UnprocessedManualEntity unprocessedManualEntity = UnprocessedManualEntity.builder() .textBefore("textBefore") .textAfter("textAfter") @@ -98,12 +102,20 @@ public class EntityLogTest extends AbstractPersistenceServerServiceTest { .build(); var entityLog = provideEntityLog(entryToRemoveId, entryToResizeId, entryLegalBasisId, forceRedactionId); - fileManagementStorageService.storeJSONObject(dossier.getId(), file.getId(), FileType.ENTITY_LOG, entityLog); - when(manualRedactionProviderService.getManualRedactions(file.getId(), true)).thenReturn(manualRedactions); + when(manualRedactionProviderService.getManualRedactions(fileId, true)).thenReturn(manualRedactions); when(unprocessedManualEntityClient.mergeUnprocessedManualEntities(any(), any(), any(), any())).thenReturn(List.of(unprocessedManualEntity)); + when(fileStatusService.getStatus(fileId)).thenReturn(FileModel.builder() + .excluded(false) + .dossierStatusId(dossierTemplateId) + .id(fileId) + .build()); + when(fileManagementStorageService.getEntityLog(dossierId, fileId)).thenReturn(entityLog); + when(dossierService.getDossierById(dossierId)).thenReturn(DossierEntity.builder() + .dossierTemplateId(dossierTemplateId) + .build()); - EntityLog response = entityLogService.getEntityLog(dossier.getId(), file.getId(), Collections.emptyList(), true); + EntityLog response = entityLogService.getEntityLog(dossierId, fileId, null, true); assertNotNull(response); assertFalse(response.getEntityLogEntry().isEmpty()); @@ -169,7 +181,7 @@ public class EntityLogTest extends AbstractPersistenceServerServiceTest { positions.add(new Position(1, 1, 1, 1, 1)); return new EntityLog(1, 1, - List.of(EntityLogEntry.builder() + Lists.newArrayList(EntityLogEntry.builder() .id(entryToRemoveId) .type("manual") .value("Luke Skywalker") diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java index aa9c4baea..d57ee8b8f 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/ManualRedactionTest.java @@ -10,13 +10,10 @@ import java.util.ArrayList; import java.util.List; import java.util.Set; -import org.assertj.core.util.Lists; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.mock.mockito.MockBean; import com.fasterxml.jackson.databind.ObjectMapper; import com.iqser.red.service.peristence.v1.server.integration.client.DictionaryClient; @@ -94,7 +91,7 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { @Autowired private InternalDictionaryClient internalDictionaryClient; - @MockBean + @Autowired private EntityLogService entityLogService; @Autowired @@ -106,11 +103,6 @@ public class ManualRedactionTest extends AbstractPersistenceServerServiceTest { @Autowired private FileProcessingClient fileProcessingClient; - @BeforeEach - public void setup() { - - when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(new EntityLog(1, 1, Lists.newArrayList(), null, 0, 0, 0, 0)); - } @Test public void testRemoveToDossierTemplateWithDossierDictionaryOnlyTrue() { diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java index f7e52814c..aca12bcb0 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/utils/AbstractPersistenceServerServiceTest.java @@ -1,13 +1,40 @@ package com.iqser.red.service.peristence.v1.server.integration.utils; -import static org.mockito.Mockito.when; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - +import com.iqser.red.commons.jackson.ObjectMapperFactory; +import com.iqser.red.service.peristence.v1.server.Application; +import com.iqser.red.service.peristence.v1.server.integration.client.ApplicationConfigClient; +import com.iqser.red.service.peristence.v1.server.integration.client.FileClient; +import com.iqser.red.service.peristence.v1.server.utils.MetricsPrinterService; +import com.iqser.red.service.persistence.management.v1.processor.client.pdftronredactionservice.PDFTronClient; +import com.iqser.red.service.persistence.management.v1.processor.client.redactionservice.RedactionClient; +import com.iqser.red.service.persistence.management.v1.processor.client.searchservice.SearchClient; +import com.iqser.red.service.persistence.management.v1.processor.client.tenantusermanagementservice.UsersClient; +import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.ApplicationConfigurationEntity; +import com.iqser.red.service.persistence.management.v1.processor.roles.ApplicationRoles; +import com.iqser.red.service.persistence.management.v1.processor.service.ApplicationConfigService; +import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService; +import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.*; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.*; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.EntryRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.FalsePositiveEntryRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.FalseRecommendationEntryRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.users.UserService; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.ApplicationConfig; +import com.iqser.red.service.redaction.v1.model.DroolsSyntaxValidation; +import com.iqser.red.storage.commons.service.StorageService; +import com.iqser.red.storage.commons.utils.FileSystemBackedStorageService; +import com.knecon.fforesight.databasetenantcommons.providers.TenantCreatedListener; +import com.knecon.fforesight.databasetenantcommons.providers.events.TenantCreatedEvent; +import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter; +import com.knecon.fforesight.tenantcommons.EncryptionDecryptionService; +import com.knecon.fforesight.tenantcommons.TenantContext; +import com.knecon.fforesight.tenantcommons.TenantsClient; +import com.knecon.fforesight.tenantcommons.model.*; +import io.micrometer.prometheus.PrometheusMeterRegistry; +import lombok.extern.slf4j.Slf4j; +import org.assertj.core.util.Lists; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; @@ -24,11 +51,7 @@ import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.*; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.StatementCallback; import org.springframework.jdbc.datasource.SingleConnectionDataSource; @@ -44,69 +67,13 @@ import org.springframework.security.web.SecurityFilterChain; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; -import com.iqser.red.commons.jackson.ObjectMapperFactory; -import com.iqser.red.service.peristence.v1.server.Application; -import com.iqser.red.service.peristence.v1.server.integration.client.ApplicationConfigClient; -import com.iqser.red.service.peristence.v1.server.integration.client.FileClient; -import com.iqser.red.service.peristence.v1.server.utils.MetricsPrinterService; -import com.iqser.red.service.persistence.management.v1.processor.client.pdftronredactionservice.PDFTronClient; -import com.iqser.red.service.persistence.management.v1.processor.client.redactionservice.RedactionClient; -import com.iqser.red.service.persistence.management.v1.processor.client.searchservice.SearchClient; -import com.iqser.red.service.persistence.management.v1.processor.client.tenantusermanagementservice.UsersClient; -import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.ApplicationConfigurationEntity; -import com.iqser.red.service.persistence.management.v1.processor.roles.ApplicationRoles; -import com.iqser.red.service.persistence.management.v1.processor.service.ApplicationConfigService; -import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService; -import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ApplicationConfigRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.AuditRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DigitalSignatureRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierAttributeConfigRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierAttributeRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierStatusRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierTemplateRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DownloadStatusRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.FileAttributeConfigRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.FileAttributesGeneralConfigurationRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.FileAttributesRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.FileRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.IndexInformationRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.LegalBasisMappingRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.NotificationPreferencesRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.NotificationRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ReportTemplateRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.RuleSetRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.TypeRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ViewedPagesRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.WatermarkRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.ForceRedactionRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.LegalBasisChangeRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.ManualRedactionRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.RecategorizationRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.RemoveRedactionRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.EntryRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.FalsePositiveEntryRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.dictionaryentry.FalseRecommendationEntryRepository; -import com.iqser.red.service.persistence.management.v1.processor.service.users.UserService; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.ApplicationConfig; -import com.iqser.red.service.redaction.v1.model.DroolsSyntaxValidation; -import com.iqser.red.storage.commons.service.StorageService; -import com.iqser.red.storage.commons.utils.FileSystemBackedStorageService; -import com.knecon.fforesight.databasetenantcommons.providers.TenantCreatedListener; -import com.knecon.fforesight.databasetenantcommons.providers.events.TenantCreatedEvent; -import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter; -import com.knecon.fforesight.tenantcommons.EncryptionDecryptionService; -import com.knecon.fforesight.tenantcommons.TenantContext; -import com.knecon.fforesight.tenantcommons.TenantsClient; -import com.knecon.fforesight.tenantcommons.model.AuthDetails; -import com.knecon.fforesight.tenantcommons.model.DatabaseConnection; -import com.knecon.fforesight.tenantcommons.model.S3StorageConnection; -import com.knecon.fforesight.tenantcommons.model.SearchConnection; -import com.knecon.fforesight.tenantcommons.model.TenantResponse; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; -import io.micrometer.prometheus.PrometheusMeterRegistry; -import lombok.extern.slf4j.Slf4j; +import static org.mockito.Mockito.when; @Slf4j @ExtendWith(SpringExtension.class) @@ -125,9 +92,9 @@ public abstract class AbstractPersistenceServerServiceTest { @MockBean protected SearchClient searchClient; @MockBean - protected PDFTronClient pdfTronRedactionClient; - @Autowired protected EntityLogService entityLogService; + @MockBean + protected PDFTronClient pdfTronRedactionClient; @Autowired protected ApplicationConfigClient appConfigClient; @Autowired @@ -223,7 +190,8 @@ public abstract class AbstractPersistenceServerServiceTest { var allRoles = ApplicationRoles.ROLE_DATA.entrySet().stream().flatMap(entry -> entry.getValue().stream()).collect(Collectors.toSet()); allRoles.addAll(ApplicationRoles.UNMAPPED_ACTION_ROLES); allRoles.addAll(ApplicationRoles.ROLE_DATA.keySet()); - return allRoles.toArray(new String[0]); + var rolesArray = allRoles.toArray(new String[0]); + return rolesArray; } @@ -277,6 +245,7 @@ public abstract class AbstractPersistenceServerServiceTest { // doNothing().when(pdfTronRedactionClient).testDigitalCurrentSignature(Mockito.any()); when(amqpAdmin.getQueueInfo(Mockito.any())).thenReturn(null); + when(entityLogService.getEntityLog(Mockito.any(), Mockito.any())).thenReturn(new EntityLog(1, 1, Lists.newArrayList(), null, 0, 0, 0, 0)); when(redactionClient.testRules(Mockito.any())).thenReturn(DroolsSyntaxValidation.builder().droolsSyntaxErrorMessages(Collections.emptyList()).build()); } -- 2.47.2 From da43634b1923ae702d4c484ede15d0ae88c4778c Mon Sep 17 00:00:00 2001 From: Andrei Isvoran Date: Fri, 27 Oct 2023 12:09:20 +0300 Subject: [PATCH 38/96] RED-7782 - Address PR comments --- .../impl/controller/EntityLogController.java | 4 +- .../external/resource/EntityLogResource.java | 2 +- .../EntityLogInternalController.java | 2 +- .../internal/resources/EntityLogResource.java | 2 +- .../processor/service/EntityLogService.java | 63 +++++++++++-------- .../integration/tests/EntityLogTest.java | 12 +++- 6 files changed, 53 insertions(+), 32 deletions(-) diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/EntityLogController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/EntityLogController.java index fa33c61bf..aaea93cdf 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/EntityLogController.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/EntityLogController.java @@ -28,9 +28,9 @@ public class EntityLogController implements EntityLogResource { public EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestParam(value = "excludedType", required = false) List excludedTypes, - @RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean unprocessed) { + @RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed) { - return entityLogService.getEntityLog(dossierId, fileId, excludedTypes, unprocessed); + return entityLogService.getEntityLog(dossierId, fileId, excludedTypes, includeUnprocessed); } diff --git a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/EntityLogResource.java b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/EntityLogResource.java index ef7c8133c..7fcf79d52 100644 --- a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/EntityLogResource.java +++ b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/EntityLogResource.java @@ -38,7 +38,7 @@ public interface EntityLogResource { EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestParam(value = "excludedType", required = false) List excludedTypes, - @RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed); + @RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed); @PostMapping(value = ENTITY_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE + "/filtered", produces = MediaType.APPLICATION_JSON_VALUE) diff --git a/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/EntityLogInternalController.java b/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/EntityLogInternalController.java index e6d1e6f32..0dd4d4fbb 100644 --- a/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/EntityLogInternalController.java +++ b/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/EntityLogInternalController.java @@ -22,7 +22,7 @@ public class EntityLogInternalController implements EntityLogResource { public EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestParam(value = "excludedType", required = false) List excludedTypes, - @RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed) { + @RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed) { return entityLogService.getEntityLog(dossierId, fileId, excludedTypes, includeUnprocessed); } diff --git a/persistence-service-v1/persistence-service-internal-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/internal/resources/EntityLogResource.java b/persistence-service-v1/persistence-service-internal-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/internal/resources/EntityLogResource.java index 9b8adc609..1a7b7c23b 100644 --- a/persistence-service-v1/persistence-service-internal-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/internal/resources/EntityLogResource.java +++ b/persistence-service-v1/persistence-service-internal-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/internal/resources/EntityLogResource.java @@ -35,5 +35,5 @@ public interface EntityLogResource { EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestParam(value = "excludedType", required = false) List excludedTypes, - @RequestParam(value = "unprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed); + @RequestParam(value = "includeUnprocessed", required = false, defaultValue = FALSE) boolean includeUnprocessed); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java index 226cb32c8..84e980d94 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java @@ -1,5 +1,7 @@ package com.iqser.red.service.persistence.management.v1.processor.service; +import static com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils.toTypeId; + import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.Collections; @@ -12,9 +14,11 @@ import java.util.Set; import org.springframework.stereotype.Service; import com.iqser.red.service.persistence.management.v1.processor.client.redactionservice.UnprocessedManualEntityClient; +import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.TypeEntity; import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity; import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionProviderService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Change; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.ChangeType; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; @@ -51,6 +55,7 @@ public class EntityLogService { UnprocessedManualEntityClient unprocessedManualEntityClient; DossierService dossierService; CommentService commentService; + DictionaryPersistenceService dictionaryPersistenceService; public EntityLog getEntityLog(String dossierId, String fileId) { @@ -76,9 +81,10 @@ public class EntityLogService { } if (includeUnprocessed) { + DossierEntity dossier = dossierService.getDossierById(dossierId); ManualRedactions manualRedactions = manualRedactionProviderService.getManualRedactions(fileId, true); - List unprocessedManualEntities = getUnprocessedManualEntities(dossierId, fileId, manualRedactions); - mergeEntityLog(manualRedactions, unprocessedManualEntities, entityLog); + List unprocessedManualEntities = getUnprocessedManualEntities(dossierId, fileId, dossier.getDossierTemplateId(), manualRedactions); + mergeEntityLog(manualRedactions, unprocessedManualEntities, entityLog, dossier.getDossierTemplateId()); } Map commentCountPerAnnotationId = commentService.getCommentCounts(fileId); @@ -124,17 +130,16 @@ public class EntityLogService { return entityLog; } - private List getUnprocessedManualEntities(String dossierId, String fileId, ManualRedactions manualRedactions) { + private List getUnprocessedManualEntities(String dossierId, String fileId, String dossierTemplateId, ManualRedactions manualRedactions) { - DossierEntity dossier = dossierService.getDossierById(dossierId); - return unprocessedManualEntityClient.mergeUnprocessedManualEntities(fileId, dossierId, dossier.getDossierTemplateId(), manualRedactions); + return unprocessedManualEntityClient.mergeUnprocessedManualEntities(fileId, dossierId, dossierTemplateId, manualRedactions); } - public void mergeEntityLog(ManualRedactions manualRedactions, List unprocessedManualEntities, EntityLog entityLog) { + public void mergeEntityLog(ManualRedactions manualRedactions, List unprocessedManualEntities, EntityLog entityLog, String dossierTemplateId) { log.info("Merging EntityLog"); - mergeManualRedactionEntries(manualRedactions.getEntriesToAdd(), unprocessedManualEntities, entityLog); + mergeManualRedactionEntries(manualRedactions.getEntriesToAdd(), unprocessedManualEntities, entityLog, dossierTemplateId); mergeIdsToRemove(manualRedactions.getIdsToRemove(), entityLog); mergeResizeRedactions(manualRedactions.getResizeRedactions(), entityLog); mergeLegalBasisChanges(manualRedactions.getLegalBasisChanges(), entityLog); @@ -144,7 +149,7 @@ public class EntityLogService { } - private void mergeManualRedactionEntries(Set manualRedactionEntries, List unprocessedManualEntities, EntityLog entityLog) { + private void mergeManualRedactionEntries(Set manualRedactionEntries, List unprocessedManualEntities, EntityLog entityLog, String dossierTemplateId) { manualRedactionEntries.forEach(manualRedactionEntry -> { UnprocessedManualEntity unprocessedManualEntity = unprocessedManualEntities.stream() @@ -162,7 +167,7 @@ public class EntityLogService { .value(manualRedactionEntry.getValue()) .legalBasis(manualRedactionEntry.getLegalBasis()) .reason(manualRedactionEntry.getReason()) - .entryType(isHint(manualRedactionEntry.getType()) ? EntryType.HINT : EntryType.ENTITY) + .entryType(isHint(manualRedactionEntry.getType(), dossierTemplateId) ? EntryType.HINT : EntryType.ENTITY) .imported(false) .matchedRule("") .section(manualRedactionEntry.getSection()) @@ -199,12 +204,12 @@ public class EntityLogService { idRemovals.forEach(idRemoval -> { var entity = entityLog.getEntityLogEntry().stream().filter(entityLogEntry -> entityLogEntry.getId().equals(idRemoval.getAnnotationId())).findAny(); if (entity.isPresent()) { - entity.get().setState(EntryState.REMOVED); - addChanges(entity.get().getChanges(), ChangeType.REMOVED); + entity.get().setState(EntryState.IGNORED); + addChanges(entity.get().getChanges(), ChangeType.REMOVED, entityLog.getAnalysisNumber()); entity.get().getManualChanges().add(ManualChange.builder() .manualRedactionType(ManualRedactionType.REMOVE_LOCALLY) .requestedDate(idRemoval.getRequestDate()) - .processedDate(idRemoval.getProcessedDate()) + .processedDate(null) .userId(idRemoval.getUser()).build()); } }); @@ -222,11 +227,11 @@ public class EntityLogService { newPosition.getWidth(), newPosition.getHeight(), newPosition.getPage()))); - addChanges(entity.get().getChanges(), ChangeType.CHANGED); + addChanges(entity.get().getChanges(), ChangeType.CHANGED, entityLog.getAnalysisNumber()); entity.get().getManualChanges().add(ManualChange.builder() .manualRedactionType(ManualRedactionType.RESIZE) .requestedDate(manualResizeRedaction.getRequestDate()) - .processedDate(manualResizeRedaction.getProcessedDate()) + .processedDate(null) .userId(manualResizeRedaction.getUser()).build()); } }); @@ -238,12 +243,16 @@ public class EntityLogService { var entity = entityLog.getEntityLogEntry().stream().filter(entityLogEntry -> entityLogEntry.getId().equals(manualLegalBasisChange.getAnnotationId())).findAny(); if (entity.isPresent()) { entity.get().setLegalBasis(manualLegalBasisChange.getLegalBasis()); - addChanges(entity.get().getChanges(), ChangeType.CHANGED); + entity.get().setSection(manualLegalBasisChange.getSection()); + entity.get().setValue(manualLegalBasisChange.getValue()); + addChanges(entity.get().getChanges(), ChangeType.CHANGED, entityLog.getAnalysisNumber()); entity.get().getManualChanges().add(ManualChange.builder() .manualRedactionType(ManualRedactionType.LEGAL_BASIS_CHANGE) .requestedDate(manualLegalBasisChange.getRequestDate()) - .processedDate(manualLegalBasisChange.getProcessedDate()) - .propertyChanges(Map.of("value", manualLegalBasisChange.getValue())) + .processedDate(null) + .propertyChanges(Map.of("value", manualLegalBasisChange.getValue(), + "section", manualLegalBasisChange.getSection(), + "legalBasis", manualLegalBasisChange.getLegalBasis())) .userId(manualLegalBasisChange.getUser()) .build()); } @@ -256,7 +265,7 @@ public class EntityLogService { var entity = entityLog.getEntityLogEntry().stream().filter(entityLogEntry -> entityLogEntry.getId().equals(recategorization.getAnnotationId())).findAny(); if (entity.isPresent()) { entity.get().setType(recategorization.getType()); - addChanges(entity.get().getChanges(), ChangeType.CHANGED); + addChanges(entity.get().getChanges(), ChangeType.CHANGED, entityLog.getAnalysisNumber()); entity.get().getManualChanges().add(ManualChange.builder() .manualRedactionType(ManualRedactionType.RECATEGORIZE) .requestedDate(recategorization.getRequestDate()) @@ -274,7 +283,7 @@ public class EntityLogService { if (entity.isPresent()) { entity.get().setLegalBasis(forceRedaction.getLegalBasis()); entity.get().setState(EntryState.APPLIED); - addChanges(entity.get().getChanges(), ChangeType.CHANGED); + addChanges(entity.get().getChanges(), ChangeType.CHANGED, entityLog.getAnalysisNumber()); entity.get().getManualChanges().add(ManualChange.builder() .manualRedactionType(ManualRedactionType.FORCE_REDACT) .requestedDate(forceRedaction.getRequestDate()) @@ -285,23 +294,27 @@ public class EntityLogService { }); } - private void addChanges(List changes, ChangeType changeType) { + private void addChanges(List changes, ChangeType changeType, int analysisNumber) { if (!changes.isEmpty()) { - var lastChange = changes.get(changes.size() -1); changes.add(Change.builder() - .analysisNumber(lastChange.getAnalysisNumber() + 1) + .analysisNumber(analysisNumber + 1) .dateTime(OffsetDateTime.now()) .type(changeType) .build()); } else { - changes.add(Change.builder().analysisNumber(1).dateTime(OffsetDateTime.now()).type(changeType).build()); + changes.add(Change.builder().analysisNumber(analysisNumber).dateTime(OffsetDateTime.now()).type(changeType).build()); } } - private boolean isHint(String manualRedactionEntryType) { + private boolean isHint(String type, String dossierTemplateId) { - return !(manualRedactionEntryType.equals("manual")); + String typeId = toTypeId(type, dossierTemplateId); + TypeEntity typeEntity = dictionaryPersistenceService.getType(typeId); + if (typeEntity == null) { + throw new NotFoundException("TypeEntity could not be found for typeId: " + typeId); + } + return typeEntity.isHint(); } } diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogTest.java index a3d80147e..d0899c48c 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogTest.java @@ -6,6 +6,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; import java.time.OffsetDateTime; @@ -22,6 +23,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import org.testcontainers.shaded.com.google.common.collect.Lists; import com.iqser.red.service.persistence.management.v1.processor.client.redactionservice.UnprocessedManualEntityClient; +import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.TypeEntity; import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity; import com.iqser.red.service.persistence.management.v1.processor.service.CommentService; import com.iqser.red.service.persistence.management.v1.processor.service.DossierService; @@ -29,6 +31,7 @@ import com.iqser.red.service.persistence.management.v1.processor.service.EntityL import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService; import com.iqser.red.service.persistence.management.v1.processor.service.manualredactions.ManualRedactionProviderService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.ChangeType; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry; @@ -67,12 +70,15 @@ public class EntityLogTest { @MockBean private UnprocessedManualEntityClient unprocessedManualEntityClient; + @MockBean + private DictionaryPersistenceService dictionaryPersistenceService; + private EntityLogService entityLogService; @BeforeEach public void setUp() { - entityLogService = new EntityLogService(fileManagementStorageService, fileStatusService, manualRedactionProviderService, unprocessedManualEntityClient, dossierService, commentService); + entityLogService = new EntityLogService(fileManagementStorageService, fileStatusService, manualRedactionProviderService, unprocessedManualEntityClient, dossierService, commentService, dictionaryPersistenceService); } @@ -114,6 +120,7 @@ public class EntityLogTest { when(dossierService.getDossierById(dossierId)).thenReturn(DossierEntity.builder() .dossierTemplateId(dossierTemplateId) .build()); + when(dictionaryPersistenceService.getType(anyString())).thenReturn(TypeEntity.builder().isHint(false).build()); EntityLog response = entityLogService.getEntityLog(dossierId, fileId, null, true); @@ -138,7 +145,7 @@ public class EntityLogTest { assertTrue(optionalRemoveEntryLogEntry.isPresent()); var removeEntryLogEntry = optionalRemoveEntryLogEntry.get(); assertEquals(removeEntryLogEntry.getEntryType(), EntryType.ENTITY); - assertEquals(removeEntryLogEntry.getState(), EntryState.REMOVED); + assertEquals(removeEntryLogEntry.getState(), EntryState.IGNORED); assertEquals(removeEntryLogEntry.getManualChanges().get(0).getManualRedactionType(), ManualRedactionType.REMOVE_LOCALLY); assertEquals(removeEntryLogEntry.getChanges().get(0).getType(), ChangeType.REMOVED); @@ -258,6 +265,7 @@ public class EntityLogTest { .annotationId(entryLegalBasisId) .value("Random") .legalBasis("New legal basis") + .section("Section") .build() )) .forceRedactions(Set.of( -- 2.47.2 From 7a0de45add27aa94a08862334114bebdb644c37e Mon Sep 17 00:00:00 2001 From: Andrei Isvoran Date: Fri, 27 Oct 2023 12:14:22 +0300 Subject: [PATCH 39/96] RED-7782 - Address PR comments --- .../management/v1/processor/service/EntityLogService.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java index 84e980d94..62bc91837 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java @@ -157,7 +157,7 @@ public class EntityLogService { .findFirst().orElseThrow(() -> new NotFoundException("Entry with annotationId " + manualRedactionEntry.getAnnotationId() + " not found")); List changes = new ArrayList<>(); changes.add(Change.builder() - .analysisNumber(1) + .analysisNumber(entityLog.getAnalysisNumber()) .dateTime(OffsetDateTime.now()) .type(ChangeType.ADDED) .build()); @@ -187,7 +187,7 @@ public class EntityLogService { .manualChanges(List.of(ManualChange.builder() .manualRedactionType(ManualRedactionType.ADD_LOCALLY) .requestedDate(manualRedactionEntry.getRequestDate()) - .processedDate(manualRedactionEntry.getProcessedDate()) + .processedDate(null) .userId(manualRedactionEntry.getUser()) .propertyChanges(Map.of("value", manualRedactionEntry.getValue())) .build())) @@ -232,6 +232,7 @@ public class EntityLogService { .manualRedactionType(ManualRedactionType.RESIZE) .requestedDate(manualResizeRedaction.getRequestDate()) .processedDate(null) + .propertyChanges(Map.of("value", manualResizeRedaction.getValue())) .userId(manualResizeRedaction.getUser()).build()); } }); -- 2.47.2 From 3bdfd4c96b1a68e76c4e0f68a1713f0a2893a0fe Mon Sep 17 00:00:00 2001 From: Andrei Isvoran Date: Fri, 27 Oct 2023 12:16:04 +0300 Subject: [PATCH 40/96] RED-7782 - Add property changes --- .../management/v1/processor/service/EntityLogService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java index 62bc91837..06b909f56 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java @@ -272,6 +272,7 @@ public class EntityLogService { .requestedDate(recategorization.getRequestDate()) .processedDate(recategorization.getProcessedDate()) .userId(recategorization.getUser()) + .propertyChanges(Map.of("type", recategorization.getType())) .build()); } }); @@ -290,6 +291,7 @@ public class EntityLogService { .requestedDate(forceRedaction.getRequestDate()) .processedDate(forceRedaction.getProcessedDate()) .userId(forceRedaction.getUser()) + .propertyChanges(Map.of("legalBasis", forceRedaction.getLegalBasis())) .build()); } }); -- 2.47.2 From 18d98ab4e6c410207cdd6d6f702c2eabcb44ae1a Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Fri, 27 Oct 2023 11:55:38 +0200 Subject: [PATCH 41/96] RED-7384: create shared models in persistence service --- .../processor/service/DictionaryService.java | 34 ++++++++------- .../analysislog/migration/MigratedIds.java | 43 +++++++++++++++++++ .../dossier/file/FileType.java | 4 +- 3 files changed, 64 insertions(+), 17 deletions(-) create mode 100644 persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/migration/MigratedIds.java diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java index 9b740aa56..781589c19 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java @@ -35,7 +35,6 @@ import com.iqser.red.service.persistence.management.v1.processor.exception.NotFo import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.service.persistence.EntryPersistenceService; import com.iqser.red.service.persistence.management.v1.processor.utils.ColorUtils; -import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter; import com.iqser.red.service.persistence.service.v1.api.shared.model.CreateTypeValue; import com.iqser.red.service.persistence.service.v1.api.shared.model.Dictionary; import com.iqser.red.service.persistence.service.v1.api.shared.model.TypeResponse; @@ -44,6 +43,7 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.UpdateTypeV import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.Colors; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.Type; +import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -307,6 +307,7 @@ public class DictionaryService { } } + @PreAuthorize("hasAuthority('" + READ_DICTIONARY_TYPES + "')") public Dictionary getMergedDictionaryForType(String type, String dossierTemplateId, String dossierId) { @@ -327,7 +328,9 @@ public class DictionaryService { } } - private Dictionary convertMergedDictionaries (List commonsDictionaries, String dossierTemplateId, String dossierId) { + + private Dictionary convertMergedDictionaries(List commonsDictionaries, String dossierTemplateId, String dossierId) { + List dictionaries = new ArrayList<>(); commonsDictionaries.forEach(cdm -> { var typeId = toTypeId(cdm.getType(), dossierTemplateId, dossierId); @@ -373,27 +376,29 @@ public class DictionaryService { return dictionaries.get(0); } + private List convertType(TypeEntity typeEntity) { return List.of(CommonsDictionaryModel.builder() - .type(typeEntity.getType()) - .rank(typeEntity.getRank()) - .color(ColorUtils.convertColor(typeEntity.getHexColor())) - .caseInsensitive(typeEntity.isCaseInsensitive()) - .hint(typeEntity.isHint()) - .entries(getCommonsEntries(typeEntity.getId(), DictionaryEntryType.ENTRY)) - .falsePositives(getCommonsEntries(typeEntity.getId(), DictionaryEntryType.FALSE_POSITIVE)) - .falseRecommendations(getCommonsEntries(typeEntity.getId(), DictionaryEntryType.FALSE_RECOMMENDATION)) - .build()); + .type(typeEntity.getType()) + .rank(typeEntity.getRank()) + .color(ColorUtils.convertColor(typeEntity.getHexColor())) + .caseInsensitive(typeEntity.isCaseInsensitive()) + .hint(typeEntity.isHint()) + .entries(getCommonsEntries(typeEntity.getId(), DictionaryEntryType.ENTRY)) + .falsePositives(getCommonsEntries(typeEntity.getId(), DictionaryEntryType.FALSE_POSITIVE)) + .falseRecommendations(getCommonsEntries(typeEntity.getId(), DictionaryEntryType.FALSE_RECOMMENDATION)) + .build()); } + private Set getCommonsEntries(String typeId, DictionaryEntryType entryType) { + var entries = MagicConverter.convert(entryPersistenceService.getEntries(typeId, entryType, null), DictionaryEntry.class); - return CollectionUtils.isNotEmpty(entries) ? new HashSet<>(entries.stream() - .map(DictionaryEntryModel::new) - .collect(Collectors.toSet())) : new HashSet<>(); + return CollectionUtils.isNotEmpty(entries) ? new HashSet<>(entries.stream().map(DictionaryEntryModel::new).collect(Collectors.toSet())) : new HashSet<>(); } + @PreAuthorize("hasAuthority('" + WRITE_COLORS + "')") public void setColors(String dossierTemplateId, Colors colors) { //validate all colors before setting them @@ -422,5 +427,4 @@ public class DictionaryService { return MagicConverter.convert(colorsService.getColors(dossierTemplateId), Colors.class); } - } diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/migration/MigratedIds.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/migration/MigratedIds.java new file mode 100644 index 000000000..09752f243 --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/analysislog/migration/MigratedIds.java @@ -0,0 +1,43 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.migration; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MigratedIds { + + List mappings; + + + public Map buildOldToNewMapping() { + + return mappings.stream().collect(Collectors.toMap(Mapping::oldId, Mapping::newId)); + } + + + public Map buildNewToOldMapping() { + + return mappings.stream().collect(Collectors.toMap(Mapping::newId, Mapping::oldId)); + } + + + public void addMapping(String oldId, String newId) { + + mappings.add(new Mapping(oldId, newId)); + } + + + private record Mapping(String oldId, String newId) { + + } + +} diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/FileType.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/FileType.java index 8008340ee..f4df3c82c 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/FileType.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/FileType.java @@ -9,7 +9,6 @@ public enum FileType { VIEWER_DOCUMENT(".pdf"), REDACTION_LOG(".json"), SIMPLIFIED_TEXT(".json"), - SECTION_GRID(".json"), TEXT(".json"), // deprecated file type, only present in legacy migrations NER_ENTITIES(".json"), IMAGE_INFO(".json"), @@ -24,7 +23,8 @@ public enum FileType { DOCUMENT_POSITION(".json"), DOCUMENT_PAGES(".json"), ENTITY_LOG(".json"), - COMPONENT_LOG(".json"); + COMPONENT_LOG(".json"), + MIGRATED_IDS(".json"); @Getter private final String extension; -- 2.47.2 From d91bbc6d0e614e79a41a58f60850b321f968e11e Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Fri, 27 Oct 2023 12:09:48 +0200 Subject: [PATCH 42/96] RED-7384: create shared models in persistence service --- .../internal/AdminInterfaceController.java | 4 +--- .../service/FileManagementStorageService.java | 14 -------------- .../v1/processor/service/FileStatusService.java | 2 -- .../dossiertemplate/dossier/file/FileType.java | 4 +++- 4 files changed, 4 insertions(+), 20 deletions(-) diff --git a/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/internal/AdminInterfaceController.java b/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/internal/AdminInterfaceController.java index 601653c2e..b4c77e297 100644 --- a/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/internal/AdminInterfaceController.java +++ b/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/internal/AdminInterfaceController.java @@ -22,7 +22,7 @@ import lombok.extern.slf4j.Slf4j; @Slf4j @RestController @RequiredArgsConstructor -@RequestMapping(InternalApi.BASE_PATH+"/admin") +@RequestMapping(InternalApi.BASE_PATH + "/admin") public class AdminInterfaceController { private final FileManagementStorageService fileManagementStorageService; @@ -35,7 +35,6 @@ public class AdminInterfaceController { @PostMapping("/reset-file") public void resetFile(@RequestParam("dossierId") String dossierId, @RequestParam("fileId") String fileId) { - fileManagementStorageService.deleteObject(dossierId, fileId, FileType.SECTION_GRID); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.REDACTION_LOG); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.ENTITY_LOG); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.DOCUMENT_PAGES); @@ -138,7 +137,6 @@ public class AdminInterfaceController { var dossierId = file.getDossierId(); var fileId = file.getId(); - fileManagementStorageService.deleteObject(dossierId, fileId, FileType.SECTION_GRID); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.REDACTION_LOG); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.ENTITY_LOG); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.DOCUMENT_STRUCTURE); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileManagementStorageService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileManagementStorageService.java index 55b17bcbf..96be2eaf2 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileManagementStorageService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileManagementStorageService.java @@ -18,7 +18,6 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.imported.ImportedRedactions; -import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.section.SectionGrid; import com.iqser.red.storage.commons.exception.StorageException; import com.iqser.red.storage.commons.exception.StorageObjectDoesNotExist; import com.iqser.red.storage.commons.service.StorageService; @@ -116,19 +115,6 @@ public class FileManagementStorageService { } - public SectionGrid getSectionGrid(String dossierId, String fileId) { - - try { - return storageService.readJSONObject(TenantContext.getTenantId(), StorageIdUtils.getStorageId(dossierId, fileId, FileType.SECTION_GRID), SectionGrid.class); - } catch (StorageObjectDoesNotExist e) { - log.debug("SectionGrid not available."); - throw new NotFoundException("SectionGrid does not exist"); - } catch (Exception e) { - throw new RuntimeException("Could not convert SectionGrid", e); - } - } - - public ImportedRedactions getImportedRedactions(String dossierId, String fileId) { try { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java index f53861151..474fdfcb1 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java @@ -640,7 +640,6 @@ public class FileStatusService { fileManagementStorageService.deleteObject(dossierId, fileId, FileType.ORIGIN); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.REDACTION_LOG); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.ENTITY_LOG); - fileManagementStorageService.deleteObject(dossierId, fileId, FileType.SECTION_GRID); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.IMAGE_INFO); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.DOCUMENT_STRUCTURE); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.DOCUMENT_PAGES); @@ -670,7 +669,6 @@ public class FileStatusService { // remove everything related to redaction fileManagementStorageService.deleteObject(dossierId, fileId, FileType.REDACTION_LOG); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.ENTITY_LOG); - fileManagementStorageService.deleteObject(dossierId, fileId, FileType.SECTION_GRID); fileManagementStorageService.deleteObject(dossierId, fileId, FileType.IMAGE_INFO); // wipe comments diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/FileType.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/FileType.java index f4df3c82c..7e67f33ac 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/FileType.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/FileType.java @@ -24,7 +24,9 @@ public enum FileType { DOCUMENT_PAGES(".json"), ENTITY_LOG(".json"), COMPONENT_LOG(".json"), - MIGRATED_IDS(".json"); + MIGRATED_IDS(".json"), + @Deprecated(forRemoval = true) // still needed for migration to delete existing ones, can be removed as soon as migration is done + SECTION_GRID(".json"); @Getter private final String extension; -- 2.47.2 From a279a7665944b05f34996b07a704effb5174cdf0 Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Fri, 27 Oct 2023 12:13:47 +0200 Subject: [PATCH 43/96] RED-7384: create shared models in persistence service --- .../service/FileManagementStorageService.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileManagementStorageService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileManagementStorageService.java index 96be2eaf2..55b17bcbf 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileManagementStorageService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileManagementStorageService.java @@ -18,6 +18,7 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog; import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.imported.ImportedRedactions; +import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.section.SectionGrid; import com.iqser.red.storage.commons.exception.StorageException; import com.iqser.red.storage.commons.exception.StorageObjectDoesNotExist; import com.iqser.red.storage.commons.service.StorageService; @@ -115,6 +116,19 @@ public class FileManagementStorageService { } + public SectionGrid getSectionGrid(String dossierId, String fileId) { + + try { + return storageService.readJSONObject(TenantContext.getTenantId(), StorageIdUtils.getStorageId(dossierId, fileId, FileType.SECTION_GRID), SectionGrid.class); + } catch (StorageObjectDoesNotExist e) { + log.debug("SectionGrid not available."); + throw new NotFoundException("SectionGrid does not exist"); + } catch (Exception e) { + throw new RuntimeException("Could not convert SectionGrid", e); + } + } + + public ImportedRedactions getImportedRedactions(String dossierId, String fileId) { try { -- 2.47.2 From 8a50f6c0a28623ceec4d45b5c524aeec176626eb Mon Sep 17 00:00:00 2001 From: Corina Olariu Date: Mon, 30 Oct 2023 11:20:02 +0200 Subject: [PATCH 44/96] RED-7848 - Sorting in merged dictionary differs from template dictionary in terms of capitalization - update the sorting to natural order - update junit tests --- .../processor/service/DictionaryService.java | 13 +++--- .../integration/tests/DictionaryTest.java | 44 ++++++++++++------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java index 781589c19..210805c19 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java @@ -14,7 +14,6 @@ import static com.iqser.red.service.persistence.management.v1.processor.roles.Ac import static com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils.toTypeId; import java.util.ArrayList; -import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -272,19 +271,19 @@ public class DictionaryService { .stream() .filter(e -> !e.isDeleted()) .map(DictionaryEntry::getValue) - .sorted(Comparator.comparing(String::toLowerCase)) + .sorted() .collect(Collectors.toList())) .falsePositiveEntries(dictionaryForType.getFalsePositiveEntries() .stream() .filter(e -> !e.isDeleted()) .map(DictionaryEntry::getValue) - .sorted(Comparator.comparing(String::toLowerCase)) + .sorted() .collect(Collectors.toList())) .falseRecommendationEntries(dictionaryForType.getFalseRecommendationEntries() .stream() .filter(e -> !e.isDeleted()) .map(DictionaryEntry::getValue) - .sorted(Comparator.comparing(String::toLowerCase)) + .sorted() .collect(Collectors.toList())) .hexColor(dictionaryForType.getHexColor()) .recommendationHexColor(dictionaryForType.getRecommendationHexColor()) @@ -340,19 +339,19 @@ public class DictionaryService { .stream() .filter(e -> !e.isDeleted()) .map(DictionaryEntry::getValue) - .sorted(Comparator.comparing(String::toLowerCase)) + .sorted() .collect(Collectors.toList())) .falsePositiveEntries(cdm.getFalsePositives() .stream() .filter(e -> !e.isDeleted()) .map(DictionaryEntry::getValue) - .sorted(Comparator.comparing(String::toLowerCase)) + .sorted() .collect(Collectors.toList())) .falseRecommendationEntries(cdm.getFalseRecommendations() .stream() .filter(e -> !e.isDeleted()) .map(DictionaryEntry::getValue) - .sorted(Comparator.comparing(String::toLowerCase)) + .sorted() .collect(Collectors.toList())) .hexColor(entity.getHexColor()) .recommendationHexColor(entity.getRecommendationHexColor()) diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DictionaryTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DictionaryTest.java index 6db1a4ee5..4abb4abc3 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DictionaryTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DictionaryTest.java @@ -5,6 +5,7 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.stream.Collectors; import java.util.stream.IntStream; import org.junit.jupiter.api.Assertions; @@ -404,9 +405,9 @@ public class DictionaryTest extends AbstractPersistenceServerServiceTest { var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate, "Dossier"); var type = typeProvider.testAndProvideType(dossierTemplate); - Assertions.assertThrows(FeignException.BadRequest.class, () -> dictionaryClient.getAllTypes(dossierTemplate1.getDossierTemplateId(), dossier.getDossierId(), false)); + Assertions.assertThrows(FeignException.BadRequest.class, () -> dictionaryClient.getAllTypes(dossierTemplate1.getId(), dossier.getId(), false)); - Assertions.assertThrows(FeignException.BadRequest.class, () -> dictionaryClient.getDictionaryForType(type.getType(), dossierTemplate1.getDossierTemplateId(), dossier.getDossierId())); + Assertions.assertThrows(FeignException.BadRequest.class, () -> dictionaryClient.getDictionaryForType(type.getType(), dossierTemplate1.getId(), dossier.getId())); } @@ -435,18 +436,18 @@ public class DictionaryTest extends AbstractPersistenceServerServiceTest { assertThat(loadedType1.getFalsePositiveEntries()).hasSize(2); assertThat(loadedType1.getFalseRecommendationEntries()).hasSize(2); - dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("word1", "word4"), false, dossier.getDossierId(), DictionaryEntryType.ENTRY); - dictionaryClient.deleteEntries(type.getType(), type.getDossierTemplateId(), List.of("word2"), dossier.getDossierId(), DictionaryEntryType.ENTRY); - dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("false_positive1", "false_positive3"), false, dossier.getDossierId(), DictionaryEntryType.FALSE_POSITIVE); + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("word1", "word4"), false, dossier.getId(), DictionaryEntryType.ENTRY); + dictionaryClient.deleteEntries(type.getType(), type.getDossierTemplateId(), List.of("word2"), dossier.getId(), DictionaryEntryType.ENTRY); + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("false_positive1", "false_positive3"), false, dossier.getId(), DictionaryEntryType.FALSE_POSITIVE); dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("false_recommendation3", "false_recommendation4"), false, - dossier.getDossierId(), + dossier.getId(), DictionaryEntryType.FALSE_RECOMMENDATION); - Assertions.assertThrows(FeignException.Unauthorized.class, () -> dictionaryClient.getMergedDictionaries(type.getType() + ";", dossierTemplate.getDossierTemplateId(), dossier.getDossierId())); + Assertions.assertThrows(FeignException.Unauthorized.class, () -> dictionaryClient.getMergedDictionaries(type.getType() + ";", dossierTemplate.getId(), dossier.getId())); - Dictionary mergedDict = dictionaryClient.getMergedDictionaries(type.getType(), dossierTemplate.getDossierTemplateId(), dossier.getDossierId()); + Dictionary mergedDict = dictionaryClient.getMergedDictionaries(type.getType(), dossierTemplate.getId(), dossier.getId()); assertThat(mergedDict).isNotNull(); assertThat(mergedDict.getEntries().size()).isEqualTo(3); assertThat(mergedDict.getFalsePositiveEntries().size()).isEqualTo(3); @@ -475,17 +476,17 @@ public class DictionaryTest extends AbstractPersistenceServerServiceTest { assertThat(loadedType1.getFalsePositiveEntries()).hasSize(2); assertThat(loadedType1.getFalseRecommendationEntries()).hasSize(2); - dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("word1", "word4"), false, dossier.getDossierId(), DictionaryEntryType.ENTRY); - dictionaryClient.deleteEntries(type.getType(), type.getDossierTemplateId(), List.of("word2"), dossier.getDossierId(), DictionaryEntryType.ENTRY); - dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("false_positive1", "false_positive3"), false, dossier.getDossierId(), DictionaryEntryType.FALSE_POSITIVE); + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("word1", "word4"), false, dossier.getId(), DictionaryEntryType.ENTRY); + dictionaryClient.deleteEntries(type.getType(), type.getDossierTemplateId(), List.of("word2"), dossier.getId(), DictionaryEntryType.ENTRY); + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("false_positive1", "false_positive3"), false, dossier.getId(), DictionaryEntryType.FALSE_POSITIVE); dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("false_recommendation3", "false_recommendation4"), false, - dossier.getDossierId(), + dossier.getId(), DictionaryEntryType.FALSE_RECOMMENDATION); - var loadedType2 = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getDossierId()); + var loadedType2 = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), dossier.getId()); assertThat(loadedType2.getEntries()).hasSize(2); assertThat(loadedType2.getFalsePositiveEntries()).hasSize(2); @@ -505,7 +506,7 @@ public class DictionaryTest extends AbstractPersistenceServerServiceTest { assertThat(type.getSkippedHexColor()).isEqualTo("#aaaaaa"); assertThat(type.isDossierDictionaryOnly()).isFalse(); - dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("Charalampos", "Carina Wilson", "carlsen"), false, null, DictionaryEntryType.ENTRY); + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("William c. Spare", "Charalampos", "Carina Wilson", "William C. Spare" ,"carlsen"), false, null, DictionaryEntryType.ENTRY); dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("false_positive1", "false_positive"), false, null, DictionaryEntryType.FALSE_POSITIVE); dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), @@ -517,10 +518,12 @@ public class DictionaryTest extends AbstractPersistenceServerServiceTest { var loadedType1 = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); var entries = loadedType1.getEntries(); - assertThat(entries).hasSize(3); + assertThat(entries).hasSize(5); assertThat(entries.get(0)).isEqualTo("Carina Wilson"); assertThat(entries.get(1)).isEqualTo("carlsen"); assertThat(entries.get(2)).isEqualTo("Charalampos"); + assertThat(entries.get(3)).isEqualTo("William C. Spare"); + assertThat(entries.get(4)).isEqualTo("William c. Spare"); assertThat(loadedType1.getFalsePositiveEntries()).hasSize(2); assertThat(loadedType1.getFalsePositiveEntries().get(0)).isEqualTo("false_positive"); assertThat(loadedType1.getFalsePositiveEntries().get(1)).isEqualTo("false_positive1"); @@ -529,7 +532,16 @@ public class DictionaryTest extends AbstractPersistenceServerServiceTest { assertThat(loadedType1.getFalseRecommendationEntries().get(1)).isEqualTo("false_recommendation1"); } + @Test + public void testSortedEntriesTest() { + var testList1 = List.of("William c. Spare", "PATRICIA A. SHEEHY", "William C. Spare", "Patricia A. Sheehy"); + var sortedList12 = testList1.stream().sorted().collect(Collectors.toList()); + + var testList2 = List.of("William C. Spare", "Patricia A. Sheehy", "William c. Spare" , "PATRICIA A. SHEEHY"); + var sortedList21 = testList2.stream().sorted().collect(Collectors.toList()); + assertThat(sortedList12).isEqualTo(sortedList21); + } @Test public void testCreateAndDeleteLargeDictionary() { @@ -559,7 +571,7 @@ public class DictionaryTest extends AbstractPersistenceServerServiceTest { assertThat(actualEntries.size()).isEqualTo(entries.size()); assertThat(actualEntries).usingComparator(new ListContentWithoutOrderAndWithoutDuplicatesComparator<>()).isEqualTo(entries); - dictionaryClient.deleteEntries(type.getType(), dossierTemplate.getDossierTemplateId(), entries, null, null); + dictionaryClient.deleteEntries(type.getType(), dossierTemplate.getId(), entries, null, null); dictionary = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); -- 2.47.2 From 13e47c64534761b288e14f982852c36d34424c58 Mon Sep 17 00:00:00 2001 From: Corina Olariu Date: Mon, 30 Oct 2023 14:51:23 +0200 Subject: [PATCH 45/96] RED-7848 - Sorting in merged dictionary differs from template dictionary in terms of capitalization - update the sorting of entries with a custom comparator - update junit tests --- .../processor/service/DictionaryService.java | 23 ++++++-- .../integration/tests/DictionaryTest.java | 59 +++++++++++++++---- 2 files changed, 64 insertions(+), 18 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java index 210805c19..580105de2 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java @@ -14,6 +14,7 @@ import static com.iqser.red.service.persistence.management.v1.processor.roles.Ac import static com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUtils.toTypeId; import java.util.ArrayList; +import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -52,6 +53,16 @@ import lombok.extern.slf4j.Slf4j; @RequiredArgsConstructor public class DictionaryService { + /** + * Comparator to sort entries list + */ + public static Comparator entryComparator = (e1, e2) -> { + if (e1.compareToIgnoreCase(e2) == 0) { + return e1.compareTo(e2); + } + return e1.compareToIgnoreCase(e2); + }; + private final DictionaryManagementService dictionaryManagementService; private final ColorsService colorsService; @@ -271,19 +282,19 @@ public class DictionaryService { .stream() .filter(e -> !e.isDeleted()) .map(DictionaryEntry::getValue) - .sorted() + .sorted(entryComparator) .collect(Collectors.toList())) .falsePositiveEntries(dictionaryForType.getFalsePositiveEntries() .stream() .filter(e -> !e.isDeleted()) .map(DictionaryEntry::getValue) - .sorted() + .sorted(entryComparator) .collect(Collectors.toList())) .falseRecommendationEntries(dictionaryForType.getFalseRecommendationEntries() .stream() .filter(e -> !e.isDeleted()) .map(DictionaryEntry::getValue) - .sorted() + .sorted(entryComparator) .collect(Collectors.toList())) .hexColor(dictionaryForType.getHexColor()) .recommendationHexColor(dictionaryForType.getRecommendationHexColor()) @@ -339,19 +350,19 @@ public class DictionaryService { .stream() .filter(e -> !e.isDeleted()) .map(DictionaryEntry::getValue) - .sorted() + .sorted(entryComparator) .collect(Collectors.toList())) .falsePositiveEntries(cdm.getFalsePositives() .stream() .filter(e -> !e.isDeleted()) .map(DictionaryEntry::getValue) - .sorted() + .sorted(entryComparator) .collect(Collectors.toList())) .falseRecommendationEntries(cdm.getFalseRecommendations() .stream() .filter(e -> !e.isDeleted()) .map(DictionaryEntry::getValue) - .sorted() + .sorted(entryComparator) .collect(Collectors.toList())) .hexColor(entity.getHexColor()) .recommendationHexColor(entity.getRecommendationHexColor()) diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DictionaryTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DictionaryTest.java index 4abb4abc3..cfc3af608 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DictionaryTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DictionaryTest.java @@ -5,7 +5,6 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.ArrayList; import java.util.Comparator; import java.util.List; -import java.util.stream.Collectors; import java.util.stream.IntStream; import org.junit.jupiter.api.Assertions; @@ -20,6 +19,7 @@ import com.iqser.red.service.peristence.v1.server.integration.service.DossierTem import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider; import com.iqser.red.service.peristence.v1.server.integration.service.TypeProvider; import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest; +import com.iqser.red.service.persistence.management.v1.processor.service.DictionaryService; import com.iqser.red.service.persistence.service.v1.api.shared.model.CreateTypeValue; import com.iqser.red.service.persistence.service.v1.api.shared.model.Dictionary; import com.iqser.red.service.persistence.service.v1.api.shared.model.TypeValue; @@ -46,6 +46,10 @@ public class DictionaryTest extends AbstractPersistenceServerServiceTest { @Autowired private DossierTemplateClient dossierTemplateClient; + private List testList1 = List.of("William c. Spare", "Charalampos", "Carina Wilson", "PATRICIA A. SHEEHY", "William C. Spare", "carlsen", "Patricia A. Sheehy"); + private List testList2 = List.of("William C. Spare", "Charalampos", "Carina Wilson", "Patricia A. Sheehy", "William c. Spare", "carlsen", "PATRICIA A. SHEEHY"); + + @BeforeEach public void createDossierRedactionDictionary() { @@ -506,8 +510,8 @@ public class DictionaryTest extends AbstractPersistenceServerServiceTest { assertThat(type.getSkippedHexColor()).isEqualTo("#aaaaaa"); assertThat(type.isDossierDictionaryOnly()).isFalse(); - dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("William c. Spare", "Charalampos", "Carina Wilson", "William C. Spare" ,"carlsen"), false, null, DictionaryEntryType.ENTRY); - dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("false_positive1", "false_positive"), false, null, DictionaryEntryType.FALSE_POSITIVE); + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), testList1, false, null, DictionaryEntryType.ENTRY); + dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), testList2, false, null, DictionaryEntryType.FALSE_POSITIVE); dictionaryClient.addEntry(type.getType(), type.getDossierTemplateId(), List.of("false_recommendation1", "afalse_recommendation2"), @@ -518,15 +522,25 @@ public class DictionaryTest extends AbstractPersistenceServerServiceTest { var loadedType1 = dictionaryClient.getDictionaryForType(type.getType(), type.getDossierTemplateId(), null); var entries = loadedType1.getEntries(); - assertThat(entries).hasSize(5); + assertThat(entries).hasSize(7); assertThat(entries.get(0)).isEqualTo("Carina Wilson"); assertThat(entries.get(1)).isEqualTo("carlsen"); assertThat(entries.get(2)).isEqualTo("Charalampos"); + assertThat(entries.get(3)).isEqualTo("PATRICIA A. SHEEHY"); + assertThat(entries.get(3)).isEqualTo("Patricia A. Sheehy"); assertThat(entries.get(3)).isEqualTo("William C. Spare"); assertThat(entries.get(4)).isEqualTo("William c. Spare"); - assertThat(loadedType1.getFalsePositiveEntries()).hasSize(2); - assertThat(loadedType1.getFalsePositiveEntries().get(0)).isEqualTo("false_positive"); - assertThat(loadedType1.getFalsePositiveEntries().get(1)).isEqualTo("false_positive1"); +// assertThat(entries).isEqualTo(loadedType1.getFalsePositiveEntries()); + + var falsePositives = loadedType1.getEntries(); + assertThat(falsePositives).hasSize(7); + assertThat(falsePositives.get(0)).isEqualTo("Carina Wilson"); + assertThat(falsePositives.get(1)).isEqualTo("carlsen"); + assertThat(falsePositives.get(2)).isEqualTo("Charalampos"); + assertThat(falsePositives.get(3)).isEqualTo("PATRICIA A. SHEEHY"); + assertThat(falsePositives.get(3)).isEqualTo("Patricia A. Sheehy"); + assertThat(falsePositives.get(3)).isEqualTo("William C. Spare"); + assertThat(falsePositives.get(4)).isEqualTo("William c. Spare"); assertThat(loadedType1.getFalseRecommendationEntries()).hasSize(2); assertThat(loadedType1.getFalseRecommendationEntries().get(0)).isEqualTo("afalse_recommendation2"); assertThat(loadedType1.getFalseRecommendationEntries().get(1)).isEqualTo("false_recommendation1"); @@ -535,12 +549,33 @@ public class DictionaryTest extends AbstractPersistenceServerServiceTest { @Test public void testSortedEntriesTest() { - var testList1 = List.of("William c. Spare", "PATRICIA A. SHEEHY", "William C. Spare", "Patricia A. Sheehy"); - var sortedList12 = testList1.stream().sorted().collect(Collectors.toList()); + var testList1 = List.of("William c. Spare", "Charalampos", "Carina Wilson", "PATRICIA A. SHEEHY", "William C. Spare", "carlsen", "Patricia A. Sheehy"); + var testList2 = List.of("William C. Spare", "Charalampos", "Carina Wilson", "Patricia A. Sheehy", "William c. Spare", "carlsen", "PATRICIA A. SHEEHY"); + System.out.println("Test list 1: " + testList1); + var sortedList1 = testList1.stream().sorted().sorted(Comparator.comparing(String::toLowerCase)).toList(); + var sortedList12 = testList1.stream().sorted().toList(); + var sortedList11 = testList1.stream().sorted(String:: compareToIgnoreCase).toList(); + var sortedList13 = testList1.stream().sorted(DictionaryService.entryComparator).toList(); - var testList2 = List.of("William C. Spare", "Patricia A. Sheehy", "William c. Spare" , "PATRICIA A. SHEEHY"); - var sortedList21 = testList2.stream().sorted().collect(Collectors.toList()); - assertThat(sortedList12).isEqualTo(sortedList21); + var sortedList2 = testList2.stream().sorted().sorted(Comparator.comparing(String::toLowerCase)).toList(); + var sortedList22 = testList2.stream().sorted().toList(); + var sortedList21 = testList2.stream().sorted(String::compareToIgnoreCase).toList(); + var sortedList23 = testList2.stream().sorted(DictionaryService.entryComparator).toList(); +// var sortedList23 = testList2.stream().sorted(Comparator.naturalOrder().thenComparing((a,b) -> a.(b))).toList(); + System.out.println("Test list 2: " + testList2); + System.out.println("With sorted()sorted(Comparator.comparing(String::toLowerCase)): " + sortedList1); + System.out.println("With sorted()sorted(Comparator.comparing(String::toLowerCase)): " + sortedList2); + System.out.println("Just sorted(): " + sortedList12); + System.out.println("Just sorted(): " + sortedList22); + System.out.println("sorted(String:: compareToIgnoreCase): " + sortedList11); + System.out.println("sorted(String:: compareToIgnoreCase): " + sortedList21); + System.out.println("sorted(custom): " + sortedList13); + System.out.println("sorted(custom): " + sortedList23); + + assertThat(sortedList1).isEqualTo(sortedList2); + assertThat(sortedList13).isEqualTo(sortedList23); + assertThat(sortedList12).isEqualTo(sortedList22); // the result are equal but not in the desired order + assertThat(sortedList11).isNotEqualTo(sortedList21); } @Test -- 2.47.2 From efe6dd5930b05a5d10b74a4f254dcd33ee1298e9 Mon Sep 17 00:00:00 2001 From: Corina Olariu Date: Mon, 30 Oct 2023 14:58:48 +0200 Subject: [PATCH 46/96] RED-7848 - Sorting in merged dictionary differs from template dictionary in terms of capitalization - correct junit assertions --- .../v1/server/integration/tests/DictionaryTest.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DictionaryTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DictionaryTest.java index cfc3af608..8325fe108 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DictionaryTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DictionaryTest.java @@ -527,9 +527,9 @@ public class DictionaryTest extends AbstractPersistenceServerServiceTest { assertThat(entries.get(1)).isEqualTo("carlsen"); assertThat(entries.get(2)).isEqualTo("Charalampos"); assertThat(entries.get(3)).isEqualTo("PATRICIA A. SHEEHY"); - assertThat(entries.get(3)).isEqualTo("Patricia A. Sheehy"); - assertThat(entries.get(3)).isEqualTo("William C. Spare"); - assertThat(entries.get(4)).isEqualTo("William c. Spare"); + assertThat(entries.get(4)).isEqualTo("Patricia A. Sheehy"); + assertThat(entries.get(5)).isEqualTo("William C. Spare"); + assertThat(entries.get(6)).isEqualTo("William c. Spare"); // assertThat(entries).isEqualTo(loadedType1.getFalsePositiveEntries()); var falsePositives = loadedType1.getEntries(); @@ -538,9 +538,9 @@ public class DictionaryTest extends AbstractPersistenceServerServiceTest { assertThat(falsePositives.get(1)).isEqualTo("carlsen"); assertThat(falsePositives.get(2)).isEqualTo("Charalampos"); assertThat(falsePositives.get(3)).isEqualTo("PATRICIA A. SHEEHY"); - assertThat(falsePositives.get(3)).isEqualTo("Patricia A. Sheehy"); - assertThat(falsePositives.get(3)).isEqualTo("William C. Spare"); - assertThat(falsePositives.get(4)).isEqualTo("William c. Spare"); + assertThat(falsePositives.get(4)).isEqualTo("Patricia A. Sheehy"); + assertThat(falsePositives.get(5)).isEqualTo("William C. Spare"); + assertThat(falsePositives.get(6)).isEqualTo("William c. Spare"); assertThat(loadedType1.getFalseRecommendationEntries()).hasSize(2); assertThat(loadedType1.getFalseRecommendationEntries().get(0)).isEqualTo("afalse_recommendation2"); assertThat(loadedType1.getFalseRecommendationEntries().get(1)).isEqualTo("false_recommendation1"); @@ -561,7 +561,6 @@ public class DictionaryTest extends AbstractPersistenceServerServiceTest { var sortedList22 = testList2.stream().sorted().toList(); var sortedList21 = testList2.stream().sorted(String::compareToIgnoreCase).toList(); var sortedList23 = testList2.stream().sorted(DictionaryService.entryComparator).toList(); -// var sortedList23 = testList2.stream().sorted(Comparator.naturalOrder().thenComparing((a,b) -> a.(b))).toList(); System.out.println("Test list 2: " + testList2); System.out.println("With sorted()sorted(Comparator.comparing(String::toLowerCase)): " + sortedList1); System.out.println("With sorted()sorted(Comparator.comparing(String::toLowerCase)): " + sortedList2); -- 2.47.2 From c2d558636c9c8e28d123a95ab94c44fd53cb14f0 Mon Sep 17 00:00:00 2001 From: Corina Olariu Date: Mon, 30 Oct 2023 15:19:28 +0200 Subject: [PATCH 47/96] RED-7848 - Sorting in merged dictionary differs from template dictionary in terms of capitalization - fic cheskstyle error --- .../management/v1/processor/service/DictionaryService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java index 580105de2..8dcc0cfdb 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DictionaryService.java @@ -54,7 +54,7 @@ import lombok.extern.slf4j.Slf4j; public class DictionaryService { /** - * Comparator to sort entries list + * Comparator to sort entries list. */ public static Comparator entryComparator = (e1, e2) -> { if (e1.compareToIgnoreCase(e2) == 0) { -- 2.47.2 From afa75b850c9631958dabf2ecdc98de6712a850c7 Mon Sep 17 00:00:00 2001 From: Corina Olariu Date: Tue, 31 Oct 2023 15:39:06 +0200 Subject: [PATCH 48/96] RED-7854 - UI stuck when selecting a future license - in case start date is in the future send 0 values for license report --- .../service/LicenseReportService.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java index da445db13..97e9fcc60 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java @@ -30,14 +30,33 @@ public class LicenseReportService { public LicenseReport getLicenseReport(LicenseReportRequest licenseReportRequest) { - if (licenseReportRequest.getStartDate() == null || licenseReportRequest.getStartDate().isAfter(Instant.now())) { + if (licenseReportRequest.getStartDate() == null) { throw new BadRequestException("Invalid start date."); } + if (licenseReportRequest.getStartDate().isAfter(Instant.now())) { + return LicenseReport.builder() + .totalFilesUploadedBytes(0) + .activeFilesUploadedBytes(0) + .trashFilesUploadedBytes(0) + .archivedFilesUploadedBytes(0) + .numberOfAnalyzedPages(0) + .numberOfOcrPages(0) + .numberOfAnalyzedFiles(0) + .analysedFilesBytes(0) + .numberOfOcrFiles(0) + .numberOfDossiers(0) + .startDate(licenseReportRequest.getStartDate()) + .endDate(licenseReportRequest.getEndDate()) + .build(); + } + if (licenseReportRequest.getStartDate().isAfter(licenseReportRequest.getEndDate())) { throw new BadRequestException("Invalid date period: End date is before start date."); } + + var files = fileStatusService.getStatusesAddedBefore(OffsetDateTime.ofInstant(licenseReportRequest.getEndDate(), UTC_ZONE_ID)); var addDossiers = dossierService.getAllDossiers(); -- 2.47.2 From 5c28072103ffdf8e1e1e3f0954a88c7bcafd2404 Mon Sep 17 00:00:00 2001 From: Corina Olariu Date: Tue, 31 Oct 2023 15:58:12 +0200 Subject: [PATCH 49/96] RED-7854 - UI stuck when selecting a future license - return 0 values in all invalid cases --- .../processor/service/LicenseReportService.java | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java index 97e9fcc60..9077d1311 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java @@ -1,7 +1,6 @@ package com.iqser.red.service.persistence.management.v1.processor.service; import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity; -import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileModel; import com.iqser.red.service.persistence.service.v1.api.shared.model.license.LicenseReport; import com.iqser.red.service.persistence.service.v1.api.shared.model.license.LicenseReportRequest; @@ -30,11 +29,9 @@ public class LicenseReportService { public LicenseReport getLicenseReport(LicenseReportRequest licenseReportRequest) { - if (licenseReportRequest.getStartDate() == null) { - throw new BadRequestException("Invalid start date."); - } - - if (licenseReportRequest.getStartDate().isAfter(Instant.now())) { + if (licenseReportRequest.getStartDate() == null || + licenseReportRequest.getStartDate().isAfter(Instant.now()) || + licenseReportRequest.getStartDate().isAfter(licenseReportRequest.getEndDate())) { return LicenseReport.builder() .totalFilesUploadedBytes(0) .activeFilesUploadedBytes(0) @@ -51,12 +48,6 @@ public class LicenseReportService { .build(); } - if (licenseReportRequest.getStartDate().isAfter(licenseReportRequest.getEndDate())) { - throw new BadRequestException("Invalid date period: End date is before start date."); - } - - - var files = fileStatusService.getStatusesAddedBefore(OffsetDateTime.ofInstant(licenseReportRequest.getEndDate(), UTC_ZONE_ID)); var addDossiers = dossierService.getAllDossiers(); -- 2.47.2 From b966ac516b53b56b7b9e55509ab36e28c24ccdca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominique=20Eifl=C3=A4nder?= Date: Tue, 31 Oct 2023 15:00:44 +0100 Subject: [PATCH 50/96] RED-7517: Save dossier and acls in same transaction --- .../impl/controller/DossierController.java | 7 ++-- .../service/DossierCreatorService.java | 34 +++++++++++++++++++ .../service/DossierManagementService.java | 32 +++++------------ .../v1/processor/service/DossierService.java | 15 ++++---- 4 files changed, 54 insertions(+), 34 deletions(-) create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierCreatorService.java diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/DossierController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/DossierController.java index 9ef7fb81a..3d606825c 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/DossierController.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/DossierController.java @@ -18,6 +18,7 @@ import java.util.Set; import java.util.TreeSet; import java.util.stream.Collectors; +import com.iqser.red.service.persistence.management.v1.processor.service.DossierCreatorService; import org.apache.commons.lang3.StringUtils; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -73,6 +74,7 @@ public class DossierController implements DossierResource { private final NotificationPersistenceService notificationPersistenceService; private final AccessControlService accessControlService; private final DossierACLService dossierACLService; + private final DossierCreatorService dossierCreatorService; @Override @@ -308,7 +310,7 @@ public class DossierController implements DossierResource { private Dossier createNewDossier(DossierRequest dossier, String ownerId, Set members, Set approvers) { - Dossier newDossier = dossierManagementService.addDossier(CreateOrUpdateDossierRequest.builder() + Dossier newDossier = dossierCreatorService.addDossier(CreateOrUpdateDossierRequest.builder() .dossierName(dossier.getDossierName()) .description(dossier.getDescription()) .dossierTemplateId(dossier.getDossierTemplateId()) @@ -318,9 +320,8 @@ public class DossierController implements DossierResource { .watermarkId(dossier.getWatermarkId()) .previewWatermarkId(dossier.getPreviewWatermarkId()) .dossierStatusId(dossier.getDossierStatusId()) - .build()); + .build(), members, approvers, ownerId); - dossierACLService.updateDossierACL(members, approvers, ownerId, newDossier.getId()); dossierACLService.enhanceDossierWithACLData(newDossier); return newDossier; diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierCreatorService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierCreatorService.java new file mode 100644 index 000000000..3cc5a39f3 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierCreatorService.java @@ -0,0 +1,34 @@ +package com.iqser.red.service.persistence.management.v1.processor.service; + +import com.iqser.red.service.persistence.management.v1.processor.acl.custom.dossier.DossierACLService; +import com.iqser.red.service.persistence.management.v1.processor.utils.DossierMapper; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.CreateOrUpdateDossierRequest; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier; +import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Set; + + +@Slf4j +@Service +@RequiredArgsConstructor +public class DossierCreatorService { + + private final DossierService dossierService; + private final DossierACLService dossierACLService; + + + @Transactional + public Dossier addDossier(CreateOrUpdateDossierRequest dossierRequest, Set members, Set approvers, String ownerId) { + + var dossier = dossierService.addDossier(dossierRequest); + dossierACLService.updateDossierACL(members, approvers, ownerId, dossier.getId()); + + return MagicConverter.convert(dossier, Dossier.class, new DossierMapper()); + } + +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierManagementService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierManagementService.java index 252ad7e56..99f93df0e 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierManagementService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierManagementService.java @@ -1,18 +1,7 @@ package com.iqser.red.service.persistence.management.v1.processor.service; -import static com.iqser.red.service.persistence.management.v1.processor.exception.DossierNotFoundException.DOSSIER_NOT_FOUND_MESSAGE; - -import java.time.OffsetDateTime; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import org.springframework.stereotype.Service; - import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity; import com.iqser.red.service.persistence.management.v1.processor.exception.DossierNotFoundException; -import com.iqser.red.service.persistence.management.v1.processor.settings.FileManagementServiceSettings; import com.iqser.red.service.persistence.management.v1.processor.utils.DossierMapper; import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierInformation; import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive; @@ -22,10 +11,18 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileModel; import com.iqser.red.service.search.v1.model.IndexMessageType; import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter; - import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.time.OffsetDateTime; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static com.iqser.red.service.persistence.management.v1.processor.exception.DossierNotFoundException.DOSSIER_NOT_FOUND_MESSAGE; @Slf4j @Service @@ -36,8 +33,6 @@ public class DossierManagementService { private final FileStatusService fileStatusService; private final FileService fileService; private final IndexingService indexingService; - private final DictionaryManagementService dictionaryManagementService; - private final FileManagementServiceSettings fileManagementServiceSettings; public Set changesSince(JSONPrimitive since) { @@ -46,15 +41,6 @@ public class DossierManagementService { } - @Transactional - public Dossier addDossier(CreateOrUpdateDossierRequest dossierRequest) { - - var dossier = dossierService.addDossier(dossierRequest); - - return MagicConverter.convert(dossier, Dossier.class, new DossierMapper()); - } - - @Transactional public Dossier updateDossier(CreateOrUpdateDossierRequest dossierRequest, String dossierId) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierService.java index 8d3f2fb33..14eb4ab47 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierService.java @@ -1,12 +1,5 @@ package com.iqser.red.service.persistence.management.v1.processor.service; -import java.time.OffsetDateTime; -import java.util.List; -import java.util.Set; - - -import org.springframework.stereotype.Service; - import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierEntity; import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException; import com.iqser.red.service.persistence.management.v1.processor.exception.ConflictException; @@ -18,10 +11,15 @@ import com.iqser.red.service.persistence.management.v1.processor.utils.TypeIdUti import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierTemplateStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.CreateOrUpdateDossierRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.DossierChange; - +import jakarta.transaction.Transactional; import jakarta.validation.ConstraintViolationException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.time.OffsetDateTime; +import java.util.List; +import java.util.Set; /** * Provides the internal interface between dossier request and the actual persistence. @@ -40,6 +38,7 @@ public class DossierService { private final DictionaryPersistenceService dictionaryPersistenceService; + @Transactional public DossierEntity addDossier(CreateOrUpdateDossierRequest createOrUpdateDossierRequest) { if (dossierPersistenceService.findAllDossiers() -- 2.47.2 From 9b5b8195dced3a6fd025f8d8cc30a92b454e64c0 Mon Sep 17 00:00:00 2001 From: Corina Olariu Date: Wed, 1 Nov 2023 10:21:36 +0200 Subject: [PATCH 51/96] RED-7854 - UI stuck when selecting a future license - no need to specify 0 for int values, will be initialized with 0 by default --- .../v1/processor/service/LicenseReportService.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java index 9077d1311..090f53f48 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java @@ -33,16 +33,6 @@ public class LicenseReportService { licenseReportRequest.getStartDate().isAfter(Instant.now()) || licenseReportRequest.getStartDate().isAfter(licenseReportRequest.getEndDate())) { return LicenseReport.builder() - .totalFilesUploadedBytes(0) - .activeFilesUploadedBytes(0) - .trashFilesUploadedBytes(0) - .archivedFilesUploadedBytes(0) - .numberOfAnalyzedPages(0) - .numberOfOcrPages(0) - .numberOfAnalyzedFiles(0) - .analysedFilesBytes(0) - .numberOfOcrFiles(0) - .numberOfDossiers(0) .startDate(licenseReportRequest.getStartDate()) .endDate(licenseReportRequest.getEndDate()) .build(); -- 2.47.2 From e1007dc5c42cf6770fcb172072a084af930eec2b Mon Sep 17 00:00:00 2001 From: Andrei Isvoran Date: Wed, 1 Nov 2023 10:16:14 +0100 Subject: [PATCH 52/96] RED-7677 - dossier-template endpoint should return a 400 if validFrom > validTo --- .../DossierTemplatePersistenceService.java | 9 +++++++ .../tests/DossierTemplateTest.java | 26 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java index cc3c0d40b..8bb15d261 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java @@ -48,6 +48,7 @@ public class DossierTemplatePersistenceService { public DossierTemplateEntity createOrUpdateDossierTemplate(CreateOrUpdateDossierTemplateRequest createOrUpdateDossierRequest) { if (createOrUpdateDossierRequest.getDossierTemplateId() != null) { + validateDossierTemplateDates(createOrUpdateDossierRequest.getValidFrom(), createOrUpdateDossierRequest.getValidTo()); validateDossierTemplate(createOrUpdateDossierRequest.getName(), createOrUpdateDossierRequest.getDescription()); Optional dossierTemplate = dossierTemplateRepository.findById(createOrUpdateDossierRequest.getDossierTemplateId()); if (dossierTemplate.isPresent()) { @@ -87,6 +88,14 @@ public class DossierTemplatePersistenceService { } + private void validateDossierTemplateDates(OffsetDateTime validFrom, OffsetDateTime validTo) { + + if (validFrom != null && validTo != null && validFrom.isAfter(validTo)) { + throw new BadRequestException("Invalid dates! validFrom can't be after validTo."); + } + } + + @Transactional public void validateDossierTemplateNameIsUnique(String templateName) { diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java index 20fa8a29e..a17264fd7 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java @@ -1,9 +1,13 @@ package com.iqser.red.service.peristence.v1.server.integration.tests; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.InputStream; import java.time.OffsetDateTime; +import java.time.ZoneOffset; import java.time.temporal.ChronoUnit; import java.util.Collections; import java.util.List; @@ -30,6 +34,7 @@ import com.iqser.red.service.peristence.v1.server.integration.client.WatermarkCl import com.iqser.red.service.peristence.v1.server.integration.service.DossierTemplateTesterAndProvider; import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider; import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest; +import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException; import com.iqser.red.service.persistence.management.v1.processor.model.DownloadJob; import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; import com.iqser.red.service.persistence.management.v1.processor.service.export.ExportDownloadMessageReceiver; @@ -784,4 +789,25 @@ public class DossierTemplateTest extends AbstractPersistenceServerServiceTest { assertThat(loadedTemplate.isRemoveWatermark()).isFalse(); } + @Test + public void testUpdateDossierTemplateWithInvalidDates() { + + var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate(); + + var allTemplates = dossierTemplateClient.getAllDossierTemplates(); + assertThat(allTemplates.size()).isEqualTo(1); + assertThat(allTemplates.get(0)).isEqualTo(dossierTemplate); + + // update + var cru = new DossierTemplateModel(); + cru.setDossierTemplateId(dossierTemplate.getId()); + BeanUtils.copyProperties(dossierTemplate, cru); + cru.setName("Template 1 Update"); + cru.setValidTo(OffsetDateTime.of(2020, 1, 1, 1, 1, 1, 1, ZoneOffset.UTC)); + cru.setValidFrom(OffsetDateTime.of(2020, 1, 2, 1, 1, 1, 1, ZoneOffset.UTC)); + + FeignException exception = assertThrows(FeignException.class, () -> dossierTemplateClient.createOrUpdateDossierTemplate(cru)); + assertTrue(exception.getMessage().contains("Invalid dates! validFrom can't be after validTo.")); + } + } -- 2.47.2 From 0f3cc144098c2b4a33190ff74206e6cc3ac288da Mon Sep 17 00:00:00 2001 From: Andrei Isvoran Date: Thu, 2 Nov 2023 09:34:17 +0100 Subject: [PATCH 53/96] RED-7784 - Add state for unprocessed redactions --- .../management/v1/processor/service/EntityLogService.java | 4 +++- .../peristence/v1/server/integration/tests/EntityLogTest.java | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java index 06b909f56..98abf835a 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/EntityLogService.java @@ -161,13 +161,15 @@ public class EntityLogService { .dateTime(OffsetDateTime.now()) .type(ChangeType.ADDED) .build()); + boolean isHint = isHint(manualRedactionEntry.getType(), dossierTemplateId); entityLog.getEntityLogEntry().add(EntityLogEntry.builder() .id(manualRedactionEntry.getAnnotationId()) .type(manualRedactionEntry.getType()) .value(manualRedactionEntry.getValue()) .legalBasis(manualRedactionEntry.getLegalBasis()) .reason(manualRedactionEntry.getReason()) - .entryType(isHint(manualRedactionEntry.getType(), dossierTemplateId) ? EntryType.HINT : EntryType.ENTITY) + .entryType(isHint ? EntryType.HINT : EntryType.ENTITY) + .state(isHint ? EntryState.SKIPPED : EntryState.APPLIED) .imported(false) .matchedRule("") .section(manualRedactionEntry.getSection()) diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogTest.java index d0899c48c..c3f2339ae 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/EntityLogTest.java @@ -132,7 +132,7 @@ public class EntityLogTest { var entityLogEntry = optionalEntityLogEntry.get(); assertEquals(entityLogEntry.getType(), "manual"); assertEquals(entityLogEntry.getEntryType(), EntryType.ENTITY); - assertNull(entityLogEntry.getState()); + assertEquals(entityLogEntry.getState(), EntryState.APPLIED); assertEquals(entityLogEntry.getValue(), "Test"); assertEquals(entityLogEntry.getReason(), "Reason"); assertEquals(entityLogEntry.getTextAfter(), "textAfter"); -- 2.47.2 From 75aa8aa4679512c27191b141a0eb97b24f925c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominique=20Eifl=C3=A4nder?= Date: Mon, 6 Nov 2023 13:06:49 +0100 Subject: [PATCH 54/96] RED-7382: Implemented Saas migration --- .../controller/MigrationStatusController.java | 45 ++++++ .../resource/MigrationStatusResource.java | 23 +++ .../configuration/MessagingConfiguration.java | 29 ++++ .../migration/SaasMigrationStatusEntity.java | 34 ++++ .../SaasAnnotationIdMigrationService.java | 152 ++++++++++++++++++ .../migration/SaasMigrationService.java | 141 ++++++++++++++++ .../processor/service/FileStatusService.java | 2 +- .../service/job/AutomaticAnalysisJob.java | 15 +- .../LayoutParsingRequestFactory.java | 2 +- ...SaasMigrationStatusPersistenceService.java | 69 ++++++++ .../repository/CommentRepository.java | 4 + .../SaasMigrationStatusRepository.java | 33 ++++ .../LayoutParsingFinishedMessageReceiver.java | 31 +++- ...onServiceSaasMigrationMessageReceiver.java | 45 ++++++ .../db/changelog/db.changelog-tenant.yaml | 4 +- .../115-add-saas-migration-status-table.yaml | 28 ++++ .../dossier/file/SaasMigrationStatus.java | 10 ++ .../migration/MigrationStatusResponse.java | 21 +++ persistence-service-v1/pom.xml | 2 +- 19 files changed, 677 insertions(+), 13 deletions(-) create mode 100644 persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/MigrationStatusController.java create mode 100644 persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/MigrationStatusResource.java create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/migration/SaasMigrationStatusEntity.java create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/SaasAnnotationIdMigrationService.java create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/SaasMigrationService.java create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/SaasMigrationStatusPersistenceService.java create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/SaasMigrationStatusRepository.java create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/RedactionServiceSaasMigrationMessageReceiver.java create mode 100644 persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/115-add-saas-migration-status-table.yaml create mode 100644 persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/SaasMigrationStatus.java create mode 100644 persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/saas/migration/MigrationStatusResponse.java diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/MigrationStatusController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/MigrationStatusController.java new file mode 100644 index 000000000..f85573a13 --- /dev/null +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/MigrationStatusController.java @@ -0,0 +1,45 @@ +package com.iqser.red.persistence.service.v1.external.api.impl.controller; + +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.SaasMigrationStatusPersistenceService; +import com.iqser.red.service.persistence.service.v1.api.external.resource.MigrationStatusResource; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.SaasMigrationStatus; +import com.iqser.red.service.persistence.service.v1.api.shared.model.saas.migration.MigrationStatusResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +import static com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.SaasMigrationStatus.*; + +@RestController +@RequiredArgsConstructor +public class MigrationStatusController implements MigrationStatusResource { + + private final SaasMigrationStatusPersistenceService saasMigrationStatusPersistenceService; + + public MigrationStatusResponse migrationStatus() { + int numberOfFilesToMigrate = saasMigrationStatusPersistenceService.countAll(); + + Map filesInStatus = new HashMap<>(); + filesInStatus.put(MIGRATION_REQUIRED, saasMigrationStatusPersistenceService.countByStatus(MIGRATION_REQUIRED)); + filesInStatus.put(DOCUMENT_FILES_MIGRATED, saasMigrationStatusPersistenceService.countByStatus(DOCUMENT_FILES_MIGRATED)); + filesInStatus.put(REDACTION_LOGS_MIGRATED, saasMigrationStatusPersistenceService.countByStatus(REDACTION_LOGS_MIGRATED)); + filesInStatus.put(ANNOTATION_IDS_MIGRATED, saasMigrationStatusPersistenceService.countByStatus(ANNOTATION_IDS_MIGRATED)); + filesInStatus.put(FINISHED, saasMigrationStatusPersistenceService.countByStatus(FINISHED)); + filesInStatus.put(ERROR, saasMigrationStatusPersistenceService.countByStatus(ERROR)); + + var filesInErrorState = saasMigrationStatusPersistenceService.findAllByStatus(ERROR); + + Map errorCauses = new HashMap<>(); + filesInErrorState.forEach(errorFile -> { + errorCauses.put(errorFile.getFileId(), errorFile.getErrorCause()); + }); + + return MigrationStatusResponse.builder() + .numberOfFilesToMigrate(numberOfFilesToMigrate) + .filesInStatus(filesInStatus) + .errorCauses(errorCauses) + .build(); + } +} diff --git a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/MigrationStatusResource.java b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/MigrationStatusResource.java new file mode 100644 index 000000000..a46bc2e81 --- /dev/null +++ b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/MigrationStatusResource.java @@ -0,0 +1,23 @@ +package com.iqser.red.service.persistence.service.v1.api.external.resource; + +import com.iqser.red.service.persistence.service.v1.api.shared.model.saas.migration.MigrationStatusResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +public interface MigrationStatusResource { + + String MIGRATION_STATUS_REST_PATH = ExternalApi.BASE_PATH + "/migration-status"; + + + @ResponseBody + @PostMapping(value = MIGRATION_STATUS_REST_PATH, produces = MediaType.APPLICATION_JSON_VALUE) + @Operation(summary = "Show the status of the migration", description = "None") + @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Success.")}) + MigrationStatusResponse migrationStatus(); + + +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/configuration/MessagingConfiguration.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/configuration/MessagingConfiguration.java index 2d6bc486e..2d6d113c8 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/configuration/MessagingConfiguration.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/configuration/MessagingConfiguration.java @@ -65,6 +65,35 @@ public class MessagingConfiguration { public static final String X_ERROR_INFO_HEADER = "x-error-message"; public static final String X_ERROR_INFO_TIMESTAMP_HEADER = "x-error-message-timestamp"; + // --- Saas Migration, can be removed later ---- + + public static final String MIGRATION_QUEUE = "migrationQueue"; + public static final String MIGRATION_DLQ = "migrationDLQ"; + public static final String MIGRATION_RESPONSE_QUEUE = "migrationResponseQueue"; + + + @Bean + public Queue migrationQueue() { + + return QueueBuilder.durable(MIGRATION_QUEUE).withArgument("x-dead-letter-exchange", "").withArgument("x-dead-letter-routing-key", MIGRATION_DLQ).maxPriority(2).build(); + } + + + @Bean + public Queue migrationDLQ() { + + return QueueBuilder.durable(MIGRATION_DLQ).build(); + } + + + @Bean + public Queue migrationResponseQueue() { + + return QueueBuilder.durable(MIGRATION_RESPONSE_QUEUE).withArgument("x-dead-letter-exchange", "").withArgument("x-dead-letter-routing-key", MIGRATION_DLQ).maxPriority(2).build(); + } + + // --- End Saas Migration + @Bean public Queue nerRequestQueue() { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/migration/SaasMigrationStatusEntity.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/migration/SaasMigrationStatusEntity.java new file mode 100644 index 000000000..e0b660f02 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/migration/SaasMigrationStatusEntity.java @@ -0,0 +1,34 @@ +package com.iqser.red.service.persistence.management.v1.processor.entity.migration; + +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.SaasMigrationStatus; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Entity +@Table(name = "saas_migration_status") +public class SaasMigrationStatusEntity { + + @Id + private String fileId; + + @Column + private String dossierId; + + @Column + @Enumerated(EnumType.STRING) + private SaasMigrationStatus status; + + @Column + private Integer processingErrorCounter; + + @Column + private String errorCause; + +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/SaasAnnotationIdMigrationService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/SaasAnnotationIdMigrationService.java new file mode 100644 index 000000000..67bd1dbdf --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/SaasAnnotationIdMigrationService.java @@ -0,0 +1,152 @@ +package com.iqser.red.service.persistence.management.v1.processor.migration; + +import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.*; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.CommentRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.FileRepository; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.annotationentity.*; +import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +@Slf4j +@Service +@RequiredArgsConstructor +public class SaasAnnotationIdMigrationService { + + private final ManualRedactionRepository manualRedactionRepository; + private final RemoveRedactionRepository removeRedactionRepository; + private final ForceRedactionRepository forceRedactionRepository; + private final ResizeRedactionRepository resizeRedactionRepository; + private final RecategorizationRepository recategorizationRepository; + private final LegalBasisChangeRepository legalBasisChangeRepository; + private final CommentRepository commentRepository; + private final FileRepository fileRepository; + + + @Transactional + public void updateAnnotationIds(String fileId, Map oldToNewMapping) { + + AtomicInteger numUpdates = new AtomicInteger(0); + AtomicInteger numCommentUpdates = new AtomicInteger(0); + oldToNewMapping.forEach((key, value) -> { + AnnotationEntityId oldAnnotationEntityId = buildAnnotationId(fileId, key); + AnnotationEntityId newAnnotationEntityId = buildAnnotationId(fileId, value); + numUpdates.getAndAdd(updateManualAddRedaction(oldAnnotationEntityId, newAnnotationEntityId)); + numUpdates.getAndAdd(updateRemoveRedaction(oldAnnotationEntityId, newAnnotationEntityId)); + numUpdates.getAndAdd(updateForceRedaction(oldAnnotationEntityId, newAnnotationEntityId)); + numUpdates.getAndAdd(updateResizeRedaction(oldAnnotationEntityId, newAnnotationEntityId)); + numUpdates.getAndAdd(updateRecategorizationRedaction(oldAnnotationEntityId, newAnnotationEntityId)); + numUpdates.getAndAdd(updateLegalBasisChangeRedaction(oldAnnotationEntityId, newAnnotationEntityId)); + numCommentUpdates.getAndAdd(commentRepository.saasMigrationUpdateAnnotationIds(fileId, key, value)); + }); + log.info("Migrated {} annotationIds and {} comments for file {}", numUpdates.get(), numCommentUpdates, fileId); + } + + private int updateManualAddRedaction(AnnotationEntityId oldAnnotationEntityId, AnnotationEntityId newAnnotationEntityId) { + var oldEntry = manualRedactionRepository.findById(oldAnnotationEntityId); + if (oldEntry.isPresent()) { + + var newEntry = MagicConverter.convert(oldEntry.get(), ManualRedactionEntryEntity.class); + newEntry.setPositions(MagicConverter.convert(oldEntry.get().getPositions(), RectangleEntity.class)); + newEntry.setFileStatus(fileRepository.findById(oldAnnotationEntityId.getFileId()).get()); + newEntry.setId(newAnnotationEntityId); + + manualRedactionRepository.save(newEntry); + manualRedactionRepository.deleteById(oldAnnotationEntityId); + return 1; + } + return 0; + } + + + private int updateRemoveRedaction(AnnotationEntityId oldAnnotationEntityId, AnnotationEntityId newAnnotationEntityId) { + var oldEntry = removeRedactionRepository.findById(oldAnnotationEntityId); + if (oldEntry.isPresent()) { + + var newEntry = MagicConverter.convert(oldEntry.get(), IdRemovalEntity.class); + newEntry.setFileStatus(fileRepository.findById(oldAnnotationEntityId.getFileId()).get()); + newEntry.setId(newAnnotationEntityId); + + removeRedactionRepository.save(newEntry); + removeRedactionRepository.deleteById(oldAnnotationEntityId); + return 1; + } + return 0; + } + + + private int updateForceRedaction(AnnotationEntityId oldAnnotationEntityId, AnnotationEntityId newAnnotationEntityId) { + var oldEntry = forceRedactionRepository.findById(oldAnnotationEntityId); + if (oldEntry.isPresent()) { + + var newEntry = MagicConverter.convert(oldEntry.get(), ManualForceRedactionEntity.class); + newEntry.setFileStatus(fileRepository.findById(oldAnnotationEntityId.getFileId()).get()); + newEntry.setId(newAnnotationEntityId); + + forceRedactionRepository.save(newEntry); + forceRedactionRepository.deleteById(oldAnnotationEntityId); + return 1; + } + return 0; + } + + + private int updateResizeRedaction(AnnotationEntityId oldAnnotationEntityId, AnnotationEntityId newAnnotationEntityId) { + var oldEntry = resizeRedactionRepository.findById(oldAnnotationEntityId); + if (oldEntry.isPresent()) { + + var newEntry = MagicConverter.convert(oldEntry.get(), ManualResizeRedactionEntity.class); + newEntry.setId(newAnnotationEntityId); + newEntry.setPositions(MagicConverter.convert(oldEntry.get().getPositions(), RectangleEntity.class)); + newEntry.setFileStatus(fileRepository.findById(oldAnnotationEntityId.getFileId()).get()); + + resizeRedactionRepository.save(newEntry); + resizeRedactionRepository.deleteById(oldAnnotationEntityId); + return 1; + } + return 0; + } + + + private int updateRecategorizationRedaction(AnnotationEntityId oldAnnotationEntityId, AnnotationEntityId newAnnotationEntityId) { + var oldEntry = recategorizationRepository.findById(oldAnnotationEntityId); + if (oldEntry.isPresent()) { + + var newEntry = MagicConverter.convert(oldEntry.get(), ManualRecategorizationEntity.class); + newEntry.setId(newAnnotationEntityId); + newEntry.setFileStatus(fileRepository.findById(oldAnnotationEntityId.getFileId()).get()); + + recategorizationRepository.save(newEntry); + recategorizationRepository.deleteById(oldAnnotationEntityId); + return 1; + } + return 0; + } + + + private int updateLegalBasisChangeRedaction(AnnotationEntityId oldAnnotationEntityId, AnnotationEntityId newAnnotationEntityId) { + var oldEntry = legalBasisChangeRepository.findById(oldAnnotationEntityId); + if (oldEntry.isPresent()) { + + var newEntry = MagicConverter.convert(oldEntry.get(), ManualLegalBasisChangeEntity.class); + newEntry.setId(newAnnotationEntityId); + newEntry.setFileStatus(fileRepository.findById(oldAnnotationEntityId.getFileId()).get()); + + legalBasisChangeRepository.save(newEntry); + legalBasisChangeRepository.deleteById(oldAnnotationEntityId); + return 1; + } + return 0; + } + + + private AnnotationEntityId buildAnnotationId(String fileId, String annotationId) { + return AnnotationEntityId.builder().fileId(fileId).annotationId(annotationId).build(); + } + +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/SaasMigrationService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/SaasMigrationService.java new file mode 100644 index 000000000..0b4335c44 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/migration/SaasMigrationService.java @@ -0,0 +1,141 @@ +package com.iqser.red.service.persistence.management.v1.processor.migration; + +import com.iqser.red.service.persistence.management.v1.processor.exception.InternalServerErrorException; +import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; +import com.iqser.red.service.persistence.management.v1.processor.service.DossierService; +import com.iqser.red.service.persistence.management.v1.processor.service.job.AutomaticAnalysisJob; +import com.iqser.red.service.persistence.management.v1.processor.service.layoutparsing.LayoutParsingRequestFactory; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileStatusPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.SaasMigrationStatusPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.settings.FileManagementServiceSettings; +import com.iqser.red.service.persistence.management.v1.processor.utils.StorageIdUtils; +import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.migration.MigratedIds; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.SaasMigrationStatus; +import com.iqser.red.service.redaction.v1.model.MigrationRequest; +import com.iqser.red.storage.commons.exception.StorageException; +import com.iqser.red.storage.commons.exception.StorageObjectDoesNotExist; +import com.iqser.red.storage.commons.service.StorageService; +import com.knecon.fforesight.tenantcommons.TenantContext; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.stereotype.Service; + +import java.util.Map; + +import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.MIGRATION_QUEUE; +import static com.knecon.fforesight.service.layoutparser.internal.api.queue.LayoutParsingQueueNames.LAYOUT_PARSING_REQUEST_QUEUE; + +@Slf4j +@Service +@RequiredArgsConstructor +public class SaasMigrationService { + + private final AutomaticAnalysisJob automaticAnalysisJob; + private final FileStatusPersistenceService fileStatusPersistenceService; + private final SaasMigrationStatusPersistenceService saasMigrationStatusPersistenceService; + private final DossierService dossierService; + + private final LayoutParsingRequestFactory layoutParsingRequestFactory; + private final RabbitTemplate rabbitTemplate; + private final FileManagementServiceSettings settings; + private final StorageService storageService; + + + private final SaasAnnotationIdMigrationService saasAnnotationIdMigrationService; + + // Persistence-Service needs to be scaled to 1. + + public void startMigrationForTenant(String tenantId) { + + // TODO migrate rules. + + automaticAnalysisJob.stopForTenant(tenantId); + + int numberOfFiles = 0; + var dossiers = dossierService.getAllDossiers().stream().filter(dossier -> dossier.getHardDeletedTime() == null).toList(); + for (var dossier : dossiers) { + var files = fileStatusPersistenceService.getStatusesForDossier(dossier.getId()).stream().filter(file -> file.getHardDeletedTime() == null).toList(); + for (var file : files) { + saasMigrationStatusPersistenceService.createMigrationRequiredStatus(dossier.getId(), file.getId()); + var layoutParsingRequest = layoutParsingRequestFactory.build(dossier.getId(), file.getId(), false); + rabbitTemplate.convertAndSend(LAYOUT_PARSING_REQUEST_QUEUE, layoutParsingRequest); + numberOfFiles++; + } + } + + log.info("Added {} for tenant {} to Layout-Parsing queue for saas migration", numberOfFiles, TenantContext.getTenantId()); + } + + + public void handleLayoutParsingFinished(String dossierId, String fileId) { + saasMigrationStatusPersistenceService.updateStatus(fileId, SaasMigrationStatus.DOCUMENT_FILES_MIGRATED); + rabbitTemplate.convertAndSend(MIGRATION_QUEUE, MigrationRequest.builder() + .dossierId(dossierId) + .fileId(fileId) + .build()); + + log.info("Layout Parsing finished for saas migration for tenant {} dossier {} and file {}", TenantContext.getTenantId(), dossierId, fileId); + } + + + public void handleEntityLogMigrationFinished(String dossierId, String fileId) { + saasMigrationStatusPersistenceService.updateStatus(fileId, SaasMigrationStatus.REDACTION_LOGS_MIGRATED); + + log.info("EntityLog migration finished for saas migration for tenant {} dossier {} and file {}", TenantContext.getTenantId(), dossierId, fileId); + migrateAnnotationIds(dossierId, fileId); + } + + + public void handleError(String dossierId, String fileId, String errorCause, String retryQueue) { + var migrationEntry = saasMigrationStatusPersistenceService.findById(fileId); + int numErrors = migrationEntry.getProcessingErrorCounter(); + if (numErrors <= settings.getMaxErrorRetries()) { + saasMigrationStatusPersistenceService.updateErrorCounter(fileId, numErrors + 1, errorCause); + rabbitTemplate.convertAndSend(retryQueue, MigrationRequest.builder() + .dossierId(dossierId) + .fileId(fileId) + .build()); + log.error("Retrying error during saas migration for tenant {} dossier {} and file {}, cause {}", TenantContext.getTenantId(), dossierId, fileId, errorCause); + } else { + saasMigrationStatusPersistenceService.updateErrorStatus(fileId, errorCause); + log.error("Error during saas migration for tenant {} dossier {} and file {}, cause {}", TenantContext.getTenantId(), dossierId, fileId, errorCause); + } + } + + + private void migrateAnnotationIds(String dossierId, String fileId) { + + MigratedIds migratedIds = getMigratedIds(dossierId, fileId); + Map oldToNewMapping = migratedIds.buildOldToNewMapping(); + try { + saasAnnotationIdMigrationService.updateAnnotationIds(fileId, oldToNewMapping); + } catch (Exception e) { + saasMigrationStatusPersistenceService.updateErrorStatus(fileId, e.getMessage()); + log.error("Error during saas migration for tenant {} dossier {} and file {}, cause {}", TenantContext.getTenantId(), dossierId, fileId, e.getMessage()); + throw e; + } + saasMigrationStatusPersistenceService.updateStatus(fileId, SaasMigrationStatus.FINISHED); + + log.info("AnnotationIds migration finished for saas migration for tenant {} dossier {} and file {}", TenantContext.getTenantId(), dossierId, fileId); + if (saasMigrationStatusPersistenceService.countByStatus(SaasMigrationStatus.FINISHED) == saasMigrationStatusPersistenceService.countAll()) { + automaticAnalysisJob.startForTenant(TenantContext.getTenantId()); + log.info("Saas migration finished for tenantId {}, re-enabled scheduler", TenantContext.getTenantId()); + } + } + + + private MigratedIds getMigratedIds(String dossierId, String fileId) { + + try { + return storageService.readJSONObject(TenantContext.getTenantId(), StorageIdUtils.getStorageId(dossierId, fileId, FileType.MIGRATED_IDS), MigratedIds.class); + } catch (StorageObjectDoesNotExist e) { + throw new NotFoundException(String.format("MigratedIds does not exist for Dossier ID \"%s\" and File ID \"%s\"!", dossierId, fileId)); + } catch (StorageException e) { + throw new InternalServerErrorException(e.getMessage()); + } + } + + +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java index 474fdfcb1..74cd03b42 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileStatusService.java @@ -186,7 +186,7 @@ public class FileStatusService { } if (!fileManagementStorageService.objectExists(dossierId, fileId, FileType.DOCUMENT_TEXT)) { - var layoutParsingRequest = layoutParsingRequestFactory.build(dossierId, fileId, priority, dossier); + var layoutParsingRequest = layoutParsingRequestFactory.build(dossierId, fileId, priority); setStatusFullProcessing(fileId); rabbitTemplate.convertAndSend(LAYOUT_PARSING_REQUEST_QUEUE, layoutParsingRequest); return; diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/job/AutomaticAnalysisJob.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/job/AutomaticAnalysisJob.java index 32a7e3313..3abb8fef3 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/job/AutomaticAnalysisJob.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/job/AutomaticAnalysisJob.java @@ -1,7 +1,9 @@ package com.iqser.red.service.persistence.management.v1.processor.service.job; import java.util.Comparator; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.quartz.Job; import org.quartz.JobExecutionContext; @@ -34,6 +36,8 @@ public class AutomaticAnalysisJob implements Job { @Setter private boolean schedulingStopped; + private Set stoppedTenants = new HashSet<>(); + @Override public void execute(JobExecutionContext jobExecutionContext) { @@ -45,7 +49,7 @@ public class AutomaticAnalysisJob implements Job { tenantProvider.getTenants().forEach(tenant -> { - if (!TenantUtils.isTenantReadyForPersistence(tenant)) { + if (!TenantUtils.isTenantReadyForPersistence(tenant) || stoppedTenants.contains(tenant.getTenantId())) { return; } @@ -100,4 +104,13 @@ public class AutomaticAnalysisJob implements Job { return fileStatusService.getAllRelevantStatusesForReanalysisScheduler(); } + + public void stopForTenant(String tenantId){ + stoppedTenants.add(tenantId); + } + + public void startForTenant(String tenantId){ + stoppedTenants.remove(tenantId); + } + } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/layoutparsing/LayoutParsingRequestFactory.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/layoutparsing/LayoutParsingRequestFactory.java index 76785a0b0..796db6f24 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/layoutparsing/LayoutParsingRequestFactory.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/layoutparsing/LayoutParsingRequestFactory.java @@ -25,7 +25,7 @@ public class LayoutParsingRequestFactory { private final LayoutParsingRequestIdentifierService layoutParsingRequestIdentifierService; - public LayoutParsingRequest build(String dossierId, String fileId, boolean priority, DossierEntity dossier) { + public LayoutParsingRequest build(String dossierId, String fileId, boolean priority) { LayoutParsingType type = switch (applicationType) { case "DocuMine" -> LayoutParsingType.DOCUMINE; diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/SaasMigrationStatusPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/SaasMigrationStatusPersistenceService.java new file mode 100644 index 000000000..e49895a98 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/SaasMigrationStatusPersistenceService.java @@ -0,0 +1,69 @@ +package com.iqser.red.service.persistence.management.v1.processor.service.persistence; + +import com.iqser.red.service.persistence.management.v1.processor.entity.migration.SaasMigrationStatusEntity; +import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.SaasMigrationStatusRepository; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.SaasMigrationStatus; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + + +@Service +@RequiredArgsConstructor +public class SaasMigrationStatusPersistenceService { + + private final SaasMigrationStatusRepository saasMigrationStatusRepository; + + public List findAllByStatus(SaasMigrationStatus status) { + return saasMigrationStatusRepository.findAllByStatus(status); + } + + public SaasMigrationStatusEntity findById(String fileId) { + + var migrationStatusOptional = saasMigrationStatusRepository.findById(fileId); + if (migrationStatusOptional.isPresent()) { + return migrationStatusOptional.get(); + } + throw new NotFoundException("No migration entry found for fileId" + fileId); + } + + public boolean isMigrating(String fileId) { + var migrationStatusOptional = saasMigrationStatusRepository.findById(fileId); + return migrationStatusOptional.isPresent() && migrationStatusOptional.get().getStatus() != SaasMigrationStatus.FINISHED; + } + + @Transactional + public void createMigrationRequiredStatus(String dossierId, String fileId) { + saasMigrationStatusRepository.save(SaasMigrationStatusEntity.builder() + .fileId(fileId) + .dossierId(dossierId) + .status(SaasMigrationStatus.MIGRATION_REQUIRED) + .build()); + } + + @Transactional + public void updateStatus(String fileId, SaasMigrationStatus status) { + saasMigrationStatusRepository.updateStatus(fileId, status); + } + + @Transactional + public void updateErrorStatus(String fileId, String errorCause) { + saasMigrationStatusRepository.updateErrorStatus(fileId, SaasMigrationStatus.ERROR, errorCause); + } + + @Transactional + public void updateErrorCounter(String fileId, Integer processingErrorCounter, String errorCause) { + saasMigrationStatusRepository.updateErrorCounter(fileId, processingErrorCounter, errorCause); + } + + public int countByStatus(SaasMigrationStatus status) { + return saasMigrationStatusRepository.countByStatus(status); + } + + public int countAll() { + return saasMigrationStatusRepository.countAll(); + } +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/CommentRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/CommentRepository.java index 19f0f264b..4c60bc891 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/CommentRepository.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/CommentRepository.java @@ -26,4 +26,8 @@ public interface CommentRepository extends JpaRepository { @Query("update CommentEntity c set c.softDeletedTime = :softDeleteTime where c.id = :id") int updateSoftDelete(long id, OffsetDateTime softDeleteTime); + @Modifying + @Query("update CommentEntity c set c.annotationId = :newAnnotationId where c.annotationId = :oldAnnotationId and c.fileId = :fileId") + int saasMigrationUpdateAnnotationIds(String fileId, String oldAnnotationId, String newAnnotationId); + } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/SaasMigrationStatusRepository.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/SaasMigrationStatusRepository.java new file mode 100644 index 000000000..26f9cf5f2 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/repository/SaasMigrationStatusRepository.java @@ -0,0 +1,33 @@ +package com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository; + +import com.iqser.red.service.persistence.management.v1.processor.entity.migration.SaasMigrationStatusEntity; +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.SaasMigrationStatus; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; + +import java.util.List; + +public interface SaasMigrationStatusRepository extends JpaRepository { + + List findAllByStatus(SaasMigrationStatus status); + + @Modifying + @Query("update SaasMigrationStatusEntity e set e.status = :status where e.fileId = :fileId") + void updateStatus(String fileId, SaasMigrationStatus status); + + @Modifying + @Query("update SaasMigrationStatusEntity e set e.status = :status, e.errorCause = :errorCause where e.fileId = :fileId") + void updateErrorStatus(String fileId, SaasMigrationStatus status, String errorCause); + + @Modifying + @Query("update SaasMigrationStatusEntity e set e.processingErrorCounter = :processingErrorCounter, e.errorCause = :errorCause where e.fileId = :fileId") + void updateErrorCounter(String fileId, Integer processingErrorCounter, String errorCause); + + @Query("select count(*) from SaasMigrationStatusEntity e where e.status = :status") + int countByStatus(SaasMigrationStatus status); + + @Query("select count(*) from SaasMigrationStatusEntity") + int countAll(); + +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/LayoutParsingFinishedMessageReceiver.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/LayoutParsingFinishedMessageReceiver.java index 5a0bb92c2..fb43103a4 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/LayoutParsingFinishedMessageReceiver.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/LayoutParsingFinishedMessageReceiver.java @@ -1,25 +1,25 @@ package com.iqser.red.service.persistence.management.v1.processor.service.queue; -import java.time.OffsetDateTime; -import java.time.temporal.ChronoUnit; - -import org.springframework.amqp.core.Message; -import org.springframework.amqp.rabbit.annotation.RabbitListener; -import org.springframework.stereotype.Service; - import com.fasterxml.jackson.databind.ObjectMapper; import com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration; +import com.iqser.red.service.persistence.management.v1.processor.migration.SaasMigrationService; import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusProcessingUpdateService; import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService; import com.iqser.red.service.persistence.management.v1.processor.service.layoutparsing.LayoutParsingRequestIdentifierService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.SaasMigrationStatusPersistenceService; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileErrorInfo; import com.knecon.fforesight.service.layoutparser.internal.api.queue.LayoutParsingFinishedEvent; import com.knecon.fforesight.service.layoutparser.internal.api.queue.LayoutParsingQueueNames; import com.knecon.fforesight.service.layoutparser.internal.api.queue.LayoutParsingRequest; - import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.stereotype.Service; + +import java.time.OffsetDateTime; +import java.time.temporal.ChronoUnit; @Slf4j @Service @@ -30,12 +30,20 @@ public class LayoutParsingFinishedMessageReceiver { private final FileStatusProcessingUpdateService fileStatusProcessingUpdateService; private final ObjectMapper objectMapper; private final LayoutParsingRequestIdentifierService layoutParsingRequestIdentifierService; + private final SaasMigrationStatusPersistenceService saasMigrationStatusPersistenceService; + private final SaasMigrationService saasMigrationService; @SneakyThrows @RabbitListener(queues = LayoutParsingQueueNames.LAYOUT_PARSING_FINISHED_EVENT_QUEUE) public void receive(LayoutParsingFinishedEvent response) { + if (saasMigrationStatusPersistenceService.isMigrating(layoutParsingRequestIdentifierService.parseFileId(response.identifier()))) { + saasMigrationService.handleLayoutParsingFinished(layoutParsingRequestIdentifierService.parseDossierId(response.identifier()), + layoutParsingRequestIdentifierService.parseFileId(response.identifier())); + return; + } + fileStatusService.setStatusAnalyse(layoutParsingRequestIdentifierService.parseDossierId(response.identifier()), layoutParsingRequestIdentifierService.parseFileId(response.identifier()), layoutParsingRequestIdentifierService.parsePriority(response.identifier())); @@ -53,6 +61,13 @@ public class LayoutParsingFinishedMessageReceiver { var analyzeRequest = objectMapper.readValue(failedMessage.getBody(), LayoutParsingRequest.class); log.info("Failed to process analyze request: {}", analyzeRequest); String errorCause = failedMessage.getMessageProperties().getHeader(MessagingConfiguration.X_ERROR_INFO_HEADER); + + if (saasMigrationStatusPersistenceService.isMigrating(layoutParsingRequestIdentifierService.parseFileId(analyzeRequest.identifier()))) { + saasMigrationService.handleError(layoutParsingRequestIdentifierService.parseDossierId(analyzeRequest.identifier()), + layoutParsingRequestIdentifierService.parseFileId(analyzeRequest.identifier()), errorCause, LayoutParsingQueueNames.LAYOUT_PARSING_REQUEST_QUEUE); + return; + } + OffsetDateTime timestamp = failedMessage.getMessageProperties().getHeader(MessagingConfiguration.X_ERROR_INFO_TIMESTAMP_HEADER); timestamp = timestamp != null ? timestamp : OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS); log.info("Failed to process layout parsing request, errorCause: {}, timestamp: {}", errorCause, timestamp); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/RedactionServiceSaasMigrationMessageReceiver.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/RedactionServiceSaasMigrationMessageReceiver.java new file mode 100644 index 000000000..a4ee11967 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/RedactionServiceSaasMigrationMessageReceiver.java @@ -0,0 +1,45 @@ +package com.iqser.red.service.persistence.management.v1.processor.service.queue; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration; +import com.iqser.red.service.persistence.management.v1.processor.migration.SaasMigrationService; +import com.iqser.red.service.redaction.v1.model.MigrationRequest; +import com.iqser.red.service.redaction.v1.model.MigrationResponse; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.stereotype.Service; + +import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.*; + +@Slf4j +@Service +@RequiredArgsConstructor +public class RedactionServiceSaasMigrationMessageReceiver { + + private final SaasMigrationService saasMigrationService; + private final ObjectMapper objectMapper; + + @SneakyThrows + @RabbitListener(queues = MIGRATION_RESPONSE_QUEUE) + public void receive(MigrationResponse response) { + + saasMigrationService.handleEntityLogMigrationFinished(response.getDossierId(), response.getFileId()); + + log.info("Received message {} in {}", response, MIGRATION_RESPONSE_QUEUE); + } + + + @SneakyThrows + @RabbitListener(queues = MIGRATION_DLQ) + public void handleDLQMessage(Message failedMessage) { + + var migrationRequest = objectMapper.readValue(failedMessage.getBody(), MigrationRequest.class); + String errorCause = failedMessage.getMessageProperties().getHeader(MessagingConfiguration.X_ERROR_INFO_HEADER); + saasMigrationService.handleError(migrationRequest.getDossierId(), migrationRequest.getFileId(), errorCause, MIGRATION_QUEUE); + + } + +} diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/db.changelog-tenant.yaml b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/db.changelog-tenant.yaml index 3992cf973..fabc20128 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/db.changelog-tenant.yaml +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/db.changelog-tenant.yaml @@ -166,4 +166,6 @@ databaseChangeLog: - include: file: db/changelog/tenant/112-modify-section-length.yaml - include: - file: db/changelog/tenant/114-add-download-redaction-file-status-table.yaml \ No newline at end of file + file: db/changelog/tenant/114-add-download-redaction-file-status-table.yaml + - include: + file: db/changelog/tenant/115-add-saas-migration-status-table.yaml \ No newline at end of file diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/115-add-saas-migration-status-table.yaml b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/115-add-saas-migration-status-table.yaml new file mode 100644 index 000000000..250758013 --- /dev/null +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/resources/db/changelog/tenant/115-add-saas-migration-status-table.yaml @@ -0,0 +1,28 @@ +databaseChangeLog: + - changeSet: + id: add-saas-migration-status-table + author: dom + changes: + - createTable: + columns: + - column: + constraints: + nullable: false + primaryKey: true + primaryKeyName: add-saas-migration-status-table_pkey + name: file_id + type: VARCHAR(255) + - column: + name: dossier_id + type: VARCHAR(255) + - column: + name: status + type: VARCHAR(255) + - column: + name: processing_error_counter + type: INTEGER + - column: + name: error_cause + type: VARCHAR(1024) + tableName: saas_migration_status + diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/SaasMigrationStatus.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/SaasMigrationStatus.java new file mode 100644 index 000000000..1ce683e0a --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/dossiertemplate/dossier/file/SaasMigrationStatus.java @@ -0,0 +1,10 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file; + +public enum SaasMigrationStatus { + MIGRATION_REQUIRED, + DOCUMENT_FILES_MIGRATED, + REDACTION_LOGS_MIGRATED, + ANNOTATION_IDS_MIGRATED, + FINISHED, + ERROR +} diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/saas/migration/MigrationStatusResponse.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/saas/migration/MigrationStatusResponse.java new file mode 100644 index 000000000..ec3b28ea6 --- /dev/null +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/saas/migration/MigrationStatusResponse.java @@ -0,0 +1,21 @@ +package com.iqser.red.service.persistence.service.v1.api.shared.model.saas.migration; + +import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.SaasMigrationStatus; +import lombok.*; + +import java.util.HashMap; +import java.util.Map; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class MigrationStatusResponse { + + private Integer numberOfFilesToMigrate; + @Builder.Default + private Map filesInStatus = new HashMap<>(); + @Builder.Default + private Map errorCauses = new HashMap<>(); + +} diff --git a/persistence-service-v1/pom.xml b/persistence-service-v1/pom.xml index 51a38b5ce..1625a1844 100755 --- a/persistence-service-v1/pom.xml +++ b/persistence-service-v1/pom.xml @@ -31,7 +31,7 @@ - 4.157.0 + 4.165.0 2.71.0 4.29.0 4.13.0 -- 2.47.2 From c1418d30dc22abe7057e6330dee79f70e3b99ede Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Mon, 6 Nov 2023 15:36:32 +0100 Subject: [PATCH 55/96] hotfix: fix component sorting --- .../controller/ComponentControllerV2.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/ComponentControllerV2.java b/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/ComponentControllerV2.java index 39705d9ab..fb43e5049 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/ComponentControllerV2.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/ComponentControllerV2.java @@ -4,10 +4,9 @@ import static com.iqser.red.service.persistence.service.v2.api.external.resource import static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierTemplateResource.DOSSIER_TEMPLATE_ID_PARAM; import static com.iqser.red.service.persistence.service.v2.api.external.resource.FileResource.FILE_ID_PARAM; -import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; @@ -53,17 +52,16 @@ public class ComponentControllerV2 implements ComponentResource { dossierTemplateController.getDossierTemplate(dossierTemplateId); var componentLog = componentLogService.getComponentLog(dossierId, fileId, true); - Map> basicComponent = componentLog.getComponentLogEntries() - .stream() - .collect(Collectors.toMap(ComponentLogEntry::getName, - componentLogEntry -> componentLogEntry.getComponentValues().stream().map(ComponentLogEntryValue::getValue).toList())); - - Map componentsDetails = Collections.emptyMap(); + Map> basicComponent = new LinkedHashMap<>(); + for (ComponentLogEntry componentLogEntry : componentLog.getComponentLogEntries()) { + basicComponent.put(componentLogEntry.getName(), componentLogEntry.getComponentValues().stream().map(ComponentLogEntryValue::getValue).toList()); + } + Map componentsDetails = new LinkedHashMap<>(); if (includeDetails) { - componentsDetails = componentLog.getComponentLogEntries() - .stream() - .collect(Collectors.toMap(ComponentLogEntry::getName, entry -> Component.builder().name(entry.getName()).componentValues(toComponentList(entry)).build())); + for (ComponentLogEntry entry : componentLog.getComponentLogEntries()) { + componentsDetails.put(entry.getName(), Component.builder().name(entry.getName()).componentValues(toComponentList(entry)).build()); + } } return FileComponents.builder() -- 2.47.2 From 93bbdd768ddd7621b23db83e0384e15adb28066a Mon Sep 17 00:00:00 2001 From: Andrei Isvoran Date: Tue, 7 Nov 2023 11:50:32 +0100 Subject: [PATCH 56/96] RED-7784 - Report with unprocessed redactions --- .../api/impl/controller/DownloadController.java | 8 +++++++- .../api/controller/EntityLogInternalController.java | 2 +- .../v1/api/internal/resources/EntityLogResource.java | 11 +++-------- .../management/v1/processor/model/DownloadJob.java | 1 + .../v1/processor/service/DownloadService.java | 3 ++- .../service/download/DownloadProcessorService.java | 1 + .../server/integration/tests/DossierTemplateTest.java | 2 +- .../v1/server/integration/tests/DownloadTest.java | 2 +- .../v1/api/shared/model/PrepareDownloadRequest.java | 1 + .../model/PrepareDownloadWithOptionRequest.java | 1 + .../v1/api/shared/model/download/DownloadRequest.java | 1 + .../model/download/DownloadWithOptionRequest.java | 1 + persistence-service-v1/pom.xml | 2 +- 13 files changed, 22 insertions(+), 14 deletions(-) diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/DownloadController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/DownloadController.java index f62218c83..e8b4e62b9 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/DownloadController.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/DownloadController.java @@ -174,6 +174,7 @@ public class DownloadController implements DownloadResource { .downloadFileTypes(request.getDownloadFileTypes()) .reportTemplateIds(request.getReportTemplateIds()) .redactionPreviewColor(request.getRedactionPreviewColor()) + .includeUnprocessed(request.isIncludeUnprocessed()) .build(); } @@ -298,7 +299,12 @@ public class DownloadController implements DownloadResource { private DownloadRequest convert(PrepareDownloadRequest request) { - return DownloadRequest.builder().dossierId(request.getDossierId()).userId(KeycloakSecurity.getUserId()).fileIds(request.getFileIds()).build(); + return DownloadRequest.builder() + .dossierId(request.getDossierId()) + .userId(KeycloakSecurity.getUserId()) + .fileIds(request.getFileIds()) + .includeUnprocessed(request.isIncludeUnprocessed()) + .build(); } diff --git a/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/EntityLogInternalController.java b/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/EntityLogInternalController.java index 0dd4d4fbb..3b1316034 100644 --- a/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/EntityLogInternalController.java +++ b/persistence-service-v1/persistence-service-internal-api-impl-v1/src/main/java/com/iqser/red/service/persistence/v1/internal/api/controller/EntityLogInternalController.java @@ -18,7 +18,7 @@ public class EntityLogInternalController implements EntityLogResource { private final EntityLogService entityLogService; - + @Override public EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestParam(value = "excludedType", required = false) List excludedTypes, diff --git a/persistence-service-v1/persistence-service-internal-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/internal/resources/EntityLogResource.java b/persistence-service-v1/persistence-service-internal-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/internal/resources/EntityLogResource.java index 1a7b7c23b..106dde48c 100644 --- a/persistence-service-v1/persistence-service-internal-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/internal/resources/EntityLogResource.java +++ b/persistence-service-v1/persistence-service-internal-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/internal/resources/EntityLogResource.java @@ -7,14 +7,11 @@ import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; - @ResponseStatus(value = HttpStatus.OK) public interface EntityLogResource { @@ -28,10 +25,8 @@ public interface EntityLogResource { String FALSE = "false"; - - @GetMapping(value = ENTITY_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE) - @Operation(summary = "Gets the entity log for a fileId", description = "None") - @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The entity log is not found.")}) + @ResponseBody + @GetMapping(value = InternalApi.BASE_PATH + ENTITY_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE) EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestParam(value = "excludedType", required = false) List excludedTypes, diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/DownloadJob.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/DownloadJob.java index 91fc5b18c..564855871 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/DownloadJob.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/model/DownloadJob.java @@ -14,5 +14,6 @@ public class DownloadJob { private String userId; private String storageId; + private boolean includeUnprocessed; } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DownloadService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DownloadService.java index e62c9d785..eea721ddb 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DownloadService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DownloadService.java @@ -61,6 +61,7 @@ public class DownloadService { .userId(request.getUserId()) .dossierId(request.getDossierId()) .fileIds(request.getFileIds()) + .includeUnprocessed(request.isIncludeUnprocessed()) .downloadFileTypes(dossier.getDownloadFileTypes()) .reportTemplateIds(dossier.getReportTemplates().stream().map(ReportTemplateEntity::getTemplateId).collect(Collectors.toList())) .build(); @@ -84,7 +85,7 @@ public class DownloadService { request.getDownloadFileTypes(), request.getReportTemplateIds(), request.getRedactionPreviewColor()); - addToDownloadQueue(DownloadJob.builder().storageId(storageId).userId(request.getUserId()).build(), 1); + addToDownloadQueue(DownloadJob.builder().storageId(storageId).userId(request.getUserId()).includeUnprocessed(request.isIncludeUnprocessed()).build(), 1); return new JSONPrimitive<>(storageId); } diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/DownloadProcessorService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/DownloadProcessorService.java index ae653b5a2..ea3bb5190 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/DownloadProcessorService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/DownloadProcessorService.java @@ -52,6 +52,7 @@ public class DownloadProcessorService { .downloadId(downloadJob.getStorageId()) .dossierId(dossier.getId()) .dossierTemplateId(dossierService.getDossierById(dossier.getId()).getDossierTemplateId()) + .includeUnprocessed(downloadJob.isIncludeUnprocessed()) .fileIds(filenameSortedFileIds) .templateIds(downloadStatus.getReports().stream().map(ReportTemplateEntity::getTemplateId).collect(Collectors.toSet())) .build(), 1); diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java index a17264fd7..01a0af423 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java @@ -521,7 +521,7 @@ public class DossierTemplateTest extends AbstractPersistenceServerServiceTest { assertThat(statuses.getDownloadStatus()).isNotEmpty(); var status = statuses.getDownloadStatus().iterator().next(); - exportDownloadReportMessageReceiver.receive(new DownloadJob(status.getUserId(), status.getStorageId())); + exportDownloadReportMessageReceiver.receive(new DownloadJob(status.getUserId(), status.getStorageId(), false)); // add new justifications legalBasisClient.setLegalBasisMapping(List.of(new LegalBasis("nameAgain", "description", "reason")), dossierTemplate.getId()); diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadTest.java index 436e026d0..7e928905a 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DownloadTest.java @@ -97,7 +97,7 @@ public class DownloadTest extends AbstractPersistenceServerServiceTest { .fileIds(List.of(file2.getId())) .build()); - downloadMessageReceiver.receive(new DownloadJob(userProvider.getUserId(), downloads.getStorageId())); + downloadMessageReceiver.receive(new DownloadJob(userProvider.getUserId(), downloads.getStorageId(), false)); var reportInfoId = downloads.getStorageId().substring(0, downloads.getStorageId().length() - 3) + "/REPORT_INFO.json"; storageService.storeJSONObject(TenantContext.getTenantId(), reportInfoId, new ArrayList<>()); diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/PrepareDownloadRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/PrepareDownloadRequest.java index 5c7abcc76..9ab7d08ab 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/PrepareDownloadRequest.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/PrepareDownloadRequest.java @@ -18,5 +18,6 @@ public class PrepareDownloadRequest { private String dossierId; private List fileIds; + private boolean includeUnprocessed; } diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/PrepareDownloadWithOptionRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/PrepareDownloadWithOptionRequest.java index 24206d209..1c9a78281 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/PrepareDownloadWithOptionRequest.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/PrepareDownloadWithOptionRequest.java @@ -28,5 +28,6 @@ public class PrepareDownloadWithOptionRequest { private List reportTemplateIds = new ArrayList<>(); private Set downloadFileTypes = new HashSet<>(); private String redactionPreviewColor; + private boolean includeUnprocessed ; } diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/download/DownloadRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/download/DownloadRequest.java index 0bcf7473a..dc87baaa5 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/download/DownloadRequest.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/download/DownloadRequest.java @@ -17,6 +17,7 @@ public class DownloadRequest { private String userId; private String dossierId; + private boolean includeUnprocessed; @Builder.Default private List fileIds = new ArrayList<>(); diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/download/DownloadWithOptionRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/download/DownloadWithOptionRequest.java index 8e11ef7fc..947f8ddeb 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/download/DownloadWithOptionRequest.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/download/DownloadWithOptionRequest.java @@ -21,6 +21,7 @@ public class DownloadWithOptionRequest { private String userId; private String dossierId; + private boolean includeUnprocessed; @Builder.Default private List fileIds = new ArrayList<>(); diff --git a/persistence-service-v1/pom.xml b/persistence-service-v1/pom.xml index 1625a1844..592b8be79 100755 --- a/persistence-service-v1/pom.xml +++ b/persistence-service-v1/pom.xml @@ -34,7 +34,7 @@ 4.165.0 2.71.0 4.29.0 - 4.13.0 + 4.30.0 3.10.0 2.45.0 -- 2.47.2 From e81e1eb000675be6a9eb99fbe0dea4ef4fbcc004 Mon Sep 17 00:00:00 2001 From: Andrei Isvoran Date: Tue, 7 Nov 2023 12:44:57 +0100 Subject: [PATCH 57/96] RED-7784 - Report with unprocessed redactions --- ...onServiceSaasMigrationMessageReceiver.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/RedactionServiceSaasMigrationMessageReceiver.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/RedactionServiceSaasMigrationMessageReceiver.java index a4ee11967..be3d50c6d 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/RedactionServiceSaasMigrationMessageReceiver.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/queue/RedactionServiceSaasMigrationMessageReceiver.java @@ -1,18 +1,22 @@ package com.iqser.red.service.persistence.management.v1.processor.service.queue; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration; -import com.iqser.red.service.persistence.management.v1.processor.migration.SaasMigrationService; -import com.iqser.red.service.redaction.v1.model.MigrationRequest; -import com.iqser.red.service.redaction.v1.model.MigrationResponse; -import lombok.RequiredArgsConstructor; -import lombok.SneakyThrows; -import lombok.extern.slf4j.Slf4j; +import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.MIGRATION_DLQ; +import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.MIGRATION_QUEUE; +import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.MIGRATION_RESPONSE_QUEUE; +import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.X_ERROR_INFO_HEADER; + import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Service; -import static com.iqser.red.service.persistence.management.v1.processor.configuration.MessagingConfiguration.*; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.iqser.red.service.persistence.management.v1.processor.migration.SaasMigrationService; +import com.iqser.red.service.redaction.v1.model.MigrationRequest; +import com.iqser.red.service.redaction.v1.model.MigrationResponse; + +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; @Slf4j @Service @@ -37,7 +41,7 @@ public class RedactionServiceSaasMigrationMessageReceiver { public void handleDLQMessage(Message failedMessage) { var migrationRequest = objectMapper.readValue(failedMessage.getBody(), MigrationRequest.class); - String errorCause = failedMessage.getMessageProperties().getHeader(MessagingConfiguration.X_ERROR_INFO_HEADER); + String errorCause = failedMessage.getMessageProperties().getHeader(X_ERROR_INFO_HEADER); saasMigrationService.handleError(migrationRequest.getDossierId(), migrationRequest.getFileId(), errorCause, MIGRATION_QUEUE); } -- 2.47.2 From 61cc1297fda758d56df4a00fdbb33017735d4672 Mon Sep 17 00:00:00 2001 From: Andrei Isvoran Date: Wed, 8 Nov 2023 09:42:23 +0100 Subject: [PATCH 58/96] RED-7784 - Report with unprocessed redactions --- .../service/download/DownloadPreparationService.java | 2 +- persistence-service-v1/pom.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/DownloadPreparationService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/DownloadPreparationService.java index 65e583478..85beda749 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/DownloadPreparationService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/download/DownloadPreparationService.java @@ -71,7 +71,7 @@ public class DownloadPreparationService { downloadStatus.getFiles().forEach(fileEntity -> { - RedactionMessage message = messageBuilder.fileId(fileEntity.getId()).unapprovedFile(fileEntity.getWorkflowStatus() != WorkflowStatus.APPROVED).build(); + RedactionMessage message = messageBuilder.fileId(fileEntity.getId()).unapprovedFile(fileEntity.getWorkflowStatus() != WorkflowStatus.APPROVED).includeUnprocessed(reportResultMessage.isIncludeUnprocessed()).build(); log.info("Sending redaction request for downloadId:{} fileId:{} to pdftron-redaction-queue", downloadId, fileEntity.getId()); rabbitTemplate.convertAndSend(MessagingConfiguration.PDFTRON_QUEUE, message); }); diff --git a/persistence-service-v1/pom.xml b/persistence-service-v1/pom.xml index 592b8be79..7f35315ca 100755 --- a/persistence-service-v1/pom.xml +++ b/persistence-service-v1/pom.xml @@ -33,8 +33,8 @@ 4.165.0 2.71.0 - 4.29.0 - 4.30.0 + 4.38.0 + 4.31.0 3.10.0 2.45.0 -- 2.47.2 From 6adfdb2991ba5f605cda4d2051fb2b95ff0a2343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominique=20Eifl=C3=A4nder?= Date: Thu, 9 Nov 2023 16:15:40 +0100 Subject: [PATCH 59/96] DM-576: Fixed connections idle in transaction --- .../entity/configuration/LegalBasisMappingEntity.java | 8 ++------ .../v1/processor/service/DossierTemplateCloneService.java | 1 - .../service/export/DossierTemplateExportService.java | 1 - .../persistence/DossierTemplatePersistenceService.java | 1 - .../service/persistence/RulesPersistenceService.java | 2 +- 5 files changed, 3 insertions(+), 10 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/configuration/LegalBasisMappingEntity.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/configuration/LegalBasisMappingEntity.java index cf88548a8..8c09d538b 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/configuration/LegalBasisMappingEntity.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/entity/configuration/LegalBasisMappingEntity.java @@ -3,11 +3,7 @@ package com.iqser.red.service.persistence.management.v1.processor.entity.configu import java.util.ArrayList; import java.util.List; -import jakarta.persistence.Column; -import jakarta.persistence.ElementCollection; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Table; +import jakarta.persistence.*; import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; @@ -30,7 +26,7 @@ public class LegalBasisMappingEntity { @Column private long version; - @ElementCollection + @ElementCollection(fetch = FetchType.EAGER) @Fetch(FetchMode.SUBSELECT) private List legalBasis = new ArrayList<>(); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateCloneService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateCloneService.java index 9912f4aba..d0acab1b9 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateCloneService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateCloneService.java @@ -65,7 +65,6 @@ public class DossierTemplateCloneService { private final FileManagementStorageService fileManagementStorageService; - @Transactional public DossierTemplateEntity cloneDossierTemplate(String dossierTemplateId, CloneDossierTemplateRequest cloneDossierTemplateRequest) { if (StringUtils.isEmpty(cloneDossierTemplateRequest.getName())) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/export/DossierTemplateExportService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/export/DossierTemplateExportService.java index d397f0145..b8f288cde 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/export/DossierTemplateExportService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/export/DossierTemplateExportService.java @@ -111,7 +111,6 @@ public class DossierTemplateExportService { @SneakyThrows - @Transactional public void createDownloadArchive(DownloadJob downloadJob) { objectMapper.registerModule(new JavaTimeModule()); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java index 8bb15d261..b69d253d9 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/DossierTemplatePersistenceService.java @@ -130,7 +130,6 @@ public class DossierTemplatePersistenceService { } - @Transactional public DossierTemplateStatus computeDossierTemplateStatus(DossierTemplateEntity dossierTemplate) { var legalBasis = legalBasisMappingPersistenceService.getLegalBasisMapping(dossierTemplate.getId()); diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/RulesPersistenceService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/RulesPersistenceService.java index db502994d..379842d4e 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/RulesPersistenceService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/persistence/RulesPersistenceService.java @@ -105,7 +105,7 @@ public class RulesPersistenceService { private final RuleSetRepository ruleSetRepository; - @Transactional(Transactional.TxType.REQUIRES_NEW) + @Transactional public RuleSetEntity getRules(String dossierTemplateId, RuleFileType ruleFileType) { return ruleSetRepository.findByDossierTemplateIdAndRuleFileType(dossierTemplateId, ruleFileType.name()) -- 2.47.2 From 05981913b3526379018e44f55e355501882c431d Mon Sep 17 00:00:00 2001 From: Kilian Schuettler Date: Fri, 10 Nov 2023 12:15:07 +0100 Subject: [PATCH 60/96] DM-557: fix component sorting --- .../management/v1/processor/service/ComponentLogService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ComponentLogService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ComponentLogService.java index ae647570f..89466eac2 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ComponentLogService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/ComponentLogService.java @@ -34,6 +34,7 @@ public class ComponentLogService { "Species", "Strain", "Was_the_definitive_study_conducted_with_positive_control", + "Study_Design_Main_Study", "Results_Main_Study", "Preliminary_Test_Results", "What_was_the_approach_used", -- 2.47.2 From 0d475e283962170f20f9455fe11008178d0e79a2 Mon Sep 17 00:00:00 2001 From: Corina Olariu Date: Mon, 13 Nov 2023 09:50:03 +0200 Subject: [PATCH 61/96] RED-7876 - Diagrams for future license are empty - remove the check for start date in the future - remove the setting to set current date for end date in case date is in the future --- .../management/v1/processor/service/LicenseReportService.java | 1 - .../v1/api/shared/model/license/LicenseReportRequest.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java index 090f53f48..c7e48b67e 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/LicenseReportService.java @@ -30,7 +30,6 @@ public class LicenseReportService { public LicenseReport getLicenseReport(LicenseReportRequest licenseReportRequest) { if (licenseReportRequest.getStartDate() == null || - licenseReportRequest.getStartDate().isAfter(Instant.now()) || licenseReportRequest.getStartDate().isAfter(licenseReportRequest.getEndDate())) { return LicenseReport.builder() .startDate(licenseReportRequest.getStartDate()) diff --git a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/license/LicenseReportRequest.java b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/license/LicenseReportRequest.java index 3db05c7a2..cee64a0fc 100644 --- a/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/license/LicenseReportRequest.java +++ b/persistence-service-v1/persistence-service-shared-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/shared/model/license/LicenseReportRequest.java @@ -20,7 +20,7 @@ public class LicenseReportRequest { public Instant getEndDate() { - if (endDate == null || endDate.isAfter(Instant.now())) { + if (endDate == null) { endDate = Instant.now(); } return endDate; -- 2.47.2 From d11a1178b38fb3609fbf4a7545f0122713105b94 Mon Sep 17 00:00:00 2001 From: Ali Oezyetimoglu Date: Mon, 13 Nov 2023 09:00:09 +0100 Subject: [PATCH 62/96] RED-7883: changed encoding from modified UTF-8 to UTF-8 for dossier template import and export --- .../service/DossierTemplateImportService.java | 16 +++++++-- .../export/DossierTemplateExportService.java | 20 +++++++++++ .../tests/DossierTemplateImportTest.java | 2 +- .../tests/DossierTemplateTest.java | 34 +++++++++++++++++++ 4 files changed, 69 insertions(+), 3 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java index 17a5ed46f..e154b8633 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java @@ -3,12 +3,15 @@ package com.iqser.red.service.persistence.management.v1.processor.service; import static com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter.convert; import java.io.BufferedInputStream; +import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.time.OffsetDateTime; import java.time.temporal.ChronoUnit; import java.util.ArrayList; @@ -17,7 +20,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.function.Function; @@ -67,7 +69,6 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.ReportTemplateUploadRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.Colors; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.CreateOrUpdateDossierStatusRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.DossierStatusInfo; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileAttributeConfig; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.importexport.ExportFilename; @@ -546,6 +547,17 @@ public class DossierTemplateImportService { return entries; } +// private List readEntries(byte[] bytes) { +// +// ByteArrayInputStream bInput = new ByteArrayInputStream(bytes); +// try (BufferedReader br = new BufferedReader(new InputStreamReader(bInput, StandardCharsets.UTF_8))) { +// return br.lines().collect(Collectors.toList()); +// } catch (IOException e) { +// log.debug("exception: ", e); +// throw new BadRequestException("Error while reading the entries", e); +// } +// } + private String getType(String filename) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/export/DossierTemplateExportService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/export/DossierTemplateExportService.java index b8f288cde..fd41eaae2 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/export/DossierTemplateExportService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/export/DossierTemplateExportService.java @@ -2,10 +2,12 @@ package com.iqser.red.service.persistence.management.v1.processor.service.export import static com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter.convert; +import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.stream.Collectors; @@ -268,6 +270,24 @@ public class DossierTemplateExportService { } } +// private void writeEntriesListToFile(FileSystemBackedArchiver fileSystemBackedArchiver, List entriesValuesList, String folderName, String filename) { +// +// try (ByteArrayOutputStream bt = new ByteArrayOutputStream(); +// OutputStreamWriter osw = new OutputStreamWriter(bt, StandardCharsets.UTF_8); +// BufferedWriter writer = new BufferedWriter(osw)) { +// +// for (String entry : entriesValuesList) { +// writer.write(entry); +// writer.newLine(); +// } +// writer.flush(); +// +// fileSystemBackedArchiver.addEntries(new FileSystemBackedArchiver.ArchiveModel(folderName, filename, bt.toByteArray())); +// } catch (IOException e) { +// log.debug("Error writing values to files"); +// } +// } + private void storeZipFile(String storageId, FileSystemBackedArchiver fileSystemBackedArchiver) { diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateImportTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateImportTest.java index 3bf948eb5..b4b82ff22 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateImportTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateImportTest.java @@ -47,7 +47,7 @@ public class DossierTemplateImportTest extends AbstractPersistenceServerServiceT @Disabled public void testLocalDossierTemplateImport() { - var importDir = new File("C:\\Users\\YannikHampe\\Downloads\\testing\\"); + var importDir = new File("/tmp/knoell"); assertThat(importDir).isNotNull(); assertThat(importDir.exists()).isTrue(); diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java index 01a0af423..815a4d5a4 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java @@ -5,12 +5,20 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.io.BufferedWriter; +import java.io.ByteArrayOutputStream; +import java.io.FileOutputStream; +import java.io.IOException; import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.charset.StandardCharsets; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.temporal.ChronoUnit; import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; import org.jetbrains.annotations.NotNull; @@ -38,6 +46,7 @@ import com.iqser.red.service.persistence.management.v1.processor.exception.BadRe import com.iqser.red.service.persistence.management.v1.processor.model.DownloadJob; import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; import com.iqser.red.service.persistence.management.v1.processor.service.export.ExportDownloadMessageReceiver; +import com.iqser.red.service.persistence.management.v1.processor.utils.FileSystemBackedArchiver; import com.iqser.red.service.persistence.service.v1.api.shared.model.CreateTypeValue; import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierAttributesConfig; import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierStatusRequest; @@ -376,6 +385,7 @@ public class DossierTemplateTest extends AbstractPersistenceServerServiceTest { } + private void setupDossierTemplate(DossierTemplateModel dossierTemplate) { var type = CreateTypeValue.builder() @@ -551,6 +561,30 @@ public class DossierTemplateTest extends AbstractPersistenceServerServiceTest { } + @Test + @SneakyThrows + public void testWriteLines() { + + List entriesValuesList = List.of("Adam", "Eva", "drei sdfs"); + + try (ByteArrayOutputStream bt = new ByteArrayOutputStream(); + OutputStreamWriter osw = new OutputStreamWriter(bt, StandardCharsets.UTF_8); + BufferedWriter writer = new BufferedWriter(osw)) { + + for (String entry : entriesValuesList) { + writer.write(entry); + writer.newLine(); + } + writer.flush(); + + try (FileOutputStream fileOutputStream = new FileOutputStream("/tmp/e.txt")) { + fileOutputStream.write(bt.toByteArray()); + } + + } + } + + @Test @SneakyThrows public void testImportDossierTemplateUpdateExisting() { -- 2.47.2 From f0a4772c3370a8159a8a05fa527c3793fc016494 Mon Sep 17 00:00:00 2001 From: Ali Oezyetimoglu Date: Tue, 14 Nov 2023 10:44:21 +0100 Subject: [PATCH 63/96] RED-7883: changed encoding of type dictionaries from modified UTF-8 to UTF-8 --- .../tests/DossierTemplateTest.java | 169 +++++++++++++----- 1 file changed, 122 insertions(+), 47 deletions(-) diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java index 815a4d5a4..e1872aeeb 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java @@ -1,59 +1,18 @@ package com.iqser.red.service.peristence.v1.server.integration.tests; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.io.BufferedWriter; -import java.io.ByteArrayOutputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.nio.charset.StandardCharsets; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import org.jetbrains.annotations.NotNull; -import org.junit.jupiter.api.Test; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.mock.web.MockMultipartFile; - import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Sets; -import com.iqser.red.service.peristence.v1.server.integration.client.DictionaryClient; -import com.iqser.red.service.peristence.v1.server.integration.client.DossierAttributeConfigClient; -import com.iqser.red.service.peristence.v1.server.integration.client.DossierClient; -import com.iqser.red.service.peristence.v1.server.integration.client.DossierStatusClient; -import com.iqser.red.service.peristence.v1.server.integration.client.DossierTemplateClient; -import com.iqser.red.service.peristence.v1.server.integration.client.DownloadClient; -import com.iqser.red.service.peristence.v1.server.integration.client.FileAttributeConfigClient; -import com.iqser.red.service.peristence.v1.server.integration.client.LegalBasisClient; -import com.iqser.red.service.peristence.v1.server.integration.client.ReportTemplateClient; -import com.iqser.red.service.peristence.v1.server.integration.client.WatermarkClient; +import com.iqser.red.service.peristence.v1.server.integration.client.*; import com.iqser.red.service.peristence.v1.server.integration.service.DossierTemplateTesterAndProvider; import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider; import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest; import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException; import com.iqser.red.service.persistence.management.v1.processor.model.DownloadJob; +import com.iqser.red.service.persistence.management.v1.processor.service.DossierTemplateImportService; +import com.iqser.red.service.persistence.management.v1.processor.service.DossierTemplateManagementService; import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; import com.iqser.red.service.persistence.management.v1.processor.service.export.ExportDownloadMessageReceiver; -import com.iqser.red.service.persistence.management.v1.processor.utils.FileSystemBackedArchiver; -import com.iqser.red.service.persistence.service.v1.api.shared.model.CreateTypeValue; -import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierAttributesConfig; -import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierStatusRequest; -import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierTemplateModel; -import com.iqser.red.service.persistence.service.v1.api.shared.model.FileAttributesConfig; -import com.iqser.red.service.persistence.service.v1.api.shared.model.TypeValue; -import com.iqser.red.service.persistence.service.v1.api.shared.model.WatermarkModel; +import com.iqser.red.service.persistence.service.v1.api.shared.model.*; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.CloneDossierTemplateRequest; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierAttributeConfig; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierTemplateStatus; @@ -68,9 +27,33 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType; import com.iqser.red.storage.commons.service.StorageService; import com.knecon.fforesight.tenantcommons.TenantContext; - import feign.FeignException; import lombok.SneakyThrows; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockMultipartFile; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class DossierTemplateTest extends AbstractPersistenceServerServiceTest { @@ -122,6 +105,11 @@ public class DossierTemplateTest extends AbstractPersistenceServerServiceTest { @Autowired private LegalBasisClient legalBasisClient; + @Autowired + private DossierTemplateImportService dossierTemplateImportService; + + @Autowired + private DossierTemplateManagementService dossierTemplateManagementService; @Test public void testDownload() { @@ -385,7 +373,6 @@ public class DossierTemplateTest extends AbstractPersistenceServerServiceTest { } - private void setupDossierTemplate(DossierTemplateModel dossierTemplate) { var type = CreateTypeValue.builder() @@ -584,6 +571,94 @@ public class DossierTemplateTest extends AbstractPersistenceServerServiceTest { } } + @Test + @Disabled + @SneakyThrows + public void changeEncodingFromModUTF8ToUTF8() { + String dossierTemplatesRepo = "/home/aoezyetimoglu/repositories/PROJECTMANAGEMENT/Syngenta/business-logic/dev-v2/"; + Stream.of( + Files.walk(Path.of(dossierTemplatesRepo + "EFSA_Regulation_2021")), + Files.walk(Path.of(dossierTemplatesRepo + "EFSA_sanitisation_GFL_v1")), + Files.walk(Path.of(dossierTemplatesRepo + "EFSA_sanitisation_pre_GFL_v1")), + Files.walk(Path.of(dossierTemplatesRepo + "Flora_SCM_(Syngenta_Evaluation)")), + Files.walk(Path.of(dossierTemplatesRepo + "Manual_Redaction"))// + ) + .flatMap(Function.identity())// + .filter(path -> path.getFileName().toString().equals("entries.txt") || // + path.getFileName().toString().equals("falsePositives.txt") || // + path.getFileName().toString().equals("falseRecommendations.txt")// + ) + .map(Path::toFile)// + .forEach(file -> { + System.out.println(file); + try { + changeEncoding(file); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + + private void changeEncoding(File modUTF8File) throws IOException { + var path = modUTF8File.getPath(); + + var bytes = convertFileToByteArray(modUTF8File); + + var entries = readEntriesModUTF8(bytes); + writeEntriesListToFileUTF8(entries, path); + + } + + private static byte[] convertFileToByteArray(File file) throws IOException { + Path path = file.toPath(); + return Files.readAllBytes(path); + } + + + private List readEntriesModUTF8(byte[] bytes) { + + ByteArrayInputStream bInput = new ByteArrayInputStream(bytes); + DataInputStream in = new DataInputStream(bInput); + List entries = new ArrayList<>(); + try { + while (in.available() > 0) { + String entry = in.readUTF(); + entries.add(entry); + + } + } catch (IOException e) { + throw new BadRequestException("Error while reading the entries", e); + } + return entries; + } + + private void writeEntriesListToFileUTF8(List entriesValuesList, String path) { + + try (ByteArrayOutputStream bt = new ByteArrayOutputStream(); + OutputStreamWriter osw = new OutputStreamWriter(bt, StandardCharsets.UTF_8); + BufferedWriter writer = new BufferedWriter(osw); + FileOutputStream fileOutputStream = new FileOutputStream(path)) { + + Iterator iterator = entriesValuesList.iterator(); + + while (iterator.hasNext()) { + String entry = iterator.next(); + writer.write(entry); + + if (iterator.hasNext()) { + writer.newLine(); + } + } + writer.flush(); + + bt.writeTo(fileOutputStream); + System.out.println("Data written to file successfully!"); + + } catch (IOException e) { + System.out.println("Error writing values to files"); + } + } + @Test @SneakyThrows -- 2.47.2 From 8845c406b2ec7acae47e6307acec12187260bba2 Mon Sep 17 00:00:00 2001 From: Ali Oezyetimoglu Date: Tue, 14 Nov 2023 10:50:42 +0100 Subject: [PATCH 64/96] RED-7883: updated methods to import and export with UTF-8 instead of modified UTF-8 --- .../service/DossierTemplateImportService.java | 22 +----- .../export/DossierTemplateExportService.java | 78 +++++++------------ .../tests/DossierTemplateTest.java | 6 -- 3 files changed, 28 insertions(+), 78 deletions(-) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java index e154b8633..10ba702d7 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/DossierTemplateImportService.java @@ -532,32 +532,14 @@ public class DossierTemplateImportService { private List readEntries(byte[] bytes) { ByteArrayInputStream bInput = new ByteArrayInputStream(bytes); - DataInputStream in = new DataInputStream(bInput); - List entries = new ArrayList<>(); - try { - while (in.available() > 0) { - String entry = in.readUTF(); - entries.add(entry); - - } + try (BufferedReader br = new BufferedReader(new InputStreamReader(bInput, StandardCharsets.UTF_8))) { + return br.lines().collect(Collectors.toList()); } catch (IOException e) { log.debug("exception: ", e); throw new BadRequestException("Error while reading the entries", e); } - return entries; } -// private List readEntries(byte[] bytes) { -// -// ByteArrayInputStream bInput = new ByteArrayInputStream(bytes); -// try (BufferedReader br = new BufferedReader(new InputStreamReader(bInput, StandardCharsets.UTF_8))) { -// return br.lines().collect(Collectors.toList()); -// } catch (IOException e) { -// log.debug("exception: ", e); -// throw new BadRequestException("Error while reading the entries", e); -// } -// } - private String getType(String filename) { diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/export/DossierTemplateExportService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/export/DossierTemplateExportService.java index fd41eaae2..385bcd56e 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/export/DossierTemplateExportService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/export/DossierTemplateExportService.java @@ -1,20 +1,5 @@ package com.iqser.red.service.persistence.management.v1.processor.service.export; -import static com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter.convert; - -import java.io.BufferedWriter; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStreamWriter; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.stream.Collectors; - -import org.springframework.amqp.rabbit.core.RabbitTemplate; -import org.springframework.stereotype.Service; - import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; @@ -28,16 +13,7 @@ import com.iqser.red.service.persistence.management.v1.processor.model.DownloadJ import com.iqser.red.service.persistence.management.v1.processor.service.ColorsService; import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService; import com.iqser.red.service.persistence.management.v1.processor.service.WatermarkService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierAttributeConfigPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierStatusPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierTemplatePersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DownloadStatusPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.EntryPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileAttributeConfigPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.LegalBasisMappingPersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.ReportTemplatePersistenceService; -import com.iqser.red.service.persistence.management.v1.processor.service.persistence.RulesPersistenceService; +import com.iqser.red.service.persistence.management.v1.processor.service.persistence.*; import com.iqser.red.service.persistence.management.v1.processor.utils.FileSystemBackedArchiver; import com.iqser.red.service.persistence.management.v1.processor.utils.StorageIdUtils; import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType; @@ -56,11 +32,19 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType; import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.Type; import com.iqser.red.service.persistence.service.v1.api.shared.model.download.DownloadStatusValue; - -import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.stereotype.Service; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; + +import static com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter.convert; @Slf4j @Service @@ -256,38 +240,28 @@ public class DossierTemplateExportService { private void writeEntriesListToFile(FileSystemBackedArchiver fileSystemBackedArchiver, List entriesValuesList, String folderName, String filename) { - try { - ByteArrayOutputStream bt = new ByteArrayOutputStream(); - DataOutputStream dt = new DataOutputStream(bt); - for (String entry : entriesValuesList) { - dt.writeUTF(entry); + try (ByteArrayOutputStream bt = new ByteArrayOutputStream(); + OutputStreamWriter osw = new OutputStreamWriter(bt, StandardCharsets.UTF_8); + BufferedWriter writer = new BufferedWriter(osw)) { + + Iterator iterator = entriesValuesList.iterator(); + + while (iterator.hasNext()) { + String entry = iterator.next(); + writer.write(entry); + + if (iterator.hasNext()) { + writer.newLine(); + } } + writer.flush(); + fileSystemBackedArchiver.addEntries(new FileSystemBackedArchiver.ArchiveModel(folderName, filename, bt.toByteArray())); - dt.close(); - bt.close(); } catch (IOException e) { log.debug("Error writing values to files"); } } -// private void writeEntriesListToFile(FileSystemBackedArchiver fileSystemBackedArchiver, List entriesValuesList, String folderName, String filename) { -// -// try (ByteArrayOutputStream bt = new ByteArrayOutputStream(); -// OutputStreamWriter osw = new OutputStreamWriter(bt, StandardCharsets.UTF_8); -// BufferedWriter writer = new BufferedWriter(osw)) { -// -// for (String entry : entriesValuesList) { -// writer.write(entry); -// writer.newLine(); -// } -// writer.flush(); -// -// fileSystemBackedArchiver.addEntries(new FileSystemBackedArchiver.ArchiveModel(folderName, filename, bt.toByteArray())); -// } catch (IOException e) { -// log.debug("Error writing values to files"); -// } -// } - private void storeZipFile(String storageId, FileSystemBackedArchiver fileSystemBackedArchiver) { diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java index e1872aeeb..f102991f5 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateTest.java @@ -105,11 +105,6 @@ public class DossierTemplateTest extends AbstractPersistenceServerServiceTest { @Autowired private LegalBasisClient legalBasisClient; - @Autowired - private DossierTemplateImportService dossierTemplateImportService; - - @Autowired - private DossierTemplateManagementService dossierTemplateManagementService; @Test public void testDownload() { @@ -624,7 +619,6 @@ public class DossierTemplateTest extends AbstractPersistenceServerServiceTest { while (in.available() > 0) { String entry = in.readUTF(); entries.add(entry); - } } catch (IOException e) { throw new BadRequestException("Error while reading the entries", e); -- 2.47.2 From 67afcfa6b00fb57838226e567d775f3ac61c04fa Mon Sep 17 00:00:00 2001 From: Ali Oezyetimoglu Date: Tue, 14 Nov 2023 12:12:39 +0100 Subject: [PATCH 65/96] RED-7883: updated zips of dossier templates to have the right encoded type dictionary lists --- .../EFSA_sanitisation_GFL_v1.zip | Bin 553481 -> 549575 bytes .../EFSA_sanitisation_GFL_v1_adress_parts.zip | Bin 574975 -> 564156 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/resources/files/dossiertemplates/EFSA_sanitisation_GFL_v1.zip b/persistence-service-v1/persistence-service-server-v1/src/test/resources/files/dossiertemplates/EFSA_sanitisation_GFL_v1.zip index 1346866d7d0f2720f4c19a23ff455aea8224b7fb..ea870134e2aca44460b6d8cd07d881ae741fabbc 100644 GIT binary patch literal 549575 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

gJtP6K4cn7^^}U059#Qrk!IJn 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 z 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

kG9Nvs}JR>8m;esB?t6zmD% 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

f|d9{{Pi9SvTp=#dWQ)^QlBZQ)Z8F2EdVv?! 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 z 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 literal 553481 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