diff --git a/backend/src/main/java/org/booklore/model/entity/BookEntity.java b/backend/src/main/java/org/booklore/model/entity/BookEntity.java index c0f5c80741..6252fd5717 100644 --- a/backend/src/main/java/org/booklore/model/entity/BookEntity.java +++ b/backend/src/main/java/org/booklore/model/entity/BookEntity.java @@ -129,6 +129,7 @@ public BookFileEntity getPrimaryBookFile() { } return bookFiles .stream() + .filter(BookFileEntity::isBook) .min(Comparator.comparingLong(BookFileEntity::getId)) .orElse(null); } diff --git a/backend/src/main/java/org/booklore/service/file/AdditionalFileService.java b/backend/src/main/java/org/booklore/service/file/AdditionalFileService.java index bf83e22fa9..a5f54afb3d 100644 --- a/backend/src/main/java/org/booklore/service/file/AdditionalFileService.java +++ b/backend/src/main/java/org/booklore/service/file/AdditionalFileService.java @@ -59,7 +59,6 @@ public void deleteAdditionalFile(Long bookId, Long fileId) { BookFileEntity file = fileOpt.get(); BookEntity book = file.getBook(); - validateAdditionalFile(file, book); try { monitoringRegistrationService.unregisterSpecificPath(file.getFullFilePath().getParent()); diff --git a/backend/src/test/java/org/booklore/service/AdditionalFileServiceTest.java b/backend/src/test/java/org/booklore/service/AdditionalFileServiceTest.java index a6cba19ff5..8c7c905614 100644 --- a/backend/src/test/java/org/booklore/service/AdditionalFileServiceTest.java +++ b/backend/src/test/java/org/booklore/service/AdditionalFileServiceTest.java @@ -164,7 +164,7 @@ void deleteAdditionalFile_WhenFileNotFound_ShouldThrowException() { } @Test - void deleteAdditionalFile_WhenFileExists_ShouldDeleteSuccessfully() { + void deleteAdditionalFile_WhenFileIsAlternativeFormat_ShouldDeleteSuccessfully() { Long bookId = 100L; Long fileId = 1L; Path parentPath = fileEntity.getFullFilePath().getParent(); @@ -309,20 +309,54 @@ void downloadAdditionalFile_WhenEntityRelationshipsMissing_ShouldThrowIllegalSta } @Test - void deleteAdditionalFile_WhenFileIsPrimaryBookFile_ShouldThrowException() { + void deleteAdditionalFile_WhenPrimaryHasAlternativeAndSupplementaryFile_ShouldDeleteAndPromoteReadableAlternative() { Long bookId = 100L; Long fileId = 1L; - bookEntity.setBookFiles(Set.of(fileEntity)); + BookFileEntity supplementaryFile = createBookFile(2L, "notes.txt"); + supplementaryFile.setBookFormat(false); + BookFileEntity alternativeFormat = createBookFile(3L, "alternative.epub"); + bookEntity.setBookFiles(new HashSet<>(Set.of(fileEntity, supplementaryFile, alternativeFormat))); + Path parentPath = fileEntity.getFullFilePath().getParent(); + assertEquals(fileEntity, bookEntity.getPrimaryBookFile()); + when(additionalFileRepository.findByIdAndBookIdWithBookAndLibraryPath(fileId, bookId)).thenReturn(Optional.of(fileEntity)); - IllegalArgumentException exception = assertThrows( - IllegalArgumentException.class, - () -> additionalFileService.deleteAdditionalFile(bookId, fileId) - ); + try (MockedStatic filesMock = mockStatic(Files.class)) { + filesMock.when(() -> Files.deleteIfExists(fileEntity.getFullFilePath())).thenReturn(true); - assertEquals("Primary book file cannot be processed as an additional file: 1", exception.getMessage()); - verify(additionalFileRepository, never()).delete(any()); - verify(monitoringRegistrationService, never()).unregisterSpecificPath(any()); + additionalFileService.deleteAdditionalFile(bookId, fileId); + + verify(monitoringRegistrationService).unregisterSpecificPath(parentPath); + filesMock.verify(() -> Files.deleteIfExists(fileEntity.getFullFilePath())); + verify(additionalFileRepository).delete(fileEntity); + } + + assertEquals(alternativeFormat, bookEntity.getPrimaryBookFile()); + } + + @Test + void deleteAdditionalFile_WhenFileIsSupplementary_ShouldDeleteSuccessfully() { + Long bookId = 100L; + Long fileId = 1L; + fileEntity.setBookFormat(false); + BookFileEntity readableFormat = createBookFile(0L, "book.epub"); + bookEntity.setBookFiles(new HashSet<>(Set.of(fileEntity, readableFormat))); + Path parentPath = fileEntity.getFullFilePath().getParent(); + assertEquals(readableFormat, bookEntity.getPrimaryBookFile()); + + when(additionalFileRepository.findByIdAndBookIdWithBookAndLibraryPath(fileId, bookId)).thenReturn(Optional.of(fileEntity)); + + try (MockedStatic filesMock = mockStatic(Files.class)) { + filesMock.when(() -> Files.deleteIfExists(fileEntity.getFullFilePath())).thenReturn(true); + + additionalFileService.deleteAdditionalFile(bookId, fileId); + + verify(monitoringRegistrationService).unregisterSpecificPath(parentPath); + filesMock.verify(() -> Files.deleteIfExists(fileEntity.getFullFilePath())); + verify(additionalFileRepository).delete(fileEntity); + } + + assertEquals(readableFormat, bookEntity.getPrimaryBookFile()); } @Test