Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added ComicVineGetIssuesAction [#301]
- Loading branch information
Showing
3 changed files
with
259 additions
and
0 deletions.
There are no files selected for viewing
111 changes: 111 additions & 0 deletions
111
...rapers/src/main/java/org/comixed/scrapers/comicvine/actions/ComicVineGetIssuesAction.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
/* | ||
* 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.scrapers.comicvine.actions; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import lombok.Getter; | ||
import lombok.Setter; | ||
import lombok.extern.log4j.Log4j2; | ||
import org.comixed.scrapers.ScrapingException; | ||
import org.comixed.scrapers.comicvine.model.ComicVineIssue; | ||
import org.comixed.scrapers.comicvine.model.ComicVineIssuesQueryResponse; | ||
import org.comixed.scrapers.model.ScrapingIssue; | ||
import org.springframework.beans.factory.config.ConfigurableBeanFactory; | ||
import org.springframework.context.annotation.Scope; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.util.StringUtils; | ||
import org.springframework.web.reactive.function.client.WebClient; | ||
import reactor.core.publisher.Mono; | ||
|
||
/** | ||
* <code>ComicVineGetIssuesAction</code> retrieves the list of issues for a given comic volume. | ||
* | ||
* @author Darryl L. Pierce | ||
*/ | ||
@Component | ||
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) | ||
@Log4j2 | ||
public class ComicVineGetIssuesAction extends AbstractComicVineScrapingAction<List<ScrapingIssue>> { | ||
@Getter @Setter private Integer volumeId; | ||
@Getter @Setter private String issueNumber; | ||
|
||
@Override | ||
public List<ScrapingIssue> execute() throws ScrapingException { | ||
if (StringUtils.isEmpty(this.getApiKey())) throw new ScrapingException("Missing API key"); | ||
if (this.volumeId == null) throw new ScrapingException("Missing volume id"); | ||
|
||
this.addField("id"); | ||
this.addField("volume"); | ||
this.addField("issue_number"); | ||
this.addField("cover_date"); | ||
this.addField("store_date"); | ||
this.addField("description"); | ||
this.addField("image"); | ||
|
||
this.addFilter("volume", String.valueOf(this.volumeId)); | ||
this.addFilter("issue_number", this.issueNumber); | ||
|
||
List<ScrapingIssue> result = new ArrayList<>(); | ||
boolean done = false; | ||
while (!done) { | ||
log.debug( | ||
"Creating url for: API key=****{} volume id={}", this.getMaskedApiKey(), this.volumeId); | ||
final String url = this.createUrl(this.baseUrl, "issues"); | ||
final WebClient client = this.createWebClient(url); | ||
|
||
final Mono<ComicVineIssuesQueryResponse> request = | ||
client.get().uri(url).retrieve().bodyToMono(ComicVineIssuesQueryResponse.class); | ||
|
||
ComicVineIssuesQueryResponse response = null; | ||
|
||
try { | ||
response = request.block(); | ||
} catch (Exception error) { | ||
throw new ScrapingException("Failed to get response", error); | ||
} | ||
|
||
log.debug( | ||
"Received: {} issue{}", | ||
response.getIssues().size(), | ||
response.getIssues().size() == 1 ? "" : "s"); | ||
|
||
for (int index = 0; index < response.getIssues().size(); index++) { | ||
final ComicVineIssue issue = response.getIssues().get(index); | ||
final ScrapingIssue entry = new ScrapingIssue(); | ||
entry.setIssueNumber(issue.getIssueNumber()); | ||
entry.setId(issue.getId().intValue()); | ||
entry.setVolumeId(issue.getVolume().getId()); | ||
entry.setName(issue.getVolume().getName()); | ||
entry.setVolumeName(issue.getVolume().getName()); | ||
entry.setDescription(issue.getDescription()); | ||
entry.setCoverDate(issue.getCoverDate()); | ||
entry.setStoreDate(issue.getStoreDate()); | ||
entry.setCoverUrl(issue.getImage().getMediumUrl()); | ||
result.add(entry); | ||
} | ||
|
||
done = | ||
response.getOffset() + response.getNumberOfPageResults() | ||
>= response.getNumberOfTotalResults(); | ||
} | ||
|
||
return result; | ||
} | ||
} |
44 changes: 44 additions & 0 deletions
44
...pers/src/main/java/org/comixed/scrapers/comicvine/model/ComicVineIssuesQueryResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/* | ||
* 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.scrapers.comicvine.model; | ||
|
||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||
import com.fasterxml.jackson.annotation.JsonInclude; | ||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import lombok.Data; | ||
import lombok.Getter; | ||
import lombok.experimental.Accessors; | ||
|
||
/** | ||
* <code>ComicVineIssuesQueryResponse</code> represents the payload of an issues request with | ||
* ComicVine. | ||
* | ||
* @author Darryl L. Pierce | ||
*/ | ||
@Data | ||
@Accessors(chain = true) | ||
@JsonInclude(value = JsonInclude.Include.NON_NULL) | ||
@JsonIgnoreProperties(ignoreUnknown = true) | ||
public class ComicVineIssuesQueryResponse extends AbstractComicVineQueryResponse { | ||
@JsonProperty("results") | ||
@Getter | ||
private List<ComicVineIssue> issues = new ArrayList<>(); | ||
} |
104 changes: 104 additions & 0 deletions
104
...rs/src/test/java/org/comixed/scrapers/comicvine/actions/ComicVineGetIssuesActionTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
/* | ||
* 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.scrapers.comicvine.actions; | ||
|
||
import static junit.framework.TestCase.assertFalse; | ||
import static junit.framework.TestCase.assertNotNull; | ||
|
||
import java.io.IOException; | ||
import java.util.List; | ||
import java.util.Random; | ||
import okhttp3.mockwebserver.MockResponse; | ||
import okhttp3.mockwebserver.MockWebServer; | ||
import org.comixed.scrapers.ScrapingException; | ||
import org.comixed.scrapers.model.ScrapingIssue; | ||
import org.junit.After; | ||
import org.junit.Before; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.mockito.InjectMocks; | ||
import org.mockito.junit.MockitoJUnitRunner; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.MediaType; | ||
|
||
@RunWith(MockitoJUnitRunner.class) | ||
public class ComicVineGetIssuesActionTest { | ||
private static final Random RANDOM = new Random(); | ||
private static final String TEST_API_KEY = "This.is.the.test.api.key"; | ||
private static final Integer TEST_VOLUME_ID = RANDOM.nextInt(); | ||
private static final String TEST_ISSUE_NUMBER = "989"; | ||
private static final String TEST_BAD_RESPONSE_BODY = "this is not JSON"; | ||
private static final String TEST_GOOD_BODY = | ||
"{\"error\":\"OK\",\"limit\":100,\"offset\":0,\"number_of_page_results\":1,\"number_of_total_results\":1,\"status_code\":1,\"results\":[{\"cover_date\":\"2012-05-01\",\"description\":null,\"id\":421092,\"image\":{\"icon_url\":\"https:\\/\\/comicvine1.cbsistatic.com\\/uploads\\/square_avatar\\/12\\/124613\\/3227301-action%20lab%20confidential%20v1%20%282012%29%20pagecover.jpg\",\"medium_url\":\"https:\\/\\/comicvine1.cbsistatic.com\\/uploads\\/scale_medium\\/12\\/124613\\/3227301-action%20lab%20confidential%20v1%20%282012%29%20pagecover.jpg\",\"screen_url\":\"https:\\/\\/comicvine1.cbsistatic.com\\/uploads\\/screen_medium\\/12\\/124613\\/3227301-action%20lab%20confidential%20v1%20%282012%29%20pagecover.jpg\",\"screen_large_url\":\"https:\\/\\/comicvine1.cbsistatic.com\\/uploads\\/screen_kubrick\\/12\\/124613\\/3227301-action%20lab%20confidential%20v1%20%282012%29%20pagecover.jpg\",\"small_url\":\"https:\\/\\/comicvine1.cbsistatic.com\\/uploads\\/scale_small\\/12\\/124613\\/3227301-action%20lab%20confidential%20v1%20%282012%29%20pagecover.jpg\",\"super_url\":\"https:\\/\\/comicvine1.cbsistatic.com\\/uploads\\/scale_large\\/12\\/124613\\/3227301-action%20lab%20confidential%20v1%20%282012%29%20pagecover.jpg\",\"thumb_url\":\"https:\\/\\/comicvine1.cbsistatic.com\\/uploads\\/scale_avatar\\/12\\/124613\\/3227301-action%20lab%20confidential%20v1%20%282012%29%20pagecover.jpg\",\"tiny_url\":\"https:\\/\\/comicvine1.cbsistatic.com\\/uploads\\/square_mini\\/12\\/124613\\/3227301-action%20lab%20confidential%20v1%20%282012%29%20pagecover.jpg\",\"original_url\":\"https:\\/\\/comicvine1.cbsistatic.com\\/uploads\\/original\\/12\\/124613\\/3227301-action%20lab%20confidential%20v1%20%282012%29%20pagecover.jpg\",\"image_tags\":\"All Images\"},\"issue_number\":\"1\",\"store_date\":\"2012-05-05\",\"volume\":{\"api_detail_url\":\"https:\\/\\/comicvine.gamespot.com\\/api\\/volume\\/4050-66143\\/\",\"id\":66143,\"name\":\"Action Lab Confidential\",\"site_detail_url\":\"https:\\/\\/comicvine.gamespot.com\\/action-lab-confidential\\/4050-66143\\/\"}}],\"version\":\"1.0\"}"; | ||
|
||
@InjectMocks private ComicVineGetIssuesAction getIssuesAction; | ||
private MockWebServer comicVineServer; | ||
|
||
@Before | ||
public void setUp() throws IOException { | ||
comicVineServer = new MockWebServer(); | ||
comicVineServer.start(); | ||
|
||
final String hostname = String.format("http://localhost:%s", this.comicVineServer.getPort()); | ||
getIssuesAction.setBaseUrl(hostname); | ||
getIssuesAction.setApiKey(TEST_API_KEY); | ||
getIssuesAction.setVolumeId(TEST_VOLUME_ID); | ||
getIssuesAction.setIssueNumber(TEST_ISSUE_NUMBER); | ||
} | ||
|
||
@After | ||
public void tearDown() throws IOException { | ||
comicVineServer.shutdown(); | ||
} | ||
|
||
@Test(expected = ScrapingException.class) | ||
public void testExecuteWithoutApiKey() throws ScrapingException { | ||
getIssuesAction.setApiKey(""); | ||
getIssuesAction.execute(); | ||
} | ||
|
||
@Test(expected = ScrapingException.class) | ||
public void testExecuteWithoutVolumeId() throws ScrapingException { | ||
getIssuesAction.setVolumeId(null); | ||
getIssuesAction.execute(); | ||
} | ||
|
||
@Test(expected = ScrapingException.class) | ||
public void testExecuteBadResponse() throws ScrapingException { | ||
this.comicVineServer.enqueue( | ||
new MockResponse() | ||
.setBody(TEST_BAD_RESPONSE_BODY) | ||
.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)); | ||
|
||
getIssuesAction.execute(); | ||
} | ||
|
||
@Test | ||
public void testExecute() throws ScrapingException { | ||
this.comicVineServer.enqueue( | ||
new MockResponse() | ||
.setBody(TEST_GOOD_BODY) | ||
.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)); | ||
|
||
final List<ScrapingIssue> result = getIssuesAction.execute(); | ||
|
||
assertNotNull(result); | ||
assertFalse(result.isEmpty()); | ||
} | ||
} |