From 26eb5f3473df12cbc49c82d8357234ff17572a83 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Mon, 13 Feb 2023 12:19:26 +0000 Subject: [PATCH 01/17] Make request and interface --- .../learning/xapi/client/DeleteStateRequest.java | 2 +- .../xapi/client/DeleteStatesRequest.java | 2 +- .../learning/xapi/client/GetStateRequest.java | 2 +- .../learning/xapi/client/GetStatesRequest.java | 4 ++-- .../learning/xapi/client/PostStateRequest.java | 2 +- .../learning/xapi/client/PutStateRequest.java | 2 +- .../java/dev/learning/xapi/client/Request.java | 16 +++------------- .../dev/learning/xapi/client/StateRequest.java | 2 +- .../dev/learning/xapi/client/StatesRequest.java | 7 +++---- 9 files changed, 14 insertions(+), 25 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java index 0f89fcf9..29642267 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStateRequest.java @@ -20,7 +20,7 @@ public class DeleteStateRequest extends StateRequest { @Override - protected HttpMethod getMethod() { + public HttpMethod getMethod() { return HttpMethod.DELETE; } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java index 34fbefed..b0ab28d7 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/DeleteStatesRequest.java @@ -20,7 +20,7 @@ public class DeleteStatesRequest extends StatesRequest { @Override - protected HttpMethod getMethod() { + public HttpMethod getMethod() { return HttpMethod.DELETE; } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java index 097e31ad..24f5e666 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStateRequest.java @@ -20,7 +20,7 @@ public class GetStateRequest extends StateRequest { @Override - protected HttpMethod getMethod() { + public HttpMethod getMethod() { return HttpMethod.GET; } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java index a3163192..ef6abaf1 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatesRequest.java @@ -31,12 +31,12 @@ public class GetStatesRequest extends StatesRequest { private final Instant since; @Override - protected HttpMethod getMethod() { + public HttpMethod getMethod() { return HttpMethod.GET; } @Override - protected UriBuilder url(UriBuilder uriBuilder, Map queryParams) { + public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { return super.url(uriBuilder, queryParams).queryParamIfPresent("since", Optional.ofNullable(since)); diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java index 81f04638..8298bfd2 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PostStateRequest.java @@ -37,7 +37,7 @@ public class PostStateRequest extends StateRequest { private final Object state; @Override - protected HttpMethod getMethod() { + public HttpMethod getMethod() { return HttpMethod.POST; } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java index db8c08a7..a5b791ed 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PutStateRequest.java @@ -34,7 +34,7 @@ public class PutStateRequest extends StateRequest { private final Object state; @Override - protected HttpMethod getMethod() { + public HttpMethod getMethod() { return HttpMethod.PUT; } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java index 70c0a53a..a36acadf 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/Request.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/Request.java @@ -5,7 +5,6 @@ package dev.learning.xapi.client; import java.util.Map; -import lombok.experimental.SuperBuilder; import org.springframework.http.HttpMethod; import org.springframework.web.util.UriBuilder; @@ -14,25 +13,16 @@ * * @author István Rátkai (Selindek) */ -@SuperBuilder -abstract class Request { +interface Request { - protected abstract UriBuilder url(UriBuilder uriBuilder, Map queryParams); + UriBuilder url(UriBuilder uriBuilder, Map queryParams); /** * The request method. * * @return the request method as a {@link HttpMethod} object. */ - protected abstract HttpMethod getMethod(); + HttpMethod getMethod(); - /** - * Builder for Request. - */ - public abstract static class Builder> { - - // This static class extends the lombok builder. - - } } diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java index f08df53d..bc8f2470 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StateRequest.java @@ -26,7 +26,7 @@ abstract class StateRequest extends StatesRequest { private final String stateId; @Override - protected UriBuilder url(UriBuilder uriBuilder, Map queryParams) { + public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { queryParams.put("stateId", stateId); diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java index bf9b6cb0..9235e38b 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/StatesRequest.java @@ -28,7 +28,7 @@ */ @SuperBuilder @Getter -abstract class StatesRequest extends Request { +abstract class StatesRequest implements Request { private static final ObjectMapper objectMapper = new ObjectMapper(); @@ -50,7 +50,7 @@ abstract class StatesRequest extends Request { private final UUID registration; @Override - protected UriBuilder url(UriBuilder uriBuilder, Map queryParams) { + public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { queryParams.put("activityId", activityId); queryParams.put("agent", agentToJsonString()); @@ -79,8 +79,7 @@ private String agentToJsonString() { /** * Builder for StatesRequest. */ - public abstract static class Builder> - extends Request.Builder { + public abstract static class Builder> { /** * Consumer Builder for agent. From ca8dd15779056c0522c5a44110979003882cd0a6 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Tue, 14 Feb 2023 18:12:09 +0000 Subject: [PATCH 02/17] tip --- pom.xml | 26 -- .../xapi/client/GetStatementsRequest.java | 277 ++++++++++++++++++ .../dev/learning/xapi/client/XapiClient.java | 98 +++++++ .../learning/xapi/client/XapiClientTests.java | 251 +++++++++++++++- .../learning/xapi/model/StatementFormat.java | 36 +++ 5 files changed, 661 insertions(+), 27 deletions(-) create mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/GetStatementsRequest.java create mode 100644 xapi-model/src/main/java/dev/learning/xapi/model/StatementFormat.java diff --git a/pom.xml b/pom.xml index 5cbd14cb..95c78302 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,6 @@ xAPI Build learning.dev xAPI Build https://github.com/BerryCloud/xapi-java - 17 0.8.8 @@ -22,19 +21,16 @@ 10.6.0 1.0.0 - Berry Cloud Ltd https://berrycloud.co.uk - Apache License, Version 2.0 https://www.apache.org/licenses/LICENSE-2.0 - thomas_turrell @@ -66,29 +62,24 @@ - https://github.com/BerryCloud/xapi-java scm:git:https://github.com/BerryCloud/xapi-java.git scm:git:https://github.com/BerryCloud/xapi-java.git HEAD - GitHub Issues https://github.com/BerryCloud/xapi-java/issues - GitHub Actions https://github.com/BerryCloud/xapi-java/actions - xapi-model xapi-client - @@ -97,7 +88,6 @@ maven-checkstyle-plugin ${maven-checkstyle-plugin.version} - org.apache.maven.plugins maven-failsafe-plugin @@ -110,7 +100,6 @@ - org.apache.maven.plugins maven-source-plugin @@ -123,7 +112,6 @@ - org.apache.maven.plugins maven-javadoc-plugin @@ -136,7 +124,6 @@ - org.apache.maven.plugins maven-gpg-plugin @@ -158,7 +145,6 @@ - org.jacoco jacoco-maven-plugin @@ -190,7 +176,6 @@ - org.sonatype.plugins nexus-staging-maven-plugin @@ -202,8 +187,6 @@ true - - org.eclipse.m2e lifecycle-mapping @@ -238,7 +221,6 @@ - org.apache.maven.plugins @@ -259,7 +241,6 @@ - org.apache.maven.plugins maven-release-plugin @@ -273,7 +254,6 @@ - @@ -283,7 +263,6 @@ - ossrh @@ -294,7 +273,6 @@ https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ - release @@ -304,17 +282,14 @@ org.apache.maven.plugins maven-source-plugin - org.apache.maven.plugins maven-javadoc-plugin - org.apache.maven.plugins maven-gpg-plugin - org.sonatype.plugins nexus-staging-maven-plugin @@ -323,5 +298,4 @@ - diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementsRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementsRequest.java new file mode 100644 index 00000000..36436d3b --- /dev/null +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementsRequest.java @@ -0,0 +1,277 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ + +package dev.learning.xapi.client; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import dev.learning.xapi.model.Agent; +import dev.learning.xapi.model.StatementFormat; +import java.net.URI; +import java.time.Instant; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.function.Consumer; +import lombok.Builder; +import lombok.Getter; +import org.springframework.http.HttpMethod; +import org.springframework.web.util.UriBuilder; + +/** + * Request for getting multiple State documents. + * + * @see Multiple + * State Document GET + * + * @author István Rátkai (Selindek) + */ +@Builder +@Getter +public class GetStatementsRequest implements Request { + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private final Agent agent; + + private final URI verb; + + private final URI activity; + + private final UUID registration; + + private final Boolean relatedActivities; + + private final Boolean relatedAgents; + + private final Instant since; + + private final Instant until; + + private final Integer limit; + + private final StatementFormat format; + + private final Boolean attachments; + + private final Boolean ascending; + + @Override + public HttpMethod getMethod() { + return HttpMethod.GET; + } + + @Override + public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { + + // All queryParams are optional + + uriBuilder.path("statements"); + + if (agent != null) { + queryParams.put("agent", agentToJsonString()); + uriBuilder.queryParam("verb", "{agent}"); + } + + if (verb != null) { + queryParams.put("verb", verb); + uriBuilder.queryParam("verb", "{verb}"); + } + + if (verb != null) { + queryParams.put("activity", activity); + uriBuilder.queryParam("activity", "{activity}"); + } + + if (since != null) { + queryParams.put("since ", since); + uriBuilder.queryParam("since ", "{since}"); + } + + if (since != null) { + queryParams.put("until ", until); + uriBuilder.queryParam("until ", "{until}"); + } + + return uriBuilder + + .queryParamIfPresent("agent", templateIfParamPresent("{agent}", agent)) + + .queryParamIfPresent("verb", templateIfParamPresent("{verb}", verb)) + + .queryParamIfPresent("activity", templateIfParamPresent("{activity}", activity)) + + .queryParamIfPresent("registration", Optional.ofNullable(registration)) + + .queryParamIfPresent("related_activities", Optional.ofNullable(relatedActivities)) + + .queryParamIfPresent("related_agents", Optional.ofNullable(relatedAgents)) + + .queryParamIfPresent("since", templateIfParamPresent("{since}", since)) + + .queryParamIfPresent("until", templateIfParamPresent("{until}", until)) + + .queryParamIfPresent("limit", Optional.ofNullable(limit)) + + .queryParamIfPresent("format", Optional.ofNullable(format)) + + .queryParamIfPresent("attachments", Optional.ofNullable(attachments)) + + .queryParamIfPresent("ascending", Optional.ofNullable(ascending)); + + } + + private Optional templateIfParamPresent(String template, Object value) { + + if (value == null) { + return Optional.empty(); + } + + return Optional.of(template); + } + + /** + * Builder for Verb. + */ + public static class Builder { + + + /** + * Sets the agent. + * + * @param agent The agent of the GetStatementRequest. + * + * @return This builder + * + * @see GetStatementsRequest#agent + */ + public Builder agent(Agent agent) { + this.agent = agent; + return this; + } + + /** + * Sets the agent. + * + * @param agent The agent of the GetStatementRequest. + * + * @return This builder + * + * @see GetStatementsRequest#agent + */ + public Builder agent(Consumer> agent) { + + final Agent.Builder builder = Agent.builder(); + + agent.accept(builder); + + return agent(builder.build()); + } + + /** + * Sets the verb. + * + * @param verb The verb of the GetStatementRequest. + * + * @return This builder + * + * @see GetStatementsRequest#verb + */ + public Builder verb(URI verb) { + this.verb = verb; + return this; + } + + /** + * Sets the verb. + * + * @param verb The verb of the GetStatementRequest. + * + * @return This builder + * + * @see GetStatementsRequest#verb + */ + public Builder verb(String verb) { + this.verb = URI.create(verb); + return this; + } + + /** + * Sets the activity. + * + * @param activity The activity of the GetStatementRequest. + * + * @return This builder + * + * @see GetStatementsRequest#activity + */ + public Builder activity(URI activity) { + this.activity = activity; + return this; + } + + /** + * Sets the activity. + * + * @param activity The activity of the GetStatementRequest. + * + * @return This builder + * + * @see GetStatementsRequest#activity + */ + public Builder activity(String activity) { + this.activity = URI.create(activity); + return this; + } + + + + /** + * Sets the registration. + * + * @param registration The registration of the GetStatementRequest. + * + * @return This builder + * + * @see GetStatementsRequest#registration + */ + public Builder registration(UUID registration) { + this.registration = registration; + return this; + } + + /** + * Sets the registration. + * + * @param registration The registration of the GetStatementRequest. + * + * @return This builder + * + * @see GetStatementsRequest#registration + */ + public Builder registration(String registration) { + this.registration = UUID.fromString(registration); + return this; + } + + // This static class extends the lombok builder. + + } + + private String agentToJsonString() { + if (agent == null) { + return null; + } + + try { + return objectMapper.writeValueAsString(agent); + } catch (JsonProcessingException e) { + // Should not happen + return null; + } + + } + +} diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 1ca66587..4ae71204 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -4,8 +4,11 @@ package dev.learning.xapi.client; +import dev.learning.xapi.model.Statement; +import dev.learning.xapi.model.StatementResult; import java.util.HashMap; import java.util.Map; +import java.util.UUID; import java.util.function.Consumer; import org.springframework.http.ResponseEntity; import org.springframework.web.reactive.function.client.WebClient; @@ -40,6 +43,101 @@ public XapiClient(WebClient.Builder builder) { .build(); } + + + /** + * Gets a Statement + * + *

+ * The returned ResponseEntity contains the response headers and the Statement. + *

+ * + * @return the ResponseEntity + */ + public Mono> getStatement(UUID id) { + + + return this.webClient + + .get() + + .uri(u -> u.path("/statements").queryParam("statementId", id).build()) + + .retrieve() + + .toEntity(Statement.class); + + } + + + + /** + * Gets a StatementResult object, a list of Statements. If additional results are available, an + * URL to retrieve them will be included in the StatementResult Object. + * + *

+ * The returned ResponseEntity contains the response headers and StatementResult. + *

+ * + * @return the ResponseEntity + */ + public Mono> getStatements() { + + return getStatements(GetStatementsRequest.builder().build()); + } + + + /** + * Gets a StatementResult object, a list of Statements. If additional results are available, an + * URL to retrieve them will be included in the StatementResult Object. + * + *

+ * The returned ResponseEntity contains the response headers and StatementResult. + *

+ * + * @param request The parameters of the get statements request + * + * @return the ResponseEntity + */ + public Mono> getStatements(GetStatementsRequest request) { + + Map queryParams = new HashMap<>(); + + return this.webClient + + .method(request.getMethod()) + + .uri(u -> request.url(u, queryParams).build()) + + .retrieve() + + .toEntity(StatementResult.class); + + } + + /** + * Gets a StatementResult object, a list of Statements. If additional results are available, an + * URL to retrieve them will be included in the StatementResult Object. + * + *

+ * The returned ResponseEntity contains the response headers and StatementResult. + *

+ * + * @param request The Consumer Builder for the get statements request + * + * @return the ResponseEntity + */ + public Mono> getStatements( + Consumer request) { + + final GetStatementsRequest.Builder builder = GetStatementsRequest.builder(); + + request.accept(builder); + + return getStatements(builder.build()); + + } + /** * Gets a single document specified by the given stateId activity, agent, and optional * registration. diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java index 1debc04d..f8b424b8 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java @@ -1,11 +1,19 @@ /* - * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + * Copyright 2016rue-2023 Berry Cloud Ltd. All rights reserved. */ package dev.learning.xapi.client; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsInstanceOf.instanceOf; +import dev.learning.xapi.model.StatementFormat; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.RecordedRequest; @@ -18,6 +26,8 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.util.UriBuilder; +import org.springframework.web.util.UriComponentsBuilder; /** * XapiClient Tests. @@ -51,6 +61,245 @@ void tearDown() throws Exception { mockWebServer.shutdown(); } + // Get Statement + + + @Test + void hello() throws MalformedURLException { + + + var x1 = new URL("https://example.com:8080:tom"); + + + var x2 = URI.create("example.com:tom"); + + + var x3 = URI.create("example.com:8080/hello:tom"); + + String agent = null; + URI verb = URI.create("http://example.com/course/1?tom=1&bob=2"); + Instant since = Instant.now(); + + Map queryParams = new HashMap<>(); + + queryParams.put("agent", agent); + queryParams.put("verb", verb); + queryParams.put("since", since); + + + UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.newInstance(); + + + URI test1 = uriComponentsBuilder.path("statements") + + .queryParam("agent", agent) + + .queryParam("verb", verb) + + .queryParam("since", since) // not encoded + + .build() + + .toUri(); + + System.out.println("test1 " + test1); + + + UriBuilder uriBuilder = UriComponentsBuilder.newInstance(); + + URI test2 = uriBuilder.path("statements") + + .queryParam("agent", "{agent}") + + .queryParam("verb", "{verb}") + + .queryParam("since", "{since}") + + .build(queryParams); + + System.out.println("test2 " + test2); + + + UriComponentsBuilder uriComponentsBuilder2 = UriComponentsBuilder.newInstance(); + + + URI test3 = uriComponentsBuilder2.path("statements") + + .queryParam("agent", agent) + + .queryParam("verb", verb) + + .queryParam("since", since) // not encoded + + .encode() + + .build() + + .toUri(); + + System.out.println("test3 " + test3); + + + } + + @Test + void whenGettingStatementThenMethodIsGet() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); + + // When Getting Statements + client.getStatement(UUID.fromString("4df42866-40e7-45b6-bf7c-8d5fccbdccd6")).block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Method Is Get + assertThat(recordedRequest.getMethod(), is("GET")); + } + + @Test + void whenGettingStatementThenPathIsExpected() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); + + // When Getting Statements + client.getStatement(UUID.fromString("4df42866-40e7-45b6-bf7c-8d5fccbdccd6")).block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Path Is Expected + assertThat(recordedRequest.getPath(), + is("/statements?statementId=4df42866-40e7-45b6-bf7c-8d5fccbdccd6")); + } + + // Get Statements + + @Test + void whenGettingStatementsThenMethodIsGet() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); + + // When Getting Statements + client.getStatements().block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Method Is Get + assertThat(recordedRequest.getMethod(), is("GET")); + } + + + @Test + void whenGettingStatementsThenPathIsExpected() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); + + // When Getting Statements + client.getStatements().block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Path Is Expected + assertThat(recordedRequest.getPath(), is("/statements")); + } + + @Test + void whenGettingStatementsWithAllParametersThenPathIsExpected() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); + + // When Getting Statements With All Parameters + client.getStatements(r -> r + + .agent(a -> a.name("A N Other").mbox("mailto:another@example.com")) + + .verb("http://adlnet.gov/expapi/verbs/answered") + + .activity("https://example.com/activity/1") + + .registration("dbf5d9e8-d2aa-4d57-9754-b11e3f195fe3") + + .relatedActivities(true) + + .relatedAgents(true) + + .since(Instant.parse("2016-01-01T00:00:00Z")) + + .until(Instant.parse("2018-01-01T00:00:00Z")) + + .limit(10) + + .format(StatementFormat.CANONICAL) + + .attachments(true) + + .ascending(true) + + ).block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Path Is Expected + assertThat(recordedRequest.getPath(), is( + "/statements?agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22mailto%3Aanother%40example.com%22%7D&verb=http%3A%2F%2Fadlnet.gov%2Fexpapi%2Fverbs%2Fanswered&activity=https%3A%2F%2Fexample.com%2Factivity%2F1®istration=dbf5d9e8-d2aa-4d57-9754-b11e3f195fe3&related_activities=true&related_agents=true&since=2016-01-01T00%3A00%3A00Z&until=2018-01-01T00%3A00%3A00Z&limit=10&format=canonical&attachments=true&ascending=true")); + } + + @Test + void whenGettingStatementsWithAgentParameterThenPathIsExpected() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); + + // When Getting Statements With Agent Parameter + client.getStatements(r -> r + + .agent(a -> a.name("A N Other").mbox("mailto:another@example.com")) + + ).block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Path Is Expected + assertThat(recordedRequest.getPath(), is( + "/statements?agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22mailto%3Aanother%40example.com%22%7D")); + } + + @Test + void whenGettingStatementsWithVerbParameterThenPathIsExpected() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); + + // When Getting Statements With Verb Parameter + client.getStatements(r -> r + + .verb("http://adlnet.gov/expapi/verbs/answered") + + ).block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Path Is Expected + assertThat(recordedRequest.getPath(), + is("/statements?verb=http%3A%2F%2Fadlnet.gov%2Fexpapi%2Fverbs%2Fanswered")); + } + + @Test + void whenGettingStatementsWithActivityParameterThenPathIsExpected() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); + + // When Getting Statements With Activity Parameter + client.getStatements(r -> r + + .activity("https://example.com/activity/1") + + ).block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Path Is Expected + assertThat(recordedRequest.getPath(), + is("/statements?activity=https%3A%2F%2Fexample.com%2Factivity%2F1")); + } + // Get Single State @Test diff --git a/xapi-model/src/main/java/dev/learning/xapi/model/StatementFormat.java b/xapi-model/src/main/java/dev/learning/xapi/model/StatementFormat.java new file mode 100644 index 00000000..558cd21c --- /dev/null +++ b/xapi-model/src/main/java/dev/learning/xapi/model/StatementFormat.java @@ -0,0 +1,36 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ + +package dev.learning.xapi.model; + +/** + * This enumeration class represents all valid Statement formats. + * + * @author Thomas Turrell-Croft + */ +public enum StatementFormat { + + IDS("ids"), + + EXACT("exact"), + + CANONICAL("canonical"); + + private final String format; + + StatementFormat(String format) { + this.format = format; + } + + public String getFormat() { + return format; + } + + @Override + public String toString() { + return format; + } + + // **Warning** do not add fields that are not required by the xAPI specification. +} From 80a52c70e912c26742bf97c032e02c387d252c3c Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Wed, 15 Feb 2023 19:15:19 +0000 Subject: [PATCH 03/17] more statements stuff --- .../xapi/client/GetStatementRequest.java | 89 ++++++ .../xapi/client/GetStatementsRequest.java | 46 +-- .../client/GetVoidedStatementRequest.java | 89 ++++++ .../xapi/client/PostStatementRequest.java | 85 ++++++ .../xapi/client/PostStatementsRequest.java | 41 +++ .../dev/learning/xapi/client/XapiClient.java | 170 ++++++++++- .../client/GetStatementsRequestTests.java | 57 ++++ .../learning/xapi/client/XapiClientTests.java | 282 ++++++++++++++---- 8 files changed, 767 insertions(+), 92 deletions(-) create mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java create mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/GetVoidedStatementRequest.java create mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/PostStatementRequest.java create mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/PostStatementsRequest.java create mode 100644 xapi-client/src/test/java/dev/learning/xapi/client/GetStatementsRequestTests.java diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java new file mode 100644 index 00000000..9edd9f0f --- /dev/null +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java @@ -0,0 +1,89 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ + +package dev.learning.xapi.client; + +import dev.learning.xapi.model.StatementFormat; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import lombok.Builder; +import lombok.Getter; +import lombok.NonNull; +import org.springframework.http.HttpMethod; +import org.springframework.web.util.UriBuilder; + +/** + * Request for getting a Statement. + * + * @see GET + * Statements + * + * @author Thomas Turrell-Croft + */ +@Builder +@Getter +public class GetStatementRequest implements Request { + + @NonNull + private final UUID id; + + private final StatementFormat format; + + private final Boolean attachments; + + @Override + public HttpMethod getMethod() { + return HttpMethod.GET; + } + + @Override + public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { + + return uriBuilder.path("statements") + + .queryParam("statementId", id) + + .queryParamIfPresent("format", Optional.ofNullable(format)) + + .queryParamIfPresent("attachments", Optional.ofNullable(attachments)); + + } + + public static class Builder { + + /** + * Sets the id. + * + * @param id The id of the GetStatementRequest. + * + * @return This builder + * + * @see GetStatementRequest#id + */ + public Builder id(UUID id) { + this.id = id; + return this; + } + + /** + * Sets the id. + * + * @param verb The id of the GetStatementRequest. + * + * @return This builder + * + * @see GetStatementRequest#id + */ + public Builder id(String id) { + this.id = UUID.fromString(id); + return this; + } + + // This static class extends the lombok builder. + + } + +} diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementsRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementsRequest.java index 36436d3b..d2b0c3a7 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementsRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementsRequest.java @@ -20,13 +20,13 @@ import org.springframework.web.util.UriBuilder; /** - * Request for getting multiple State documents. + * Request for getting multiple Statements. * * @see Multiple - * State Document GET + * "https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Communication.md#213-get-statements">GET + * Statements * - * @author István Rátkai (Selindek) + * @author Thomas Turrell-Croft */ @Builder @Getter @@ -72,7 +72,7 @@ public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { if (agent != null) { queryParams.put("agent", agentToJsonString()); - uriBuilder.queryParam("verb", "{agent}"); + uriBuilder.queryParam("agent", "{agent}"); } if (verb != null) { @@ -80,39 +80,29 @@ public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { uriBuilder.queryParam("verb", "{verb}"); } - if (verb != null) { + if (activity != null) { queryParams.put("activity", activity); uriBuilder.queryParam("activity", "{activity}"); } if (since != null) { - queryParams.put("since ", since); - uriBuilder.queryParam("since ", "{since}"); + queryParams.put("since", since); + uriBuilder.queryParam("since", "{since}"); } - if (since != null) { - queryParams.put("until ", until); - uriBuilder.queryParam("until ", "{until}"); + if (until != null) { + queryParams.put("until", until); + uriBuilder.queryParam("until", "{until}"); } return uriBuilder - .queryParamIfPresent("agent", templateIfParamPresent("{agent}", agent)) - - .queryParamIfPresent("verb", templateIfParamPresent("{verb}", verb)) - - .queryParamIfPresent("activity", templateIfParamPresent("{activity}", activity)) - .queryParamIfPresent("registration", Optional.ofNullable(registration)) .queryParamIfPresent("related_activities", Optional.ofNullable(relatedActivities)) .queryParamIfPresent("related_agents", Optional.ofNullable(relatedAgents)) - .queryParamIfPresent("since", templateIfParamPresent("{since}", since)) - - .queryParamIfPresent("until", templateIfParamPresent("{until}", until)) - .queryParamIfPresent("limit", Optional.ofNullable(limit)) .queryParamIfPresent("format", Optional.ofNullable(format)) @@ -123,17 +113,8 @@ public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { } - private Optional templateIfParamPresent(String template, Object value) { - - if (value == null) { - return Optional.empty(); - } - - return Optional.of(template); - } - /** - * Builder for Verb. + * Builder for GetStatementsRequest. */ public static class Builder { @@ -261,9 +242,6 @@ public Builder registration(String registration) { } private String agentToJsonString() { - if (agent == null) { - return null; - } try { return objectMapper.writeValueAsString(agent); diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetVoidedStatementRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetVoidedStatementRequest.java new file mode 100644 index 00000000..8483460f --- /dev/null +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetVoidedStatementRequest.java @@ -0,0 +1,89 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ + +package dev.learning.xapi.client; + +import dev.learning.xapi.model.StatementFormat; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import lombok.Builder; +import lombok.Getter; +import lombok.NonNull; +import org.springframework.http.HttpMethod; +import org.springframework.web.util.UriBuilder; + +/** + * Request for getting a voided Statement. + * + * @see Voided + * Statements + * + * @author Thomas Turrell-Croft + */ +@Builder +@Getter +public class GetVoidedStatementRequest implements Request { + + @NonNull + private final UUID id; + + private final StatementFormat format; + + private final Boolean attachments; + + @Override + public HttpMethod getMethod() { + return HttpMethod.GET; + } + + @Override + public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { + + return uriBuilder.path("statements") + + .queryParam("voidedStatementId", id) + + .queryParamIfPresent("format", Optional.ofNullable(format)) + + .queryParamIfPresent("attachments", Optional.ofNullable(attachments)); + + } + + public static class Builder { + + /** + * Sets the id. + * + * @param id The id of the GetStatementRequest. + * + * @return This builder + * + * @see GetVoidedStatementRequest#id + */ + public Builder id(UUID id) { + this.id = id; + return this; + } + + /** + * Sets the id. + * + * @param verb The id of the GetStatementRequest. + * + * @return This builder + * + * @see GetVoidedStatementRequest#id + */ + public Builder id(String id) { + this.id = UUID.fromString(id); + return this; + } + + // This static class extends the lombok builder. + + } + +} diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PostStatementRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PostStatementRequest.java new file mode 100644 index 00000000..9680d3a7 --- /dev/null +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PostStatementRequest.java @@ -0,0 +1,85 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ + +package dev.learning.xapi.client; + +import dev.learning.xapi.model.Statement; +import java.util.Map; +import java.util.function.Consumer; +import lombok.Builder; +import lombok.Getter; +import org.springframework.http.HttpMethod; +import org.springframework.web.util.UriBuilder; + +/** + * Request for posting multiple Statements. + * + * @see POST + * Statements + * + * @author Thomas Turrell-Croft + */ +@Builder +@Getter +public class PostStatementRequest implements Request { + + private final Statement statement; + + @Override + public HttpMethod getMethod() { + return HttpMethod.POST; + } + + @Override + public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { + + return uriBuilder.path("statements"); + + } + + /** + * Builder for Statement. + */ + public static class Builder { + + // This static class extends the lombok builder. + + /** + * Consumer Builder for statement. + * + * @param statement The Consumer Builder for statement + * + * @return This builder + * + * @see PostStatementRequest#statement + */ + public Builder statement(Consumer statement) { + + final Statement.Builder builder = Statement.builder(); + + statement.accept(builder); + + return statement(builder.build()); + } + + /** + * Sets the statement. + * + * @param statement The Statement to post + * + * @return This builder + * + * @see PostStatementRequest#statement + */ + public Builder statement(Statement statement) { + + this.statement = statement; + + return this; + } + + } + +} diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PostStatementsRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PostStatementsRequest.java new file mode 100644 index 00000000..475df20f --- /dev/null +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PostStatementsRequest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ + +package dev.learning.xapi.client; + +import dev.learning.xapi.model.Statement; +import java.util.Map; +import lombok.Builder; +import lombok.Getter; +import org.springframework.http.HttpMethod; +import org.springframework.web.util.UriBuilder; + +/** + * Request for posting multiple Statements. + * + * @see POST + * Statements + * + * @author Thomas Turrell-Croft + */ +@Builder +@Getter +public class PostStatementsRequest implements Request { + + private final Statement[] statements; + + @Override + public HttpMethod getMethod() { + return HttpMethod.POST; + } + + @Override + public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { + + return uriBuilder.path("statements"); + + } + +} diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 4ae71204..3d1c1458 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -8,7 +8,6 @@ import dev.learning.xapi.model.StatementResult; import java.util.HashMap; import java.util.Map; -import java.util.UUID; import java.util.function.Consumer; import org.springframework.http.ResponseEntity; import org.springframework.web.reactive.function.client.WebClient; @@ -43,7 +42,30 @@ public XapiClient(WebClient.Builder builder) { .build(); } + /** + * Gets a Statement + * + *

+ * The returned ResponseEntity contains the response headers and the Statement. + *

+ * + * @return the ResponseEntity + */ + public Mono> getStatement(GetStatementRequest request) { + + Map queryParams = new HashMap<>(); + + return this.webClient + + .method(request.getMethod()) + + .uri(u -> request.url(u, queryParams).build(queryParams)) + + .retrieve() + + .toEntity(Statement.class); + } /** * Gets a Statement @@ -54,14 +76,133 @@ public XapiClient(WebClient.Builder builder) { * * @return the ResponseEntity */ - public Mono> getStatement(UUID id) { + public Mono> getStatement( + Consumer request) { + + final GetStatementRequest.Builder builder = GetStatementRequest.builder(); + + request.accept(builder); + + return getStatement(builder.build()); + + } + + /** + * Posts Statement + * + *

+ * The returned ResponseEntity contains the response headers and the Statement identifier. + *

+ * + * @return the ResponseEntity + */ + public Mono> postStatement(PostStatementRequest request) { + Map queryParams = new HashMap<>(); return this.webClient - .get() + .method(request.getMethod()) + + .uri(u -> request.url(u, queryParams).build(queryParams)) - .uri(u -> u.path("/statements").queryParam("statementId", id).build()) + .bodyValue(request.getStatement()) + + .retrieve() + + .toEntity(String[].class) + + .map(i -> ResponseEntity.ok().headers(i.getHeaders()).body(i.getBody()[0])); + + } + + /** + * Post Statement + * + *

+ * The returned ResponseEntity contains the response headers and the Statement identifier. + *

+ * + * @return the ResponseEntity + */ + public Mono> postStatement( + Consumer request) { + + final PostStatementRequest.Builder builder = PostStatementRequest.builder(); + + request.accept(builder); + + return postStatement(builder.build()); + + } + + /** + * Posts Statements + * + *

+ * The returned ResponseEntity contains the response headers and an array of Statement + * identifiers. + *

+ * + * @return the ResponseEntity + */ + public Mono> postStatements(PostStatementsRequest request) { + + Map queryParams = new HashMap<>(); + + return this.webClient + + .method(request.getMethod()) + + .uri(u -> request.url(u, queryParams).build(queryParams)) + + .bodyValue(request.getStatements()) + + .retrieve() + + .toEntity(String[].class); + + } + + /** + * Posts Statements + * + *

+ * The returned ResponseEntity contains the response headers and an array of Statement + * identifiers. + *

+ * + * @return the ResponseEntity + */ + public Mono> postStatements( + Consumer request) { + + final PostStatementsRequest.Builder builder = PostStatementsRequest.builder(); + + request.accept(builder); + + return postStatements(builder.build()); + + } + + /** + * Gets a voided Statement + * + *

+ * The returned ResponseEntity contains the response headers and the voided Statement. + *

+ * + * @return the ResponseEntity + */ + public Mono> getVoidedStatement(GetVoidedStatementRequest request) { + + Map queryParams = new HashMap<>(); + + return this.webClient + + .method(request.getMethod()) + + .uri(u -> request.url(u, queryParams).build(queryParams)) .retrieve() @@ -69,7 +210,25 @@ public Mono> getStatement(UUID id) { } + /** + * Gets a voided Statement + * + *

+ * The returned ResponseEntity contains the response headers and the voided Statement. + *

+ * + * @return the ResponseEntity + */ + public Mono> getVoidedStatement( + Consumer request) { + final GetVoidedStatementRequest.Builder builder = GetVoidedStatementRequest.builder(); + + request.accept(builder); + + return getVoidedStatement(builder.build()); + + } /** * Gets a StatementResult object, a list of Statements. If additional results are available, an @@ -86,7 +245,6 @@ public Mono> getStatements() { return getStatements(GetStatementsRequest.builder().build()); } - /** * Gets a StatementResult object, a list of Statements. If additional results are available, an * URL to retrieve them will be included in the StatementResult Object. @@ -107,7 +265,7 @@ public Mono> getStatements(GetStatementsRequest .method(request.getMethod()) - .uri(u -> request.url(u, queryParams).build()) + .uri(u -> request.url(u, queryParams).build(queryParams)) .retrieve() diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/GetStatementsRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/GetStatementsRequestTests.java new file mode 100644 index 00000000..5e4355cd --- /dev/null +++ b/xapi-client/src/test/java/dev/learning/xapi/client/GetStatementsRequestTests.java @@ -0,0 +1,57 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ +package dev.learning.xapi.client; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import dev.learning.xapi.model.StatementFormat; +import java.net.URI; +import java.time.Instant; +import java.util.UUID; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +/** + * GetStatementsRequest Tests. + * + * @author Thomas Turrell-Croft + */ +@DisplayName("GetStatementsRequest Tests") +class GetStatementsRequestTests { + + @Test + void whenBuildingGetStatementsRequestWithAllParametersThenNoExceptionIsThrown() { + + // When Building GetStatementsRequest With All Parameters + GetStatementsRequest.Builder builder = GetStatementsRequest.builder() + + .agent(a -> a.name("A N Other").mbox("mailto:another@example.com")) + + .verb(URI.create("http://adlnet.gov/expapi/verbs/answered")) + + .activity(URI.create("https://example.com/activity/1")) + + .registration(UUID.fromString("dbf5d9e8-d2aa-4d57-9754-b11e3f195fe3")) + + .relatedActivities(true) + + .relatedAgents(true) + + .since(Instant.parse("2016-01-01T00:00:00Z")) + + .until(Instant.parse("2018-01-01T00:00:00Z")) + + .limit(10) + + .format(StatementFormat.CANONICAL) + + .attachments(true) + + .ascending(true); + + // Then No Exception Is Thrown + assertDoesNotThrow(() -> builder.build()); + + } + +} diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java index f8b424b8..427b702c 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java @@ -6,13 +6,11 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsInstanceOf.instanceOf; +import dev.learning.xapi.model.Statement; import dev.learning.xapi.model.StatementFormat; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URL; +import dev.learning.xapi.model.Verb; import java.time.Instant; -import java.util.HashMap; -import java.util.Map; +import java.util.Locale; import java.util.UUID; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; @@ -26,8 +24,6 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.reactive.function.client.WebClient; -import org.springframework.web.util.UriBuilder; -import org.springframework.web.util.UriComponentsBuilder; /** * XapiClient Tests. @@ -63,92 +59,241 @@ void tearDown() throws Exception { // Get Statement + @Test + void whenGettingStatementThenMethodIsGet() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); + + // When Getting Statements + client.getStatement(r -> r.id(UUID.fromString("4df42866-40e7-45b6-bf7c-8d5fccbdccd6"))).block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Method Is Get + assertThat(recordedRequest.getMethod(), is("GET")); + } + + @Test + void whenGettingStatementThenPathIsExpected() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); + + // When Getting Statement + client.getStatement(r -> r.id("4df42866-40e7-45b6-bf7c-8d5fccbdccd6")).block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Path Is Expected + assertThat(recordedRequest.getPath(), + is("/statements?statementId=4df42866-40e7-45b6-bf7c-8d5fccbdccd6")); + } + + @Test + void whenGettingStatementWithAttachmentsThenPathIsExpected() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); + + // When Getting Statement With Attachments + client.getStatement(r -> r.id("4df42866-40e7-45b6-bf7c-8d5fccbdccd6").attachments(true)) + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Path Is Expected + assertThat(recordedRequest.getPath(), + is("/statements?statementId=4df42866-40e7-45b6-bf7c-8d5fccbdccd6&attachments=true")); + } @Test - void hello() throws MalformedURLException { + void whenGettingStatementWithCanonicalFormatThenPathIsExpected() throws InterruptedException { + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); - var x1 = new URL("https://example.com:8080:tom"); + // When Getting Statement With Canonical Format + client + .getStatement( + r -> r.id("4df42866-40e7-45b6-bf7c-8d5fccbdccd6").format(StatementFormat.CANONICAL)) + .block(); + RecordedRequest recordedRequest = mockWebServer.takeRequest(); - var x2 = URI.create("example.com:tom"); + // Then Path Is Expected + assertThat(recordedRequest.getPath(), + is("/statements?statementId=4df42866-40e7-45b6-bf7c-8d5fccbdccd6&format=canonical")); + } + // Posting Statements - var x3 = URI.create("example.com:8080/hello:tom"); + @Test + void whenPostingStatementsThenMethodIsPost() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); - String agent = null; - URI verb = URI.create("http://example.com/course/1?tom=1&bob=2"); - Instant since = Instant.now(); + final Statement attemptedStatement = Statement.builder() - Map queryParams = new HashMap<>(); + .actor(a -> a.name("A N Other").mbox("mailto:another@example.com")) - queryParams.put("agent", agent); - queryParams.put("verb", verb); - queryParams.put("since", since); + .verb(Verb.ATTEMPTED) + .activityObject(o -> o.id("https://example.com/activity/simplestatement") + .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement"))) - UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.newInstance(); + .build(); + final Statement passedStatement = attemptedStatement.toBuilder().verb(Verb.PASSED).build(); - URI test1 = uriComponentsBuilder.path("statements") + Statement statements[] = {attemptedStatement, passedStatement}; - .queryParam("agent", agent) + // When posting Statements + client.postStatements(r -> r.statements(statements)).block(); - .queryParam("verb", verb) + RecordedRequest recordedRequest = mockWebServer.takeRequest(); - .queryParam("since", since) // not encoded + // Then Method Is Post + assertThat(recordedRequest.getMethod(), is("POST")); + } - .build() + @Test + void whenPostingStatementsThenBodyIsExpected() throws InterruptedException { - .toUri(); + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); - System.out.println("test1 " + test1); + final Statement attemptedStatement = Statement.builder() + .actor(a -> a.name("A N Other").mbox("mailto:another@example.com")) - UriBuilder uriBuilder = UriComponentsBuilder.newInstance(); + .verb(Verb.ATTEMPTED) - URI test2 = uriBuilder.path("statements") + .activityObject(o -> o.id("https://example.com/activity/simplestatement") + .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement"))) - .queryParam("agent", "{agent}") + .build(); - .queryParam("verb", "{verb}") + final Statement passedStatement = attemptedStatement.toBuilder().verb(Verb.PASSED).build(); - .queryParam("since", "{since}") + Statement statements[] = {attemptedStatement, passedStatement}; - .build(queryParams); + // When Posting Statements + client.postStatements(r -> r.statements(statements)).block(); - System.out.println("test2 " + test2); + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + // Then Body Is Expected + assertThat(recordedRequest.getBody().readUtf8(), is( + "[{\"actor\":{\"name\":\"A N Other\",\"mbox\":\"mailto:another@example.com\"},\"verb\":{\"id\":\"http://adlnet.gov/expapi/verbs/attempted\",\"display\":{\"und\":\"attempted\"}},\"object\":{\"objectType\":\"Activity\",\"id\":\"https://example.com/activity/simplestatement\",\"definition\":{\"name\":{\"en\":\"Simple Statement\"}}}},{\"actor\":{\"name\":\"A N Other\",\"mbox\":\"mailto:another@example.com\"},\"verb\":{\"id\":\"http://adlnet.gov/expapi/verbs/passed\",\"display\":{\"und\":\"passed\"}},\"object\":{\"objectType\":\"Activity\",\"id\":\"https://example.com/activity/simplestatement\",\"definition\":{\"name\":{\"en\":\"Simple Statement\"}}}}]")); + } - UriComponentsBuilder uriComponentsBuilder2 = UriComponentsBuilder.newInstance(); + @Test + void whenPostingStatementsThenContentTypeHeaderIsApplicationJson() throws InterruptedException { + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); - URI test3 = uriComponentsBuilder2.path("statements") + final Statement attemptedStatement = Statement.builder() - .queryParam("agent", agent) + .actor(a -> a.name("A N Other").mbox("mailto:another@example.com")) - .queryParam("verb", verb) + .verb(Verb.ATTEMPTED) - .queryParam("since", since) // not encoded + .activityObject(o -> o.id("https://example.com/activity/simplestatement") + .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement"))) - .encode() + .build(); - .build() + final Statement passedStatement = attemptedStatement.toBuilder().verb(Verb.PASSED).build(); - .toUri(); + Statement statements[] = {attemptedStatement, passedStatement}; - System.out.println("test3 " + test3); + // When Posting Statements + client.postStatements(r -> r.statements(statements)).block(); + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + // Then Content Type Header Is Application Json + assertThat(recordedRequest.getHeader("content-type"), is("application/json")); } + // Posting a Statement + @Test - void whenGettingStatementThenMethodIsGet() throws InterruptedException { + void whenPostingStatementThenMethodIsPost() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content") + .setBody("[\"19a74a3f-7354-4254-aa4a-1c39ab4f2ca7\"]") + .setHeader("Content-Type", "application/json")); + + // When posting Statement + client.postStatement( + r -> r.statement(s -> s.actor(a -> a.name("A N Other").mbox("mailto:another@example.com")) + + .verb(Verb.ATTEMPTED) + + .activityObject(o -> o.id("https://example.com/activity/simplestatement") + .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement"))))) + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Method Is Post + assertThat(recordedRequest.getMethod(), is("POST")); + } + + @Test + void whenPostingStatementThenBodyIsExpected() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content") + .setBody("[\"19a74a3f-7354-4254-aa4a-1c39ab4f2ca7\"]") + .setHeader("Content-Type", "application/json")); + + // When Posting Statement + client.postStatement( + r -> r.statement(s -> s.actor(a -> a.name("A N Other").mbox("mailto:another@example.com")) + + .verb(Verb.ATTEMPTED) + + .activityObject(o -> o.id("https://example.com/activity/simplestatement") + .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement"))))) + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Body Is Expected + assertThat(recordedRequest.getBody().readUtf8(), is( + "{\"actor\":{\"name\":\"A N Other\",\"mbox\":\"mailto:another@example.com\"},\"verb\":{\"id\":\"http://adlnet.gov/expapi/verbs/attempted\",\"display\":{\"und\":\"attempted\"}},\"object\":{\"objectType\":\"Activity\",\"id\":\"https://example.com/activity/simplestatement\",\"definition\":{\"name\":{\"en\":\"Simple Statement\"}}}}")); + } + + @Test + void whenPostingStatementThenContentTypeHeaderIsApplicationJson() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content") + .setBody("[\"19a74a3f-7354-4254-aa4a-1c39ab4f2ca7\"]") + .setHeader("Content-Type", "application/json")); + + // When Posting Statement + client.postStatement( + r -> r.statement(s -> s.actor(a -> a.name("A N Other").mbox("mailto:another@example.com")) + + .verb(Verb.ATTEMPTED) + + .activityObject(o -> o.id("https://example.com/activity/simplestatement") + .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement"))))) + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Content Type Header Is Application Json + assertThat(recordedRequest.getHeader("content-type"), is("application/json")); + } + + // Get Voided Statement + + @Test + void whenGettingVoidedStatementThenMethodIsGet() throws InterruptedException { mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); - // When Getting Statements - client.getStatement(UUID.fromString("4df42866-40e7-45b6-bf7c-8d5fccbdccd6")).block(); + // When Getting Voided Statement + client.getVoidedStatement(r -> r.id(UUID.fromString("4df42866-40e7-45b6-bf7c-8d5fccbdccd6"))) + .block(); RecordedRequest recordedRequest = mockWebServer.takeRequest(); @@ -157,18 +302,53 @@ void whenGettingStatementThenMethodIsGet() throws InterruptedException { } @Test - void whenGettingStatementThenPathIsExpected() throws InterruptedException { + void whenGettingVoidedStatementThenPathIsExpected() throws InterruptedException { mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); - // When Getting Statements - client.getStatement(UUID.fromString("4df42866-40e7-45b6-bf7c-8d5fccbdccd6")).block(); + // When Getting Voided Statement + client.getVoidedStatement(r -> r.id("4df42866-40e7-45b6-bf7c-8d5fccbdccd6")).block(); RecordedRequest recordedRequest = mockWebServer.takeRequest(); // Then Path Is Expected assertThat(recordedRequest.getPath(), - is("/statements?statementId=4df42866-40e7-45b6-bf7c-8d5fccbdccd6")); + is("/statements?voidedStatementId=4df42866-40e7-45b6-bf7c-8d5fccbdccd6")); + } + + @Test + void whenGettingVoidedStatementWithAttachmentsThenPathIsExpected() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); + + // When Getting Voided Statement With Attachments + client.getStatement(r -> r.id("4df42866-40e7-45b6-bf7c-8d5fccbdccd6").attachments(true)) + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Path Is Expected + assertThat(recordedRequest.getPath(), + is("/statements?statementId=4df42866-40e7-45b6-bf7c-8d5fccbdccd6&attachments=true")); + } + + @Test + void whenGettingVoidedStatementWithCanonicalFormatThenPathIsExpected() + throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); + + // When Getting Voided Statement With Canonical Format + client + .getStatement( + r -> r.id("4df42866-40e7-45b6-bf7c-8d5fccbdccd6").format(StatementFormat.CANONICAL)) + .block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Path Is Expected + assertThat(recordedRequest.getPath(), + is("/statements?statementId=4df42866-40e7-45b6-bf7c-8d5fccbdccd6&format=canonical")); } // Get Statements @@ -240,7 +420,7 @@ void whenGettingStatementsWithAllParametersThenPathIsExpected() throws Interrupt // Then Path Is Expected assertThat(recordedRequest.getPath(), is( - "/statements?agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22mailto%3Aanother%40example.com%22%7D&verb=http%3A%2F%2Fadlnet.gov%2Fexpapi%2Fverbs%2Fanswered&activity=https%3A%2F%2Fexample.com%2Factivity%2F1®istration=dbf5d9e8-d2aa-4d57-9754-b11e3f195fe3&related_activities=true&related_agents=true&since=2016-01-01T00%3A00%3A00Z&until=2018-01-01T00%3A00%3A00Z&limit=10&format=canonical&attachments=true&ascending=true")); + "/statements?agent=%7B%22name%22%3A%22A%20N%20Other%22%2C%22mbox%22%3A%22mailto%3Aanother%40example.com%22%7D&verb=http%3A%2F%2Fadlnet.gov%2Fexpapi%2Fverbs%2Fanswered&activity=https%3A%2F%2Fexample.com%2Factivity%2F1&since=2016-01-01T00%3A00%3A00Z&until=2018-01-01T00%3A00%3A00Z®istration=dbf5d9e8-d2aa-4d57-9754-b11e3f195fe3&related_activities=true&related_agents=true&limit=10&format=canonical&attachments=true&ascending=true")); } @Test @@ -322,8 +502,6 @@ void whenGettingASingleStateThenMethodIsGet() throws InterruptedException { assertThat(recordedRequest.getMethod(), is("GET")); } - - @Test void whenGettingASingleStateThenPathIsExpected() throws InterruptedException { From 6b9641cca131919b4a922b1729a74d442550e4d7 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 17 Feb 2023 13:35:26 +0000 Subject: [PATCH 04/17] tip --- .../xapi/client/GetMoreStatementsRequest.java | 53 +++++++++++++++++ .../dev/learning/xapi/client/XapiClient.java | 27 +++++++++ .../client/GetMoreStatementsRequestTests.java | 46 +++++++++++++++ .../learning/xapi/client/XapiClientTests.java | 57 ++++++++++++++++++- 4 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 xapi-client/src/main/java/dev/learning/xapi/client/GetMoreStatementsRequest.java create mode 100644 xapi-client/src/test/java/dev/learning/xapi/client/GetMoreStatementsRequestTests.java diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetMoreStatementsRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetMoreStatementsRequest.java new file mode 100644 index 00000000..5e205605 --- /dev/null +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetMoreStatementsRequest.java @@ -0,0 +1,53 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ + +package dev.learning.xapi.client; + +import java.net.URI; +import java.util.Map; +import lombok.Builder; +import lombok.Getter; +import lombok.NonNull; +import org.springframework.http.HttpMethod; +import org.springframework.web.util.UriBuilder; +import org.springframework.web.util.UriComponentsBuilder; + +/** + * Request for getting multiple Statements. + * + * @see GET + * Statements + * + * @author Thomas Turrell-Croft + */ +@Builder +@Getter +public class GetMoreStatementsRequest implements Request { + + @NonNull + private final URI more; + + @Override + public HttpMethod getMethod() { + return HttpMethod.GET; + } + + @Override + public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { + + return UriComponentsBuilder.fromUri(more); + + } + + /** + * Builder for GetMoreStatementsRequest. + */ + public static class Builder { + + // This static class extends the lombok builder. + + } + +} diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 3d1c1458..10a2b87b 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -296,6 +296,33 @@ public Mono> getStatements( } + public Mono> getMoreStatements(GetMoreStatementsRequest request) { + + Map queryParams = new HashMap<>(); + + return this.webClient + + .method(request.getMethod()) + + .uri(u -> request.url(u, queryParams).build(queryParams)) + + .retrieve() + + .toEntity(StatementResult.class); + + } + + public Mono> getMoreStatements( + Consumer request) { + + final GetMoreStatementsRequest.Builder builder = GetMoreStatementsRequest.builder(); + + request.accept(builder); + + return getMoreStatements(builder.build()); + + } + /** * Gets a single document specified by the given stateId activity, agent, and optional * registration. diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/GetMoreStatementsRequestTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/GetMoreStatementsRequestTests.java new file mode 100644 index 00000000..39cdb842 --- /dev/null +++ b/xapi-client/src/test/java/dev/learning/xapi/client/GetMoreStatementsRequestTests.java @@ -0,0 +1,46 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ +package dev.learning.xapi.client; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; +import java.net.URI; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +/** + * GetMoreStatementsRequest Tests. + * + * @author Thomas Turrell-Croft + */ +@DisplayName("GetMoreStatementsRequest Tests") +class GetMoreStatementsRequestTests { + + @Test + void whenBuildingGetMoreStatementsRequestWithAllParametersThenNoExceptionIsThrown() { + + // When Building GetMoreStatementsRequest With All Parameters + GetMoreStatementsRequest.Builder builder = GetMoreStatementsRequest.builder() + + .more( + URI.create("https://example.com/xapi/statements/869cc589-76fa-4283-8e96-eea86f9124e1")); + + // Then No Exception Is Thrown + assertDoesNotThrow(() -> builder.build()); + + } + + @Test + void whenBuildingGetMoreStatementsRequestWithoutMoreThenNullPointerExceptionIsThrown() { + + // When Building GetMoreStatementsRequest Without More + GetMoreStatementsRequest.Builder builder = GetMoreStatementsRequest.builder(); + + // Then NullPointerException Is Thrown + assertThrows(NullPointerException.class, () -> builder.build()); + + } + + +} diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java index 427b702c..799888f9 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java @@ -65,7 +65,7 @@ void whenGettingStatementThenMethodIsGet() throws InterruptedException { mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); // When Getting Statements - client.getStatement(r -> r.id(UUID.fromString("4df42866-40e7-45b6-bf7c-8d5fccbdccd6"))).block(); + client.getStatement(r -> r.id("4df42866-40e7-45b6-bf7c-8d5fccbdccd6")).block(); RecordedRequest recordedRequest = mockWebServer.takeRequest(); @@ -88,6 +88,22 @@ void whenGettingStatementThenPathIsExpected() throws InterruptedException { is("/statements?statementId=4df42866-40e7-45b6-bf7c-8d5fccbdccd6")); } + @Test + void whenGettingStatementThenBodyIsInstanceOfStatement() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content") + + .setBody( + "{\"actor\":{\"objectType\":\"Agent\",\"name\":\"A N Other\",\"mbox\":\"mailto:another@example.com\"},\"verb\":{\"id\":\"http://adlnet.gov/expapi/verbs/attempted\",\"display\":{\"und\":\"attempted\"}},\"object\":{\"objectType\":\"Activity\",\"id\":\"https://example.com/activity/simplestatement\",\"definition\":{\"name\":{\"en\":\"Simple Statement\"}}}}") + .addHeader("Content-Type", "application/json; charset=utf-8")); + + // When Getting Statement + var response = client.getStatement(r -> r.id("4df42866-40e7-45b6-bf7c-8d5fccbdccd6")).block(); + + // Then Body Is Instance Of Statement + assertThat(response.getBody(), instanceOf(Statement.class)); + } + @Test void whenGettingStatementWithAttachmentsThenPathIsExpected() throws InterruptedException { @@ -480,6 +496,45 @@ void whenGettingStatementsWithActivityParameterThenPathIsExpected() throws Inter is("/statements?activity=https%3A%2F%2Fexample.com%2Factivity%2F1")); } + + + @Test + void whenGettingMoreStatementsThenRequestMethodIsGet() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); + + // When Getting Statements With Activity Parameter + client.getMoreStatements(r -> r + + .more(mockWebServer.url("/xapi/statements/869cc589-76fa-4283-8e96-eea86f9124e1").uri()) + + ).block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Method Is Get + assertThat(recordedRequest.getMethod(), is("GET")); + } + + @Test + void whenGettingMoreStatementsThenRequestURLExpected() throws InterruptedException { + + mockWebServer.enqueue(new MockResponse().setStatus("HTTP/1.1 200 No Content")); + + // When Getting Statements With Activity Parameter + client.getMoreStatements(r -> r + + .more(mockWebServer.url("/xapi/statements/869cc589-76fa-4283-8e96-eea86f9124e1").uri()) + + ).block(); + + RecordedRequest recordedRequest = mockWebServer.takeRequest(); + + // Then Request URL Is Expected + assertThat(recordedRequest.getRequestUrl(), + is(mockWebServer.url("/xapi/statements/869cc589-76fa-4283-8e96-eea86f9124e1"))); + } + // Get Single State @Test From a85591a3d3e2c938d3fe75723f3cea5fd1fbce37 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 17 Feb 2023 15:19:19 +0000 Subject: [PATCH 05/17] tip --- README.md | 99 +++++++++++++++++-- .../client/GetVoidedStatementRequest.java | 3 + .../xapi/client/PostStatementRequest.java | 2 +- .../xapi/client/PostStatementsRequest.java | 23 +++++ 4 files changed, 116 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 2a20a3e9..a4955860 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,85 @@ To use the xAPI Client include the appropriate XML in the `dependencies` section ``` +### Statement Resource + +The xAPI Client allows applications to store and fetch xAPI [Statements](https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Data.md#statements). + +### Getting a Statement + +```java +var response = client.getStatement(r -> r.id("4df42866-40e7-45b6-bf7c-8d5fccbdccd6")).block(); + +Statement statement = response.getBody(); +``` + +### Getting Statements + +Example: + +```java +var response = client.getStatements().block(); + +StatementResult statementResult = response.getBody(); + +Statement[] statements = statementResult.getStatements(); +``` + +### Getting the next page of Statements + + +Example: + +```java +var response = client.getStatements().block(); + +var moreResponse = client.getMoreStatements(r -> r.more(response.getBody().getMore())).block(); + +StatementResult moreStatementResult = moreResponse.getBody(); + +Statement[] statements = moreStatementResult.getStatements(); +``` + + +### Posting a Statement + +Example: + +```java +client.postStatement( + r -> r.statement(s -> s.actor(a -> a.name("A N Other").mbox("mailto:another@example.com")) + + .verb(Verb.ATTEMPTED) + + .activityObject(o -> o.id("https://example.com/activity/simplestatement") + .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement"))))) + .block(); +``` + +### Posting Statements + +Example: + +```java +Statement attemptedStatement = Statement.builder() + .actor(a -> a.name("A N Other").mbox("mailto:another@example.com")).verb(Verb.ATTEMPTED) + .activityObject(o -> o.id("https://example.com/activity/simplestatement") + .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement"))) + .build(); + +Statement passedStatement = attemptedStatement.toBuilder().verb(Verb.PASSED).build(); + +client.postStatements(r -> r.statements(attemptedStatement, passedStatement)).block(); +``` + +### Getting voided a Statement + +```java +var response = client.getVoidedStatement(r -> r.id("4df42866-40e7-45b6-bf7c-8d5fccbdccd6")).block(); + +Statement voidedStatement = response.getBody(); +``` + ### State Resource The xAPI Client allows applications to store, change, fetch, or delete [state documents](https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Communication.md#23-state-resource). @@ -39,7 +118,7 @@ The xAPI Client allows applications to store, change, fetch, or delete [state do Example: ```java -final var request = client.getState(r -> r.activityId("https://example.com/activity/1") +var request = client.getState(r -> r.activityId("https://example.com/activity/1") .agent(a -> a.name("A N Other").mbox("another@example.com")) @@ -48,8 +127,8 @@ final var request = client.getState(r -> r.activityId("https://example.com/activ .stateId("bookmark"), String.class) .block(); - -final String state = request.getBody(); + +String state = request.getBody(); ``` #### Posting a state @@ -134,7 +213,7 @@ To use the xAPI Model include the appropriate XML in the `dependencies` section Example: ```java -final Statement statement = Statement.builder() +Statement statement = Statement.builder() .actor(a -> a.name("A N Other").mbox("mailto:another@example.com")) @@ -153,7 +232,7 @@ The Jackson ObjectMapper can be used to deserialize statements into Java objects Example: ```java -final String json = """ +String json = """ { "actor":{ "objectType":"Agent", @@ -177,7 +256,7 @@ final String json = """ } }"""; -final Statement statement = objectMapper.readValue(json, Statement.class); +Statement statement = objectMapper.readValue(json, Statement.class); ``` ### Serializing Statements @@ -188,13 +267,13 @@ Example: ```java -final Statement statement = Statement.builder() +Statement statement = Statement.builder() .actor(a -> a.name("A N Other").mbox("mailto:another@example.com")).verb(Verb.ATTEMPTED) .activityObject(o -> o.id("https://example.com/activity/simplestatement") .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement"))) .build(); -final String json = objectMapper.writeValueAsString(statement); +String json = objectMapper.writeValueAsString(statement); ``` @@ -204,13 +283,13 @@ Example: ```java -final Statement passed = Statement.builder() +Statement passed = Statement.builder() .actor(a -> a.name("A N Other").mbox("mailto:another@example.com")).verb(Verb.PASSED) .activityObject(o -> o.id("https://example.com/activity/simplestatement") .definition(d -> d.addName(Locale.ENGLISH, "Simple Statement"))) .build(); -final Statement completed = passed.toBuilder().verb(Verb.COMPLETED).build(); +Statement completed = passed.toBuilder().verb(Verb.COMPLETED).build(); ``` diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetVoidedStatementRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetVoidedStatementRequest.java index 8483460f..4a8a13f6 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetVoidedStatementRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetVoidedStatementRequest.java @@ -52,6 +52,9 @@ public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { } + /** + * Builder for GetVoidedStatementRequest. + */ public static class Builder { /** diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PostStatementRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PostStatementRequest.java index 9680d3a7..ad016646 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PostStatementRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PostStatementRequest.java @@ -40,7 +40,7 @@ public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { } /** - * Builder for Statement. + * Builder for PostStatementRequest. */ public static class Builder { diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/PostStatementsRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/PostStatementsRequest.java index 475df20f..1a3bc262 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/PostStatementsRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/PostStatementsRequest.java @@ -38,4 +38,27 @@ public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { } + /** + * Builder for PostStatementsRequest. + */ + public static class Builder { + + // This static class extends the lombok builder. + + /** + * Sets the statements. + * + * @param statements The statements of the PostStatementsRequest. + * + * @return This builder + * + * @see PostStatementsRequest#statements + */ + public Builder statements(Statement... statements) { + this.statements = statements; + return this; + } + + } + } From 69926b296ccc62d949fd7107d482270f8e318ca6 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 17 Feb 2023 15:41:15 +0000 Subject: [PATCH 06/17] tip --- .../xapi/client/GetStatementRequest.java | 5 ++- .../client/GetVoidedStatementRequest.java | 4 +- .../dev/learning/xapi/client/XapiClient.java | 40 +++++++++++++++---- 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java index 9edd9f0f..7beac02d 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java @@ -52,6 +52,9 @@ public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { } + /** + * Builder for GetStatementRequest. + */ public static class Builder { /** @@ -71,7 +74,7 @@ public Builder id(UUID id) { /** * Sets the id. * - * @param verb The id of the GetStatementRequest. + * @param id The id of the GetStatementRequest. * * @return This builder * diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetVoidedStatementRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetVoidedStatementRequest.java index 4a8a13f6..573a2636 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetVoidedStatementRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetVoidedStatementRequest.java @@ -60,7 +60,7 @@ public static class Builder { /** * Sets the id. * - * @param id The id of the GetStatementRequest. + * @param id The id of the GetVoidedStatementRequest. * * @return This builder * @@ -74,7 +74,7 @@ public Builder id(UUID id) { /** * Sets the id. * - * @param verb The id of the GetStatementRequest. + * @param id The id of the GetVoidedStatementRequest. * * @return This builder * diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 10a2b87b..a34425a5 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -43,7 +43,7 @@ public XapiClient(WebClient.Builder builder) { } /** - * Gets a Statement + * Gets a Statement. * *

* The returned ResponseEntity contains the response headers and the Statement. @@ -68,7 +68,7 @@ public Mono> getStatement(GetStatementRequest request) } /** - * Gets a Statement + * Gets a Statement. * *

* The returned ResponseEntity contains the response headers and the Statement. @@ -88,7 +88,7 @@ public Mono> getStatement( } /** - * Posts Statement + * Posts Statement. * *

* The returned ResponseEntity contains the response headers and the Statement identifier. @@ -117,7 +117,7 @@ public Mono> postStatement(PostStatementRequest request) } /** - * Post Statement + * Post Statement. * *

* The returned ResponseEntity contains the response headers and the Statement identifier. @@ -137,7 +137,7 @@ public Mono> postStatement( } /** - * Posts Statements + * Posts Statements. * *

* The returned ResponseEntity contains the response headers and an array of Statement @@ -165,7 +165,7 @@ public Mono> postStatements(PostStatementsRequest reque } /** - * Posts Statements + * Posts Statements. * *

* The returned ResponseEntity contains the response headers and an array of Statement @@ -186,7 +186,7 @@ public Mono> postStatements( } /** - * Gets a voided Statement + * Gets a voided Statement. * *

* The returned ResponseEntity contains the response headers and the voided Statement. @@ -211,7 +211,7 @@ public Mono> getVoidedStatement(GetVoidedStatementRequ } /** - * Gets a voided Statement + * Gets a voided Statement. * *

* The returned ResponseEntity contains the response headers and the voided Statement. @@ -296,6 +296,18 @@ public Mono> getStatements( } + /** + * Gets a StatementResult object, a list of Statements. If additional results are available, an + * URL to retrieve them will be included in the StatementResult Object. + * + *

+ * The returned ResponseEntity contains the response headers and StatementResult. + *

+ * + * @param request The parameters of the get more statements request + * + * @return the ResponseEntity + */ public Mono> getMoreStatements(GetMoreStatementsRequest request) { Map queryParams = new HashMap<>(); @@ -312,6 +324,18 @@ public Mono> getMoreStatements(GetMoreStatements } + /** + * Gets a StatementResult object, a list of Statements. If additional results are available, an + * URL to retrieve them will be included in the StatementResult Object. + * + *

+ * The returned ResponseEntity contains the response headers and StatementResult. + *

+ * + * @param request The Consumer Builder for the get more statements request + * + * @return the ResponseEntity + */ public Mono> getMoreStatements( Consumer request) { From 114d03c45f5e5be91939b37a480b1b14b02dbc79 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 17 Feb 2023 16:14:49 +0000 Subject: [PATCH 07/17] Remove duplication in GetVoiedStatements --- .../xapi/client/GetStatementRequest.java | 20 +++---- .../client/GetVoidedStatementRequest.java | 58 +------------------ 2 files changed, 13 insertions(+), 65 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java index 7beac02d..0a284073 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java @@ -8,9 +8,9 @@ import java.util.Map; import java.util.Optional; import java.util.UUID; -import lombok.Builder; import lombok.Getter; import lombok.NonNull; +import lombok.experimental.SuperBuilder; import org.springframework.http.HttpMethod; import org.springframework.web.util.UriBuilder; @@ -23,16 +23,16 @@ * * @author Thomas Turrell-Croft */ -@Builder +@SuperBuilder @Getter public class GetStatementRequest implements Request { @NonNull - private final UUID id; + protected final UUID id; - private final StatementFormat format; + protected final StatementFormat format; - private final Boolean attachments; + protected final Boolean attachments; @Override public HttpMethod getMethod() { @@ -55,7 +55,7 @@ public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { /** * Builder for GetStatementRequest. */ - public static class Builder { + public abstract static class Builder> { /** * Sets the id. @@ -66,9 +66,9 @@ public static class Builder { * * @see GetStatementRequest#id */ - public Builder id(UUID id) { + public Builder id(UUID id) { this.id = id; - return this; + return self(); } /** @@ -80,9 +80,9 @@ public Builder id(UUID id) { * * @see GetStatementRequest#id */ - public Builder id(String id) { + public Builder id(String id) { this.id = UUID.fromString(id); - return this; + return self(); } // This static class extends the lombok builder. diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetVoidedStatementRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetVoidedStatementRequest.java index 573a2636..13bbd9aa 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetVoidedStatementRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetVoidedStatementRequest.java @@ -4,14 +4,10 @@ package dev.learning.xapi.client; -import dev.learning.xapi.model.StatementFormat; import java.util.Map; import java.util.Optional; -import java.util.UUID; -import lombok.Builder; import lombok.Getter; -import lombok.NonNull; -import org.springframework.http.HttpMethod; +import lombok.experimental.SuperBuilder; import org.springframework.web.util.UriBuilder; /** @@ -23,21 +19,10 @@ * * @author Thomas Turrell-Croft */ -@Builder +@SuperBuilder @Getter -public class GetVoidedStatementRequest implements Request { +public class GetVoidedStatementRequest extends GetStatementRequest { - @NonNull - private final UUID id; - - private final StatementFormat format; - - private final Boolean attachments; - - @Override - public HttpMethod getMethod() { - return HttpMethod.GET; - } @Override public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { @@ -52,41 +37,4 @@ public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { } - /** - * Builder for GetVoidedStatementRequest. - */ - public static class Builder { - - /** - * Sets the id. - * - * @param id The id of the GetVoidedStatementRequest. - * - * @return This builder - * - * @see GetVoidedStatementRequest#id - */ - public Builder id(UUID id) { - this.id = id; - return this; - } - - /** - * Sets the id. - * - * @param id The id of the GetVoidedStatementRequest. - * - * @return This builder - * - * @see GetVoidedStatementRequest#id - */ - public Builder id(String id) { - this.id = UUID.fromString(id); - return this; - } - - // This static class extends the lombok builder. - - } - } From 2edb9c75f33db93054f21b86b41b8075bf45a002 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 17 Feb 2023 16:27:01 +0000 Subject: [PATCH 08/17] tip --- .../main/java/dev/learning/xapi/client/XapiClient.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index a34425a5..30f467d9 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -77,9 +77,9 @@ public Mono> getStatement(GetStatementRequest request) * @return the ResponseEntity */ public Mono> getStatement( - Consumer request) { + Consumer> request) { - final GetStatementRequest.Builder builder = GetStatementRequest.builder(); + final GetStatementRequest.Builder builder = GetStatementRequest.builder(); request.accept(builder); @@ -220,9 +220,9 @@ public Mono> getVoidedStatement(GetVoidedStatementRequ * @return the ResponseEntity */ public Mono> getVoidedStatement( - Consumer request) { + Consumer> request) { - final GetVoidedStatementRequest.Builder builder = GetVoidedStatementRequest.builder(); + final GetVoidedStatementRequest.Builder builder = GetVoidedStatementRequest.builder(); request.accept(builder); From 89d25c276a1d00269207f13f9862fec6c43a5b94 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 17 Feb 2023 16:31:40 +0000 Subject: [PATCH 09/17] tip --- .../java/dev/learning/xapi/client/GetStatementRequest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java index 0a284073..93c58aca 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java @@ -55,7 +55,7 @@ public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { /** * Builder for GetStatementRequest. */ - public abstract static class Builder> { + public abstract static class Builder> { /** * Sets the id. @@ -66,7 +66,7 @@ public abstract static class Builder id(UUID id) { + public Builder id(UUID id) { this.id = id; return self(); } @@ -80,7 +80,7 @@ public Builder id(UUID id) { * * @see GetStatementRequest#id */ - public Builder id(String id) { + public Builder id(String id) { this.id = UUID.fromString(id); return self(); } From b7091872ae044989d7e5427979c7229303d075ca Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 17 Feb 2023 16:40:41 +0000 Subject: [PATCH 10/17] tip --- .../java/dev/learning/xapi/client/GetStatementRequest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java index 93c58aca..0a284073 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementRequest.java @@ -55,7 +55,7 @@ public UriBuilder url(UriBuilder uriBuilder, Map queryParams) { /** * Builder for GetStatementRequest. */ - public abstract static class Builder> { + public abstract static class Builder> { /** * Sets the id. @@ -66,7 +66,7 @@ public abstract static class Builder id(UUID id) { + public Builder id(UUID id) { this.id = id; return self(); } @@ -80,7 +80,7 @@ public abstract static class Builder id(String id) { + public Builder id(String id) { this.id = UUID.fromString(id); return self(); } From ee9d867d153a25e1a11379c35cb860551270cf49 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 17 Feb 2023 16:53:38 +0000 Subject: [PATCH 11/17] tip --- .../xapi/client/GetStatementsRequest.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementsRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementsRequest.java index d2b0c3a7..55e7d0e5 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementsRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementsRequest.java @@ -130,7 +130,7 @@ public static class Builder { */ public Builder agent(Agent agent) { this.agent = agent; - return this; + return self(); } /** @@ -144,7 +144,7 @@ public Builder agent(Agent agent) { */ public Builder agent(Consumer> agent) { - final Agent.Builder builder = Agent.builder(); + final dev.learning.xapi.model.Agent.Builder builder = Agent.builder(); agent.accept(builder); @@ -162,7 +162,7 @@ public Builder agent(Consumer> agent) { */ public Builder verb(URI verb) { this.verb = verb; - return this; + return self(); } /** @@ -176,7 +176,7 @@ public Builder verb(URI verb) { */ public Builder verb(String verb) { this.verb = URI.create(verb); - return this; + return self(); } /** @@ -190,7 +190,7 @@ public Builder verb(String verb) { */ public Builder activity(URI activity) { this.activity = activity; - return this; + return self(); } /** @@ -204,7 +204,7 @@ public Builder activity(URI activity) { */ public Builder activity(String activity) { this.activity = URI.create(activity); - return this; + return self(); } @@ -220,7 +220,7 @@ public Builder activity(String activity) { */ public Builder registration(UUID registration) { this.registration = registration; - return this; + return self(); } /** @@ -234,7 +234,7 @@ public Builder registration(UUID registration) { */ public Builder registration(String registration) { this.registration = UUID.fromString(registration); - return this; + return self(); } // This static class extends the lombok builder. From a57c0f68f7ecef64dd7700a8f9063c6fea1efbac Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Fri, 17 Feb 2023 16:54:51 +0000 Subject: [PATCH 12/17] tip --- .../learning/xapi/client/GetStatementsRequest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementsRequest.java b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementsRequest.java index 55e7d0e5..cf6005f4 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementsRequest.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/GetStatementsRequest.java @@ -130,7 +130,7 @@ public static class Builder { */ public Builder agent(Agent agent) { this.agent = agent; - return self(); + return this; } /** @@ -162,7 +162,7 @@ public Builder agent(Consumer> agent) { */ public Builder verb(URI verb) { this.verb = verb; - return self(); + return this; } /** @@ -176,7 +176,7 @@ public Builder verb(URI verb) { */ public Builder verb(String verb) { this.verb = URI.create(verb); - return self(); + return this; } /** @@ -190,7 +190,7 @@ public Builder verb(String verb) { */ public Builder activity(URI activity) { this.activity = activity; - return self(); + return this; } /** @@ -204,7 +204,7 @@ public Builder activity(URI activity) { */ public Builder activity(String activity) { this.activity = URI.create(activity); - return self(); + return this; } @@ -220,7 +220,7 @@ public Builder activity(String activity) { */ public Builder registration(UUID registration) { this.registration = registration; - return self(); + return this; } /** @@ -234,7 +234,7 @@ public Builder registration(UUID registration) { */ public Builder registration(String registration) { this.registration = UUID.fromString(registration); - return self(); + return this; } // This static class extends the lombok builder. From e7c59f3cfb12fdf4f527cc009e62726e8975c9d3 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Sun, 19 Feb 2023 14:15:48 +0000 Subject: [PATCH 13/17] tip --- .../xapi/model/StatementFormatTests.java | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 xapi-model/src/test/java/dev/learning/xapi/model/StatementFormatTests.java diff --git a/xapi-model/src/test/java/dev/learning/xapi/model/StatementFormatTests.java b/xapi-model/src/test/java/dev/learning/xapi/model/StatementFormatTests.java new file mode 100644 index 00000000..fb4613da --- /dev/null +++ b/xapi-model/src/test/java/dev/learning/xapi/model/StatementFormatTests.java @@ -0,0 +1,73 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ + +package dev.learning.xapi.model; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import org.junit.jupiter.api.Test; + +class StatementFormatTests { + + @Test + void whenCallingToStringOnCanonicalEnumResultIsLowerCase() { + + // When Calling ToString On Canonical Enum + String result = StatementFormat.CANONICAL.toString(); + + // Result Is Lower Case + assertThat(result, is("canonical")); + } + + @Test + void whenCallingGetFormatOnCanonicalEnumResultIsLowerCase() { + + // When Calling GetFormat On Canonical Enum + String result = StatementFormat.CANONICAL.getFormat(); + + // Result Is Lower Case + assertThat(result, is("canonical")); + } + + @Test + void whenCallingToStringOnExactEnumResultIsLowerCase() { + + // When Calling ToString On Exact Enum + String result = StatementFormat.EXACT.toString(); + + // Result Is Lower Case + assertThat(result, is("exact")); + } + + @Test + void whenCallingGetFormatOnExactEnumResultIsLowerCase() { + + // When Calling GetFormat On Exact Enum + String result = StatementFormat.EXACT.getFormat(); + + // Result Is Lower Case + assertThat(result, is("exact")); + } + + @Test + void whenCallingToStringOnIdsEnumResultIsLowerCase() { + + // When Calling ToString On Ids Enum + String result = StatementFormat.IDS.toString(); + + // Result Is Lower Case + assertThat(result, is("ids")); + } + + @Test + void whenCallingGetFormatOnIdsEnumResultIsLowerCase() { + + // When Calling GetFormat On Ids Enum + String result = StatementFormat.IDS.getFormat(); + + // Result Is Lower Case + assertThat(result, is("ids")); + } + +} From 6a26ba27f39652d2171ff12b9a2690b95bfbb4f2 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Sun, 19 Feb 2023 14:16:23 +0000 Subject: [PATCH 14/17] tip 2 --- .../test/java/dev/learning/xapi/client/XapiClientTests.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java index 799888f9..f3bbd585 100644 --- a/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java +++ b/xapi-client/src/test/java/dev/learning/xapi/client/XapiClientTests.java @@ -45,9 +45,8 @@ void setUp() throws Exception { mockWebServer = new MockWebServer(); mockWebServer.start(); - String baseUrl = String.format("http://localhost:%s", mockWebServer.getPort()); + webClientBuilder.baseUrl(mockWebServer.url("").toString()); - webClientBuilder.baseUrl(baseUrl); client = new XapiClient(webClientBuilder); } From 6461bab27bfabba379b20f40a481ff261f9fc56e Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Sun, 19 Feb 2023 14:32:59 +0000 Subject: [PATCH 15/17] version --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a4955860..e3bf4d4d 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ To use the xAPI Client include the appropriate XML in the `dependencies` section dev.learning.xapi xapi-client - 1.0.3 + 1.0.4 @@ -202,7 +202,7 @@ To use the xAPI Model include the appropriate XML in the `dependencies` section dev.learning.xapi xapi-model - 1.0.3 + 1.0.4 From 10d0a0ddd1bb6db5c6dba1f5711b85fd97b95ad7 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Sun, 19 Feb 2023 14:40:10 +0000 Subject: [PATCH 16/17] Update xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java --- .../src/main/java/dev/learning/xapi/client/XapiClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 30f467d9..09a0090b 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -137,7 +137,7 @@ public Mono> postStatement( } /** - * Posts Statements. + * Post Statements. * *

* The returned ResponseEntity contains the response headers and an array of Statement From f7c5f5ce162765cf7569a129408a95e44436dcf1 Mon Sep 17 00:00:00 2001 From: Thomas Turrell-Croft Date: Sun, 19 Feb 2023 14:41:59 +0000 Subject: [PATCH 17/17] Update xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java --- .../src/main/java/dev/learning/xapi/client/XapiClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java index 09a0090b..69d36218 100644 --- a/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java +++ b/xapi-client/src/main/java/dev/learning/xapi/client/XapiClient.java @@ -117,7 +117,7 @@ public Mono> postStatement(PostStatementRequest request) } /** - * Post Statement. + * Posts Statement. * *

* The returned ResponseEntity contains the response headers and the Statement identifier.