diff --git a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/FileManagementController.java b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/FileManagementController.java index cb082957e..a678cd9cc 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/FileManagementController.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v1/src/main/java/com/iqser/red/persistence/service/v1/external/api/impl/controller/FileManagementController.java @@ -81,12 +81,12 @@ public class FileManagementController implements FileManagementResource { accessControlService.checkAccessPermissionsToDossier(dossierId); fileService.deleteFile(dossierId, fileId); auditPersistenceService.audit(AuditRequest.builder() - .userId(KeycloakSecurity.getUserId()) - .objectId(dossierId) - .category(AuditCategory.DOSSIER.name()) - .message("File has been deleted.") - .details(Map.of("fileId", fileId)) - .build()); + .userId(KeycloakSecurity.getUserId()) + .objectId(dossierId) + .category(AuditCategory.DOSSIER.name()) + .message("File has been deleted.") + .details(Map.of("fileId", fileId)) + .build()); } @@ -101,12 +101,12 @@ public class FileManagementController implements FileManagementResource { try { fileService.deleteFile(dossierId, fileId); auditPersistenceService.audit(AuditRequest.builder() - .userId(KeycloakSecurity.getUserId()) - .objectId(dossierId) - .category(AuditCategory.DOSSIER.name()) - .message("Files have been deleted.") - .details(Map.of("Size", fileIds.size())) - .build()); + .userId(KeycloakSecurity.getUserId()) + .objectId(dossierId) + .category(AuditCategory.DOSSIER.name()) + .message("Files have been deleted.") + .details(Map.of("Size", fileIds.size())) + .build()); } catch (Exception e) { errorIds.add(fileId); } @@ -179,6 +179,7 @@ public class FileManagementController implements FileManagementResource { @Override @PreAuthorize("hasAuthority('" + DELETE_FILE + "')") + @Deprecated(forRemoval = true) public void hardDeleteFiles(@PathVariable(DOSSIER_ID) String dossierId, @RequestParam(FILE_IDS) Set fileIds) { accessControlService.checkDossierExistenceAndAccessPermissionsToDossier(dossierId); @@ -187,14 +188,36 @@ public class FileManagementController implements FileManagementResource { accessControlService.verifyUserIsReviewerOrApprover(dossierId, fileId); } } + fileService.hardDeleteFiles(dossierId, new ArrayList<>(fileIds)); + auditPersistenceService.audit(AuditRequest.builder() + .userId(KeycloakSecurity.getUserId()) + .objectId(dossierId) + .category(AuditCategory.DOSSIER.name()) + .message("Files has been hard deleted.") + .details(Map.of("FileIds", fileIds)) + .build()); + } + + + @Override + @PreAuthorize("hasAuthority('" + DELETE_FILE + "')") + public void hardDeleteFiles(String dossierId, @RequestBody List fileIds) { + + accessControlService.checkDossierExistenceAndAccessPermissionsToDossier(dossierId); + fileIds.forEach(fileId -> { + if (fileStatusManagementService.getFileStatus(fileId).getAssignee() != null) { + accessControlService.verifyUserIsReviewerOrApprover(dossierId, fileId); + } + }); + fileService.hardDeleteFiles(dossierId, fileIds); auditPersistenceService.audit(AuditRequest.builder() - .userId(KeycloakSecurity.getUserId()) - .objectId(dossierId) - .category(AuditCategory.DOSSIER.name()) - .message("Files has been hard deleted.") - .details(Map.of("FileIds", fileIds)) - .build()); + .userId(KeycloakSecurity.getUserId()) + .objectId(dossierId) + .category(AuditCategory.DOSSIER.name()) + .message("Files have been hard deleted.") + .details(Map.of("FileIds", fileIds)) + .build()); } @@ -206,12 +229,12 @@ public class FileManagementController implements FileManagementResource { verifyUserIsDossierOwnerOrApproverOrAssignedReviewer(dossierId, fileIds); fileService.undeleteFiles(dossierId, fileIds); auditPersistenceService.audit(AuditRequest.builder() - .userId(KeycloakSecurity.getUserId()) - .objectId(dossierId) - .category(AuditCategory.DOSSIER.name()) - .message("Files has been restored.") - .details(Map.of("FileIds", fileIds)) - .build()); + .userId(KeycloakSecurity.getUserId()) + .objectId(dossierId) + .category(AuditCategory.DOSSIER.name()) + .message("Files has been restored.") + .details(Map.of("FileIds", fileIds)) + .build()); } @@ -225,10 +248,10 @@ public class FileManagementController implements FileManagementResource { try { pdfTronClient.rotate(com.iqser.red.service.pdftron.redaction.v1.api.model.RotatePagesRequest.builder() - .dossierId(dossierId) - .fileId(fileId) - .pages(rotatePagesRequest.getPages()) - .build()); + .dossierId(dossierId) + .fileId(fileId) + .pages(rotatePagesRequest.getPages()) + .build()); fileStatusManagementService.updateFileModificationDate(fileId); @@ -243,12 +266,12 @@ public class FileManagementController implements FileManagementResource { } auditPersistenceService.audit(AuditRequest.builder() - .userId(KeycloakSecurity.getUserId()) - .objectId(dossierId) - .category(AuditCategory.DOCUMENT.name()) - .message("Pages have been rotated.") - .details(Map.of("Pages", rotatePagesRequest.getPages().keySet())) - .build()); + .userId(KeycloakSecurity.getUserId()) + .objectId(dossierId) + .category(AuditCategory.DOCUMENT.name()) + .message("Pages have been rotated.") + .details(Map.of("Pages", rotatePagesRequest.getPages().keySet())) + .build()); } catch (FeignException e) { throw processFeignException(e); diff --git a/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/FileControllerV2.java b/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/FileControllerV2.java index 43621419a..97c3ec5c8 100644 --- a/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/FileControllerV2.java +++ b/persistence-service-v1/persistence-service-external-api-impl-v2/src/main/java/com/iqser/red/persistence/service/v2/external/api/impl/controller/FileControllerV2.java @@ -108,7 +108,7 @@ public class FileControllerV2 implements FileResource { dossierTemplateController.getDossierTemplate(dossierTemplateId); if (deletePermanently) { - fileManagementController.hardDeleteFiles(dossierId, Set.of(fileId)); + fileManagementController.hardDeleteFiles(dossierId, List.of(fileId)); } else { fileManagementController.deleteFile(dossierId, fileId); } @@ -124,7 +124,7 @@ public class FileControllerV2 implements FileResource { dossierTemplateController.getDossierTemplate(dossierTemplateId); if (deletePermanently) { - fileManagementController.hardDeleteFiles(dossierId, new HashSet<>(fileDeleteRequest.getFileIds())); + fileManagementController.hardDeleteFiles(dossierId, new ArrayList<>(fileDeleteRequest.getFileIds())); } else { fileManagementController.deleteFiles(dossierId, fileDeleteRequest.getFileIds()); } diff --git a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/FileManagementResource.java b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/FileManagementResource.java index be338d82a..3073a7ccb 100644 --- a/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/FileManagementResource.java +++ b/persistence-service-v1/persistence-service-external-api-v1/src/main/java/com/iqser/red/service/persistence/service/v1/api/external/resource/FileManagementResource.java @@ -74,6 +74,7 @@ public interface FileManagementResource { @RequestParam(value = "inline", required = false, defaultValue = FALSE) boolean inline); + @Deprecated(forRemoval = true) @ResponseStatus(value = HttpStatus.NO_CONTENT) @DeleteMapping(value = HARD_DELETE_PATH + DOSSIER_ID_PATH_VARIABLE) @Operation(summary = "Hard deletes an uploaded file.", description = "None") @@ -81,6 +82,13 @@ public interface FileManagementResource { void hardDeleteFiles(@PathVariable(DOSSIER_ID) String dossierId, @RequestParam(FILE_IDS) Set fileIds); + @ResponseStatus(value = HttpStatus.NO_CONTENT) + @PostMapping(value = HARD_DELETE_PATH + DOSSIER_ID_PATH_VARIABLE) + @Operation(summary = "Hard deletes a list of files", description = "None") + @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Successfully hard deleted the files."), @ApiResponse(responseCode = "404", description = "Not found")}) + void hardDeleteFiles(@PathVariable(DOSSIER_ID) String dossierId, @RequestBody List files); + + @ResponseBody @ResponseStatus(value = HttpStatus.CREATED) @PostMapping(value = UNDELETE_PATH + DOSSIER_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE) diff --git a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileService.java b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileService.java index 5930f9d33..bf5537fec 100644 --- a/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileService.java +++ b/persistence-service-v1/persistence-service-processor-v1/src/main/java/com/iqser/red/service/persistence/management/v1/processor/service/FileService.java @@ -5,6 +5,7 @@ import static com.iqser.red.service.persistence.management.v1.processor.exceptio import java.time.OffsetDateTime; import java.time.temporal.ChronoUnit; import java.util.Arrays; +import java.util.List; import java.util.Set; import org.springframework.stereotype.Service; @@ -153,18 +154,17 @@ public class FileService { } - public void hardDeleteFiles(String dossierId, Set fileIds) { + public void hardDeleteFiles(String dossierId, List fileIds) { var dossier = dossierService.getDossierById(dossierId); if (dossier.getSoftDeletedTime() != null) { throw new DossierNotFoundException(String.format(DOSSIER_NOT_FOUND_MESSAGE, dossierId)); } - for (String fileId : fileIds) { + fileIds.forEach(fileId -> { hardDeleteFile(dossierId, fileId); fileStatusService.setFileStatusHardDeleted(fileId); - } - + }); } diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateStatsTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateStatsTest.java index f5d492f4e..04c1a6ace 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateStatsTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/DossierTemplateStatsTest.java @@ -294,7 +294,7 @@ public class DossierTemplateStatsTest extends AbstractPersistenceServerServiceTe fileManagementClient.deleteFile(dossier.getId(), fileId); } if (k == 3) { - fileManagementClient.hardDeleteFiles(dossier.getId(), Set.of(fileId)); + fileManagementClient.hardDeleteFiles(dossier.getId(), List.of(fileId)); } if (k == 4) { fileClient.setStatusUnderReview(dossier.getId(), fileId, userId); diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileAttributeTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileAttributeTest.java index ac7d88cbf..39f41d4af 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileAttributeTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileAttributeTest.java @@ -213,7 +213,7 @@ public class FileAttributeTest extends AbstractPersistenceServerServiceTest { // Delete file fileManagementClient.deleteFile(dossier.getId(), file.getId()); - fileManagementClient.hardDeleteFiles(dossier.getId(), Sets.newHashSet(file.getId())); + fileManagementClient.hardDeleteFiles(dossier.getId(), List.of(file.getId())); var deletedFile = fileClient.getFileStatus(dossier.getId(), file.getId()); assertThat(deletedFile.getFileAttributes().getAttributeIdToValue()).isEmpty(); diff --git a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java index 131075f21..e59615b6f 100644 --- a/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java +++ b/persistence-service-v1/persistence-service-server-v1/src/test/java/com/iqser/red/service/peristence/v1/server/integration/tests/FileTest.java @@ -138,7 +138,8 @@ public class FileTest extends AbstractPersistenceServerServiceTest { var nrOfFiles = fileClient.getSoftDeletedDossierStatus(dossier.getId()).size(); assertThat(nrOfFiles).isEqualTo(1); - loadedFile = fileClient.getSoftDeletedDossierStatus(dossier.getId()).get(0); + loadedFile = fileClient.getSoftDeletedDossierStatus(dossier.getId()) + .get(0); var fileUploaded = fileTesterAndProvider.testAndProvideFile(dossier); loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId()); @@ -163,15 +164,21 @@ public class FileTest extends AbstractPersistenceServerServiceTest { reanalysisClient.toggleAutomaticAnalysis(dossier.getId(), file.getId(), true); List configs = new ArrayList<>(); - configs.add(FileAttributeConfig.builder().csvColumnHeader("Name").primaryAttribute(true).label("Name").build()); - configs.add(FileAttributeConfig.builder().csvColumnHeader("Attribute A").primaryAttribute(true).label("Attribute A").build()); + configs.add(FileAttributeConfig.builder().csvColumnHeader("Name").primaryAttribute(true).label("Name") + .build()); + configs.add(FileAttributeConfig.builder().csvColumnHeader("Attribute A").primaryAttribute(true).label("Attribute A") + .build()); var loadedConfig = fileAttributeConfigClient.setFileAttributesConfig(dossier.getDossierTemplateId(), new FileAttributesConfig(configs)); - fileAttributeClient.setFileAttributes(dossier.getId(), file.getId(), new FileAttributes(Map.of(loadedConfig.getFileAttributeConfigs().get(0).getId(), "123"))); + fileAttributeClient.setFileAttributes(dossier.getId(), + file.getId(), + new FileAttributes(Map.of(loadedConfig.getFileAttributeConfigs() + .get(0).getId(), "123"))); loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId()); assertThat(loadedFile.isExcludedFromAutomaticAnalysis()).isTrue(); assertThat(loadedFile.getFileAttributes().getAttributeIdToValue()).size().isEqualTo(1); - assertThat(loadedFile.getFileAttributes().getAttributeIdToValue()).isEqualTo(Map.of(loadedConfig.getFileAttributeConfigs().get(0).getId(), "123")); + assertThat(loadedFile.getFileAttributes().getAttributeIdToValue()).isEqualTo(Map.of(loadedConfig.getFileAttributeConfigs() + .get(0).getId(), "123")); viewedPagesClient.addPage(file.getDossierId(), file.getFileId(), new ViewedPagesRequest(1)); var viewedPages = viewedPagesClient.getViewedPages(file.getDossierId(), file.getFileId()); @@ -181,7 +188,9 @@ public class FileTest extends AbstractPersistenceServerServiceTest { var fileUpload = new MockMultipartFile("test.pdf", "test.pdf", "application/pdf", "content".getBytes()); var uploadResult = uploadClient.upload(fileUpload, dossier.getId(), false); - loadedFile = fileClient.getFileStatus(dossier.getId(), uploadResult.getFileIds().iterator().next()); + loadedFile = fileClient.getFileStatus(dossier.getId(), + uploadResult.getFileIds() + .iterator().next()); assertThat(loadedFile.isExcludedFromAutomaticAnalysis()).isFalse(); assertThat(loadedFile.getFileAttributes().getAttributeIdToValue()).size().isEqualTo(0); @@ -220,7 +229,9 @@ public class FileTest extends AbstractPersistenceServerServiceTest { var fileUpload = new MockMultipartFile(file.getFilename(), file.getFilename(), "application/pdf", "content".getBytes()); var uploadResult = uploadClient.upload(fileUpload, dossier.getId(), false); - loadedFile = fileClient.getFileStatus(dossier.getId(), uploadResult.getFileIds().iterator().next()); + loadedFile = fileClient.getFileStatus(dossier.getId(), + uploadResult.getFileIds() + .iterator().next()); assertThat(loadedFile.isExcludedFromAutomaticAnalysis()).isFalse(); } @@ -336,7 +347,7 @@ public class FileTest extends AbstractPersistenceServerServiceTest { activeFiles = fileClient.getDossierStatus(dossier.getId()); assertThat(activeFiles.size()).isEqualTo(1); - fileManagementClient.hardDeleteFiles(dossier.getId(), Sets.newHashSet(file.getId())); + fileManagementClient.hardDeleteFiles(dossier.getId(), List.of(file.getId())); softDeletedFiles = fileClient.getSoftDeletedDossierStatus(dossier.getId()); assertThat(softDeletedFiles.size()).isEqualTo(0); @@ -360,8 +371,20 @@ public class FileTest extends AbstractPersistenceServerServiceTest { var type = typeProvider.testAndProvideType(dossierTemplate, null, "manual"); var annotationId = "imagine_this_makes_sense"; - EntityLog entityLog = new EntityLog(1, 1, - List.of(EntityLogEntry.builder().id(annotationId).type(type.getType()).value("value entry").state(EntryState.APPLIED).entryType(EntryType.ENTITY).build()), null, 0, 0, 0, 0); + EntityLog entityLog = new EntityLog(1, + 1, + List.of(EntityLogEntry.builder() + .id(annotationId) + .type(type.getType()) + .value("value entry") + .state(EntryState.APPLIED) + .entryType(EntryType.ENTITY) + .build()), + null, + 0, + 0, + 0, + 0); when(entityLogService.getEntityLog(Mockito.any(), Mockito.any(), any(), anyBoolean())).thenReturn(entityLog); @@ -379,19 +402,23 @@ public class FileTest extends AbstractPersistenceServerServiceTest { manualRedactionClient.addRedactionBulk(dossierId, fileId, Set.of(addRedactionRequest)); manualRedactionClient.removeRedactionBulk(dossierId, - fileId, - Set.of(RemoveRedactionRequestModel.builder().annotationId(annotationId).comment("comment").removeFromDictionary(false).build()), - false); + fileId, + Set.of(RemoveRedactionRequestModel.builder().annotationId(annotationId).comment("comment").removeFromDictionary(false) + .build()), + false); manualRedactionClient.forceRedactionBulk(dossierId, - fileId, - Set.of(ForceRedactionRequestModel.builder().annotationId("forceRedactionAnnotation").comment("comment").legalBasis("1").build())); + fileId, + Set.of(ForceRedactionRequestModel.builder().annotationId("forceRedactionAnnotation").comment("comment").legalBasis("1") + .build())); manualRedactionClient.legalBasisChangeBulk(dossierId, - fileId, - Set.of(LegalBasisChangeRequestModel.builder().annotationId("legalBasisChangeAnnotation").comment("comment").legalBasis("1").build())); + fileId, + Set.of(LegalBasisChangeRequestModel.builder().annotationId("legalBasisChangeAnnotation").comment("comment").legalBasis("1") + .build())); manualRedactionClient.recategorizeBulk(dossierId, - fileId, - Set.of(RecategorizationRequestModel.builder().annotationId(annotationId).comment("comment").type("new-type").build()), - false); + fileId, + Set.of(RecategorizationRequestModel.builder().annotationId(annotationId).comment("comment").type("new-type") + .build()), + false); var loadedFile = fileClient.getFileStatus(dossierId, fileId); @@ -407,7 +434,7 @@ public class FileTest extends AbstractPersistenceServerServiceTest { activeFiles = fileClient.getDossierStatus(dossier.getId()); assertThat(activeFiles.size()).isEqualTo(1); - fileManagementClient.hardDeleteFiles(dossier.getId(), Sets.newHashSet(file.getId())); + fileManagementClient.hardDeleteFiles(dossier.getId(), List.of(file.getId())); softDeletedFiles = fileClient.getSoftDeletedDossierStatus(dossier.getId()); assertThat(softDeletedFiles.size()).isEqualTo(0); @@ -437,17 +464,18 @@ public class FileTest extends AbstractPersistenceServerServiceTest { fileClient.setStatusUnderReview(dossier.getId(), file.getId(), userId); var addRedaction = manualRedactionClient.addRedactionBulk(dossierId, - fileId, - Set.of(AddRedactionRequestModel.builder() - .addToDictionary(true) - .addToAllDossiers(true) - .comment(new AddCommentRequestModel("comment")) - .type(type.getType()) - .reason("1") - .value("test") - .legalBasis("1") - .dictionaryEntryType(DictionaryEntryType.ENTRY) - .build())).iterator().next(); + fileId, + Set.of(AddRedactionRequestModel.builder() + .addToDictionary(true) + .addToAllDossiers(true) + .comment(new AddCommentRequestModel("comment")) + .type(type.getType()) + .reason("1") + .value("test") + .legalBasis("1") + .dictionaryEntryType(DictionaryEntryType.ENTRY) + .build())) + .iterator().next(); var loadedFile = fileClient.getFileStatus(dossier.getId(), file.getId()); @@ -489,7 +517,7 @@ public class FileTest extends AbstractPersistenceServerServiceTest { var activeFiles = fileClient.getDossierStatus(dossierId); assertThat(activeFiles.size()).isEqualTo(0); - fileManagementClient.hardDeleteFiles(dossierId, Sets.newHashSet(fileId)); + fileManagementClient.hardDeleteFiles(dossierId, List.of(fileId)); softDeletedFiles = fileClient.getSoftDeletedDossierStatus(dossierId); assertThat(softDeletedFiles.size()).isEqualTo(0); @@ -606,7 +634,8 @@ public class FileTest extends AbstractPersistenceServerServiceTest { MockMultipartFile mff = new MockMultipartFile(fileName, fileName + ".pdf", "application/pdf", "lorem ipsum".getBytes()); FileUploadResult uploadResult = uploadClient.upload(mff, dossier.getId(), false); - fileId = uploadResult.getFileIds().iterator().next(); + fileId = uploadResult.getFileIds() + .iterator().next(); FileStatus file = fileClient.getFileStatus(dossier.getId(), fileId); assertThat(file.getProcessingStatus()).isEqualTo(ProcessingStatus.OCR_PROCESSING_QUEUED);