Skip to content
This repository has been archived by the owner on May 16, 2023. It is now read-only.

Added pocnat endpoint #121

Merged
merged 5 commits into from
Feb 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 73 additions & 5 deletions src/main/java/app/coronawarn/testresult/TestResultController.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@

package app.coronawarn.testresult;

import app.coronawarn.testresult.model.PocNatResultList;
import app.coronawarn.testresult.model.QuickTestResultList;
import app.coronawarn.testresult.model.TestResult;
import app.coronawarn.testresult.model.TestResultList;
import app.coronawarn.testresult.model.TestResultRequest;
import app.coronawarn.testresult.model.TestResultResponse;
import app.coronawarn.testresult.model.TestType;
import app.coronawarn.testresult.service.TestResultService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
Expand Down Expand Up @@ -79,10 +81,10 @@ public ResponseEntity<TestResultResponse> result(
) {
log.info("Received test result request from app.");

TestResult result = testResultService.getOrCreate(request.getId(), false, null);
TestResult result = testResultService.getOrCreate(request.getId(), TestType.PCR, null);
return ResponseEntity.ok(new TestResultResponse()
.setLabId(result.getLabId())
.setTestResult(result.getResult(), result.getSc())
.setTestResult(testResultService.conversionCheck(result.getResult()), result.getSc())
);
}

