Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • fit-connect/sdk-java
1 result
Show changes
Commits on Source (34)
Showing
with 234 additions and 129 deletions
......@@ -26,19 +26,19 @@ reuse:
DOCKER_REGISTRY_READ: $DOCKER_PULL_REGISTRY
build:
image: maven:latest
image: eclipse-temurin:11.0.18_10-jdk
stage: build
script:
- ./mvnw $MAVEN_CLI_OPTS clean install -DskipTests --no-transfer-progress -T2
test:
image: maven:latest
image: eclipse-temurin:11.0.18_10-jdk
stage: test
script:
- ./mvnw $MAVEN_CLI_OPTS test --no-transfer-progress -T2
- ./mvnw $MAVEN_CLI_OPTS verify --no-transfer-progress -T2
package:
image: maven:latest
image: eclipse-temurin:11.0.18_10-jdk
stage: package
before_script: &gpg-setup
- apt-get update
......@@ -50,14 +50,15 @@ package:
- ./mvnw $MAVEN_CLI_OPTS package -DskipTests
artifacts:
paths:
- client/target/*.jar
- core/target/*.jar
- api/target/*.jar
- core/target/*.jar
- client/target/*.jar
- integration-tests/target/*.jar
expire_in: 1 day
when: manual
deploy:
image: maven:latest
image: eclipse-temurin:11.0.18_10-jdk
stage: deploy
before_script: *gpg-setup
script:
......
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Files: api/src/* client/src/* core/src/*
Files: api/src/* client/src/* core/src/* integration-tests/src/*
api/README.md client/README.md core/README.md
README.md CHANGELOG.md SECURITY.md
Copyright: 2022 FIT-Connect contributors
......@@ -10,7 +10,7 @@ Files: .mvn/wrapper/* mvnw mvnw.cmd
Copyright: 2013-2022 The Apache Software Foundation
License: Apache-2.0
Files: pom.xml api/pom.xml core/pom.xml client/pom.xml open-api/pom.xml
Files: pom.xml api/pom.xml core/pom.xml client/pom.xml integration-tests/pom.xml
.gitlab-ci.yml .gitignore .m2/release.xml
renovate.json checkstyle.xml checkstyle-suppressions.xml config.yml
Copyright: 2022 FIT-Connect contributors
......
......@@ -106,11 +106,18 @@ _The following steps show how to get the SDK running_
- add reference to private signature key (JWK) to *SUBSCRIBER* section
6. Provide config via environment variable ``FIT_CONNECT_CONFIG`` or load the config with
6. Load a configuration via:
````java
final var config = ApplicationConfigLoader.loadConfig("absolute/path/to/config.yml");
final var senderClient = ClientFactory.senderClient(config);
final ApplicationConfig config = ApplicationConfigLoader.loadConfigFromPath(Path.of("path/to/config.yml"));
````
7. Afterwards the config is used to initialize clients with the `ClientFactory` that offer clients for sender, subscriber and routing:
````java
final SenderClient senderClient = ClientFactory.getSenderClient(config);
//
final SubscriberClient subscriberClient = ClientFactory.getSubscriberClient(config);
//
final RoutingClient routingClient = ClientFactory.getRoutingClient(config);
````
<p align="right">(<a href="#top">back to top</a>)</p>
......@@ -126,7 +133,7 @@ A typical workflow using the `RoutingClient` and `SenderClient` would be:
Areas can be searched with one or more search criteria:
```java
final RoutingClient routingClient = ClientFactory.routingClient(config);
final RoutingClient routingClient = ClientFactory.getRoutingClient(config);
final var citySearchCriterion = "Leip*";
final var zipCodeSearchCriterion = "04229";
......@@ -156,7 +163,7 @@ __Note:__ Both, the `leikaKey` service-identifier and the region keys `ars/ags`c
#### Find destination by service identifier and *areaId*
```java
final RoutingClient routingClient = ClientFactory.routingClient(config);
final RoutingClient routingClient = ClientFactory.getRoutingClient(config);
final DestinationSearch search = DestinationSearch.Builder()
.withLeikaKey("99123456760610")
......@@ -178,7 +185,7 @@ for (final Route route : routes){
Besides the areaId another search criterion for the area/region can be used as well:
```java
final RoutingClient routingClient = ClientFactory.routingClient(config);
final RoutingClient routingClient = ClientFactory.getRoutingClient(config);
final DestinationSearch search = DestinationSearch.Builder()
.withLeikaKey("99123456760610")
......@@ -212,12 +219,12 @@ If all data, metadata and attachments are encrypted outside the SDK the sender c
```java
final var destinationId = UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14");
final Optional<String> publicJwk = ClientFactory.senderClient(config).getPublicKey(destinationId);
final String publicJwkAsJsonString = ClientFactory.getSenderClient(config).getPublicKey(destinationId);
```
#### 2. Send encrypted data
To send an encrypted submission the builder `EncryptedSubmissionBuilder` is needed to construct an `EncryptedSubmissionPayload` object.
To send an encrypted submission the builder `EncryptedSubmissionBuilder` is needed to construct an `SendableEncryptedSubmission` object.
The payload can be submitted as shown below via the `ClientFactory`.
If optional attachments are added, the UUID needs to be provided for each attachment to be able to announce them before the submission is actually sent.
......@@ -225,17 +232,17 @@ This is necessary because the SDK does not have access to the already encrypted
```java
// The constructed client can be reused to send multiple submissions
final SenderClient senderClient = ClientFactory.senderClient(config);
final EncryptedSubmissionPayload frontendEncryptedPayload = EncryptedSubmissionBuilder.Builder()
.withEncryptedAttachment(UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14"), "$encrpyt€ed @tt@chment") // optional
.withEncryptedData("{$encrpyt€ed json}")
.withEncryptedMetadata("$encrpyt€ed metadata")
.withDestination(UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14"))
.withServiceType("Führerscheinummeldung", "urn:de:fim:leika:leistung:99400048079000")
final SenderClient senderClient = ClientFactory.getSenderClient(config);
final SendableEncryptedSubmission encryptedSubmission = SendableEncryptedSubmission.Builder()
.setDestination(UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14"))
.setServiceType("urn:de:fim:leika:leistung:99400048079000", "Führerscheinummeldung")
.setEncryptedMetadata("$encrpyt€ed metadata")
.setEncryptedData("{$encrpyt€ed json}")
.addEncryptedAttachment(new EncryptedAttachment(UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14"), "$encrpyt€ed @tt@chment")) // optional
.build();
final SentSubmission sentSubmission = senderClient.submit(frontendEncryptedPayload);
final SentSubmission sentSubmission = senderClient.send(encryptedSubmission);
```
| **Important** |
......@@ -249,21 +256,23 @@ If all data, metadata and attachments are encrypted in the sender using the SDK,
Be aware that this example is not end-2-end encrypted, see [FIT-Connect documentation](https://docs.fitko.de/fit-connect/docs/getting-started/encryption) for details.
To send a submission the builder `SubmissionBuilder` is needed to construct a `SubmissionPayload` object.
To send a submission the builder `SubmissionBuilder` is needed to construct a `SendableSubmission` object.
The payload can be submitted as shown below via the `ClientFactory`.
```java
// The constructed client can be reused to send multiple submissions
final SenderClient senderClient = ClientFactory.senderClient(config);
final SubmissionPayload submissionPayload = SubmissionBuilder.Builder()
.withAttachment(Path.of("path/to/attachment.txt").toFile()) // optional
.withJsonData("{ \"foo\" : \"bar\"}")
.withDestination(UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14"))
.withServiceType("Führerscheinummeldung", "urn:de:fim:leika:leistung:99400048079000")
final SenderClient senderClient = ClientFactory.getSenderClient(config);
final SendableSubmission sendableSubmission = SendableSubmission.Builder()
.setDestination(UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14"))
.setServiceType("urn:de:fim:leika:leistung:99400048079000", "Führerscheinummeldung")
.setJsonData("{ \"foo\" : \"bar\"}")
// optional properties
.addAttachment(Attachment.fromPath(Path.of("path/to/attachment.txt"), "text/plain"))
.setReplyChannel(ReplyChannel.fromEmail("test@mail.org"))
.build();
final SentSubmission sentSubmission = senderClient.submit(submissionPayload);
final SentSubmission sentSubmission = senderClient.send(sendableSubmission);
```
......@@ -273,7 +282,7 @@ To read the event-log, destinationId and caseId are needed.
final var caseId = UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14");
final var destinationId = UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14");
final List<EventLogEntry> eventLog = ClientFactory.senderClient(config).getEventLog(caseId, destinationId);
final List<EventLogEntry> eventLog = ClientFactory.getSenderClient(config).getEventLog(caseId, destinationId);
for(EventLogEntry logEntry: eventLog) {
LOGGER.info("Event: {}", logEntry.getEvent());
......@@ -303,9 +312,9 @@ Instead of the entire log, the latest status for a submission can be retrieved a
```java
final SentSubmission sentSubmission = ... // persisted sent submission by sender client
final EventStatus eventStatus = ClientFactory.senderClient(config).getStatusForSubmission(sentSubmission);
final EventStatus submissionStatus = ClientFactory.getSenderClient(config).getStatusForSubmission(sentSubmission);
LOGGER.info("Current status for submission {} => {}", sentSubmission.getSubmissionId(), eventStatus.getStatus());
LOGGER.info("Current status for submission {} => {}", sentSubmission.getSubmissionId(), submissionStatus.getStatus());
```
The example output shows the current state of the submission after being created, following the transitions in the diagram below:
......@@ -326,7 +335,7 @@ More details on how this method works can be found here:
The Java SDK provides a convenient method for validating callbacks, its usage could look like this:
```java
final SenderClient senderClient = ClientFactory.senderClient(config);
final SenderClient senderClient = ClientFactory.getSenderClient(config);
final ValidationResult validationResult = senderClient.validateCallback("hmac", 0L, "body", "secret");
......@@ -342,45 +351,62 @@ Submissions can be fetched by id or as a list of submissions for a specific case
#### List with pagination
Limit and offset parameters allow to page through the result.
```java
final var subscriberClient = ClientFactory.getSubscriberClient(config);
final int offset = 0;
final int limit = 100;
final var destinationId = UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14");
final Set<SubmissionForPickup> firstOneHundredSubmissions = ClientFactory.subscriberClient(config).getAvailableSubmissions(destinationId), limit, offset);
final Set<SubmissionForPickup> firstOneHundredSubmissions = subscriberClient.getAvailableSubmissionsforDestination(destinationId), limit, offset);
```
#### List without pagination
Listing available submissions without pagination pulls the first 500 entries.
```java
final var subscriberClient = ClientFactory.getSubscriberClient(config);
final var destinationId= UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14");
final Set<SubmissionForPickup> submissions = ClientFactory.subscriberClient(config).getAvailableSubmissions(destinationId);
final Set<SubmissionForPickup> submissions = subscriberClient.getAvailableSubmissionsForDestination(destinationId);
```
#### Receive single submission
#### Receive single submission
```java
final submissionId = UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14");
final ReceivedSubmission receivedSubmission = ClientFactory.subscriberClient(config).requestSubmission(submissionId);
// by id
final var submissionId = UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14");
final ReceivedSubmission receivedSubmission = ClientFactory.getSubscriberClient(config).requestSubmission(submissionId);
```
```java
// by object
final SubmissionForPickup submissionForPickup = // code for sending submission;
final ReceivedSubmission receivedSubmission = ClientFactory.getSubscriberClient(config).requestSubmission(submissionForPickup);
```
Now, the received submission allows access to the decrypted data, attachments, metadata and ids
```java
// access data
final String data = receivedData.getData();
final URI dataSchemaUri = receivedData.getDataSchemaUri();
final MimeType mimeType = receivedData.getDataMimeType();
final String data = receivedSubmission.getDataAsString();
final URI dataSchemaUri = receivedSubmission.getDataSchemaUri();
final String mimeType = receivedSubmission.getDataMimeType();
// access metadata
final Metadata = receivedData.getSubmissionMetdata();
final Metadata metadata = receivedSubmission.getSubmissionMetdata();
// access reply channel
final ReplyChannel replyChannel = metadata.getReplyChannel();
// access attachments
for(final ReceivedAttachment attachment : receivedSubmission.getAttachments()){
final byte[] attachmentRawData = attachment.getData();
for(final Attachment attachment : receivedSubmission.getAttachments()){
final String originalFilename = attachment.getFilename();
final UUID attachmentId = attachment.getAttachmentId();
final String attachmentMimeType = attachment.getMimeType();
// different formats to retrieve the attachment content
final byte[] attachmentDataAsBytes = attachment.getDataAsBytes();
final String attachmentDataAsString = attachment.getDataAString(StandardCharsets.UTF_8);
}
// access further ids of submission
final UUID caseId = receivedData.getCaseId();
final UUID submissionId = receivedData.getSubmissionId();
final UUID destinationId = receivedData.getDestinationId();
final UUID caseId = receivedSubmission.getCaseId();
final UUID submissionId = receivedSubmission.getSubmissionId();
final UUID destinationId = receivedSubmission.getDestinationId();
```
### Sending events to the event-log
......@@ -389,13 +415,20 @@ In order to accept or reject a submission, the subscriber client can send events
For more details please see the documentation on [events](https://docs.fitko.de/fit-connect/docs/getting-started/event-log/overview) and the creation of [set-events](https://docs.fitko.de/fit-connect/docs/getting-started/event-log/set-creation).
#### Accepting a submission
If the functional review by the subscriber was positive, the submission can be accepted with an `accept-submission` event.
If the functional review by the subscriber was positive, the submission can be accepted with an `accept-submission` event.
For this event a list of optional problems can be sent, the submission is still accepted but with remarks.
```java
final var submissionId = UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14");
ClientFactory.subscriberClient(config)
.requestSubmission(submissionId)
ClientFactory.getSubscriberClient(config)
.requestSubmission(submissionId);
.acceptSubmission();
// OR accept with an optional list of problems
ClientFactory.getSubscriberClient(config)
.requestSubmission(submissionId);
.acceptSubmission(List.of(new MyCustomProblem()));
```
After the accept event was sent the submission transitions into the state `deleted` and is removed.
#### Rejecting a submission
......@@ -405,11 +438,9 @@ See the Fit-Connect documentation for more details on [available (technical) pro
```java
final var submissionId = UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14");
final var rejectionProblems = List.of(new DataSchemaViolation());
ClientFactory.subscriberClient(config)
.requestSubmission(submissionId)
.rejectSubmission(rejectionProblems);
ClientFactory.getSubscriberClient(config)
.requestSubmission(submissionId);
.rejectSubmission(List.of(new DataSchemaViolation()));
```
After the rejection event was sent the submission transitions into the state `deleted` and is removed.
......@@ -419,7 +450,7 @@ To read the event-log, destinationId and caseId are needed.
final var caseId = UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14");
final var destinationId = UUID.fromString("d2d43892-9d9c-4630-980a-5af341179b14");
final List<EventLogEntry> eventLog = ClientFactory.subscriberClient(config).getEventLog(caseId, destinationId);
final List<EventLogEntry> eventLog = ClientFactory.getSubscriberClient(config).getEventLog(caseId, destinationId);
for(EventLogEntry logEntry: eventLog) {
LOGGER.info("Event: {}", logEntry.getEvent());
......@@ -450,7 +481,7 @@ For more details please see the [event-log documentation](https://docs.fitko.de/
The validation of callbacks works similar to the sender side (see [Sender Callback Validation](#validating-callbacks)), but instead of the `SenderClient`, we use the `SubscriberClient`:
```java
final SubscriberClient subscriberClient = ClientFactory.subscriberClient(config);
final SubscriberClient subscriberClient = ClientFactory.getSubscriberClient(config);
final ValidationResult validationResult = subscriberClient.validateCallback("hmac", 0L, "body", "secret");
......@@ -461,8 +492,8 @@ if(validationResult.hasError()){
## Integration Tests
Integration tests in `dev.fitko.fitconnect.client.ClientIntegrationTest` run only on the CI-Server and are ignored by default locally.
To run them on a local machine the following environment variables have to be set in the run-configuration of the IDE:
Integration tests do not run per default with `mvn test`, but they can be executed with the maven profile `IntegrationTests` via `mvn -PIntegrationTests test`.
They expect the following environment variables to be set in the rn configuration of the IDE or on the local terminal:
* SENDER_CLIENT_ID
* SENDER_CLIENT_SECRET
......@@ -481,9 +512,8 @@ var submissionBaseUrl = "https://submission-api-testing.fit-connect.fitko.dev";
```
## Roadmap
- [ ] Add auto-reject on technical errors
- [ ] Maven central release of 1.0.0
- [ ] Maven central release of 1.0.0-beta
See the [open issues](https://git.fitko.de/fit-connect/planning/-/boards/44?search=SDK) for a full list of proposed features (and known issues).
......@@ -506,6 +536,6 @@ Hierfür kann das SDK in die anzubindenden Software integriert werden.
Erfolgt die Integration des SDK in unveränderter Form, liegt keine Bearbeitung im Sinne der EUPL bzw. des deutschen Urheberrechts vor.
Die Art und Weise der Verlinkung des SDK führt insbesondere nicht zur Schaffung eines abgeleiteten Werkes.
Die unveränderte Übernahme des SDK in eine anzubindende Software führt damit nicht dazu, dass die anzubindende Software unter den Bedingungen der EUPL zu lizenzieren ist.
Für die Weitergabe des SDK selbst - in unveränderter oder bearbeiteter Form, als Quellcode oder ausführbares Programm - gelten die Lizenzbedingungen der EUPL in unverände*rter Weise.
Für die Weitergabe des SDK selbst - in unveränderter oder bearbeiteter Form, als Quellcode oder ausführbares Programm - gelten die Lizenzbedingungen der EUPL in unveränderter Weise.*
<p align="right">(<a href="#top">back to top</a>)</p>
......@@ -17,13 +17,21 @@ import java.util.stream.Collectors;
@AllArgsConstructor
public class ApplicationConfig {
@Builder.Default
public static final String AUTH_TAG_SPLIT_TOKEN = "\\.";
@Builder.Default
private String httpProxyHost = "";
@Builder.Default
private Integer httpProxyPort = 0;
@Builder.Default
private Integer requestTimeoutInSeconds = 30;
@Builder.Default
private boolean enableAutoReject = true;
@Builder.Default
private URI setSchemaWriteVersion = SchemaConfig.SET_V_1_0_1.getSchemaUri();
......@@ -120,5 +128,9 @@ public class ApplicationConfig {
.map(EnvironmentName::getName)
.collect(Collectors.joining(" | "));
}
public boolean isProxySet() {
return (httpProxyPort != null && httpProxyPort > 0) && (httpProxyHost != null || !httpProxyHost.isEmpty());
}
}
......@@ -5,6 +5,8 @@ import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@Builder
@AllArgsConstructor
......@@ -12,6 +14,6 @@ import lombok.NoArgsConstructor;
public class SubscriberConfig {
private String clientId;
private String clientSecret;
private String privateDecryptionKeyPath;
private List<String> privateDecryptionKeyPaths;
private String privateSigningKeyPath;
}
......@@ -2,6 +2,7 @@ package dev.fitko.fitconnect.api.domain.model.destination;
import com.fasterxml.jackson.annotation.JsonProperty;
import dev.fitko.fitconnect.api.domain.model.replychannel.ReplyChannel;
import dev.fitko.fitconnect.api.domain.model.submission.Callback;
import lombok.Data;
import lombok.NoArgsConstructor;
......
package dev.fitko.fitconnect.api.domain.model.destination;
import com.fasterxml.jackson.annotation.JsonProperty;
import dev.fitko.fitconnect.api.domain.model.replychannel.ReplyChannel;
import lombok.Data;
import lombok.NoArgsConstructor;
......
......@@ -100,12 +100,12 @@ public enum Event {
@Override
public SubmissionState getState() {
return SubmissionState.SUBMITTED;
return SubmissionState.NOTIFIED;
}
@Override
public Set<Event> allowedNextEvents() {
return Set.of(SUBMIT);
return Set.of(ACCEPT, REJECT, FORWARD);
}
},
......
......@@ -9,5 +9,7 @@ public final class EventClaimFields {
public static final String CLAIM_SCHEMA = "$schema";
public static final String CLAIM_TXN = "txn";
public static final String CLAIM_SUB = "sub";
public static final String AUTHENTICATION_TAGS = "authenticationTags";
public static final String PROBLEMS = "problems";
public static final String HEADER_TYPE = "secevent+jwt";
}
......@@ -2,43 +2,72 @@ package dev.fitko.fitconnect.api.domain.model.event;
import dev.fitko.fitconnect.api.domain.model.event.problems.Problem;
import dev.fitko.fitconnect.api.domain.model.submission.Submission;
import dev.fitko.fitconnect.api.domain.model.submission.SubmissionForPickup;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@Data
@Builder
@AllArgsConstructor
public class EventPayload {
private UUID submissionId;
private UUID destinationId;
private UUID caseId;
// used for auth-tag validation
private String encryptedMetadata;
private String encryptedData;
private Map<UUID, String> encryptedAttachments;
private List<Problem> problems;
public EventPayload(final Submission submission, final Map<UUID, String> encryptedAttachments, final List<Problem> problems) {
submissionId = submission.getSubmissionId();
destinationId = submission.getDestinationId();
caseId = submission.getCaseId();
encryptedData = submission.getEncryptedData();
encryptedMetadata = submission.getEncryptedMetadata();
this.encryptedAttachments = encryptedAttachments;
this.problems = problems;
public static EventPayload forRejectEvent(final SubmissionForPickup submission, final List<Problem> problems){
return EventPayload.builder()
.submissionId(submission.getSubmissionId())
.destinationId(submission.getDestinationId())
.caseId(submission.getCaseId())
.problems(problems)
.build();
}
public EventPayload(final Submission submission, final Map<UUID, String> encryptedAttachments) {
this(submission, encryptedAttachments, Collections.emptyList());
public static EventPayload forRejectEvent(final Submission submission, final List<Problem> problems){
return EventPayload.builder()
.submissionId(submission.getSubmissionId())
.destinationId(submission.getDestinationId())
.caseId(submission.getCaseId())
.problems(problems)
.build();
}
public EventPayload(final Submission submission, final List<Problem> problems) {
this(submission, Collections.emptyMap(), problems);
public static EventPayload forAcceptEvent(final Submission submission, final Problem... problems){
return EventPayload.builder()
.submissionId(submission.getSubmissionId())
.destinationId(submission.getDestinationId())
.caseId(submission.getCaseId())
.encryptedData(submission.getEncryptedData())
.encryptedMetadata(submission.getEncryptedMetadata())
.encryptedAttachments(Collections.emptyMap())
.problems(Arrays.asList(problems))
.build();
}
public EventPayload(final Submission submission) {
this(submission, Collections.emptyMap(), Collections.emptyList());
public static EventPayload forAcceptEventWithAttachments(final Submission submission, final Map<UUID, String> encryptedAttachments, final Problem... problems){
return EventPayload.builder()
.submissionId(submission.getSubmissionId())
.destinationId(submission.getDestinationId())
.caseId(submission.getCaseId())
.encryptedData(submission.getEncryptedData())
.encryptedMetadata(submission.getEncryptedMetadata())
.encryptedAttachments(encryptedAttachments)
.problems(Arrays.asList(problems))
.build();
}
}
......@@ -7,7 +7,8 @@ public enum SubmissionState {
ACCEPTED("accepted"),
REJECTED("rejected"),
DELETED("deleted"),
FORWARDED("forwarded");
FORWARDED("forwarded"),
NOTIFIED("notified");
private final String name;
......
......@@ -10,7 +10,7 @@ import java.util.List;
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class EventStatus {
public class SubmissionStatus {
SubmissionState status;
List<Problem> problems;
}
......@@ -7,7 +7,9 @@ import java.util.UUID;
@Data
public class AuthenticationTags {
private String metadata;
private String data;
private Map<UUID, String> attachments;
}
package dev.fitko.fitconnect.api.domain.model.event.problems;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
......@@ -12,11 +13,19 @@ import lombok.Data;
@Data
@AllArgsConstructor
public class Problem {
@JsonIgnore
public static final String SCHEMA_URL = "https://schema.fitko.de/fit-connect/events/problems/";
@JsonProperty("type")
private final String type;
@JsonProperty("title")
private final String title;
@JsonProperty("detail")
private final String detail;
@JsonProperty("instance")
private final String instance;
}
......@@ -2,16 +2,18 @@ package dev.fitko.fitconnect.api.domain.model.event.problems.attachment;
import dev.fitko.fitconnect.api.domain.model.event.problems.Problem;
import java.util.UUID;
import static java.lang.String.format;
public class AttachmentEncryptionIssue extends Problem {
public final class AttachmentEncryptionIssue extends Problem {
private static final String type = SCHEMA_URL + "encryption-issue";
private static final String title = "Entschlüsselungs-Fehler";
private static final String detail = "Die Anlage %s konnte nicht entschlüsselt werden.";
private static final String instance = "attachment:%s";
private static final String TYPE = SCHEMA_URL + "encryption-issue";
private static final String TITLE = "Decryption failure";
private static final String DETAIL = "Decrypting attachment %s failed.";
private static final String INSTANCE = "attachment:%s";
public AttachmentEncryptionIssue(final String attachmentId) {
super(type, title, format(detail, attachmentId), format(instance, attachmentId));
public AttachmentEncryptionIssue(final UUID attachmentId) {
super(TYPE, TITLE, format(DETAIL, attachmentId), format(INSTANCE, attachmentId));
}
}
......@@ -4,14 +4,18 @@ import dev.fitko.fitconnect.api.domain.model.event.problems.Problem;
import static java.lang.String.format;
public class AttachmentEncryptionKeyIssue extends Problem {
public final class AttachmentEncryptionKeyIssue extends Problem {
private static final String type = SCHEMA_URL + "encryption-issue";
private static final String title = "Entschlüsselungs-Fehler";
private static final String detail = "Der Schlüssel %s ist nicht der zu diesem Zweck vorgesehene Schlüssel.";
private static final String instance = "attachment:%s";
private static final String TYPE = SCHEMA_URL + "encryption-issue";
private static final String TITLE = "Decryption failure";
private static final String DETAIL = "The key %s is not the key intended for this purpose.";
private static final String INSTANCE = "attachment:%s";
public AttachmentEncryptionKeyIssue(final String keyId) {
super(type, title, format(detail, keyId), format(instance, keyId));
super(TYPE, TITLE, format(DETAIL, keyId), format(INSTANCE, keyId));
}
public static Problem getWithAttachmentId(final String keyId) {
return new AttachmentEncryptionKeyIssue(keyId);
}
}
......@@ -2,16 +2,18 @@ package dev.fitko.fitconnect.api.domain.model.event.problems.attachment;
import dev.fitko.fitconnect.api.domain.model.event.problems.Problem;
import java.util.UUID;
import static java.lang.String.format;
public class AttachmentHashMismatch extends Problem {
public final class AttachmentHashMismatch extends Problem {
private static final String type = SCHEMA_URL + "hash-mismatch";
private static final String title = "Prüfsumme stimmt nicht";
private static final String detail = "Der Hash der Anlage %s stimmt nicht.";
private static final String instance = "attachment:%s";
private static final String TYPE = SCHEMA_URL + "hash-mismatch";
private static final String TITLE = "Checksum does not match";
private static final String DETAIL = "Attachment %s hash value is wrong.";
private static final String INSTANCE = "attachment:%s";
public AttachmentHashMismatch(final String attachmentId) {
super(type, title, format(detail, attachmentId), format(instance, attachmentId));
public AttachmentHashMismatch(final UUID attachmentId) {
super(TYPE, TITLE, format(DETAIL, attachmentId), format(INSTANCE, attachmentId));
}
}
......@@ -2,16 +2,18 @@ package dev.fitko.fitconnect.api.domain.model.event.problems.attachment;
import dev.fitko.fitconnect.api.domain.model.event.problems.Problem;
import java.util.UUID;
import static java.lang.String.format;
public class IncorrectAttachmentAuthenticationTag extends Problem {
public final class IncorrectAttachmentAuthenticationTag extends Problem {
private static final String type = SCHEMA_URL + "incorrect-authentication-tag";
private static final String title = "Authentication-Tag ungültig";
private static final String detail = "Das Authentication-Tag der Anlage %s ist ungültig.";
private static final String instance = "attachment:%s";
private static final String TYPE = SCHEMA_URL + "incorrect-authentication-tag";
private static final String TITLE = "Authentication tag is invalid";
private static final String DETAIL = "The authentication tag for the attachment %s is invalid.";
private static final String INSTANCE = "attachment:%s";
public IncorrectAttachmentAuthenticationTag(final String attachmentId) {
super(type, title, format(detail, attachmentId), format(instance, attachmentId));
public IncorrectAttachmentAuthenticationTag(final UUID attachmentId) {
super(TYPE, TITLE, format(DETAIL, attachmentId), format(INSTANCE, attachmentId));
}
}
......@@ -2,16 +2,19 @@ package dev.fitko.fitconnect.api.domain.model.event.problems.attachment;
import dev.fitko.fitconnect.api.domain.model.event.problems.Problem;
import java.util.UUID;
import static java.lang.String.format;
public class InvalidAttachmentContent extends Problem {
public final class InvalidAttachmentContent extends Problem {
private static final String type = SCHEMA_URL + "invalid-content";
private static final String title = "Unzulässiger Inhalt";
private static final String detail = "Der Inhalt der Anlage %s ist nicht zulässig.";
private static final String instance = "attachment:%s";
private static final String TYPE = SCHEMA_URL + "invalid-content";
private static final String TITLE = "Invalid content";
private static final String DETAIL = "The content of the attachment %s is not allowed.";
private static final String INSTANCE = "attachment:%s";
public InvalidAttachmentContent(final String attachmentId) {
super(type, title, format(detail, attachmentId), format(instance, attachmentId));
public InvalidAttachmentContent(final UUID attachmentId) {
super(TYPE, TITLE, format(DETAIL, attachmentId), format(INSTANCE, attachmentId));
}
}
......@@ -2,15 +2,17 @@ package dev.fitko.fitconnect.api.domain.model.event.problems.attachment;
import dev.fitko.fitconnect.api.domain.model.event.problems.Problem;
import java.util.UUID;
import static java.lang.String.format;
public class MissingAttachment extends Problem {
private static final String type = SCHEMA_URL + "missing-attachment";
private static final String title = "Anlage fehlt";
private static final String detail = "Die Anlage %s konnte nicht geladen werden.";
private static final String instance = "attachment:%s";
public final class MissingAttachment extends Problem {
private static final String TYPE = SCHEMA_URL + "missing-attachment";
private static final String TITLE = "List of attachments is invalid";
private static final String DETAIL = "Unable to load attachment %s.";
private static final String INSTANCE = "attachment:%s";
public MissingAttachment(final String attachmentId){
super(type, title, format(detail, attachmentId), format(instance, attachmentId));
public MissingAttachment(final UUID attachmentId){
super(TYPE, TITLE, format(DETAIL, attachmentId), format(INSTANCE, attachmentId));
}
}