Skip to content

Commit

Permalink
Added a REST API for clearing the image cache [#176]
Browse files Browse the repository at this point in the history
  • Loading branch information
mcpierce committed Jun 25, 2020
1 parent 85075f2 commit d6661c5
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 12 deletions.
10 changes: 10 additions & 0 deletions comixed-library/src/main/java/org/comixed/utils/Utils.java
Expand Up @@ -68,4 +68,14 @@ public String encodeURL(String string, String charset) throws UnsupportedEncodin
public String streamToString(InputStream stream, Charset charset) throws IOException {
return IOUtils.toString(stream, charset);
}

/**
* Clears the contents of the specified directory.
*
* @param path the parent directory
* @throws IOException if an error occurs
*/
public void deleteDirectoryContents(String path) throws IOException {
FileUtils.cleanDirectory(new File(path));
}
}
Expand Up @@ -27,22 +27,17 @@
import org.comixed.model.comic.Comic;
import org.comixed.model.library.ReadingList;
import org.comixed.model.user.LastReadDate;
import org.comixed.net.ConsolidateLibraryRequest;
import org.comixed.net.ConvertComicsRequest;
import org.comixed.net.GetUpdatedComicsRequest;
import org.comixed.net.GetUpdatedComicsResponse;
import org.comixed.net.*;
import org.comixed.service.comic.ComicService;
import org.comixed.service.library.LibraryException;
import org.comixed.service.library.LibraryService;
import org.comixed.service.library.ReadingListService;
import org.comixed.service.user.ComiXedUserException;
import org.comixed.service.user.UserService;
import org.comixed.views.View;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(value = "/api")
Expand Down Expand Up @@ -158,4 +153,18 @@ public List<Comic> consolidateLibrary(@RequestBody() ConsolidateLibraryRequest r
"Consolidating library: delete physic files={}", request.getDeletePhysicalFiles());
return this.libraryService.consolidateLibrary(request.getDeletePhysicalFiles());
}

@DeleteMapping(value = "/library/cache/images")
public ClearImageCacheResponse clearImageCache() {
this.log.info("Clearing the image cache");

try {
this.libraryService.clearImageCache();
} catch (LibraryException error) {
this.log.error("failed to clear image cache", error);
return new ClearImageCacheResponse(false);
}

return new ClearImageCacheResponse(true);
}
}
@@ -0,0 +1,34 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

package org.comixed.net;

import com.fasterxml.jackson.annotation.JsonProperty;

public class ClearImageCacheResponse {
@JsonProperty("success")
private final boolean success;

public ClearImageCacheResponse(boolean success) {
this.success = success;
}

public boolean isSuccess() {
return success;
}
}
Expand Up @@ -29,11 +29,9 @@
import org.comixed.model.library.ReadingList;
import org.comixed.model.user.ComiXedUser;
import org.comixed.model.user.LastReadDate;
import org.comixed.net.ConsolidateLibraryRequest;
import org.comixed.net.ConvertComicsRequest;
import org.comixed.net.GetUpdatedComicsRequest;
import org.comixed.net.GetUpdatedComicsResponse;
import org.comixed.net.*;
import org.comixed.service.comic.ComicService;
import org.comixed.service.library.LibraryException;
import org.comixed.service.library.LibraryService;
import org.comixed.service.library.ReadingListService;
import org.comixed.service.user.ComiXedUserException;
Expand All @@ -58,6 +56,7 @@ public class LibraryControllerTest {
private static final Random RANDOM = new Random();
private static final boolean TEST_RENAME_PAGES = RANDOM.nextBoolean();
private static final Boolean TEST_DELETE_PHYSICAL_FILES = RANDOM.nextBoolean();
private static final int TEST_CACHE_ENTRIES_CLEARED = RANDOM.nextInt();

@InjectMocks private LibraryController libraryController;
@Mock private LibraryService libraryService;
Expand Down Expand Up @@ -231,4 +230,29 @@ public void testConsolidate() {

Mockito.verify(libraryService, Mockito.times(1)).consolidateLibrary(TEST_DELETE_PHYSICAL_FILES);
}

@Test
public void testClearImageCache() throws LibraryException {
Mockito.doNothing().when(libraryService).clearImageCache();

ClearImageCacheResponse result = libraryController.clearImageCache();

assertNotNull(result);
assertTrue(result.isSuccess());

Mockito.verify(libraryService, Mockito.times(1)).clearImageCache();
;
}

@Test
public void testClearImageCacheWithError() throws LibraryException {
Mockito.doThrow(LibraryException.class).when(libraryService).clearImageCache();

ClearImageCacheResponse result = libraryController.clearImageCache();

assertNotNull(result);
assertFalse(result.isSuccess());

Mockito.verify(libraryService, Mockito.times(1)).clearImageCache();
}
}
Expand Up @@ -78,4 +78,14 @@ public void saveByHash(final String hash, final byte[] content) throws IOExcepti
file.getParentFile().mkdirs();
IOUtils.write(content, new FileOutputStream(file, false));
}

