diff --git a/lib/src/main/java/org/koppe/epub/client/AuthorAdapter.java b/lib/src/main/java/org/koppe/epub/client/AuthorAdapter.java index c4650c0..64f5d23 100644 --- a/lib/src/main/java/org/koppe/epub/client/AuthorAdapter.java +++ b/lib/src/main/java/org/koppe/epub/client/AuthorAdapter.java @@ -1,11 +1,14 @@ package org.koppe.epub.client; import java.io.IOException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.koppe.epub.client.cache.CacheType; import org.koppe.epub.client.dto.AuthorDto; +import org.koppe.epub.client.dto.PagedRequestDto; import org.koppe.epub.client.exceptions.ApiCallException; import org.koppe.epub.client.exceptions.BadRequestException; import org.koppe.epub.client.exceptions.ForbiddenException; @@ -13,6 +16,8 @@ import org.koppe.epub.client.exceptions.ServerErrorException; import org.koppe.epub.client.exceptions.SessionExpiredException; import org.koppe.epub.client.exceptions.UnexpectedStatusException; +import org.koppe.epub.client.http.AuthorQueryBuilder; +import org.koppe.epub.client.http.HttpQuery; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,7 +37,14 @@ class AuthorAdapter { * Client to execute requests */ private final EpubClient client; + /** + * Object mapper + */ private final ObjectMapper mapper = new ObjectMapper(); + /** + * Executor for running parallel threads + */ + private final ExecutorService executor = Executors.newSingleThreadExecutor(); /** * Default constructor @@ -102,4 +114,180 @@ protected AuthorAdapter(EpubClient client) { return dto; } + // #region get author + /** + * Queries api for author with given id. + * + * @param jwt JWT to authenticate at the api + * @param authorId Id of the author to query + * @param query Defines attributes the api should return, for example whether + * books should be returned as well + * @return Queried author or null, if no such author exists + * @throws ApiCallException General wrapper for all unexpected api errors + * @throws SessionExpiredException If the jwt has expired + */ + protected @Nullable AuthorDto getAuthorById(@NotNull String jwt, long authorId, @Nullable HttpQuery query) + throws ApiCallException, SessionExpiredException { + if (jwt == null || jwt.isBlank()) { + logger.info("Invalid jwt given"); + throw new IllegalArgumentException("Missing jwt"); + } + + Object cached = client.checkCache(CacheType.AUTHORS, (Long) authorId); + if (cached != null && (cached instanceof AuthorDto)) { + logger.info("Author with given id already cached"); + return (AuthorDto) cached; + } + + logger.info("Retrieving authors for id {}", authorId); + Request.Builder builder = new Request.Builder() + .url(String.format("%s/authors/%s%s", client.url(), "" + authorId, + (query != null ? query.toQueryString() : ""))) + .get(); + + client.addHeaders(builder, jwt, EpubClient.APPLICATION_JSON_STRING, EpubClient.APPLICATION_JSON_STRING); + logger.debug("Executing request"); + + AuthorDto dto = null; + try { + dto = client.executeRequest(builder.build(), AuthorDto.class, query, true); + } catch (BadRequestException | ForbiddenException + | ServerErrorException | UnexpectedStatusException | IOException e) { + logger.info("Request failed with an exception", e); + throw new ApiCallException(null, e); + } catch (SessionExpiredException ex) { + logger.info("Jwt expired"); + throw ex; + } catch (NotFoundException ex) { + logger.info("Author with given id not found"); + return null; + } + + if (dto == null) { + logger.info("No author found"); + return null; + } + + client.cacheValue(CacheType.AUTHORS, dto.getId(), dto); + return dto; + } + + // #region delete author + /** + * Deletes author with given id. If deleteWithBooks is set to true, all epubs + * assoicated with the given author are deleted as well. Use with caution! + * + * @param jwt JWT to authenticate at the api with + * @param authorId Id of the author to be deleted + * @param deleteWithBooks If set to true, all epubs associated with the author + * are deleted as well. USE WITH CAUTION. + * @return The deleted author or null, if no author with given id exists + * @throws IllegalArgumentException If no jwt is given + * @throws SessionExpiredException If the session has expired + * @throws ApiCallException If an unexpected error occurred during the + * api call. + * @throws BadRequestException If the server returned 400 + */ + protected @Nullable AuthorDto deleteAuthor(@NotNull String jwt, long authorId, boolean deleteWithBooks) + throws IllegalArgumentException, SessionExpiredException, ApiCallException, BadRequestException { + if (jwt == null || jwt.isBlank()) { + logger.info("Invalid jwt given"); + throw new IllegalArgumentException("Missing jwt"); + } + + logger.info("Building query to delete author with id {}", authorId); + if (deleteWithBooks) + logger.warn("Deleting associated epubs as well"); + + HttpQuery query = new AuthorQueryBuilder().deleteEpubsAsWell(deleteWithBooks).build(); + Request.Builder builder = new Request.Builder() + .url(String.format("%s/authors/%s%s", client.url(), "" + authorId, query.toQueryString())) + .delete(); + + client.addHeaders(builder, jwt, EpubClient.APPLICATION_JSON_STRING, EpubClient.APPLICATION_JSON_STRING); + + AuthorDto dto = null; + try { + dto = client.executeRequest(builder.build(), AuthorDto.class, query, false); + } catch (SessionExpiredException e) { + logger.info("Session has expired", e); + throw e; + } catch (BadRequestException e) { + logger.info("Author has not been deleted", e); + throw e; + } catch (ForbiddenException | ServerErrorException | UnexpectedStatusException | IOException e) { + logger.info("Exception occurred while querying the api", e); + throw new ApiCallException(null, e); + } catch (NotFoundException e) { + logger.info("Author with given id does not exist"); + return null; + } + + if (dto == null) { + logger.info("No dto received"); + return null; + } + logger.info("Successfully deleted author {}", dto); + client.removeFromCache(CacheType.AUTHORS, dto.getId()); + + return dto; + } + + // #region get all authors + /** + * + * @param jwt + * @param query + * @return + * @throws IllegalArgumentException + * @throws ApiCallException + * @throws SessionExpiredException + */ + public @Nullable PagedRequestDto getAllAuthors(@NotNull String jwt, @Nullable HttpQuery query) + throws IllegalArgumentException, ApiCallException, SessionExpiredException { + if (jwt == null || jwt.isBlank()) { + logger.info("No jwt given"); + throw new IllegalArgumentException("Missing jwt"); + } + + if (query == null) { + logger.info("No query given, initialising default query"); + query = new AuthorQueryBuilder().page(0).pageSize(1000).build(); + } + + if (query.get("page") == null) + query.overwrite("page", (Long) 0L); + if (query.get("page_size") == null) + query.overwrite("page_size", (Long) 1000L); + + Request.Builder builer = new Request.Builder() + .url(String.format("%s/authors%s", client.url(), query.toQueryString())) + .get(); + client.addHeaders(builer, jwt, EpubClient.APPLICATION_JSON_STRING, EpubClient.APPLICATION_JSON_STRING); + logger.info("Querying api for all authors"); + + PagedRequestDto authors = null; + try { + authors = client.executeRequestPaged(builer.build(), AuthorDto.class, query, true); + } catch (BadRequestException | ForbiddenException | NotFoundException + | ServerErrorException | UnexpectedStatusException | IOException e) { + logger.info("Unexpected status returned by api", e); + throw new ApiCallException(null, e); + } catch (SessionExpiredException ex) { + logger.info("Session has expired"); + throw ex; + } + + if (authors == null || authors.getContent() == null) { + logger.info("No authors found"); + return null; + } + + final var finalAuthors = authors; + logger.info("Caching all authors threaded"); + executor.submit( + () -> finalAuthors.getContent().forEach(a -> client.cacheValue(CacheType.AUTHORS, a.getId(), a))); + return authors; + } + } diff --git a/lib/src/main/java/org/koppe/epub/client/EpubClient.java b/lib/src/main/java/org/koppe/epub/client/EpubClient.java index 8b1ce65..ad4e474 100644 --- a/lib/src/main/java/org/koppe/epub/client/EpubClient.java +++ b/lib/src/main/java/org/koppe/epub/client/EpubClient.java @@ -41,6 +41,7 @@ import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; +import okhttp3.ResponseBody; import tools.jackson.databind.ObjectMapper; /** @@ -1013,6 +1014,87 @@ private void uploadEpub(@NotNull String jwt, @NotNull String uploadGuid, @NotNul authors = new AuthorAdapter(this); return authors.addAuthor(jwt, author); } + // #endregion add author + + // #region get author + /** + * Returns the author with given id. Query defines what the backend should add + * into the AuthorDto (for example if epubs should be returned as well.) + * Example of getting author with id 1, as well as all epubs associated with it: + * + *
+     * {@code
+     * HttpQuery query = new AuthorQueryBuilder().withEpubs(true).build();
+     * AuthorDto dto = client.getAuthor("admin", "admin", 1L, query);
+     * }
+     * 
+ * + * @param username Username to authenticate at the api + * @param password Password to authenticate at the api + * @param authorId Id of the author to return + * @param query Query for getting author. + * @return Requested author. + * @throws IllegalArgumentException If username or password are missing + * @throws ApiCallException General api error wrapper + * @throws SessionExpiredException If client could not authenticate + */ + public @Nullable AuthorDto getAuthor(@NotNull String username, @NotNull String password, long authorId, + @Nullable HttpQuery query) throws IllegalArgumentException, ApiCallException, SessionExpiredException { + return getAuthor(getNewJwt(username, password), authorId, query); + } + + /** + * Returns the author with given id. Query defines what the backend should add + * into the AuthorDto (for example if epubs should be returned as well.) + * Requires cached credentials. + * Example of getting author with id 1, as well as all epubs associated with it: + * + *
+     * {@code
+     * HttpQuery query = new AuthorQueryBuilder().withEpubs(true).build();
+     * AuthorDto dto = client.getAuthor(1L, query);
+     * }
+     * 
+ * + * @param authorId Id of the author to return + * @param query Query for getting author. + * @return Requested author. + * @throws CacheMissException + * @throws ApiCallException General api error wrapper + * @throws SessionExpiredException If client could not authenticate + */ + public @Nullable AuthorDto getAuthor(long authorId, @Nullable HttpQuery query) + throws CacheMissException, ApiCallException, SessionExpiredException { + return getAuthor(getCurrentJwt(), authorId, query); + } + + /** + * Returns the author with given id. Query defines what the backend should add + * into the AuthorDto (for example if epubs should be returned as well.) + * Example of getting author with id 1, as well as all epubs associated with it: + * + *
+     * {@code
+     * HttpQuery query = new AuthorQueryBuilder().withEpubs(true).build();
+     * AuthorDto dto = client.getAuthor("jwt-123", 1L, query);
+     * }
+     * 
+ * + * @param jwt JWT to authenticate at the api + * @param authorId Id of the author to return + * @param query Query for getting author. + * @return Requested author. + * @throws IllegalArgumentException If username or password are missing + * @throws ApiCallException General api error wrapper + * @throws SessionExpiredException If client could not authenticate + */ + private @Nullable AuthorDto getAuthor(@NotNull String jwt, long authorId, @Nullable HttpQuery query) + throws ApiCallException, SessionExpiredException { + if (authors == null) + authors = new AuthorAdapter(this); + return authors.getAuthorById(jwt, authorId, query); + } + // #endregion get author // #region register cache /** @@ -1128,7 +1210,17 @@ private String getNewJwt(@NotNull String username, @NotNull String password) logger.info("Expecting void, returning"); return null; } - String body = response.body().string(); + ResponseBody resp = response.body(); + if (resp == null) { + logger.info("No response body"); + return null; + } + String body = resp.string(); + if (body == null || body.isBlank()) { + logger.info("No response body"); + return null; + } + dto = mapper.readValue(body, type); break; case 204: diff --git a/lib/src/main/java/org/koppe/epub/client/cache/AuthorCache.java b/lib/src/main/java/org/koppe/epub/client/cache/AuthorCache.java new file mode 100644 index 0000000..5ca510a --- /dev/null +++ b/lib/src/main/java/org/koppe/epub/client/cache/AuthorCache.java @@ -0,0 +1,7 @@ +package org.koppe.epub.client.cache; + +import org.koppe.epub.client.dto.AuthorDto; + +public class AuthorCache extends AbstractCache { + +} diff --git a/lib/src/main/java/org/koppe/epub/client/cache/CacheFactory.java b/lib/src/main/java/org/koppe/epub/client/cache/CacheFactory.java index eff8b4d..6c1116f 100644 --- a/lib/src/main/java/org/koppe/epub/client/cache/CacheFactory.java +++ b/lib/src/main/java/org/koppe/epub/client/cache/CacheFactory.java @@ -77,7 +77,16 @@ public static EditionCache newDefaultEditionCache() { case CREDENTIALS -> newDefaultCredentialCache(client); case EPUBS -> newDefaultEpubCache(); case EDITIONS -> newDefaultEditionCache(); + case AUTHORS -> newDefaultAuthorCache(); default -> null; }; } + + public static AuthorCache newDefaultAuthorCache() { + AuthorCache cache = new AuthorCache(); + cache.setRetention(10, TimeUnit.MINUTES); + cache.setMaxElements(100); + + return cache; + } } diff --git a/lib/src/main/java/org/koppe/epub/client/dto/AuthorDto.java b/lib/src/main/java/org/koppe/epub/client/dto/AuthorDto.java index f307a9f..37d5a6c 100644 --- a/lib/src/main/java/org/koppe/epub/client/dto/AuthorDto.java +++ b/lib/src/main/java/org/koppe/epub/client/dto/AuthorDto.java @@ -44,4 +44,5 @@ public class AuthorDto { private String description; private List epubs; private List tags; + private List genres; } diff --git a/lib/src/main/java/org/koppe/epub/client/http/AuthorQueryBuilder.java b/lib/src/main/java/org/koppe/epub/client/http/AuthorQueryBuilder.java new file mode 100644 index 0000000..65c7036 --- /dev/null +++ b/lib/src/main/java/org/koppe/epub/client/http/AuthorQueryBuilder.java @@ -0,0 +1,28 @@ +package org.koppe.epub.client.http; + +import lombok.NoArgsConstructor; + +/** + * Builder for queries associated with authors + */ +@NoArgsConstructor +public class AuthorQueryBuilder extends AbstractQueryBuilder { + + /** + * If set to true and given to a delete query, all epubs the given author is + * associated with are deleted as well. Use with caution! + * + * @param delete Set to true to delete all epubs associated with the given + * author as well. + * @return This builder + */ + public AuthorQueryBuilder deleteEpubsAsWell(boolean delete) { + getBuilder().addParam(Boolean.class, "with_epubs", delete); + return this; + } + + public AuthorQueryBuilder withEpubs(boolean w) { + getBuilder().addParam(Boolean.class, "with_epubs", w); + return this; + } +} diff --git a/lib/src/main/java/org/koppe/epub/client/http/EpubQueryBuilder.java b/lib/src/main/java/org/koppe/epub/client/http/EpubQueryBuilder.java index e77826e..2bac639 100644 --- a/lib/src/main/java/org/koppe/epub/client/http/EpubQueryBuilder.java +++ b/lib/src/main/java/org/koppe/epub/client/http/EpubQueryBuilder.java @@ -43,6 +43,12 @@ public EpubQueryBuilder withEditions(boolean w) { return this; } + /** + * Find all epubs which titles contain the given string. + * + * @param title Substring of the title to find + * @return This builder + */ public EpubQueryBuilder titleContains(String title) { getBuilder().addParam(String.class, "title_contains", title); return this; diff --git a/lib/src/test/java/org/koppe/epub/client/AuthorAdapterTest.java b/lib/src/test/java/org/koppe/epub/client/AuthorAdapterTest.java new file mode 100644 index 0000000..aa1ad96 --- /dev/null +++ b/lib/src/test/java/org/koppe/epub/client/AuthorAdapterTest.java @@ -0,0 +1,106 @@ +package org.koppe.epub.client; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.fail; + +import org.junit.jupiter.api.Test; +import org.koppe.epub.client.cache.CacheType; +import org.koppe.epub.client.dto.AuthorDto; +import org.koppe.epub.client.exceptions.ApiCallException; +import org.koppe.epub.client.exceptions.BadRequestException; +import org.koppe.epub.client.exceptions.SessionExpiredException; + +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; + +public class AuthorAdapterTest { + private static MockWebServer server; + private static AuthorAdapter adapter; + + @Test + public void testAddAuthorExceptions() { + server = new MockWebServer(); + adapter = new AuthorAdapter(EpubClientFactory.newCredentialCacheClient(server.url("/").toString())); + + try { + AuthorDto dto = new AuthorDto(); + dto.setFirstName("Test"); + dto.setSurname("Test"); + + assertThrows(IllegalArgumentException.class, () -> adapter.addAuthor(null, null)); + assertThrows(IllegalArgumentException.class, () -> adapter.addAuthor(" ", null)); + + server.enqueue(new MockResponse().setResponseCode(401)); + assertThrows(SessionExpiredException.class, () -> adapter.addAuthor("fake-jwt-123", dto)); + + server.enqueue(new MockResponse().setResponseCode(400)); + assertThrows(BadRequestException.class, () -> adapter.addAuthor("fake-jwt-123", dto)); + + server.enqueue(new MockResponse().setResponseCode(403)); + assertThrows(ApiCallException.class, () -> adapter.addAuthor("fake-jwt-123", dto)); + + server.enqueue(new MockResponse().setResponseCode(404)); + assertThrows(ApiCallException.class, () -> adapter.addAuthor("fake-jwt-123", dto)); + + server.enqueue(new MockResponse().setResponseCode(500)); + assertThrows(ApiCallException.class, () -> adapter.addAuthor("fake-jwt-123", dto)); + + server.enqueue(new MockResponse().setResponseCode(503)); + assertThrows(ApiCallException.class, () -> adapter.addAuthor("fake-jwt-123", dto)); + + server.enqueue(new MockResponse().setResponseCode(200)); + assertNull(adapter.addAuthor("fake-jwt-123", dto)); + + } catch (Exception ex) { + fail(); + } + } + + @Test + public void testGetAuthor() { + server = new MockWebServer(); + EpubClient client = EpubClientFactory.newCachingClient(server.url("/").toString(), + new CacheType[] { CacheType.AUTHORS, CacheType.CREDENTIALS }); + adapter = new AuthorAdapter(EpubClientFactory.newCredentialCacheClient(server.url("/").toString())); + + try { + assertThrows(IllegalArgumentException.class, () -> adapter.getAuthorById(null, 1L, null)); + assertThrows(IllegalArgumentException.class, () -> adapter.getAuthorById(" ", 1L, null)); + + server.enqueue(new MockResponse().setResponseCode(401)); + assertThrows(SessionExpiredException.class, () -> adapter.getAuthorById("fake-jwt-123", 1L, null)); + + server.enqueue(new MockResponse().setResponseCode(400)); + assertThrows(ApiCallException.class, () -> adapter.getAuthorById("fake-jwt-123", 1L, null)); + + server.enqueue(new MockResponse().setResponseCode(403)); + assertThrows(ApiCallException.class, () -> adapter.getAuthorById("fake-jwt-123", 1L, null)); + + server.enqueue(new MockResponse().setResponseCode(500)); + assertThrows(ApiCallException.class, () -> adapter.getAuthorById("fake-jwt-123", 1L, null)); + + server.enqueue(new MockResponse().setResponseCode(503)); + assertThrows(ApiCallException.class, () -> adapter.getAuthorById("fake-jwt-123", 1L, null)); + + server.enqueue(new MockResponse().setResponseCode(404)); + assertNull(adapter.getAuthorById("fake-jwt-123", 1L, null)); + + server.enqueue(new MockResponse().setResponseCode(200)); + assertNull(adapter.getAuthorById("fake-jwt-123", 1L, null)); + + AuthorDto dto = new AuthorDto(); + dto.setId(1L); + client.cacheValue(CacheType.AUTHORS, (Long) 1L, dto); + + client.cacheValue(CacheType.CREDENTIALS, "jwt", "123"); + client.cacheValue(CacheType.CREDENTIALS, "username", "123"); + client.cacheValue(CacheType.CREDENTIALS, "password", "123"); + client.cacheValue(CacheType.CREDENTIALS, "refresh", "123"); + assertEquals(dto, client.getAuthor(1L, null)); + } catch (Exception ex) { + fail(); + } + } +} diff --git a/lib/src/test/java/org/koppe/epub/client/DtoRecord.java b/lib/src/test/java/org/koppe/epub/client/DtoRecord.java index bb2e34c..9bdaa90 100644 --- a/lib/src/test/java/org/koppe/epub/client/DtoRecord.java +++ b/lib/src/test/java/org/koppe/epub/client/DtoRecord.java @@ -3,9 +3,11 @@ import java.time.LocalDate; import java.util.UUID; +import org.koppe.epub.client.dto.AuthorDto; import org.koppe.epub.client.dto.CredentialDto; import org.koppe.epub.client.dto.EpubDto; import org.koppe.epub.client.dto.EpubEditionDto; +import org.koppe.epub.client.dto.GenreDto; import lombok.Getter; @@ -24,5 +26,14 @@ class DtoRecord { static final EpubEditionDto edition1 = new EpubEditionDto(1L, "edition 1", 1, UUID.randomUUID().toString(), UUID.randomUUID().toString(), null); - + + static final AuthorDto author1 = new AuthorDto(1L, "Test", "Test", LocalDate.of(2000, 1, 1), + LocalDate.of(2000, 1, 1), "Test author", null, null, null); + + static final AuthorDto author2 = new AuthorDto(2L, "Test2", "Test2", LocalDate.of(2000, 1, 1), + LocalDate.of(2000, 1, 1), "Test author 2", null, null, null); + + static final GenreDto genre1 = new GenreDto(1L); + + static final GenreDto genre2 = new GenreDto(2L); } diff --git a/lib/src/test/java/org/koppe/epub/client/EpubClientCommunicationTest.java b/lib/src/test/java/org/koppe/epub/client/EpubClientCommunicationTest.java index c4386d8..e5edd32 100644 --- a/lib/src/test/java/org/koppe/epub/client/EpubClientCommunicationTest.java +++ b/lib/src/test/java/org/koppe/epub/client/EpubClientCommunicationTest.java @@ -1,16 +1,18 @@ package org.koppe.epub.client; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.io.File; import java.io.IOException; import java.time.LocalDate; import org.junit.jupiter.api.Test; +import org.koppe.epub.client.dto.AuthorDto; import org.koppe.epub.client.dto.CredentialDto; import org.koppe.epub.client.dto.EpubDto; import org.koppe.epub.client.dto.EpubEditionDto; @@ -24,6 +26,7 @@ import org.koppe.epub.client.exceptions.ServerErrorException; import org.koppe.epub.client.exceptions.SessionExpiredException; import org.koppe.epub.client.exceptions.UnexpectedStatusException; +import org.koppe.epub.client.http.AuthorQueryBuilder; import org.koppe.epub.client.http.EpubQueryBuilder; import okhttp3.Request; @@ -386,4 +389,66 @@ public void testUpload() { fail(); } } + + // #region add author + @Test + public void testAddAuthor() { + server.setDispatcher(new MockDispatcher()); + EpubClient client = EpubClientFactory.newCredentialCacheClient(server.url("/").toString()); + + assertThrows(IllegalArgumentException.class, () -> client.addAuthor(null, null, null)); + assertThrows(IllegalArgumentException.class, () -> client.addAuthor("", null, null)); + assertThrows(IllegalArgumentException.class, () -> client.addAuthor(null, "", null)); + assertThrows(IllegalArgumentException.class, () -> client.addAuthor("admin", "admin", null)); + + AuthorDto toAdd = new AuthorDto(); + assertThrows(IllegalArgumentException.class, () -> client.addAuthor("admin", "admin", toAdd)); + + toAdd.setFirstName(" "); + assertThrows(IllegalArgumentException.class, () -> client.addAuthor(toAdd)); + + toAdd.setFirstName("Test"); + assertThrows(IllegalArgumentException.class, () -> client.addAuthor(toAdd)); + + toAdd.setSurname(" "); + assertThrows(IllegalArgumentException.class, () -> client.addAuthor(toAdd)); + + toAdd.setSurname("Test"); + AuthorDto added = null; + + try { + added = client.addAuthor(toAdd); + } catch (IllegalArgumentException | ApiCallException | SessionExpiredException | BadRequestException + | CacheMissException e) { + fail(); + } + + assertNotNull(added); + assertEquals(toAdd.getFirstName(), added.getFirstName()); + assertEquals(toAdd.getSurname(), added.getSurname()); + assertNotNull(added.getId()); + } + + @Test + public void testGetAuthor() { + server.setDispatcher(new MockDispatcher()); + EpubClient client = EpubClientFactory.newCredentialCacheClient(server.url("/").toString()); + + try { + AuthorDto a3 = client.getAuthor("admin", "admin", 3L, null); + assertNull(a3); + + AuthorDto a1 = client.getAuthor(1L, new AuthorQueryBuilder().withEpubs(true).withGenres(true).build()); + AuthorDto a2 = client.getAuthor(2L, null); + + assertEquals((Long) 1L, a1.getId()); + assertEquals("Test", a1.getFirstName()); + assertTrue(a1.getEpubs().size() > 0); + assertNotNull(a2); + assertEquals("Test2", a2.getFirstName()); + assertTrue(a2.getEpubs().size() == 0); + } catch (Exception ex) { + fail(); + } + } } diff --git a/lib/src/test/java/org/koppe/epub/client/MockDispatcher.java b/lib/src/test/java/org/koppe/epub/client/MockDispatcher.java index 3ec378f..11e3ddd 100644 --- a/lib/src/test/java/org/koppe/epub/client/MockDispatcher.java +++ b/lib/src/test/java/org/koppe/epub/client/MockDispatcher.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.UUID; +import org.koppe.epub.client.dto.AuthorDto; import org.koppe.epub.client.dto.EpubDto; import org.koppe.epub.client.dto.EpubEditionDto; import org.koppe.epub.client.dto.PagedRequestDto; @@ -73,6 +74,20 @@ public MockResponse dispatch(RecordedRequest request) throws InterruptedExceptio default: return new MockResponse().setResponseCode(403); } + case "/authors": + switch (request.getMethod()) { + case "POST": + return addAuthor(request); + default: + return new MockResponse().setResponseCode(403); + } + case "/authors/1", "/authors/2": + switch (request.getMethod()) { + case "GET": + return getAuthor(request); + default: + return new MockResponse().setResponseCode(403); + } default: return new MockResponse().setResponseCode(404); } @@ -236,6 +251,50 @@ private MockResponse upload(RecordedRequest r) { return new MockResponse().setResponseCode(400); } + // #region add author + private MockResponse addAuthor(RecordedRequest r) { + AuthorDto dto = getBody(r.getBody(), AuthorDto.class); + if (dto == null) { + return new MockResponse().setResponseCode(400); + } + + if (dto.getFirstName() == null || dto.getFirstName().isBlank() || dto.getSurname() == null + || dto.getSurname().isBlank()) { + return new MockResponse().setResponseCode(400); + } + + dto.setId((long) Math.floor(Math.random() * 100.0) + 1); + return new MockResponse().setResponseCode(200).setBody(mapper.writeValueAsString(dto)); + } + + // #region get author + private MockResponse getAuthor(RecordedRequest r) { + AuthorDto dto = r.getPath().contains("1") ? DtoRecord.author1 : DtoRecord.author2; + + if (r.getRequestUrl().queryParameter("with_epubs") == null + || r.getRequestUrl().queryParameter("with_epubs").equals("false")) + dto.setEpubs(new ArrayList<>()); + else if (r.getRequestUrl().queryParameter("with_epubs").equals("true")) { + dto.setEpubs(List.of(DtoRecord.epub1, DtoRecord.epub2)); + } + + if (r.getRequestUrl().queryParameter("with_genres") == null + || r.getRequestUrl().queryParameter("with_genres").equals("false")) + dto.setGenres(new ArrayList<>()); + else if (r.getRequestUrl().queryParameter("with_genres").equals("true")) { + dto.setGenres(List.of(DtoRecord.genre1, DtoRecord.genre2)); + } + + if (r.getRequestUrl().queryParameter("with_tags") == null + || r.getRequestUrl().queryParameter("with_tags").equals("false")) + dto.setGenres(new ArrayList<>()); + else if (r.getRequestUrl().queryParameter("with_tags").equals("true")) { + dto.setGenres(new ArrayList<>()); + } + + return new MockResponse().setResponseCode(200).setBody(mapper.writeValueAsString(dto)); + } + // #region get body private T getBody(Buffer buffer, Class expected) { try {