DM-285: add component log and entity log, deprecate redaction log #110

Merged
kilian.schuettler1 merged 9 commits from DM-285 into master 2023-09-11 17:14:02 +02:00
83 changed files with 1506 additions and 242 deletions

View File

@ -0,0 +1,71 @@
package com.iqser.red.persistence.service.v1.external.api.impl.controller;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_REDACTION_LOG;
import static com.iqser.red.service.persistence.management.v1.processor.service.FeignExceptionHandler.processFeignException;
import java.util.List;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.iqser.red.service.persistence.management.v1.processor.service.ComponentLogService;
import com.iqser.red.service.persistence.management.v1.processor.service.EntityLogService;
import com.iqser.red.service.persistence.service.v1.api.external.resource.AnalysisLogResource;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.FilteredEntityLogRequest;
import feign.FeignException;
import lombok.RequiredArgsConstructor;
@RestController
@RequiredArgsConstructor
public class AnalysisLogController implements AnalysisLogResource {
private final EntityLogService entityLogService;
private final ComponentLogService componentLogService;
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId,
@PathVariable(FILE_ID) String fileId,
@RequestParam(value = "excludedType", required = false) List<String> excludedTypes,
@RequestParam(value = "withManualRedactions", required = false, defaultValue = "true") boolean withManualRedactions,
@RequestParam(value = "includeFalsePositives", required = false, defaultValue = "false") boolean includeFalsePositives) {
try {
return entityLogService.getEntityLog(dossierId, fileId, excludedTypes);
} catch (FeignException e) {
throw processFeignException(e);
}
}
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public EntityLog getFilteredEntityLog(@PathVariable(DOSSIER_ID) String dossierId,
@PathVariable(FILE_ID) String fileId,
@RequestBody FilteredEntityLogRequest filteredEntityLogRequest) {
try {
return entityLogService.getFilteredEntityLog(dossierId, fileId, filteredEntityLogRequest);
} catch (FeignException e) {
throw processFeignException(e);
}
}
@Override
public ComponentLog getComponentLog(String dossierId, String fileId) {
try {
return componentLogService.getComponentLog(dossierId, fileId);
} catch (FeignException e) {
throw processFeignException(e);
}
}
}

View File

@ -0,0 +1,168 @@
package com.iqser.red.persistence.service.v1.external.api.impl.controller;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_REDACTION_LOG;
import static com.iqser.red.service.persistence.management.v1.processor.service.FeignExceptionHandler.processFeignException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import com.iqser.red.service.persistence.management.v1.processor.service.FileManagementStorageService;
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService;
import com.iqser.red.service.persistence.management.v1.processor.service.RedactionLogService;
import com.iqser.red.service.persistence.management.v1.processor.utils.StringEncodingUtils;
import com.iqser.red.service.persistence.service.v1.api.external.resource.DocumentResource;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType;
import com.iqser.red.storage.commons.exception.StorageObjectDoesNotExist;
import com.knecon.fforesight.tenantcommons.TenantContext;
import feign.FeignException;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
@RestController
@RequiredArgsConstructor
public class DocumentController implements DocumentResource {
private final RedactionLogService redactionLogService;
private final FileStatusService fileStatusService;
private final FileManagementStorageService fileManagementStorageService;
@SneakyThrows
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public ResponseEntity<?> getDocumentText(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
try {
return buildZipFileResponseEntity(fileId, dossierId, FileType.DOCUMENT_TEXT);
} catch (FeignException e) {
throw processFeignException(e);
}
}
@SneakyThrows
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public ResponseEntity<?> getDocumentPositions(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
try {
return buildZipFileResponseEntity(fileId, dossierId, FileType.DOCUMENT_POSITION);
} catch (FeignException e) {
throw processFeignException(e);
}
}
@SneakyThrows
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public ResponseEntity<?> getDocumentStructure(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
try {
return buildZipFileResponseEntity(fileId, dossierId, FileType.DOCUMENT_STRUCTURE);
} catch (FeignException e) {
throw processFeignException(e);
}
}
@SneakyThrows
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public ResponseEntity<?> getDocumentPages(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
try {
return buildZipFileResponseEntity(fileId, dossierId, FileType.DOCUMENT_PAGES);
} catch (FeignException e) {
throw processFeignException(e);
}
}
@SneakyThrows
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public ResponseEntity<?> getSimplifiedSectionText(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
try {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.parseMediaType("application/zip"));
var fileStatus = fileStatusService.getStatus(fileId);
String filename = fileStatus.getFilename();
if (filename != null) {
var index = filename.lastIndexOf(".");
String prefix = filename.substring(0, index);
filename = prefix + ".json";
httpHeaders.add("Content-Disposition", "attachment; filename*=utf-8''" + StringEncodingUtils.urlEncode(prefix) + ".zip");
}
byte[] zipBytes = getZippedBytes(dossierId, fileId, filename, FileType.SIMPLIFIED_TEXT);
return new ResponseEntity<>(zipBytes, httpHeaders, HttpStatus.OK);
} catch (StorageObjectDoesNotExist e) {
throw new RuntimeException("Simplified Text is not available", e);
} catch (FeignException e) {
throw processFeignException(e);
}
}
private ResponseEntity<byte[]> buildZipFileResponseEntity(String fileId, String dossierId, FileType fileType) throws IOException {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.parseMediaType("application/zip"));
var fileStatus = fileStatusService.getStatus(fileId);
String filename = fileStatus.getFilename();
if (filename != null) {
var index = filename.lastIndexOf(".");
String prefix = filename.substring(0, index);
filename = prefix + ".json";
httpHeaders.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=utf-8''" + StringEncodingUtils.urlEncode(prefix) + ".zip");
}
byte[] zipBytes = getZippedBytes(dossierId, fileId, filename, fileType);
httpHeaders.setContentLength(zipBytes.length);
return new ResponseEntity<>(zipBytes, httpHeaders, HttpStatus.OK);
}
private byte[] getZippedBytes(String dossierId, String fileId, String filename, FileType fileType) throws IOException {
try {
String objectId = dossierId + "/" + fileId + "." + fileType.name() + fileType.getExtension();
try (var inputStream = fileManagementStorageService.getObject(TenantContext.getTenantId(), objectId)) {
byte[] input = inputStream.readAllBytes();
inputStream.close();
return zipBytes(filename, input);
}
} catch (StorageObjectDoesNotExist e) {
throw new RuntimeException(String.format("%s is not available", fileType.name()), e);
}
}
public static byte[] zipBytes(String filename, byte[] input) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zos = new ZipOutputStream(baos);
ZipEntry entry = new ZipEntry(filename);
entry.setSize(input.length);
zos.putNextEntry(entry);
zos.write(input);
zos.closeEntry();
zos.close();
return baos.toByteArray();
}
}

View File

