From a53a61cea3ce4178bd6bad2aab9649398c1edfeb Mon Sep 17 00:00:00 2001 From: Timo Bejan Date: Mon, 6 Dec 2021 09:54:24 +0200 Subject: [PATCH] Ignore hint feature RED-2867 --- .../v1/server/redaction/model/Entity.java | 2 + .../v1/server/redaction/model/Image.java | 1 + .../v1/server/redaction/model/Section.java | 4 +- .../redaction/service/ReanalyzeService.java | 34 ++++++++++---- .../service/RedactionLogMergeService.java | 1 + .../v1/server/RedactionIntegrationTest.java | 43 ++++++++++++++++-- .../resources/dictionaries/CBI_address.txt | 1 + .../dictionaries/published_information.txt | 1 + .../resources/files/new/test-ignore-hint.pdf | Bin 0 -> 19697 bytes 9 files changed, 70 insertions(+), 17 deletions(-) create mode 100644 redaction-service-v1/redaction-service-server-v1/src/test/resources/files/new/test-ignore-hint.pdf diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/model/Entity.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/model/Entity.java index 2ae553db..2cb82371 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/model/Entity.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/model/Entity.java @@ -39,6 +39,8 @@ public class Entity implements ReasonHolder { private boolean isDossierDictionaryEntry; + private boolean ignored; + public Entity(String word, String type, boolean redaction, String redactionReason, List positionSequences, String headline, int matchedRule, int sectionNumber, String legalBasis, boolean isDictionaryEntry, String textBefore, String textAfter, Integer start, Integer end, boolean isDossierDictionaryEntry) { diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/model/Image.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/model/Image.java index 63d382d5..35317fdf 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/model/Image.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/model/Image.java @@ -20,6 +20,7 @@ public class Image implements ReasonHolder { private int sectionNumber; private String section; private int page; + private boolean ignored; private boolean hasTransparency; } diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/model/Section.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/model/Section.java index f87e937f..cc267f33 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/model/Section.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/model/Section.java @@ -134,13 +134,13 @@ public class Section { public boolean matchesType(String type) { - return entities.stream().anyMatch(entity -> entity.getType().equals(type)); + return entities.stream().anyMatch(entity -> !entity.isIgnored() && entity.getType().equals(type)); } public boolean matchesImageType(String type) { - return images.stream().anyMatch(image -> image.getType().equals(type)); + return images.stream().anyMatch(image -> !image.isIgnored() && image.getType().equals(type)); } diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/service/ReanalyzeService.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/service/ReanalyzeService.java index 4a22087e..172cae85 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/service/ReanalyzeService.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/service/ReanalyzeService.java @@ -213,19 +213,33 @@ public class ReanalyzeService { surroundingWordsService.addSurroundingText(entities, reanalysisSection.getSearchableText(), dictionary); } - if (!local && reanalysisSection.getImages() != null && !reanalysisSection.getImages() - .isEmpty() && analyzeRequest.getManualRedactions() != null && analyzeRequest.getManualRedactions() - .getImageRecategorizations() != null) { - for (Image image : reanalysisSection.getImages()) { - String imageId = IdBuilder.buildId(image.getPosition(), image.getPage()); - for (ManualImageRecategorization imageRecategorization : analyzeRequest.getManualRedactions() - .getImageRecategorizations()) { - if (imageRecategorization.getStatus().equals(Status.APPROVED) && imageRecategorization.getId() - .equals(imageId)) { - image.setType(imageRecategorization.getType()); + if (!local && analyzeRequest.getManualRedactions() != null) { + + var idsToRemove = analyzeRequest.getManualRedactions().getIdsToRemove().stream().map(IdRemoval::getId).collect(Collectors.toSet()); + + if (reanalysisSection.getImages() != null && !reanalysisSection.getImages().isEmpty() && analyzeRequest.getManualRedactions().getImageRecategorizations() != null) { + for (Image image : reanalysisSection.getImages()) { + String imageId = IdBuilder.buildId(image.getPosition(), image.getPage()); + for (ManualImageRecategorization imageRecategorization : analyzeRequest.getManualRedactions() + .getImageRecategorizations()) { + if (imageRecategorization.getStatus().equals(Status.APPROVED) && imageRecategorization.getId() + .equals(imageId)) { + image.setType(imageRecategorization.getType()); + } + } + if (idsToRemove.contains(imageId)) { + image.setIgnored(true); } } } + + entities.forEach(entity -> + entity.getPositionSequences().forEach(ps -> { + if (idsToRemove.contains(ps.getId())) { + entity.setIgnored(true); + } + })); + } sectionSearchableTextPairs.add(new SectionSearchableTextPair(Section.builder() diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/service/RedactionLogMergeService.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/service/RedactionLogMergeService.java index 53e073f7..f0fb70b6 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/service/RedactionLogMergeService.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/service/RedactionLogMergeService.java @@ -136,6 +136,7 @@ public class RedactionLogMergeService { manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", removed by manual override"); redactionLogEntry.setColor(getColor(redactionLogEntry.getType(), dossierTemplateId, false, redactionLogEntry .isRedacted(), true)); + redactionLogEntry.setHint(false); redactionLogEntry.setHasBeenRemovedByManualOverride(true); } else if (manualRemoval.getStatus().equals(Status.REQUESTED)) { manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", requested to remove"); diff --git a/redaction-service-v1/redaction-service-server-v1/src/test/java/com/iqser/red/service/redaction/v1/server/RedactionIntegrationTest.java b/redaction-service-v1/redaction-service-server-v1/src/test/java/com/iqser/red/service/redaction/v1/server/RedactionIntegrationTest.java index 7f684a1c..bb0f19bb 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/test/java/com/iqser/red/service/redaction/v1/server/RedactionIntegrationTest.java +++ b/redaction-service-v1/redaction-service-server-v1/src/test/java/com/iqser/red/service/redaction/v1/server/RedactionIntegrationTest.java @@ -18,11 +18,10 @@ import com.iqser.red.service.redaction.v1.server.redaction.utils.ResourceLoader; import com.iqser.red.service.redaction.v1.server.redaction.utils.TextNormalizationUtilities; import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService; import com.iqser.red.storage.commons.service.StorageService; - import lombok.SneakyThrows; - import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; +import org.assertj.core.util.Sets; import org.junit.After; import org.junit.Before; import org.junit.Ignore; @@ -758,6 +757,43 @@ public class RedactionIntegrationTest { } + @Test + public void testIgnoreHint() { + + System.out.println("testIgnoreHint"); + + AnalyzeRequest request = prepareStorage("files/new/test-ignore-hint.pdf"); + reanalyzeService.analyze(request); + var redactionLog = redactionStorageService.getRedactionLog(TEST_DOSSIER_ID, TEST_FILE_ID); + + var manualRedactions = ManualRedactions.builder().idsToRemove(Sets.newLinkedHashSet( + IdRemoval.builder() + .id("c630599611e6e3db314518374bcf70f7") + .status(Status.APPROVED) + .user("test") + .removeFromDictionary(false) + .processedDate(OffsetDateTime.now()) + .requestDate(OffsetDateTime.now()) + .build())).build(); + + request.setManualRedactions(manualRedactions); + reanalyzeService.reanalyze(request); + + + var mergedRedactionLog = redactionController.getRedactionLog(RedactionRequest.builder().withSectionDataForManualRedactions(true) + .manualRedactions(manualRedactions) + .dossierTemplateId(TEST_DOSSIER_TEMPLATE_ID) + .dossierId(TEST_DOSSIER_ID) + .fileId(TEST_FILE_ID) + .build()); + + var cbiAddressBeforeHintRemoval = redactionLog.getRedactionLogEntry().stream().filter(re -> re.getType().equalsIgnoreCase("CBI_Address")).findAny().get(); + assertThat(cbiAddressBeforeHintRemoval.isRedacted()).isFalse(); + + var cbiAddressAfterHintRemoval = mergedRedactionLog.getRedactionLogEntry().stream().filter(re -> re.getType().equalsIgnoreCase("CBI_Address")).findAny().get(); + assertThat(cbiAddressAfterHintRemoval.isRedacted()).isTrue(); + } + @Test public void testTableRedaction() throws IOException { @@ -805,9 +841,6 @@ public class RedactionIntegrationTest { } - - - @Test public void testManualRedaction() throws IOException { diff --git a/redaction-service-v1/redaction-service-server-v1/src/test/resources/dictionaries/CBI_address.txt b/redaction-service-v1/redaction-service-server-v1/src/test/resources/dictionaries/CBI_address.txt index b6ad4398..b6acc607 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/test/resources/dictionaries/CBI_address.txt +++ b/redaction-service-v1/redaction-service-server-v1/src/test/resources/dictionaries/CBI_address.txt @@ -1654,3 +1654,4 @@ Zyma SA Zyma SA, Nyon, Switzerland Mambo-Tox Ltd. Biomedical Sciences Building Bassett Crescent East Southampton SO16 7PX UK Syngenta Environmental Sciences Jealott’s Hill International Research Centre Bracknell, Berkshire RG42 6EY UK +Test Ignored Hint CBI_ADDRESS diff --git a/redaction-service-v1/redaction-service-server-v1/src/test/resources/dictionaries/published_information.txt b/redaction-service-v1/redaction-service-server-v1/src/test/resources/dictionaries/published_information.txt index 023d801e..b1496e4b 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/test/resources/dictionaries/published_information.txt +++ b/redaction-service-v1/redaction-service-server-v1/src/test/resources/dictionaries/published_information.txt @@ -85,3 +85,4 @@ Toxicology and Applied Pharmacology Toxicol Sci Toxicol Sci. Toxicol Sci. 1 +Test Ignored Hint Published Information diff --git a/redaction-service-v1/redaction-service-server-v1/src/test/resources/files/new/test-ignore-hint.pdf b/redaction-service-v1/redaction-service-server-v1/src/test/resources/files/new/test-ignore-hint.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f63b18aecdee496b72133383cab31287a352bd43 GIT binary patch literal 19697 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 literal 0 HcmV?d00001