Compare commits

...
Author SHA1 Message Date
Timo Bejan bc4a517514 RED-4799 2022-07-29 10:22:11 +02:00
Timo Bejan d616dc9a57 Pull request #440: RED-4799
Merge in RED/redaction-service from RED-4799-33x-release-fix to release/3.107.x

* commit '4289dfee2ddc1acf673ce7d16569ab514d1bbe6e':
  RED-4799
2022-07-27 12:00:20 +02:00
Timo Bejan 4289dfee2d RED-4799 2022-07-27 12:56:52 +03:00
Dominique Eiflaender 05834865ec Pull request #428: RED-4686: Added jackson-commons to fix InvalidDefinitionException: Java 8 date/time type java.time.OffsetDateTime
Merge in RED/redaction-service from RED-4686-bp2 to release/3.107.x

* commit '2e5ba30b3205f32dcbf10de4765b1aad2ee46cbe':
  RED-4686: Added jackson-commons to fix InvalidDefinitionException: Java 8 date/time type java.time.OffsetDateTime
2022-07-22 15:08:22 +02:00
deiflaender 2e5ba30b32 RED-4686: Added jackson-commons to fix InvalidDefinitionException: Java 8 date/time type java.time.OffsetDateTime 2022-07-22 15:04:07 +02:00
Dominique Eiflaender 17783c7e1d Pull request #427: RED-4686: Stream objects to storage
Merge in RED/redaction-service from RED-4686-backport to release/3.107.x

* commit 'bb433a09974d048291a362d7fb9f6e3cf431543d':
  RED-4686: Stream objects to storage
2022-07-22 14:19:34 +02:00
deiflaender bb433a0997 RED-4686: Stream objects to storage 2022-07-22 14:14:59 +02:00
Ali Oezyetimoglu 2564136407 Pull request #423: RED-4548: Create SIMPLIFIED_TEXT.json from TEXT.json (for NER-service)
Merge in RED/redaction-service from RED-4548-rs2PORT to release/3.107.x

* commit '15676ba13ad5cb4741092c2ad72fe582b3465cc2':
  RED-4548: Create SIMPLIFIED_TEXT.json from TEXT.json (for NER-service)
2022-07-14 17:09:20 +02:00
Ali Oezyetimoglu 15676ba13a RED-4548: Create SIMPLIFIED_TEXT.json from TEXT.json (for NER-service) 2022-07-14 17:04:29 +02:00
Ali Oezyetimoglu a76eedb4cf Pull request #421: RED-4548: PORT: Create SIMPLIFIED_TEXT.json from TEXT.json (for NER-service)
Merge in RED/redaction-service from RED-4548-rs1PORT to release/3.107.x

* commit '8eef6ab3faa92da5f4d510131805614abda14c9a':
  RED-4548: PORT: Create SIMPLIFIED_TEXT.json from TEXT.json (for NER-service)
2022-07-14 11:53:53 +02:00
Ali Oezyetimoglu 8eef6ab3fa RED-4548: PORT: Create SIMPLIFIED_TEXT.json from TEXT.json (for NER-service) 2022-07-14 11:50:51 +02:00
Dominique Eiflaender 637f7bc502 Pull request #410: RED-4218: Do not perform surrounding text analysis for resize redactions with value = null
Merge in RED/redaction-service from RED-4218 to release/3.107.x

* commit '3c09f0a63f9e0010ce65d9d6281606c6118365d3':
  RED-4218: Do not perform surrounding text analysis for resize redactions with value = null
2022-06-13 12:32:05 +02:00
deiflaender 3c09f0a63f RED-4218: Do not perform surrounding text analysis for resize redactions with value = null 2022-06-13 12:28:24 +02:00
Dominique Eiflaender 166a30bcc9 Pull request #391: RED-4075: Add legalBasis if Rule Entity overrides Ai Recommendation
Merge in RED/redaction-service from RED-4075-backport to release/3.107.x

* commit 'f4281bf40a6ff15bfeceb6eeacb64bfa6fc49c4f':
  RED-4075: Add legalBasis if Rule Entity overrides Ai Recommendation
2022-05-23 14:24:34 +02:00
deiflaender f4281bf40a RED-4075: Add legalBasis if Rule Entity overrides Ai Recommendation 2022-05-23 14:19:17 +02:00
Timo Bejan b820463fff RED-3800 Exception handling for processed files 2022-05-04 12:09:46 +03:00
Dominique Eiflaender bbd60e4bf4 Pull request #379: RED-3774: Always prefer entities over recommendactions
Merge in RED/redaction-service from RED-3774 to master

* commit 'ecf794ff37ae5cdeb8aa63f69d6e5205c6da1271':
  RED-3774: Always prefer entities over recommendactions
2022-04-20 12:20:01 +02:00
deiflaender ecf794ff37 RED-3774: Always prefer entities over recommendactions 2022-04-20 12:07:31 +02:00
Dominique Eiflaender 5d8f44d55d Pull request #378: RED-3658: Fixed annotation positions for document with rotation = 180 and text direction = 180
Merge in RED/redaction-service from RED-3658 to master

* commit '513fbbb38d2b9efff6b58489c518db53961e9464':
  RED-3658: Fixed annotation positions for document with rotation = 180 and text direction = 180
2022-04-20 10:17:34 +02:00
deiflaender 513fbbb38d RED-3658: Fixed annotation positions for document with rotation = 180 and text direction = 180 2022-04-20 09:58:26 +02:00
Timo Bejan 6178efb7ef Pull request #376: soft delete types RED-3880
Merge in RED/redaction-service from RED-3880 to master

* commit '7a9bb45b6dbfde2ef68c4ac19d4a144a272e5571':
  soft delete types RED-3880
  soft delete types RED-3880
2022-04-19 14:01:31 +02:00
Timo Bejan 7a9bb45b6d soft delete types RED-3880 2022-04-19 14:54:44 +03:00
Timo Bejan 00f2a0cb82 soft delete types RED-3880 2022-04-19 14:32:23 +03:00
Timo Bejan 1eb0485dca Pull request #375: RED-3800 java-18 support
Merge in RED/redaction-service from JAVA-18-support to master

* commit 'be15d38065fc6915f815a586d468235b38362e93':
  RED-3800 java-18 support
2022-04-14 10:52:02 +02:00
Timo Bejan be15d38065 RED-3800 java-18 support 2022-04-14 11:44:47 +03:00
deiflaender f154065824 RED-3877: Fixed missing images after migration 2022-04-14 10:38:30 +02:00
Dominique Eiflaender d4b0de9184 Pull request #374: RED-3616: Fixed removing not redaction images that intersects imported redactions
Merge in RED/redaction-service from RED-3616-11 to master

* commit 'fbd9bc71a80ba7788992c6213fd88ce649e127e2':
  RED-3616: Fixed removing not redaction images that intersects imported redactions
2022-04-12 11:18:53 +02:00
deiflaender fbd9bc71a8 RED-3616: Fixed removing not redaction images that intersects imported redactions 2022-04-12 11:09:25 +02:00
Dominique Eiflaender c963c7ac32 Pull request #373: RED-3666: Added rule function Section containsRegEx
Merge in RED/redaction-service from RED-3666 to master

* commit '404fd25be0e8ee20528c1f9491f85d8b695a2433':
  RED-3666: Added rule function Section containsRegEx
2022-04-11 13:02:02 +02:00
deiflaender 404fd25be0 RED-3666: Added rule function Section containsRegEx 2022-04-11 12:57:57 +02:00
Kresnadi Budisantoso efd53066c4 Pull request #371: RED-3761 Fix expandByRegEx and expandByPrefixRegEx
Merge in RED/redaction-service from kbudisantoso/RED-3761-fix-filter-expanded to master

* commit '5b5d898b933c3ae79fb7cb07a6105b15d2952f8e':
  RED-3761 Fix expandByRegEx and expandByPrefixRegEx
