Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,23 @@ public ResponseEntity<byte[]> getMedia(
return new ResponseEntity<>(media.getContent(), headers, HttpStatus.OK);
}

@RequestMapping(value = "/session-overview-pdf", method = RequestMethod.GET)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GET?

public ResponseEntity<byte[]> getSessionOverviewPdf(@RequestParam(value = "sessionId") String sessionId) {
Media media;
try {
media = docScanService.createSessionOverviewPdf(sessionId);
} catch (DocScanException e) {
LOG.error(e.getMessage());
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType(media.getMimeType()));
headers.setContentDispositionFormData("attachment", "session-overview.pdf");

return new ResponseEntity<>(media.getContent(), headers, HttpStatus.OK);
}

@RequestMapping(value = "/tracked-devices", method = RequestMethod.GET)
public @ResponseBody List<MetadataResponse> getTrackedDevices(@RequestParam(value = "sessionId") String sessionId) throws DocScanException {
return docScanService.getTrackedDevices(sessionId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.yoti.api.client.docs.session.create.filters.RequiredIdDocument;
import com.yoti.api.client.docs.session.create.filters.RequiredSupplementaryDocument;
import com.yoti.api.client.docs.session.create.objective.ProofOfAddressObjective;
import com.yoti.api.client.docs.session.create.pdf.CreateSessionOverviewPdfPayload;
import com.yoti.api.client.docs.session.create.task.RequestedIdDocTextExtractionTask;
import com.yoti.api.client.docs.session.create.task.RequestedSupplementaryDocTextExtractionTask;
import com.yoti.api.client.docs.session.devicemetadata.MetadataResponse;
Expand Down Expand Up @@ -151,6 +152,16 @@ public Media getMedia(String sessionId, String mediaId) throws DocScanException
return docScanClient.getMediaContent(sessionId, mediaId);
}

public Media createSessionOverviewPdf(String sessionId) throws DocScanException {
CreateSessionOverviewPdfPayload payload = CreateSessionOverviewPdfPayload.builder()
.withIncludeImages(true)
.withIncludeExtractedText(true)
.withIncludeDeviceTracking(true)
.build();

return docScanClient.createSessionOverviewPdf(sessionId, payload);
}

public List<MetadataResponse> getTrackedDevices(String sessionId) throws DocScanException {
return docScanClient.getTrackedDevices(sessionId);
}
Expand Down
12 changes: 12 additions & 0 deletions examples/doc-scan/src/main/resources/templates/success.html
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,18 @@ <h2>
</h2>
</div>
</div>

<div class="row pt-4">
<div class="col">
<h2>
Session Overview PDF
<a th:href="${'/session-overview-pdf?sessionId=' + sessionResult.getSessionId()}">
<span class="badge badge-success" th:text="DOWNLOAD">
</span>
</a>
</h2>
</div>
</div>
</div>

<div th:replace="fragments/components :: footer"></div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.yoti.api.client.docs.session.create.SessionSpec;
import com.yoti.api.client.docs.session.create.facecapture.CreateFaceCaptureResourcePayload;
import com.yoti.api.client.docs.session.create.facecapture.UploadFaceCaptureImagePayload;
import com.yoti.api.client.docs.session.create.pdf.CreateSessionOverviewPdfPayload;
import com.yoti.api.client.docs.session.devicemetadata.MetadataResponse;
import com.yoti.api.client.docs.session.instructions.Instructions;
import com.yoti.api.client.docs.session.retrieve.CreateFaceCaptureResourceResponse;
Expand Down Expand Up @@ -141,6 +142,19 @@ public Media getIbvInstructionsPdf(String sessionId) throws DocScanException {
return docScanService.getIbvInstructionsPdf(authStrategy, sessionId);
}

/**
* Creates a PDF overview of the given session.
*
* @param sessionId the session ID
* @param createSessionOverviewPdfPayload the {@link CreateSessionOverviewPdfPayload} describing what to include
* @return the PDF media
* @throws DocScanException if an error has occurred
*/
public Media createSessionOverviewPdf(String sessionId, CreateSessionOverviewPdfPayload createSessionOverviewPdfPayload) throws DocScanException {
LOG.debug("Creating session overview PDF for session '{}'", sessionId);
return docScanService.createSessionOverviewPdf(authStrategy, sessionId, createSessionOverviewPdfPayload);
}

/**
* Fetches the associated instructions contact profile for the given In-Branch Verification session
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.yoti.api.client.docs.session.create.SessionSpec;
import com.yoti.api.client.docs.session.create.facecapture.CreateFaceCaptureResourcePayload;
import com.yoti.api.client.docs.session.create.facecapture.UploadFaceCaptureImagePayload;
import com.yoti.api.client.docs.session.create.pdf.CreateSessionOverviewPdfPayload;
import com.yoti.api.client.docs.session.devicemetadata.MetadataResponse;
import com.yoti.api.client.docs.session.instructions.Instructions;
import com.yoti.api.client.docs.session.retrieve.CreateFaceCaptureResourceResponse;
Expand Down Expand Up @@ -383,6 +384,38 @@ Media getIbvInstructionsPdf(AuthStrategy authStrategy, String sessionId) throws
}
}

Media createSessionOverviewPdf(AuthStrategy authStrategy,
String sessionId,
CreateSessionOverviewPdfPayload createSessionOverviewPdfPayload) throws DocScanException {
notNull(authStrategy, "authStrategy");
notNullOrEmpty(sessionId, "sessionId");
notNull(createSessionOverviewPdfPayload, "createSessionOverviewPdfPayload");

String path = unsignedPathFactory.createSessionOverviewPdfPath(sessionId);
LOG.info("Creating session overview PDF at '{}'", path);

try {
byte[] payload = objectMapper.writeValueAsBytes(createSessionOverviewPdfPayload);

YotiHttpRequest yotiHttpRequest = yotiHttpRequestBuilderFactory.create()
.withAuthStrategy(authStrategy)
.withBaseUrl(apiUrl)
.withEndpoint(path)
.withPayload(payload)
.withHttpMethod(HTTP_POST)
.build();
YotiHttpResponse response = yotiHttpRequest.execute();

return new MediaValue(findContentType(response), response.getResponseBody());
} catch (GeneralSecurityException ex) {
throw new DocScanException("Error signing the request: " + ex.getMessage(), ex);
} catch (ResourceException ex) {
throw new DocScanException("Error executing the POST: " + ex.getMessage(), ex);
} catch (IOException | URISyntaxException ex) {
throw new DocScanException("Error building the request: " + ex.getMessage(), ex);
}
}

SessionConfigurationResponse fetchSessionConfiguration(AuthStrategy authStrategy, String sessionId) throws DocScanException {
notNull(authStrategy, "authStrategy");
notNullOrEmpty(sessionId, "sessionId");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.yoti.api.client.docs.session.create.pdf;

import com.fasterxml.jackson.annotation.JsonProperty;

public class CreateSessionOverviewPdfPayload {

@JsonProperty("include_images")
private final Boolean includeImages;

@JsonProperty("include_extracted_text")
private final Boolean includeExtractedText;

@JsonProperty("include_device_tracking")
private final Boolean includeDeviceTracking;

private CreateSessionOverviewPdfPayload(Boolean includeImages, Boolean includeExtractedText, Boolean includeDeviceTracking) {
this.includeImages = includeImages;
this.includeExtractedText = includeExtractedText;
this.includeDeviceTracking = includeDeviceTracking;
}

public static CreateSessionOverviewPdfPayload.Builder builder() {
return new CreateSessionOverviewPdfPayload.Builder();
}

public Boolean getIncludeImages() {
return includeImages;
}

public Boolean getIncludeExtractedText() {
return includeExtractedText;
}

public Boolean getIncludeDeviceTracking() {
return includeDeviceTracking;
}

public static class Builder {

private Boolean includeImages;
private Boolean includeExtractedText;
private Boolean includeDeviceTracking;

private Builder() { }

/**
* Sets whether images should be included in the PDF.
*
* @param includeImages whether to include images
* @return the builder
*/
public Builder withIncludeImages(boolean includeImages) {
this.includeImages = includeImages;
return this;
}

/**
* Sets whether extracted text should be included in the PDF.
*
* @param includeExtractedText whether to include extracted text
* @return the builder
*/
public Builder withIncludeExtractedText(boolean includeExtractedText) {
this.includeExtractedText = includeExtractedText;
return this;
}

/**
* Sets whether device tracking information should be included in the PDF.
*
* @param includeDeviceTracking whether to include device tracking information
* @return the builder
*/
public Builder withIncludeDeviceTracking(boolean includeDeviceTracking) {
this.includeDeviceTracking = includeDeviceTracking;
return this;
}

public CreateSessionOverviewPdfPayload build() {
return new CreateSessionOverviewPdfPayload(includeImages, includeExtractedText, includeDeviceTracking);
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class UnsignedPathFactory {
private static final String DOCS_UPLOAD_FACE_CAPTURE_IMAGE = "/sessions/%s/resources/face-capture/%s/image";
private static final String DOCS_TRIGGER_IBV_NOTIFICATION = "/sessions/%s/instructions/email";
private static final String DOCS_TRACKED_DEVICES = "/sessions/%s/tracked-devices";
private static final String DOCS_SESSION_OVERVIEW_PDF = "/sessions/%s/pdf";

public String createAmlPath() {
return format(AML);
Expand Down Expand Up @@ -105,6 +106,10 @@ public String createFetchIbvInstructionsPdfPath(String sessionId) {
return format(DOCS_FETCH_IBV_INSTRUCTIONS_PDF, sessionId);
}

public String createSessionOverviewPdfPath(String sessionId) {
return format(DOCS_SESSION_OVERVIEW_PDF, sessionId);
}

public String createGetSupportedDocumentsPath(boolean includeNonLatin) {
return format(DOCS_SUPPORTED_DOCUMENTS, includeNonLatin);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import static org.mockito.Mockito.when;

import com.yoti.api.client.docs.session.create.SessionSpec;
import com.yoti.api.client.docs.session.create.pdf.CreateSessionOverviewPdfPayload;
import com.yoti.api.client.docs.session.instructions.Instructions;
import com.yoti.api.client.spi.remote.call.factory.AuthStrategy;

Expand Down Expand Up @@ -110,6 +111,17 @@ public void getIbvInstructionsPdf_shouldFailWithExceptionFromYotiDocsService() t
assertThat(exception, is(original));
}

@Test
public void createSessionOverviewPdf_shouldFailWithExceptionFromYotiDocsService() throws Exception {
CreateSessionOverviewPdfPayload payload = CreateSessionOverviewPdfPayload.builder().build();
DocScanException original = new DocScanException("Test exception");
doThrow(original).when(docScanServiceMock).createSessionOverviewPdf(authStrategyMock, SOME_SESSION_ID, payload);

DocScanException exception = assertThrows(DocScanException.class, () -> testObj.createSessionOverviewPdf(SOME_SESSION_ID, payload));

assertThat(exception, is(original));
}

@Test
public void fetchInstructionsContactProfile_shouldFailWithExceptionFromYotiDocsService() throws Exception {
DocScanException original = new DocScanException("Test exception");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import com.yoti.api.client.docs.session.create.SessionSpec;
import com.yoti.api.client.docs.session.create.facecapture.CreateFaceCaptureResourcePayload;
import com.yoti.api.client.docs.session.create.facecapture.UploadFaceCaptureImagePayload;
import com.yoti.api.client.docs.session.create.pdf.CreateSessionOverviewPdfPayload;
import com.yoti.api.client.docs.session.devicemetadata.MetadataResponse;
import com.yoti.api.client.docs.session.instructions.Instructions;
import com.yoti.api.client.docs.session.retrieve.AuthenticityCheckResponse;
Expand Down Expand Up @@ -98,6 +99,7 @@ public class DocScanServiceTest {
@Mock Instructions instructionsMock;
@Mock CreateFaceCaptureResourcePayload createFaceCaptureResourcePayloadMock;
@Mock UploadFaceCaptureImagePayload uploadFaceCaptureImagePayloadMock;
@Mock CreateSessionOverviewPdfPayload createSessionOverviewPdfPayloadMock;

@Before
public void setUp() {
Expand Down Expand Up @@ -870,6 +872,100 @@ public void getIbvInstructionsPdf_shouldReturnNullForNoContent() throws Exceptio
assertThat(result, is(nullValue()));
}

@Test
public void createSessionOverviewPdf_shouldThrowExceptionWhenAuthStrategyIsNull() {
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> docScanService.createSessionOverviewPdf(
null, SOME_SESSION_ID, createSessionOverviewPdfPayloadMock));

assertThat(ex.getMessage(), containsString("'authStrategy' must not be null."));
}

@Test
public void createSessionOverviewPdf_shouldThrowExceptionWhenSessionIdIsNull() {
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> docScanService.createSessionOverviewPdf(
authStrategyMock, null, createSessionOverviewPdfPayloadMock));

assertThat(ex.getMessage(), containsString("sessionId"));
}

@Test
public void createSessionOverviewPdf_shouldThrowExceptionWhenSessionIdIsEmpty() {
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> docScanService.createSessionOverviewPdf(
authStrategyMock, "", createSessionOverviewPdfPayloadMock));

assertThat(ex.getMessage(), containsString("sessionId"));
}

@Test
public void createSessionOverviewPdf_shouldThrowExceptionWhenPayloadIsNull() {
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> docScanService.createSessionOverviewPdf(
authStrategyMock, SOME_SESSION_ID, null));

assertThat(ex.getMessage(), containsString("createSessionOverviewPdfPayload"));
}

@Test
public void createSessionOverviewPdf_shouldWrapGeneralSecurityException() throws Exception {
GeneralSecurityException gse = new GeneralSecurityException("some gse");
when(yotiHttpRequestBuilderMock.build()).thenThrow(gse);

DocScanException ex = assertThrows(DocScanException.class, () -> docScanService.createSessionOverviewPdf(authStrategyMock, SOME_SESSION_ID, createSessionOverviewPdfPayloadMock));

assertThat(ex.getMessage(), containsString("Error signing the request: some gse"));
}

@Test
public void createSessionOverviewPdf_shouldWrapResourceException() throws Exception {
ResourceException resourceException = new ResourceException(400, "Failed Request", "Some response from API");
when(yotiHttpRequestBuilderMock.build()).thenReturn(yotiHttpRequestMock);
when(yotiHttpRequestMock.execute()).thenThrow(resourceException);

DocScanException ex = assertThrows(DocScanException.class, () -> docScanService.createSessionOverviewPdf(authStrategyMock, SOME_SESSION_ID, createSessionOverviewPdfPayloadMock));

assertThat(ex.getMessage(), containsString("Error executing the POST: Failed Request"));
}

@Test
public void createSessionOverviewPdf_shouldWrapIOException() throws Exception {
IOException ioException = new IOException("Some io exception");
when(yotiHttpRequestBuilderMock.build()).thenReturn(yotiHttpRequestMock);
when(yotiHttpRequestMock.execute()).thenThrow(ioException);

DocScanException ex = assertThrows(DocScanException.class, () -> docScanService.createSessionOverviewPdf(authStrategyMock, SOME_SESSION_ID, createSessionOverviewPdfPayloadMock));

assertThat(ex.getMessage(), containsString("Error building the request: Some io exception"));
}

@Test
public void createSessionOverviewPdf_shouldWrapURISyntaxException() throws Exception {
URISyntaxException uriSyntaxException = new URISyntaxException("someUrl", "Failed to build URI");
when(yotiHttpRequestBuilderMock.build()).thenThrow(uriSyntaxException);

DocScanException ex = assertThrows(DocScanException.class, () -> docScanService.createSessionOverviewPdf(authStrategyMock, SOME_SESSION_ID, createSessionOverviewPdfPayloadMock));

assertThat(ex.getMessage(), containsString("Error building the request: Failed to build URI: someUrl"));
}

@Test
public void createSessionOverviewPdf_shouldPostPayloadAndReturnMedia() throws Exception {
when(objectMapperMock.writeValueAsBytes(createSessionOverviewPdfPayloadMock)).thenReturn(SOME_SESSION_SPEC_BYTES);
when(yotiHttpRequestBuilderMock.build()).thenReturn(yotiHttpRequestMock);
when(yotiHttpRequestMock.execute()).thenReturn(yotiHttpResponseMock);
when(yotiHttpResponseMock.getResponseHeaders()).thenReturn(createHeadersMap(CONTENT_TYPE, "application/pdf"));
when(yotiHttpResponseMock.getResponseBody()).thenReturn(IMAGE_BODY);
when(unsignedPathFactoryMock.createSessionOverviewPdfPath(SOME_SESSION_ID)).thenReturn(SOME_PATH);

Media result = docScanService.createSessionOverviewPdf(authStrategyMock, SOME_SESSION_ID, createSessionOverviewPdfPayloadMock);

assertThat(result.getMimeType(), is("application/pdf"));
assertThat(result.getContent(), is(IMAGE_BODY));
verify(yotiHttpRequestBuilderMock).withAuthStrategy(authStrategyMock);
verify(yotiHttpRequestBuilderMock).withEndpoint(SOME_PATH);
verify(yotiHttpRequestBuilderMock).withBaseUrl(SOME_API_URL);
verify(yotiHttpRequestBuilderMock).withHttpMethod(HttpMethod.HTTP_POST);
verify(yotiHttpRequestBuilderMock).withPayload(SOME_SESSION_SPEC_BYTES);
}

@Test
public void fetchInstructionsContactProfile_shouldThrowExceptionWhenAuthStrategyIsNull() {
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> docScanService.fetchInstructionsContactProfile(null, SOME_SESSION_ID));
Expand Down
Loading
Loading