Commit 2572cade authored by Bergamote Orange's avatar Bergamote Orange
Browse files

wip

parent 5834b99c
Pipeline #293425 passed with stages
in 28 minutes and 24 seconds
......@@ -155,11 +155,14 @@
</goals>
<configuration>
<inputSpec>
${project.basedir}/src/main/resources/api-clea-server-specs/v1/api-clea-server-v1.yml
${project.basedir}/src/main/resources/api-clea-server-specs/v1/openapi-clea-server-v1.yml
</inputSpec>
<apiPackage>fr.gouv.clea.ws.api.v1</apiPackage>
<modelPackage
>fr.gouv.clea.ws.api.v1.model</modelPackage>
<modelPackage>fr.gouv.clea.ws.api.v1.model
</modelPackage>
<configOptions>
<useBeanValidation>false</useBeanValidation>
</configOptions>
</configuration>
</execution>
<execution>
......@@ -169,11 +172,19 @@
</goals>
<configuration>
<inputSpec>
${project.basedir}/src/main/resources/api-clea-server-specs/v2/with-validation.yml
${project.basedir}/src/main/resources/api-clea-server-specs/v2/openapi-with-validation-clea-server-v2.yml
</inputSpec>
<apiPackage>fr.gouv.clea.ws.api.v2</apiPackage>
<modelPackage
>fr.gouv.clea.ws.api.v2.model</modelPackage>
<modelPackage>fr.gouv.clea.ws.api.v2.model
</modelPackage>
<typeMappings>
<typeMapping
>OffsetDateTime=Instant</typeMapping>
</typeMappings>
<importMappings>
<importMapping
>java.time.OffsetDateTime=java.time.Instant</importMapping>
</importMappings>
</configuration>
</execution>
<execution>
......@@ -183,14 +194,22 @@
</goals>
<configuration>
<inputSpec>
${project.basedir}/src/main/resources/api-clea-server-specs/v2/without-validation.yml
${project.basedir}/src/main/resources/api-clea-server-specs/v2/openapi-without-validation-clea-server-v2.yml
</inputSpec>
<apiPackage>fr.gouv.clea.ws.api.v2</apiPackage>
<modelPackage
>fr.gouv.clea.ws.api.v2.model</modelPackage>
<modelPackage>fr.gouv.clea.ws.api.v2.model
</modelPackage>
<configOptions>
<useBeanValidation>false</useBeanValidation>
</configOptions>
<typeMappings>
<typeMapping
>OffsetDateTime=Instant</typeMapping>
</typeMappings>
<importMappings>
<importMapping
>java.time.OffsetDateTime=java.time.Instant</importMapping>
</importMappings>
</configuration>
</execution>
</executions>
......
......@@ -36,7 +36,7 @@ public class CleaController implements CleaApi {
.map(this::toVisitNullSafe)
.collect(toList());
final var acceptedVisits = reportService.report(pivotDate, visits);
final var acceptedVisits = reportService.reportWithPivotDate(pivotDate, visits);
final var message = String.format("%d/%d accepted visits", acceptedVisits, reportRequest.getVisits().size());
log.info(message);
......
......@@ -25,7 +25,7 @@ import static org.springframework.http.HttpStatus.BAD_REQUEST;
@ControllerAdvice
@Slf4j
public class CleaRestExceptionHandler extends ResponseEntityExceptionHandler {
public class CleaRestExceptionHandlerV1 extends ResponseEntityExceptionHandler {
public static final String ERROR_MESSAGE_TEMPLATE = "%s, requested uri: %s";
......
......@@ -3,13 +3,40 @@ package fr.gouv.clea.ws.controller.v2;
import fr.gouv.clea.ws.api.v2.DefaultApi;
import fr.gouv.clea.ws.api.v2.model.ManualReportRequest;
import fr.gouv.clea.ws.api.v2.model.ReportResponse;
import org.springframework.http.HttpStatus;
import fr.gouv.clea.ws.service.ReportService;
import fr.gouv.clea.ws.service.model.Visit;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;
import static java.lang.Integer.toUnsignedLong;
import static java.util.stream.Collectors.toList;
@RestController
@RequiredArgsConstructor
public class ManualReportController implements DefaultApi {
private final ReportService reportService;
@Override
public ResponseEntity<ReportResponse> manualReport(final ManualReportRequest manualReportRequest) {
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
final var visits = manualReportRequest.getVisits()
.stream()
.map(this::toVisitNullSafe)
.collect(toList());
final var acceptedVisits = reportService.reportWithoutPivotDate(visits);
return ResponseEntity.ok(
ReportResponse.builder()
.accepted(toUnsignedLong(acceptedVisits))
.rejected(toUnsignedLong(manualReportRequest.getVisits().size() - acceptedVisits))
.build()
);
}
private Visit toVisitNullSafe(final fr.gouv.clea.ws.api.v2.model.Visit visit) {
return visit == null ? null
: new Visit(visit.getEncryptedLocationSpecificPart(), visit.getScanTime());
}
}
......@@ -10,14 +10,13 @@ import fr.gouv.clea.ws.service.model.Visit;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import static java.lang.Integer.toUnsignedLong;
import static java.util.stream.Collectors.toList;
import static org.springframework.util.CollectionUtils.isEmpty;
@RestController
@RequestMapping(path = "/api/clea/v2")
@RequiredArgsConstructor
@Slf4j
public class WReportController implements WithoutValidationApi {
......@@ -25,32 +24,31 @@ public class WReportController implements WithoutValidationApi {
private final ReportService reportService;
@Override
public ResponseEntity<ReportResponse> wreport(ReportRequest reportRequest) {
public ResponseEntity<ReportResponse> wreport(final ReportRequest reportRequest) {
nonNullPivotDateOrThrowBadRequest(reportRequest);
nonEmptyVisitsOrThrowBadRequest(reportRequest);
final var pivotDate = reportRequest.getPivotDate().toInstant();
final var visits = reportRequest.getVisits()
.stream()
.map(this::toVisitNullSafe)
.collect(toList());
final var acceptedVisits = reportService.report(pivotDate, visits);
final var acceptedVisits = reportService.reportWithPivotDate(reportRequest.getPivotDate(), visits);
return ResponseEntity.ok(
ReportResponse.builder()
.accepted(Integer.toUnsignedLong(acceptedVisits))
.rejected(Integer.toUnsignedLong(reportRequest.getVisits().size() - acceptedVisits))
.accepted(toUnsignedLong(acceptedVisits))
.rejected(toUnsignedLong(reportRequest.getVisits().size() - acceptedVisits))
.build()
);
}
private Visit toVisitNullSafe(fr.gouv.clea.ws.api.v2.model.Visit visit) {
private Visit toVisitNullSafe(final fr.gouv.clea.ws.api.v2.model.Visit visit) {
return visit == null ? null
: new Visit(visit.getEncryptedLocationSpecificPart(), visit.getScanTime().toInstant());
: new Visit(visit.getEncryptedLocationSpecificPart(), visit.getScanTime());
}
private void nonNullPivotDateOrThrowBadRequest(ReportRequest reportRequest) {
private void nonNullPivotDateOrThrowBadRequest(final ReportRequest reportRequest) {
if (reportRequest.getPivotDate() == null) {
throw new CleaBadRequestException(
ValidationError.builder()
......@@ -63,7 +61,7 @@ public class WReportController implements WithoutValidationApi {
}
}
private void nonEmptyVisitsOrThrowBadRequest(ReportRequest reportRequest) {
private void nonEmptyVisitsOrThrowBadRequest(final ReportRequest reportRequest) {
if (isEmpty(reportRequest.getVisits())) {
throw new CleaBadRequestException(
ValidationError.builder()
......
......@@ -21,7 +21,7 @@ import static java.util.stream.Collectors.toList;
@ControllerAdvice
@Slf4j
public class CleaRestExceptionHandler extends ResponseEntityExceptionHandler {
public class CleaRestExceptionHandlerV2 extends ResponseEntityExceptionHandler {
public static final String ERROR_MESSAGE_TEMPLATE = "%s, requested uri: %s";
......
......@@ -15,7 +15,9 @@ import org.springframework.stereotype.Service;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import static fr.gouv.clea.ws.utils.MessageFormatter.truncateQrCode;
import static java.time.Instant.now;
......@@ -36,10 +38,20 @@ public class ReportService {
private final ProducerService producerService;
public int report(final Instant pivotDate, final List<Visit> visits) {
public int reportWithPivotDate(final Instant pivotDate, final List<Visit> visits) {
final var now = now();
final var validatedPivotDate = this.validatePivotDate(pivotDate, now);
return report(pivotDate, visits, now);
}
public int reportWithoutPivotDate(final List<Visit> visits) {
final var now = now();
return report(now.minus(14, DAYS), visits, now);
}
private int report(final Instant pivotDate, final List<Visit> visits, final Instant now) {
final var validatedPivotDate = this.validatePivotDate(pivotDate, now);
final var verifiedAndDecodedVisits = visits.stream()
.filter(Objects::nonNull)
.filter(this::nonBlankBase64urlLocationSpecificPart)
......
......@@ -9,7 +9,7 @@ components:
pivotDate:
type: string
format: date-time
description: An estimate date of contamination
description: Estimated ISO 8601 instant of contamination
visits:
type: array
items:
......
......@@ -47,3 +47,39 @@ paths:
application/json:
schema:
"$ref": "components.yml#/components/schemas/ErrorResponse"
"/api/v2/wreport":
post:
tags:
- withoutValidation
summary: Upload locations history
operationId: wreport
requestBody:
content:
application/json:
schema:
"$ref": "components.yml#/components/schemas/ReportRequest"
responses:
"200":
description: Successful operation
content:
application/json:
schema:
"$ref": "components.yml#/components/schemas/ReportResponse"
"400":
description: Bad request
content:
application/json:
schema:
"$ref": "components.yml#/components/schemas/ErrorResponse"
"401":
description: Invalid authentication
content:
application/json:
schema:
"$ref": "components.yml#/components/schemas/ErrorResponse"
"500":
description: Internal error
content:
application/json:
schema:
"$ref": "components.yml#/components/schemas/ErrorResponse"
......@@ -64,7 +64,7 @@ class ReportServiceTest {
newVisit("33333333-3333-3333-3333-333333333333", now) // pass
);
final var acceptedCount = reportService.report(now.minus(5, DAYS), visits);
final var acceptedCount = reportService.reportWithPivotDate(now.minus(5, DAYS), visits);
verify(producerService).produceVisits(acceptedVisits.capture());
assertThat(acceptedVisits.getValue())
......@@ -87,7 +87,7 @@ class ReportServiceTest {
newVisit("33333333-3333-3333-3333-333333333333", now.plus(1, DAYS)) // don't pass
);
final var acceptedCount = reportService.report(now.minus(5, DAYS), visits);
final var acceptedCount = reportService.reportWithPivotDate(now.minus(5, DAYS), visits);
verify(producerService).produceVisits(acceptedVisits.capture());
assertThat(acceptedVisits.getValue())
......@@ -111,7 +111,7 @@ class ReportServiceTest {
newVisit("44444444-4444-4444-4444-444444444444", now) // pass
);
final var acceptedCount = reportService.report(now.minus(5, DAYS), visits);
final var acceptedCount = reportService.reportWithPivotDate(now.minus(5, DAYS), visits);
verify(producerService).produceVisits(acceptedVisits.capture());
assertThat(acceptedVisits.getValue())
......@@ -134,7 +134,7 @@ class ReportServiceTest {
newVisit("22222222-2222-2222-2222-222222222222", now.plus(2, SECONDS)) // don't pass
);
final var acceptedCount = reportService.report(now.minus(5, DAYS), visits);
final var acceptedCount = reportService.reportWithPivotDate(now.minus(5, DAYS), visits);
verify(producerService).produceVisits(acceptedVisits.capture());
assertThat(acceptedVisits.getValue())
......@@ -165,7 +165,7 @@ class ReportServiceTest {
newVisit("33333333-3333-3333-3333-333333333333", now) // don't pass (duplicate)
);
final var acceptedCount = reportService.report(now.minus(5, DAYS), visits);
final var acceptedCount = reportService.reportWithPivotDate(now.minus(5, DAYS), visits);
verify(producerService).produceVisits(acceptedVisits.capture());
assertThat(acceptedVisits.getValue())
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment