Pull request #197: RED-3243

Merge in RED/persistence-service from RED-3243 to master

* commit 'd8d9b1c2a7b4ff6db0727e89931280b861ac7305':
  RED-3243: Fixed not working tests
  RED-3243 Added db and api for ImportedAnnotations (either finished nor working)
  RED-3243: Read redaction annotation from preview documents
This commit is contained in:
Dominique Eiflaender 2022-01-27 09:24:28 +01:00
commit 420e380d4a
14 changed files with 416 additions and 5 deletions

View File

@ -0,0 +1,25 @@
package com.iqser.red.service.persistence.service.v1.api.model.annotations;
import com.iqser.red.service.redaction.v1.model.Rectangle;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class AddImportedAnnotationRequest {
private String annotationId;
private List<Rectangle> positions = new ArrayList<>();
private ImportedAnnotationStatus status;
private String userId;
private String comment;
}

View File

@ -0,0 +1,26 @@
package com.iqser.red.service.persistence.service.v1.api.model.annotations;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ImportedAnnotation {
private String annotationId;
private String fileId;
private List<Rectangle> positions = new ArrayList<>();
private ImportedAnnotationStatus status;
private String user;
private String comment;
private OffsetDateTime processedDate;
}

View File

@ -0,0 +1,8 @@
package com.iqser.red.service.persistence.service.v1.api.model.annotations;
public enum ImportedAnnotationStatus {
NEW,
APPROVED,
DECLINED,
ADDED
}

View File

@ -0,0 +1,18 @@
package com.iqser.red.service.persistence.service.v1.api.model.annotations;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UpdateImportedAnnotationStatusRequest {
private ImportedAnnotationStatus status;
private String user;
private String comment;
}

View File

@ -0,0 +1,46 @@
package com.iqser.red.service.persistence.service.v1.api.resources;
import java.util.List;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.DeleteMapping;
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 com.iqser.red.service.persistence.service.v1.api.model.annotations.AddImportedAnnotationRequest;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.ImportedAnnotation;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.UpdateImportedAnnotationStatusRequest;
public interface ImportedAnnotationResource {
String IMPORTED_ANNOTATION_PATH = "/imported-annotation";
String FILE_ID_PARAM = "fileId";
String FILE_ID_PATH_PARAM = "/{" + FILE_ID_PARAM + "}";
String ANNOTATION_ID_PARAM = "fileId";
String ANNOTATION_ID_PATH_PARAM = "/{" + ANNOTATION_ID_PARAM + "}";
@GetMapping(value = IMPORTED_ANNOTATION_PATH + FILE_ID_PATH_PARAM, produces = MediaType.APPLICATION_JSON_VALUE)
List<ImportedAnnotation> getByFileId(@PathVariable(FILE_ID_PARAM) String fileId);
@DeleteMapping(value = IMPORTED_ANNOTATION_PATH + FILE_ID_PATH_PARAM + ANNOTATION_ID_PATH_PARAM)
void delete(@PathVariable(FILE_ID_PARAM) String fileId,
@PathVariable(ANNOTATION_ID_PATH_PARAM) String annotationId);
@PostMapping(value = IMPORTED_ANNOTATION_PATH + FILE_ID_PATH_PARAM)
void insert(@PathVariable(FILE_ID_PARAM) String fileId,
@RequestBody AddImportedAnnotationRequest annotation);
@PostMapping(value = IMPORTED_ANNOTATION_PATH + FILE_ID_PATH_PARAM + ANNOTATION_ID_PATH_PARAM)
void updateStatus(@PathVariable(FILE_ID_PARAM) String fileId,
@PathVariable(ANNOTATION_ID_PATH_PARAM) String annotationId,
@RequestBody UpdateImportedAnnotationStatusRequest UpdateImportedAnnotationRequest);
}

View File