Expand All @@ -108,7 +110,7 @@ public ResponseEntity<TestResultResponse> result(
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<?> results(
public ResponseEntity<Object> results(
@org.springframework.web.bind.annotation.RequestBody @NotNull @Valid TestResultList list
) {
log.info("Received {} test results to insert or update from lab.", list.getTestResults().size());
Expand Down Expand Up @@ -146,7 +148,7 @@ public ResponseEntity<TestResultResponse> quickTestResult(
@org.springframework.web.bind.annotation.RequestBody @Valid TestResultRequest request
) {
log.info("Received test result request from Quicktest.");
TestResult result = testResultService.getOrCreate(request.getId(), true, request.getSc());
TestResult result = testResultService.getOrCreate(request.getId(), TestType.QUICKTEST, request.getSc());
return ResponseEntity.ok(new TestResultResponse()
.setLabId(result.getLabId())
.setTestResult(result.getResult()));
Expand Down Expand Up @@ -174,7 +176,7 @@ public ResponseEntity<TestResultResponse> quickTestResult(
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<?> quicktestResults(
public ResponseEntity<Object> quicktestResults(
@org.springframework.web.bind.annotation.RequestBody @NotNull @Valid QuickTestResultList list
) {
log.info("Received {} test result to insert or update from Quicktests. ", list.getTestResults().size());
Expand All @@ -185,4 +187,70 @@ public ResponseEntity<?> quicktestResults(

return ResponseEntity.noContent().build();
}

/**
* Get the test result response from a request containing the id.
*
* @param request the test result request with id
* @return the test result response
*/
@Operation(
description = "The result and the sc (sample collection) timestamp of a PoC-NAT can be set.",
summary = "Set the testresult for a PoC-NAT.",
requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = TestResultRequest.class))),
responses = {
@ApiResponse(
responseCode = "200",
description = "Ok, PoC-NAT result inserted successfully."
)
}
)
@PostMapping(
value = "/api/v1/pocnat/result",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<TestResultResponse> pocnatResult(
@org.springframework.web.bind.annotation.RequestBody @Valid TestResultRequest request
) {
log.info("Received test result request from PoC-NAT.");
TestResult result = testResultService.getOrCreate(request.getId(), TestType.POCNAT, request.getSc());
return ResponseEntity.ok(new TestResultResponse()
.setLabId(result.getLabId())
.setTestResult(result.getResult()));
}

/**
* Insert or update the PoC-NAT.
*
* @param list the test result list request
* @return the response
*/
@Operation(
description = "The result and the sc (sample collection) timestamp of a PoC-NAT can be set.",
summary = "Set multiple testresults for a PoC-NAT as an array.",
requestBody = @RequestBody(content = @Content(schema = @Schema(implementation = TestResultRequest.class))),
responses = {
@ApiResponse(
responseCode = "204",
description = "No content, PoC-NAT result(s) inserted successfully."
)
}
)
@PostMapping(
value = "/api/v1/pocnat/results",
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<Object> pocnatResults(
@org.springframework.web.bind.annotation.RequestBody @NotNull @Valid PocNatResultList list
) {
log.info("Received {} test result to insert or update from PoC-NATs. ", list.getTestResults().size());

list.getTestResults().stream()
.map(tr -> testResultService.convertPocNat(tr, list.getLabId()))
.forEach(testResultService::createOrUpdate);

return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public TestResultEntity setLabId(String labId) {

public enum Result {
PENDING, NEGATIVE, POSITIVE, INVALID, REDEEMED,
QUICK_PENDING, QUICK_NEGATIVE, QUICK_POSITIVE, QUICK_INVALID, QUICK_REDEEMED
QUICK_PENDING, QUICK_NEGATIVE, QUICK_POSITIVE, QUICK_INVALID, QUICK_REDEEMED,
POCNAT_PENDING, POCNAT_NEGATIVE, POCNAT_POSITIVE, POCNAT_INVALID, POCNAT_REDEEMED
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ public class TestResultExceptionHandler {
MethodArgumentNotValidException.class,
ConstraintViolationException.class
})
public ResponseEntity<?> handleValidationExceptions() {
public ResponseEntity<Object> handleValidationExceptions() {
log.warn("Request contains invalid arguments or constraint violations in body.");
return ResponseEntity.badRequest().build();
}

@ExceptionHandler(TestResultException.class)
public ResponseEntity<?> handleTestResultExceptions(
public ResponseEntity<Object> handleTestResultExceptions(
TestResultException exception
) {
log.warn("Request produced a test result exception with status {}.", exception.getStatus());
Expand Down
77 changes: 77 additions & 0 deletions src/main/java/app/coronawarn/testresult/model/PocNatResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Corona-Warn-App / cwa-testresult-server
*
* (C) 2020, T-Systems International GmbH
*
* Deutsche Telekom AG and all other contributors /
* copyright owners license this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package app.coronawarn.testresult.model;

import io.swagger.v3.oas.annotations.media.Schema;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;

/**
* Model of the test result.
*/
@Schema(
description = "The PoC-NAT result model."
)
@Getter
@Setter
@ToString
@EqualsAndHashCode
@Accessors(chain = true)
public class PocNatResult {

/**
* Hash (SHA256) of test result id (aka QR-Code, GUID) encoded as hex string.
*/
@NotBlank
@Pattern(regexp = "^[XxA-Fa-f0-9]([A-Fa-f0-9]{63})$")
@Schema(description = "the testId (Hashed GUID")
private String id;

/**
* The test result.
* 10: PoC-NAT-Pending
* 11: PoC-NAT-Negative
* 12: PoC-NAT-Positive
* 13: PoC-NAT-Invalid
* 14: PoC-NAT-Redeemed
*/
@Min(10)
@Max(14)
@NotNull
@Schema(description = "the result of the PoC-NAT", required = true)
private Integer result;

/**
* Timestamp of the SampleCollection (sc).
*/
@Schema(description = "the timestamp of the sample collection (sc) in unix epoch format. If not set,"
+ " the time of insertion will be used instead")
private Long sc;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Corona-Warn-App / cwa-testresult-server
*
* (C) 2020, T-Systems International GmbH
*
* Deutsche Telekom AG and all other contributors /
* copyright owners license this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this
* file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package app.coronawarn.testresult.model;

import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;



/**
* Model of the test result list.
*/
@Schema(
description = "The PoC-NAT result list model."
)
@Getter
@Setter
@ToString
@EqualsAndHashCode
@Accessors(chain = true)
public class PocNatResultList {

/**
* The test result entries.
*/
@NotNull
@NotEmpty
@Schema(description = "array of PoC-NAT results", required = true)
private List<@Valid PocNatResult> testResults;

/**
* The labId of the uploader.
*/
@Schema(description = "The id that identifies a lab. Every lab can choose its own labid, "
+ "but it must be unique over all labs, should be generated once via cryptographic hash function",
required = true, maxLength = 64)
@JsonInclude(JsonInclude.Include.NON_NULL)
private String labId;
}
7 changes: 7 additions & 0 deletions src/main/java/app/coronawarn/testresult/model/TestType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package app.coronawarn.testresult.model;

public enum TestType {
PCR,
QUICKTEST,
POCNAT
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@
import app.coronawarn.testresult.TestResultRepository;
import app.coronawarn.testresult.entity.TestResultEntity;
import app.coronawarn.testresult.exception.TestResultException;
import app.coronawarn.testresult.model.PocNatResult;
import app.coronawarn.testresult.model.QuickTestResult;
import app.coronawarn.testresult.model.TestResult;
import app.coronawarn.testresult.model.TestType;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
Expand Down Expand Up @@ -97,7 +99,7 @@ public TestResult createOrUpdate(final TestResult result) {
LocalDateTime sc = LocalDateTime.now();
if (result.getSc() != null) {
log.warn("Set Sc for Lab {}", result.getLabId());
sc = LocalDateTime.ofEpochSecond(result.getSc(),0, ZoneOffset.UTC);
sc = LocalDateTime.ofEpochSecond(result.getSc(), 0, ZoneOffset.UTC);
}
entity.setResult(result.getResult())
.setResultDate(sc);
Expand All @@ -118,23 +120,26 @@ public TestResult createOrUpdate(final TestResult result) {
* @param id the test result id
* @return the test result
*/
public TestResult getOrCreate(final String id, boolean quicktest, Long sc) {
public TestResult getOrCreate(final String id, TestType testtype, Long sc) {
try {
TestResultEntity entity = testResultRepository.findByResultId(id)
.orElseGet(() -> {
log.info("Get failed now creating test result in database.");
TestResultEntity resultEntity = new TestResultEntity();
if (quicktest) {
if (testtype == TestType.QUICKTEST) {
resultEntity.setResult(TestResultEntity.Result.QUICK_PENDING.ordinal());
resultEntity.setResultId(DigestUtils.sha256Hex(id));
} else if (testtype == TestType.POCNAT) {
resultEntity.setResult(TestResultEntity.Result.POCNAT_PENDING.ordinal());
resultEntity.setResultId(id);
} else {
resultEntity.setResult(TestResultEntity.Result.PENDING.ordinal());
resultEntity.setResultId(id);
}
if (sc == null) {
log.info("Set Sc during get or create");
resultEntity.setResultDate(LocalDateTime.now());
} else {
} else {
resultEntity.setResultDate(LocalDateTime.ofEpochSecond(sc, 0, ZoneOffset.UTC));
}
return testResultRepository.save(resultEntity);
Expand Down Expand Up @@ -162,4 +167,31 @@ public TestResult convertQuickTest(QuickTestResult quickTestResult, String labId
return testResult;
}

/**
* Converting a PoCNATResult to Testresult for saving.
*
* @param pocnatResult the Result to convert
* @return the converted test result
*/
public TestResult convertPocNat(PocNatResult pocnatResult, String labId) {
TestResult testResult = new TestResult();
testResult.setResult(pocnatResult.getResult());
testResult.setLabId(labId);
testResult.setId(DigestUtils.sha256Hex(pocnatResult.getId()));
testResult.setSc(pocnatResult.getSc());
return testResult;
}

/**
* Checks and converts PoC-NAT results to PCR results for REST reponse.
*
* @param result the Result to check and possibly convert
* @return either the original result or the converted result
*/
public Integer conversionCheck(Integer result) {
if (result >= 10 && result <= 14) {
result -= 10;
}
return result;
}
}
Loading