Compare commits

..
Author SHA1 Message Date
Dominique Eifländer bcd469bb65 Added equalsIgnoreCase fileattributes methods for rules 2021-08-20 14:58:56 +02:00
Dominique Eifländer 078dc2c3c3 RED-1755: Calculate falgs in file-management-service async 2021-08-18 16:02:38 +02:00
Dominique Eiflaender 4dda7ae543 Pull request #211: RED-2015: Fixed (Manual) Redactions in download reports/files for excluded pages
Merge in RED/redaction-service from RED-2015-master to master

* commit '4d514d0e5ed1c22436bd8ba58578022d5fb8c4db':
  RED-2015: Fixed (Manual) Redactions in download reports/files for excluded pages
2021-08-17 12:39:11 +02:00
Dominique Eifländer 4d514d0e5e RED-2015: Fixed (Manual) Redactions in download reports/files for excluded pages 2021-08-17 11:34:03 +02:00
Timo Bejan 1f12f9571f RedactionLogMergeService.java edited online with Bitbucket 2021-08-13 13:56:13 +02:00
Timo Bejan 5312d5ffdf RedactionLogMergeService.java edited online with Bitbucket 2021-08-13 13:19:42 +02:00
Timo Bejan e43e8bccbf RedactionLogMergeService.java edited online with Bitbucket 2021-08-13 13:00:32 +02:00
Timo Bejan 54250583b1 Pull request #207: Proper Order of manual actions based on time
Merge in RED/redaction-service from RED-1788 to master

* commit 'bb80b7ae7550d70a98b4d500d3870a13585b57e8':
  Proper Order of manual actions based on time
2021-08-13 10:27:23 +02:00
Timo Bejan bb80b7ae75 Proper Order of manual actions based on time 2021-08-13 11:19:54 +03:00
Dominique Eiflaender 25264f1450 Pull request #206: RED-1908: Removed RedactionChangeLog added changes to RedactionLog
Merge in RED/redaction-service from RED-1908 to master

* commit 'e8a4ef172c994ab8dd99f84f7a725e3dddfaca5f':
  RED-1908: Removed RedactionChangeLog added changes to RedactionLog