@ -0,0 +1,54 @@
package com.iqser.red.service.persistence.management.v1.processor.entity.annotations;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.FileEntity;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.ImportedAnnotationStatus;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "imported_annotation")
public class ImportedAnnotationEntity {
@EmbeddedId
private AnnotationEntityId id;
@Column(name = "user_id")
private String user;
@Column
@Enumerated(EnumType.STRING)
private ImportedAnnotationStatus status;
@Column
private OffsetDateTime processedDate;
@ElementCollection
private List<RectangleEntity> positions = new ArrayList<>();
@ManyToOne
private FileEntity fileStatus;
@Column
private String comment;
}

View File

@ -0,0 +1,104 @@
package com.iqser.red.service.persistence.management.v1.processor.service.persistence;
import java.time.OffsetDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import javax.transaction.Transactional;
import org.springframework.stereotype.Service;
import com.iqser.red.service.pdftron.redaction.v1.api.model.Annotation;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.AnnotationEntityId;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ImportedAnnotationEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.RectangleEntity;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.ImportedAnnotationRepository;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.AddImportedAnnotationRequest;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.ImportedAnnotationStatus;
import com.iqser.red.service.redaction.v1.model.Rectangle;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class ImportedAnnotationPersistenceService {
private final ImportedAnnotationRepository importedAnnotationRepository;
@Transactional
public void insert(String fileId, AddImportedAnnotationRequest annotation) {
ImportedAnnotationEntity importedAnnotationEntity = new ImportedAnnotationEntity();
importedAnnotationEntity.setId(new AnnotationEntityId(annotation.getAnnotationId(), fileId));
importedAnnotationEntity.setStatus(annotation.getStatus() != null ? annotation.getStatus() : ImportedAnnotationStatus.NEW);
importedAnnotationEntity.setProcessedDate(OffsetDateTime.now().truncatedTo(ChronoUnit.MILLIS));
importedAnnotationEntity.setPositions(convert(annotation.getPositions()));
importedAnnotationEntity.setUser(annotation.getUserId());
importedAnnotationEntity.setComment(annotation.getComment());
importedAnnotationRepository.save(importedAnnotationEntity);
}
@Transactional
public void insert(String fileId, List<Annotation> annotations) {
annotations.forEach(annotation -> insert(fileId, annotation, ImportedAnnotationStatus.NEW, null, null));
}
@Transactional
public void insert(String fileId, Annotation annotation, ImportedAnnotationStatus status, String userId,
String comment) {
ImportedAnnotationEntity importedAnnotationEntity = new ImportedAnnotationEntity();
importedAnnotationEntity.setId(new AnnotationEntityId(annotation.getId(), fileId));
importedAnnotationEntity.setStatus(status);
importedAnnotationEntity.setProcessedDate(status == ImportedAnnotationStatus.ADDED ? OffsetDateTime.now()
.truncatedTo(ChronoUnit.MILLIS) : null);
importedAnnotationEntity.setUser(userId);
importedAnnotationEntity.setComment(comment);
importedAnnotationEntity.setPositions(convert(annotation.getPositions()));
importedAnnotationRepository.save(importedAnnotationEntity);
}
@Transactional
public void updateStatus(String fileId, String annotationId, ImportedAnnotationStatus annotationStatus,
String comment, String userId) {
importedAnnotationRepository.updateStatus(new AnnotationEntityId(annotationId, fileId), OffsetDateTime.now()
.truncatedTo(ChronoUnit.MILLIS), annotationStatus, comment, userId);
}
@Transactional
public void delete(String fileId, String annotationId) {
importedAnnotationRepository.deleteById(new AnnotationEntityId(annotationId, fileId));
}
public List<ImportedAnnotationEntity> findImportedAnnotations(String fileId) {
return importedAnnotationRepository.findByIdFileId(fileId);
}
private List<RectangleEntity> convert(List<Rectangle> positions) {
List<RectangleEntity> rectangleEntities = new ArrayList<>();
positions.forEach(p -> {
RectangleEntity re = new RectangleEntity();
re.setTopLeftX(p.getTopLeft().getX());
re.setTopLeftY(p.getTopLeft().getY());
re.setWidth(p.getWidth());
re.setHeight(p.getHeight());
re.setPage(p.getPage());
rectangleEntities.add(re);
});
return rectangleEntities;
}
}

