RED-8784 - Change PII.9.1/PII.9.2 to CBI.23.0/CBI.23.1
This commit is contained in:
parent
25015f633e
commit
fe07e500b9
@ -126,6 +126,8 @@ public class RedactionAcceptanceTest extends AbstractRedactionIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void acceptanceTests() throws IOException {
|
public void acceptanceTests() throws IOException {
|
||||||
|
|
||||||
|
String EFSA_SANITISATION_RULES = loadFromClassPath("drools/efsa_sanitisation.drl");
|
||||||
|
when(rulesClient.getRules(TEST_DOSSIER_TEMPLATE_ID, RuleFileType.ENTITY)).thenReturn(JSONPrimitive.of(EFSA_SANITISATION_RULES));
|
||||||
AnalyzeRequest request = uploadFileToStorage("files/syngenta/CustomerFiles/SYNGENTA_EFSA_sanitisation_GFL_v1_moreSections.pdf");
|
AnalyzeRequest request = uploadFileToStorage("files/syngenta/CustomerFiles/SYNGENTA_EFSA_sanitisation_GFL_v1_moreSections.pdf");
|
||||||
System.out.println("Start Full integration test");
|
System.out.println("Start Full integration test");
|
||||||
analyzeDocumentStructure(LayoutParsingType.REDACT_MANAGER, request);
|
analyzeDocumentStructure(LayoutParsingType.REDACT_MANAGER, request);
|
||||||
@ -190,6 +192,8 @@ public class RedactionAcceptanceTest extends AbstractRedactionIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void noEndlessLoopsTest() {
|
public void noEndlessLoopsTest() {
|
||||||
|
|
||||||
|
String EFSA_SANITISATION_RULES = loadFromClassPath("drools/efsa_sanitisation.drl");
|
||||||
|
when(rulesClient.getRules(TEST_DOSSIER_TEMPLATE_ID, RuleFileType.ENTITY)).thenReturn(JSONPrimitive.of(EFSA_SANITISATION_RULES));
|
||||||
AnalyzeRequest request = uploadFileToStorage("files/syngenta/CustomerFiles/SYNGENTA_EFSA_sanitisation_GFL_v1_moreSections.pdf");
|
AnalyzeRequest request = uploadFileToStorage("files/syngenta/CustomerFiles/SYNGENTA_EFSA_sanitisation_GFL_v1_moreSections.pdf");
|
||||||
System.out.println("Start Full integration test");
|
System.out.println("Start Full integration test");
|
||||||
analyzeDocumentStructure(LayoutParsingType.REDACT_MANAGER, request);
|
analyzeDocumentStructure(LayoutParsingType.REDACT_MANAGER, request);
|
||||||
|
|||||||
@ -68,6 +68,7 @@ import com.iqser.red.service.redaction.v1.server.annotate.AnnotateResponse;
|
|||||||
import com.iqser.red.service.redaction.v1.server.model.document.TextRange;
|
import com.iqser.red.service.redaction.v1.server.model.document.TextRange;
|
||||||
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Section;
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Section;
|
||||||
import com.iqser.red.service.redaction.v1.server.redaction.utils.OsUtils;
|
import com.iqser.red.service.redaction.v1.server.redaction.utils.OsUtils;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.rules.RulesIntegrationTest;
|
||||||
import com.iqser.red.service.redaction.v1.server.service.document.DocumentGraphMapper;
|
import com.iqser.red.service.redaction.v1.server.service.document.DocumentGraphMapper;
|
||||||
import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService;
|
import com.iqser.red.service.redaction.v1.server.storage.RedactionStorageService;
|
||||||
import com.iqser.red.storage.commons.StorageAutoConfiguration;
|
import com.iqser.red.storage.commons.StorageAutoConfiguration;
|
||||||
@ -82,7 +83,7 @@ import lombok.SneakyThrows;
|
|||||||
@ExtendWith(SpringExtension.class)
|
@ExtendWith(SpringExtension.class)
|
||||||
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||||
@Import(RedactionIntegrationTest.RedactionIntegrationTestConfiguration.class)
|
@Import(RedactionIntegrationTest.RedactionIntegrationTestConfiguration.class)
|
||||||
public class RedactionIntegrationTest extends AbstractRedactionIntegrationTest {
|
public class RedactionIntegrationTest extends RulesIntegrationTest {
|
||||||
|
|
||||||
private static final String RULES = loadFromClassPath("drools/rules.drl");
|
private static final String RULES = loadFromClassPath("drools/rules.drl");
|
||||||
|
|
||||||
@ -586,6 +587,8 @@ public class RedactionIntegrationTest extends AbstractRedactionIntegrationTest {
|
|||||||
@Test
|
@Test
|
||||||
public void redactionTest() throws IOException {
|
public void redactionTest() throws IOException {
|
||||||
|
|
||||||
|
String EFSA_SANITISATION_RULES = loadFromClassPath("drools/efsa_sanitisation.drl");
|
||||||
|
when(rulesClient.getRules(TEST_DOSSIER_TEMPLATE_ID, RuleFileType.ENTITY)).thenReturn(JSONPrimitive.of(EFSA_SANITISATION_RULES));
|
||||||
String fileName = "files/new/crafted document.pdf";
|
String fileName = "files/new/crafted document.pdf";
|
||||||
String outputFileName = OsUtils.getTemporaryDirectory() + "/Annotated.pdf";
|
String outputFileName = OsUtils.getTemporaryDirectory() + "/Annotated.pdf";
|
||||||
|
|
||||||
@ -1451,6 +1454,8 @@ public class RedactionIntegrationTest extends AbstractRedactionIntegrationTest {
|
|||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public void testResizeWithUpdateDictionaryTrue() {
|
public void testResizeWithUpdateDictionaryTrue() {
|
||||||
|
|
||||||
|
String EFSA_SANITISATION_RULES = loadFromClassPath("drools/efsa_sanitisation.drl");
|
||||||
|
when(rulesClient.getRules(TEST_DOSSIER_TEMPLATE_ID, RuleFileType.ENTITY)).thenReturn(JSONPrimitive.of(EFSA_SANITISATION_RULES));
|
||||||
String pdfFile = "files/new/crafted document.pdf";
|
String pdfFile = "files/new/crafted document.pdf";
|
||||||
|
|
||||||
AnalyzeRequest request = uploadFileToStorage(pdfFile);
|
AnalyzeRequest request = uploadFileToStorage(pdfFile);
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package com.iqser.red.service.redaction.v1.server.rules;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.kie.api.KieServices;
|
import org.kie.api.KieServices;
|
||||||
import org.kie.api.builder.KieBuilder;
|
import org.kie.api.builder.KieBuilder;
|
||||||
import org.kie.api.builder.KieFileSystem;
|
import org.kie.api.builder.KieFileSystem;
|
||||||
@ -10,6 +11,8 @@ import org.kie.api.builder.KieModule;
|
|||||||
import org.kie.api.runtime.KieContainer;
|
import org.kie.api.runtime.KieContainer;
|
||||||
import org.kie.api.runtime.KieSession;
|
import org.kie.api.runtime.KieSession;
|
||||||
import org.kie.internal.io.ResourceFactory;
|
import org.kie.internal.io.ResourceFactory;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@ -17,11 +20,13 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
import com.iqser.red.service.redaction.v1.server.document.graph.BuildDocumentIntegrationTest;
|
import com.iqser.red.service.redaction.v1.server.document.graph.BuildDocumentIntegrationTest;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.dictionary.Dictionary;
|
||||||
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document;
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document;
|
||||||
import com.iqser.red.service.redaction.v1.server.service.ManualChangesApplicationService;
|
import com.iqser.red.service.redaction.v1.server.service.ManualChangesApplicationService;
|
||||||
import com.iqser.red.service.redaction.v1.server.service.document.EntityCreationService;
|
import com.iqser.red.service.redaction.v1.server.service.document.EntityCreationService;
|
||||||
import com.iqser.red.service.redaction.v1.server.service.document.EntityEnrichmentService;
|
import com.iqser.red.service.redaction.v1.server.service.document.EntityEnrichmentService;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
public class RulesIntegrationTest extends BuildDocumentIntegrationTest {
|
public class RulesIntegrationTest extends BuildDocumentIntegrationTest {
|
||||||
|
|
||||||
protected static final String RULES = "drools/rules.drl";
|
protected static final String RULES = "drools/rules.drl";
|
||||||
@ -73,10 +78,12 @@ public class RulesIntegrationTest extends BuildDocumentIntegrationTest {
|
|||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void createServices() {
|
public void createServices() {
|
||||||
|
|
||||||
|
Dictionary dict = Mockito.mock(Dictionary.class);
|
||||||
kieSession = kieContainer.newKieSession();
|
kieSession = kieContainer.newKieSession();
|
||||||
entityCreationService = new EntityCreationService(entityEnrichmentService, kieSession);
|
entityCreationService = new EntityCreationService(entityEnrichmentService, kieSession);
|
||||||
kieSession.setGlobal("manualChangesApplicationService", manualChangesApplicationService);
|
kieSession.setGlobal("manualChangesApplicationService", manualChangesApplicationService);
|
||||||
kieSession.setGlobal("entityCreationService", entityCreationService);
|
kieSession.setGlobal("entityCreationService", entityCreationService);
|
||||||
|
kieSession.setGlobal("dictionary", dict);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -410,6 +410,26 @@ rule "CBI.20.3: Redact between \"PERFORMING LABORATORY\" and \"LABORATORY PROJEC
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: CBI.23
|
||||||
|
rule "CBI.23.0: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (non vertebrate study)"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
||||||
|
then
|
||||||
|
entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "CBI_author", EntityType.ENTITY, $document)
|
||||||
|
.forEach(authorEntity -> authorEntity.redact("CBI.23.0", "AUTHOR(S) was found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "CBI.23.1: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (vertebrate study)"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
||||||
|
then
|
||||||
|
entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "CBI_author", EntityType.ENTITY, $document)
|
||||||
|
.forEach(authorEntity -> authorEntity.redact("CBI.23.1", "AUTHOR(S) was found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------ PII rules ------------------------------------
|
//------------------------------------ PII rules ------------------------------------
|
||||||
|
|
||||||
// Rule unit: PII.0
|
// Rule unit: PII.0
|
||||||
@ -835,24 +855,6 @@ rule "PII.9.0: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\""
|
|||||||
.forEach(authorEntity -> authorEntity.redact("PII.9.0", "AUTHOR(S) was found", "Reg (EC) No 1107/2009 Art. 63 (2e)"));
|
.forEach(authorEntity -> authorEntity.redact("PII.9.0", "AUTHOR(S) was found", "Reg (EC) No 1107/2009 Art. 63 (2e)"));
|
||||||
end
|
end
|
||||||
|
|
||||||
rule "PII.9.1: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (non vertebrate study)"
|
|
||||||
when
|
|
||||||
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
|
||||||
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
|
||||||
then
|
|
||||||
entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "PII", EntityType.ENTITY, $document)
|
|
||||||
.forEach(authorEntity -> authorEntity.redact("PII.9.1", "AUTHOR(S) was found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
|
||||||
end
|
|
||||||
|
|
||||||
rule "PII.9.2: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (vertebrate study)"
|
|
||||||
when
|
|
||||||
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
|
||||||
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
|
||||||
then
|
|
||||||
entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "PII", EntityType.ENTITY, $document)
|
|
||||||
.forEach(authorEntity -> authorEntity.redact("PII.9.2", "AUTHOR(S) was found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
|
|
||||||
end
|
|
||||||
|
|
||||||
rule "PII.9.3: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\""
|
rule "PII.9.3: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\""
|
||||||
when
|
when
|
||||||
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
||||||
|
|||||||
@ -833,6 +833,26 @@ rule "CBI.22.0: Redact Addresses in Reference Tables for vertebrate studies in n
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: CBI.23
|
||||||
|
rule "CBI.23.0: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (non vertebrate study)"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
||||||
|
then
|
||||||
|
entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "CBI_author", EntityType.ENTITY, $document)
|
||||||
|
.forEach(authorEntity -> authorEntity.redact("CBI.23.0", "AUTHOR(S) was found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "CBI.23.1: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (vertebrate study)"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
||||||
|
then
|
||||||
|
entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "CBI_author", EntityType.ENTITY, $document)
|
||||||
|
.forEach(authorEntity -> authorEntity.redact("CBI.23.1", "AUTHOR(S) was found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------ PII rules ------------------------------------
|
//------------------------------------ PII rules ------------------------------------
|
||||||
|
|
||||||
// Rule unit: PII.0
|
// Rule unit: PII.0
|
||||||
@ -1281,24 +1301,6 @@ rule "PII.9.0: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\""
|
|||||||
.forEach(authorEntity -> authorEntity.redact("PII.9.0", "AUTHOR(S) was found", "Reg (EC) No 1107/2009 Art. 63 (2e)"));
|
.forEach(authorEntity -> authorEntity.redact("PII.9.0", "AUTHOR(S) was found", "Reg (EC) No 1107/2009 Art. 63 (2e)"));
|
||||||
end
|
end
|
||||||
|
|
||||||
rule "PII.9.1: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (non vertebrate study)"
|
|
||||||
when
|
|
||||||
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
|
||||||
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
|
||||||
then
|
|
||||||
entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "PII", EntityType.ENTITY, $document)
|
|
||||||
.forEach(authorEntity -> authorEntity.redact("PII.9.1", "AUTHOR(S) was found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
|
||||||
end
|
|
||||||
|
|
||||||
rule "PII.9.2: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (vertebrate study)"
|
|
||||||
when
|
|
||||||
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
|
||||||
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
|
||||||
then
|
|
||||||
entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "PII", EntityType.ENTITY, $document)
|
|
||||||
.forEach(authorEntity -> authorEntity.redact("PII.9.2", "AUTHOR(S) was found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
|
|
||||||
end
|
|
||||||
|
|
||||||
rule "PII.9.3: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\""
|
rule "PII.9.3: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\""
|
||||||
when
|
when
|
||||||
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
||||||
|
|||||||
@ -0,0 +1,977 @@
|
|||||||
|
package drools
|
||||||
|
|
||||||
|
import static java.lang.String.format;
|
||||||
|
import static com.iqser.red.service.redaction.v1.server.utils.RedactionSearchUtility.anyMatch;
|
||||||
|
import static com.iqser.red.service.redaction.v1.server.utils.RedactionSearchUtility.exactMatch;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.*;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.TextRange;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.entity.*;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.entity.EntityType;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.entity.MatchedRule;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.entity.TextEntity
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.entity.MatchedRule
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.*;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Section;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Table;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.TableCell;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.SemanticNode;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Document;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Paragraph;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Image;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.ImageType;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Page;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Headline;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.SectionIdentifier;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Footer;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.Header;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.nodes.NodeType;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.textblock.*;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.textblock.TextBlock;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.textblock.TextBlockCollector;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.textblock.AtomicTextBlock;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.document.textblock.ConcatenatedTextBlock;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.NerEntities;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.dictionary.Dictionary;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.model.dictionary.DictionaryModel;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.service.document.EntityCreationService;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.service.ManualChangesApplicationService;
|
||||||
|
import com.iqser.red.service.redaction.v1.server.utils.RedactionSearchUtility;
|
||||||
|
|
||||||
|
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileAttribute;
|
||||||
|
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Engine;
|
||||||
|
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualResizeRedaction;
|
||||||
|
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.IdRemoval;
|
||||||
|
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualForceRedaction;
|
||||||
|
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualRecategorization;
|
||||||
|
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.ManualLegalBasisChange;
|
||||||
|
|
||||||
|
import com.knecon.fforesight.service.layoutparser.internal.api.data.redaction.LayoutEngine;
|
||||||
|
|
||||||
|
global Document document
|
||||||
|
global EntityCreationService entityCreationService
|
||||||
|
global ManualChangesApplicationService manualChangesApplicationService
|
||||||
|
global Dictionary dictionary
|
||||||
|
|
||||||
|
//------------------------------------ queries ------------------------------------
|
||||||
|
|
||||||
|
query "getFileAttributes"
|
||||||
|
$fileAttribute: FileAttribute()
|
||||||
|
end
|
||||||
|
|
||||||
|
//------------------------------------ Syngenta specific rules ------------------------------------
|
||||||
|
|
||||||
|
// Rule unit: SYN.1
|
||||||
|
rule "SYN.1.0: Recommend CTL/BL laboratory that start with BL or CTL"
|
||||||
|
when
|
||||||
|
$section: Section(containsString("CT") || containsString("BL"))
|
||||||
|
then
|
||||||
|
/* Regular expression: ((\b((([Cc]T(([1ILli\/])| L|~P))|(BL))[\. ]?([\dA-Ziltphz~\/.:!]| ?[\(',][Ppi](\(e)?|([\(-?']\/))+( ?[\(\/\dA-Znasieg]+)?)\b( ?\/? ?\d+)?)|(\bCT[L1i]\b)) */
|
||||||
|
entityCreationService.byRegexIgnoreCase("((\\b((([Cc]T(([1ILli\\/])| L|~P))|(BL))[\\. ]?([\\dA-Ziltphz~\\/.:!]| ?[\\(',][Ppi](\\(e)?|([\\(-?']\\/))+( ?[\\(\\/\\dA-Znasieg]+)?)\\b( ?\\/? ?\\d+)?)|(\\bCT[L1i]\\b))", "CBI_address", EntityType.RECOMMENDATION, $section)
|
||||||
|
.forEach(entity -> entity.skip("SYN.1.0", ""));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------ CBI rules ------------------------------------
|
||||||
|
|
||||||
|
// Rule unit: CBI.0
|
||||||
|
rule "CBI.0.0: Redact CBI Authors (non vertebrate Study)"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$entity: TextEntity(type() == "CBI_author", dictionaryEntry)
|
||||||
|
then
|
||||||
|
$entity.redact("CBI.0.0", "Author found", "Article 39(e)(3) of Regulation (EC) No 178/2002");
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "CBI.0.1: Redact CBI Authors (vertebrate Study)"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$entity: TextEntity(type() == "CBI_author", dictionaryEntry)
|
||||||
|
then
|
||||||
|
$entity.redact("CBI.0.1", "Author found", "Article 39(e)(2) of Regulation (EC) No 178/2002");
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: CBI.1
|
||||||
|
rule "CBI.1.0: Do not redact CBI Address (non vertebrate Study)"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$entity: TextEntity(type() == "CBI_address", dictionaryEntry)
|
||||||
|
then
|
||||||
|
$entity.skip("CBI.1.0", "Address found for Non Vertebrate Study");
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "CBI.1.1: Redact CBI Address (vertebrate Study)"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$entity: TextEntity(type() == "CBI_address", dictionaryEntry)
|
||||||
|
then
|
||||||
|
$entity.redact("CBI.1.1", "Address found", "Article 39(e)(2) of Regulation (EC) No 178/2002");
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: CBI.2
|
||||||
|
rule "CBI.2.0: Do not redact genitive CBI Author"
|
||||||
|
when
|
||||||
|
$entity: TextEntity(type() == "CBI_author", anyMatch(textAfter, "['’’'ʼˈ´`‘′ʻ’']s"))
|
||||||
|
then
|
||||||
|
entityCreationService.byTextRange($entity.getTextRange(), "CBI_author", EntityType.FALSE_POSITIVE, document)
|
||||||
|
.ifPresent(falsePositive -> falsePositive.skip("CBI.2.0", "Genitive Author found"));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: CBI.7
|
||||||
|
rule "CBI.7.0: Do not redact Names and Addresses if published information found in Section without tables"
|
||||||
|
when
|
||||||
|
$section: Section(!hasTables(),
|
||||||
|
hasEntitiesOfType("published_information"),
|
||||||
|
(hasEntitiesOfType("CBI_author") || hasEntitiesOfType("CBI_address")))
|
||||||
|
then
|
||||||
|
$section.getEntitiesOfType(List.of("CBI_author", "CBI_address"))
|
||||||
|
.forEach(redactionEntity -> {
|
||||||
|
redactionEntity.skipWithReferences(
|
||||||
|
"CBI.7.0",
|
||||||
|
"Published Information found in section",
|
||||||
|
$section.getEntitiesOfType("published_information")
|
||||||
|
);
|
||||||
|
});
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "CBI.7.1: Do not redact Names and Addresses if published information found in same table row"
|
||||||
|
when
|
||||||
|
$table: Table(hasEntitiesOfType("published_information"), hasEntitiesOfType("CBI_author") || hasEntitiesOfType("CBI_address"))
|
||||||
|
$cellsWithPublishedInformation: TableCell() from $table.streamTableCellsWhichContainType("published_information").toList()
|
||||||
|
$tableCell: TableCell(row == $cellsWithPublishedInformation.row) from $table.streamTableCells().toList()
|
||||||
|
$authorOrAddress: TextEntity(type() == "CBI_author" || type() == "CBI_address", active()) from $tableCell.getEntities()
|
||||||
|
then
|
||||||
|
$authorOrAddress.skipWithReferences("CBI.7.1", "Published Information found in row", $table.getEntitiesOfTypeInSameRow("published_information", $authorOrAddress));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: CBI.9
|
||||||
|
rule "CBI.9.0: Redact all cells with Header Author(s) as CBI_author (non vertebrate study)"
|
||||||
|
agenda-group "LOCAL_DICTIONARY_ADDS"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$table: Table(hasHeader("Author(s)"))
|
||||||
|
then
|
||||||
|
$table.streamTableCellsWithHeader("Author(s)")
|
||||||
|
.map(tableCell -> entityCreationService.bySemanticNode(tableCell, "CBI_author", EntityType.ENTITY))
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get)
|
||||||
|
.forEach(redactionEntity -> redactionEntity.redact("CBI.9.0", "Author(s) found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "CBI.9.1: Redact all cells with Header Author as CBI_author (non vertebrate study)"
|
||||||
|
agenda-group "LOCAL_DICTIONARY_ADDS"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$table: Table(hasHeader("Author"))
|
||||||
|
then
|
||||||
|
$table.streamTableCellsWithHeader("Author")
|
||||||
|
.map(tableCell -> entityCreationService.bySemanticNode(tableCell, "CBI_author", EntityType.ENTITY))
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get)
|
||||||
|
.forEach(redactionEntity -> redactionEntity.redact("CBI.9.1", "Author found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: CBI.10
|
||||||
|
rule "CBI.10.0: Redact all cells with Header Author(s) as CBI_author (vertebrate study)"
|
||||||
|
agenda-group "LOCAL_DICTIONARY_ADDS"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$table: Table(hasHeader("Author(s)"))
|
||||||
|
then
|
||||||
|
$table.streamTableCellsWithHeader("Author(s)")
|
||||||
|
.map(tableCell -> entityCreationService.bySemanticNode(tableCell, "CBI_author", EntityType.ENTITY))
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get)
|
||||||
|
.forEach(redactionEntity -> redactionEntity.redact("CBI.10.0", "Author(s) found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "CBI.10.1: Redact all cells with Header Author as CBI_author (vertebrate study)"
|
||||||
|
agenda-group "LOCAL_DICTIONARY_ADDS"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$table: Table(hasHeader("Author"))
|
||||||
|
then
|
||||||
|
$table.streamTableCellsWithHeader("Author")
|
||||||
|
.map(tableCell -> entityCreationService.bySemanticNode(tableCell, "CBI_author", EntityType.ENTITY))
|
||||||
|
.filter(Optional::isPresent)
|
||||||
|
.map(Optional::get)
|
||||||
|
.forEach(redactionEntity -> redactionEntity.redact("CBI.10.1", "Author found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: CBI.11
|
||||||
|
rule "CBI.11.0: Recommend all CBI_author entities in Table with Vertebrate Study Y/N Header"
|
||||||
|
agenda-group "LOCAL_DICTIONARY_ADDS"
|
||||||
|
salience -1
|
||||||
|
when
|
||||||
|
$table: Table(hasHeader("Author(s)") && hasHeader("Vertebrate Study Y/N"))
|
||||||
|
then
|
||||||
|
$table.getEntitiesOfType("CBI_author").stream().filter(IEntity::applied).forEach(entity -> dictionary.addMultipleAuthorsAsRecommendation(entity));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: CBI.16
|
||||||
|
rule "CBI.16.1: Add CBI_author with \"et al.\" RegEx (non vertebrate study)"
|
||||||
|
agenda-group "LOCAL_DICTIONARY_ADDS"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$section: Section(containsString("et al."))
|
||||||
|
then
|
||||||
|
entityCreationService.byRegex("\\b([A-ZÄÖÜ][^\\s\\.,]+( [A-ZÄÖÜ]{1,2}\\.?)?( ?[A-ZÄÖÜ]\\.?)?) et al\\.?", "CBI_author", EntityType.ENTITY, 1, $section)
|
||||||
|
.forEach(entity -> {
|
||||||
|
entity.redact("CBI.16.1", "Author found by \"et al\" regex", "Article 39(e)(3) of Regulation (EC) No 178/2002");
|
||||||
|
dictionary.recommendEverywhere(entity);
|
||||||
|
});
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "CBI.16.2: Add CBI_author with \"et al.\" RegEx (vertebrate study)"
|
||||||
|
agenda-group "LOCAL_DICTIONARY_ADDS"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$section: Section(containsString("et al."))
|
||||||
|
then
|
||||||
|
entityCreationService.byRegex("\\b([A-ZÄÖÜ][^\\s\\.,]+( [A-ZÄÖÜ]{1,2}\\.?)?( ?[A-ZÄÖÜ]\\.?)?) et al\\.?", "CBI_author", EntityType.ENTITY, 1, $section)
|
||||||
|
.forEach(entity -> {
|
||||||
|
entity.redact("CBI.16.2", "Author found by \"et al\" regex", "Article 39(e)(2) of Regulation (EC) No 178/2002");
|
||||||
|
dictionary.recommendEverywhere(entity);
|
||||||
|
});
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: CBI.17
|
||||||
|
rule "CBI.17.0: Add recommendation for Addresses in Test Organism sections, without colon"
|
||||||
|
when
|
||||||
|
$section: Section(!hasTables(), containsString("Species") && containsString("Source") && !containsString("Species:") && !containsString("Source:"))
|
||||||
|
then
|
||||||
|
entityCreationService.lineAfterString("Source", "CBI_address", EntityType.RECOMMENDATION, $section)
|
||||||
|
.forEach(entity -> entity.skip("CBI.17.0", "Line after \"Source\" in Test Organism Section"));
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "CBI.17.1: Add recommendation for Addresses in Test Organism sections, with colon"
|
||||||
|
when
|
||||||
|
$section: Section(!hasTables(), containsString("Species:"), containsString("Source:"))
|
||||||
|
then
|
||||||
|
entityCreationService.lineAfterString("Source:", "CBI_address", EntityType.RECOMMENDATION, $section)
|
||||||
|
.forEach(entity -> entity.skip("CBI.17.1", "Line after \"Source:\" in Test Animals Section"));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: CBI.20
|
||||||
|
rule "CBI.20.1: Redact between \"PERFORMING LABORATORY\" and \"LABORATORY PROJECT ID:\" (non vertebrate study)"
|
||||||
|
agenda-group "LOCAL_DICTIONARY_ADDS"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$section: Section(!hasTables(), containsString("PERFORMING LABORATORY:"), containsString("LABORATORY PROJECT ID:"))
|
||||||
|
then
|
||||||
|
entityCreationService.betweenStrings("PERFORMING LABORATORY:", "LABORATORY PROJECT ID:", "CBI_address", EntityType.ENTITY, $section)
|
||||||
|
.forEach(laboratoryEntity -> {
|
||||||
|
laboratoryEntity.skip("CBI.20.1", "PERFORMING LABORATORY was found for non vertebrate study");
|
||||||
|
dictionary.recommendEverywhere(laboratoryEntity);
|
||||||
|
});
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "CBI.20.2: Redact between \"PERFORMING LABORATORY\" and \"LABORATORY PROJECT ID:\" (vertebrate study)"
|
||||||
|
agenda-group "LOCAL_DICTIONARY_ADDS"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$section: Section(!hasTables(), containsString("PERFORMING LABORATORY:"), containsString("LABORATORY PROJECT ID:"))
|
||||||
|
then
|
||||||
|
entityCreationService.betweenStrings("PERFORMING LABORATORY:", "LABORATORY PROJECT ID:", "CBI_address", EntityType.ENTITY, $section)
|
||||||
|
.forEach(laboratoryEntity -> {
|
||||||
|
laboratoryEntity.redact("CBI.20.2", "PERFORMING LABORATORY was found", "Article 39(e)(2) of Regulation (EC) No 178/2002");
|
||||||
|
dictionary.recommendEverywhere(laboratoryEntity);
|
||||||
|
});
|
||||||
|
end
|
||||||
|
|
||||||
|
// Rule unit: CBI.23
|
||||||
|
rule "CBI.23.0: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (non vertebrate study)"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
||||||
|
then
|
||||||
|
entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "CBI_author", EntityType.ENTITY, $document)
|
||||||
|
.forEach(authorEntity -> authorEntity.redact("CBI.23.0", "AUTHOR(S) was found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "CBI.23.1: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (vertebrate study)"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
||||||
|
then
|
||||||
|
entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "CBI_author", EntityType.ENTITY, $document)
|
||||||
|
.forEach(authorEntity -> authorEntity.redact("CBI.23.1", "AUTHOR(S) was found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
//------------------------------------ PII rules ------------------------------------
|
||||||
|
|
||||||
|
// Rule unit: PII.0
|
||||||
|
rule "PII.0.1: Redact all PII (non vertebrate study)"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$pii: TextEntity(type() == "PII", dictionaryEntry)
|
||||||
|
then
|
||||||
|
$pii.redact("PII.0.1", "Personal Information found", "Article 39(e)(3) of Regulation (EC) No 178/2002");
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "PII.0.2: Redact all PII (vertebrate study)"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$pii: TextEntity(type() == "PII", dictionaryEntry)
|
||||||
|
then
|
||||||
|
$pii.redact("PII.0.2", "Personal Information found", "Article 39(e)(2) of Regulation (EC) No 178/2002");
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: PII.1
|
||||||
|
rule "PII.1.1: Redact Emails by RegEx (Non vertebrate study)"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$section: Section(containsString("@"))
|
||||||
|
then
|
||||||
|
entityCreationService.byRegex("\\b([A-Za-z0-9._%+\\-]+@[A-Za-z0-9.\\-]+\\.[A-Za-z\\-]{1,23}[A-Za-z])\\b", "PII", EntityType.ENTITY, 1, $section)
|
||||||
|
.forEach(emailEntity -> emailEntity.redact("PII.1.1", "Found by Email Regex", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "PII.1.2: Redact Emails by RegEx (vertebrate study)"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$section: Section(containsString("@"))
|
||||||
|
then
|
||||||
|
entityCreationService.byRegex("\\b([A-Za-z0-9._%+\\-]+@[A-Za-z0-9.\\-]+\\.[A-Za-z\\-]{1,23}[A-Za-z])\\b", "PII", EntityType.ENTITY, 1, $section)
|
||||||
|
.forEach(emailEntity -> emailEntity.redact("PII.1.2", "Found by Email Regex", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "PII.1.3: Redact typoed Emails with indicator"
|
||||||
|
when
|
||||||
|
$section: Section(containsString("@") || containsStringIgnoreCase("mail"))
|
||||||
|
then
|
||||||
|
entityCreationService.byRegexIgnoreCase("mail[:\\.\\s]{1,2}([\\w\\/\\-\\{\\(\\. ]{3,20}(@|a|f)\\s?[\\w\\/\\-\\{\\(\\. ]{3,20}(\\. \\w{2,4}\\b|\\.\\B|\\.\\w{1,4}\\b))", "PII", EntityType.ENTITY, 1, $section)
|
||||||
|
.forEach(emailEntity -> emailEntity.redact("PII.1.3", "Personal information found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: PII.2
|
||||||
|
rule "PII.2.1: Redact Phone and Fax by RegEx (non vertebrate study)"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$section: Section(containsString("Contact") ||
|
||||||
|
containsString("Telephone") ||
|
||||||
|
containsString("Phone") ||
|
||||||
|
containsString("Ph.") ||
|
||||||
|
containsString("Fax") ||
|
||||||
|
containsString("Tel") ||
|
||||||
|
containsString("Ter") ||
|
||||||
|
containsString("Mobile") ||
|
||||||
|
containsString("Fel") ||
|
||||||
|
containsString("Fer"))
|
||||||
|
then
|
||||||
|
entityCreationService.byRegexIgnoreCase("\\b(contact|telephone|phone|ph\\.|fax|tel|ter|mobile|fel|fer)[a-zA-Z\\s]{0,10}[:.\\s]{0,3}([\\+\\d\\(][\\s\\d\\(\\)\\-\\/\\.]{4,100}\\d)\\b", "PII", EntityType.ENTITY, 2, $section)
|
||||||
|
.forEach(contactEntity -> contactEntity.redact("PII.2.1", "Found by Phone and Fax Regex", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "PII.2.2: Redact Phone and Fax by RegEx (vertebrate study)"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$section: Section(containsString("Contact") ||
|
||||||
|
containsString("Telephone") ||
|
||||||
|
containsString("Phone") ||
|
||||||
|
containsString("Ph.") ||
|
||||||
|
containsString("Fax") ||
|
||||||
|
containsString("Tel") ||
|
||||||
|
containsString("Ter") ||
|
||||||
|
containsString("Mobile") ||
|
||||||
|
containsString("Fel") ||
|
||||||
|
containsString("Fer"))
|
||||||
|
then
|
||||||
|
entityCreationService.byRegexIgnoreCase("\\b(contact|telephone|phone|ph\\.|fax|tel|ter|mobile|fel|fer)[a-zA-Z\\s]{0,10}[:.\\s]{0,3}([\\+\\d\\(][\\s\\d\\(\\)\\-\\/\\.]{4,100}\\d)\\b", "PII", EntityType.ENTITY, 2, $section)
|
||||||
|
.forEach(contactEntity -> contactEntity.redact("PII.2.2", "Found by Phone and Fax Regex", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "PII.2.3: Redact phone numbers without indicators"
|
||||||
|
when
|
||||||
|
$section: Section(containsString("+"))
|
||||||
|
then
|
||||||
|
entityCreationService.byRegex("(\\+[\\dO]{1,2} )(\\([\\dO]{1,3}\\))?[\\d\\-O ]{8,15}", "PII", EntityType.ENTITY, $section)
|
||||||
|
.forEach(entity -> entity.redact("PII.2.3", "Personal information found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: PII.3
|
||||||
|
rule "PII.3.1: Redact telephone numbers by RegEx (Non vertebrate study)"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$section: Section(matchesRegex("[+]\\d{1,}"))
|
||||||
|
then
|
||||||
|
entityCreationService.byRegex("((([+]\\d{1,3} (\\d{7,12})\\b)|([+]\\d{1,3}(\\d{3,12})\\b|[+]\\d{1,3}([ -]\\(?\\d{1,6}\\)?){2,4})|[+]\\d{1,3} ?((\\d{2,6}\\)?)([ -]\\d{2,6}){1,4}))(-\\d{1,3})?\\b)", "PII", EntityType.ENTITY, 1, $section)
|
||||||
|
.forEach(entity -> entity.redact("PII.3.1", "Telephone number found by regex", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "PII.3.2: Redact telephone numbers by RegEx (vertebrate study)"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$section: Section(matchesRegex("[+]\\d{1,}"))
|
||||||
|
then
|
||||||
|
entityCreationService.byRegex("((([+]\\d{1,3} (\\d{7,12})\\b)|([+]\\d{1,3}(\\d{3,12})\\b|[+]\\d{1,3}([ -]\\(?\\d{1,6}\\)?){2,4})|[+]\\d{1,3} ?((\\d{2,6}\\)?)([ -]\\d{2,6}){1,4}))(-\\d{1,3})?\\b)", "PII", EntityType.ENTITY, 1, $section)
|
||||||
|
.forEach(entity -> entity.redact("PII.3.2", "Telephone number found by regex", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: PII.7
|
||||||
|
rule "PII.7.1: Redact contact information if applicant is found (non vertebrate study)"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$section: Section(getHeadline().containsString("applicant") ||
|
||||||
|
getHeadline().containsString("Primary contact") ||
|
||||||
|
getHeadline().containsString("Alternative contact") ||
|
||||||
|
containsString("Applicant") ||
|
||||||
|
containsString("Telephone number:"))
|
||||||
|
then
|
||||||
|
Stream.concat(entityCreationService.lineAfterStrings(List.of("Contact point:", "Contact:", "Alternative contact:", "European contact:", "No:", "Contact:", "Tel.:", "Tel:", "Telephone number:",
|
||||||
|
"Telephone No:", "Telephone:", "Phone No.", "Phone:", "Fax number:", "Fax:", "E-mail:", "Email:", "e-mail:", "E-mail address:"), "PII", EntityType.ENTITY, $section),
|
||||||
|
Stream.concat(
|
||||||
|
entityCreationService.betweenStrings("No:", "Fax", "PII", EntityType.ENTITY, $section),
|
||||||
|
entityCreationService.betweenStrings("Contact:", "Tel", "PII", EntityType.ENTITY, $section)
|
||||||
|
))
|
||||||
|
.forEach(entity -> entity.redact("PII.7.1", "Applicant information was found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "PII.7.2: Redact contact information if applicant is found (vertebrate study)"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$section: Section(getHeadline().containsString("applicant") ||
|
||||||
|
getHeadline().containsString("Primary contact") ||
|
||||||
|
getHeadline().containsString("Alternative contact") ||
|
||||||
|
containsString("Applicant") ||
|
||||||
|
containsString("Telephone number:"))
|
||||||
|
then
|
||||||
|
Stream.concat(entityCreationService.lineAfterStrings(List.of("Contact point:", "Contact:", "Alternative contact:", "European contact:", "No:", "Contact:", "Tel.:", "Tel:", "Telephone number:",
|
||||||
|
"Telephone No:", "Telephone:", "Phone No.", "Phone:", "Fax number:", "Fax:", "E-mail:", "Email:", "e-mail:", "E-mail address:"), "PII", EntityType.ENTITY, $section),
|
||||||
|
Stream.concat(
|
||||||
|
entityCreationService.betweenStrings("No:", "Fax", "PII", EntityType.ENTITY, $section),
|
||||||
|
entityCreationService.betweenStrings("Contact:", "Tel", "PII", EntityType.ENTITY, $section)
|
||||||
|
))
|
||||||
|
.forEach(entity -> entity.redact("PII.7.2", "Applicant information was found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: PII.8
|
||||||
|
rule "PII.8.1: Redact contact information if producer is found (non vertebrate study)"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$section: Section(containsStringIgnoreCase("producer of the plant protection") ||
|
||||||
|
containsStringIgnoreCase("producer of the active substance") ||
|
||||||
|
containsStringIgnoreCase("manufacturer of the active substance") ||
|
||||||
|
containsStringIgnoreCase("manufacturer:") ||
|
||||||
|
containsStringIgnoreCase("Producer or producers of the active substance"))
|
||||||
|
then
|
||||||
|
Stream.concat(entityCreationService.lineAfterStrings(List.of("Contact point:", "Contact:", "Alternative contact:", "European contact:", "No:", "Contact:", "Tel.:", "Tel:", "Telephone number:",
|
||||||
|
"Telephone No:", "Telephone:", "Phone No.", "Phone:", "Fax number:", "Fax:", "E-mail:", "Email:", "e-mail:", "E-mail address:"), "PII", EntityType.ENTITY, $section),
|
||||||
|
Stream.concat(
|
||||||
|
entityCreationService.betweenStrings("No:", "Fax", "PII", EntityType.ENTITY, $section),
|
||||||
|
entityCreationService.betweenStrings("Contact:", "Tel", "PII", EntityType.ENTITY, $section)
|
||||||
|
))
|
||||||
|
.forEach(entity -> entity.redact("PII.8.1", "Producer was found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "PII.8.2: Redact contact information if producer is found (vertebrate study)"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$section: Section(containsStringIgnoreCase("producer of the plant protection") ||
|
||||||
|
containsStringIgnoreCase("producer of the active substance") ||
|
||||||
|
containsStringIgnoreCase("manufacturer of the active substance") ||
|
||||||
|
containsStringIgnoreCase("manufacturer:") ||
|
||||||
|
containsStringIgnoreCase("Producer or producers of the active substance"))
|
||||||
|
then
|
||||||
|
Stream.concat(entityCreationService.lineAfterStrings(List.of("Contact point:", "Contact:", "Alternative contact:", "European contact:", "No:", "Contact:", "Tel.:", "Tel:", "Telephone number:",
|
||||||
|
"Telephone No:", "Telephone:", "Phone No.", "Phone:", "Fax number:", "Fax:", "E-mail:", "Email:", "e-mail:", "E-mail address:"), "PII", EntityType.ENTITY, $section),
|
||||||
|
Stream.concat(
|
||||||
|
entityCreationService.betweenStrings("No:", "Fax", "PII", EntityType.ENTITY, $section),
|
||||||
|
entityCreationService.betweenStrings("Contact:", "Tel", "PII", EntityType.ENTITY, $section)
|
||||||
|
))
|
||||||
|
.forEach(entity -> entity.redact("PII.8.2", "Producer was found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
// Rule unit: PII.10
|
||||||
|
rule "PII.10.0: Redact study director abbreviation"
|
||||||
|
when
|
||||||
|
$section: Section(containsString("KATH") || containsString("BECH") || containsString("KML"))
|
||||||
|
then
|
||||||
|
entityCreationService.byRegexIgnoreCase("((KATH)|(BECH)|(KML)) ?(\\d{4})","PII", EntityType.ENTITY, 1, $section)
|
||||||
|
.forEach(entity -> entity.redact("PII.10.0", "Personal information found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: PII.11
|
||||||
|
rule "PII.11.0: Redact On behalf of Sequani Ltd.:"
|
||||||
|
when
|
||||||
|
$section: Section(!hasTables(), containsString("On behalf of Sequani Ltd.: Name Title"))
|
||||||
|
then
|
||||||
|
entityCreationService.betweenStrings("On behalf of Sequani Ltd.: Name Title", "On behalf of", "PII", EntityType.ENTITY, $section)
|
||||||
|
.forEach(authorEntity -> authorEntity.redact("PII.11.0", "On behalf of Sequani Ltd.: Name Title was found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: PII.12
|
||||||
|
rule "PII.12.0: Expand PII entities with salutation prefix"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$entityToExpand: TextEntity(type() == "PII", anyMatch(textBefore, "\\b(Mrs?|Ms|Miss|Sir|Madame?|Mme)\\s?\\.?\\s*"))
|
||||||
|
then
|
||||||
|
entityCreationService.byPrefixExpansionRegex($entityToExpand, "\\b(Mrs?|Ms|Miss|Sir|Madame?|Mme)\\s?\\.?\\s*")
|
||||||
|
.ifPresent(expandedEntity -> expandedEntity.apply("PII.12.0", "Expanded PII with salutation prefix", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "PII.12.1: Expand PII entities with salutation prefix"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$entityToExpand: TextEntity(type() == "PII", anyMatch(textBefore, "\\b(Mrs?|Ms|Miss|Sir|Madame?|Mme)\\s?\\.?\\s*"))
|
||||||
|
then
|
||||||
|
entityCreationService.byPrefixExpansionRegex($entityToExpand, "\\b(Mrs?|Ms|Miss|Sir|Madame?|Mme)\\s?\\.?\\s*")
|
||||||
|
.ifPresent(expandedEntity -> expandedEntity.apply("PII.12.1", "Expanded PII with salutation prefix", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------ Other rules ------------------------------------
|
||||||
|
|
||||||
|
// Rule unit: ETC.0
|
||||||
|
rule "ETC.0.0: Purity Hint"
|
||||||
|
when
|
||||||
|
$section: Section(containsStringIgnoreCase("purity"))
|
||||||
|
then
|
||||||
|
entityCreationService.byRegexIgnoreCase("(purity ?( of|\\(.{1,20}\\))?( ?:)?) .{0,5}[\\d\\.]+( .{0,4}\\.)? ?%", "hint_only", EntityType.HINT, 1, $section)
|
||||||
|
.forEach(hint -> hint.skip("ETC.0.0", "hint only"));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: ETC.2
|
||||||
|
rule "ETC.2.1: Redact signatures (non vertebrate study)"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$signature: Image(imageType == ImageType.SIGNATURE)
|
||||||
|
then
|
||||||
|
$signature.redact("ETC.2.1", "Signature Found", "Article 39(e)(3) of Regulation (EC) No 178/2002");
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "ETC.2.2: Redact signatures (vertebrate study)"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$signature: Image(imageType == ImageType.SIGNATURE)
|
||||||
|
then
|
||||||
|
$signature.redact("ETC.2.2", "Signature Found", "Article 39(e)(2) of Regulation (EC) No 178/2002");
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: ETC.3
|
||||||
|
rule "ETC.3.1: Skip logos (non vertebrate study)"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$logo: Image(imageType == ImageType.LOGO)
|
||||||
|
then
|
||||||
|
$logo.skip("ETC.3.1", "Logo Found");
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "ETC.3.2: Redact logos (vertebrate study)"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$logo: Image(imageType == ImageType.LOGO)
|
||||||
|
then
|
||||||
|
$logo.redact("ETC.3.2", "Logo Found", "Article 39(e)(3) of Regulation (EC) No 178/2002");
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: ETC.5
|
||||||
|
rule "ETC.5.0: Skip dossier_redaction entries if confidentiality is 'confidential'"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Confidentiality", value == "confidential")
|
||||||
|
$dossierRedaction: TextEntity(type() == "dossier_redaction")
|
||||||
|
then
|
||||||
|
$dossierRedaction.skip("ETC.5.0", "Ignore dossier_redaction when confidential");
|
||||||
|
$dossierRedaction.getIntersectingNodes().forEach(node -> update(node));
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "ETC.5.1: Remove dossier_redaction entries if confidentiality is not 'confidential'"
|
||||||
|
salience 256
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Confidentiality", value == "confidential")
|
||||||
|
$dossierRedaction: TextEntity(type() == "dossier_redaction")
|
||||||
|
then
|
||||||
|
$dossierRedaction.remove("ETC.5.1", "Remove dossier_redaction when not confidential");
|
||||||
|
retract($dossierRedaction);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------ AI rules ------------------------------------
|
||||||
|
|
||||||
|
// Rule unit: AI.0
|
||||||
|
rule "AI.0.0: Add all NER Entities of type CBI_author"
|
||||||
|
salience 999
|
||||||
|
when
|
||||||
|
nerEntities: NerEntities(hasEntitiesOfType("CBI_author"))
|
||||||
|
then
|
||||||
|
nerEntities.streamEntitiesOfType("CBI_author")
|
||||||
|
.forEach(nerEntity -> entityCreationService.optionalByNerEntity(nerEntity, EntityType.RECOMMENDATION, document));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: AI.1
|
||||||
|
rule "AI.1.0: Combine and add NER Entities as CBI_address"
|
||||||
|
salience 999
|
||||||
|
when
|
||||||
|
nerEntities: NerEntities(hasEntitiesOfType("ORG") || hasEntitiesOfType("STREET") || hasEntitiesOfType("CITY"))
|
||||||
|
then
|
||||||
|
entityCreationService.combineNerEntitiesToCbiAddressDefaults(nerEntities, "CBI_address", EntityType.RECOMMENDATION, document).toList();
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------ Manual changes rules ------------------------------------
|
||||||
|
|
||||||
|
// Rule unit: MAN.0
|
||||||
|
rule "MAN.0.0: Apply manual resize redaction"
|
||||||
|
salience 128
|
||||||
|
when
|
||||||
|
$resizeRedaction: ManualResizeRedaction($id: annotationId, $requestDate: requestDate)
|
||||||
|
not ManualResizeRedaction(annotationId == $id, requestDate.isBefore($requestDate))
|
||||||
|
$entityToBeResized: TextEntity(matchesAnnotationId($id))
|
||||||
|
then
|
||||||
|
manualChangesApplicationService.resize($entityToBeResized, $resizeRedaction);
|
||||||
|
retract($resizeRedaction);
|
||||||
|
update($entityToBeResized);
|
||||||
|
$entityToBeResized.getIntersectingNodes().forEach(node -> update(node));
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "MAN.0.1: Apply manual resize redaction"
|
||||||
|
salience 128
|
||||||
|
when
|
||||||
|
$resizeRedaction: ManualResizeRedaction($id: annotationId, $requestDate: requestDate)
|
||||||
|
not ManualResizeRedaction(annotationId == $id, requestDate.isBefore($requestDate))
|
||||||
|
$imageToBeResized: Image(id == $id)
|
||||||
|
then
|
||||||
|
manualChangesApplicationService.resizeImage($imageToBeResized, $resizeRedaction);
|
||||||
|
retract($resizeRedaction);
|
||||||
|
update($imageToBeResized);
|
||||||
|
update($imageToBeResized.getParent());
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: MAN.1
|
||||||
|
rule "MAN.1.0: Apply id removals that are valid and not in forced redactions to Entity"
|
||||||
|
salience 128
|
||||||
|
when
|
||||||
|
$idRemoval: IdRemoval($id: annotationId, !removeFromDictionary, !removeFromAllDossiers)
|
||||||
|
$entityToBeRemoved: TextEntity(matchesAnnotationId($id))
|
||||||
|
then
|
||||||
|
$entityToBeRemoved.getManualOverwrite().addChange($idRemoval);
|
||||||
|
update($entityToBeRemoved);
|
||||||
|
retract($idRemoval);
|
||||||
|
$entityToBeRemoved.getIntersectingNodes().forEach(node -> update(node));
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "MAN.1.1: Apply id removals that are valid and not in forced redactions to Image"
|
||||||
|
salience 128
|
||||||
|
when
|
||||||
|
$idRemoval: IdRemoval($id: annotationId)
|
||||||
|
$imageEntityToBeRemoved: Image($id == id)
|
||||||
|
then
|
||||||
|
$imageEntityToBeRemoved.getManualOverwrite().addChange($idRemoval);
|
||||||
|
update($imageEntityToBeRemoved);
|
||||||
|
retract($idRemoval);
|
||||||
|
update($imageEntityToBeRemoved.getParent());
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: MAN.2
|
||||||
|
rule "MAN.2.0: Apply force redaction"
|
||||||
|
salience 128
|
||||||
|
when
|
||||||
|
$force: ManualForceRedaction($id: annotationId)
|
||||||
|
$entityToForce: TextEntity(matchesAnnotationId($id))
|
||||||
|
then
|
||||||
|
$entityToForce.getManualOverwrite().addChange($force);
|
||||||
|
update($entityToForce);
|
||||||
|
$entityToForce.getIntersectingNodes().forEach(node -> update(node));
|
||||||
|
retract($force);
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "MAN.2.1: Apply force redaction to images"
|
||||||
|
salience 128
|
||||||
|
when
|
||||||
|
$force: ManualForceRedaction($id: annotationId)
|
||||||
|
$imageToForce: Image(id == $id)
|
||||||
|
then
|
||||||
|
$imageToForce.getManualOverwrite().addChange($force);
|
||||||
|
update($imageToForce);
|
||||||
|
update($imageToForce.getParent());
|
||||||
|
retract($force);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: MAN.3
|
||||||
|
rule "MAN.3.0: Apply entity recategorization"
|
||||||
|
salience 128
|
||||||
|
when
|
||||||
|
$recategorization: ManualRecategorization($id: annotationId, $type: type, $requestDate: requestDate)
|
||||||
|
not ManualRecategorization($id == annotationId, requestDate.isBefore($requestDate))
|
||||||
|
$entityToBeRecategorized: TextEntity(matchesAnnotationId($id), type() != $type)
|
||||||
|
then
|
||||||
|
$entityToBeRecategorized.getIntersectingNodes().forEach(node -> update(node));
|
||||||
|
$entityToBeRecategorized.getManualOverwrite().addChange($recategorization);
|
||||||
|
update($entityToBeRecategorized);
|
||||||
|
retract($recategorization);
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "MAN.3.1: Apply entity recategorization of same type"
|
||||||
|
salience 128
|
||||||
|
when
|
||||||
|
$recategorization: ManualRecategorization($id: annotationId, $type: type, $requestDate: requestDate)
|
||||||
|
not ManualRecategorization($id == annotationId, requestDate.isBefore($requestDate))
|
||||||
|
$entityToBeRecategorized: TextEntity(matchesAnnotationId($id), type() == $type)
|
||||||
|
then
|
||||||
|
$entityToBeRecategorized.getManualOverwrite().addChange($recategorization);
|
||||||
|
retract($recategorization);
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "MAN.3.2: Apply image recategorization"
|
||||||
|
salience 128
|
||||||
|
when
|
||||||
|
$recategorization: ManualRecategorization($id: annotationId, $requestDate: requestDate)
|
||||||
|
not ManualRecategorization($id == annotationId, requestDate.isBefore($requestDate))
|
||||||
|
$imageToBeRecategorized: Image($id == id)
|
||||||
|
then
|
||||||
|
manualChangesApplicationService.recategorize($imageToBeRecategorized, $recategorization);
|
||||||
|
update($imageToBeRecategorized);
|
||||||
|
update($imageToBeRecategorized.getParent());
|
||||||
|
retract($recategorization);
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "MAN.3.3: Apply recategorization entities by default"
|
||||||
|
salience 128
|
||||||
|
when
|
||||||
|
$entity: TextEntity(getManualOverwrite().getRecategorized().orElse(false), !dictionary.isHint(type()))
|
||||||
|
then
|
||||||
|
$entity.apply("MAN.3.3", "Recategorized entities are applied by default.", $entity.legalBasis());
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: MAN.4
|
||||||
|
rule "MAN.4.0: Apply legal basis change"
|
||||||
|
salience 128
|
||||||
|
when
|
||||||
|
$legalBasisChange: ManualLegalBasisChange($id: annotationId)
|
||||||
|
$imageToBeRecategorized: Image($id == id)
|
||||||
|
then
|
||||||
|
$imageToBeRecategorized.getManualOverwrite().addChange($legalBasisChange);
|
||||||
|
update($imageToBeRecategorized)
|
||||||
|
retract($legalBasisChange)
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "MAN.4.1: Apply legal basis change"
|
||||||
|
salience 128
|
||||||
|
when
|
||||||
|
$legalBasisChange: ManualLegalBasisChange($id: annotationId)
|
||||||
|
$entityToBeChanged: TextEntity(matchesAnnotationId($id))
|
||||||
|
then
|
||||||
|
$entityToBeChanged.getManualOverwrite().addChange($legalBasisChange);
|
||||||
|
update($entityToBeChanged)
|
||||||
|
retract($legalBasisChange)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------ Entity merging rules ------------------------------------
|
||||||
|
|
||||||
|
// Rule unit: X.0
|
||||||
|
rule "X.0.0: Remove Entity contained by Entity of same type"
|
||||||
|
salience 65
|
||||||
|
when
|
||||||
|
$larger: TextEntity($type: type(), $entityType: entityType, active())
|
||||||
|
$contained: TextEntity(containedBy($larger), type() == $type, entityType == $entityType, this != $larger, !hasManualChanges())
|
||||||
|
then
|
||||||
|
$contained.remove("X.0.0", "remove Entity contained by Entity of same type");
|
||||||
|
retract($contained);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: X.1
|
||||||
|
rule "X.1.0: Merge intersecting Entities of same type"
|
||||||
|
salience 64
|
||||||
|
when
|
||||||
|
$first: TextEntity($type: type(), $entityType: entityType, !resized(), active())
|
||||||
|
$second: TextEntity(intersects($first), type() == $type, entityType == $entityType, this != $first, !hasManualChanges(), active())
|
||||||
|
then
|
||||||
|
TextEntity mergedEntity = entityCreationService.mergeEntitiesOfSameType(List.of($first, $second), $type, $entityType, document);
|
||||||
|
$first.remove("X.1.0", "merge intersecting Entities of same type");
|
||||||
|
$second.remove("X.1.0", "merge intersecting Entities of same type");
|
||||||
|
retract($first);
|
||||||
|
retract($second);
|
||||||
|
mergedEntity.getIntersectingNodes().forEach(node -> update(node));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: X.2
|
||||||
|
rule "X.2.0: Remove Entity of type ENTITY when contained by FALSE_POSITIVE"
|
||||||
|
salience 64
|
||||||
|
when
|
||||||
|
$falsePositive: TextEntity($type: type(), entityType == EntityType.FALSE_POSITIVE, active())
|
||||||
|
$entity: TextEntity(containedBy($falsePositive), type() == $type, (entityType == EntityType.ENTITY || entityType == EntityType.HINT), !hasManualChanges())
|
||||||
|
then
|
||||||
|
$entity.getIntersectingNodes().forEach(node -> update(node));
|
||||||
|
$entity.remove("X.2.0", "remove Entity of type ENTITY when contained by FALSE_POSITIVE");
|
||||||
|
retract($entity)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: X.3
|
||||||
|
rule "X.3.0: Remove Entity of type RECOMMENDATION when contained by FALSE_RECOMMENDATION"
|
||||||
|
salience 64
|
||||||
|
when
|
||||||
|
$falseRecommendation: TextEntity($type: type(), entityType == EntityType.FALSE_RECOMMENDATION, active())
|
||||||
|
$recommendation: TextEntity(containedBy($falseRecommendation), type() == $type, entityType == EntityType.RECOMMENDATION, !hasManualChanges())
|
||||||
|
then
|
||||||
|
$recommendation.remove("X.3.0", "remove Entity of type RECOMMENDATION when contained by FALSE_RECOMMENDATION");
|
||||||
|
retract($recommendation);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: X.4
|
||||||
|
rule "X.4.0: Remove Entity of type RECOMMENDATION when text range equals ENTITY with same type"
|
||||||
|
salience 256
|
||||||
|
when
|
||||||
|
$entity: TextEntity($type: type(), (entityType == EntityType.ENTITY || entityType == EntityType.HINT), active())
|
||||||
|
$recommendation: TextEntity(getTextRange().equals($entity.getTextRange()), type() == $type, entityType == EntityType.RECOMMENDATION, !hasManualChanges())
|
||||||
|
then
|
||||||
|
$entity.addEngines($recommendation.getEngines());
|
||||||
|
$recommendation.remove("X.4.0", "remove Entity of type RECOMMENDATION when text range equals ENTITY with same type");
|
||||||
|
retract($recommendation);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: X.5
|
||||||
|
rule "X.5.0: Remove Entity of type RECOMMENDATION when intersected by ENTITY"
|
||||||
|
salience 256
|
||||||
|
when
|
||||||
|
$entity: TextEntity((entityType == EntityType.ENTITY || entityType == EntityType.HINT), active())
|
||||||
|
$recommendation: TextEntity(intersects($entity), entityType == EntityType.RECOMMENDATION, !hasManualChanges())
|
||||||
|
then
|
||||||
|
$recommendation.remove("X.5.0", "remove Entity of type RECOMMENDATION when intersected by ENTITY");
|
||||||
|
retract($recommendation);
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "X.5.1: Remove Entity of type RECOMMENDATION when contained by RECOMMENDATION"
|
||||||
|
salience 256
|
||||||
|
when
|
||||||
|
$entity: TextEntity($type: type(), entityType == EntityType.RECOMMENDATION, active())
|
||||||
|
$recommendation: TextEntity(containedBy($entity), type() != $type, entityType == EntityType.RECOMMENDATION, !hasManualChanges())
|
||||||
|
then
|
||||||
|
$recommendation.remove("X.5.1", "remove Entity of type RECOMMENDATION when contained by RECOMMENDATION");
|
||||||
|
retract($recommendation);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: X.6
|
||||||
|
rule "X.6.0: Remove Entity of lower rank, when contained by entity of type ENTITY or HINT"
|
||||||
|
salience 32
|
||||||
|
when
|
||||||
|
$higherRank: TextEntity($type: type(), (entityType == EntityType.ENTITY || entityType == EntityType.HINT), active())
|
||||||
|
$lowerRank: TextEntity(containedBy($higherRank), type() != $type, dictionary.getDictionaryRank(type) < dictionary.getDictionaryRank($type), !hasManualChanges())
|
||||||
|
then
|
||||||
|
$lowerRank.getIntersectingNodes().forEach(node -> update(node));
|
||||||
|
$lowerRank.remove("X.6.0", "remove Entity of lower rank, when contained by entity of type ENTITY or HINT");
|
||||||
|
retract($lowerRank);
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "X.6.1: remove Entity, when contained in another entity of type ENTITY or HINT with larger text range"
|
||||||
|
salience 32
|
||||||
|
when
|
||||||
|
$outer: TextEntity($type: type(), (entityType == EntityType.ENTITY || entityType == EntityType.HINT), active())
|
||||||
|
$inner: TextEntity(containedBy($outer), type() != $type, $outer.getTextRange().length > getTextRange().length(), !hasManualChanges())
|
||||||
|
then
|
||||||
|
$inner.getIntersectingNodes().forEach(node -> update(node));
|
||||||
|
$inner.remove("X.6.1", "remove Entity, when contained in another entity of type ENTITY or HINT with larger text range");
|
||||||
|
retract($inner);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: X.8
|
||||||
|
rule "X.8.0: Remove Entity when text range and type equals to imported Entity"
|
||||||
|
salience 257
|
||||||
|
when
|
||||||
|
$entity: TextEntity($type: type(), engines contains Engine.IMPORTED, active())
|
||||||
|
$other: TextEntity(getTextRange().equals($entity.getTextRange()), this != $entity, type() == $type, engines not contains Engine.IMPORTED)
|
||||||
|
then
|
||||||
|
$other.remove("X.8.0", "remove Entity when text range and type equals to imported Entity");
|
||||||
|
$entity.addEngines($other.getEngines());
|
||||||
|
retract($other);
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "X.8.1: Remove Entity when intersected by imported Entity"
|
||||||
|
salience 256
|
||||||
|
when
|
||||||
|
$entity: TextEntity(engines contains Engine.IMPORTED, active())
|
||||||
|
$other: TextEntity(intersects($entity), this != $entity, engines not contains Engine.IMPORTED)
|
||||||
|
then
|
||||||
|
$other.remove("X.8.1", "remove Entity when intersected by imported Entity");
|
||||||
|
retract($other);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: X.9
|
||||||
|
rule "X.9.0: Merge mostly contained signatures"
|
||||||
|
when
|
||||||
|
$aiSignature: Image(imageType == ImageType.SIGNATURE, engines contains LayoutEngine.AI)
|
||||||
|
$signature: Image(imageType == ImageType.SIGNATURE, engines contains LayoutEngine.ALGORITHM, mostlyContains($aiSignature, 0.8))
|
||||||
|
then
|
||||||
|
$aiSignature.remove("X.9.0", "removed because already contained by alogrithm signature");
|
||||||
|
$signature.addEngine(LayoutEngine.AI);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: X.10
|
||||||
|
rule "X.10.0: remove false positives of ai"
|
||||||
|
when
|
||||||
|
$anyImage: Image(engines contains LayoutEngine.ALGORITHM)
|
||||||
|
$aiSignature: Image(imageType == ImageType.SIGNATURE, engines contains LayoutEngine.AI, !mostlyContainedBy($anyImage, 0.8))
|
||||||
|
then
|
||||||
|
$aiSignature.remove("X.10.0", "Removed because false positive");
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------ File attributes rules ------------------------------------
|
||||||
|
|
||||||
|
// Rule unit: FA.1
|
||||||
|
rule "FA.1.0: Remove duplicate FileAttributes"
|
||||||
|
salience 64
|
||||||
|
when
|
||||||
|
$fileAttribute: FileAttribute($label: label, $value: value)
|
||||||
|
$duplicate: FileAttribute(this != $fileAttribute, label == $label, value == $value)
|
||||||
|
then
|
||||||
|
retract($duplicate);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------ Local dictionary search rules ------------------------------------
|
||||||
|
|
||||||
|
// Rule unit: LDS.0
|
||||||
|
rule "LDS.0.0: Run local dictionary search"
|
||||||
|
agenda-group "LOCAL_DICTIONARY_ADDS"
|
||||||
|
salience -999
|
||||||
|
when
|
||||||
|
$dictionaryModel: DictionaryModel(!localEntriesWithMatchedRules.isEmpty()) from dictionary.getDictionaryModels()
|
||||||
|
then
|
||||||
|
entityCreationService.bySearchImplementation($dictionaryModel.getLocalSearch(), $dictionaryModel.getType(), EntityType.RECOMMENDATION, document)
|
||||||
|
.forEach(entity -> {
|
||||||
|
Collection<MatchedRule> matchedRules = $dictionaryModel.getMatchedRulesForLocalDictionaryEntry(entity.getValue());
|
||||||
|
matchedRules.forEach(matchedRule -> entity.addMatchedRule(matchedRule.asSkippedIfApplied()));
|
||||||
|
});
|
||||||
|
end
|
||||||
@ -580,6 +580,26 @@ rule "CBI.20.3: Redact between \"PERFORMING LABORATORY\" and \"LABORATORY PROJEC
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: CBI.23
|
||||||
|
rule "CBI.23.0: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (non vertebrate study)"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
||||||
|
then
|
||||||
|
entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "CBI_author", EntityType.ENTITY, $document)
|
||||||
|
.forEach(authorEntity -> authorEntity.redact("CBI.23.0", "AUTHOR(S) was found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "CBI.23.1: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (vertebrate study)"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
||||||
|
then
|
||||||
|
entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "CBI_author", EntityType.ENTITY, $document)
|
||||||
|
.forEach(authorEntity -> authorEntity.redact("CBI.23.1", "AUTHOR(S) was found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------ PII rules ------------------------------------
|
//------------------------------------ PII rules ------------------------------------
|
||||||
|
|
||||||
|
|
||||||
@ -883,24 +903,6 @@ rule "PII.9.0: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\""
|
|||||||
.forEach(authorEntity -> authorEntity.redact("PII.9.0", "AUTHOR(S) was found", "Reg (EC) No 1107/2009 Art. 63 (2e)"));
|
.forEach(authorEntity -> authorEntity.redact("PII.9.0", "AUTHOR(S) was found", "Reg (EC) No 1107/2009 Art. 63 (2e)"));
|
||||||
end
|
end
|
||||||
|
|
||||||
rule "PII.9.1: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (non vertebrate study)"
|
|
||||||
when
|
|
||||||
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
|
||||||
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
|
||||||
then
|
|
||||||
entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "PII", EntityType.ENTITY, $document)
|
|
||||||
.forEach(authorEntity -> authorEntity.redact("PII.9.1", "AUTHOR(S) was found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
|
||||||
end
|
|
||||||
|
|
||||||
rule "PII.9.2: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (vertebrate study)"
|
|
||||||
when
|
|
||||||
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
|
||||||
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
|
||||||
then
|
|
||||||
entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "PII", EntityType.ENTITY, $document)
|
|
||||||
.forEach(authorEntity -> authorEntity.redact("PII.9.2", "AUTHOR(S) was found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
|
|
||||||
end
|
|
||||||
|
|
||||||
rule "PII.9.3: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\""
|
rule "PII.9.3: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\""
|
||||||
when
|
when
|
||||||
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
||||||
|
|||||||
@ -833,6 +833,26 @@ rule "CBI.22.0: Redact Addresses in Reference Tables for vertebrate studies in n
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
// Rule unit: CBI.23
|
||||||
|
rule "CBI.23.0: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (non vertebrate study)"
|
||||||
|
when
|
||||||
|
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
||||||
|
then
|
||||||
|
entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "CBI_author", EntityType.ENTITY, $document)
|
||||||
|
.forEach(authorEntity -> authorEntity.redact("CBI.23.0", "AUTHOR(S) was found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
rule "CBI.23.1: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (vertebrate study)"
|
||||||
|
when
|
||||||
|
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
||||||
|
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
||||||
|
then
|
||||||
|
entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "CBI_author", EntityType.ENTITY, $document)
|
||||||
|
.forEach(authorEntity -> authorEntity.redact("CBI.23.1", "AUTHOR(S) was found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------ PII rules ------------------------------------
|
//------------------------------------ PII rules ------------------------------------
|
||||||
|
|
||||||
// Rule unit: PII.0
|
// Rule unit: PII.0
|
||||||
@ -1281,24 +1301,6 @@ rule "PII.9.0: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\""
|
|||||||
.forEach(authorEntity -> authorEntity.redact("PII.9.0", "AUTHOR(S) was found", "Reg (EC) No 1107/2009 Art. 63 (2e)"));
|
.forEach(authorEntity -> authorEntity.redact("PII.9.0", "AUTHOR(S) was found", "Reg (EC) No 1107/2009 Art. 63 (2e)"));
|
||||||
end
|
end
|
||||||
|
|
||||||
rule "PII.9.1: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (non vertebrate study)"
|
|
||||||
when
|
|
||||||
not FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
|
||||||
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
|
||||||
then
|
|
||||||
entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "PII", EntityType.ENTITY, $document)
|
|
||||||
.forEach(authorEntity -> authorEntity.redact("PII.9.1", "AUTHOR(S) was found", "Article 39(e)(3) of Regulation (EC) No 178/2002"));
|
|
||||||
end
|
|
||||||
|
|
||||||
rule "PII.9.2: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\" (vertebrate study)"
|
|
||||||
when
|
|
||||||
FileAttribute(label == "Vertebrate Study", value soundslike "Yes" || value.toLowerCase() == "y")
|
|
||||||
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
|
||||||
then
|
|
||||||
entityCreationService.shortestBetweenAnyStringIgnoreCase(List.of("AUTHOR(S)", "AUTHOR(S):"), List.of("COMPLETION DATE", "COMPLETION DATE:", "STUDY COMPLETION DATE", "STUDY COMPLETION DATE:"), "PII", EntityType.ENTITY, $document)
|
|
||||||
.forEach(authorEntity -> authorEntity.redact("PII.9.2", "AUTHOR(S) was found", "Article 39(e)(2) of Regulation (EC) No 178/2002"));
|
|
||||||
end
|
|
||||||
|
|
||||||
rule "PII.9.3: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\""
|
rule "PII.9.3: Redact between \"AUTHOR(S)\" and \"(STUDY) COMPLETION DATE\""
|
||||||
when
|
when
|
||||||
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
$document: Document(containsStringIgnoreCase("AUTHOR(S)"), containsAnyStringIgnoreCase("COMPLETION DATE", "STUDY COMPLETION DATE"))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user