diff --git a/comixed-library/src/main/java/org/comixed/repositories/library/ReadingListRepository.java b/comixed-library/src/main/java/org/comixed/repositories/library/ReadingListRepository.java index 1c9dc3deb..b6c4b8f26 100644 --- a/comixed-library/src/main/java/org/comixed/repositories/library/ReadingListRepository.java +++ b/comixed-library/src/main/java/org/comixed/repositories/library/ReadingListRepository.java @@ -18,6 +18,7 @@ package org.comixed.repositories.library; +import java.util.Date; import java.util.List; import org.comixed.model.comic.Comic; import org.comixed.model.library.ReadingList; @@ -29,8 +30,9 @@ @Repository public interface ReadingListRepository extends CrudRepository { - @Query("SELECT list FROM ReadingList list WHERE list.owner = :owner") - List findAllReadingListsForUser(ComiXedUser owner); + @Query("SELECT l FROM ReadingList l WHERE l.owner = :owner AND l.lastUpdated > :lastUpdated") + List getAllReadingListsForOwnerUpdatedAfter( + @Param("owner") ComiXedUser owner, @Param("lastUpdated") Date lastUpdated); @Query("SELECT list FROM ReadingList list WHERE list.owner = :owner AND list.name = :listName") ReadingList findReadingListForUser(ComiXedUser owner, String listName); diff --git a/comixed-library/src/test/java/org/comixed/repositories/library/ReadingListRepositoryTest.java b/comixed-library/src/test/java/org/comixed/repositories/library/ReadingListRepositoryTest.java index cde93f63a..1a5fa3440 100644 --- a/comixed-library/src/test/java/org/comixed/repositories/library/ReadingListRepositoryTest.java +++ b/comixed-library/src/test/java/org/comixed/repositories/library/ReadingListRepositoryTest.java @@ -22,6 +22,7 @@ import com.github.springtestdbunit.DbUnitTestExecutionListener; import com.github.springtestdbunit.annotation.DatabaseSetup; +import java.util.Date; import java.util.List; import java.util.Optional; import org.comixed.model.comic.Comic; @@ -74,7 +75,8 @@ public void setUp() { @Test public void testFindAllReadingListsForUser() { - List result = repository.findAllReadingListsForUser(reader); + List result = + repository.getAllReadingListsForOwnerUpdatedAfter(reader, new Date(0L)); assertNotNull(result); assertEquals(2, result.size()); @@ -91,6 +93,15 @@ public void testFindAllReadingListsForUser() { } } + @Test + public void testFindAllReadingListsForUserNoneUpdated() { + List result = + repository.getAllReadingListsForOwnerUpdatedAfter(reader, new Date()); + + assertNotNull(result); + assertTrue(result.isEmpty()); + } + @Test public void testFindReadingListForUser() { ReadingList result = repository.findReadingListForUser(reader, TEST_EXISTING_LIST_NAME); diff --git a/comixed-rest-api/src/main/java/org/comixed/controller/library/LibraryController.java b/comixed-rest-api/src/main/java/org/comixed/controller/library/LibraryController.java index 6b3c8b89b..e50a3f0d2 100644 --- a/comixed-rest-api/src/main/java/org/comixed/controller/library/LibraryController.java +++ b/comixed-rest-api/src/main/java/org/comixed/controller/library/LibraryController.java @@ -25,6 +25,7 @@ import lombok.extern.log4j.Log4j2; import org.comixed.adaptors.ArchiveType; 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; @@ -32,6 +33,7 @@ import org.comixed.net.GetUpdatedComicsResponse; import org.comixed.service.comic.ComicService; import org.comixed.service.library.LibraryService; +import org.comixed.service.library.ReadingListService; import org.comixed.service.user.UserService; import org.comixed.views.View; import org.springframework.beans.factory.annotation.Autowired; @@ -48,6 +50,7 @@ public class LibraryController { @Autowired private LibraryService libraryService; @Autowired private ComicService comicService; @Autowired private UserService userService; + @Autowired private ReadingListService readingListService; @PostMapping( value = "/library/updates", @@ -57,10 +60,11 @@ public class LibraryController { public GetUpdatedComicsResponse getUpdatedComics( Principal principal, @RequestBody() GetUpdatedComicsRequest request) { Date latestUpdateDate = new Date(request.getLastUpdatedDate()); + String email = principal.getName(); this.log.info( "Getting comics updated since {} for {} (max: {}, last id: {}, timeout: {}s)", latestUpdateDate, - principal.getName(), + email, request.getMaximumComics(), request.getLastComicId(), request.getTimeout()); @@ -76,10 +80,7 @@ public GetUpdatedComicsResponse getUpdatedComics( while (!done) { comics = this.libraryService.getComicsUpdatedSince( - principal.getName(), - latestUpdateDate, - request.getMaximumComics() + 1, - request.getLastComicId()); + email, latestUpdateDate, request.getMaximumComics() + 1, request.getLastComicId()); if (comics.size() > request.getMaximumComics()) { this.log.debug("More updates are waiting"); @@ -112,11 +113,21 @@ public GetUpdatedComicsResponse getUpdatedComics( this.log.debug("Loading updated last read dates"); List lastReadDates = - this.libraryService.getLastReadDatesSince(principal.getName(), latestUpdateDate); + this.libraryService.getLastReadDatesSince(email, latestUpdateDate); + + this.log.debug("Getting updated reading lists"); + List readingLists = + this.readingListService.getReadingListsForUser(email, latestUpdateDate); this.log.debug("Returning result"); return new GetUpdatedComicsResponse( - comics, lastComicId, mostRecentUpdate, lastReadDates, moreUpdates, processingCount); + comics, + lastComicId, + mostRecentUpdate, + lastReadDates, + readingLists, + moreUpdates, + processingCount); } @PostMapping(value = "/library/convert", consumes = MediaType.APPLICATION_JSON_VALUE) diff --git a/comixed-rest-api/src/main/java/org/comixed/controller/library/ReadingListController.java b/comixed-rest-api/src/main/java/org/comixed/controller/library/ReadingListController.java index 0f6cb1c05..b4b9f444f 100644 --- a/comixed-rest-api/src/main/java/org/comixed/controller/library/ReadingListController.java +++ b/comixed-rest-api/src/main/java/org/comixed/controller/library/ReadingListController.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.annotation.JsonView; import java.security.Principal; +import java.util.Date; import java.util.List; import lombok.extern.log4j.Log4j2; import org.comixed.model.library.ReadingList; @@ -83,7 +84,7 @@ public ReadingList updateReadingList( @RequestMapping(value = "/lists", method = RequestMethod.GET) @JsonView(View.ReadingList.class) - public List getReadingListsForUser(Principal principal) { + public List getReadingListsForUser(Principal principal, final Date lastUpdated) { if (principal == null) { return null; } @@ -91,7 +92,8 @@ public List getReadingListsForUser(Principal principal) { this.log.info("Getting reading lists: user={}", email); - final List result = this.readingListService.getReadingListsForUser(email); + final List result = + this.readingListService.getReadingListsForUser(email, lastUpdated); this.log.debug("Returning {} lists{}", result.size(), result.size() == 1 ? "" : "s"); return result; diff --git a/comixed-rest-api/src/main/java/org/comixed/controller/opds/OPDSController.java b/comixed-rest-api/src/main/java/org/comixed/controller/opds/OPDSController.java index e373d8bc4..9389eac65 100644 --- a/comixed-rest-api/src/main/java/org/comixed/controller/opds/OPDSController.java +++ b/comixed-rest-api/src/main/java/org/comixed/controller/opds/OPDSController.java @@ -22,6 +22,7 @@ import java.awt.image.BufferedImage; import java.io.*; import java.text.ParseException; +import java.util.Date; import java.util.Optional; import javax.imageio.ImageIO; import javax.swing.*; @@ -80,7 +81,7 @@ public OPDSFeed getAllLists() throws ParseException { return new OPDSNavigationFeed( "/opds/all?groupByFolder=true", "Comics - ", - this.readingListService.getReadingListsForUser(authentication.getName())); + this.readingListService.getReadingListsForUser(authentication.getName(), new Date(0L))); } @ResponseBody diff --git a/comixed-rest-api/src/main/java/org/comixed/net/GetUpdatedComicsResponse.java b/comixed-rest-api/src/main/java/org/comixed/net/GetUpdatedComicsResponse.java index 5f4c9d68b..3a954b857 100644 --- a/comixed-rest-api/src/main/java/org/comixed/net/GetUpdatedComicsResponse.java +++ b/comixed-rest-api/src/main/java/org/comixed/net/GetUpdatedComicsResponse.java @@ -21,13 +21,16 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonView; +import java.util.ArrayList; import java.util.Date; import java.util.List; import org.comixed.model.comic.Comic; +import org.comixed.model.library.ReadingList; import org.comixed.model.user.LastReadDate; import org.comixed.views.View; public class GetUpdatedComicsResponse { + @JsonProperty("comics") @JsonView(View.ComicList.class) private List comics; @@ -45,6 +48,10 @@ public class GetUpdatedComicsResponse { @JsonView(View.ComicList.class) private List lastReadDates; + @JsonProperty("readingLists") + @JsonView(View.ComicList.class) + private List readingLists = new ArrayList<>(); + @JsonProperty("moreUpdates") @JsonView(View.ComicList.class) private boolean moreUpdates; @@ -60,12 +67,14 @@ public GetUpdatedComicsResponse( Long lastComicId, Date mostRecentUpdate, List lastReadDates, + List readingLists, boolean moreUpdates, long processingCount) { this.comics = comics; this.lastComicId = lastComicId; this.mostRecentUpdate = mostRecentUpdate; this.lastReadDates = lastReadDates; + this.readingLists = readingLists; this.moreUpdates = moreUpdates; this.processingCount = processingCount; } @@ -93,4 +102,8 @@ public boolean hasMoreUpdates() { public long getProcessingCount() { return processingCount; } + + public List getReadingLists() { + return this.readingLists; + } } diff --git a/comixed-rest-api/src/test/java/org/comixed/controller/library/LibraryControllerTest.java b/comixed-rest-api/src/test/java/org/comixed/controller/library/LibraryControllerTest.java index ac49d4f2b..ffac48b80 100644 --- a/comixed-rest-api/src/test/java/org/comixed/controller/library/LibraryControllerTest.java +++ b/comixed-rest-api/src/test/java/org/comixed/controller/library/LibraryControllerTest.java @@ -26,6 +26,7 @@ import java.util.Random; import org.comixed.adaptors.ArchiveType; import org.comixed.model.comic.Comic; +import org.comixed.model.library.ReadingList; import org.comixed.model.user.ComiXedUser; import org.comixed.model.user.LastReadDate; import org.comixed.net.ConsolidateLibraryRequest; @@ -34,6 +35,7 @@ import org.comixed.net.GetUpdatedComicsResponse; import org.comixed.service.comic.ComicService; import org.comixed.service.library.LibraryService; +import org.comixed.service.library.ReadingListService; import org.comixed.service.user.UserService; import org.junit.Test; import org.junit.runner.RunWith; @@ -66,6 +68,8 @@ public class LibraryControllerTest { @Mock private Principal principal; @Mock private ComiXedUser user; @Mock private List comicIdList; + @Mock private ReadingListService readingListService; + @Mock private List readingLists; @Test public void testGetUpdatedComics() { @@ -82,6 +86,9 @@ public void testGetUpdatedComics() { Mockito.when(libraryService.getLastReadDatesSince(Mockito.anyString(), Mockito.any(Date.class))) .thenReturn(lastReadList); Mockito.when(libraryService.getProcessingCount()).thenReturn(TEST_PROCESSING_COUNT); + Mockito.when( + readingListService.getReadingListsForUser(Mockito.anyString(), Mockito.any(Date.class))) + .thenReturn(readingLists); GetUpdatedComicsResponse result = libraryController.getUpdatedComics( @@ -100,6 +107,7 @@ public void testGetUpdatedComics() { assertSame(lastReadList, result.getLastReadDates()); assertFalse(result.hasMoreUpdates()); assertEquals(TEST_PROCESSING_COUNT, result.getProcessingCount()); + assertEquals(readingLists, result.getReadingLists()); Mockito.verify(libraryService, Mockito.times(1)) .getComicsUpdatedSince( @@ -109,6 +117,8 @@ public void testGetUpdatedComics() { TEST_MOST_RECENT_COMIC_ID); Mockito.verify(libraryService, Mockito.times(1)) .getLastReadDatesSince(TEST_USER_EMAIL, TEST_LATEST_UPDATED_DATE); + Mockito.verify(readingListService, Mockito.times(1)) + .getReadingListsForUser(TEST_USER_EMAIL, TEST_LAST_UPDATED_DATE); } @Test @@ -214,7 +224,7 @@ public void testConsolidate() { List response = libraryController.consolidateLibrary( new ConsolidateLibraryRequest(TEST_DELETE_PHYSICAL_FILES)); -k + assertNotNull(response); assertSame(comicList, response); diff --git a/comixed-rest-api/src/test/java/org/comixed/controller/library/ReadingListControllerTest.java b/comixed-rest-api/src/test/java/org/comixed/controller/library/ReadingListControllerTest.java index faafc81b2..0fbb0efeb 100644 --- a/comixed-rest-api/src/test/java/org/comixed/controller/library/ReadingListControllerTest.java +++ b/comixed-rest-api/src/test/java/org/comixed/controller/library/ReadingListControllerTest.java @@ -22,10 +22,7 @@ import static org.junit.Assert.assertSame; import java.security.Principal; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import org.comixed.model.comic.Comic; import org.comixed.model.library.ReadingList; import org.comixed.model.library.ReadingListEntry; @@ -55,6 +52,7 @@ public class ReadingListControllerTest { private static final Long TEST_COMIC_ID_3 = 1002L; private static final Long TEST_COMIC_ID_4 = 1003L; private static final Long TEST_COMIC_ID_5 = 1004L; + private static final Date TEST_LAST_UPDATED_DATE = new Date(); static { TEST_READING_LIST_ENTRIES.add(TEST_COMIC_ID_1); @@ -105,15 +103,17 @@ public void testCreateReadingList() @Test public void testGetReadingListsForUser() { Mockito.when(principal.getName()).thenReturn(TEST_USER_EMAIL); - Mockito.when(readingListService.getReadingListsForUser(Mockito.anyString())) + Mockito.when( + readingListService.getReadingListsForUser(Mockito.anyString(), Mockito.any(Date.class))) .thenReturn(readingLists); - List result = controller.getReadingListsForUser(principal); + List result = controller.getReadingListsForUser(principal, TEST_LAST_UPDATED_DATE); assertNotNull(result); assertSame(readingLists, result); - Mockito.verify(readingListService, Mockito.times(1)).getReadingListsForUser(TEST_USER_EMAIL); + Mockito.verify(readingListService, Mockito.times(1)) + .getReadingListsForUser(TEST_USER_EMAIL, TEST_LAST_UPDATED_DATE); Mockito.verify(principal, Mockito.atLeast(1)).getName(); } diff --git a/comixed-rest-api/src/test/java/org/comixed/controller/opds/OPDSControllerTest.java b/comixed-rest-api/src/test/java/org/comixed/controller/opds/OPDSControllerTest.java index a213b7506..eed36e5c6 100644 --- a/comixed-rest-api/src/test/java/org/comixed/controller/opds/OPDSControllerTest.java +++ b/comixed-rest-api/src/test/java/org/comixed/controller/opds/OPDSControllerTest.java @@ -24,6 +24,7 @@ import java.security.Principal; import java.text.ParseException; import java.util.ArrayList; +import java.util.Date; import java.util.List; import org.comixed.model.comic.Comic; import org.comixed.model.library.ReadingList; @@ -97,7 +98,8 @@ public void testGetAllLists() throws ParseException { Mockito.when(autentication.getName()).thenReturn(TEST_USER_EMAIL); Mockito.when(securityContext.getAuthentication()).thenReturn(autentication); BDDMockito.given(SecurityContextHolder.getContext()).willReturn(securityContext); - Mockito.when(readingListService.getReadingListsForUser(TEST_USER_EMAIL)) + Mockito.when( + readingListService.getReadingListsForUser(Mockito.anyString(), Mockito.any(Date.class))) .thenReturn(readingLists); OPDSFeed result = controller.getAllLists(); diff --git a/comixed-services/src/main/java/org/comixed/service/library/ReadingListService.java b/comixed-services/src/main/java/org/comixed/service/library/ReadingListService.java index 3ea310df8..152703fbb 100644 --- a/comixed-services/src/main/java/org/comixed/service/library/ReadingListService.java +++ b/comixed-services/src/main/java/org/comixed/service/library/ReadingListService.java @@ -83,13 +83,13 @@ private void loadComics(final List entries, final ReadingList readingList) } } - public List getReadingListsForUser(final String email) { - this.log.debug("Getting reading lists for user: email={}", email); + public List getReadingListsForUser(final String email, final Date lastUpdated) { + this.log.debug("Getting reading lists for user: email={} updated after={}", email, lastUpdated); this.log.debug("Getting owner"); final ComiXedUser owner = this.userRepository.findByEmail(email); - return this.readingListRepository.findAllReadingListsForUser(owner); + return this.readingListRepository.getAllReadingListsForOwnerUpdatedAfter(owner, lastUpdated); } @Transactional diff --git a/comixed-services/src/test/java/org/comixed/service/library/ReadingListServiceTest.java b/comixed-services/src/test/java/org/comixed/service/library/ReadingListServiceTest.java index 49111e12d..6e5901253 100644 --- a/comixed-services/src/test/java/org/comixed/service/library/ReadingListServiceTest.java +++ b/comixed-services/src/test/java/org/comixed/service/library/ReadingListServiceTest.java @@ -51,6 +51,7 @@ public class ReadingListServiceTest { private static final Long TEST_COMIC_ID_5 = 1004L; private static final Long TEST_USER_ID = 17L; private static final Long TEST_OTHER_USER_ID = 29L; + private static final Date TEST_LAST_UPDATED_DATE = new Date(); static { TEST_READING_LIST_ENTRIES.add(TEST_COMIC_ID_1); @@ -135,16 +136,20 @@ public void testCreateReadingListName() @Test public void testGetReadingListsForUser() { Mockito.when(userRepository.findByEmail(Mockito.anyString())).thenReturn(user); - Mockito.when(readingListRepository.findAllReadingListsForUser(Mockito.any(ComiXedUser.class))) + Mockito.when( + readingListRepository.getAllReadingListsForOwnerUpdatedAfter( + Mockito.any(ComiXedUser.class), Mockito.any(Date.class))) .thenReturn(readingLists); - List result = readingListService.getReadingListsForUser(TEST_USER_EMAIL); + List result = + readingListService.getReadingListsForUser(TEST_USER_EMAIL, TEST_LAST_UPDATED_DATE); assertNotNull(result); assertSame(readingLists, result); Mockito.verify(userRepository, Mockito.times(1)).findByEmail(TEST_USER_EMAIL); - Mockito.verify(readingListRepository, Mockito.times(1)).findAllReadingListsForUser(user); + Mockito.verify(readingListRepository, Mockito.times(1)) + .getAllReadingListsForOwnerUpdatedAfter(user, TEST_LAST_UPDATED_DATE); } @Test(expected = NoSuchReadingListException.class)