View File

@ -0,0 +1,24 @@
package com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository;
import java.time.OffsetDateTime;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.AnnotationEntityId;
import com.iqser.red.service.persistence.management.v1.processor.entity.annotations.ImportedAnnotationEntity;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.ImportedAnnotationStatus;
public interface ImportedAnnotationRepository extends JpaRepository<ImportedAnnotationEntity, AnnotationEntityId> {
List<ImportedAnnotationEntity> findByIdFileId(String fileId);
@Modifying
@Query("update ImportedAnnotationEntity m set m.processedDate = :processedDate, m.status = :annotationStatus, m.comment = :comment, m.user = :userId where m.id = :id")
void updateStatus(AnnotationEntityId id, OffsetDateTime processedDate, ImportedAnnotationStatus annotationStatus,
String comment, String userId);
}

View File

@ -0,0 +1,57 @@
package com.iqser.red.service.peristence.v1.server.controller;
import static com.iqser.red.service.persistence.management.v1.processor.utils.MagicConverter.convert;
import java.util.List;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.ImportedAnnotationPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.AddImportedAnnotationRequest;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.ImportedAnnotation;
import com.iqser.red.service.persistence.service.v1.api.model.annotations.UpdateImportedAnnotationStatusRequest;
import com.iqser.red.service.persistence.service.v1.api.resources.ImportedAnnotationResource;
import lombok.RequiredArgsConstructor;
@RestController
@RequiredArgsConstructor
public class ImportedAnnotationController implements ImportedAnnotationResource {
private final ImportedAnnotationPersistenceService importedAnnotationPersistenceService;
@Override
public List<ImportedAnnotation> getByFileId(@PathVariable(FILE_ID_PARAM) String fileId) {
return convert(importedAnnotationPersistenceService.findImportedAnnotations(fileId), ImportedAnnotation.class);
}
@Override
public void insert(@PathVariable(FILE_ID_PARAM) String fileId,
@RequestBody AddImportedAnnotationRequest annotation) {
importedAnnotationPersistenceService.insert(fileId, annotation);
}
@Override
public void updateStatus(@PathVariable(FILE_ID_PARAM) String fileId,
@PathVariable(ANNOTATION_ID_PATH_PARAM) String annotationId,
@RequestBody UpdateImportedAnnotationStatusRequest updateImportedAnnotationStatusRequest) {
importedAnnotationPersistenceService.updateStatus(fileId, annotationId, updateImportedAnnotationStatusRequest.getStatus(), updateImportedAnnotationStatusRequest.getComment(), updateImportedAnnotationStatusRequest.getUser());
}
@Override
public void delete(@PathVariable(FILE_ID_PARAM) String fileId,
@PathVariable(ANNOTATION_ID_PATH_PARAM) String annotationId) {
importedAnnotationPersistenceService.delete(fileId, annotationId);
}
}

View File

