RED-7086 - Deprecate hard-delete files and add new endpoint with POST request

This commit is contained in:
Andrei Isvoran 2024-02-09 15:32:31 +01:00
parent bf66fdf4b7
commit 34c7e51ae8
7 changed files with 136 additions and 76 deletions

View File

@ -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<String> 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<String> 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);

View File

@ -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());
}

View File

@ -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<String> 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<String> files);
@ResponseBody
@ResponseStatus(value = HttpStatus.CREATED)
@PostMapping(value = UNDELETE_PATH + DOSSIER_ID_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE)

View File

@ -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<String> fileIds) {
public void hardDeleteFiles(String dossierId, List<String> 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);
}
});
}

View File

@ -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);

View File

@ -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();

View File

@ -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<FileAttributeConfig> 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);