2021-08-11 10:00:48 +02:00
Dominique Eifländer e8a4ef172c RED-1908: Removed RedactionChangeLog added changes to RedactionLog 2021-08-11 09:45:00 +02:00
56 changed files with 340 additions and 2292 deletions
@@ -93,11 +93,6 @@ public class PlanSpec {
.description("Resultparser")
.resultDirectories("**/test-reports/*.xml, **/target/surefire-reports/*.xml, **/target/failsafe-reports/*.xml")
.enabled(true),
new ScriptTask()
.description("Sonar")
.location(Location.FILE)
.fileFromPath("bamboo-specs/src/main/resources/scripts/sonar-java.sh")
.argument(SERVICE_NAME),
new InjectVariablesTask()
.description("Inject git Tag")
.path("git.tag")
@@ -1,42 +0,0 @@
#!/bin/bash
set -e
SERVICE_NAME=$1
echo "dependency-check:aggregate"
${bamboo_capability_system_builder_mvn3_Maven_3}/bin/mvn \
--no-transfer-progress \
-f ${bamboo_build_working_directory}/$SERVICE_NAME-v1/pom.xml \
org.owasp:dependency-check-maven:aggregate
if [[ -z "${bamboo_repository_pr_key}" ]]
then
echo "Sonar Scan for branch: ${bamboo_planRepository_1_branch}"
${bamboo_capability_system_builder_mvn3_Maven_3}/bin/mvn \
--no-transfer-progress \
-f ${bamboo_build_working_directory}/$SERVICE_NAME-v1/pom.xml \
sonar:sonar \
-Dsonar.projectKey=RED_$SERVICE_NAME \
-Dsonar.host.url=https://sonarqube.iqser.com \
-Dsonar.login=${bamboo_sonarqube_api_token_secret} \
-Dsonar.branch.name=${bamboo_planRepository_1_branch} \
-Dsonar.dependencyCheck.jsonReportPath=target/dependency-check-report.json \
-Dsonar.dependencyCheck.xmlReportPath=target/dependency-check-report.xml \
-Dsonar.dependencyCheck.htmlReportPath=target/dependency-check-report.html
else
echo "Sonar Scan for PR with key1: ${bamboo_repository_pr_key}"
${bamboo_capability_system_builder_mvn3_Maven_3}/bin/mvn \
--no-transfer-progress \
-f ${bamboo_build_working_directory}/$SERVICE_NAME-v1/pom.xml \
sonar:sonar \
-Dsonar.projectKey=RED_$SERVICE_NAME \
-Dsonar.host.url=https://sonarqube.iqser.com \
-Dsonar.login=${bamboo_sonarqube_api_token_secret} \
-Dsonar.pullrequest.key=${bamboo_repository_pr_key} \
-Dsonar.pullrequest.branch=${bamboo_repository_pr_sourceBranch} \
-Dsonar.pullrequest.base=${bamboo_repository_pr_targetBranch} \
-Dsonar.dependencyCheck.jsonReportPath=target/dependency-check-report.json \
-Dsonar.dependencyCheck.xmlReportPath=target/dependency-check-report.xml \
-Dsonar.dependencyCheck.htmlReportPath=target/dependency-check-report.html
fi
-1
View File
@@ -6,7 +6,6 @@
<groupId>com.iqser.red</groupId>
<artifactId>platform-docker-dependency</artifactId>
<version>1.0.0</version>
<relativePath />
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -13,7 +13,6 @@ RUN apt-get update \
wget cabextract xfonts-utils fonts-liberation \
&& rm -rf /var/lib/apt/lists/*
RUN curl http://ftp.debian.org/debian/pool/contrib/m/msttcorefonts/ttf-mscorefonts-installer_3.8_all.deb -o /tmp/ttf-mscorefonts-installer_3.8_all.deb \
RUN curl http://ftp.br.debian.org/debian/pool/contrib/m/msttcorefonts/ttf-mscorefonts-installer_3.8_all.deb -o /tmp/ttf-mscorefonts-installer_3.8_all.deb \
&& dpkg -i /tmp/ttf-mscorefonts-installer_3.8_all.deb \
&& rm /tmp/ttf-mscorefonts-installer_3.8_all.deb \
+1 -2
View File
@@ -5,8 +5,7 @@
<parent>
<artifactId>platform-dependency</artifactId>
<groupId>com.iqser.red</groupId>
<version>1.1.3.3</version>
<relativePath />
<version>1.1.3</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -0,0 +1,18 @@
package com.iqser.red.service.redaction.v1.model;
import java.time.OffsetDateTime;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Change {
private ChangeType type;
private OffsetDateTime dateTime;
}
@@ -1,5 +1,5 @@
package com.iqser.red.service.redaction.v1.model;
public enum ChangeType {
ADDED, REMOVED
ADDED, REMOVED, CHANGED
}
@@ -17,8 +17,6 @@ public class ManualLegalBasisChange {
private String user;
private Status status;
private String legalBasis;
private String section;
private String value;
private OffsetDateTime requestDate;
private OffsetDateTime processedDate;
@@ -23,8 +23,6 @@ public class ManualRedactionEntry {
private String legalBasis;
private List<Rectangle> positions = new ArrayList<>();
private Status status;
private String section;
private boolean rectangle;
private boolean addToDictionary;
private boolean addToDossierDictionary;
@@ -1,22 +0,0 @@
package com.iqser.red.service.redaction.v1.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RedactionChangeLog {
private List<RedactionChangeLogEntry> redactionLogEntry = new ArrayList<>();
private long dictionaryVersion = -1;
private long dossierDictionaryVersion = -1;
private long rulesVersion = -1;
private long legalBasisVersion = -1;
}
@@ -1,49 +0,0 @@
package com.iqser.red.service.redaction.v1.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RedactionChangeLogEntry {
private String id;
private String type;
private String value;
private String reason;
private int matchedRule;
private String legalBasis;
private boolean redacted;
private boolean isHint;
private boolean isRecommendation;
private String section;
private float[] color;
@Builder.Default
private List<Rectangle> positions = new ArrayList<>();
private int sectionNumber;
private boolean manual;
private Status status;
private ManualRedactionType manualRedactionType;
private boolean isDictionaryEntry;
private String textBefore;
private String textAfter;
@Builder.Default
private List<Comment> comments = new ArrayList<>();
private ChangeType changeType;
private boolean isDossierDictionaryEntry;
private boolean excluded;
}
@@ -0,0 +1,17 @@
package com.iqser.red.service.redaction.v1.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class RedactionLogChanges {
private RedactionLog redactionLog;
private boolean hasChanges;
}
@@ -22,7 +22,6 @@ public class RedactionLogEntry {
private String type;
private String value;
private String reason;
private boolean rectangle;
private int matchedRule;
private String legalBasis;
private boolean redacted;
@@ -31,11 +30,6 @@ public class RedactionLogEntry {
private String section;
private float[] color;
private boolean hasBeenRecategorized;
private boolean hasLegalBasisChanged;
private boolean hasBeenForced;
private boolean hasBeenRemovedByManualOverride;
@Builder.Default
private List<Rectangle> positions = new ArrayList<>();
private int sectionNumber;
@@ -64,4 +58,8 @@ public class RedactionLogEntry {
private String recategorizationType;
private String legalBasisChangeValue;
@EqualsAndHashCode.Exclude
@Builder.Default
private List<Change> changes = new ArrayList<>();
}
@@ -20,6 +20,4 @@ public class RedactionRequest {
private ManualRedactions manualRedactions;
@Builder.Default
private Set<Integer> excludedPages = new HashSet<>();
private boolean withSectionDataForManualRedactions;
}
@@ -27,11 +27,7 @@ public class SectionArea {
private String header;
public boolean contains(Rectangle other) {
return page == other.getPage()
&& topLeft.getX() <= other.getTopLeft().getX()
&& topLeft.getX() + getWidth() >= other.getTopLeft().getX() + other.getWidth()
&& getTopLeft().getY() <= other.getTopLeft().getY()
&& getTopLeft().getY() + getHeight() >= other.getTopLeft().getY() + other.getHeight();
return page == other.getPage() && this.topLeft.getX() <= other.getTopLeft().getX() && this.topLeft.getX() + this.getWidth() >= other.getTopLeft().getX() + other.getWidth() && this.getTopLeft().getY() <= other.getTopLeft().getY() && this.getTopLeft().getY() + this.getHeight() >= other.getTopLeft().getY() + other.getHeight();
}
}
@@ -3,9 +3,10 @@ package com.iqser.red.service.redaction.v1.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Data
@AllArgsConstructor
@@ -14,16 +15,4 @@ public class SectionGrid {
private Map<Integer, List<SectionRectangle>> rectanglesPerPage = new HashMap<>();
private List<SectionGridSection> sections = new ArrayList<>();
@Data
@RequiredArgsConstructor
public static class SectionGridSection {
private final int sectionNumber;
private final String headline;
private final Set<Integer> pages;
private final List<SectionArea> sectionAreas;
}
}
@@ -1,6 +1,10 @@
package com.iqser.red.service.redaction.v1.model;
import lombok.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import java.util.List;
@@ -27,11 +31,4 @@ public class SectionRectangle {
private List<CellRectangle> tableCells;
public boolean contains(Rectangle other) {
return topLeft.getX() <= other.getTopLeft().getX()
&& topLeft.getX() + getWidth() >= other.getTopLeft().getX() + other.getWidth()
&& getTopLeft().getY() <= other.getTopLeft().getY()
&& getTopLeft().getY() + getHeight() >= other.getTopLeft().getY() + other.getHeight();
}
}
@@ -24,7 +24,7 @@
<dependency>
<groupId>com.iqser.red.service</groupId>
<artifactId>file-management-service-api-v1</artifactId>
<version>2.80.15</version>
<version>2.25.0</version>
<exclusions>
<exclusion>
<groupId>com.iqser.red.service</groupId>
@@ -1,7 +1,5 @@
package com.iqser.red.service.redaction.v1.server.classification.service;
import static java.util.stream.Collectors.toSet;
import com.iqser.red.service.redaction.v1.server.classification.model.FloatFrequencyCounter;
import com.iqser.red.service.redaction.v1.server.classification.model.Orientation;
import com.iqser.red.service.redaction.v1.server.classification.model.Page;
@@ -18,7 +16,6 @@ import com.iqser.red.service.redaction.v1.server.tableextraction.model.Table;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
@@ -28,12 +25,9 @@ public class BlockificationService {
static final float THRESHOLD = 1f;
public Page blockify(List<TextPositionSequence> textPositions, List<Ruling> horizontalRulingLines,
List<Ruling> verticalRulingLines) {
sortRotatedSequences(textPositions);
List<TextPositionSequence> chunkWords = new ArrayList<>();
List<AbstractTextContainer> chunkBlockList1 = new ArrayList<>();
@@ -56,7 +50,7 @@ public class BlockificationService {
if (prev != null && (lineSeparation || startFromTop || splitByX || newLineAfterSplit || splittedByRuling)) {
Orientation prevOrientation = null;
if (!chunkBlockList1.isEmpty()) {
if(!chunkBlockList1.isEmpty()) {
prevOrientation = chunkBlockList1.get(chunkBlockList1.size() - 1).getOrientation();
}
@@ -68,11 +62,15 @@ public class BlockificationService {
wasSplitted = true;
cb1.setOrientation(Orientation.LEFT);
splitX1 = word.getX1();
} else if (newLineAfterSplit && !splittedByRuling) {
} else
if (newLineAfterSplit && !splittedByRuling) {
wasSplitted = false;
cb1.setOrientation(Orientation.RIGHT);
splitX1 = null;
} else if (prevOrientation != null && prevOrientation.equals(Orientation.RIGHT) && (lineSeparation || !startFromTop || !splitByX || !newLineAfterSplit || !splittedByRuling)) {
} else
if(prevOrientation != null && prevOrientation.equals(Orientation.RIGHT) && (lineSeparation || !startFromTop || !splitByX || !newLineAfterSplit || !splittedByRuling)){
cb1.setOrientation(Orientation.LEFT);
}
@@ -112,18 +110,16 @@ public class BlockificationService {
while (itty.hasNext()) {
TextBlock block = (TextBlock) itty.next();
if (previousLeft != null && block.getOrientation().equals(Orientation.LEFT)) {
if (previousLeft.getMinY() > block.getMinY() && block.getMaxY() + block.getMostPopularWordHeight() > previousLeft
.getMinY()) {
if(previousLeft != null && block.getOrientation().equals(Orientation.LEFT)){
if (previousLeft.getMinY() > block.getMinY() && block.getMaxY() + block.getMostPopularWordHeight() > previousLeft.getMinY()){
previousLeft.add(block);
itty.remove();
continue;
}
}
if (previousRight != null && block.getOrientation().equals(Orientation.RIGHT)) {
if (previousRight.getMinY() > block.getMinY() && block.getMaxY() + block.getMostPopularWordHeight() > previousRight
.getMinY()) {
if(previousRight != null && block.getOrientation().equals(Orientation.RIGHT)){
if (previousRight.getMinY() > block.getMinY() && block.getMaxY() + block.getMostPopularWordHeight() > previousRight.getMinY()){
previousRight.add(block);
itty.remove();
continue;
@@ -137,16 +133,16 @@ public class BlockificationService {
}
}
itty = chunkBlockList1.iterator();
TextBlock previous = null;
while (itty.hasNext()) {
TextBlock block = (TextBlock) itty.next();
if (previous != null && previous.getOrientation().equals(Orientation.LEFT) && block.getOrientation()
.equals(Orientation.LEFT) && equalsWithThreshold(block.getMaxY(), previous.getMaxY()) || previous != null && previous
.getOrientation()
.equals(Orientation.LEFT) && block.getOrientation()
.equals(Orientation.RIGHT) && equalsWithThreshold(block.getMaxY(), previous.getMaxY())) {
if(previous != null && previous.getOrientation().equals(Orientation.LEFT) && block.getOrientation().equals(Orientation.LEFT) && equalsWithThreshold(block.getMaxY(), previous
.getMaxY())||
previous != null && previous.getOrientation().equals(Orientation.LEFT) && block.getOrientation().equals(Orientation.RIGHT) && equalsWithThreshold(block.getMaxY(), previous
.getMaxY())){
previous.add(block);
itty.remove();
continue;
@@ -155,12 +151,11 @@ public class BlockificationService {
previous = block;
}
return new Page(chunkBlockList1);
}
private boolean equalsWithThreshold(float f1, float f2) {
private boolean equalsWithThreshold(float f1, float f2){
return Math.abs(f1 - f2) < THRESHOLD;
}
@@ -202,13 +197,6 @@ public class BlockificationService {
textBlock.setHighestFontSize(fontSizeFrequencyCounter.getHighest());
}
if (textBlock != null && textBlock.getSequences() != null && textBlock.getSequences()
.stream()
.map(t -> round(t.getY1(), 3))
.collect(toSet())
.size() == 1) {
textBlock.getSequences().sort(Comparator.comparing(TextPositionSequence::getX1));
}
return textBlock;
}
@@ -303,30 +291,4 @@ public class BlockificationService {
return new Rectangle(minY, minX, maxX - minX, maxY - minY);
}
private void sortRotatedSequences(List<TextPositionSequence> sequences) {
List<TextPositionSequence> rotatedWords = new ArrayList<>();
Iterator<TextPositionSequence> itty = sequences.iterator();
while (itty.hasNext()) {
var pos = itty.next();
if (pos.getTextPositions().get(0).getDir() == 270) {
rotatedWords.add(pos);
itty.remove();
}
}
if (!rotatedWords.isEmpty() && !sequences.isEmpty()) {
rotatedWords.sort(Comparator.comparing(TextPositionSequence::getX1));
}
sequences.addAll(rotatedWords);
}
private double round(float value, int decimalPoints) {
var d = Math.pow(10, decimalPoints);
return Math.round(value * d) / d;
}
}
@@ -73,10 +73,8 @@ public class ClassificationService {
}
} else if (PositionUtils.isWithinBodyTextFrame(bodyTextFrame, textBlock) && textBlock.getMostPopularWordFontSize() > document
.getFontSizeCounter()
.getMostPopular() && PositionUtils.getApproxLineCount(textBlock) < 4.9 && (textBlock.getMostPopularWordStyle()
.equals("bold") || !document.getFontStyleCounter().getCountPerValue().containsKey("bold") && textBlock.getMostPopularWordFontSize() > document
.getFontSizeCounter()
.getMostPopular() + 1) && textBlock.getSequences().get(0).getTextPositions().get(0).getFontSizeInPt() >= textBlock.getMostPopularWordFontSize()) {
.getMostPopular() && PositionUtils.getApproxLineCount(textBlock) < 4.9 && textBlock.getMostPopularWordStyle()
.equals("bold")) {
for (int i = 1; i <= headlineFontSizes.size(); i++) {
if (textBlock.getMostPopularWordFontSize() == headlineFontSizes.get(i - 1)) {
@@ -88,7 +86,7 @@ public class ClassificationService {
.startsWith("Figure ") && PositionUtils.isWithinBodyTextFrame(bodyTextFrame, textBlock) && textBlock.getMostPopularWordStyle()
.equals("bold") && !document.getFontStyleCounter()
.getMostPopular()
.equals("bold") && PositionUtils.getApproxLineCount(textBlock) < 2.9 && textBlock.getSequences().get(0).getTextPositions().get(0).getFontSizeInPt() >= textBlock.getMostPopularWordFontSize()) {
.equals("bold") && PositionUtils.getApproxLineCount(textBlock) < 2.9) {
textBlock.setClassification("H " + (headlineFontSizes.size() + 1));
document.setHeadlines(true);
} else if (PositionUtils.isWithinBodyTextFrame(bodyTextFrame, textBlock) && textBlock.getMostPopularWordFontSize() == document
@@ -1,7 +1,6 @@
package com.iqser.red.service.redaction.v1.server.controller;
import com.iqser.red.commons.spring.ErrorMessage;
import com.iqser.red.service.redaction.v1.server.exception.RedactionLogNotFoundException;
import com.iqser.red.service.redaction.v1.server.exception.RulesValidationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
@@ -18,13 +17,6 @@ public class ControllerAdvice {
/* error handling */
@ResponseBody
@ResponseStatus(value = HttpStatus.NOT_FOUND)
@ExceptionHandler(value = RedactionLogNotFoundException.class)
public ErrorMessage handleRedactionLogNotFoundException(RedactionLogNotFoundException e) {
return new ErrorMessage(OffsetDateTime.now(), e.getMessage());
}
@ResponseBody
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(value = NullPointerException.class)
@@ -6,12 +6,12 @@ import com.iqser.red.service.redaction.v1.resources.RedactionResource;
import com.iqser.red.service.redaction.v1.server.classification.model.Document;
import com.iqser.red.service.redaction.v1.server.classification.model.Page;
import com.iqser.red.service.redaction.v1.server.exception.RedactionException;
import com.iqser.red.service.redaction.v1.server.exception.RedactionLogNotFoundException;
import com.iqser.red.service.redaction.v1.server.redaction.service.AnnotationService;
import com.iqser.red.service.redaction.v1.server.redaction.service.DictionaryService;
import com.iqser.red.service.redaction.v1.server.redaction.service.DroolsExecutionService;
import com.iqser.red.service.redaction.v1.server.redaction.service.RedactionLogMergeService;
import com.iqser.red.service.redaction.v1.server.segmentation.PdfSegmentationService;
import com.iqser.red.service.redaction.v1.server.settings.RedactionServiceSettings;
import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.AbstractTextContainer;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Table;
@@ -20,12 +20,12 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.io.MemoryUsageSetting;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.stream.Collectors;
@Slf4j
@RestController
@@ -147,44 +147,19 @@ public class RedactionController implements RedactionResource {
}
@Override
public RedactionLog getRedactionLog(@RequestBody RedactionRequest redactionRequest) {
public RedactionLog getRedactionLog(RedactionRequest redactionRequest) {
log.info("Requested preview for: {}", redactionRequest);
dictionaryService.updateDictionary(redactionRequest.getDossierTemplateId(), redactionRequest.getDossierId());
SectionGrid sectionGrid = null;
var redactionLog = redactionStorageService.getRedactionLog(redactionRequest.getDossierId(), redactionRequest.getFileId());
if (redactionLog == null) {
throw new RedactionLogNotFoundException();
}
if (redactionRequest.isWithSectionDataForManualRedactions()) {
sectionGrid = redactionStorageService.getSectionGrid(redactionRequest.getDossierId(), redactionRequest.getFileId());
if (sectionGrid.getSections().isEmpty()) {
log.info("SectionGrid does not have headlines set. Computing headlines now!");
var text = redactionStorageService.getText(redactionRequest.getDossierId(), redactionRequest.getFileId());
// enhance section grid with headline data
for (var sectionText : text.getSectionTexts()) {
sectionGrid.getSections().add(new SectionGrid.SectionGridSection(sectionText.getSectionNumber(),
sectionText.getHeadline(),
sectionText.getSectionAreas().stream().map(SectionArea::getPage).collect(Collectors.toSet()),
sectionText.getSectionAreas()));
}
redactionStorageService.storeObject(redactionRequest.getDossierId(), redactionRequest.getFileId(), FileType.SECTION_GRID, sectionGrid);
}
}
log.info("Loaded redaction log with computationalVersion: {}", redactionLog.getAnalysisVersion());
if (redactionLog.getAnalysisVersion() == 0) {
// old redaction logs are returned directly
return redactionLog;
} else {
return redactionLogMergeService.mergeRedactionLogData(redactionLog, sectionGrid, redactionRequest.getDossierTemplateId(), redactionRequest.getManualRedactions(), redactionRequest.getExcludedPages());
return redactionLogMergeService.mergeRedactionLogData(redactionLog, redactionRequest.getDossierTemplateId(), redactionRequest.getManualRedactions(), redactionRequest.getExcludedPages());
}
}
@@ -1,9 +0,0 @@
package com.iqser.red.service.redaction.v1.server.exception;
public class RedactionLogNotFoundException extends RuntimeException {
public RedactionLogNotFoundException() {
super("RedactionLog not found!");
}
}
@@ -1,33 +1,16 @@
package com.iqser.red.service.redaction.v1.server.parsing;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.iqser.red.service.redaction.v1.server.parsing.model.TextPositionSequence;
import com.iqser.red.service.redaction.v1.server.redaction.model.PdfImage;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Ruling;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.pdfbox.contentstream.operator.Operator;
import org.apache.pdfbox.contentstream.operator.OperatorName;
import org.apache.pdfbox.contentstream.operator.color.SetNonStrokingColor;
import org.apache.pdfbox.contentstream.operator.color.SetNonStrokingColorN;
import org.apache.pdfbox.contentstream.operator.color.SetNonStrokingColorSpace;
import org.apache.pdfbox.contentstream.operator.color.SetNonStrokingDeviceCMYKColor;
import org.apache.pdfbox.contentstream.operator.color.SetNonStrokingDeviceGrayColor;
import org.apache.pdfbox.contentstream.operator.color.SetNonStrokingDeviceRGBColor;
import org.apache.pdfbox.contentstream.operator.color.SetStrokingColor;
import org.apache.pdfbox.contentstream.operator.color.SetStrokingColorN;
import org.apache.pdfbox.contentstream.operator.color.SetStrokingColorSpace;
import org.apache.pdfbox.contentstream.operator.color.SetStrokingDeviceCMYKColor;
import org.apache.pdfbox.contentstream.operator.color.SetStrokingDeviceGrayColor;
import org.apache.pdfbox.contentstream.operator.color.SetStrokingDeviceRGBColor;
import org.apache.pdfbox.contentstream.operator.state.SetFlatness;
import org.apache.pdfbox.contentstream.operator.state.SetLineCapStyle;
import org.apache.pdfbox.contentstream.operator.state.SetLineDashPattern;
import org.apache.pdfbox.contentstream.operator.state.SetLineJoinStyle;
import org.apache.pdfbox.contentstream.operator.state.SetLineMiterLimit;
import org.apache.pdfbox.contentstream.operator.state.SetLineWidth;
import org.apache.pdfbox.contentstream.operator.state.SetRenderingIntent;
import org.apache.pdfbox.contentstream.operator.color.*;
import org.apache.pdfbox.contentstream.operator.state.*;
import org.apache.pdfbox.contentstream.operator.text.SetFontAndSize;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSName;
@@ -40,14 +23,12 @@ import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.TextPosition;
import org.apache.pdfbox.util.Matrix;
import com.iqser.red.service.redaction.v1.server.parsing.model.RedTextPosition;
import com.iqser.red.service.redaction.v1.server.parsing.model.TextPositionSequence;
import com.iqser.red.service.redaction.v1.server.redaction.model.PdfImage;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Ruling;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class PDFLinesTextStripper extends PDFTextStripper {
@@ -208,19 +189,16 @@ public class PDFLinesTextStripper extends PDFTextStripper {
COSName objectName = (COSName) arguments.get(0);
PDXObject xobject = getResources().getXObject(objectName);
if (xobject instanceof PDImageXObject) {
PDImageXObject image = (PDImageXObject) xobject;
PDImageXObject image = (PDImageXObject)xobject;
Matrix ctmNew = getGraphicsState().getCurrentTransformationMatrix();
Rectangle2D rect = new Rectangle2D.Float(ctmNew.getTranslateX(), ctmNew.getTranslateY(), ctmNew.getScaleX(), ctmNew
.getScaleY());
Rectangle2D rect = new Rectangle2D.Float(ctmNew.getTranslateX(), ctmNew.getTranslateY(), ctmNew.getScaleX(), ctmNew.getScaleY());
// Memory Hack - sofReference kills me
FieldUtils.writeField(image, "cachedImageSubsampling", -1, true);
if (rect.getHeight() > 2 && rect.getWidth() > 2) {
this.images.add(new PdfImage(image.getImage(), rect, pageNumber, image.getImage()
.getColorModel()
.hasAlpha()));
this.images.add(new PdfImage(image.getImage(), rect, pageNumber, image.getImage().getColorModel().hasAlpha()));
}
}
} catch (Exception e) {
@@ -229,6 +207,8 @@ public class PDFLinesTextStripper extends PDFTextStripper {
}
private float floatValue(COSBase value) {
if (value instanceof COSNumber) {
@@ -267,16 +247,8 @@ public class PDFLinesTextStripper extends PDFTextStripper {
public void writeString(String text, List<TextPosition> textPositions) throws IOException {
int startIndex = 0;
RedTextPosition previous = null;
for (int i = 0; i <= textPositions.size() - 1; i++) {
if (!textPositionSequences.isEmpty()) {
previous = textPositionSequences.get(textPositionSequences.size() - 1)
.getTextPositions()
.get(textPositionSequences.get(textPositionSequences.size() - 1).getTextPositions().size() - 1);
}
int charWidth = (int) textPositions.get(i).getWidthDirAdj();
if (charWidth < minCharWidth) {
minCharWidth = charWidth;
@@ -295,54 +267,42 @@ public class PDFLinesTextStripper extends PDFTextStripper {
if (i == 0 && (textPositions.get(i).getUnicode().equals(" ") || textPositions.get(i)
.getUnicode()
.equals("\u00A0") || textPositions.get(i)
.getUnicode()
.equals("\t"))) {
.equals("\u00A0"))) {
startIndex++;
continue;
}
// Strange but sometimes this is happening, for example: Metolachlor2.pdf
if (i > 0 && textPositions.get(i).getXDirAdj() < textPositions.get(i - 1).getXDirAdj()) {
if (i > 0 && textPositions.get(i).getX() < textPositions.get(i - 1).getX()) {
List<TextPosition> sublist = textPositions.subList(startIndex, i);
if (!(sublist.isEmpty() || sublist.size() == 1 && (sublist.get(0)
.getUnicode()
.equals(" ") || sublist.get(0).getUnicode().equals("\u00A0") || sublist.get(0).getUnicode().equals("\t")))) {
.equals(" ") || sublist.get(0).getUnicode().equals("\u00A0")))) {
textPositionSequences.add(new TextPositionSequence(sublist, pageNumber));
}
startIndex = i;
}
if (textPositions.get(i).getRotation() == 0 && i > 0 && textPositions.get(i)
.getX() > textPositions.get(i - 1).getEndX() + 1) {
if (textPositions.get(i).getRotation() == 0 && i > 0 && textPositions.get(i).getX() > textPositions.get(i - 1).getEndX() + 1) {
List<TextPosition> sublist = textPositions.subList(startIndex, i);
if (!(sublist.isEmpty() || sublist.size() == 1 && (sublist.get(0)
.getUnicode()
.equals(" ") || sublist.get(0).getUnicode().equals("\u00A0") || sublist.get(0).getUnicode().equals("\t")))) {
.equals(" ") || sublist.get(0).getUnicode().equals("\u00A0")))) {
textPositionSequences.add(new TextPositionSequence(sublist, pageNumber));
}
startIndex = i;
}
if (i > 0 && (textPositions.get(i).getUnicode().equals(" ") || textPositions.get(i)
.getUnicode()
.equals("\u00A0") || textPositions.get(i)
.getUnicode()
.equals("\t")) && i <= textPositions.size() - 2) {
.equals("\u00A0")) && i <= textPositions.size() - 2) {
List<TextPosition> sublist = textPositions.subList(startIndex, i);
if (!(sublist.isEmpty() || sublist.size() == 1 && (sublist.get(0)
.getUnicode()
.equals(" ") || sublist.get(0).getUnicode().equals("\u00A0") || sublist.get(0).getUnicode().equals("\t")))) {
// Remove false sequence ends (whitespaces)
if (previous != null && sublist.get(0).getYDirAdj() == previous.getYDirAdj() && sublist.get(0)
.getXDirAdj() - (previous.getXDirAdj() + previous.getWidthDirAdj()) < 0.01) {
for (TextPosition t : sublist) {
textPositionSequences.get(textPositionSequences.size() - 1).add(t);
}
} else {
textPositionSequences.add(new TextPositionSequence(sublist, pageNumber));
}
.equals(" ") || sublist.get(0).getUnicode().equals("\u00A0")))) {
textPositionSequences.add(new TextPositionSequence(sublist, pageNumber));
}
startIndex = i + 1;
}
@@ -351,23 +311,13 @@ public class PDFLinesTextStripper extends PDFTextStripper {
List<TextPosition> sublist = textPositions.subList(startIndex, textPositions.size());
if (!sublist.isEmpty() && (sublist.get(sublist.size() - 1)
.getUnicode()
.equals(" ") || sublist.get(sublist.size() - 1).getUnicode().equals("\u00A0") || sublist.get(sublist.size() - 1).getUnicode().equals("\t"))) {
.equals(" ") || sublist.get(sublist.size() - 1).getUnicode().equals("\u00A0"))) {
sublist = sublist.subList(0, sublist.size() - 1);
}
if (!(sublist.isEmpty() || sublist.size() == 1 && (sublist.get(0).getUnicode().equals(" ") || sublist.get(0)
.getUnicode()
.equals("\u00A0") || sublist.get(0)
.getUnicode()
.equals("\t")))) {
if (previous != null && sublist.get(0).getYDirAdj() == previous.getYDirAdj() && sublist.get(0)
.getXDirAdj() - (previous.getXDirAdj() + previous.getWidthDirAdj()) < 0.01) {
for (TextPosition t : sublist) {
textPositionSequences.get(textPositionSequences.size() - 1).add(t);
}
} else {
textPositionSequences.add(new TextPositionSequence(sublist, pageNumber));
}
.equals("\u00A0")))) {
textPositionSequences.add(new TextPositionSequence(sublist, pageNumber));
}
super.writeString(text);
}
@@ -21,8 +21,6 @@ public class RedTextPosition {
private float YDirAdj;
private float width;
private float heightDir;
private float widthDirAdj;
private float dir;
// not used in reanalysis
@JsonIgnore
@@ -1,7 +1,5 @@
package com.iqser.red.service.redaction.v1.server.parsing.model;
import static java.util.stream.Collectors.toSet;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.iqser.red.service.redaction.v1.model.Point;
@@ -138,13 +136,6 @@ public class TextPositionSequence implements CharSequence {
}
@JsonIgnore
public float getRotationAdjustedX() {
return textPositions.get(0).getXDirAdj();
}
@JsonIgnore
public float getY1() {
@@ -242,7 +233,7 @@ public class TextPositionSequence implements CharSequence {
float posYInit;
float posYEnd;
if (textPositions.get(0).getRotation() == 90 && textPositions.get(0).getDir() != 0.0f) {
if (textPositions.get(0).getRotation() == 90) {
posXEnd = textPositions.get(0).getYDirAdj() + 2;
posYInit = getY1();
posYEnd = textPositions.get(textPositions.size() - 1).getXDirAdj() - height + 4;
@@ -253,31 +244,9 @@ public class TextPositionSequence implements CharSequence {
posXInit = textPositions.get(0).getPageWidth() - textPositions.get(0).getYDirAdj() - 2;
posXEnd = textPositions.get(0).getPageWidth() - textPositions.get(textPositions.size() - 1)
.getYDirAdj() + height;
} else if(textPositions.get(0).getRotation() == 0 && textPositions.get(0).getDir() == 270f) {
posYInit = textPositions.get(0).getPageHeight() - getX1();
posYEnd = textPositions.get(0).getPageHeight() - getX2() - textPositions.get(0)
.getWidthDirAdj() - textPositions.get(textPositions.size() - 1).getWidthDirAdj() - 3;
posXInit = textPositions.get(0).getPageWidth() - textPositions.get(0).getYDirAdj() - 2;
posXEnd = textPositions.get(0).getPageWidth() - textPositions.get(textPositions.size() - 1)
.getYDirAdj() + height;
} else if(textPositions.get(0).getRotation() == 90 && textPositions.get(0).getDir() == 0.0f){
posXInit = textPositions.get(textPositions.size() - 1)
.getXDirAdj() + textPositions.get(textPositions.size() - 1).getHeightDir();
posXEnd = textPositions.get(0).getXDirAdj();
posYInit = textPositions.get(0).getPageHeight() - textPositions.get(0).getYDirAdj() - 2;
posYEnd = textPositions.get(0).getPageHeight() - textPositions.get(textPositions.size() - 1)
.getYDirAdj() + 2;
} else if(textPositions.get(0).getRotation() == 0 && textPositions.get(0).getDir() == 90f){
posYInit = getX1();
posYEnd = getX2() + textPositions.get(0)
.getWidthDirAdj() - textPositions.get(textPositions.size() - 1).getWidthDirAdj() - 3;
posXInit = textPositions.get(0).getYDirAdj() + 2;
posXEnd = textPositions.get(textPositions.size() - 1)
.getYDirAdj() - height;
}
else {
} else {
posXEnd = textPositions.get(textPositions.size() - 1)
.getXDirAdj() + textPositions.get(textPositions.size() - 1).getWidthDirAdj() + 1;
.getXDirAdj() + textPositions.get(textPositions.size() - 1).getWidth() + 1;
posYInit = textPositions.get(0).getPageHeight() - textPositions.get(0).getYDirAdj() - 2;
posYEnd = textPositions.get(0).getPageHeight() - textPositions.get(textPositions.size() - 1)
.getYDirAdj() + 2;
@@ -39,8 +39,6 @@ public class Entity implements ReasonHolder {
private boolean isDossierDictionaryEntry;
private boolean ignored;
public Entity(String word, String type, boolean redaction, String redactionReason, List<EntityPositionSequence> positionSequences, String headline, int matchedRule, int sectionNumber, String legalBasis, boolean isDictionaryEntry, String textBefore, String textAfter, Integer start, Integer end, boolean isDossierDictionaryEntry) {
@@ -20,7 +20,6 @@ public class Image implements ReasonHolder {
private int sectionNumber;
private String section;
private int page;
private boolean ignored;
private boolean hasTransparency;
}
@@ -1,6 +1,13 @@
package com.iqser.red.service.redaction.v1.server.redaction.model;
import static com.iqser.red.service.redaction.v1.server.redaction.model.Dictionary.RECOMMENDATION_PREFIX;
import com.iqser.red.service.redaction.v1.model.FileAttribute;
import com.iqser.red.service.redaction.v1.server.classification.model.TextBlock;
import com.iqser.red.service.redaction.v1.server.redaction.utils.EntitySearchUtils;
import com.iqser.red.service.redaction.v1.server.redaction.utils.Patterns;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.Collection;
@@ -13,16 +20,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import com.iqser.red.service.redaction.v1.model.FileAttribute;
import com.iqser.red.service.redaction.v1.server.classification.model.TextBlock;
import com.iqser.red.service.redaction.v1.server.redaction.utils.EntitySearchUtils;
import com.iqser.red.service.redaction.v1.server.redaction.utils.Patterns;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import static com.iqser.red.service.redaction.v1.server.redaction.model.Dictionary.RECOMMENDATION_PREFIX;
@Data
@Slf4j
@@ -61,57 +59,29 @@ public class Section {
private List<FileAttribute> fileAttributes = new ArrayList<>();
public boolean fileAttributeByIdEquals(String id, String value) {
public boolean fileAttributeByIdEquals(String id, String value){
return fileAttributes != null && fileAttributes.stream().filter(attribute -> id.equals(attribute.getId()) && value.equals(attribute.getValue())).findFirst().isPresent();
}
return fileAttributes != null && fileAttributes.stream()
.filter(attribute -> id.equals(attribute.getId()) && value.equals(attribute.getValue()))
.findFirst()
.isPresent();
public boolean fileAttributeByPlaceholderEquals(String placeholder, String value){
return fileAttributes != null && fileAttributes.stream().filter(attribute -> placeholder.equals(attribute.getPlaceholder()) && value.equals(attribute.getValue())).findFirst().isPresent();
}
public boolean fileAttributeByLabelEquals(String label, String value){
return fileAttributes != null && fileAttributes.stream().filter(attribute -> label.equals(attribute.getLabel()) && value.equals(attribute.getValue())).findFirst().isPresent();
}
public boolean fileAttributeByPlaceholderEquals(String placeholder, String value) {
return fileAttributes != null && fileAttributes.stream()
.filter(attribute -> placeholder.equals(attribute.getPlaceholder()) && value.equals(attribute.getValue()))
.findFirst()
.isPresent();
public boolean fileAttributeByIdEqualsIgnoreCase(String id, String value){
return fileAttributes != null && fileAttributes.stream().filter(attribute -> id.equals(attribute.getId()) && value.equalsIgnoreCase(attribute.getValue())).findFirst().isPresent();
}
public boolean fileAttributeByLabelEquals(String label, String value) {
return fileAttributes != null && fileAttributes.stream()
.filter(attribute -> label.equals(attribute.getLabel()) && value.equals(attribute.getValue()))
.findFirst()
.isPresent();
public boolean fileAttributeByPlaceholderEqualsIgnoreCase(String placeholder, String value){
return fileAttributes != null && fileAttributes.stream().filter(attribute -> placeholder.equals(attribute.getPlaceholder()) && value.equalsIgnoreCase(attribute.getValue())).findFirst().isPresent();
}
public boolean fileAttributeByIdEqualsIgnoreCase(String id, String value) {
return fileAttributes != null && fileAttributes.stream()
.filter(attribute -> id.equals(attribute.getId()) && value.equalsIgnoreCase(attribute.getValue()))
.findFirst()
.isPresent();
}
public boolean fileAttributeByPlaceholderEqualsIgnoreCase(String placeholder, String value) {
return fileAttributes != null && fileAttributes.stream()
.filter(attribute -> placeholder.equals(attribute.getPlaceholder()) && value.equalsIgnoreCase(attribute.getValue()))
.findFirst()
.isPresent();
}
public boolean fileAttributeByLabelEqualsIgnoreCase(String label, String value) {
return fileAttributes != null && fileAttributes.stream()
.filter(attribute -> label.equals(attribute.getLabel()) && value.equalsIgnoreCase(attribute.getValue()))
.findFirst()
.isPresent();
public boolean fileAttributeByLabelEqualsIgnoreCase(String label, String value){
return fileAttributes != null && fileAttributes.stream().filter(attribute -> label.equals(attribute.getLabel()) && value.equalsIgnoreCase(attribute.getValue())).findFirst().isPresent();
}
@@ -134,13 +104,13 @@ public class Section {
public boolean matchesType(String type) {
return entities.stream().anyMatch(entity -> !entity.isIgnored() && entity.getType().equals(type));
return entities.stream().anyMatch(entity -> entity.getType().equals(type));
}
public boolean matchesImageType(String type) {
return images.stream().anyMatch(image -> !image.isIgnored() && image.getType().equals(type));
return images.stream().anyMatch(image -> image.getType().equals(type));
}
@@ -152,18 +122,6 @@ public class Section {
public void expandByRegEx(String type, String pattern, boolean patternCaseInsensitive, int group) {
expandByRegEx(type, pattern, patternCaseInsensitive, group, null);
}
public void expandByRegEx(String type, String pattern, boolean patternCaseInsensitive, int group,
String withoutPattern) {
Pattern compiledWithoutPattern = null;
if (withoutPattern != null) {
compiledWithoutPattern = Patterns.getCompiledPattern(withoutPattern, patternCaseInsensitive);
}
Pattern compiledPattern = Patterns.getCompiledPattern(pattern, patternCaseInsensitive);
Set<Entity> expanded = new HashSet<>();
@@ -173,21 +131,14 @@ public class Section {
continue;
}
if (withoutPattern != null) {
Matcher matcherWithout = compiledWithoutPattern.matcher(entity.getWord());
if (matcherWithout.find()) {
continue;
}
}
Matcher matcher = compiledPattern.matcher(entity.getTextAfter());
while (matcher.find()) {
String match = matcher.group(group);
if (StringUtils.isNotBlank(match)) {
Set<Entity> expandedEntities = findEntities(entity.getWord() + match, type, false, entity.isRedaction(), entity.getMatchedRule(), entity.getRedactionReason(), entity.getLegalBasis());
expanded.addAll(EntitySearchUtils.findNonOverlappingMatchEntities(entities, expandedEntities));
expanded.addAll(findEntities(entity.getWord() + match, type, false, entity.isRedaction(), entity.getMatchedRule(), entity
.getRedactionReason(), entity.getLegalBasis()));
}
}
}
@@ -253,12 +204,6 @@ public class Section {
}
public void ignore(String type) {
entities.removeIf(entity -> entity.getType().equals(type));
}
public void expandToHintAnnotationByRegEx(String type, String pattern, boolean patternCaseInsensitive, int group,
String asType) {
@@ -1,12 +1,10 @@
package com.iqser.red.service.redaction.v1.server.redaction.service;
import com.iqser.red.service.redaction.v1.model.AnalyzeResult;
import com.iqser.red.service.redaction.v1.model.RedactionChangeLog;
import com.iqser.red.service.redaction.v1.model.RedactionLog;
import com.iqser.red.service.redaction.v1.model.RedactionLogEntry;
import com.iqser.red.service.redaction.v1.server.settings.RedactionServiceSettings;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@@ -17,15 +15,9 @@ public class AnalyzeResponseService {
private final RedactionServiceSettings redactionServiceSettings;
public AnalyzeResult createAnalyzeResponse(String dossierId, String fileId, long duration, int pageCount,
RedactionLog redactionLog, RedactionChangeLog redactionChangeLog) {
RedactionLog redactionLog, boolean hasUpdates) {
boolean hasUpdates = redactionChangeLog != null && redactionChangeLog.getRedactionLogEntry() != null && !redactionChangeLog
.getRedactionLogEntry()
.isEmpty() && redactionChangeLog.getRedactionLogEntry()
.stream()
.anyMatch(entry -> !entry.getType().equals("false_positive"));
return AnalyzeResult.builder()
.dossierId(dossierId)
.fileId(fileId)
@@ -105,9 +105,9 @@ public class EntityRedactionService {
List<Table> tables = paragraph.getTables();
for (Table table : tables) {
if (table.getColCount() == 2) {
sectionSearchableTextPairs.addAll(processTableAsOneText(classifiedDoc, table, sectionNumber, dictionary, local, hintsPerSectionNumber, fileAttributes, manualRedactions));
sectionSearchableTextPairs.addAll(processTableAsOneText(classifiedDoc, table, sectionNumber, dictionary, local, hintsPerSectionNumber, fileAttributes));
} else {
sectionSearchableTextPairs.addAll(processTablePerRow(classifiedDoc, table, sectionNumber, dictionary, local, hintsPerSectionNumber, fileAttributes, manualRedactions));
sectionSearchableTextPairs.addAll(processTablePerRow(classifiedDoc, table, sectionNumber, dictionary, local, hintsPerSectionNumber, fileAttributes));
}
sectionNumber.incrementAndGet();
}
@@ -178,7 +178,7 @@ public class EntityRedactionService {
AtomicInteger sectionNumber, Dictionary dictionary,
boolean local,
Map<Integer, Set<Entity>> hintsPerSectionNumber,
List<FileAttribute> fileAttributes, ManualRedactions manualRedactions) {
List<FileAttribute> fileAttributes) {
List<SectionSearchableTextPair> sectionSearchableTextPairs = new ArrayList<>();
@@ -229,31 +229,6 @@ public class EntityRedactionService {
Set<Entity> rowEntities = findEntities(searchableRow, table.getHeadline(), sectionNumber.intValue(), dictionary, local);
surroundingWordsService.addSurroundingText(rowEntities, searchableRow, dictionary, cellStarts);
if (!local && manualRedactions != null) {
var approvedForceRedactions = manualRedactions.getForceRedacts().stream()
.filter(fr -> fr.getStatus() == Status.APPROVED)
.filter(fr -> fr.getRequestDate() != null)
.collect(Collectors.toList());
// only approved id removals, that haven't been forced back afterwards
var idsToRemove = manualRedactions.getIdsToRemove().stream()
.filter(idr -> idr.getStatus() == Status.APPROVED)
.filter(idr -> idr.getRequestDate() != null)
.filter(idr -> approvedForceRedactions.stream().noneMatch(forceRedact -> forceRedact.getRequestDate().isAfter(idr.getRequestDate())))
.map(IdRemoval::getId).collect(Collectors.toSet());
log.info("Removed Ids: {}", idsToRemove);
rowEntities.forEach(entity ->
entity.getPositionSequences().forEach(ps -> {
if (idsToRemove.contains(ps.getId())) {
entity.setIgnored(true);
}
}));
}
sectionSearchableTextPairs.add(new SectionSearchableTextPair(Section.builder()
.isLocal(local)
.dictionaryTypes(dictionary.getTypes())
@@ -291,7 +266,7 @@ public class EntityRedactionService {
AtomicInteger sectionNumber, Dictionary dictionary,
boolean local,
Map<Integer, Set<Entity>> hintsPerSectionNumber,
List<FileAttribute> fileAttributes, ManualRedactions manualRedactions) {
List<FileAttribute> fileAttributes) {
List<SectionSearchableTextPair> sectionSearchableTextPairs = new ArrayList<>();
SearchableText entireTableText = new SearchableText();
@@ -322,31 +297,6 @@ public class EntityRedactionService {
Set<Entity> rowEntities = findEntities(entireTableText, table.getHeadline(), sectionNumber.intValue(), dictionary, local);
surroundingWordsService.addSurroundingText(rowEntities, entireTableText, dictionary);
if (!local && manualRedactions != null) {
var approvedForceRedactions = manualRedactions.getForceRedacts().stream()
.filter(fr -> fr.getStatus() == Status.APPROVED)
.filter(fr -> fr.getRequestDate() != null)
.collect(Collectors.toList());
// only approved id removals, that haven't been forced back afterwards
var idsToRemove = manualRedactions.getIdsToRemove().stream()
.filter(idr -> idr.getStatus() == Status.APPROVED)
.filter(idr -> idr.getRequestDate() != null)
.filter(idr -> approvedForceRedactions.stream().noneMatch(forceRedact -> forceRedact.getRequestDate().isAfter(idr.getRequestDate())))
.map(IdRemoval::getId).collect(Collectors.toSet());
log.info("Removed Ids: {}", idsToRemove);
rowEntities.forEach(entity ->
entity.getPositionSequences().forEach(ps -> {
if (idsToRemove.contains(ps.getId())) {
entity.setIgnored(true);
}
}));
}
sectionSearchableTextPairs.add(new SectionSearchableTextPair(Section.builder()
.isLocal(local)
.dictionaryTypes(dictionary.getTypes())
@@ -403,31 +353,6 @@ public class EntityRedactionService {
Set<Entity> entities = findEntities(searchableText, headline, sectionNumber.intValue(), dictionary, local);
surroundingWordsService.addSurroundingText(entities, searchableText, dictionary);
if (!local && manualRedactions != null) {
var approvedForceRedactions = manualRedactions.getForceRedacts().stream()
.filter(fr -> fr.getStatus() == Status.APPROVED)
.filter(fr -> fr.getRequestDate() != null)
.collect(Collectors.toList());
// only approved id removals, that haven't been forced back afterwards
var idsToRemove = manualRedactions.getIdsToRemove().stream()
.filter(idr -> idr.getStatus() == Status.APPROVED)
.filter(idr -> idr.getRequestDate() != null)
.filter(idr -> approvedForceRedactions.stream().noneMatch(forceRedact -> forceRedact.getRequestDate().isAfter(idr.getRequestDate())))
.map(IdRemoval::getId).collect(Collectors.toSet());
log.info("Removed Ids: {}", idsToRemove);
entities.forEach(entity ->
entity.getPositionSequences().forEach(ps -> {
if (idsToRemove.contains(ps.getId())) {
entity.setIgnored(true);
}
}));
}
return new SectionSearchableTextPair(Section.builder()
.isLocal(local)
.dictionaryTypes(dictionary.getTypes())
@@ -14,9 +14,11 @@ import com.iqser.red.service.redaction.v1.server.redaction.utils.IdBuilder;
import com.iqser.red.service.redaction.v1.server.segmentation.PdfSegmentationService;
import com.iqser.red.service.redaction.v1.server.settings.RedactionServiceSettings;
import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.kie.api.runtime.KieContainer;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
@@ -76,26 +78,17 @@ public class ReanalyzeService {
log.info("Analyzed with rules {} and dictionary {} for dossierTemplate: {}", classifiedDoc.getRulesVersion(), classifiedDoc
.getDictionaryVersion(), analyzeRequest.getDossierTemplateId());
// first create changelog - this only happens when we migrate files analyzed via the old process and we don't want to loose changeLog data
var changeLog = redactionChangeLogService.createAndStoreChangeLog(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), redactionLog);
// store redactionLog
var redactionLogChange = redactionChangeLogService.computeChanges(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), redactionLog);
redactionLog = redactionLogChange.getRedactionLog();
redactionStorageService.storeObject(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), FileType.REDACTION_LOG, redactionLog);
redactionStorageService.storeObject(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), FileType.TEXT, new Text(pageCount, classifiedDoc
.getSectionText()));
// enhance section grid with headline data
classifiedDoc.getSectionText().forEach(sectionText -> {
classifiedDoc
.getSectionGrid().getSections().add(new SectionGrid.SectionGridSection(sectionText.getSectionNumber(),
sectionText.getHeadline(),
sectionText.getSectionAreas().stream().map(SectionArea::getPage).collect(Collectors.toSet()),
sectionText.getSectionAreas()));
});
redactionStorageService.storeObject(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), FileType.SECTION_GRID, classifiedDoc
.getSectionGrid());
long duration = System.currentTimeMillis() - startTime;
return analyzeResponseService.createAnalyzeResponse(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), duration, pageCount, redactionLog, changeLog);
return analyzeResponseService.createAnalyzeResponse(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), duration, pageCount, redactionLog, redactionLogChange.isHasChanges());
}
@@ -213,45 +206,19 @@ public class ReanalyzeService {
surroundingWordsService.addSurroundingText(entities, reanalysisSection.getSearchableText(), dictionary);
}
if (!local && analyzeRequest.getManualRedactions() != null) {
var approvedForceRedactions = analyzeRequest.getManualRedactions().getForceRedacts().stream()
.filter(fr -> fr.getStatus() == Status.APPROVED)
.filter(fr -> fr.getRequestDate() != null)
.collect(Collectors.toList());
// only approved id removals, that haven't been forced back afterwards
var idsToRemove = analyzeRequest.getManualRedactions().getIdsToRemove().stream()
.filter(idr -> idr.getStatus() == Status.APPROVED)
.filter(idr -> idr.getRequestDate() != null)
.filter(idr -> approvedForceRedactions.stream().noneMatch(forceRedact -> forceRedact.getRequestDate().isAfter(idr.getRequestDate())))
.map(IdRemoval::getId).collect(Collectors.toSet());
log.info("Removed Ids: {}", idsToRemove);
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);
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());
}
}
}
entities.forEach(entity ->
entity.getPositionSequences().forEach(ps -> {
if (idsToRemove.contains(ps.getId())) {
entity.setIgnored(true);
}
}));
}
sectionSearchableTextPairs.add(new SectionSearchableTextPair(Section.builder()
@@ -299,13 +266,13 @@ public class ReanalyzeService {
excludeExcludedPages(redactionLog, analyzeRequest.getExcludedPages());
var changeLog = redactionChangeLogService.createAndStoreChangeLog(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), redactionLog);
redactionStorageService.storeObject(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), FileType.REDACTION_LOG, redactionLog);
var redactionLogChange = redactionChangeLogService.computeChanges(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), redactionLog);
redactionStorageService.storeObject(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), FileType.REDACTION_LOG, redactionLogChange.getRedactionLog());
long duration = System.currentTimeMillis() - startTime;
return analyzeResponseService.createAnalyzeResponse(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), duration, text
.getNumberOfPages(), redactionLog, changeLog);
.getNumberOfPages(), redactionLogChange.getRedactionLog(), redactionLogChange.isHasChanges());
}
@@ -316,12 +283,12 @@ public class ReanalyzeService {
}
return Stream.concat(manualRedactions.getManualLegalBasisChanges()
.stream()
.map(ManualLegalBasisChange::getId), Stream.concat(manualRedactions.getImageRecategorizations()
.stream()
.map(ManualImageRecategorization::getId), Stream.concat(manualRedactions.getIdsToRemove()
.stream()
.map(IdRemoval::getId), manualRedactions.getForceRedacts().stream().map(ManualForceRedact::getId))))
.stream()
.map(ManualLegalBasisChange::getId), Stream.concat(manualRedactions.getImageRecategorizations()
.stream()
.map(ManualImageRecategorization::getId), Stream.concat(manualRedactions.getIdsToRemove()
.stream()
.map(IdRemoval::getId), manualRedactions.getForceRedacts().stream().map(ManualForceRedact::getId))))
.collect(Collectors.toSet());
}
@@ -344,12 +311,10 @@ public class ReanalyzeService {
private void excludeExcludedPages(RedactionLog redactionLog, Set<Integer> excludedPages) {
if (excludedPages != null && !excludedPages.isEmpty()) {
redactionLog.getRedactionLogEntry().forEach(entry -> entry.getPositions().forEach(pos -> {
if (excludedPages.contains(pos.getPage())) {
entry.setExcluded(true);
}
}));
if(excludedPages != null && !excludedPages.isEmpty()) {
redactionLog.getRedactionLogEntry().forEach(entry -> entry.getPositions().forEach(pos -> { if (excludedPages.contains(pos.getPage())) {
entry.setExcluded(true);
}}));
}
}
@@ -1,19 +1,25 @@
package com.iqser.red.service.redaction.v1.server.redaction.service;
import com.iqser.red.service.file.management.v1.api.model.FileType;
import com.iqser.red.service.redaction.v1.model.ChangeType;
import com.iqser.red.service.redaction.v1.model.RedactionChangeLog;
import com.iqser.red.service.redaction.v1.model.RedactionChangeLogEntry;
import com.iqser.red.service.redaction.v1.model.RedactionLog;
import com.iqser.red.service.redaction.v1.model.RedactionLogEntry;
import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.time.OffsetDateTime;
import java.util.ArrayList;
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;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import com.iqser.red.service.redaction.v1.model.Change;
import com.iqser.red.service.redaction.v1.model.ChangeType;
import com.iqser.red.service.redaction.v1.model.RedactionLog;
import com.iqser.red.service.redaction.v1.model.RedactionLogChanges;
import com.iqser.red.service.redaction.v1.model.RedactionLogEntry;
import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
@@ -22,76 +28,77 @@ public class RedactionChangeLogService {
private final RedactionStorageService redactionStorageService;
public RedactionChangeLog createAndStoreChangeLog(String dossierId, String fileId, RedactionLog currentRedactionLog) {
try {
RedactionLog previousRedactionLog = redactionStorageService.getRedactionLog(dossierId, fileId);
var changeLog = createChangeLog(currentRedactionLog, previousRedactionLog);
redactionStorageService.storeObject(dossierId, fileId, FileType.REDACTION_CHANGELOG, changeLog);
return changeLog;
} catch (Exception e) {
log.debug("Previous redaction log not available");
return null;
}
}
private RedactionChangeLog createChangeLog(RedactionLog currentRedactionLog, RedactionLog previousRedactionLog) {
public RedactionLogChanges computeChanges(String dossierId, String fileId, RedactionLog currentRedactionLog) {
RedactionLog previousRedactionLog = redactionStorageService.getRedactionLog(dossierId, fileId);
if (previousRedactionLog == null) {
return null;
currentRedactionLog.getRedactionLogEntry().forEach(entry -> {
entry.getChanges().add(new Change(ChangeType.ADDED, OffsetDateTime.now()));
});
return new RedactionLogChanges(currentRedactionLog, false);
}
List<RedactionLogEntry> added = new ArrayList<>(currentRedactionLog.getRedactionLogEntry());
added.removeAll(previousRedactionLog.getRedactionLogEntry());
List<RedactionLogEntry> notRemovedPreviousEntries = previousRedactionLog.getRedactionLogEntry()
.stream()
.filter(entry -> !entry.getChanges()
.get(entry.getChanges().size() - 1)
.getType()
.equals(ChangeType.REMOVED))
.collect(Collectors.toList());
List<RedactionLogEntry> removed = new ArrayList<>(previousRedactionLog.getRedactionLogEntry());
Set<RedactionLogEntry> added = new HashSet<>(currentRedactionLog.getRedactionLogEntry());
added.removeAll(notRemovedPreviousEntries);
Set<RedactionLogEntry> removed = new HashSet<>(notRemovedPreviousEntries);
removed.removeAll(currentRedactionLog.getRedactionLogEntry());
List<RedactionChangeLogEntry> changeLogEntries = added.stream()
.map(entry -> convert(entry, ChangeType.ADDED))
.collect(Collectors.toList());
changeLogEntries.addAll(removed.stream()
.map(entry -> convert(entry, ChangeType.REMOVED))
.collect(Collectors.toList()));
Map<String, RedactionLogEntry> addedIds = new HashMap<>();
added.forEach(entry -> {
addedIds.put(entry.getId(), entry);
});
return new RedactionChangeLog(changeLogEntries,
currentRedactionLog.getDictionaryVersion(),
currentRedactionLog.getDossierDictionaryVersion(),
currentRedactionLog.getRulesVersion(),
currentRedactionLog.getLegalBasisVersion());
}
Set<String> removedIds = new HashSet<>();
removed.forEach(entry -> {
removedIds.add(entry.getId());
});
List<RedactionLogEntry> newRedactionLogEntries = previousRedactionLog.getRedactionLogEntry();
private RedactionChangeLogEntry convert(RedactionLogEntry entry, ChangeType changeType) {
List<RedactionLogEntry> toRemove = new ArrayList<>();
newRedactionLogEntries.forEach(entry -> {
if (removedIds.contains(entry.getId()) && addedIds.containsKey(entry.getId())) {
List<Change> changes = entry.getChanges();
changes.add(new Change(ChangeType.CHANGED, OffsetDateTime.now()));
var newEntry = addedIds.get(entry.getId());
newEntry.setChanges(changes);
addedIds.put(entry.getId(), newEntry);
toRemove.add(entry);
} else if (removedIds.contains(entry.getId())) {
entry.getChanges().add(new Change(ChangeType.REMOVED, OffsetDateTime.now()));
} else if (addedIds.containsKey(entry.getId())) {
List<Change> changes = entry.getChanges();
changes.add(new Change(ChangeType.ADDED, OffsetDateTime.now()));
var newEntry = addedIds.get(entry.getId());
newEntry.setChanges(changes);
addedIds.put(entry.getId(), newEntry);
toRemove.add(entry);
}
});
return RedactionChangeLogEntry.builder()
.id(entry.getId())
.type(entry.getType())
.value(entry.getValue())
.reason(entry.getReason())
.matchedRule(entry.getMatchedRule())
.legalBasis(entry.getLegalBasis())
.redacted(entry.isRedacted())
.isHint(entry.isHint())
.isRecommendation(entry.isRecommendation())
.section(entry.getSection())
.color(entry.getColor())
.positions(entry.getPositions())
.sectionNumber(entry.getSectionNumber())
.manual(entry.isManual())
.status(entry.getStatus())
.manualRedactionType(entry.getManualRedactionType())
.isDictionaryEntry(entry.isDictionaryEntry())
.textBefore(entry.getTextBefore())
.textAfter(entry.getTextAfter())
.comments(entry.getComments())
.changeType(changeType)
.isDossierDictionaryEntry(entry.isDossierDictionaryEntry())
.excluded(entry.isExcluded())
.build();
newRedactionLogEntries.removeAll(toRemove);
addedIds.forEach((k, v) -> {
if(v.getChanges().isEmpty()) {
v.getChanges().add(new Change(ChangeType.ADDED, OffsetDateTime.now()));
}
newRedactionLogEntries.add(v);
});
currentRedactionLog.setRedactionLogEntry(newRedactionLogEntries);
return new RedactionLogChanges(currentRedactionLog, !addedIds.isEmpty() || !removedIds.isEmpty());
}
}
@@ -1,15 +1,5 @@
package com.iqser.red.service.redaction.v1.server.redaction.service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import com.iqser.red.service.redaction.v1.model.CellRectangle;
import com.iqser.red.service.redaction.v1.model.Point;
import com.iqser.red.service.redaction.v1.model.Rectangle;
@@ -27,8 +17,16 @@ import com.iqser.red.service.redaction.v1.server.redaction.utils.IdBuilder;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.AbstractTextContainer;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Cell;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Table;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
@@ -56,8 +54,7 @@ public class RedactionLogCreatorService {
}
public List<RedactionLogEntry> addImageEntries(Map<Integer, Set<Image>> images, int pageNumber,
String dossierTemplateId) {
public List<RedactionLogEntry> addImageEntries(Map<Integer, Set<Image>> images, int pageNumber, String dossierTemplateId) {
List<RedactionLogEntry> redactionLogEntities = new ArrayList<>();
@@ -82,12 +79,11 @@ public class RedactionLogCreatorService {
.getX(), (float) image.getPosition().getY()), (float) image.getPosition()
.getWidth(), (float) image.getPosition().getHeight(), pageNumber)))
.sectionNumber(image.getSectionNumber())
//.section(image.getSection())
// RED-2622
.section("Image:" + image.getType())
.section(image.getSection())
.imageHasTransparency(image.isHasTransparency())
.build();
redactionLogEntities.add(redactionLogEntry);
}
@@ -105,6 +101,7 @@ public class RedactionLogCreatorService {
entityLoop:
for (Entity entity : entities.get(page)) {
for (EntityPositionSequence entityPositionSequence : entity.getPositionSequences()) {
RedactionLogEntry redactionLogEntry = createRedactionLogEntry(entity, dossierTemplateId);
@@ -124,10 +121,12 @@ public class RedactionLogCreatorService {
.flatMap(seq -> seq.getTextPositions().stream())
.collect(Collectors.toList()), page);
redactionLogEntry.getPositions().addAll(rectanglesPerLine);
}
// FIXME ids should never be null. Figure out why this happens.
if (redactionLogEntry.getId() != null) {
redactionLogEntities.add(redactionLogEntry);
@@ -145,27 +144,16 @@ public class RedactionLogCreatorService {
if (textPositions.size() == 1) {
rectangles.add(TextPositionSequence.fromData(textPositions, page).getRectangle());
} else {
float x = textPositions.get(0).getXDirAdj();
float y = textPositions.get(0).getYDirAdj();
float width = textPositions.get(0).getWidth();
float height = textPositions.get(0).getHeightDir();
int startIndex = 0;
for (int i = 1; i < textPositions.size(); i++) {
float xDirAdj = textPositions.get(i).getXDirAdj();
float yDirAdj = textPositions.get(i).getYDirAdj();
float widthDir = textPositions.get(i).getWidth();
float heightDir = textPositions.get(i).getHeightDir();
if (!(isCharInSameLine(y, yDirAdj, height, heightDir) && isCharClose(x, xDirAdj, width))) {
if (yDirAdj != y) {
rectangles.add(TextPositionSequence.fromData(textPositions.subList(startIndex, i), page)
.getRectangle());
y = yDirAdj;
width = widthDir;
height = heightDir;
startIndex = i;
}
x = xDirAdj;
}
if (startIndex != textPositions.size()) {
rectangles.add(TextPositionSequence.fromData(textPositions.subList(startIndex, textPositions.size()), page)
@@ -177,34 +165,6 @@ public class RedactionLogCreatorService {
}
private boolean isCharClose(float x, float xDirAdj, float width) {
float max = x + (5 * width);
if (xDirAdj < max) {
return true;
}
return false;
}
private boolean isCharInSameLine(float y, float yCompare, float height, float heightCompare) {
float offsetHeight = height / 2;
float minHeight = height - offsetHeight;
float maxHeight = height + offsetHeight;
float offsetY = height / 10;
float minY = y - offsetY;
float maxY = y + offsetY;
if (yCompare > minY && yCompare < maxY && heightCompare > minHeight && heightCompare < maxHeight) {
return true;
}
return false;
}
private RedactionLogEntry createRedactionLogEntry(Entity entity, String dossierTemplateId) {
return RedactionLogEntry.builder()
@@ -246,8 +206,8 @@ public class RedactionLogCreatorService {
classifiedDoc.getSectionGrid()
.getRectanglesPerPage()
.computeIfAbsent(page, (x) -> new ArrayList<>())
.add(new SectionRectangle(new Point(textBlock.getMinX(), textBlock.getMinY()), textBlock.getWidth(), textBlock.getHeight(), i + 1, paragraph.getPageBlocks()
.size()));
.add(new SectionRectangle(new Point(textBlock.getMinX(), textBlock.getMinY()), textBlock.getWidth(), textBlock
.getHeight(), i + 1, paragraph.getPageBlocks().size()));
} else if (textBlock instanceof Table) {
@@ -255,7 +215,8 @@ public class RedactionLogCreatorService {
for (List<Cell> row : ((Table) textBlock).getRows()) {
for (Cell cell : row) {
if (cell != null) {
cellRectangles.add(new CellRectangle(new Point((float) cell.getX(), (float) cell.getY()), (float) cell.getWidth(), (float) cell.getHeight()));
cellRectangles.add(new CellRectangle(new Point((float) cell.getX(), (float) cell.getY()), (float) cell
.getWidth(), (float) cell.getHeight()));
}
}
}
@@ -263,8 +224,8 @@ public class RedactionLogCreatorService {
classifiedDoc.getSectionGrid()
.getRectanglesPerPage()
.computeIfAbsent(page, (x) -> new ArrayList<>())
.add(new SectionRectangle(new Point(textBlock.getMinX(), textBlock.getMinY()), textBlock.getWidth(), textBlock.getHeight(), i + 1, paragraph.getPageBlocks()
.size(), cellRectangles));
.add(new SectionRectangle(new Point(textBlock.getMinX(), textBlock.getMinY()), textBlock.getWidth(), textBlock
.getHeight(), i + 1, paragraph.getPageBlocks().size(), cellRectangles));
}
}
@@ -292,4 +253,5 @@ public class RedactionLogCreatorService {
return dictionaryService.isRecommendation(type, dossierTemplateId);
}
}
@@ -1,15 +1,31 @@
package com.iqser.red.service.redaction.v1.server.redaction.service;
import com.iqser.red.service.redaction.v1.model.*;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.stereotype.Service;
import com.iqser.red.service.redaction.v1.model.Comment;
import com.iqser.red.service.redaction.v1.model.IdRemoval;
import com.iqser.red.service.redaction.v1.model.ManualForceRedact;
import com.iqser.red.service.redaction.v1.model.ManualImageRecategorization;
import com.iqser.red.service.redaction.v1.model.ManualLegalBasisChange;
import com.iqser.red.service.redaction.v1.model.ManualRedactionEntry;
import com.iqser.red.service.redaction.v1.model.ManualRedactionType;
import com.iqser.red.service.redaction.v1.model.ManualRedactions;
import com.iqser.red.service.redaction.v1.model.RedactionLog;
import com.iqser.red.service.redaction.v1.model.RedactionLogEntry;
import com.iqser.red.service.redaction.v1.model.Status;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.OffsetDateTime;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Service
@@ -17,15 +33,15 @@ import java.util.stream.Collectors;
public class RedactionLogMergeService {
private final DictionaryService dictionaryService;
private final SectionTextService sectionTextService;
public RedactionLog mergeRedactionLogData(RedactionLog redactionLog, SectionGrid sectionGrid, String dossierTemplateId,
public RedactionLog mergeRedactionLogData(RedactionLog redactionLog, String dossierTemplateId,
ManualRedactions manualRedactions, Set<Integer> excludedPages) {
log.info("Merging Redaction log with manual redactions {}", manualRedactions);
if (manualRedactions != null) {
var manualRedactionLogEntries = addManualAddEntries(sectionGrid, manualRedactions.getEntriesToAdd(), manualRedactions.getComments(), dossierTemplateId);
var manualRedactionLogEntries = addManualAddEntries(manualRedactions.getEntriesToAdd(), manualRedactions.getComments(), dossierTemplateId);
redactionLog.getRedactionLogEntry().addAll(manualRedactionLogEntries);
@@ -50,14 +66,6 @@ public class RedactionLogMergeService {
}
Set<String> processedIds = new HashSet<>();
redactionLog.getRedactionLogEntry().removeIf(entry -> {
if(processedIds.contains(entry.getId())){
return true;
}
processedIds.add(entry.getId());
return false;
});
return redactionLog;
}
@@ -107,16 +115,6 @@ public class RedactionLogMergeService {
if (imageRecategorization.getStatus().equals(Status.APPROVED)) {
redactionLogEntry.setStatus(Status.APPROVED);
redactionLogEntry.setType(imageRecategorization.getType());
redactionLogEntry.setHasBeenRecategorized(true);
if (dictionaryService.isHint(imageRecategorization.getType(), dossierTemplateId)) {
redactionLogEntry.setRedacted(false);
redactionLogEntry.setHint(true);
} else {
redactionLogEntry.setHint(false);
}
redactionLogEntry.setSection("Image:" + redactionLogEntry.getType());
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", recategorized by manual override");
} else if (imageRecategorization.getStatus().equals(Status.REQUESTED)) {
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", requested to recategorize");
@@ -143,8 +141,6 @@ 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");
redactionLogEntry.setStatus(Status.REQUESTED);
@@ -166,20 +162,12 @@ public class RedactionLogMergeService {
var manualForceRedact = (ManualForceRedact) mrw.getItem();
String manualOverrideReason = null;
if (manualForceRedact.getStatus().equals(Status.APPROVED)) {
// Forcing a skipped hint should result in a hint
if (dictionaryService.isHint(redactionLogEntry.getType(), dossierTemplateId)) {
redactionLogEntry.setHint(true);
} else {
redactionLogEntry.setRedacted(true);
}
redactionLogEntry.setRedacted(true);
redactionLogEntry.setStatus(Status.APPROVED);
redactionLogEntry.setColor(getColor(redactionLogEntry.getType(), dossierTemplateId, false, redactionLogEntry
.isRedacted(), false));
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", forced by manual override");
redactionLogEntry.setLegalBasis(manualForceRedact.getLegalBasis());
redactionLogEntry.setHasBeenForced(true);
} else if (manualForceRedact.getStatus().equals(Status.REQUESTED)) {
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", requested to force redact");
redactionLogEntry.setStatus(Status.REQUESTED);
@@ -202,16 +190,8 @@ public class RedactionLogMergeService {
String manualOverrideReason = null;
if (manualLegalBasisChange.getStatus().equals(Status.APPROVED)) {
redactionLogEntry.setStatus(Status.APPROVED);
redactionLogEntry.setRedacted(true);
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", legal basis was manually changed");
redactionLogEntry.setLegalBasis(manualLegalBasisChange.getLegalBasis());
if (manualLegalBasisChange.getSection() != null) {
redactionLogEntry.setSection(manualLegalBasisChange.getSection());
}
if (redactionLogEntry.isRectangle() && manualLegalBasisChange.getValue() != null) {
redactionLogEntry.setValue(manualLegalBasisChange.getValue());
}
redactionLogEntry.setHasLegalBasisChanged(true);
} else if (manualLegalBasisChange.getStatus().equals(Status.REQUESTED)) {
manualOverrideReason = mergeReasonIfNecessary(redactionLogEntry.getReason(), ", legal basis change requested");
redactionLogEntry.setStatus(Status.REQUESTED);
@@ -222,7 +202,6 @@ public class RedactionLogMergeService {
redactionLogEntry.setStatus(Status.DECLINED);
}
redactionLogEntry.setManualRedactionUserId(manualLegalBasisChange.getUser());
redactionLogEntry.setReason(manualOverrideReason);
redactionLogEntry.setManual(true);
@@ -247,24 +226,19 @@ public class RedactionLogMergeService {
}
private List<RedactionLogEntry> addManualAddEntries(SectionGrid sectionGrid,
Set<ManualRedactionEntry> manualAdds,
Map<String, List<Comment>> comments, String dossierTemplateId) {
public List<RedactionLogEntry> addManualAddEntries(Set<ManualRedactionEntry> manualAdds,
Map<String, List<Comment>> comments, String dossierTemplateId) {
List<RedactionLogEntry> redactionLogEntries = new ArrayList<>();
for (ManualRedactionEntry manualRedactionEntry : manualAdds) {
if (!approvedAndShouldBeInDictionary(manualRedactionEntry)) {
RedactionLogEntry redactionLogEntry = createRedactionLogEntry(manualRedactionEntry, manualRedactionEntry
.getId(), dossierTemplateId);
redactionLogEntry.setPositions(manualRedactionEntry.getPositions());
redactionLogEntry.setComments(comments.get(manualRedactionEntry.getId()));
sectionTextService.handleSectionText(sectionGrid, redactionLogEntry);
redactionLogEntries.add(redactionLogEntry);
}
}
@@ -290,16 +264,14 @@ public class RedactionLogMergeService {
.isDossierDictionaryEntry(manualRedactionEntry.isAddToDossierDictionary())
.legalBasis(manualRedactionEntry.getLegalBasis())
.value(manualRedactionEntry.getValue())
.section(manualRedactionEntry.getSection())
.type(manualRedactionEntry.getType())
.rectangle(manualRedactionEntry.isRectangle())
.redacted(true)
.isHint(false)
.section(null)
.sectionNumber(-1)
.manual(true)
.status(manualRedactionEntry.getStatus())
.manualRedactionType(ManualRedactionType.ADD)
.positions(manualRedactionEntry.getPositions())
.manualRedactionUserId(manualRedactionEntry.getUser())
.build();
}
@@ -1,42 +0,0 @@
package com.iqser.red.service.redaction.v1.server.redaction.service;
import com.iqser.red.service.redaction.v1.model.RedactionLogEntry;
import com.iqser.red.service.redaction.v1.model.SectionGrid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class SectionTextService {
public void handleSectionText(SectionGrid sectionGrid, RedactionLogEntry redactionLogEntry) {
log.info("Handling manual redaction match for sections: {} and entry section: {}, positions: {}",
sectionGrid != null ? sectionGrid.getSections().size() : "null", redactionLogEntry.getSection(), redactionLogEntry.getPositions());
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;
}
}
}
}
}
}
}
}
@@ -1,16 +1,5 @@
package com.iqser.red.service.redaction.v1.server.redaction.utils;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import com.iqser.red.service.redaction.v1.server.redaction.model.Dictionary;
import com.iqser.red.service.redaction.v1.server.redaction.model.DictionaryIncrementValue;
import com.iqser.red.service.redaction.v1.server.redaction.model.Entity;
@@ -20,6 +9,10 @@ import com.iqser.red.service.redaction.v1.server.redaction.model.SearchableText;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@Slf4j
@UtilityClass
@SuppressWarnings("PMD")
@@ -159,44 +152,6 @@ public class EntitySearchUtils {
// HashSet keeps old value but we want the new.
entities.removeAll(found);
entities.addAll(found);
removeEntitiesContainedInLarger(entities);
}
public Set<Entity> findNonOverlappingMatchEntities(Set<Entity> existingEntities, Set<Entity> foundEntities) {
Set<Entity> result = new HashSet<>();
if (existingEntities != null && foundEntities != null) {
for (Entity foundEntity : foundEntities) {
if (!overlaps(existingEntities, foundEntity)) {
result.add(foundEntity);
}
}
}
return result;
}
private boolean overlaps(Set<Entity> existingEntities, Entity found) {
for (Entity existing : existingEntities) {
if(existing.getStart().equals(found.getStart())){
continue;
}
for (int i = existing.getStart(); i <= existing.getEnd(); i++) {
for (int j = found.getStart(); j <= found.getEnd(); j++) {
if (i == j) {
return true;
}
}
}
}
return false;
}
}
@@ -83,6 +83,7 @@ public class RedactionStorageService {
}
}
@RequiredArgsConstructor
public enum StorageType {
PARSED_DOCUMENT(".json");
@@ -18,10 +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;
@@ -569,7 +569,7 @@ public class RedactionIntegrationTest {
.fileId(TEST_FILE_ID)
.build());
try (FileOutputStream fileOutputStream = new FileOutputStream(getTemporaryDirectory() + "/Annotated3.pdf")) {
try (FileOutputStream fileOutputStream = new FileOutputStream("/tmp/Annotated3.pdf")) {
fileOutputStream.write(annotateResponse.getDocument());
}
long rstart = System.currentTimeMillis();
@@ -652,28 +652,11 @@ public class RedactionIntegrationTest {
}
@Test
public void redactionExpansionOverlap() throws IOException {
ClassPathResource pdfFileResource = new ClassPathResource("files/Minimal Examples/ExpansionTest.pdf");
AnalyzeRequest request = prepareStorage(pdfFileResource.getInputStream());
AnalyzeResult result = reanalyzeService.analyze(request);
var redactionLog = redactionStorageService.getRedactionLog(TEST_DOSSIER_ID, TEST_FILE_ID);
var values = redactionLog.getRedactionLogEntry().stream().map(RedactionLogEntry::getValue).collect(Collectors.toList());
assertThat(values).containsExactlyInAnyOrder("Lastname M.", "Doe", "Doe J.", "M. Mustermann", "Mustermann M.", "F. Lastname");
}
@Test
public void redactionTest() throws IOException {
long start = System.currentTimeMillis();
ClassPathResource pdfFileResource = new ClassPathResource("files/new/just-a-document-20211215.pdf");
ClassPathResource pdfFileResource = new ClassPathResource("files/new/Single Study - Oral (Gavage) Mouse.pdf");
AnalyzeRequest request = prepareStorage(pdfFileResource.getInputStream());
request.setExcludedPages(Set.of(1));
@@ -699,7 +682,7 @@ public class RedactionIntegrationTest {
System.out.println("first analysis duration: " + (end - start));
try (FileOutputStream fileOutputStream = new FileOutputStream(getTemporaryDirectory() + "/Test.json")) {
try (FileOutputStream fileOutputStream = new FileOutputStream("/tmp/Test.json")) {
fileOutputStream.write(objectMapper.writeValueAsBytes(redactionStorageService.getText(TEST_DOSSIER_ID, TEST_FILE_ID)));
}
@@ -731,10 +714,13 @@ public class RedactionIntegrationTest {
reanlysisVersions.put("physical", 2L);
deleted.add("David Chubb");
deleted.add("mouse");
dictionary.get(FALSE_POSITIVE).add("David Chubb");
reanlysisVersions.put("David Chubb", 3L);
reanlysisVersions.put("mouse", 3L);
when(dictionaryClient.getVersion(TEST_DOSSIER_TEMPLATE_ID, DictionaryResource.GLOBAL_DOSSIER)).thenReturn(3L);
when(dictionaryClient.getDictionaryForType(VERTEBRATE, TEST_DOSSIER_TEMPLATE_ID, DictionaryResource.GLOBAL_DOSSIER))
@@ -767,85 +753,27 @@ public class RedactionIntegrationTest {
.fileId(TEST_FILE_ID)
.build());
try (FileOutputStream fileOutputStream = new FileOutputStream(getTemporaryDirectory() + "/Annotated.pdf")) {
try (FileOutputStream fileOutputStream = new FileOutputStream("/tmp/Annotated.pdf")) {
fileOutputStream.write(annotateResponse.getDocument());
}
}
deleted.remove("mouse");
reanlysisVersions.put("mouse", 4L);
@Test
public void testIgnoreHint() {
when(dictionaryClient.getVersion(TEST_DOSSIER_TEMPLATE_ID, DictionaryResource.GLOBAL_DOSSIER)).thenReturn(4L);
System.out.println("testIgnoreHint");
when(dictionaryClient.getDictionaryForType(VERTEBRATE, TEST_DOSSIER_TEMPLATE_ID, DictionaryResource.GLOBAL_DOSSIER))
.thenReturn(getDictionaryResponse(VERTEBRATE, false));
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);
redactionLog = redactionStorageService.getRedactionLog(TEST_DOSSIER_ID, TEST_FILE_ID);
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();
System.out.println("hi");
}
@Test
public void testIgnoreHintFirstAnalysis() {
System.out.println("testIgnoreHintFirstAnalysis");
AnalyzeRequest request = prepareStorage("files/new/test-ignore-hint.pdf");
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.analyze(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 cbiAddressAfterHintRemoval = mergedRedactionLog.getRedactionLogEntry().stream().filter(re -> re.getType().equalsIgnoreCase("CBI_Address")).findAny().get();
assertThat(cbiAddressAfterHintRemoval.isRedacted()).isTrue();
}
@Test
public void testTableRedaction() throws IOException {
@@ -860,30 +788,7 @@ public class RedactionIntegrationTest {
.fileId(TEST_FILE_ID)
.build());
try (FileOutputStream fileOutputStream = new FileOutputStream(getTemporaryDirectory() + "/Annotated.pdf")) {
fileOutputStream.write(annotateResponse.getDocument());
}
long end = System.currentTimeMillis();
System.out.println("duration: " + (end - start));
System.out.println("numberOfPages: " + result.getNumberOfPages());
}
@Test
public void testIgnoreDossierRedactionIfConfidential() throws IOException {
long start = System.currentTimeMillis();
AnalyzeRequest request = prepareStorage("files/new/VV-919901.pdf");
AnalyzeResult result = reanalyzeService.analyze(request);
AnnotateResponse annotateResponse = redactionController.annotate(AnnotateRequest.builder()
.dossierId(TEST_DOSSIER_ID)
.fileId(TEST_FILE_ID)
.build());
try (FileOutputStream fileOutputStream = new FileOutputStream(getTemporaryDirectory() + "/Annotated.pdf")) {
try (FileOutputStream fileOutputStream = new FileOutputStream("/tmp/Annotated.pdf")) {
fileOutputStream.write(annotateResponse.getDocument());
}
long end = System.currentTimeMillis();
@@ -959,7 +864,7 @@ public class RedactionIntegrationTest {
.fileId(TEST_FILE_ID)
.build());
try (FileOutputStream fileOutputStream = new FileOutputStream(getTemporaryDirectory() + "/Annotated.pdf")) {
try (FileOutputStream fileOutputStream = new FileOutputStream("/tmp/Annotated.pdf")) {
fileOutputStream.write(annotateResponse.getDocument());
}
long end = System.currentTimeMillis();
@@ -985,7 +890,7 @@ public class RedactionIntegrationTest {
RedactionResult result = redactionController.classify(redactionRequest);
try (FileOutputStream fileOutputStream = new FileOutputStream(getTemporaryDirectory() + "/Classified.pdf")) {
try (FileOutputStream fileOutputStream = new FileOutputStream("/tmp/Classified.pdf")) {
fileOutputStream.write(result.getDocument());
}
}
@@ -1007,7 +912,7 @@ public class RedactionIntegrationTest {
RedactionResult result = redactionController.sections(redactionRequest);
try (FileOutputStream fileOutputStream = new FileOutputStream(getTemporaryDirectory() + "/Sections.pdf")) {
try (FileOutputStream fileOutputStream = new FileOutputStream("/tmp/Sections.pdf")) {
fileOutputStream.write(result.getDocument());
}
}
@@ -1029,7 +934,7 @@ public class RedactionIntegrationTest {
RedactionResult result = redactionController.htmlTables(redactionRequest);
try (FileOutputStream fileOutputStream = new FileOutputStream(getTemporaryDirectory() + "/Tables.html")) {
try (FileOutputStream fileOutputStream = new FileOutputStream("/tmp/Tables.html")) {
fileOutputStream.write(result.getDocument());
}
}
@@ -1051,7 +956,7 @@ public class RedactionIntegrationTest {
RedactionResult result = redactionController.htmlTables(redactionRequest);
try (FileOutputStream fileOutputStream = new FileOutputStream(getTemporaryDirectory() + "/Tables.html")) {
try (FileOutputStream fileOutputStream = new FileOutputStream("/tmp/Tables.html")) {
fileOutputStream.write(result.getDocument());
}
}
@@ -1119,31 +1024,7 @@ public class RedactionIntegrationTest {
.fileId(TEST_FILE_ID)
.build());
try (FileOutputStream fileOutputStream = new FileOutputStream(getTemporaryDirectory() + "/Annotated.pdf")) {
fileOutputStream.write(annotateResponse.getDocument());
}
long end = System.currentTimeMillis();
System.out.println("duration: " + (end - start));
System.out.println("numberOfPages: " + result.getNumberOfPages());
}
@Test
public void testExpandByRegEx() throws IOException {
System.out.println("expandByRegex");
long start = System.currentTimeMillis();
AnalyzeRequest request = prepareStorage("files/Metolachlor/S-Metolachlor_RAR_02_Volume_2_2018-09-06.pdf");
AnalyzeResult result = reanalyzeService.analyze(request);
AnnotateResponse annotateResponse = redactionController.annotate(AnnotateRequest.builder()
.dossierId(TEST_DOSSIER_ID)
.fileId(TEST_FILE_ID)
.build());
try (FileOutputStream fileOutputStream = new FileOutputStream(getTemporaryDirectory() + "/Annotated.pdf")) {
try (FileOutputStream fileOutputStream = new FileOutputStream("/tmp/Annotated.pdf")) {
fileOutputStream.write(annotateResponse.getDocument());
}
long end = System.currentTimeMillis();
@@ -1171,13 +1052,4 @@ public class RedactionIntegrationTest {
}
}
private static String getTemporaryDirectory() {
// String tmpdir = System.getProperty("java.io.tmpdir");
// if (StringUtils.isNotBlank(tmpdir)) {
// return tmpdir;
// }
return "/tmp";
}
}
@@ -1,171 +0,0 @@
package com.iqser.red.service.redaction.v1.server.redaction.utils;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
import com.iqser.red.service.redaction.v1.server.redaction.model.Entity;
public class EntitySearchUtilsTest {
/*
* Text: Batman X. Superman Y.
* Position: 0123456789
* 0123456789
* 0123456789
*/
@Test
public void testNotOverlappingEntitiesExpandedEnd() {
// Arrange
Set<Entity> existingEntities = new HashSet<>();
Entity existingEntity1 = new Entity("Batman", "fake type", 0, 5, "fake headline", 0, false, false);
Entity existingEntity2 = new Entity("Superman", "fake type", 10, 17, "fake headline", 0, false, false);
existingEntities.add(existingEntity1);
existingEntities.add(existingEntity2);
Set<Entity> foundEntities = new HashSet<>();
Entity foundEntities1 = new Entity("Batman X.", "fake type", 0, 8, "fake headline", 0, false, false);
Entity foundEntities2 = new Entity("Superman Y.", "fake type", 10, 20, "fake headline", 0, false, false);
foundEntities.add(foundEntities1);
foundEntities.add(foundEntities2);
// Act
Set<Entity> result = EntitySearchUtils.findNonOverlappingMatchEntities(existingEntities, foundEntities);
// Assert
assertThat(result.size()).isEqualTo(2);
assertThat(result).contains(foundEntities1);
assertThat(result).contains(foundEntities2);
}
/*
* Text: Batman X. Superman Y.
* Position: 0123456789
* 0123456789
* 0123456789
*/
@Test
public void testNotOverlappingEntitiesExpandedStartAndEndOverlapping() {
// Arrange
Set<Entity> existingEntities = new HashSet<>();
Entity existingEntity1 = new Entity("Batman X.", "fake type", 0, 8, "fake headline", 0, false, false);
Entity existingEntity2 = new Entity("Superman", "fake type", 10, 17, "fake headline", 0, false, false);
existingEntities.add(existingEntity1);
existingEntities.add(existingEntity2);
Set<Entity> foundEntities = new HashSet<>();
Entity foundEntities1 = new Entity("Batman X.", "fake type", 0, 8, "fake headline", 0, false, false);
Entity foundEntities2 = new Entity("X. Superman Y.", "fake type", 7, 20, "fake headline", 0, false, false);
foundEntities.add(foundEntities1);
foundEntities.add(foundEntities2);
// Act
Set<Entity> result = EntitySearchUtils.findNonOverlappingMatchEntities(existingEntities, foundEntities);
// Assert
assertThat(result.size()).isEqualTo(1);
assertThat(result).contains(foundEntities1);
}
/*
* Text: Batman X. Superman Y.
* Position: 0123456789
* 0123456789
* 0123456789
*/
@Test
public void testNotOverlappingEntitiesExpandedStartAndEnd() {
// Arrange
Set<Entity> existingEntities = new HashSet<>();
Entity existingEntity1 = new Entity("Batman X.", "fake type", 0, 8, "fake headline", 0, false, false);
Entity existingEntity2 = new Entity("Superman", "fake type", 10, 17, "fake headline", 0, false, false);
existingEntities.add(existingEntity1);
existingEntities.add(existingEntity2);
Set<Entity> foundEntities = new HashSet<>();
Entity foundEntities1 = new Entity("Batman X.", "fake type", 0, 8, "fake headline", 0, false, false);
Entity foundEntities2 = new Entity("X. Superman", "fake type", 7, 17, "fake headline", 0, false, false);
foundEntities.add(foundEntities1);
foundEntities.add(foundEntities2);
// Act
Set<Entity> result = EntitySearchUtils.findNonOverlappingMatchEntities(existingEntities, foundEntities);
// Assert
assertThat(result.size()).isEqualTo(1);
assertThat(result).contains(foundEntities1);
}
/*
* Text: Batman X. Superman Y.
* Position: 0123456789
* 0123456789
* 0123456789
*/
@Test
public void testNotOverlappingEntitiesExpandedExistingAndExpandedEnd() {
// Arrange
Set<Entity> existingEntities = new HashSet<>();
Entity existingEntity1 = new Entity("X. Superman", "fake type", 7, 17, "fake headline", 0, false, false);
Entity existingEntity2 = new Entity("Batman", "fake type", 0, 5, "fake headline", 0, false, false);
existingEntities.add(existingEntity1);
existingEntities.add(existingEntity2);
Set<Entity> foundEntities = new HashSet<>();
Entity foundEntities1 = new Entity("Batman X.", "fake type", 0, 8, "fake headline", 0, false, false);
Entity foundEntities2 = new Entity("Superman", "fake type", 10, 17, "fake headline", 0, false, false);
foundEntities.add(foundEntities1);
foundEntities.add(foundEntities2);
// Act
Set<Entity> result = EntitySearchUtils.findNonOverlappingMatchEntities(existingEntities, foundEntities);
// Assert
assertThat(result.size()).isEqualTo(0);
}
/*
* Text: Batman X. Superman Y.
* Position: 0123456789
* 0123456789
* 0123456789
*/
@Test
public void testNotOverlappingEntitiesExpandedEndLong() {
// Arrange
Set<Entity> existingEntities = new HashSet<>();
Entity existingEntity1 = new Entity("X. Superman", "fake type", 7, 17, "fake headline", 0, false, false);
Entity existingEntity2 = new Entity("Batman", "fake type", 0, 5, "fake headline", 0, false, false);
existingEntities.add(existingEntity1);
existingEntities.add(existingEntity2);
Set<Entity> foundEntities = new HashSet<>();
Entity foundEntities1 = new Entity("Batman X. Superman", "fake type", 0, 17, "fake headline", 0, false, false);
Entity foundEntities2 = new Entity("Superman", "fake type", 10, 17, "fake headline", 0, false, false);
foundEntities.add(foundEntities1);
foundEntities.add(foundEntities2);
// Act
Set<Entity> result = EntitySearchUtils.findNonOverlappingMatchEntities(existingEntities, foundEntities);
// Assert
assertThat(result.size()).isEqualTo(0);
}
}
@@ -1,80 +0,0 @@
package com.iqser.red.service.redaction.v1.server.redaction.utils;
import com.amazonaws.services.s3.AmazonS3;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.iqser.red.service.redaction.v1.model.ManualRedactions;
import com.iqser.red.service.redaction.v1.model.RedactionLog;
import com.iqser.red.service.redaction.v1.model.SectionGrid;
import com.iqser.red.service.redaction.v1.server.Application;
import com.iqser.red.service.redaction.v1.server.redaction.service.DictionaryService;
import com.iqser.red.service.redaction.v1.server.redaction.service.RedactionLogMergeService;
import com.iqser.red.service.redaction.v1.server.redaction.service.SectionTextService;
import lombok.SneakyThrows;
import org.apache.commons.compress.utils.Lists;
import org.assertj.core.util.Sets;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.ClassPathResource;
import org.springframework.test.context.junit4.SpringRunner;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@Import(SectionTextServiceTest.TestConfiguration.class)
public class SectionTextServiceTest {
@Autowired
private ObjectMapper objectMapper;
@Autowired
private SectionTextService service;
@Autowired
private RedactionLogMergeService redactionLogMergeService;
@MockBean
private DictionaryService dictionaryService;
@MockBean
private AmazonS3 amazonS3;
@Configuration
@EnableAutoConfiguration(exclude = {RabbitAutoConfiguration.class})
public static class TestConfiguration {
}
@Test
@SneakyThrows
public void testMerge() {
when(dictionaryService.getColor(Mockito.anyString(), Mockito.anyString())).thenReturn(new float[]{0, 0, 0});
ManualRedactions manualRedactions = objectMapper.readValue(new ClassPathResource("contains/manual-redactions.json").getInputStream(), ManualRedactions.class);
RedactionLog redactionLog = new RedactionLog(1, Lists.newArrayList(), Lists.newArrayList(), 1, 1, 1, 1);
SectionGrid sectionGrid = objectMapper.readValue(new ClassPathResource("contains/sections.json").getInputStream(), SectionGrid.class);
RedactionLog merged = redactionLogMergeService.mergeRedactionLogData(redactionLog, sectionGrid, "1", manualRedactions, Sets.newHashSet());
assertThat(merged.getRedactionLogEntry().isEmpty()).isFalse();
assertThat(merged.getRedactionLogEntry().iterator().next().getSection()).isEqualTo("NOTIFICATION OF AN ACTIVE\n" +
"SUBSTANCE UNDER COMMISSION\n" +
"REGULATION (EU) 844/2012");
assertThat(merged.getRedactionLogEntry().iterator().next().getSectionNumber()).isEqualTo(7);
}
}
@@ -1,54 +0,0 @@
{
"idsToRemove": [],
"entriesToAdd": [
{
"id": "d5fd9fd9690557703a22d8ab22832c7f",
"user": "7adf30b4-a0d8-4abb-adbb-760b1211098f",
"type": "manual",
"value": "DOCUMENT M-CA, Section 10\nSupplement",
"reason": "names and addresses of persons involved in testing on vertebrate animals",
"legalBasis": "[Reg (EC) No 1107/2009 Art. 63 (2g)]",
"section": null,
"positions": [
{
"topLeft": {
"x": 190.92,
"y": 376.7999
},
"width": 227.49368,
"height": 14.974969,
"page": 1
},
{
"topLeft": {
"x": 258.96,
"y": 358.31992
},
"width": 91.47408,
"height": 14.974969,
"page": 1
}
],
"status": "APPROVED",
"addToDictionary": false,
"addToDossierDictionary": false,
"requestDate": "2021-11-03T15:01:45Z",
"processedDate": "2021-11-03T15:01:45Z",
"softDeletedTime": null
}
],
"forceRedactions": [],
"imageRecategorization": [],
"legalBasisChanges": [],
"comments": {
"d5fd9fd9690557703a22d8ab22832c7f": [
{
"id": "56c1a675-0d64-4190-b76c-6af9d0b361a9",
"date": "2021-11-03T15:01:45Z",
"text": "test",
"user": "7adf30b4-a0d8-4abb-adbb-760b1211098f",
"softDeletedTime": null
}
]
}
}
@@ -1,877 +0,0 @@
{
"rectanglesPerPage": {
"1": [
{
"topLeft": {
"x": 251.4,
"y": 550.32
},
"width": 107.763336,
"height": 12.02002,
"part": 1,
"numberOfParts": 1,
"tableCells": null
},
{
"topLeft": {
"x": 159.24,
"y": 280.92004
},
"width": 291.92004,
"height": 212.29996,
"part": 1,
"numberOfParts": 3,
"tableCells": null
}
],
"2": [
{
"topLeft": {
"x": 70.92,
"y": 735.36
},
"width": 105.64288,
"height": 9.02002,
"part": 2,
"numberOfParts": 3,
"tableCells": null
},
{
"topLeft": {
"x": 65.56436,
"y": 719.9557
},
"width": 478.4686,
"height": -110.91278,
"part": 3,
"numberOfParts": 3,
"tableCells": [
{
"topLeft": {
"x": 65.56436,
"y": 684.47955
},
"width": 83.35573,
"height": 35.476135
},
{
"topLeft": {
"x": 148.92009,
"y": 684.47955
},
"width": 255.12016,
"height": 35.476135
},
{
"topLeft": {
"x": 404.04025,
"y": 684.47955
},
"width": 139.9927,
"height": 35.476135
},
{
"topLeft": {
"x": 65.56436,
"y": 659.27954
},
"width": 83.35573,
"height": 25.200012
},
{
"topLeft": {
"x": 148.92009,
"y": 659.27954
},
"width": 255.12016,
"height": 25.200012
},
{
"topLeft": {
"x": 404.04025,
"y": 659.27954
},
"width": 139.9927,
"height": 25.200012
},
{
"topLeft": {
"x": 65.56436,
"y": 634.20074
},
"width": 83.35573,
"height": 25.078796
},
{
"topLeft": {
"x": 148.92009,
"y": 634.20074
},
"width": 255.12016,
"height": 25.078796
},
{
"topLeft": {
"x": 404.04025,
"y": 634.20074
},
"width": 139.9927,
"height": 25.078796
},
{
"topLeft": {
"x": 65.56436,
"y": 609.0429
},
"width": 83.35573,
"height": 25.157837
},
{
"topLeft": {
"x": 148.92009,
"y": 609.0429
},
"width": 255.12016,
"height": 25.157837
},
{
"topLeft": {
"x": 404.04025,
"y": 609.0429
},
"width": 139.9927,
"height": 25.157837
}
]
}
],
"3": [
{
"topLeft": {
"x": 70.92,
"y": 691.2
},
"width": 468.76624,
"height": 53.179993,
"part": 1,
"numberOfParts": 3,
"tableCells": null
}
],
"4": [
{
"topLeft": {
"x": 71.04,
"y": 555.48
},
"width": 461.24002,
"height": 188.78003,
"part": 2,
"numberOfParts": 3,
"tableCells": null
},
{
"topLeft": {
"x": 65.68587,
"y": 540.55756
},
"width": 478.58698,
"height": -365.55508,
"part": 3,
"numberOfParts": 3,
"tableCells": [
{
"topLeft": {
"x": 65.68587,
"y": 515.4003
},
"width": 125.808716,
"height": 25.157227
},
{
"topLeft": {
"x": 191.49458,
"y": 515.4003
},
"width": 352.77826,
"height": 25.157227
},
{
"topLeft": {
"x": 65.68587,
"y": 404.75992
},
"width": 125.808716,
"height": 110.64041
},
{
"topLeft": {
"x": 191.49458,
"y": 404.75992
},
"width": 352.77826,
"height": 110.64041
},
{
"topLeft": {
"x": 65.68587,
"y": 379.68002
},
"width": 125.808716,
"height": 25.079895
},
{
"topLeft": {
"x": 191.49458,
"y": 379.68002
},
"width": 352.77826,
"height": 25.079895
},
{
"topLeft": {
"x": 65.68587,
"y": 335.8798
},
"width": 125.808716,
"height": 43.800232
},
{
"topLeft": {
"x": 191.49458,
"y": 335.8798
},
"width": 352.77826,
"height": 43.800232
},
{
"topLeft": {
"x": 65.68587,
"y": 310.68
},
"width": 125.808716,
"height": 25.199799
},
{
"topLeft": {
"x": 191.49458,
"y": 310.68
},
"width": 352.77826,
"height": 25.199799
},
{
"topLeft": {
"x": 65.68587,
"y": 281.2798
},
"width": 125.808716,
"height": 29.400208
},
{
"topLeft": {
"x": 191.49458,
"y": 281.2798
},
"width": 352.77826,
"height": 29.400208
},
{
"topLeft": {
"x": 65.68587,
"y": 218.76001
},
"width": 125.808716,
"height": 62.519775
},
{
"topLeft": {
"x": 191.49458,
"y": 218.76001
},
"width": 352.77826,
"height": 62.519775
},
{
"topLeft": {
"x": 65.68587,
"y": 175.00247
},
"width": 125.808716,
"height": 43.757538
},
{
"topLeft": {
"x": 191.49458,
"y": 175.00247
},
"width": 352.77826,
"height": 43.757538
}
]
}
]
},
"sections": [
{
"sectionNumber": 1,
"headline": "",
"pages": [
1
],
"sectionAreas": [
{
"topLeft": {
"x": 251.4,
"y": 550.32
},
"width": 107.763336,
"height": 12.02002,
"page": 1,
"header": null
}
]
},
{
"sectionNumber": 2,
"headline": "Table in: NOTIFICATION OF AN ACTIVE\nSUBSTANCE UNDER COMMISSION\nREGULATION (EU) 844/2012",
"pages": [
2
],
"sectionAreas": [
{
"topLeft": {
"x": 65.56436,
"y": 684.47955
},
"width": 83.35573,
"height": 35.476135,
"page": 2,
"header": null
},
{
"topLeft": {
"x": 148.92009,
"y": 684.47955
},
"width": 255.12016,
"height": 35.476135,
"page": 2,
"header": null
},
{
"topLeft": {
"x": 404.04025,
"y": 684.47955
},
"width": 139.9927,
"height": 35.476135,
"page": 2,
"header": null
}
]
},
{
"sectionNumber": 3,
"headline": "Table in: NOTIFICATION OF AN ACTIVE\nSUBSTANCE UNDER COMMISSION\nREGULATION (EU) 844/2012",
"pages": [],
"sectionAreas": []
},
{
"sectionNumber": 4,
"headline": "Table in: NOTIFICATION OF AN ACTIVE\nSUBSTANCE UNDER COMMISSION\nREGULATION (EU) 844/2012",
"pages": [],
"sectionAreas": []
},
{
"sectionNumber": 5,
"headline": "Table in: NOTIFICATION OF AN ACTIVE\nSUBSTANCE UNDER COMMISSION\nREGULATION (EU) 844/2012",
"pages": [
2
],
"sectionAreas": [
{
"topLeft": {
"x": 65.56436,
"y": 609.0429
},
"width": 83.35573,
"height": 25.157837,
"page": 2,
"header": "Date"
}
]
},
{
"sectionNumber": 7,
"headline": "NOTIFICATION OF AN ACTIVE\nSUBSTANCE UNDER COMMISSION\nREGULATION (EU) 844/2012",
"pages": [
1,
2
],
"sectionAreas": [
{
"topLeft": {
"x": 159.24,
"y": 280.92004
},
"width": 291.92004,
"height": 212.29996,
"page": 1,
"header": null
},
{
"topLeft": {
"x": 70.92,
"y": 735.36
},
"width": 105.64288,
"height": 9.02002,
"page": 2,
"header": null
}
]
},
{
"sectionNumber": 8,
"headline": "Table in: Table of Contents",
"pages": [
4
],
"sectionAreas": [
{
"topLeft": {
"x": 65.68587,
"y": 515.4003
},
"width": 125.808716,
"height": 25.157227,
"page": 4,
"header": null
},
{
"topLeft": {
"x": 191.49458,
"y": 515.4003
},
"width": 352.77826,
"height": 25.157227,
"page": 4,
"header": null
},
{
"topLeft": {
"x": 65.68587,
"y": 404.75992
},
"width": 125.808716,
"height": 110.64041,
"page": 4,
"header": null
},
{
"topLeft": {
"x": 65.68587,
"y": 379.68002
},
"width": 125.808716,
"height": 25.079895,
"page": 4,
"header": null
},
{
"topLeft": {
"x": 191.49458,
"y": 379.68002
},
"width": 352.77826,
"height": 25.079895,
"page": 4,
"header": null
},
{
"topLeft": {
"x": 65.68587,
"y": 335.8798
},
"width": 125.808716,
"height": 43.800232,
"page": 4,
"header": null
},
{
"topLeft": {
"x": 191.49458,
"y": 335.8798
},
"width": 352.77826,
"height": 43.800232,
"page": 4,
"header": null
},
{
"topLeft": {
"x": 65.68587,
"y": 310.68
},
"width": 125.808716,
"height": 25.199799,
"page": 4,
"header": null
},
{
"topLeft": {
"x": 191.49458,
"y": 310.68
},
"width": 352.77826,
"height": 25.199799,
"page": 4,
"header": null
},
{
"topLeft": {
"x": 65.68587,
"y": 281.2798
},
"width": 125.808716,
"height": 29.400208,
"page": 4,
"header": null
},
{
"topLeft": {
"x": 191.49458,
"y": 281.2798
},
"width": 352.77826,
"height": 29.400208,
"page": 4,
"header": null
},
{
"topLeft": {
"x": 65.68587,
"y": 218.76001
},
"width": 125.808716,
"height": 62.519775,
"page": 4,
"header": null
},
{
"topLeft": {
"x": 191.49458,
"y": 218.76001
},
"width": 352.77826,
"height": 62.519775,
"page": 4,
"header": null
},
{
"topLeft": {
"x": 65.68587,
"y": 175.00247
},
"width": 125.808716,
"height": 43.757538,
"page": 4,
"header": null
},
{
"topLeft": {
"x": 191.49458,
"y": 175.00247
},
"width": 352.77826,
"height": 43.757538,
"page": 4,
"header": null
}
]
},
{
"sectionNumber": 9,
"headline": "Table of Contents",
"pages": [
3,
4
],
"sectionAreas": [
{
"topLeft": {
"x": 70.92,
"y": 691.2
},
"width": 468.76624,
"height": 53.179993,
"page": 3,
"header": null
},
{
"topLeft": {
"x": 71.04,
"y": 555.48
},
"width": 461.24002,
"height": 188.78003,
"page": 4,
"header": null
}
]
},
{
"sectionNumber": 10,
"headline": "Header",
"pages": [
1
],
"sectionAreas": [
{
"topLeft": {
"x": 70.92,
"y": 799.08
},
"width": 469.31543,
"height": 6.799988,
"page": 1,
"header": null
},
{
"topLeft": {
"x": 534.72,
"y": 783.84
},
"width": 5.470215,
"height": 6.0200195,
"page": 1,
"header": null
}
]
},
{
"sectionNumber": 11,
"headline": "Header",
"pages": [
2
],
"sectionAreas": [
{
"topLeft": {
"x": 70.92,
"y": 799.08
},
"width": 469.31543,
"height": 6.799988,
"page": 2,
"header": null
},
{
"topLeft": {
"x": 534.72,
"y": 783.84
},
"width": 5.470215,
"height": 6.0200195,
"page": 2,
"header": null
}
]
},
{
"sectionNumber": 12,
"headline": "Header",
"pages": [
3
],
"sectionAreas": [
{
"topLeft": {
"x": 70.92,
"y": 799.08
},
"width": 469.31543,
"height": 6.799988,
"page": 3,
"header": null
},
{
"topLeft": {
"x": 534.72,
"y": 783.84
},
"width": 5.470215,
"height": 6.0200195,
"page": 3,
"header": null
}
]
},
{
"sectionNumber": 13,
"headline": "Header",
"pages": [
4
],
"sectionAreas": [
{
"topLeft": {
"x": 71.04,
"y": 798.96
},
"width": 469.70926,
"height": 6.799988,
"page": 4,
"header": null
},
{
"topLeft": {
"x": 534.84,
"y": 783.72
},
"width": 5.488098,
"height": 6.036072,
"page": 4,
"header": null
}
]
},
{
"sectionNumber": 14,
"headline": "Footer",
"pages": [
1
],
"sectionAreas": [
{
"topLeft": {
"x": 70.92,
"y": 37.080017
},
"width": 93.19173,
"height": 6.0200005,
"page": 1,
"header": null
},
{
"topLeft": {
"x": 468.0,
"y": 37.080017
},
"width": 71.701416,
"height": 6.0200005,
"page": 1,
"header": null
}
]
},
{
"sectionNumber": 15,
"headline": "Footer",
"pages": [
2
],
"sectionAreas": [
{
"topLeft": {
"x": 70.92,
"y": 37.440002
},
"width": 93.19173,
"height": 6.0200005,
"page": 2,
"header": null
},
{
"topLeft": {
"x": 468.0,
"y": 37.440002
},
"width": 71.701416,
"height": 6.0200005,
"page": 2,
"header": null
}
]
},
{
"sectionNumber": 16,
"headline": "Footer",
"pages": [
3
],
"sectionAreas": [
{
"topLeft": {
"x": 70.92,
"y": 37.440002
},
"width": 468.78143,
"height": 6.0200005,
"page": 3,
"header": null
}
]
},
{
"sectionNumber": 17,
"headline": "Footer",
"pages": [
4
],
"sectionAreas": [
{
"topLeft": {
"x": 71.04,
"y": 37.320007
},
"width": 93.3805,
"height": 6.0360794,
"page": 4,
"header": null
},
{
"topLeft": {
"x": 468.12,
"y": 37.320007
},
"width": 71.984375,
"height": 6.0360794,
"page": 4,
"header": null
},
{
"topLeft": {
"x": 71.04,
"y": 140.16003
},
"width": 254.69507,
"height": 7.5200043,
"page": 4,
"header": null
},
{
"topLeft": {
"x": 71.04,
"y": 115.56
},
"width": 65.564415,
"height": 7.5199966,
"page": 4,
"header": null
},
{
"topLeft": {
"x": 71.04,
"y": 90.599976
},
"width": 424.84805,
"height": 7.5199966,
"page": 4,
"header": null
}
]
}
]
}
@@ -1654,12 +1654,3 @@ 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
CTL
CTL - Central Toxicology Laboratory
CTL/P/3557
CTL/P/3607
CTL/P/S 161
CTL/Pl4333
CTL/with dictionary entry
@@ -8585,9 +8585,4 @@ Zoriki Hosomi R.
Zoriki Hosomi Rosana
Zuberer D
Zubrod J
Zwicker R.E.
Doe
M. Mustermann
F. Lastname
Mustermann
Lastname
Zwicker R.E.
@@ -1,5 +0,0 @@
Amendment 1
Report Number: 33168
Page
Report Number: BFI0714
Tesh Consultants International
@@ -1,2 +1 @@
Difenoconazole
FENPROPIDIN
Difenoconazole
@@ -85,4 +85,3 @@ Toxicology and Applied Pharmacology
Toxicol Sci
Toxicol Sci.
Toxicol Sci. 1
Test Ignored Hint Published Information
@@ -7,20 +7,12 @@ global Section section
// --------------------------------------- CBI rules -------------------------------------------------------------------
//rule "0: Expand CBI Authors with firstname initials"
// when
// Section(matchesType("CBI_author") || matchesType("recommendation_CBI_author"))
// then
// section.expandByRegEx("CBI_author", "(,? [A-Z]\\.?( ?[A-Z]\\.?)?( ?[A-Z]\\.?)?\\b\\.?)", false, 1);
// section.expandByRegEx("recommendation_CBI_author", "(,? [A-Z]\\.?( ?[A-Z]\\.?)?( ?[A-Z]\\.?)?\\b\\.?)", false, 1);
// end
rule "0: Expand CBI Authors with firstname initials"
when
Section(matchesType("CBI_author") || matchesType("recommendation_CBI_author"))
then
section.expandByRegEx("CBI_author", "(,? [A-Z]\\.?( ?[A-Z]\\.?)?( ?[A-Z]\\.?)?\\b\\.?)", false, 1, "[^\\s]+");
section.expandByRegEx("recommendation_CBI_author", "(,? [A-Z]\\.?( ?[A-Z]\\.?)?( ?[A-Z]\\.?)?\\b\\.?)", false, 1, "[^\\s]+");
section.expandByRegEx("CBI_author", "(,? [A-Z]\\.?( ?[A-Z]\\.?)?( ?[A-Z]\\.?)?\\b\\.?)", false, 1);
section.expandByRegEx("recommendation_CBI_author", "(,? [A-Z]\\.?( ?[A-Z]\\.?)?( ?[A-Z]\\.?)?\\b\\.?)", false, 1);
end
@@ -7,20 +7,12 @@ global Section section
// --------------------------------------- CBI rules -------------------------------------------------------------------
//rule "0: Expand CBI Authors with firstname initials"
// when
// Section(matchesType("CBI_author") || matchesType("recommendation_CBI_author"))
// then
// section.expandByRegEx("CBI_author", "(,? [A-Z]\\.?( ?[A-Z]\\.?)?( ?[A-Z]\\.?)?\\b\\.?)", false, 1);
// section.expandByRegEx("recommendation_CBI_author", "(,? [A-Z]\\.?( ?[A-Z]\\.?)?( ?[A-Z]\\.?)?\\b\\.?)", false, 1);
// end
rule "0: Expand CBI Authors with firstname initials"
when
Section(matchesType("CBI_author") || matchesType("recommendation_CBI_author"))
then
section.expandByRegEx("CBI_author", "(,? [A-Z]\\.?( ?[A-Z]\\.?)?( ?[A-Z]\\.?)?\\b\\.?)", false, 1, "[\\s]+");
section.expandByRegEx("recommendation_CBI_author", "(,? [A-Z]\\.?( ?[A-Z]\\.?)?( ?[A-Z]\\.?)?\\b\\.?)", false, 1, "[\\s]+");
section.expandByRegEx("CBI_author", "(,? [A-Z]\\.?( ?[A-Z]\\.?)?( ?[A-Z]\\.?)?\\b\\.?)", false, 1);
section.expandByRegEx("recommendation_CBI_author", "(,? [A-Z]\\.?( ?[A-Z]\\.?)?( ?[A-Z]\\.?)?\\b\\.?)", false, 1);
end
@@ -344,11 +336,4 @@ rule "29: Redact Dossier Redactions"
Section(matchesType("dossier_redactions"))
then
section.redact("dossier_redactions", 29, "Dossier Redaction found", "Article 39(1)(2) of Regulation (EC) No 178/2002");
end
rule "30: Ignore dossier_redactions if confidential"
when
Section(!fileAttributeByLabelEqualsIgnoreCase("Confidentiality","confidential") && matchesType("dossier_redactions"));
then
section.ignore("dossier_redactions");
end
end