/**
* Returns the root directory for the image cache.
*
* @return the root directory
*/
public String getRootDirectory() {
this.log.debug("Getting the image cache root directory: {}", this.cacheDirectory);
return this.cacheDirectory;
}
}
@@ -0,0 +1,30 @@
/*
* ComiXed - A digital comic book library management application.
* Copyright (C) 2020, The ComiXed Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses>
*/

package org.comixed.service.library;

/**
* <code>LibraryException</code> is thrown when an error occurs during a library operation.
*
* @author Darryl L. Pierce
*/
public class LibraryException extends Exception {
public LibraryException(String message, Exception cause) {
super(message, cause);
}
}
Expand Up @@ -19,6 +19,7 @@
package org.comixed.service.library;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
Expand All @@ -30,6 +31,7 @@
import org.comixed.model.user.LastReadDate;
import org.comixed.repositories.comic.ComicRepository;
import org.comixed.repositories.library.LastReadDatesRepository;
import org.comixed.service.comic.PageCacheService;
import org.comixed.service.task.TaskService;
import org.comixed.service.user.ComiXedUserException;
import org.comixed.service.user.UserService;
Expand All @@ -53,6 +55,7 @@ public class LibraryService {
@Autowired private ObjectFactory<ConvertComicsWorkerTask> convertComicsWorkerTaskObjectFactory;
@Autowired private Worker worker;
@Autowired private Utils utils;
@Autowired private PageCacheService pageCacheService;

public List<Comic> getComicsUpdatedSince(
String email, Date latestUpdatedDate, int maximumComics, long lastComicId) {
Expand Down Expand Up @@ -146,4 +149,19 @@ public List<Comic> consolidateLibrary(boolean deletePhysicalFiles) {
}
return result;
}

/**
* Removes all files in the image cache directory.
*
* @throws LibraryException if an error occurs
*/
public void clearImageCache() throws LibraryException {
String directory = this.pageCacheService.getRootDirectory();
this.log.debug("Clearing the image cache: {}", directory);
try {
this.utils.deleteDirectoryContents(directory);
} catch (IOException error) {
throw new LibraryException("failed to clean image cache directory", error);
}
}
}
Expand Up @@ -3,6 +3,7 @@
import static junit.framework.TestCase.*;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
Expand All @@ -15,6 +16,7 @@
import org.comixed.model.user.LastReadDate;
import org.comixed.repositories.comic.ComicRepository;
import org.comixed.repositories.library.LastReadDatesRepository;
import org.comixed.service.comic.PageCacheService;
import org.comixed.service.task.TaskService;
import org.comixed.service.user.ComiXedUserException;
import org.comixed.service.user.UserService;
Expand Down Expand Up @@ -42,6 +44,8 @@ public class LibraryServiceTest {
private static final Boolean TEST_DELETE_PHYSICAL_FILES = RANDOM.nextBoolean();
private static final String TEST_FILENAME = "/home/comixeduser/Library/comicfile.cbz";
private static final Long TEST_USER_ID = 723L;
private static final String TEST_IMAGE_CACHE_DIRECTORY =
"/home/ComiXedReader/.comixed/image-cache";

@InjectMocks private LibraryService libraryService;
@Mock private ComicRepository comicRepository;
Expand All @@ -59,6 +63,7 @@ public class LibraryServiceTest {
@Mock private List<LastReadDate> lastReadDateList;
@Mock private ComiXedUser user;
@Mock private LastReadDatesRepository lastReadDatesRepository;
@Mock private PageCacheService pageCacheService;

private List<Comic> comicList = new ArrayList<>();
private Comic comic1 = new Comic();
Expand Down Expand Up @@ -206,4 +211,26 @@ public void testGetLastReadDatesForUser() throws ComiXedUserException {
Mockito.verify(lastReadDatesRepository, Mockito.times(1))
.findAllForUser(TEST_USER_ID, TEST_LAST_UPDATED_TIMESTAMP);
}

@Test
public void testClearImageCache() throws LibraryException, IOException {
Mockito.when(pageCacheService.getRootDirectory()).thenReturn(TEST_IMAGE_CACHE_DIRECTORY);
Mockito.doNothing().when(utils).deleteDirectoryContents(Mockito.anyString());

libraryService.clearImageCache();

Mockito.verify(pageCacheService, Mockito.times(1)).getRootDirectory();
Mockito.verify(utils, Mockito.times(1)).deleteDirectoryContents(TEST_IMAGE_CACHE_DIRECTORY);
}

@Test(expected = LibraryException.class)
public void testClearImageCacheError() throws LibraryException, IOException {
Mockito.when(pageCacheService.getRootDirectory()).thenReturn(TEST_IMAGE_CACHE_DIRECTORY);
Mockito.doThrow(IOException.class).when(utils).deleteDirectoryContents(Mockito.anyString());

libraryService.clearImageCache();

Mockito.verify(pageCacheService, Mockito.times(1)).getRootDirectory();
Mockito.verify(utils, Mockito.times(1)).deleteDirectoryContents(TEST_IMAGE_CACHE_DIRECTORY);
}
}

0 comments on commit d6661c5

Please sign in to comment.