2022-04-11 12:51:57 +02:00
Kresnadi Budisantoso 5b5d898b93 RED-3761 Fix expandByRegEx and expandByPrefixRegEx
Adjusted the overlap test to ignore if the compared entities are subsets
of each other (start or end position is equal). The `removeEntitiesContainedInLarger`
instruction will remove the subset entity.
2022-04-11 11:54:30 +02:00
Dominique Eiflaender cf75ac56cc Pull request #372: RED-3802: Fixed prefer redactions over recommendations
Merge in RED/redaction-service from RED-3802 to master

* commit '1a6a1a008f76897f01f10dd40ea0307c2c84175c':
  RED-3802: Fixed prefer redactions over recommendations
2022-04-11 11:04:55 +02:00
deiflaender 1a6a1a008f RED-3802: Fixed prefer redactions over recommendations 2022-04-11 11:00:07 +02:00
Ali Oezyetimoglu e19b4573bb Pull request #370: RED-3809: Upgrade to latest spring version
Merge in RED/redaction-service from RED-3809-rs1 to master

* commit '150ee92c1e63de2145a1a093e6c6fe7820b7256d':
  RED-3809: Upgrade to latest spring version
2022-04-08 11:40:40 +02:00
aoezyetimoglu 150ee92c1e RED-3809: Upgrade to latest spring version 2022-04-08 11:19:53 +02:00
Kresnadi Budisantoso 7988a8de66 Pull request #369: RED-3761 prevent compiledPrefixPattern to be nullable by testing prefixPattern parameter
Merge in RED/redaction-service from kbudisantoso/RED-3761-prevent-nullable to master

* commit '0014d7725ab3f82d2fba4f0677c3966324504876':
  RED-3761 prevent compiledPrefixPattern to be nullable by testing prefixPattern parameter
2022-04-06 12:52:24 +02:00
Kresnadi Budisantoso 0014d7725a RED-3761 prevent compiledPrefixPattern to be nullable by testing prefixPattern parameter 2022-04-06 11:38:20 +02:00
Christoph Schabert 55f608cf99 Pull request #368: verify version finding
Merge in RED/redaction-service from autoRelease to master

* commit '52e5c58d6e2a30744b3c9b5220edb102b457c8b0':
  verify version finding
2022-04-06 11:03:54 +02:00
cschabert f3ad0749b8 add build version output 2022-04-05 11:15:37 +02:00
Dominique Eiflaender 0f0aee9480 Pull request #367: RED-3616: Do not remove annotation that intersects with skipped imported redactions
Merge in RED/redaction-service from RED-3616 to master

* commit '941448492bfe294634a8c3c309f237034245e842':
  RED-3616: Do not remove annotation that intersects with skipped imported redactions
2022-04-05 10:22:08 +02:00
cschabert ff22dd1a49 verify version check 2022-04-05 09:26:05 +02:00
cschabert 52e5c58d6e verify version finding 2022-04-05 09:22:31 +02:00
deiflaender 941448492b RED-3616: Do not remove annotation that intersects with skipped imported redactions 2022-04-05 08:59:18 +02:00
Christoph Schabert 49d47a0682 Pull request #365: Change Major Version to 3.x
Merge in RED/redaction-service from cschabert/pomxml-1649055501527 to master

* commit '9bab1205b711d94888a6b3364a41a89d07d310b6':
  Change Major Version to 3.x
2022-04-04 09:21:17 +02:00
Christoph Schabert 9bab1205b7 Change Major Version to 3.x 2022-04-04 08:58:35 +02:00
Kresnadi Budisantoso 7963c57552 Pull request #364: RED-3761 add possibility to expand dictionary match with a prefix regex pattern
Merge in RED/redaction-service from kbudisantoso/RED-3761-expandByPrefixRegEx to master

* commit '1427087d8fa29a218b8b378f83c345c497a26b77':
  RED-3761 add possibility to expand dictionary match with a prefix regex pattern
2022-04-01 15:35:45 +02:00
Kresnadi Budisantoso 1427087d8f RED-3761 add possibility to expand dictionary match with a prefix regex pattern 2022-04-01 14:21:47 +02:00
Christoph Schabert b83400ffa3 Pull request #362: automate releases
Merge in RED/redaction-service from autoRelease to master

* commit 'f05f2b21a46b8a4f15bd933570d5a107351aa7b7':
  automate releases