@ -2,6 +2,8 @@ package com.iqser.red.service.peristence.v1.server.service;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
import com.iqser.red.service.pdftron.redaction.v1.api.model.AnnotationExtractionResponse;
import com.iqser.red.service.pdftron.redaction.v1.api.model.DocumentRequest;
import com.iqser.red.service.pdftron.redaction.v1.api.model.PdfTronOptimizeRequest;
import com.iqser.red.service.pdftron.redaction.v1.api.model.PdfTronOptimizeResponse;
import com.iqser.red.service.persistence.management.v1.processor.client.PDFTronRedactionClient;
@ -47,6 +49,7 @@ public class FileService {
private final LegalBasisChangePersistenceService legalBasisChangePersistenceService;
private final ResizeRedactionPersistenceService resizeRedactionPersistenceService;
private final IndexingService indexingService;
private final ImportedAnnotationPersistenceService importedAnnotationPersistenceService;
public JSONPrimitive<String> upload(BinaryFileRequest request) {
@ -68,7 +71,9 @@ public class FileService {
}
try {
PdfTronOptimizeResponse optimized = pdfTronRedactionClient.optimize(new PdfTronOptimizeRequest(request.getData()));
AnnotationExtractionResponse optimized = pdfTronRedactionClient.optimizeGetAndRemoveAnnotations(new DocumentRequest(request.getData()));
importedAnnotationPersistenceService.insert(fileId, optimized.getAnnotations());
if (optimized.getNumberOfPages() == 0) {
throw new BadRequestException("Empty document");
}

View File

@ -0,0 +1,40 @@
databaseChangeLog:
- changeSet:
id: imported-annotation
author: philipp
changes:
- createTable:
columns:
- column:
constraints:
nullable: false
primaryKey: true
primaryKeyName: imported_annotation_pkey
name: annotation_id
type: VARCHAR(255)
- column:
constraints:
nullable: false
primaryKey: true
primaryKeyName: imported_annotation_pkey
name: file_id
type: VARCHAR(255)
- column:
name: user_id
type: VARCHAR(255)
- column:
name: status
type: VARCHAR(255)
- column:
name: processed_date
type: TIMESTAMP WITHOUT TIME ZONE
- column:
name: TODO-positions
type: TIMESTAMP WITHOUT TIME ZONE
- column:
name: TODO-file_status_id
type: VARCHAR(255)
- column:
name: comment
type: VARCHAR(255)
tableName: imported_annotation

View File

@ -7,3 +7,5 @@ databaseChangeLog:
file: db/changelog/3-added-annotation-modification-date.changelog.yaml
- include:
file: db/changelog/4-archived-dossier.changelog.yaml
- include:
file: db/changelog/5-imported-annotation.changelog.yaml

View File

@ -36,6 +36,7 @@ import org.springframework.test.context.junit4.SpringRunner;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;
import java.util.List;
import java.util.TimeZone;
@RunWith(SpringRunner.class)
@ -114,10 +115,11 @@ public abstract class AbstractPersistenceServerServiceTest {
doNothing().when(pdfTronRedactionClient).testDigitalCurrentSignature(Mockito.any());
when(amqpAdmin.getQueueInfo(Mockito.any())).thenReturn(null);
when(pdfTronRedactionClient.optimize(Mockito.any())).thenAnswer((args) -> {
PdfTronOptimizeRequest request = (PdfTronOptimizeRequest) args.getArguments()[0];
when(pdfTronRedactionClient.optimizeGetAndRemoveAnnotations(Mockito.any())).thenAnswer((args) -> {
DocumentRequest request = (DocumentRequest) args.getArguments()[0];
int numberOfPages = (request.getDocument().length == 0? 0: 10);
return new PdfTronOptimizeResponse(request.getDocument(), numberOfPages);
return new AnnotationExtractionResponse(request.getDocument(), numberOfPages, List.of());
});
when(pdfTronRedactionClient.redact(Mockito.any())).thenAnswer((args) ->
new PdfTronRedactionResult(((PdfTronRedactionRequest) args.getArguments()[0]).getDocument()));

View File

@ -27,7 +27,7 @@
<properties>
<redaction-service.version>3.56.0</redaction-service.version>
<search-service.version>2.18.0</search-service.version>
<pdftron-redaction-service.version>3.17.0</pdftron-redaction-service.version>
<pdftron-redaction-service.version>3.28.0</pdftron-redaction-service.version>
<redaction-report-service.version>3.19.0</redaction-report-service.version>
</properties>