@ -37,6 +37,7 @@ import lombok.SneakyThrows;
@RestController
@RequiredArgsConstructor
@Deprecated(forRemoval = true)
public class RedactionLogController implements RedactionLogResource {
private final RedactionLogService redactionLogService;
@ -44,6 +45,7 @@ public class RedactionLogController implements RedactionLogResource {
private final FileManagementStorageService fileManagementStorageService;
@Deprecated(forRemoval = true)
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public RedactionLog getRedactionLog(@PathVariable(DOSSIER_ID) String dossierId,
@PathVariable(FILE_ID) String fileId,
@ -59,6 +61,7 @@ public class RedactionLogController implements RedactionLogResource {
}
@Deprecated(forRemoval = true)
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public SectionGrid getSectionGrid(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
@ -70,6 +73,7 @@ public class RedactionLogController implements RedactionLogResource {
}
@Deprecated(forRemoval = true)
@SneakyThrows
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public ResponseEntity<?> getSectionText(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
@ -102,83 +106,7 @@ public class RedactionLogController implements RedactionLogResource {
}
@SneakyThrows
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public ResponseEntity<?> getDocumentText(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
try {
return buildZipFileResponseEntity(fileId, dossierId, FileType.DOCUMENT_TEXT);
} catch (FeignException e) {
throw processFeignException(e);
}
}
@SneakyThrows
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public ResponseEntity<?> getDocumentPositions(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
try {
return buildZipFileResponseEntity(fileId, dossierId, FileType.DOCUMENT_POSITION);
} catch (FeignException e) {
throw processFeignException(e);
}
}
@SneakyThrows
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public ResponseEntity<?> getDocumentStructure(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
try {
return buildZipFileResponseEntity(fileId, dossierId, FileType.DOCUMENT_STRUCTURE);
} catch (FeignException e) {
throw processFeignException(e);
}
}
@SneakyThrows
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public ResponseEntity<?> getDocumentPages(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
try {
return buildZipFileResponseEntity(fileId, dossierId, FileType.DOCUMENT_PAGES);
} catch (FeignException e) {
throw processFeignException(e);
}
}
@SneakyThrows
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public ResponseEntity<?> getSimplifiedSectionText(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
try {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.parseMediaType("application/zip"));
var fileStatus = fileStatusService.getStatus(fileId);
String filename = fileStatus.getFilename();
if (filename != null) {
var index = filename.lastIndexOf(".");
String prefix = filename.substring(0, index);
filename = prefix + ".json";
httpHeaders.add("Content-Disposition", "attachment; filename*=utf-8''" + StringEncodingUtils.urlEncode(prefix) + ".zip");
}
byte[] zipBytes = getZippedBytes(dossierId, fileId, filename, FileType.SIMPLIFIED_TEXT);
return new ResponseEntity<>(zipBytes, httpHeaders, HttpStatus.OK);
} catch (StorageObjectDoesNotExist e) {
throw new RuntimeException("Simplified Text is not available", e);
} catch (FeignException e) {
throw processFeignException(e);
}
}
@Deprecated(forRemoval = true)
@PreAuthorize("hasAuthority('" + READ_REDACTION_LOG + "')")
public RedactionLog getFilteredRedactionLog(@PathVariable(DOSSIER_ID) String dossierId,
@PathVariable(FILE_ID) String fileId,

View File

@ -1,19 +1,13 @@
package com.iqser.red.persistence.service.v1.external.api.impl.controller;
import com.iqser.red.service.persistence.management.v1.processor.client.redactionservice.RedactionClient;
import com.iqser.red.service.persistence.management.v1.processor.exception.FileUploadException;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.RulesPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.external.resource.RulesResource;
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.RuleSyntaxErrorMessage;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.Rules;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.RulesUploadRequest;
import com.iqser.red.service.redaction.v1.model.DroolsSyntaxValidation;
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_RULES;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.WRITE_RULES;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
@ -26,13 +20,22 @@ import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import com.iqser.red.service.persistence.management.v1.processor.exception.FileUploadException;
import com.iqser.red.service.persistence.management.v1.processor.service.RulesValidationService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.RulesPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.external.resource.RulesResource;
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.RuleSyntaxErrorMessage;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.Rules;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.RulesUploadRequest;
import com.iqser.red.service.redaction.v1.model.DroolsSyntaxValidation;
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_RULES;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.WRITE_RULES;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RestController
@ -42,7 +45,7 @@ public class RulesController implements RulesResource {
private static final String DOWNLOAD_FILE_NAME = "rules.drl";
private final RulesPersistenceService rulesPersistenceService;
private final RedactionClient redactionServiceClient;
private final RulesValidationService rulesValidationService;
private final AuditPersistenceService auditPersistenceService;
@ -50,7 +53,7 @@ public class RulesController implements RulesResource {
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
public ResponseEntity<?> upload(@RequestBody RulesUploadRequest rules) {
DroolsSyntaxValidation droolsSyntaxValidation = redactionServiceClient.testRules(rules.getRules());
DroolsSyntaxValidation droolsSyntaxValidation = rulesValidationService.validateRules(rules.getRuleFileType(), rules.getRules());
if (!droolsSyntaxValidation.isCompiled()) {
var rulesSyntaxErrorMessages = droolsSyntaxValidation.getDroolsSyntaxErrorMessages()
.stream()
@ -58,7 +61,7 @@ public class RulesController implements RulesResource {
.toList();
return new ResponseEntity<>(rulesSyntaxErrorMessages, HttpStatus.BAD_REQUEST);
}
rulesPersistenceService.setRules(rules.getRules(), rules.getDossierTemplateId());
rulesPersistenceService.setRules(rules.getRules(), rules.getDossierTemplateId(), rules.getRuleFileType());
auditPersistenceService.audit(AuditRequest.builder()
.userId(KeycloakSecurity.getUserId())
@ -75,7 +78,15 @@ public class RulesController implements RulesResource {
@PreAuthorize("hasAuthority('" + READ_RULES + "')")
public Rules download(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId) {
var ruleEntity = rulesPersistenceService.getRules(dossierTemplateId);
return download(dossierTemplateId, RuleFileType.ENTITY);
}
@Override
@PreAuthorize("hasAuthority('" + READ_RULES + "')")
public Rules download(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, @PathVariable(RULE_FILE_TYPE_PARAMETER_NAME) RuleFileType ruleFileType) {
var ruleEntity = rulesPersistenceService.getRules(dossierTemplateId, ruleFileType);
return new Rules(ruleEntity.getValue(), dossierTemplateId, ruleEntity.isTimeoutDetected());
}
@ -85,12 +96,21 @@ public class RulesController implements RulesResource {
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
public ResponseEntity<?> uploadFile(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, @RequestPart(name = "file") MultipartFile file) {
return uploadFile(dossierTemplateId, RuleFileType.ENTITY, file);
}
@Override
@PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
public ResponseEntity<?> uploadFile(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
@PathVariable(RULE_FILE_TYPE_PARAMETER_NAME) RuleFileType ruleFileType,
@RequestPart(name = "file") MultipartFile file) {
try {
return upload(new RulesUploadRequest(new String(file.getBytes(), StandardCharsets.UTF_8), dossierTemplateId));
return upload(new RulesUploadRequest(new String(file.getBytes(), StandardCharsets.UTF_8), dossierTemplateId, ruleFileType));
} catch (IOException e) {
throw new FileUploadException("Could not upload file.", e);
}
}
@ -98,15 +118,23 @@ public class RulesController implements RulesResource {
@PreAuthorize("hasAuthority('" + READ_RULES + "')")
public ResponseEntity<?> downloadFile(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId) {
return downloadFile(dossierTemplateId, RuleFileType.ENTITY);
}
@Override
@PreAuthorize("hasAuthority('" + READ_RULES + "')")
public ResponseEntity<?> downloadFile(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
@PathVariable(RULE_FILE_TYPE_PARAMETER_NAME) RuleFileType ruleFileType) {
byte[] data = download(dossierTemplateId).getRules().getBytes(StandardCharsets.UTF_8);
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.TEXT_PLAIN);
httpHeaders.add("Content-Disposition", "attachment; filename*=utf-8\"" + DOWNLOAD_FILE_NAME + "\"");
httpHeaders.add("Content-Disposition", "attachment; filename*=utf-8\"" + ruleFileType.name() + "_" + DOWNLOAD_FILE_NAME + "\"");
InputStream is = new ByteArrayInputStream(data);
return new ResponseEntity<>(new InputStreamResource(is), httpHeaders, HttpStatus.OK);
}
}

View File

@ -1,6 +1,9 @@
package com.iqser.red.persistence.service.v1.external.api.impl.controller;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.*;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_FILE_STATUS;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.SET_REVIEWER;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.SET_STATUS_APPROVED;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.SET_STATUS_UNDER_APPROVAL;
import java.time.OffsetDateTime;
import java.util.ArrayList;
@ -11,8 +14,6 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import jakarta.transaction.Transactional;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
@ -20,16 +21,16 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.iqser.red.service.persistence.management.v1.processor.roles.ApplicationRoles;
import com.iqser.red.service.persistence.management.v1.processor.acl.custom.dossier.DossierACLService;
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotAllowedException;
import com.iqser.red.service.persistence.management.v1.processor.roles.ApplicationRoles;
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
import com.iqser.red.service.persistence.management.v1.processor.service.DossierManagementService;
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusManagementService;
import com.iqser.red.service.persistence.management.v1.processor.service.users.UserService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.NotificationPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.users.UserService;
import com.iqser.red.service.persistence.service.v1.api.external.resource.StatusResource;
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileAttributes;
@ -43,6 +44,7 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp
import com.iqser.red.service.persistence.service.v1.api.shared.model.notification.NotificationType;
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -142,6 +144,7 @@ public class StatusController implements StatusResource {
}
@PreAuthorize("hasAuthority('" + READ_FILE_STATUS + "')")
public FileStatus getFileStatus(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
@ -257,6 +260,7 @@ public class StatusController implements StatusResource {
generatePossibleUnassignedFromFileNotification(dossierId, fileId, fileStatus, assigneeId);
}
@PreAuthorize("hasAuthority('" + SET_STATUS_UNDER_APPROVAL + "')")
public void setStatusUnderApproval(@PathVariable(DOSSIER_ID) String dossierId,
@PathVariable(FILE_ID) String fileId,
@ -286,6 +290,7 @@ public class StatusController implements StatusResource {
generatePossibleUnassignedFromFileNotification(dossierId, fileId, fileStatus, assigneeId);
}
@PreAuthorize("hasAuthority('" + SET_STATUS_APPROVED + "')")
public void setStatusApproved(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId) {
@ -391,6 +396,7 @@ public class StatusController implements StatusResource {
fileIds.forEach(fileId -> setStatusApproved(dossierId, fileId));
}
@PreAuthorize("hasAuthority('" + SET_REVIEWER + "')")
public void setStatusNewForList(@PathVariable(DOSSIER_ID) String dossierId, @RequestBody List<String> fileIds) {
@ -409,6 +415,7 @@ public class StatusController implements StatusResource {
}
@PreAuthorize("hasAuthority('" + READ_FILE_STATUS + "')")
public List<FileStatus> getSoftDeletedDossierStatus(@PathVariable(DOSSIER_ID) String dossierId) {
@ -468,6 +475,7 @@ public class StatusController implements StatusResource {
.uploader(status.getUploader())
.dictionaryVersion(status.getDictionaryVersion())
.rulesVersion(status.getRulesVersion())
.componentRulesVersion(status.getComponentRulesVersion())
.legalBasisVersion(status.getLegalBasisVersion())
.lastProcessed(status.getLastProcessed())
.lastLayoutProcessed(status.getLastLayoutProcessed())

View File

@ -11,10 +11,10 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.iqser.red.service.persistence.management.v1.processor.service.DictionaryManagementService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DictionaryPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.RulesPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.external.resource.VersionsResource;
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.VersionsResponse;
import lombok.RequiredArgsConstructor;
@ -33,7 +33,8 @@ public class VersionsController implements VersionsResource {
var result = new HashMap<String, VersionsResponse>();
dossierTemplateIds.forEach(rsId -> {
VersionsResponse response = new VersionsResponse(dictionaryPersistenceService.getVersion(rsId), rulesPersistenceService.getRules(rsId).getVersion());
VersionsResponse response = new VersionsResponse(dictionaryPersistenceService.getVersion(rsId),
rulesPersistenceService.getRules(rsId, RuleFileType.ENTITY).getVersion());
result.put(rsId, response);
});

View File

@ -0,0 +1,58 @@
package com.iqser.red.service.persistence.service.v1.api.external.resource;
import java.util.List;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.FilteredEntityLogRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
@ResponseStatus(value = HttpStatus.OK)
public interface AnalysisLogResource {
String ENTITY_LOG_PATH = ExternalApi.BASE_PATH + "/entityLog";
String COMPONENT_LOG_PATH = ExternalApi.BASE_PATH + "/componentLog";
String FILE_ID = "fileId";
String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID + "}";
String DOSSIER_ID = "dossierId";
String DOSSIER_ID_PATH_VARIABLE = "/{" + DOSSIER_ID + "}";
@GetMapping(value = ENTITY_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Gets the entity log for a fileId", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The redaction log is not found.")})
EntityLog getEntityLog(@PathVariable(DOSSIER_ID) String dossierId,
@PathVariable(FILE_ID) String fileId,
@RequestParam(value = "excludedType", required = false) List<String> excludedTypes,
@RequestParam(value = "withManualRedactions", required = false, defaultValue = "true") boolean withManualRedactions,
@RequestParam(value = "includeFalsePositives", required = false, defaultValue = "false") boolean includeFalsePositives);
@PostMapping(value = ENTITY_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE + "/filtered", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Gets the entity log for a fileId grater than the specified date", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The redaction log is not found.")})
EntityLog getFilteredEntityLog(@PathVariable(DOSSIER_ID) String dossierId,
@PathVariable(FILE_ID) String fileId,
@RequestBody FilteredEntityLogRequest filteredEntityLogRequest);
@GetMapping(value = COMPONENT_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Gets the component log for a fileId", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The redaction log is not found.")})
ComponentLog getComponentLog(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
}

View File

@ -0,0 +1,58 @@
package com.iqser.red.service.persistence.service.v1.api.external.resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseStatus;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
@ResponseStatus(value = HttpStatus.OK)
public interface DocumentResource {
String DOCUMENT_TEXT_PATH = ExternalApi.BASE_PATH + "/documentText";
String DOCUMENT_POSITIONS_PATH = ExternalApi.BASE_PATH + "/documentPositions";
String DOCUMENT_PAGES_PATH = ExternalApi.BASE_PATH + "/documentPages";
String DOCUMENT_STRUCTURE_PATH = ExternalApi.BASE_PATH + "/documentStructure";
String SIMPLIFIED_SECTION_TEXT_PATH = ExternalApi.BASE_PATH + "/simplifiedSectionText";
String FILE_ID = "fileId";
String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID + "}";
String DOSSIER_ID = "dossierId";
String DOSSIER_ID_PATH_VARIABLE = "/{" + DOSSIER_ID + "}";
@GetMapping(value = DOCUMENT_TEXT_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE)
@Operation(summary = "Gets the text blocks of a document for a fileId", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The document text is not found.")})
ResponseEntity<?> getDocumentText(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
@GetMapping(value = DOCUMENT_POSITIONS_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE)
@Operation(summary = "Gets the positions of the text blocks of a document for a fileId", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The document positions is not found.")})
ResponseEntity<?> getDocumentPositions(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
@GetMapping(value = DOCUMENT_STRUCTURE_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE)
@Operation(summary = "Gets the document structure for a fileId", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The document structure is not found.")})
ResponseEntity<?> getDocumentStructure(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
@GetMapping(value = DOCUMENT_PAGES_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE)
@Operation(summary = "Gets the page information of a document for a fileId", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The page information is not found.")})
ResponseEntity<?> getDocumentPages(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
@GetMapping(value = SIMPLIFIED_SECTION_TEXT_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE)
@Operation(summary = "Gets the simplified section text for a fileId", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The simplified section text is not found.")})
ResponseEntity<?> getSimplifiedSectionText(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
}

View File

@ -32,12 +32,14 @@ public interface RSSResource {
String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID + "}";
@Deprecated(forRemoval = true)
@GetMapping(value = RSS_PATH + DOSSIER_ID_PATH_VARIABLE, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
@Operation(summary = "Returns the RSS response for a dossier", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
RSSResponse getRSS(@PathVariable(DOSSIER_ID) String dossierId, @RequestParam(value = "fileId", required = false) String fileId);
@Deprecated(forRemoval = true)
@GetMapping(value = RSS_PATH + "/detailed" + DOSSIER_ID_PATH_VARIABLE, produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
@Operation(summary = "Returns the RSS response with more details for a dossier", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})

View File

@ -20,17 +20,13 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
@Deprecated(forRemoval = true)
@ResponseStatus(value = HttpStatus.OK)
public interface RedactionLogResource {
String REDACTION_LOG_PATH = ExternalApi.BASE_PATH + "/redactionLog";
String SECTION_GRID_PATH = ExternalApi.BASE_PATH + "/sectionGrid";
String SECTION_TEXT_PATH = ExternalApi.BASE_PATH + "/sectionText";
String DOCUMENT_TEXT_PATH = ExternalApi.BASE_PATH + "/documentText";
String DOCUMENT_POSITIONS_PATH = ExternalApi.BASE_PATH + "/documentPositions";
String DOCUMENT_PAGES_PATH = ExternalApi.BASE_PATH + "/documentPages";
String DOCUMENT_STRUCTURE_PATH = ExternalApi.BASE_PATH + "/documentStructure";
String SIMPLIFIED_SECTION_TEXT_PATH = ExternalApi.BASE_PATH + "/simplifiedSectionText";
String FILE_ID = "fileId";
String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID + "}";
@ -39,6 +35,7 @@ public interface RedactionLogResource {
String DOSSIER_ID_PATH_VARIABLE = "/{" + DOSSIER_ID + "}";
@Deprecated(forRemoval = true)
@GetMapping(value = REDACTION_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Gets the redaction log for a fileId", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The redaction log is not found.")})
@ -49,50 +46,21 @@ public interface RedactionLogResource {
@RequestParam(value = "includeFalsePositives", required = false, defaultValue = "false") boolean includeFalsePositives);
@Deprecated
@Deprecated(forRemoval = true)
@GetMapping(value = SECTION_GRID_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Gets the section grid for a fileId", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The section grid is not found.")})
SectionGrid getSectionGrid(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
@Deprecated
@Deprecated(forRemoval = true)
@GetMapping(value = SECTION_TEXT_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE)
@Operation(summary = "Gets the text blocks of a document for a fileId", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The section text is not found.")})
ResponseEntity<?> getSectionText(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
@GetMapping(value = DOCUMENT_TEXT_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE)
@Operation(summary = "Gets the text blocks of a document for a fileId", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The document text is not found.")})
ResponseEntity<?> getDocumentText(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
@GetMapping(value = DOCUMENT_POSITIONS_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE)
@Operation(summary = "Gets the positions of the text blocks of a document for a fileId", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The document positions is not found.")})
ResponseEntity<?> getDocumentPositions(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
@GetMapping(value = DOCUMENT_STRUCTURE_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE)
@Operation(summary = "Gets the document structure for a fileId", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The document structure is not found.")})
ResponseEntity<?> getDocumentStructure(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
@GetMapping(value = DOCUMENT_PAGES_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE)
@Operation(summary = "Gets the page information of a document for a fileId", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The page information is not found.")})
ResponseEntity<?> getDocumentPages(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
@GetMapping(value = SIMPLIFIED_SECTION_TEXT_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE)
@Operation(summary = "Gets the simplified section text for a fileId", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The simplified section text is not found.")})
ResponseEntity<?> getSimplifiedSectionText(@PathVariable(DOSSIER_ID) String dossierId, @PathVariable(FILE_ID) String fileId);
@Deprecated(forRemoval = true)
@PostMapping(value = REDACTION_LOG_PATH + DOSSIER_ID_PATH_VARIABLE + FILE_ID_PATH_VARIABLE + "/filtered", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "Gets the redaction log for a fileId grater than the specified date", description = "None")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The redaction log is not found.")})

View File

@ -1,16 +1,25 @@
package com.iqser.red.service.persistence.service.v1.api.external.resource;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.Rules;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.RulesUploadRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.multipart.MultipartFile;
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.Rules;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.RulesUploadRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
public interface RulesResource {
String RULES_PATH = ExternalApi.BASE_PATH + "/rules";
@ -20,6 +29,9 @@ public interface RulesResource {
String DOSSIER_TEMPLATE_PARAMETER_NAME = "dossierTemplateId";
String DOSSIER_TEMPLATE_PATH_VARIABLE = "/{dossierTemplateId}";
String RULE_FILE_TYPE_PARAMETER_NAME = "ruleFileType";
String RULE_FILE_TYPE_PATH_VARIABLE = "/{ruleFileType}";
/**
* Upload rules to be used by redaction service.
@ -41,6 +53,14 @@ public interface RulesResource {
Rules download(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId);
@ResponseBody
@ResponseStatus(value = HttpStatus.OK)
@Operation(summary = "Returns object containing the currently used Drools rules.")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
@GetMapping(value = RULES_PATH + DOSSIER_TEMPLATE_PATH_VARIABLE + RULE_FILE_TYPE_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
Rules download(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, @PathVariable(RULE_FILE_TYPE_PARAMETER_NAME) RuleFileType ruleFileType);
/**
* Upload rules as file to be used by redaction service.
*
@ -53,6 +73,15 @@ public interface RulesResource {
ResponseEntity<?> uploadFile(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, @RequestPart(name = "file") MultipartFile file);
@ResponseStatus(value = HttpStatus.NO_CONTENT)
@PostMapping(value = RULES_PATH + DOSSIER_TEMPLATE_PATH_VARIABLE + RULE_FILE_TYPE_PATH_VARIABLE + UPLOAD_PATH, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@Operation(summary = "Takes object containing string or rules as argument, which will be used by the redaction service.")
@ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Rules upload successful."), @ApiResponse(responseCode = "400", description = "Uploaded rules could not be verified.")})
ResponseEntity<?> uploadFile(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
@PathVariable(RULE_FILE_TYPE_PARAMETER_NAME) RuleFileType ruleFileType,
@RequestPart(name = "file") MultipartFile file);
@ResponseBody
@ResponseStatus(value = HttpStatus.OK)
@Operation(summary = "Returns file containing the currently used Drools rules.")
@ -60,4 +89,12 @@ public interface RulesResource {
@GetMapping(value = RULES_PATH + DOSSIER_TEMPLATE_PATH_VARIABLE + DOWNLOAD_PATH)
ResponseEntity<?> downloadFile(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId);
@ResponseBody
@ResponseStatus(value = HttpStatus.OK)
@Operation(summary = "Returns file containing the currently used Drools rules.")
@ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
@GetMapping(value = RULES_PATH + DOSSIER_TEMPLATE_PATH_VARIABLE + RULE_FILE_TYPE_PATH_VARIABLE + DOWNLOAD_PATH)
ResponseEntity<?> downloadFile(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, @PathVariable(RULE_FILE_TYPE_PARAMETER_NAME) RuleFileType ruleFileType);
}

View File

@ -1,13 +1,16 @@
package com.iqser.red.service.persistence.v1.internal.api.controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.exception.RulesTimeoutDetectedException;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.RulesPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.internal.resources.RulesResource;
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
@ -17,17 +20,17 @@ public class RulesInternalController implements RulesResource {
@Override
public JSONPrimitive<String> getRules(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId) {
public JSONPrimitive<String> getRules(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, RuleFileType ruleFileType) {
return new JSONPrimitive<>(rulesPersistenceService.getRules(dossierTemplateId).getValue());
return new JSONPrimitive<>(rulesPersistenceService.getRules(dossierTemplateId, ruleFileType).getValue());
}
@Override
public long getVersion(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId) {
public long getVersion(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, RuleFileType ruleFileType) {
try {
var rules = rulesPersistenceService.getRules(dossierTemplateId);
var rules = rulesPersistenceService.getRules(dossierTemplateId, ruleFileType);
if (rules.isTimeoutDetected()) {
throw new RulesTimeoutDetectedException(dossierTemplateId);
@ -41,9 +44,9 @@ public class RulesInternalController implements RulesResource {
@Override
public void setRulesTimeoutDetected(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId) {
public void setRulesTimeoutDetected(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, RuleFileType ruleFileType) {
rulesPersistenceService.setTimeoutDetected(dossierTemplateId);
rulesPersistenceService.setTimeoutDetected(dossierTemplateId, ruleFileType);
}
}

View File

@ -1,9 +1,15 @@
package com.iqser.red.service.persistence.service.v1.api.internal.resources;
import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive;
public interface RulesResource {
@ -19,14 +25,15 @@ public interface RulesResource {
@ResponseBody
@ResponseStatus(HttpStatus.OK)
@GetMapping(value = InternalApi.BASE_PATH + PATH + DOSSIER_TEMPLATE_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
JSONPrimitive<String> getRules(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId);
JSONPrimitive<String> getRules(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, RuleFileType ruleFileType);
@ResponseStatus(HttpStatus.OK)
@GetMapping(value = InternalApi.BASE_PATH + PATH + DOSSIER_TEMPLATE_PATH_VARIABLE + VERSION_PATH)
long getVersion(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId);
long getVersion(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, RuleFileType ruleFileType);
@PostMapping(value = InternalApi.BASE_PATH + PATH + DOSSIER_TEMPLATE_PATH_VARIABLE + TIMEOUT_PATH)
void setRulesTimeoutDetected(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId);
void setRulesTimeoutDetected(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, RuleFileType ruleFileType);
}

View File

@ -1,6 +1,11 @@
package com.iqser.red.service.persistence.management.v1.processor.entity.configuration;
import jakarta.persistence.*;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import jakarta.persistence.Lob;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@ -10,12 +15,17 @@ import lombok.NoArgsConstructor;
@AllArgsConstructor
@Entity
@Table(name = "rule_set")
@IdClass(RuleSetEntityKey.class)
public class RuleSetEntity {
@Id
@Column
private String dossierTemplateId;
@Id
@Column
private String ruleFileType;
@Column
private long version;

View File

@ -0,0 +1,23 @@
package com.iqser.red.service.persistence.management.v1.processor.entity.configuration;
import java.io.Serializable;
import jakarta.persistence.Column;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldDefaults;
@Data
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class RuleSetEntityKey implements Serializable {
@Column
String dossierTemplateId;
@Column
String ruleFileType;
}

View File

@ -6,6 +6,13 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import com.iqser.red.service.persistence.management.v1.processor.utils.JSONIntegerSetConverter;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.ProcessingStatus;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Convert;
@ -17,14 +24,6 @@ import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import com.iqser.red.service.persistence.management.v1.processor.utils.JSONIntegerSetConverter;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.ProcessingStatus;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -112,6 +111,9 @@ public class FileEntity {
@Column
private long rulesVersion;
@Column
private long componentRulesVersion;
@Column
private long dossierDictionaryVersion;

View File

@ -0,0 +1,21 @@
package com.iqser.red.service.persistence.management.v1.processor.service;
import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLog;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class ComponentLogService {
private final FileManagementStorageService fileManagementStorageService;
public ComponentLog getComponentLog(String dossierId, String fileId) {
return fileManagementStorageService.getComponentLog(dossierId, fileId);
}
}

View File

@ -6,8 +6,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import jakarta.transaction.Transactional;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
@ -29,15 +27,17 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.ReportTemplatePersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.RulesPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierTemplateRepository;
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.WatermarkModel;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.CloneDossierTemplateRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierTemplateStatus;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.CreateOrUpdateDossierStatusRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.legalbasis.LegalBasis;
import com.iqser.red.storage.commons.service.StorageService;
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;
import com.knecon.fforesight.tenantcommons.TenantContext;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
@ -127,7 +127,10 @@ public class DossierTemplateCloneService {
private void cloneRules(String dossierTemplateId, String clonedDossierTemplateId) {
rulesPersistenceService.setRules(rulesPersistenceService.getRules(dossierTemplateId).getValue(), clonedDossierTemplateId);
for (RuleFileType ruleFileType : RuleFileType.values()) {
rulesPersistenceService.setRules(rulesPersistenceService.getRules(dossierTemplateId, ruleFileType).getValue(), clonedDossierTemplateId, ruleFileType);
}
}
@ -218,6 +221,7 @@ public class DossierTemplateCloneService {
fileAttributeConfigPersistenceService.setFileAttributesConfig(clonedDossierTemplateId, facList);
}
@SneakyThrows
private void cloneReportTemplates(DossierTemplateEntity dossierTemplate, String clonedDossierTemplateId) {

View File

@ -55,6 +55,7 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierTemplateRepository;
import com.iqser.red.service.persistence.management.v1.processor.settings.FileManagementServiceSettings;
import com.iqser.red.service.persistence.management.v1.processor.utils.FileUtils;
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.WatermarkModel;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierAttributeConfig;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierTemplate;
@ -214,6 +215,9 @@ public class DossierTemplateImportService {
} else if (ze.getName().contains(ExportFilename.RULES.getFilename())) {
String rules = objectMapper.readValue(bytes, String.class);
importTemplateResult.setRuleSet(rules);
} else if (ze.getName().contains(ExportFilename.COMPONENT_RULES.getFilename())) {
String rules = objectMapper.readValue(bytes, String.class);
importTemplateResult.setComponentRuleSet(rules);
} else if (ze.getName().contains(ExportFilename.DOSSIER_TYPE.getFilename())) {
Type type = objectMapper.readValue(bytes, Type.class);
importTemplateResult.getTypes().add(type);
@ -300,7 +304,8 @@ public class DossierTemplateImportService {
dossierTemplateRepository.save(existingDossierTemplate);
// set rules
rulesPersistenceService.setRules(request.getRuleSet(), dossierTemplateId);
rulesPersistenceService.setRules(request.getRuleSet(), dossierTemplateId, RuleFileType.ENTITY);
rulesPersistenceService.setRules(request.getComponentRuleSet(), dossierTemplateId, RuleFileType.COMPONENT);
existingDossierTemplate.setDossierTemplateStatus(DossierTemplateStatus.valueOf(dossierTemplatePersistenceService.computeDossierTemplateStatus(existingDossierTemplate)
.name()));
@ -403,7 +408,9 @@ public class DossierTemplateImportService {
dossierTemplateEntity.setDateAdded(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));
dossierTemplateEntity.setCreatedBy(request.getUserId());
//set rules
rulesPersistenceService.setRules(request.getRuleSet(), dossierTemplateEntity.getId());
rulesPersistenceService.setRules(request.getRuleSet(), dossierTemplateEntity.getId(), RuleFileType.ENTITY);
rulesPersistenceService.setRules(request.getComponentRuleSet(), dossierTemplateEntity.getId(), RuleFileType.COMPONENT);
var loadedDossierTemplate = dossierTemplateRepository.save(dossierTemplateEntity);
loadedDossierTemplate.setDossierTemplateStatus(dossierTemplatePersistenceService.computeDossierTemplateStatus(loadedDossierTemplate));
dossierTemplateId = loadedDossierTemplate.getId();

View File

@ -0,0 +1,88 @@
package com.iqser.red.service.persistence.management.v1.processor.service;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLogEntry;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.FilteredEntityLogRequest;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class EntityLogService {
private final FileManagementStorageService fileManagementStorageService;
private final FileStatusService fileStatusService;
public EntityLog getEntityLog(String dossierId, String fileId) {
return getEntityLog(dossierId, fileId, Collections.emptyList());
}
public EntityLog getEntityLog(String dossierId, String fileId, List<String> excludedTypes) {
var fileStatus = fileStatusService.getStatus(fileId);
EntityLog redactionLog;
redactionLog = fileManagementStorageService.getEntityLog(dossierId, fileId);
if (fileStatus.isExcluded()) {
redactionLog.setEntityLogEntry(new ArrayList<>());
}
if (excludedTypes != null) {
redactionLog.getEntityLogEntry().removeIf(nextEntry -> excludedTypes.contains(nextEntry.getType()));
}
return redactionLog;
}
public EntityLog getFilteredEntityLog(String dossierId, String fileId, FilteredEntityLogRequest filteredEntityLogRequest) {
if (filteredEntityLogRequest.getSpecifiedDate() == null) {
filteredEntityLogRequest.setSpecifiedDate(OffsetDateTime.MIN);
}
var entityLog = getEntityLog(dossierId, fileId, filteredEntityLogRequest.getExcludedTypes());
var entityLogEntry = entityLog.getEntityLogEntry();
Iterator<EntityLogEntry> it = entityLogEntry.iterator();
while (it.hasNext()) {
var redactionLogEntry = it.next();
boolean isAfterSpecifiedDate = false;
for (var change : redactionLogEntry.getChanges()) {
if (change.getDateTime() != null && change.getDateTime().isAfter(filteredEntityLogRequest.getSpecifiedDate())) {
isAfterSpecifiedDate = true;
break;
}
}
for (var manualChange : redactionLogEntry.getManualChanges()) {
if (manualChange.getProcessedDate() != null && manualChange.getProcessedDate()
.isAfter(filteredEntityLogRequest.getSpecifiedDate()) || manualChange.getRequestedDate() != null && manualChange.getRequestedDate()
.isAfter(filteredEntityLogRequest.getSpecifiedDate())) {
isAfterSpecifiedDate = true;
break;
}
}
if (!isAfterSpecifiedDate) {
it.remove();
}
}
return entityLog;
}
}

View File

@ -12,6 +12,8 @@ import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.management.v1.processor.exception.InternalServerErrorException;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.utils.StorageIdUtils;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog.ComponentLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntityLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.RedactionLog;
import com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog.imported.ImportedRedactions;
@ -93,6 +95,19 @@ public class FileManagementStorageService {
}
public EntityLog getEntityLog(String dossierId, String fileId) {
try {
return storageService.readJSONObject(TenantContext.getTenantId(), StorageIdUtils.getStorageId(dossierId, fileId, FileType.ENTITY_LOG), EntityLog.class);
} catch (StorageObjectDoesNotExist e) {
log.debug("EntityLog does not exist");
throw new NotFoundException(String.format("EntityLog does not exist for Dossier ID \"%s\" and File ID \"%s\"!", dossierId, fileId));
} catch (StorageException e) {
throw new InternalServerErrorException(e.getMessage());
}
}
public void storeRedactionLog(String dossierId, String fileId, RedactionLog redactionLog) {
storageService.storeJSONObject(TenantContext.getTenantId(), StorageIdUtils.getStorageId(dossierId, fileId, FileType.REDACTION_LOG), redactionLog);
@ -132,6 +147,7 @@ public class FileManagementStorageService {
return storageService.objectExists(TenantContext.getTenantId(), StorageIdUtils.getStorageId(dossierId, fileId, origin));
}
public boolean objectExists(String storageId) {
return storageService.objectExists(TenantContext.getTenantId(), storageId);
@ -149,4 +165,17 @@ public class FileManagementStorageService {
storageService.deleteObject(TenantContext.getTenantId(), storageId);
}
public ComponentLog getComponentLog(String dossierId, String fileId) {
try {
return storageService.readJSONObject(TenantContext.getTenantId(), StorageIdUtils.getStorageId(dossierId, fileId, FileType.COMPONENT_LOG), ComponentLog.class);
} catch (StorageObjectDoesNotExist e) {
log.debug("ComponentLog does not exist");
throw new NotFoundException(String.format("ComponentLog does not exist for Dossier ID \"%s\" and File ID \"%s\"!", dossierId, fileId));
} catch (StorageException e) {
throw new InternalServerErrorException(e.getMessage());
}
}
}

View File

@ -1,5 +1,6 @@
package com.iqser.red.service.persistence.management.v1.processor.service;
import static com.iqser.red.service.persistence.management.v1.processor.service.ReanalysisRequiredStatusService.VersionType.COMPONENT_RULES;
import static com.iqser.red.service.persistence.management.v1.processor.service.ReanalysisRequiredStatusService.VersionType.DICTIONARY;
import static com.iqser.red.service.persistence.management.v1.processor.service.ReanalysisRequiredStatusService.VersionType.LEGAL_BASIS;
import static com.iqser.red.service.persistence.management.v1.processor.service.ReanalysisRequiredStatusService.VersionType.RULES;
@ -17,6 +18,7 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.LegalBasisMappingPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.RulesPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileModel;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.ProcessingStatus;
@ -119,18 +121,21 @@ public class ReanalysisRequiredStatusService {
// compute matches
var rulesVersionMatches = fileStatus.getRulesVersion() == dossierTemplateVersions.getOrDefault(RULES, -1L);
var componentRulesVersionMatches = fileStatus.getComponentRulesVersion() == dossierTemplateVersions.getOrDefault(COMPONENT_RULES, -1L);
var dictionaryVersionMatches = fileStatus.getDictionaryVersion() == dossierTemplateVersions.getOrDefault(DICTIONARY, -1L);
var legalBasisVersionMatches = fileStatus.getLegalBasisVersion() == dossierTemplateVersions.getOrDefault(LEGAL_BASIS, -1L);
var dossierDictionaryVersionMatches = Math.max(fileStatus.getDossierDictionaryVersion(), 0) == dossierDictionaryVersion;
var reanalysisRequired = !dictionaryVersionMatches || !dossierDictionaryVersionMatches;
var fullAnalysisRequired = !rulesVersionMatches || !legalBasisVersionMatches;
var fullAnalysisRequired = !rulesVersionMatches || !componentRulesVersionMatches || !legalBasisVersionMatches;
if (reanalysisRequired || fullAnalysisRequired) {
log.info(
"For file: {} analysis is required because -> ruleVersionMatches: {}/{}, dictionaryVersionMatches: {}/{}, legalBasisVersionMatches: {}/{}, dossierDictionaryVersionMatches: {}/{}",
"For file: {} analysis is required because -> ruleVersionMatches: {}/{}, componentRuleVersionMatches {}/{}, dictionaryVersionMatches: {}/{}, legalBasisVersionMatches: {}/{}, dossierDictionaryVersionMatches: {}/{}",
fileStatus.getFilename(),
fileStatus.getRulesVersion(),
dossierTemplateVersions.getOrDefault(RULES, -1L),
fileStatus.getComponentRulesVersion(),
dossierTemplateVersions.getOrDefault(COMPONENT_RULES, -1L),
fileStatus.getDictionaryVersion(),
dossierTemplateVersions.getOrDefault(DICTIONARY, -1L),
fileStatus.getLegalBasisVersion(),
@ -147,7 +152,8 @@ public class ReanalysisRequiredStatusService {
var versions = new HashMap<VersionType, Long>();
versions.put(RULES, rulesPersistenceService.getRules(dossierTemplateId).getVersion());
versions.put(RULES, rulesPersistenceService.getRules(dossierTemplateId, RuleFileType.ENTITY).getVersion());
versions.put(COMPONENT_RULES, rulesPersistenceService.getRules(dossierTemplateId, RuleFileType.COMPONENT).getVersion());
versions.put(DICTIONARY, dictionaryPersistenceService.getVersion(dossierTemplateId));
versions.put(LEGAL_BASIS, legalBasisMappingPersistenceService.getVersion(dossierTemplateId));
@ -175,6 +181,7 @@ public class ReanalysisRequiredStatusService {
public enum VersionType {
RULES,
COMPONENT_RULES,
DICTIONARY,
LEGAL_BASIS
}

View File

@ -0,0 +1,24 @@
package com.iqser.red.service.persistence.management.v1.processor.service;
import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.management.v1.processor.client.redactionservice.RedactionClient;
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
import com.iqser.red.service.redaction.v1.model.DroolsSyntaxValidation;
import com.iqser.red.service.redaction.v1.model.RuleValidationModel;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class RulesValidationService {
private final RedactionClient redactionServiceClient;
public DroolsSyntaxValidation validateRules(RuleFileType ruleFileType, String rules) {
return redactionServiceClient.testRules(new RuleValidationModel(ruleFileType.name(), rules));
}
}

View File

@ -9,8 +9,6 @@ import java.io.InputStream;
import java.util.List;
import java.util.stream.Collectors;
import jakarta.transaction.Transactional;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
@ -39,6 +37,7 @@ import com.iqser.red.service.persistence.management.v1.processor.service.persist
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.RulesPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.utils.FileSystemBackedArchiver;
import com.iqser.red.service.persistence.management.v1.processor.utils.StorageIdUtils;
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.WatermarkModel;
import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierAttributeConfig;
@ -55,6 +54,7 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.Type;
import com.iqser.red.service.persistence.service.v1.api.shared.model.download.DownloadStatusValue;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
@ -171,11 +171,17 @@ public class DossierTemplateExportService {
}
// add rule set
var ruleSet = rulesPersistenceService.getRules(dossierTemplateId);
var ruleSet = rulesPersistenceService.getRules(dossierTemplateId, RuleFileType.ENTITY);
fileSystemBackedArchiver.addEntries(new FileSystemBackedArchiver.ArchiveModel(null,
getFilename(ExportFilename.RULES, TXT_EXT),
objectMapper.writeValueAsBytes(ruleSet.getValue())));
// add component rule set
var componentRuleSet = rulesPersistenceService.getRules(dossierTemplateId, RuleFileType.COMPONENT);
fileSystemBackedArchiver.addEntries(new FileSystemBackedArchiver.ArchiveModel(null,
getFilename(ExportFilename.COMPONENT_RULES, TXT_EXT),
objectMapper.writeValueAsBytes(componentRuleSet.getValue())));
//N files with the related report templates
var reportTemplateList = reportTemplatePersistenceService.findByDossierTemplateId(dossierTemplate.getId());
fileSystemBackedArchiver.addEntries(new FileSystemBackedArchiver.ArchiveModel(null,

View File

@ -6,8 +6,6 @@ import java.util.List;
import java.util.Optional;
import java.util.UUID;
import jakarta.transaction.Transactional;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
@ -19,9 +17,11 @@ import com.iqser.red.service.persistence.management.v1.processor.exception.Confl
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierTemplateRepository;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.TypeRepository;
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.CreateOrUpdateDossierTemplateRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.DossierTemplateStatus;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
@Service
@ -68,7 +68,8 @@ public class DossierTemplatePersistenceService {
BeanUtils.copyProperties(createOrUpdateDossierRequest, dossierTemplate);
dossierTemplate.setDateAdded(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));
dossierTemplate.setCreatedBy(createOrUpdateDossierRequest.getRequestingUser());
rulesPersistenceService.setRules(RulesPersistenceService.DEFAULT_RULES, dossierTemplate.getId());
rulesPersistenceService.setRules(RulesPersistenceService.DEFAULT_RULES, dossierTemplate.getId(), RuleFileType.ENTITY);
rulesPersistenceService.setRules(RulesPersistenceService.DEFAULT_RULES, dossierTemplate.getId(), RuleFileType.COMPONENT);
var loadedDossierTemplate = dossierTemplateRepository.save(dossierTemplate);
loadedDossierTemplate.setDossierTemplateStatus(computeDossierTemplateStatus(loadedDossierTemplate));
@ -102,8 +103,9 @@ public class DossierTemplatePersistenceService {
return DossierTemplateStatus.INCOMPLETE;
}
var rules = rulesPersistenceService.getRules(dossierTemplate.getId());
if (rules == null) {
var rules = rulesPersistenceService.getRules(dossierTemplate.getId(), RuleFileType.ENTITY);
var componentRules = rulesPersistenceService.getRules(dossierTemplate.getId(), RuleFileType.COMPONENT);
if (rules == null || componentRules == null) {
return DossierTemplateStatus.INCOMPLETE;
}
@ -165,11 +167,10 @@ public class DossierTemplatePersistenceService {
}
@Transactional(Transactional.TxType.REQUIRES_NEW)
public void insertDossierTemplate(DossierTemplateEntity dossierTemplate){
public void insertDossierTemplate(DossierTemplateEntity dossierTemplate) {
dossierTemplateRepository.saveAndFlush(dossierTemplate);
}
}

View File

@ -1,57 +1,159 @@
package com.iqser.red.service.persistence.management.v1.processor.service.persistence;
import org.springframework.stereotype.Service;
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.RuleSetEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.RuleSetRepository;
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
@SuppressWarnings("PMD.TooManyStaticImports")
public class RulesPersistenceService {
public static final String DEFAULT_RULES = "" + "package drools\n" + "\n" + "import com.iqser.red.service.redaction.v1.server.redaction.model.Section\n" + "\n" + "global Section section\n" + "\n" + "// --------------------------------------- Your rules below this line--------------------------------------------------";
public static final String DEFAULT_RULES = """
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.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.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus;
global Document document
global EntityCreationService entityCreationService
global ManualChangesApplicationService manualChangesApplicationService
global Dictionary dictionary
//------------------------------------ queries ------------------------------------
query "getFileAttributes"
$fileAttribute: FileAttribute()
end
//------------------------------------ Local dictionary search rules ------------------------------------
// Rule unit: LocalDictionarySearch.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.getLocalEntriesWithMatchedRules().get(entity.getValue());
entity.addMatchedRules(matchedRules);
});
end
// --------------------------------------- Your rules below this line --------------------------------------------------
""";
private final RuleSetRepository ruleSetRepository;
public RuleSetEntity getRules(String dossierTemplateId) {
@Transactional
public RuleSetEntity getRules(String dossierTemplateId, RuleFileType ruleFileType) {
return ruleSetRepository.findById(dossierTemplateId).orElseGet(() -> {
RuleSetEntity ruleSet = new RuleSetEntity();
ruleSet.setDossierTemplateId(dossierTemplateId);
ruleSet.setValue(DEFAULT_RULES);
ruleSet.setVersion(1);
if (ruleFileType.equals(RuleFileType.ENTITY)) {
return ruleSetRepository.save(ruleSet);
});
return ruleSetRepository.findByDossierTemplateIdAndRuleFileType(dossierTemplateId, ruleFileType.name())
.orElseGet(() -> createAndGetDefaultRuleSet(dossierTemplateId, ruleFileType));
}
return ruleSetRepository.findByDossierTemplateIdAndRuleFileType(dossierTemplateId, ruleFileType.name())
.orElseThrow(() -> new NotFoundException(String.format("No rule file of type %s found for dossierTemplateId %s", ruleFileType, dossierTemplateId)));
}
private RuleSetEntity createAndGetDefaultRuleSet(String dossierTemplateId, RuleFileType ruleFileType) {
RuleSetEntity ruleSet = new RuleSetEntity();
ruleSet.setDossierTemplateId(dossierTemplateId);
ruleSet.setRuleFileType(ruleFileType.name());
ruleSet.setValue(DEFAULT_RULES);
ruleSet.setVersion(1);
ruleSet.setTimeoutDetected(false);
return ruleSetRepository.save(ruleSet);
}
@Transactional
public void setRules(String rules, String dossierTemplateId) {
public void setRules(String rules, String dossierTemplateId, RuleFileType ruleFileType) {
ruleSetRepository.findById(dossierTemplateId).ifPresentOrElse(r -> {
r.setValue(rules);
r.setVersion(r.getVersion() + 1);
r.setTimeoutDetected(false);
ruleSetRepository.findByDossierTemplateIdAndRuleFileType(dossierTemplateId, ruleFileType.name()).ifPresentOrElse(ruleSet -> {
ruleSet.setDossierTemplateId(dossierTemplateId);
ruleSet.setRuleFileType(ruleFileType.name());
ruleSet.setValue(rules);
ruleSet.setVersion(ruleSet.getVersion() + 1);
ruleSet.setTimeoutDetected(false);
}, () -> {
RuleSetEntity ruleSet = new RuleSetEntity();
ruleSet.setDossierTemplateId(dossierTemplateId);
ruleSet.setRuleFileType(ruleFileType.name());
ruleSet.setValue(rules);
ruleSet.setVersion(1);
ruleSet.setTimeoutDetected(false);
ruleSetRepository.save(ruleSet);
});
}
@Transactional
public void setTimeoutDetected(String dossierTemplateId) {
ruleSetRepository.updateTimeoutDetected(dossierTemplateId);
public void setTimeoutDetected(String dossierTemplateId, RuleFileType ruleFileType) {
ruleSetRepository.updateTimeoutDetected(dossierTemplateId, ruleFileType.name());
}
}

View File

@ -1,14 +1,21 @@
package com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository;
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.RuleSetEntity;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
public interface RuleSetRepository extends JpaRepository<RuleSetEntity, String> {
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.RuleSetEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.RuleSetEntityKey;
public interface RuleSetRepository extends JpaRepository<RuleSetEntity, RuleSetEntityKey> {
@Modifying
@Query("update RuleSetEntity r set r.timeoutDetected = true where r.dossierTemplateId = :dossierTemplatedId")
void updateTimeoutDetected(String dossierTemplatedId);
@Query("update RuleSetEntity r set r.timeoutDetected = true where r.dossierTemplateId = :dossierTemplateId and r.ruleFileType = :ruleFileType")
void updateTimeoutDetected(String dossierTemplateId, String ruleFileType);
Optional<RuleSetEntity> findByDossierTemplateIdAndRuleFileType(String dossierTemplateId, String ruleFileType);
}

View File

@ -12,7 +12,6 @@ import com.iqser.red.service.persistence.management.v1.processor.configuration.M
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusProcessingUpdateService;
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService;
import com.iqser.red.service.persistence.management.v1.processor.service.layoutparsing.LayoutParsingRequestIdentifierService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.AnalyzeRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileErrorInfo;
import com.knecon.fforesight.service.layoutparser.internal.api.queue.LayoutParsingFinishedEvent;
import com.knecon.fforesight.service.layoutparser.internal.api.queue.LayoutParsingQueueNames;
@ -43,7 +42,7 @@ public class LayoutParsingFinishedMessageReceiver {
fileStatusService.updateLayoutProcessedTime(layoutParsingRequestIdentifierService.parseFileId(response.identifier()));
log.info("Received message {} in {}", response, MessagingConfiguration.OCR_STATUS_UPDATE_RESPONSE_QUEUE);
log.info("Received message {} in {}", response, LayoutParsingQueueNames.LAYOUT_PARSING_FINISHED_EVENT_QUEUE);
}

View File

@ -158,4 +158,6 @@ databaseChangeLog:
- include:
file: db/changelog/tenant/108-added-dictionary-changes-to-manual-recategorization.yaml
- include:
file: db/changelog/tenant/109-add-rules-timeout-detected-column.yaml
file: db/changelog/tenant/109-add-rules-timeout-detected-column.yaml
- include:
file: db/changelog/tenant/110-add-rules-file-type.yaml

View File

@ -0,0 +1,34 @@
databaseChangeLog:
- changeSet:
id: add-rules-file-type
author: kilian
changes:
- addColumn:
columns:
- column:
name: rule_file_type
type: VARCHAR(255)
defaultValue: ENTITY
tableName: rule_set
- changeSet:
id: make-rules-file-type-primary-key
author: kilian
changes:
- dropPrimaryKey:
constraintName: rule_set_pkey
tableName: rule_set
- addPrimaryKey:
columnNames: dossier_template_id, rule_file_type
constraintName: PK_rule_set
tableName: rule_set
- changeSet:
id: add-component-rules-version
author: kilian
changes:
- addColumn:
columns:
- column:
name: component_rules_version
type: BIGINT
tableName: file

View File

@ -1,5 +1,14 @@
package com.iqser.red.service.peristence.v1.server.integration.service;
import static org.assertj.core.api.Assertions.assertThat;
import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.google.common.collect.Sets;
import com.iqser.red.service.peristence.v1.server.integration.client.DictionaryClient;
import com.iqser.red.service.peristence.v1.server.integration.client.DossierTemplateClient;
@ -10,14 +19,6 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemp
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.Colors;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.legalbasis.LegalBasis;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules.RulesUploadRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@Service
public class DossierTemplateTesterAndProvider {
@ -46,6 +47,7 @@ public class DossierTemplateTesterAndProvider {
return provideTestTemplate("Template 1", false);
}
public DossierTemplateModel provideTestTemplate(boolean ocrByDefault) {
return provideTestTemplate("Template 1", ocrByDefault);
@ -57,6 +59,7 @@ public class DossierTemplateTesterAndProvider {
return provideTestTemplate(name, false);
}
public DossierTemplateModel provideTestTemplate(String name, boolean ocrByDefault) {
var cru = new DossierTemplateModel();

View File

@ -277,7 +277,7 @@ public abstract class AbstractPersistenceServerServiceTest {
when(amqpAdmin.getQueueInfo(Mockito.any())).thenReturn(null);
when(redactionLogService.getRedactionLog(Mockito.any(), Mockito.any())).thenReturn(new RedactionLog(1, 1, Lists.newArrayList(), null, 0, 0, 0, 0));
when(redactionClient.testRules(Mockito.anyString())).thenReturn(DroolsSyntaxValidation.builder().compiled(true).droolsSyntaxErrorMessages(Collections.emptyList()).build());
when(redactionClient.testRules(Mockito.any())).thenReturn(DroolsSyntaxValidation.builder().compiled(true).droolsSyntaxErrorMessages(Collections.emptyList()).build());
}

View File

@ -21,7 +21,6 @@
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>

View File

@ -95,8 +95,10 @@ public class FileStatus {
private String uploader;
@Schema(description = "Shows which dictionary versions was used during the analysis.")
private long dictionaryVersion;
@Schema(description = "Shows which rules versions was used during the analysis.")
@Schema(description = "Shows which entity rules versions was used during the analysis.")
private long rulesVersion;
@Schema(description = "Shows which component rules versions was used during the analysis.")
private long componentRulesVersion;
@Schema(description = "Shows which legal basis versions was used during the analysis.")
private long legalBasisVersion;
@Schema(description = "Shows if the file was excluded from analysis.")

View File

@ -0,0 +1,6 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model;
public enum RuleFileType {
ENTITY,
COMPONENT
}

View File

@ -0,0 +1,22 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldDefaults;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class ComponentEntityReference {
String id;
String type;
int page;
String ruleIdentifier;
String reason;
}

View File

@ -0,0 +1,25 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog;
import java.util.ArrayList;
import java.util.List;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldDefaults;
@Data
@AllArgsConstructor
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class ComponentLog {
int analysisNumber;
List<ComponentLogCategory> componentLogCategories = new ArrayList<>();
long dictionaryVersion = -1;
long dossierDictionaryVersion = -1;
long rulesVersion = -1;
}

View File

@ -0,0 +1,20 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog;
import java.util.List;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldDefaults;
@Data
@AllArgsConstructor
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class ComponentLogCategory {
String category;
List<ComponentLogEntry> componentLogEntries;
}

View File

@ -0,0 +1,26 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.componentlog;
import java.util.List;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldDefaults;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class ComponentLogEntry {
String value;
List<String> originalValue;
String transformation;
String matchedRule;
List<ComponentEntityReference> componentEntityReferences;
}

View File

@ -0,0 +1,20 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog;
import java.time.OffsetDateTime;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Change {
private int analysisNumber;
private ChangeType type;
private OffsetDateTime dateTime;
}

View File

@ -0,0 +1,7 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog;
public enum ChangeType {
ADDED,
REMOVED,
CHANGED
}

View File

@ -0,0 +1,8 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog;
public enum Engine {
DICTIONARY,
NER,
RULE,
MANUAL
}

View File

@ -0,0 +1,34 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class EntityLog {
/**
* Version 0 Redaction Logs have manual redactions merged inside them
* Version 1 Redaction Logs only contain system ( rule/dictionary ) redactions. Manual Redactions are merged in at runtime.
*/
private long analysisVersion;
/**
* Which analysis created this redactionLog.
*/
private int analysisNumber;
private List<EntityLogEntry> entityLogEntry = new ArrayList<>();
private List<EntityLogLegalBasis> legalBasis = new ArrayList<>();
private long dictionaryVersion = -1;
private long dossierDictionaryVersion = -1;
private long rulesVersion = -1;
private long legalBasisVersion = -1;
}

View File

@ -0,0 +1,17 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class EntityLogChanges {
private EntityLog entityLog;
private boolean hasChanges;
}

View File

@ -0,0 +1,22 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog;
import java.time.OffsetDateTime;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EntityLogComment {
private long id;
private String user;
private String text;
private String annotationId;
private String fileId;
private OffsetDateTime date;
private OffsetDateTime softDeletedTime;
}

View File

@ -0,0 +1,72 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldDefaults;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@FieldDefaults(level = AccessLevel.PRIVATE)
public class EntityLogEntry {
String id;
String type;
EntryType entryType;
EntryState state;
String value;
String reason;
String matchedRule;
String legalBasis;
boolean imported;
String section;
float[] color;
@Builder.Default
List<Position> positions = new ArrayList<>();
int sectionNumber;
String textBefore;
String textAfter;
int startOffset;
int endOffset;
boolean imageHasTransparency;
boolean dictionaryEntry;
boolean dossierDictionaryEntry;
boolean excluded;
@EqualsAndHashCode.Exclude
@Builder.Default
List<Change> changes = new ArrayList<>();
@EqualsAndHashCode.Exclude
@Builder.Default
List<ManualChange> manualChanges = new ArrayList<>();
@Builder.Default
Set<Engine> engines = new HashSet<>();
@Builder.Default
Set<String> reference = new HashSet<>();
@Builder.Default
Set<String> importedRedactionIntersections = new HashSet<>();
}

View File

@ -0,0 +1,16 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EntityLogLegalBasis {
private String name;
private String description;
private String reason;
}

View File

@ -0,0 +1,8 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog;
public enum EntryState {
APPLIED,
SKIPPED,
IGNORED,
REMOVED
}

View File

@ -0,0 +1,11 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog;
public enum EntryType {
ENTITY,
HINT,
FALSE_POSITIVE,
RECOMMENDATION,
FALSE_RECOMMENDATION,
IMAGE,
AREA
}

View File

@ -0,0 +1,22 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog;
import java.time.OffsetDateTime;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class FilteredEntityLogRequest {
private List<String> excludedTypes;
private boolean withManualRedactions;
private boolean includeFalsePositives;
private OffsetDateTime specifiedDate;
}

View File

@ -0,0 +1,59 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog;
import java.time.OffsetDateTime;
import java.util.HashMap;
import java.util.Map;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationStatus;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.entitymapped.BaseAnnotation;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ManualChange {
private AnnotationStatus annotationStatus;
private ManualRedactionType manualRedactionType;
private OffsetDateTime processedDate;
private OffsetDateTime requestedDate;
private String userId;
private Map<String, String> propertyChanges = new HashMap<>();
public static ManualChange from(BaseAnnotation baseAnnotation) {
ManualChange manualChange = new ManualChange();
manualChange.annotationStatus = baseAnnotation.getStatus();
manualChange.processedDate = baseAnnotation.getProcessedDate();
manualChange.requestedDate = baseAnnotation.getRequestDate();
manualChange.userId = baseAnnotation.getUser();
return manualChange;
}
public boolean isProcessed() {
return processedDate != null;
}
public ManualChange withManualRedactionType(ManualRedactionType manualRedactionType) {
this.manualRedactionType = manualRedactionType;
return this;
}
public ManualChange withChange(String property, String value) {
this.propertyChanges.put(property, value);
return this;
}
}

View File

@ -0,0 +1,13 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog;
public enum ManualRedactionType {
ADD_LOCALLY,
ADD_TO_DICTIONARY,
REMOVE_LOCALLY,
REMOVE_FROM_DICTIONARY,
FORCE_REDACT,
FORCE_HINT,
RECATEGORIZE,
LEGAL_BASIS_CHANGE,
RESIZE
}

View File

@ -0,0 +1,64 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog;
import java.awt.geom.Rectangle2D;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldDefaults;
@Data
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class Position {
float[] rectangle; // x, y, w, h
int pageNumber;
public Position(float x, float y, float w, float h, int pageNumber) {
this.rectangle = new float[]{x, y, w, h};
this.pageNumber = pageNumber;
}
public Position(Rectangle2D rectangle2D, int pageNumber) {
this.rectangle = new float[]{(float) rectangle2D.getX(), (float) rectangle2D.getY(), (float) rectangle2D.getWidth(), (float) rectangle2D.getHeight()};
this.pageNumber = pageNumber;
}
public Rectangle2D toRectangle2D() {
return new Rectangle2D.Float(x(), y(), w(), h());
}
public float x() {
return rectangle[0];
}
public float y() {
return rectangle[1];
}
public float w() {
return rectangle[2];
}
public float h() {
return rectangle[3];
}
}

View File

@ -0,0 +1,24 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.imported;
import java.util.ArrayList;
import java.util.List;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.Position;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ImportedRedaction {
private String id;
@Builder.Default
private List<Position> positions = new ArrayList<>();
}

View File

@ -0,0 +1,21 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.imported;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ImportedRedactions {
@Builder.Default
private Map<Integer, List<ImportedRedaction>> importedRedactions = new HashMap<>();
}

View File

@ -42,6 +42,7 @@ public class ManualRedactions {
@Builder.Default
private Set<ManualResizeRedaction> resizeRedactions = new HashSet<>();
@Deprecated(forRemoval = true)
@Builder.Default
private Map<String, List<Comment>> comments = new HashMap<>();

View File

@ -47,6 +47,7 @@ public class FileModel {
private String uploader;
private long dictionaryVersion;
private long rulesVersion;
private long componentRulesVersion;
private long dossierDictionaryVersion;
private long legalBasisVersion;
private OffsetDateTime approvalDate;

View File

@ -22,7 +22,9 @@ public enum FileType {
DOCUMENT_TEXT(".json"),
DOCUMENT_STRUCTURE(".json"),
DOCUMENT_POSITION(".json"),
DOCUMENT_PAGES(".json");
DOCUMENT_PAGES(".json"),
ENTITY_LOG(".json"),
COMPONENT_LOG(".json");
@Getter
private final String extension;

View File

@ -13,6 +13,7 @@ public enum ExportFilename {
FILE_ATTRIBUTE_GENERAL_CONFIG("fileAttributeGeneralConfigList"),
LEGAL_BASIS("legalBasisMappingList"),
RULES("rules"),
COMPONENT_RULES("componentRules"),
REPORT_TEMPLATE("reportTemplateList"),
REPORT_TEMPLATE_MULTI_FILE(" (Multi-file)"),
DOSSIER_TYPE("dossierType"),

View File

@ -55,6 +55,8 @@ public class ImportTemplateResult {
public String ruleSet;
public String componentRuleSet;
@Builder.Default
public List<ReportTemplateUploadRequest> reportTemplateUploadRequests = new ArrayList<>();

View File

@ -1,5 +1,7 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.rules;
import com.iqser.red.service.persistence.service.v1.api.shared.model.RuleFileType;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
@ -11,9 +13,21 @@ import lombok.NoArgsConstructor;
@Schema(description = "Object containing a string of Drools rules.")
public class RulesUploadRequest {
public RulesUploadRequest(String rules, String dossierTemplateId) {
this.rules = rules;
this.dossierTemplateId = dossierTemplateId;
this.ruleFileType = RuleFileType.ENTITY;
}
@Schema(description = "The actual string of rules.")
private String rules;
@Schema(description = "The DossierTemplate Id for these rules")
private String dossierTemplateId;
@Schema(description = "The Rule file type of these rules", allowableValues = {"ENTITY", "COMPONENT"})
private RuleFileType ruleFileType;
}

View File

@ -8,6 +8,7 @@ import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Deprecated(forRemoval = true)
@Builder
@AllArgsConstructor
@NoArgsConstructor

View File

@ -1,5 +1,7 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog;
@Deprecated(forRemoval = true)
public enum ChangeType {
ADDED,
REMOVED,

View File

@ -1,5 +1,7 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog;
@Deprecated(forRemoval = true)
public enum Engine {
DICTIONARY,
NER,

View File

@ -9,6 +9,7 @@ import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Deprecated(forRemoval = true)
@Builder
@AllArgsConstructor
@NoArgsConstructor

View File

@ -14,6 +14,7 @@ import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@Deprecated(forRemoval = true)
@NoArgsConstructor
@Builder
public class ManualChange {

View File

@ -1,5 +1,7 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog;
@Deprecated(forRemoval = true)
public enum ManualRedactionType {
ADD_LOCALLY,
ADD_TO_DICTIONARY,

View File

@ -4,6 +4,7 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Deprecated(forRemoval = true)
@Data
@AllArgsConstructor
@NoArgsConstructor

View File

@ -1,11 +1,11 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Deprecated(forRemoval = true)
@AllArgsConstructor
@NoArgsConstructor
public class Rectangle {

View File

@ -3,11 +3,11 @@ package com.iqser.red.service.persistence.service.v1.api.shared.model.redactionl
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Deprecated(forRemoval = true)
@Data
@AllArgsConstructor
@NoArgsConstructor

View File

@ -1,6 +1,5 @@
package com.iqser.red.service.persistence.service.v1.api.shared.model.redactionlog;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -8,6 +7,7 @@ import lombok.NoArgsConstructor;
@Data
@Builder
@Deprecated(forRemoval = true)
@AllArgsConstructor
@NoArgsConstructor
public class RedactionLogChanges {

View File

@ -8,6 +8,7 @@ import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@Deprecated(forRemoval = true)
@AllArgsConstructor
public class RedactionLogComment {

View File

@ -17,6 +17,7 @@ import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@Deprecated(forRemoval = true)
@AllArgsConstructor
@EqualsAndHashCode
public class RedactionLogEntry {

View File

@ -5,6 +5,7 @@ import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Deprecated(forRemoval = true)
@NoArgsConstructor
@AllArgsConstructor
public class RedactionLogLegalBasis {

View File

@ -13,6 +13,7 @@ import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@Deprecated(forRemoval = true)
@AllArgsConstructor
public class ImportedRedaction {

View File

@ -4,7 +4,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -13,6 +12,7 @@ import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@Deprecated(forRemoval = true)
@AllArgsConstructor
public class ImportedRedactions {

View File

@ -8,6 +8,7 @@ import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@Deprecated(forRemoval = true)
@NoArgsConstructor
public class CellRectangle {

View File

@ -9,6 +9,7 @@ import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@Deprecated(forRemoval = true)
@AllArgsConstructor
public class SectionArea {

View File

@ -6,13 +6,13 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@Deprecated(forRemoval = true)
@NoArgsConstructor
public class SectionGrid {

View File

@ -10,6 +10,7 @@ import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@Deprecated(forRemoval = true)
@NoArgsConstructor
public class SectionRectangle {

View File

@ -10,6 +10,7 @@ import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Deprecated(forRemoval = true)
@Data
@Builder
@AllArgsConstructor

View File

@ -8,6 +8,7 @@ import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Deprecated(forRemoval = true)
@Data
@Builder
@AllArgsConstructor

View File

@ -29,7 +29,7 @@
</modules>
<properties>
<redaction-service.version>4.112.0</redaction-service.version>
<redaction-service.version>4.122.0</redaction-service.version>
<search-service.version>2.71.0</search-service.version>
<pdftron-redaction-service.version>4.29.0</pdftron-redaction-service.version>
<redaction-report-service.version>4.13.0</redaction-report-service.version>