2022-04-01 14:12:09 +02:00
cschabert f05f2b21a4 automate releases 2022-04-01 13:47:26 +02:00
32 changed files with 542 additions and 199 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>com.atlassian.bamboo</groupId>
<artifactId>bamboo-specs-parent</artifactId>
<version>8.0.3</version>
<version>8.1.3</version>
<relativePath/>
</parent>
@@ -17,6 +17,7 @@ import com.atlassian.bamboo.specs.api.builders.plan.branches.BranchCleanup;
import com.atlassian.bamboo.specs.api.builders.plan.branches.PlanBranchManagement;
import com.atlassian.bamboo.specs.api.builders.project.Project;
import com.atlassian.bamboo.specs.builders.task.CheckoutItem;
import com.atlassian.bamboo.specs.api.builders.Variable;
import com.atlassian.bamboo.specs.builders.task.InjectVariablesTask;
import com.atlassian.bamboo.specs.builders.task.ScriptTask;
import com.atlassian.bamboo.specs.builders.task.VcsCheckoutTask;
@@ -83,6 +84,7 @@ public class PlanSpec {
project(),
SERVICE_NAME, new BambooKey(SERVICE_KEY))
.description("Plan created from (enter repository url of your plan)")
.variables(new Variable("maven_add_param", ""))
.stages(new Stage("Default Stage")
.jobs(new Job("Default Job",
new BambooKey("JOB1"))
@@ -94,6 +96,7 @@ public class PlanSpec {
"rm -rf ./*"),
new VcsCheckoutTask()
.description("Checkout Default Repository")
.cleanCheckout(true)
.checkoutItems(new CheckoutItem().defaultRepository()),
new ScriptTask()
.description("Build")
@@ -115,7 +118,7 @@ public class PlanSpec {
.defaultRepository())
.dockerConfiguration(
new DockerConfiguration()
.image("nexus.iqser.com:5001/infra/maven:3.6.2-jdk-13-3.0.0")
.image("nexus.iqser.com:5001/infra/maven:3.8.4-openjdk-17-slim")
.volume("/etc/maven/settings.xml", "/usr/share/maven/ref/settings.xml")
.volume("/var/run/docker.sock", "/var/run/docker.sock")
)
@@ -147,6 +150,7 @@ public class PlanSpec {
"rm -rf ./*"),
new VcsCheckoutTask()
.description("Checkout Default Repository")
.cleanCheckout(true)
.checkoutItems(new CheckoutItem().defaultRepository()),
new ScriptTask()
.description("Sonar")
@@ -155,9 +159,9 @@ public class PlanSpec {
.argument(SERVICE_NAME))
.dockerConfiguration(
new DockerConfiguration()
.image("nexus.iqser.com:5001/infra/maven:3.6.2-jdk-13-3.0.0")
.image("nexus.iqser.com:5001/infra/maven:3.8.4-openjdk-17-slim")
.dockerRunArguments("--net=host")
.volume("/etc/maven/settings.xml", "/usr/share/maven/ref/settings.xml")
.volume("/etc/maven/settings.xml", "/usr/share/maven/conf/settings.xml")
.volume("/var/run/docker.sock", "/var/run/docker.sock")
)
)
@@ -165,8 +169,7 @@ public class PlanSpec {
.linkedRepositories("RED / " + SERVICE_NAME)
.triggers(
new ScheduledTrigger()
.scheduleOnceDaily(LocalTime.of(12, 00)),
new BitbucketServerTrigger())
.scheduleOnceDaily(LocalTime.of(23, 00)))
.planBranchManagement(new PlanBranchManagement()
.createForVcsBranchMatching("release.*")
.notificationForCommitters());
@@ -3,49 +3,62 @@ set -e
SERVICE_NAME=$1
if [[ "${bamboo_version_tag}" = "dev" ]]
then
${bamboo_capability_system_builder_mvn3_Maven_3}/bin/mvn \
-f ${bamboo_build_working_directory}/$SERVICE_NAME-v1/pom.xml \
if [[ "$bamboo_planRepository_branchName" == "master" ]]
then
branchVersion=$(cat pom.xml | grep -Eo " <version>.*-SNAPSHOT</version>" | sed -s 's|<version>\(.*\)\..*\(-*.*\)</version>|\1|' | tr -d ' ')
latestVersion=$( semver $(git tag -l "${branchVersion}.*" ) | tail -n1 )
newVersion="$(semver $latestVersion -p -i minor)"
echo "new release on master with version $newVersion"
elif [[ "$bamboo_planRepository_branchName" == release* ]]
then
branchVersion=$(echo $bamboo_planRepository_branchName | sed -s 's|release\/\([0-9]\+\.[0-9]\+\)\.x|\1|')
latestVersion=$( semver $(git tag -l "${branchVersion}.*" ) | tail -n1 )
newVersion="$(semver $latestVersion -p -i patch)"
echo "new release on $bamboo_planRepository_branchName with version $newVersion"
elif [[ "${bamboo_version_tag}" != "dev" ]]
then
newVersion="${bamboo_version_tag}"
echo "new special version bild with $newVersion"
else
mvn -f ${bamboo_build_working_directory}/$SERVICE_NAME-v1/pom.xml \
--no-transfer-progress \
${bamboo_maven_add_param} \
clean install \
-Djava.security.egd=file:/dev/./urandomelse
else
${bamboo_capability_system_builder_mvn3_Maven_3}/bin/mvn \
--no-transfer-progress \
-f ${bamboo_build_working_directory}/$SERVICE_NAME-v1/pom.xml \
versions:set \
-DnewVersion=${bamboo_version_tag}
${bamboo_capability_system_builder_mvn3_Maven_3}/bin/mvn \
--no-transfer-progress \
-f ${bamboo_build_working_directory}/$SERVICE_NAME-image-v1/pom.xml \
versions:set \
-DnewVersion=${bamboo_version_tag}
${bamboo_capability_system_builder_mvn3_Maven_3}/bin/mvn \
-f ${bamboo_build_working_directory}/$SERVICE_NAME-v1/pom.xml \
--no-transfer-progress \
clean deploy \
-e \
-DdeployAtEnd=true \
-Dmaven.wagon.http.ssl.insecure=true \
-Dmaven.wagon.http.ssl.allowall=true \
-Dmaven.wagon.http.ssl.ignore.validity.dates=true \
-DaltDeploymentRepository=iqser_release::default::https://nexus.iqser.com/repository/red-platform-releases
echo "dev build with tag ${bamboo_planRepository_1_branch}_${bamboo_buildNumber}"
echo "gitTag=${bamboo_planRepository_1_branch}_${bamboo_buildNumber}" > git.tag
exit 0
fi
${bamboo_capability_system_builder_mvn3_Maven_3}/bin/mvn \
echo "gitTag=${newVersion}" > git.tag
mvn --no-transfer-progress \
-f ${bamboo_build_working_directory}/$SERVICE_NAME-v1/pom.xml \
${bamboo_maven_add_param} \
versions:set \
-DnewVersion=${newVersion}
mvn --no-transfer-progress \
-f ${bamboo_build_working_directory}/$SERVICE_NAME-image-v1/pom.xml \
${bamboo_maven_add_param} \
versions:set \
-DnewVersion=${newVersion}
mvn -f ${bamboo_build_working_directory}/$SERVICE_NAME-v1/pom.xml \
--no-transfer-progress \
clean deploy \
${bamboo_maven_add_param} \
-e \
-DdeployAtEnd=true \
-Dmaven.wagon.http.ssl.insecure=true \
-Dmaven.wagon.http.ssl.allowall=true \
-Dmaven.wagon.http.ssl.ignore.validity.dates=true \
-DaltDeploymentRepository=iqser_release::default::https://nexus.iqser.com/repository/red-platform-releases
mvn --no-transfer-progress \
-f ${bamboo_build_working_directory}/$SERVICE_NAME-image-v1/pom.xml \
package
${bamboo_capability_system_builder_mvn3_Maven_3}/bin/mvn \
--no-transfer-progress \
mvn --no-transfer-progress \
-f ${bamboo_build_working_directory}/$SERVICE_NAME-image-v1/pom.xml \
docker:push
if [[ "${bamboo_version_tag}" = "dev" ]]
then
echo "gitTag=${bamboo_planRepository_1_branch}_${bamboo_buildNumber}" > git.tag
else
echo "gitTag=${bamboo_version_tag}" > git.tag
fi
@@ -3,46 +3,42 @@ set -e
SERVICE_NAME=$1
${bamboo_capability_system_builder_mvn3_Maven_3}/bin/mvn \
-f ${bamboo_build_working_directory}/$SERVICE_NAME-v1/pom.xml \
echo "build jar binaries"
mvn -f ${bamboo_build_working_directory}/$SERVICE_NAME-v1/pom.xml \
--no-transfer-progress \
clean install \
-Djava.security.egd=file:/dev/./urandomelse
echo "dependency-check:aggregate"
${bamboo_capability_system_builder_mvn3_Maven_3}/bin/mvn \
--no-transfer-progress \
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
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
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
+2 -2
View File
@@ -7,7 +7,7 @@
<artifactId>redaction-service</artifactId>
<groupId>com.iqser.red.service</groupId>
<version>1.0-SNAPSHOT</version>
<version>3.0-SNAPSHOT</version>
<packaging>pom</packaging>
@@ -18,4 +18,4 @@
<module>redaction-service-image-v1</module>
</modules>
</project>
</project>
+4 -4
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>platform-dependency</artifactId>
<groupId>com.iqser.red</groupId>
<version>1.6.0</version>
<version>1.10.0</version>
<relativePath />
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -32,7 +32,7 @@
<dependency>
<groupId>com.iqser.red</groupId>
<artifactId>platform-commons-dependency</artifactId>
<version>1.11.0</version>
<version>1.15.0</version>
<scope>import</scope>
<type>pom</type>
</dependency>
@@ -59,7 +59,7 @@
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.9.0.2155</version>
</plugin>
</plugin>
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
@@ -92,7 +92,7 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.7</version>
<version>0.8.8</version>
<executions>
<execution>
<id>prepare-agent</id>
@@ -12,7 +12,7 @@
<artifactId>redaction-service-api-v1</artifactId>
<properties>
<persistence-service.version>1.85.0</persistence-service.version>
<persistence-service.version>1.156.20</persistence-service.version>
</properties>
<dependencies>
@@ -25,6 +25,12 @@
<groupId>com.iqser.red.service</groupId>
<artifactId>persistence-service-api-v1</artifactId>
<version>${persistence-service.version}</version>
<exclusions>
<exclusion>
<groupId>com.iqser.red.service</groupId>
<artifactId>redaction-service-api-v1</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
@@ -66,6 +66,9 @@ public class RedactionLogEntry {
private Set<String> reference = new HashSet<>();
@Builder.Default
private Set<String> importedRedactionIntersections = new HashSet<>();
public boolean lastChangeIsRemoved() {
return last(changes).map(c -> c.getType() == ChangeType.REMOVED).orElse(false);
}
@@ -20,6 +20,11 @@
</properties>
<dependencies>
<dependency>
<groupId>com.iqser.red.commons</groupId>
<artifactId>jackson-commons</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.iqser.red.commons</groupId>
<artifactId>storage-commons</artifactId>
@@ -0,0 +1,18 @@
package com.iqser.red.service.redaction.v1.server.classification.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SimplifiedSectionText {
private int sectionNumber;
private String text;
}
@@ -0,0 +1,20 @@
package com.iqser.red.service.redaction.v1.server.classification.model;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SimplifiedText {
private int numberOfPages;
private List<SimplifiedSectionText> sectionTexts = new ArrayList<>();
}
@@ -1,42 +1,30 @@
package com.iqser.red.service.redaction.v1.server.controller;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.stream.Collectors;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.ManualRedactions;
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.file.FileType;
import com.iqser.red.service.redaction.v1.model.*;
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.NotFoundException;
import com.iqser.red.service.redaction.v1.server.exception.RedactionException;
import com.iqser.red.service.redaction.v1.server.redaction.service.*;
import com.iqser.red.service.redaction.v1.server.segmentation.PdfSegmentationService;
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;
import com.iqser.red.service.redaction.v1.server.visualization.service.PdfVisualisationService;
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 com.iqser.red.service.persistence.service.v1.api.model.annotations.ManualRedactions;
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.dossier.file.FileType;
import com.iqser.red.service.redaction.v1.model.AnnotateRequest;
import com.iqser.red.service.redaction.v1.model.AnnotateResponse;
import com.iqser.red.service.redaction.v1.model.RedactionLog;
import com.iqser.red.service.redaction.v1.model.RedactionRequest;
import com.iqser.red.service.redaction.v1.model.RedactionResult;
import com.iqser.red.service.redaction.v1.model.SectionArea;
import com.iqser.red.service.redaction.v1.model.SectionGrid;
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.NotFoundException;
import com.iqser.red.service.redaction.v1.server.exception.RedactionException;
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.ManualRedactionSurroundingTextService;
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.storage.RedactionStorageService;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.AbstractTextContainer;
import com.iqser.red.service.redaction.v1.server.tableextraction.model.Table;
import com.iqser.red.service.redaction.v1.server.visualization.service.PdfVisualisationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.stream.Collectors;
@Slf4j
@RestController
@@ -197,7 +185,7 @@ public class RedactionController implements RedactionResource {
}
log.info("Loaded redaction log with computationalVersion: {}", redactionLog.getAnalysisVersion());
var merged = redactionLogMergeService.mergeRedactionLogData(redactionLog, sectionGrid, redactionRequest.getDossierTemplateId(), redactionRequest.getManualRedactions(), redactionRequest.getExcludedPages(), redactionRequest.getTypes(), redactionRequest.getColors());
var merged = redactionLogMergeService.mergeRedactionLogData(redactionLog, sectionGrid, redactionRequest.getManualRedactions(), redactionRequest.getExcludedPages(), redactionRequest.getTypes(), redactionRequest.getColors());
merged.getRedactionLogEntry().removeIf(e -> e.isFalsePositive() && !redactionRequest.isIncludeFalsePositives());
@@ -240,7 +240,7 @@ public class TextPositionSequence implements CharSequence {
@JsonIgnore
public Rectangle getRectangle() {
log.debug("Page: '{}', Word: '{}', Rotation: '{}'", page, toString(), textPositions.get(0).getRotation());
log.debug("Page: '{}', Word: '{}', Rotation: '{}', textRotation {}", page, toString(), textPositions.get(0).getRotation(), textPositions.get(0).getDir());
float height = getTextHeight();
@@ -291,6 +291,14 @@ public class TextPositionSequence implements CharSequence {
posXInit = textPositions.get(0).getYDirAdj() + 2;
posXEnd = textPositions.get(textPositions.size() - 1).getYDirAdj() - height;
} else if (textPositions.get(0).getRotation() == 180 && textPositions.get(0).getDir() == 180f) {
posXInit = textPositions.get(0).getPageWidth() - getX1() +1;
posXEnd = textPositions.get(0).getPageWidth() - getX2() + textPositions.get(0).getWidthDirAdj() - textPositions.get(textPositions.size() - 1)
.getWidthDirAdj() - 3;
posYInit = textPositions.get(0).getYDirAdj() - height + 2;
posYEnd = textPositions.get(textPositions.size() - 1)
.getYDirAdj() - height + 2;
} else {
posXEnd = textPositions.get(textPositions.size() - 1)
.getXDirAdj() + textPositions.get(textPositions.size() - 1).getWidthDirAdj() + 1;
@@ -1,12 +1,5 @@
package com.iqser.red.service.redaction.v1.server.queue;
import static com.iqser.red.service.redaction.v1.server.queue.MessagingConfiguration.REDACTION_DQL;
import static com.iqser.red.service.redaction.v1.server.queue.MessagingConfiguration.REDACTION_QUEUE;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.iqser.red.service.redaction.v1.model.AnalyzeRequest;
@@ -15,9 +8,13 @@ import com.iqser.red.service.redaction.v1.model.StructureAnalyzeRequest;
import com.iqser.red.service.redaction.v1.server.client.FileStatusProcessingUpdateClient;
import com.iqser.red.service.redaction.v1.server.redaction.service.AnalyzeService;
import com.iqser.red.service.redaction.v1.server.redaction.service.ManualRedactionSurroundingTextService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;
import static com.iqser.red.service.redaction.v1.server.queue.MessagingConfiguration.REDACTION_DQL;
@Slf4j
@Service
@@ -36,31 +33,37 @@ public class RedactionMessageReceiver {
log.info("Processing priority: {} analyze request for file: {}", priority, analyzeRequest.getFileId());
AnalyzeResult result = null;
switch (analyzeRequest.getMessageType()) {
try {
switch (analyzeRequest.getMessageType()) {
case REANALYSE:
result = analyzeService.reanalyze(analyzeRequest);
log.info("Successfully reanalyzed dossier {} file {} took: {}", analyzeRequest.getDossierId(), analyzeRequest.getFileId(), result.getDuration());
break;
case REANALYSE:
result = analyzeService.reanalyze(analyzeRequest);
log.info("Successfully reanalyzed dossier {} file {} took: {}", analyzeRequest.getDossierId(), analyzeRequest.getFileId(), result.getDuration());
break;
case STRUCTURE_ANALYSE:
result = analyzeService.analyzeDocumentStructure(new StructureAnalyzeRequest(analyzeRequest.getDossierId(), analyzeRequest.getFileId()));
log.info("Successfully analyzed structure dossier {} file {} took: {}", analyzeRequest.getDossierId(), analyzeRequest.getFileId(), result.getDuration());
break;
case STRUCTURE_ANALYSE:
result = analyzeService.analyzeDocumentStructure(new StructureAnalyzeRequest(analyzeRequest.getDossierId(), analyzeRequest.getFileId()));
log.info("Successfully analyzed structure dossier {} file {} took: {}", analyzeRequest.getDossierId(), analyzeRequest.getFileId(), result.getDuration());
break;
case ANALYSE:
result = analyzeService.analyze(analyzeRequest);
log.info("Successfully analyzed dossier {} file {} took: {}", analyzeRequest.getDossierId(), analyzeRequest.getFileId(), result.getDuration());
break;
case ANALYSE:
result = analyzeService.analyze(analyzeRequest);
log.info("Successfully analyzed dossier {} file {} took: {}", analyzeRequest.getDossierId(), analyzeRequest.getFileId(), result.getDuration());
break;
case SURROUNDING_TEXT:
result = manualRedactionSurroundingTextService.addSurroundingText(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), analyzeRequest.getManualRedactions());
log.info("Successfully added surrounding text for manual redaction in dossierId {} and fileId {} took: {}", analyzeRequest.getDossierId(), analyzeRequest.getFileId(), result.getDuration());
break;
case SURROUNDING_TEXT:
result = manualRedactionSurroundingTextService.addSurroundingText(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), analyzeRequest.getManualRedactions());
log.info("Successfully added surrounding text for manual redaction in dossierId {} and fileId {} took: {}", analyzeRequest.getDossierId(), analyzeRequest.getFileId(), result.getDuration());
break;
}
result.setMessageType(analyzeRequest.getMessageType());
fileStatusProcessingUpdateClient.analysisSuccessful(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), result);
} catch (Exception e) {
log.warn("Failed to process analyze request: {}", analyzeRequest, e);
fileStatusProcessingUpdateClient.analysisFailed(analyzeRequest.getDossierId(), analyzeRequest.getFileId());
}
result.setMessageType(analyzeRequest.getMessageType());
fileStatusProcessingUpdateClient.analysisSuccessful(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), result);
}
@@ -240,6 +240,17 @@ public class Section {
}
@WhenCondition
public boolean containsRegEx(@Argument(ArgumentType.STRING) String regEx, @Argument(ArgumentType.BOOLEAN) boolean patternCaseInsensitive){
var compiledPattern = Patterns.getCompiledPattern(regEx, patternCaseInsensitive);
var matcher = compiledPattern.matcher(text);
return matcher.find();
}
@WhenCondition
public boolean rowEquals(@Argument(ArgumentType.STRING) String headerName, @Argument(ArgumentType.STRING) String value) {
@@ -248,6 +259,60 @@ public class Section {
return tabularData != null && tabularData.containsKey(cleanHeaderName) && tabularData.get(cleanHeaderName).toString().equals(value);
}
@ThenAction
public void expandByPrefixRegEx(@Argument(ArgumentType.TYPE) String type, @Argument(ArgumentType.REGEX) String prefixPattern,
@Argument(ArgumentType.BOOLEAN) boolean patternCaseInsensitive, @Argument(ArgumentType.INTEGER) int group) {
expandByPrefixRegEx(type, prefixPattern, patternCaseInsensitive, group, null);
}
@ThenAction
public void expandByPrefixRegEx(@Argument(ArgumentType.TYPE) String type, @Argument(ArgumentType.REGEX) String prefixPattern,
@Argument(ArgumentType.BOOLEAN) boolean patternCaseInsensitive, @Argument(ArgumentType.INTEGER) int group,
@Argument(ArgumentType.REGEX) String valuePattern) {
if (StringUtils.isEmpty(prefixPattern)) return;
var compiledValuePattern = valuePattern == null ? null : Patterns.getCompiledPattern(valuePattern, patternCaseInsensitive);
var compiledPrefixPattern = Patterns.getCompiledPattern(prefixPattern, patternCaseInsensitive);
Set<Entity> expanded = new HashSet<>();
for (var entity : entities) {
if (!entity.getType().equals(type) || entity.getTextBefore() == null) {
continue;
}
if (valuePattern != null) {
var valueMatcher = compiledValuePattern.matcher(entity.getWord());
if (!valueMatcher.matches()) {
continue;
}
}
var matcher = compiledPrefixPattern.matcher(entity.getTextBefore());
while (matcher.find()) {
var match = matcher.group(group);
if (StringUtils.isNotBlank(match)) {
if (!StringUtils.endsWith(entity.getTextBefore(), match)) {
log.warn("Rules contain invalid group for expandByPrefixRegEx command; prefixPattern:{}, group{}", prefixPattern, group);
continue;
}
var expandedEntities = findEntities(match + entity.getWord(), type, false, entity.isRedaction(), entity.getMatchedRule(), entity.getRedactionReason(), entity.getLegalBasis(), Engine.RULE, false);
expanded.addAll(EntitySearchUtils.findNonOverlappingMatchEntities(entities, expandedEntities));
}
}
}
EntitySearchUtils.addEntitiesWithHigherRank(entities, expanded, dictionary);
EntitySearchUtils.removeEntitiesContainedInLarger(entities);
}
@ThenAction
public void expandByRegEx(@Argument(ArgumentType.TYPE) String type, @Argument(ArgumentType.REGEX) String suffixPattern,
@@ -262,13 +327,10 @@ public class Section {
@Argument(ArgumentType.BOOLEAN) boolean patternCaseInsensitive, @Argument(ArgumentType.INTEGER) int group,
@Argument(ArgumentType.REGEX) String valuePattern) {
Pattern compiledValuePattern = null;
if (StringUtils.isEmpty(suffixPattern)) return;
if (valuePattern != null) {
compiledValuePattern = Patterns.getCompiledPattern(valuePattern, patternCaseInsensitive);
}
Pattern compiledPattern = Patterns.getCompiledPattern(suffixPattern, patternCaseInsensitive);
var compiledValuePattern = valuePattern == null ? null : Patterns.getCompiledPattern(valuePattern, patternCaseInsensitive);
var compiledSuffixPattern = Patterns.getCompiledPattern(suffixPattern, patternCaseInsensitive);
Set<Entity> expanded = new HashSet<>();
for (Entity entity : entities) {
@@ -278,19 +340,25 @@ public class Section {
}
if (valuePattern != null) {
Matcher valueMatcher = compiledValuePattern.matcher(entity.getWord());
var valueMatcher = compiledValuePattern.matcher(entity.getWord());
if (!valueMatcher.matches()) {
continue;
}
}
Matcher matcher = compiledPattern.matcher(entity.getTextAfter());
var matcher = compiledSuffixPattern.matcher(entity.getTextAfter());
while (matcher.find()) {
String match = matcher.group(group);
var 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(), Engine.RULE, false);
if (!StringUtils.startsWith(entity.getTextAfter(), match)) {
log.warn("Rules contain invalid group for expandByRegEx command; suffixPattern:{}, group{}", suffixPattern, group);
continue;
}
var expandedEntities = findEntities(entity.getWord() + match, type, false, entity.isRedaction(), entity.getMatchedRule(), entity.getRedactionReason(), entity.getLegalBasis(), Engine.RULE, false);
expanded.addAll(EntitySearchUtils.findNonOverlappingMatchEntities(entities, expandedEntities));
}
}
@@ -3,6 +3,9 @@ package com.iqser.red.service.redaction.v1.server.redaction.model.image;
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
@@ -10,6 +13,9 @@ public class ImageServiceResponse {
private String dossierId;
private String fileId;
@JsonProperty(value = "imageMetadata")
@JsonAlias("data")
private List<ImageMetadata> data = new ArrayList<>();
}
@@ -2,10 +2,12 @@ package com.iqser.red.service.redaction.v1.server.redaction.service;
import static com.iqser.red.service.redaction.v1.server.redaction.service.ImportedRedactionService.IMPORTED_REDACTION_TYPE;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -30,6 +32,8 @@ import com.iqser.red.service.redaction.v1.model.SectionGrid;
import com.iqser.red.service.redaction.v1.model.StructureAnalyzeRequest;
import com.iqser.red.service.redaction.v1.server.classification.model.Document;
import com.iqser.red.service.redaction.v1.server.classification.model.SectionText;
import com.iqser.red.service.redaction.v1.server.classification.model.SimplifiedSectionText;
import com.iqser.red.service.redaction.v1.server.classification.model.SimplifiedText;
import com.iqser.red.service.redaction.v1.server.classification.model.Text;
import com.iqser.red.service.redaction.v1.server.client.LegalBasisClient;
import com.iqser.red.service.redaction.v1.server.client.model.NerEntities;
@@ -104,8 +108,9 @@ public class AnalyzeService {
.map(SectionArea::getPage)
.collect(Collectors.toSet()), sectionText.getSectionAreas())));
log.info("Store text and section grid for file {} in dossier {}", analyzeRequest.getFileId(), analyzeRequest.getDossierId());
log.info("Store text, simplified text and section grid for file {} in dossier {}", analyzeRequest.getFileId(), analyzeRequest.getDossierId());
redactionStorageService.storeObject(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), FileType.TEXT, text);
redactionStorageService.storeObject(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), FileType.SIMPLIFIED_TEXT, convert(text));
redactionStorageService.storeObject(analyzeRequest.getDossierId(), analyzeRequest.getFileId(), FileType.SECTION_GRID, classifiedDoc.getSectionGrid());
return AnalyzeResult.builder()
@@ -310,4 +315,16 @@ public class AnalyzeService {
}
}
private SimplifiedText convert(Text text) {
List<SimplifiedSectionText> sectionTexts = new ArrayList<>();
int numberOfPages = 0;
if (text != null) {
numberOfPages = text.getNumberOfPages();
text.getSectionTexts().stream().filter(Objects::nonNull).forEach(st -> sectionTexts.add(new SimplifiedSectionText(st.getSectionNumber(), st.getText())));
}
return SimplifiedText.builder().numberOfPages(numberOfPages).sectionTexts(sectionTexts).build();
}
}
@@ -102,7 +102,8 @@ public class DictionaryService {
try {
DictionaryRepresentation dictionaryRepresentation = new DictionaryRepresentation();
var typeResponse = dossierId == null ? dictionaryClient.getAllTypesForDossierTemplate(dossierTemplateId) : dictionaryClient.getAllTypesForDossier(dossierId);
var typeResponse = dossierId == null ? dictionaryClient.getAllTypesForDossierTemplate(dossierTemplateId, false)
: dictionaryClient.getAllTypesForDossier(dossierId, false);
if (CollectionUtils.isNotEmpty(typeResponse)) {
List<DictionaryModel> dictionary = typeResponse
@@ -1,6 +1,6 @@
package com.iqser.red.service.redaction.v1.server.redaction.service;
import java.util.Iterator;
import java.util.HashSet;
import java.util.List;
import org.springframework.stereotype.Service;
@@ -24,14 +24,15 @@ public class ImportedRedactionService {
public List<RedactionLogEntry> processImportedRedactions(String dossierTemplateId, String dossierId, String fileId,
List<RedactionLogEntry> redactionLogEntries, boolean addImportedRedactions) {
List<RedactionLogEntry> redactionLogEntries,
boolean addImportedRedactions) {
var importedRedactions = redactionStorageService.getImportedRedactions(dossierId, fileId);
if (importedRedactions == null) {
return redactionLogEntries;
}
redactionLogEntries.removeIf(redactionLogEntry -> hasIntersections(redactionLogEntry, importedRedactions));
redactionLogEntries.forEach(redactionLogEntry -> addIntersections(redactionLogEntry, importedRedactions));
if (addImportedRedactions) {
return addImportedRedactionsRedactionLogEntries(dossierTemplateId, redactionLogEntries, importedRedactions);
@@ -42,8 +43,8 @@ public class ImportedRedactionService {
private List<RedactionLogEntry> addImportedRedactionsRedactionLogEntries(String dossierTemplateId,
List<RedactionLogEntry> redactionLogEntries,
ImportedRedactions importedRedactions) {
List<RedactionLogEntry> redactionLogEntries,
ImportedRedactions importedRedactions) {
for (List<ImportedRedaction> importedRedactionsValues : importedRedactions.getImportedRedactions().values()) {
for (ImportedRedaction importedRedaction : importedRedactionsValues) {
@@ -53,7 +54,7 @@ public class ImportedRedactionService {
.imported(true)
.redacted(true)
.positions(importedRedaction.getPositions())
.color(getColor("imported_redaction", dossierTemplateId))
.color(getColor(IMPORTED_REDACTION_TYPE, dossierTemplateId))
.build();
redactionLogEntries.add(redactionLogEntry);
@@ -64,7 +65,7 @@ public class ImportedRedactionService {
}
private boolean hasIntersections(RedactionLogEntry redactionLogEntry, ImportedRedactions importedRedactions) {
private void addIntersections(RedactionLogEntry redactionLogEntry, ImportedRedactions importedRedactions) {
for (Rectangle rectangle : redactionLogEntry.getPositions()) {
if (importedRedactions.getImportedRedactions().containsKey(rectangle.getPage())) {
@@ -72,13 +73,15 @@ public class ImportedRedactionService {
for (ImportedRedaction importedRedaction : importedRedactionsOnPage) {
for (Rectangle importedRedactionPosition : importedRedaction.getPositions()) {
if (intersects(importedRedactionPosition, rectangle)) {
return true;
if(redactionLogEntry.getImportedRedactionIntersections() == null){
redactionLogEntry.setImportedRedactionIntersections(new HashSet<>());
}
redactionLogEntry.getImportedRedactionIntersections().add(importedRedaction.getId());
}
}
}
}
}
return false;
}
@@ -65,7 +65,7 @@ public class ManualRedactionSurroundingTextService {
var resizeItty = manualRedactions.getResizeRedactions().iterator();
while (resizeItty.hasNext()) {
var manualResizeRedaction = resizeItty.next();
if (sectionContainsEntry(sectionArea, manualResizeRedaction.getPositions())) {
if (manualResizeRedaction.getValue() != null && sectionContainsEntry(sectionArea, manualResizeRedaction.getPositions())) {
var surroundingText = findSurroundingText(sectionText, manualResizeRedaction.getValue(), manualResizeRedaction.getPositions());
manualResizeRedaction.setTextBefore(surroundingText.getLeft());
manualResizeRedaction.setTextAfter(surroundingText.getRight());
@@ -6,6 +6,8 @@ import com.iqser.red.service.persistence.service.v1.api.model.annotations.Manual
import com.iqser.red.service.persistence.service.v1.api.model.annotations.entitymapped.*;
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.configuration.Colors;
import com.iqser.red.service.persistence.service.v1.api.model.dossiertemplate.type.Type;
import com.iqser.red.service.redaction.v1.model.Point;
import com.iqser.red.service.redaction.v1.model.Rectangle;
import com.iqser.red.service.redaction.v1.model.*;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -13,8 +15,9 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.awt.Color;
import java.awt.*;
import java.time.OffsetDateTime;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
@@ -27,13 +30,15 @@ public class RedactionLogMergeService {
private final SectionTextService sectionTextService;
public RedactionLog mergeRedactionLogData(RedactionLog redactionLog, SectionGrid sectionGrid,
String dossierTemplateId, ManualRedactions manualRedactions,
public RedactionLog mergeRedactionLogData(RedactionLog redactionLog, SectionGrid sectionGrid, ManualRedactions manualRedactions,
Set<Integer> excludedPages, List<Type> types, Colors colors) {
var skippedImportedRedactions = new HashSet<>();
log.info("Merging Redaction log with manual redactions");
if (manualRedactions != null) {
var manualRedactionLogEntries = addManualAddEntries(sectionGrid, manualRedactions.getEntriesToAdd(), manualRedactions.getComments(), colors, types);
redactionLog.getRedactionLogEntry().addAll(manualRedactionLogEntries);
@@ -46,6 +51,10 @@ public class RedactionLogMergeService {
.filter(mr -> entry.getId().equals(mr.getId()))
.collect(Collectors.toList()), entry, types, colors);
if (entry.isImported() && !entry.isRedacted()) {
skippedImportedRedactions.add(entry.getId());
}
entry.setComments(manualRedactions.getComments().get(entry.getId()));
if (excludedPages != null && !excludedPages.isEmpty()) {
@@ -61,6 +70,12 @@ public class RedactionLogMergeService {
Set<String> processedIds = new HashSet<>();
redactionLog.getRedactionLogEntry().removeIf(entry -> {
if (entry.getImportedRedactionIntersections() != null) {
entry.getImportedRedactionIntersections().removeAll(skippedImportedRedactions);
if (!entry.getImportedRedactionIntersections().isEmpty() && (!entry.isImage() || entry.isImage() && !(entry.getType().equals("image") || entry.getType().equals("ocr")))) {
return true;
}
}
if (processedIds.contains(entry.getId())) {
log.info("Duplicate annotation found with id {}", entry.getId());
return true;
@@ -367,20 +382,25 @@ public class RedactionLogMergeService {
private float[] getColor(List<Type> types, String type) {
Optional<Type> foundType = types.stream().filter(t -> t.getType().equals(type)).findFirst();
if (foundType.isPresent()){
return convertColor(foundType.get().getHexColor());
var matchingTypes = getMatchingTypes(types, type);
Optional<Type> foundAndNotDeletedType = matchingTypes.stream().filter(t -> !isDeletedType(t)).findFirst();
if (foundAndNotDeletedType.isPresent()) {
return convertColor(foundAndNotDeletedType.get().getHexColor());
}
return convertColor("#9398a0");
Optional<Type> firstDeletedType = matchingTypes.stream().findFirst();
return firstDeletedType.map(value -> convertColor(value.getHexColor())).orElseGet(() -> convertColor("#9398a0"));
}
boolean isHint(List<Type> types, String type){
Optional<Type> foundType = types.stream().filter(t -> t.getType().equals(type)).findFirst();
if (foundType.isPresent()){
return foundType.get().isHint();
boolean isHint(List<Type> types, String type) {
var matchingTypes = getMatchingTypes(types, type);
Optional<Type> foundAndNotDeletedType = matchingTypes.stream().filter(t -> !isDeletedType(t)).findFirst();
if (foundAndNotDeletedType.isPresent()) {
return foundAndNotDeletedType.get().isHint();
}
return false;
Optional<Type> firstDeletedType = matchingTypes.stream().findFirst();
return firstDeletedType.map(Type::isHint).orElse(false);
}
@@ -390,6 +410,14 @@ public class RedactionLogMergeService {
return new float[]{color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f};
}
private List<Type> getMatchingTypes(List<Type> types, String type) {
return types.stream().filter(t -> t.getType().equals(type)).collect(Collectors.toList());
}
private boolean isDeletedType(Type type) {
return type.getSoftDeletedTime() != null;
}
@Data
@AllArgsConstructor
@@ -62,14 +62,16 @@ public class EntitySearchUtils {
Set<Entity> found = find(inputString, values, type.getType(), headline, sectionNumber, isDictionaryEntry, isDossierDictionary, engine, ignoreMinLength, asRecommendation ? EntityType.RECOMMENDATION : EntityType.ENTITY);
if(asRecommendation){
Set<Entity> falseRecommendations = find(inputString, type.getFalseRecommendationValues(), type.getType(), headline, sectionNumber, isDictionaryEntry, isDossierDictionary, engine, ignoreMinLength, EntityType.FALSE_RECOMMENDATION);
if (details.getEntityType() == EntityType.RECOMMENDATION) {
Set<Entity> falseRecommendations = find(inputString, type.getFalseRecommendationsSearch(), details.withEntityType(EntityType.FALSE_RECOMMENDATION));
removeFalsePositives(found, falseRecommendations);
found.addAll(falseRecommendations);
// RED-4799 - false positives are no longer in redaction log
// found.addAll(falseRecommendations);
} else {
Set<Entity> falsePositives = find(inputString, type.getFalsePositiveValues(), type.getType(), headline, sectionNumber, isDictionaryEntry, isDossierDictionary, engine, ignoreMinLength, EntityType.FALSE_POSITIVE);
Set<Entity> falsePositives = find(inputString, type.getFalsePositiveSearch(), details.withEntityType(EntityType.FALSE_POSITIVE));
removeFalsePositives(found, falsePositives);
found.addAll(falsePositives);
// RED-4799 - false positives are no longer in redaction log
// found.addAll(falsePositives);
}
return found;
@@ -164,9 +166,18 @@ public class EntitySearchUtils {
List<Entity> wordsToRemove = new ArrayList<>();
for (Entity word : entities) {
for (Entity inner : entities) {
// skip cross-type false positives
if(word.getEntityType() == EntityType.FALSE_POSITIVE && inner.getEntityType() == EntityType.ENTITY && !inner.getType().equals(word.getType())){
continue;
}
// skip cross-type false reccommendations
if(word.getEntityType() == EntityType.FALSE_RECOMMENDATION && inner.getEntityType() == EntityType.RECOMMENDATION && !inner.getType().equals(word.getType())){
continue;
}
if (inner.getWord().length() < word.getWord()
.length() && inner.getStart() >= word.getStart() && inner.getEnd() <= word.getEnd() && word != inner && word.getSectionNumber() == inner.getSectionNumber()) {
if (word.getEntityType().equals(EntityType.RECOMMENDATION) && word.getEntityType().equals(EntityType.ENTITY)) {
if (word.getEntityType().equals(EntityType.RECOMMENDATION) && inner.getEntityType().equals(EntityType.ENTITY)) {
wordsToRemove.add(word);
} else {
wordsToRemove.add(inner);
@@ -223,6 +234,16 @@ public class EntitySearchUtils {
if (existing.getType().equals(found.getType())) {
existing.getEngines().addAll(found.getEngines());
existing.setLegalBasis(found.getLegalBasis());
existing.setMatchedRule(found.getMatchedRule());
existing.setRedactionReason(found.getRedactionReason());
if(existing.getEntityType().equals(EntityType.RECOMMENDATION) && found.getEntityType().equals(EntityType.ENTITY)
|| existing.getEntityType().equals(EntityType.ENTITY) && found.getEntityType().equals(EntityType.RECOMMENDATION)){
existing.setEntityType(EntityType.ENTITY);
if(found.isRedaction()){
existing.setRedaction(true);
}
}
} else if (dictionary.getDictionaryRank(existing.getType()) <= dictionary.getDictionaryRank(found.getType())) {
entities.remove(found);
entities.add(found);
@@ -280,18 +301,25 @@ public class EntitySearchUtils {
}
var existingEntity = existingOptional.get();
existingEntity.getEngines().addAll(toAdd.getEngines());
existingEntity.setLegalBasis(toAdd.getLegalBasis());
existingEntity.setMatchedRule(toAdd.getMatchedRule());
existingEntity.setRedactionReason(toAdd.getRedactionReason());
} else {
existing.add(toAdd);
}
}
}
/*
* returns true if the found entity overlaps with an existing entity in a way
* that neither entity is a subset of the other
*/
private boolean overlaps(Set<Entity> existingEntities, Entity found) {
for (Entity existing : existingEntities) {
if (existing.getStart().equals(found.getStart())) {
// skip if either start or end is equal
if (existing.getStart().equals(found.getStart()) || existing.getEnd().equals(found.getEnd())) {
continue;
}
@@ -1,5 +1,6 @@
package com.iqser.red.service.redaction.v1.server.storage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -41,7 +42,10 @@ public class RedactionStorageService {
@SneakyThrows
public void storeObject(String dossierId, String fileId, FileType fileType, Object any) {
storageService.storeObject(StorageIdUtils.getStorageId(dossierId, fileId, fileType), objectMapper.writeValueAsBytes(any));
try (var baos = new ByteArrayOutputStream()){
objectMapper.writeValue(baos, any);
storageService.storeObject(StorageIdUtils.getStorageId(dossierId, fileId, fileType), baos);
}
}
@@ -9,6 +9,8 @@ server:
port: 8080
spring:
main:
allow-circular-references: true # FIXME
profiles:
active: kubernetes
rabbitmq:
@@ -7,18 +7,20 @@ import lombok.SneakyThrows;
import org.apache.commons.io.IOUtils;
import org.springframework.core.io.InputStreamResource;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Map;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.GZIPOutputStream;
public class FileSystemBackedStorageService extends S3StorageService {
public class FileSystemBackedStorageService implements StorageService{
private final Map<String, File> dataMap = new HashMap<>();
public FileSystemBackedStorageService() {
super(null, null);
}
@SneakyThrows
@@ -33,20 +35,73 @@ public class FileSystemBackedStorageService extends S3StorageService {
}
@Override
public void deleteObject(String objectId) {
dataMap.remove(objectId);
}
@Override
public boolean objectExists(String objectId) {
return dataMap.containsKey(objectId);
}
@Override
public void init() {
}
public List<String> listPaths(){
return new ArrayList<>(dataMap.keySet());
}
public List<String> listFilePaths(){
return dataMap.values().stream().map(File::getAbsolutePath).collect(Collectors.toList());
}
@SneakyThrows
@Override
public void storeObject(String objectId, byte[] data) {
File tempFile = File.createTempFile("test", ".tmp");
File tempFile = File.createTempFile("storage", objectId.replace("/","-"));
IOUtils.write(data, new FileOutputStream(tempFile));
try(var fileOutputStream = new FileOutputStream(tempFile)) {
IOUtils.write(data, fileOutputStream);
}
dataMap.put(objectId, tempFile);
}
@Override
@SneakyThrows
public void storeObject(String objectId, InputStream stream) {
File tempFile = File.createTempFile("test", ".tmp");
try(var fileOutputStream = new FileOutputStream(tempFile)) {
IOUtils.copy(stream, fileOutputStream);
}
dataMap.put(objectId, tempFile);
}
@Override
@SneakyThrows
public void storeObject(String objectId, ByteArrayOutputStream stream) {
File tempFile = File.createTempFile("test", ".tmp");
try(var fileOutputStream = new FileOutputStream(tempFile)){
stream.writeTo(fileOutputStream);
}
dataMap.put(objectId, tempFile);
}
public void clearStorage() {
this.dataMap.forEach((k, v) -> {
v.delete();
});
this.dataMap.clear();
}
}
}
@@ -188,10 +188,10 @@ public class RedactionIntegrationTest {
loadTypeForTest();
loadNerForTest();
when(dictionaryClient.getVersion(TEST_DOSSIER_TEMPLATE_ID)).thenReturn(0L);
when(dictionaryClient.getAllTypesForDossierTemplate(TEST_DOSSIER_TEMPLATE_ID)).thenReturn(getTypeResponse());
when(dictionaryClient.getAllTypesForDossierTemplate(TEST_DOSSIER_TEMPLATE_ID, false)).thenReturn(getTypeResponse());
when(dictionaryClient.getVersion(TEST_DOSSIER_TEMPLATE_ID)).thenReturn(0L);
when(dictionaryClient.getAllTypesForDossier(TEST_DOSSIER_ID)).thenReturn(List.of(Type.builder()
when(dictionaryClient.getAllTypesForDossier(TEST_DOSSIER_ID, false)).thenReturn(List.of(Type.builder()
.id(DOSSIER_REDACTIONS + ":" + TEST_DOSSIER_TEMPLATE_ID)
.type(DOSSIER_REDACTIONS)
.dossierTemplateId(TEST_DOSSIER_ID)
@@ -208,7 +208,7 @@ public class RedactionIntegrationTest {
when(dictionaryClient.getColors(TEST_DOSSIER_TEMPLATE_ID)).thenReturn(colors);
}
private void mockDictionaryCalls(Long version){
when(dictionaryClient.getDictionaryForType(VERTEBRATE + ":" + TEST_DOSSIER_TEMPLATE_ID, version)).thenReturn(getDictionaryResponse(VERTEBRATE, false));
@@ -303,6 +303,8 @@ public class RedactionIntegrationTest {
@Test
public void redactionExpansionOverlap() throws IOException {
// F. Lastname, J. Doe, M. Mustermann
// Lastname M., Doe J., Mustermann M.
ClassPathResource pdfFileResource = new ClassPathResource("files/Minimal Examples/ExpansionTest.pdf");
AnalyzeRequest request = prepareStorage(pdfFileResource.getInputStream());
@@ -1534,6 +1536,44 @@ public class RedactionIntegrationTest {
}
}
@Test
public void testExpandByPrefixRegEx() throws IOException {
assertThat(dictionary.get(AUTHOR).contains("Robinson"));
assertThat(! dictionary.get(AUTHOR).contains("Mrs. Robinson"));
assertThat(dictionary.get(AUTHOR).contains("Bojangles"));
assertThat(! dictionary.get(AUTHOR).contains("Mr. Bojangles"));
assertThat(dictionary.get(AUTHOR).contains("Tambourine Man"));
assertThat(! dictionary.get(AUTHOR).contains("Mr. Tambourine Man"));
String fileName = "files/mr-mrs.pdf";
String outputFileName = OsUtils.getTemporaryDirectory() + "/Annotated.pdf";
ClassPathResource pdfFileResource = new ClassPathResource(fileName);
AnalyzeRequest request = prepareStorage(pdfFileResource.getInputStream());
analyzeService.analyzeDocumentStructure(new StructureAnalyzeRequest(request.getDossierId(), request.getFileId()));
analyzeService.analyze(request);
AnnotateResponse annotateResponse = redactionController.annotate(AnnotateRequest.builder()
.dossierId(TEST_DOSSIER_ID)
.fileId(TEST_FILE_ID)
.build());
try (FileOutputStream fileOutputStream = new FileOutputStream(outputFileName)) {
fileOutputStream.write(annotateResponse.getDocument());
}
var redactionLog = redactionStorageService.getRedactionLog(TEST_DOSSIER_ID, TEST_FILE_ID);
var values = redactionLog.getRedactionLogEntry()
.stream()
.map(RedactionLogEntry::getValue)
.collect(Collectors.toList());
assertThat(values).contains("Mrs. Robinson");
assertThat(values).contains("Mr. Bojangles");
assertThat(values).contains("Mr. Tambourine Man");
}
@SneakyThrows
private AnalyzeRequest prepareStorage(InputStream stream) {
@@ -145,14 +145,17 @@ public class EntitySearchUtilsTest {
Set<Entity> foundEntities = new HashSet<>();
Entity foundEntities1 = new Entity("Batman X.", "fake type", 0, 8, "fake headline", 0, false, false, Engine.RULE, EntityType.ENTITY);
Entity foundEntities2 = new Entity("Superman", "fake type", 10, 17, "fake headline", 0, false, false, Engine.RULE, EntityType.ENTITY);
Entity foundEntities3 = new Entity("Superman Y.", "fake type", 10, 20, "fake headline", 0, false, false, Engine.RULE, EntityType.ENTITY);
foundEntities.add(foundEntities1);
foundEntities.add(foundEntities2);
foundEntities.add(foundEntities3);
// Act
Set<Entity> result = EntitySearchUtils.findNonOverlappingMatchEntities(existingEntities, foundEntities);
// Assert
assertThat(result.size()).isEqualTo(0);
assertThat(result.size()).isEqualTo(1);
assertThat(result.contains(foundEntities2));
}
@@ -173,16 +176,21 @@ public class EntitySearchUtilsTest {
existingEntities.add(existingEntity2);
Set<Entity> foundEntities = new HashSet<>();
Entity foundEntities1 = new Entity("Batman X. Superman", "fake type", 0, 17, "fake headline", 0, false, false, Engine.RULE, EntityType.ENTITY);
Entity foundEntities2 = new Entity("Superman", "fake type", 10, 17, "fake headline", 0, false, false, Engine.RULE, EntityType.ENTITY);
foundEntities.add(foundEntities1);
foundEntities.add(foundEntities2);
Entity foundEntitiesOverlap1 = new Entity("Batman X. Superman Y.", "fake type", 0, 17, "fake headline", 0, false, false, Engine.RULE, EntityType.ENTITY);
Entity foundEntitiesOverlap2 = new Entity("Superman Y.", "fake type", 10, 20, "fake headline", 0, false, false, Engine.RULE, EntityType.ENTITY);
Entity foundEntitiesSubset1 = new Entity("Batman X. Superman", "fake type", 0, 17, "fake headline", 0, false, false, Engine.RULE, EntityType.ENTITY);
Entity foundEntitiesSubset2 = new Entity("Superman", "fake type", 10, 17, "fake headline", 0, false, false, Engine.RULE, EntityType.ENTITY);
foundEntities.add(foundEntitiesOverlap1);
foundEntities.add(foundEntitiesOverlap2);
foundEntities.add(foundEntitiesSubset1);
foundEntities.add(foundEntitiesSubset2);
// Act
Set<Entity> result = EntitySearchUtils.findNonOverlappingMatchEntities(existingEntities, foundEntities);
// Assert
assertThat(result.size()).isEqualTo(0);
assertThat(result.size()).isEqualTo(2);
assertThat(result).containsExactlyInAnyOrder(foundEntitiesSubset1, foundEntitiesSubset2);
}
@@ -9,6 +9,7 @@ ribbon:
spring:
main:
allow-bean-definition-overriding: true
allow-circular-references: true # FIXME
processing.kafkastreams: false
@@ -8620,4 +8620,6 @@ Doe
M. Mustermann
F. Lastname
Mustermann
Lastname
Lastname
Bojangles
Tambourine Man
@@ -36,6 +36,23 @@ rule "0: Expand CBI Authors with firstname initials"
section.expandByRegEx("CBI_author", "(,? [A-Z]\\.?( ?[A-Z]\\.?)?( ?[A-Z]\\.?)?\\b\\.?)", false, 1, "[^\\s]+");
end
rule "0: Expand CBI_author and PII matches with salutation prefix"
when
Section((matchesType("CBI_author") || matchesType("PII")) && (
searchText.contains("Mr")
|| searchText.contains("Mrs")
|| searchText.contains("Ms")
|| searchText.contains("Miss")
|| searchText.contains("Sir")
|| searchText.contains("Madam")
|| searchText.contains("Madame")
|| searchText.contains("Mme")
))
then
section.expandByPrefixRegEx("CBI_author", "\\b(Mrs?|Ms|Miss|Sir|Madame?|Mme)\\s?\\.?\\s*", false, 0);
section.expandByPrefixRegEx("PII", "\\b(Mrs?|Ms|Miss|Sir|Madame?|Mme)\\s?\\.?\\s*", false, 0);
end
rule "1: Redacted because Section contains Vertebrate"
when