RED-9608 - Comments not removed after uploading multiple files via ZIP-Archive with "Overwrite and start over" selected

- remove (soft-delete) all comments, not just the ones related to the manual redactions at overwrite
- restore back all comments (not just the ones related to the manual redactions) when file is restored
- unit tests added
This commit is contained in:
corinaolariu 2024-07-16 13:48:25 +03:00
parent 55c6b7419d
commit 552d760ead
3 changed files with 142 additions and 16 deletions

View File

@ -56,7 +56,8 @@ public class CommentPersistenceService {
}
public void softDeleteCommentsForFiles(List<String> fileId, OffsetDateTime softDeletedTime) {
commentRepository.softDeleteCommentsByFilesAndAnnotationSoftDeletedTime(fileId, softDeletedTime);
commentRepository.softDeleteCommentsByFiles(fileId, softDeletedTime);
}
public void undeleteByFileId(String fileId, OffsetDateTime deletionTime) {

View File

@ -34,29 +34,39 @@ public interface CommentRepository extends JpaRepository<CommentEntity, Long> {
int updateSoftDelete(@Param("id") long id, @Param("softDeleteTime") OffsetDateTime softDeleteTime);
@Modifying
@Query("update CommentEntity c set c.softDeletedTime = :softDeleteTime where c.fileId in (:fileIds) and " +
"(exists (select a from ManualForceRedactionEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime = :softDeleteTime) or "+
"exists (select a from IdRemovalEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime = :softDeleteTime) or "+
"exists (select a from ManualRedactionEntryEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime = :softDeleteTime) or "+
"exists (select a from ManualRecategorizationEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime = :softDeleteTime) or "+
"exists (select a from ManualResizeRedactionEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime = :softDeleteTime) or "+
"exists (select a from ManualLegalBasisChangeEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime = :softDeleteTime)) ")
@Query("update CommentEntity c set c.softDeletedTime = :softDeleteTime where c.fileId in (:fileIds) and "
+ "(exists (select a from ManualForceRedactionEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime = :softDeleteTime) or "
+ "exists (select a from IdRemovalEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime = :softDeleteTime) or "
+ "exists (select a from ManualRedactionEntryEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime = :softDeleteTime) or "
+ "exists (select a from ManualRecategorizationEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime = :softDeleteTime) or "
+ "exists (select a from ManualResizeRedactionEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime = :softDeleteTime) or "
+ "exists (select a from ManualLegalBasisChangeEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime = :softDeleteTime)) ")
void softDeleteCommentsByFilesAndAnnotationSoftDeletedTime(@Param("fileIds") List<String> fileIds, @Param("softDeleteTime") OffsetDateTime softDeleteTime);
@Modifying
@Query("update CommentEntity c set c.softDeletedTime = :softDeleteTime where c.fileId in (:fileIds)")
void softDeleteCommentsByFiles(@Param("fileIds") List<String> fileIds, @Param("softDeleteTime") OffsetDateTime softDeleteTime);
@Modifying
@Query("delete from CommentEntity c where c.fileId in (:fileIds)")
void deleteCommentsByFiles(@Param("fileIds") List<String> fileIds);
@Modifying
@Query("update CommentEntity c set c.softDeletedTime = null where c.fileId = :fileId and " +
"(exists (select a from ManualForceRedactionEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime >= :deletionTime) or "+
"exists (select a from IdRemovalEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime >= :deletionTime) or "+
"exists (select a from ManualRedactionEntryEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime >= :deletionTime) or "+
"exists (select a from ManualRecategorizationEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime >= :deletionTime) or "+
"exists (select a from ManualResizeRedactionEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime >= :deletionTime) or "+
"exists (select a from ManualLegalBasisChangeEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime >= :deletionTime)) ")
void undeleteByFileId(@Param("fileId") String fileId,@Param("deletionTime") OffsetDateTime deletionTime);
@Query("update CommentEntity c set c.softDeletedTime = null where c.fileId = :fileId and "
+ "(exists (select a from ManualForceRedactionEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime >= :deletionTime) or "
+ "exists (select a from IdRemovalEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime >= :deletionTime) or "
+ "exists (select a from ManualRedactionEntryEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime >= :deletionTime) or "
+ "exists (select a from ManualRecategorizationEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime >= :deletionTime) or "
+ "exists (select a from ManualResizeRedactionEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime >= :deletionTime) or "
+ "exists (select a from ManualLegalBasisChangeEntity a where a.id.annotationId = c.annotationId and a.softDeletedTime >= :deletionTime)) ")
void undeleteByFileIdAndAnnotationSoftDeletedTime(@Param("fileId") String fileId, @Param("deletionTime") OffsetDateTime deletionTime);
@Modifying
@Query("update CommentEntity c set c.softDeletedTime = null where c.fileId = :fileId and c.softDeletedTime >= :deletionTime")
void undeleteByFileId(@Param("fileId") String fileId, @Param("deletionTime") OffsetDateTime deletionTime);
@Modifying

View File

@ -58,6 +58,7 @@ import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog
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.EntryState;
import com.iqser.red.service.persistence.service.v1.api.shared.model.analysislog.entitylog.EntryType;
import com.iqser.red.service.persistence.service.v1.api.shared.model.annotations.AnnotationComments;
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.dossier.Dossier;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileAttributeConfig;
@ -375,6 +376,7 @@ public class FileTest extends AbstractPersistenceServerServiceTest {
var type = typeProvider.testAndProvideType(dossierTemplate, null, "manual");
typeProvider.testAndProvideType(dossierTemplate, null, "new-type", false, 2000);
var annotationId = "imagine_this_makes_sense";
var commentId = "commentId";
EntityLog entityLog = new EntityLog(1,
1,
List.of(EntityLogEntry.builder()
@ -397,6 +399,14 @@ public class FileTest extends AbstractPersistenceServerServiceTest {
.value("value entry 3")
.state(EntryState.APPLIED)
.entryType(EntryType.ENTITY)
.build(),
EntityLogEntry.builder()
.id(commentId)
.type(type.getType())
.value("value entry 4")
.dictionaryEntry(true)
.state(EntryState.APPLIED)
.entryType(EntryType.ENTITY)
.build()),
null,
0,
@ -445,19 +455,39 @@ public class FileTest extends AbstractPersistenceServerServiceTest {
.build()),
false);
manualRedactionClient.addComment(dossierId, fileId, commentId, AddCommentRequestModel.builder().text("comment added via text fileId").build());
var loadedFile = fileClient.getFileStatus(dossierId, fileId);
//check comments are restored
AnnotationComments annotationComments = manualRedactionClient.getComments(dossierId, fileId, commentId);
assertThat(annotationComments.getComments()).hasSize(1);
AnnotationComments annotationCommentsForManualRedactions = manualRedactionClient.getComments(dossierId, fileId, annotationId);
assertThat(annotationCommentsForManualRedactions.getComments()).hasSize(1);
fileManagementClient.deleteFile(dossier.getId(), file.getId());
var softDeletedFiles = fileClient.getSoftDeletedDossierStatus(dossier.getId());
assertThat(softDeletedFiles).hasSize(1);
var activeFiles = fileClient.getDossierStatus(dossier.getId());
assertThat(activeFiles).isEmpty();
// check the comment added to an annotation that has no manual redaction
Exception exception = Assertions.assertThrows(FeignException.NotFound.class, () -> manualRedactionClient.getComments(dossierId, fileId, commentId));
String expectedMessage = "The requested file has been soft deleted on";
String actualMessage = exception.getMessage();
assertThat(actualMessage).contains(expectedMessage);
fileManagementClient.restoreFiles(dossier.getId(), Sets.newHashSet(file.getId()));
softDeletedFiles = fileClient.getSoftDeletedDossierStatus(dossier.getId());
assertThat(softDeletedFiles).isEmpty();
activeFiles = fileClient.getDossierStatus(dossier.getId());
assertThat(activeFiles).hasSize(1);
//check comments are restored
annotationComments = manualRedactionClient.getComments(dossierId, fileId, commentId);
assertThat(annotationComments.getComments()).hasSize(1);
annotationCommentsForManualRedactions = manualRedactionClient.getComments(dossierId, fileId, annotationId);
assertThat(annotationCommentsForManualRedactions.getComments()).hasSize(1);
fileManagementClient.hardDeleteFiles(dossier.getId(), List.of(file.getId()));
softDeletedFiles = fileClient.getSoftDeletedDossierStatus(dossier.getId());
@ -697,4 +727,89 @@ public class FileTest extends AbstractPersistenceServerServiceTest {
assertThrows(FeignException.class, () -> uploadClient.upload(malformedCsvFile, dossier.getId(), false));
}
@Test
void testFileWithCommentsAtReupload() {
var dossierTemplate = dossierTemplateTesterAndProvider.provideTestTemplate();
var dossier = dossierTesterAndProvider.provideTestDossier(dossierTemplate);
String dossierId = dossier.getId();
var file = fileTesterAndProvider.testAndProvideFile(dossier);
String fileId = file.getId();
var type = typeProvider.testAndProvideType(dossierTemplate, null, "manual");
typeProvider.testAndProvideType(dossierTemplate, null, "new-type", false, 2000);
var annotationId = "imagine_this_makes_sense";
var annotation2Id = "imagine_this_makes_sense 2";
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(),
EntityLogEntry.builder()
.id(annotation2Id)
.type(type.getType())
.value("value entry 3")
.state(EntryState.APPLIED)
.entryType(EntryType.ENTITY)
.build()),
null,
0,
0,
0,
0);
fileManagementStorageService.saveEntityLog(dossier.getId(), file.getId(), entityLog);
when(entityLogService.getEntityLog(any(), any(), anyBoolean())).thenReturn(entityLog);
assertThat(fileClient.getDossierStatus(dossier.getId()).size()).isEqualTo(1);
var recatResponse = manualRedactionClient.recategorizeBulk(dossierId,
fileId,
Set.of(RecategorizationRequestModel.builder()
.annotationId(annotation2Id)
.comment("comment edit via edit dialog")
.type(type.getType())
.legalBasis("")
.section("section")
.value("value entry 3")
.build()),
false);
var loadedFile = fileClient.getFileStatus(dossierId, fileId);
manualRedactionClient.addComment(dossierId, fileId, annotationId, AddCommentRequestModel.builder().text("comment added via text fileId").build());
//check comments are restored
AnnotationComments annotationComments = manualRedactionClient.getComments(dossierId, fileId, annotationId);
assertThat(annotationComments.getComments()).hasSize(1);
AnnotationComments annotationCommentsForInitialAnnotation = manualRedactionClient.getComments(dossierId, fileId, annotation2Id);
assertThat(annotationCommentsForInitialAnnotation.getComments()).hasSize(0);
AnnotationComments annotationCommentsForManualRecat = manualRedactionClient.getComments(dossierId, fileId, recatResponse.getManualAddResponses().get(0).getAnnotationId());
assertThat(annotationCommentsForManualRecat.getComments()).hasSize(1);
//overwrite the file
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());
//check comments are soft deleted
annotationComments = manualRedactionClient.getComments(dossierId, loadedFile.getId(), annotation2Id);
assertThat(annotationComments.getComments()).hasSize(0);
annotationCommentsForInitialAnnotation = manualRedactionClient.getComments(dossierId, fileId, annotation2Id);
assertThat(annotationCommentsForInitialAnnotation.getComments()).hasSize(0);
annotationCommentsForManualRecat = manualRedactionClient.getComments(dossierId, fileId, recatResponse.getManualAddResponses().get(0).getAnnotationId());
assertThat(annotationCommentsForManualRecat.getComments()).hasSize(0);
}
}