From 54b49761925952cddc1c737838b6dade76fbd2f9 Mon Sep 17 00:00:00 2001 From: srmontero Date: Mon, 14 Dec 2020 17:25:12 +0100 Subject: [PATCH] [SRM] visited countries --- CHANGELOG.md | 6 ++ README.md | 2 +- .../gob/radarcovid/efgs/EfgsApplication.java | 6 +- .../src/main/resources/application.yml | 2 +- .../test/GaenExposedMapperTestSpec.groovy | 24 +++++-- efgs-server-boot/src/test/resources/data.sql | 1 + .../src/test/resources/schema.sql | 21 ++++-- .../radarcovid/efgs/etc/EfgsProperties.java | 2 +- .../efgs/persistence/GaenExposedDao.java | 8 ++- .../persistence/entity/GaenExposedEntity.java | 5 ++ .../persistence/entity/VisitedEntity.java | 42 +++++++++++ .../persistence/entity/VisitedEntityId.java | 28 ++++++++ .../persistence/impl/GaenExposedDaoImpl.java | 11 +-- .../persistence/mapper/GaenExposedMapper.java | 7 +- .../persistence/mapper/VisitedMapper.java | 57 +++++++++++++++ .../persistence/model/GaenExposedDto.java | 10 ++- .../GaenExposedEntityJdbcRepository.java | 21 ++++++ .../GaenExposedEntityRepository.java | 31 +------- .../GaenExposedEntityJdbcRepositoryImpl.java | 71 +++++++++++++++++++ sql/V0_8__gaen_efgs.sql | 12 ++++ 20 files changed, 309 insertions(+), 58 deletions(-) create mode 100644 efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/entity/VisitedEntity.java create mode 100644 efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/entity/VisitedEntityId.java create mode 100644 efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/mapper/VisitedMapper.java create mode 100644 efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/repository/GaenExposedEntityJdbcRepository.java create mode 100644 efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/repository/impl/GaenExposedEntityJdbcRepositoryImpl.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 3109542..14b3fcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. +## [Unreleased] + +### Added + +- Download keys service save visited countries in database. + ## [1.1.0.RELEASE] - 2020-11-12 ### Added diff --git a/README.md b/README.md index 2b93e2d..55878d4 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ EFGS Service in terms of the Radar COVID project enables the connectivity with [ These are the frameworks and tools used to develop the solution: - [Java 11](https://openjdk.java.net/). -- [Maven](https://maven.apache.org/). +- [Maven 3.6](https://maven.apache.org/). - [Spring Boot](https://spring.io/projects/spring-boot) version 2.3. - [Lombok](https://projectlombok.org/), to help programmer. Developers have to include the IDE plugin to support Lombok features (ie, for Eclipse based IDE, go [here](https://projectlombok.org/setup/eclipse)). - [ArchUnit](https://www.archunit.org/) is used to check Java architecture. diff --git a/efgs-server-boot/src/main/java/es/gob/radarcovid/efgs/EfgsApplication.java b/efgs-server-boot/src/main/java/es/gob/radarcovid/efgs/EfgsApplication.java index 85f5187..1852a90 100644 --- a/efgs-server-boot/src/main/java/es/gob/radarcovid/efgs/EfgsApplication.java +++ b/efgs-server-boot/src/main/java/es/gob/radarcovid/efgs/EfgsApplication.java @@ -9,7 +9,6 @@ */ package es.gob.radarcovid.efgs; -import es.gob.radarcovid.efgs.etc.EfgsProperties; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -17,6 +16,8 @@ import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import es.gob.radarcovid.efgs.etc.EfgsProperties; + @SpringBootApplication @EnableAspectJAutoProxy @EnableJpaRepositories(basePackages = {"es.gob.radarcovid.efgs.persistence.repository"}) @@ -25,7 +26,8 @@ public class EfgsApplication { public static void main(String[] args) { - SpringApplication.run(EfgsApplication.class, args); + System.exit(SpringApplication + .exit(SpringApplication.run(EfgsApplication.class, args))); } } diff --git a/efgs-server-boot/src/main/resources/application.yml b/efgs-server-boot/src/main/resources/application.yml index 8660b22..5b1e18e 100644 --- a/efgs-server-boot/src/main/resources/application.yml +++ b/efgs-server-boot/src/main/resources/application.yml @@ -62,6 +62,7 @@ application: efgs: retention-days: 6 country: 'ES' + country-list: BE,BG,CZ,DK,DE,EE,ES,IE,GR,FR,HR,IT,CY,LV,LT,LU,HU,MT,NL,AT,PL,PT,RO,SI,SK,FI,SE,IS,LI,NO,CH ssl: enabled: ${EFGS_SSL_ENABLED:true} key-store: classpath:radarcovid-ta.jks @@ -84,7 +85,6 @@ application: json-version: 1.0 upload-diagnosis-keys: enabled: ${EFGS_UPLOAD_DIAGNOSIS_KEYS_ENABLED:true} - country-list: BE,BG,CZ,DK,DE,EE,IE,GR,FR,HR,IT,CY,LV,LT,LU,HU,MT,NL,AT,PL,PT,RO,SI,SK,FI,SE,IS,LI,NO,CH default-values: transmission-risk-level: ${EFGS_DEFAULT_TRANSMISSION_RISK_LEVEL:2} report-type: ${EFGS_DEFAULT_REPORT_TYPE:CONFIRMED_TEST} diff --git a/efgs-server-boot/src/test/groovy/es/gob/radarcovid/efgs/persistence/mapper/test/GaenExposedMapperTestSpec.groovy b/efgs-server-boot/src/test/groovy/es/gob/radarcovid/efgs/persistence/mapper/test/GaenExposedMapperTestSpec.groovy index c0f4d24..63ed6b1 100644 --- a/efgs-server-boot/src/test/groovy/es/gob/radarcovid/efgs/persistence/mapper/test/GaenExposedMapperTestSpec.groovy +++ b/efgs-server-boot/src/test/groovy/es/gob/radarcovid/efgs/persistence/mapper/test/GaenExposedMapperTestSpec.groovy @@ -17,6 +17,7 @@ import org.springframework.test.context.ActiveProfiles import es.gob.radarcovid.efgs.etc.EfgsProperties import es.gob.radarcovid.efgs.persistence.entity.GaenExposedEntity +import es.gob.radarcovid.efgs.persistence.entity.VisitedEntity import es.gob.radarcovid.efgs.persistence.mapper.GaenExposedMapper import es.gob.radarcovid.efgs.persistence.model.GaenExposedDto import eu.interop.federationgateway.model.EfgsProto.ReportType @@ -48,11 +49,12 @@ class GaenExposedMapperTestSpec extends Specification { dto.reportType == efgsProperties.uploadDiagnosisKeys.defaultValues.reportType dto.daysSinceOnset == (entity.daysSinceOnset != null ? entity.daysSinceOnset : 1) dto.efgsSharing == entity.efgsSharing + dto.visitedCountries.size() == entity.visitedCountries.size() where: entity << [ - createEntity(1, 'key1', 13, 5, 8, LocalDateTime.now(), 11, true), - createEntity(2, 'key2', 13, 144, 3, LocalDateTime.now(), -11, true), + createEntity(1, 'key1', 13, 5, 8, LocalDateTime.now(), 11, true, 'IT', 'FR', 'DE'), + createEntity(2, 'key2', 13, 144, 3, LocalDateTime.now(), -11, true, 'ES'), createEntity(3, 'key3', null, null, null, LocalDateTime.now(), null, false) ] } @@ -73,17 +75,18 @@ class GaenExposedMapperTestSpec extends Specification { entity.reportType == dto.reportType entity.daysSinceOnset == dto.daysSinceOnset entity.efgsSharing == dto.efgsSharing + entity.visitedCountries.size() == dto.visitedCountries.size() where: dto << [ - createDto('key1', 13, 5, 8, LocalDateTime.now(), 'ES', ReportType.CONFIRMED_TEST, 11, true), - createDto('key2', 13, 144, 3, LocalDateTime.now(), 'DE', ReportType.CONFIRMED_CLINICAL_DIAGNOSIS, -11, true), + createDto('key1', 13, 5, 8, LocalDateTime.now(), 'ES', ReportType.CONFIRMED_TEST, 11, true, 'IT', 'FR', 'DE'), + createDto('key2', 13, 144, 3, LocalDateTime.now(), 'DE', ReportType.CONFIRMED_CLINICAL_DIAGNOSIS, -11, true, 'ES'), createDto('key3', null, null, null, LocalDateTime.now(), null, ReportType.SELF_REPORT, null, false) ] } def createEntity(Integer id, String key, Integer rollingStartNumber, Integer rollingPeriod, Integer transmissionRiskLevel, - LocalDateTime receivedAt, Integer daysSinceOnset, Boolean efgsSharing) { + LocalDateTime receivedAt, Integer daysSinceOnset, Boolean efgsSharing, String... visitedCountries) { def entity = new GaenExposedEntity() entity.setId(id) entity.setKey(key) @@ -93,11 +96,19 @@ class GaenExposedMapperTestSpec extends Specification { entity.setReceivedAt(receivedAt) entity.setDaysSinceOnset(daysSinceOnset) entity.setEfgsSharing(efgsSharing) + + visitedCountries.stream().forEach({country -> + def visitedEntity = new VisitedEntity() + visitedEntity.setCountry(country) + entity.visitedCountries.add(visitedEntity) + } ) + return entity } def createDto(String key, Integer rollingStartNumber, Integer rollingPeriod, Integer transmissionRiskLevel, - LocalDateTime receivedAt, String countryOrigin, ReportType reportType, Integer daysSinceOnset, Boolean efgsSharing) { + LocalDateTime receivedAt, String countryOrigin, ReportType reportType, Integer daysSinceOnset, Boolean efgsSharing, + String... visitedCountries) { def dto = new GaenExposedDto() dto.setKey(key) dto.setRollingStartNumber(rollingStartNumber) @@ -108,6 +119,7 @@ class GaenExposedMapperTestSpec extends Specification { dto.setReportType(reportType) dto.setDaysSinceOnset(daysSinceOnset) dto.setEfgsSharing(efgsSharing) + dto.setVisitedCountries(visitedCountries as Set) return dto } } diff --git a/efgs-server-boot/src/test/resources/data.sql b/efgs-server-boot/src/test/resources/data.sql index 03d131f..6049747 100644 --- a/efgs-server-boot/src/test/resources/data.sql +++ b/efgs-server-boot/src/test/resources/data.sql @@ -1,4 +1,5 @@ DELETE FROM DPPPT.DOWNLOAD_EXECUTION; DELETE FROM DPPPT.UPLOAD_KEYS_EXECUTION; DELETE FROM DPPPT.BATCH_JOB_EXECUTION; +DELETE FROM DPPPT.T_VISITED; DELETE FROM DPPPT.T_GAEN_EXPOSED; diff --git a/efgs-server-boot/src/test/resources/schema.sql b/efgs-server-boot/src/test/resources/schema.sql index 447a1f0..956a908 100644 --- a/efgs-server-boot/src/test/resources/schema.sql +++ b/efgs-server-boot/src/test/resources/schema.sql @@ -63,6 +63,20 @@ CREATE TABLE DPPPT.T_GAEN_EXPOSED( BATCH_TAG CHAR VARYING(128) ); +ALTER TABLE DPPPT.T_GAEN_EXPOSED ADD CONSTRAINT PK_T_GAEN_EXPOSED PRIMARY KEY (PK_EXPOSED_ID); + +ALTER TABLE DPPPT.T_GAEN_EXPOSED ADD CONSTRAINT GAEN_EXPOSED_KEY UNIQUE (KEY); + +CREATE TABLE DPPPT.T_VISITED ( + PFK_EXPOSED_ID INTEGER NOT NULL, + COUNTRY CHAR(2), + CONSTRAINT PK_T_VISITED + PRIMARY KEY (PFK_EXPOSED_ID, COUNTRY), + CONSTRAINT R_GAEN_EXPOSED_VISITED + FOREIGN KEY (PFK_EXPOSED_ID) + REFERENCES DPPPT.T_GAEN_EXPOSED (PK_EXPOSED_ID) ON DELETE CASCADE +); + ALTER SEQUENCE DPPPT.SQ_NM_ID_BATCH_JOB_EXECUTION OWNED BY DPPPT.BATCH_JOB_EXECUTION.NM_JOB_EXECUTION_ID; @@ -71,10 +85,6 @@ ALTER SEQUENCE DPPPT.SQ_NM_DOWNLOAD_EXECUTION ALTER SEQUENCE DPPPT.SQ_NM_UPLOAD_KEYS_EXECUTION OWNED BY DPPPT.UPLOAD_KEYS_EXECUTION.NM_UPLOAD_KEYS_ID; - -ALTER TABLE DPPPT.T_GAEN_EXPOSED ADD CONSTRAINT PK_T_GAEN_EXPOSED PRIMARY KEY (PK_EXPOSED_ID); - -ALTER TABLE DPPPT.T_GAEN_EXPOSED ADD CONSTRAINT GAEN_EXPOSED_KEY UNIQUE (KEY); CREATE INDEX IN_EFGS_BATCH_JOB_EXECUTION_START_TIME ON DPPPT.BATCH_JOB_EXECUTION(FC_START_TIME); @@ -97,4 +107,7 @@ CREATE INDEX IN_GAEN_EXPOSED_COUNTRY_SHARING_RECEIVED CREATE INDEX IN_GAEN_EXPOSED_COUNTRY_SHARING_BATCH_TAG ON DPPPT.T_GAEN_EXPOSED(COUNTRY_ORIGIN, EFGS_SHARING, BATCH_TAG); +CREATE INDEX IDX_VISITED_EXPOSED_ID + ON DPPPT.T_VISITED(PFK_EXPOSED_ID); + diff --git a/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/etc/EfgsProperties.java b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/etc/EfgsProperties.java index e532cef..7e0348a 100644 --- a/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/etc/EfgsProperties.java +++ b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/etc/EfgsProperties.java @@ -25,6 +25,7 @@ public class EfgsProperties { private int retentionDays = 14; private String country; + private List countryList; private final Credentials credentials = new Credentials(); private final Ssl ssl = new Ssl(); @@ -84,7 +85,6 @@ public static class ContentNegotiation { @Setter public static class UploadDiagnosisKeys { private boolean enabled; - private List countryList; private int maximumUploadBatchSize = 5000; private String url; private final Retry retry = new Retry(); diff --git a/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/GaenExposedDao.java b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/GaenExposedDao.java index 0872b5b..f2ff2ac 100644 --- a/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/GaenExposedDao.java +++ b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/GaenExposedDao.java @@ -9,14 +9,16 @@ */ package es.gob.radarcovid.efgs.persistence; -import es.gob.radarcovid.efgs.persistence.model.GaenExposedDto; -import org.springframework.transaction.annotation.Transactional; - import java.util.Collection; import java.util.List; +import org.springframework.transaction.annotation.Transactional; + +import es.gob.radarcovid.efgs.persistence.model.GaenExposedDto; + public interface GaenExposedDao { + @Transactional(readOnly=true) List findPendingByCountry(String country, Integer page, Integer size); @Transactional diff --git a/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/entity/GaenExposedEntity.java b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/entity/GaenExposedEntity.java index f93588c..aa7e620 100644 --- a/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/entity/GaenExposedEntity.java +++ b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/entity/GaenExposedEntity.java @@ -16,6 +16,8 @@ import javax.validation.constraints.NotNull; import java.io.Serializable; import java.time.LocalDateTime; +import java.util.HashSet; +import java.util.Set; @Entity @Table(name = "t_gaen_exposed") @@ -57,6 +59,9 @@ public class GaenExposedEntity implements Serializable { @Column(name = "batch_tag") private String batchTag; + + @OneToMany(mappedBy = "gaenExposed") + private Set visitedCountries = new HashSet<>(); public EfgsProto.ReportType getReportType() { return EfgsProto.ReportType.valueOf(reportType); diff --git a/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/entity/VisitedEntity.java b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/entity/VisitedEntity.java new file mode 100644 index 0000000..7bc94d0 --- /dev/null +++ b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/entity/VisitedEntity.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 Gobierno de España + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ +package es.gob.radarcovid.efgs.persistence.entity; + +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import lombok.Data; + +@Entity +@Table(name = "t_visited") +@IdClass(VisitedEntityId.class) +@Data +public class VisitedEntity implements Serializable { + + @Id + @Column(name = "pfk_exposed_id") + private Integer exposedId; + + @Id + @Column(name = "country") + private String country; + + @ManyToOne + @JoinColumn(name = "pfk_exposed_id", insertable = false, updatable = false) + private GaenExposedEntity gaenExposed; + +} diff --git a/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/entity/VisitedEntityId.java b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/entity/VisitedEntityId.java new file mode 100644 index 0000000..9d50d13 --- /dev/null +++ b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/entity/VisitedEntityId.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020 Gobierno de España + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ +package es.gob.radarcovid.efgs.persistence.entity; + +import java.io.Serializable; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode +public class VisitedEntityId implements Serializable { + + private Integer exposedId; + private String country; + +} diff --git a/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/impl/GaenExposedDaoImpl.java b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/impl/GaenExposedDaoImpl.java index 6a2df1b..cf24bf0 100644 --- a/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/impl/GaenExposedDaoImpl.java +++ b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/impl/GaenExposedDaoImpl.java @@ -49,8 +49,8 @@ public void updateBatchTagForKeys(Collection originalKeys, Strin @Override public int saveAll(List gaenExposedDtos) { AtomicInteger total = new AtomicInteger(0); - gaenExposedDtos.stream().forEach(dto -> { - int saved = repository.saveUpdateOnConflict( + gaenExposedDtos.stream().forEach(dto -> { + repository.saveOnConflictUpdate( dto.getKey(), dto.getRollingStartNumber(), dto.getRollingPeriod(), @@ -60,9 +60,10 @@ public int saveAll(List gaenExposedDtos) { dto.getReportType().getNumber(), dto.getDaysSinceOnset(), dto.getEfgsSharing(), - dto.getBatchTag()); - total.addAndGet(saved); - }); + dto.getBatchTag(), + dto.getVisitedCountries()); + total.addAndGet(1); + }); return total.get(); } diff --git a/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/mapper/GaenExposedMapper.java b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/mapper/GaenExposedMapper.java index 24a29f8..ba4d0b4 100644 --- a/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/mapper/GaenExposedMapper.java +++ b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/mapper/GaenExposedMapper.java @@ -27,7 +27,7 @@ import es.gob.radarcovid.efgs.persistence.model.GaenExposedDto; import eu.interop.federationgateway.model.EfgsProto; -@Mapper(componentModel = "spring") +@Mapper(componentModel = "spring", uses = VisitedMapper.class) public abstract class GaenExposedMapper { @Autowired @@ -67,7 +67,7 @@ public EfgsProto.DiagnosisKey dtoToDiagnosisKey(GaenExposedDto gaenExposedDto) { .setOrigin(gaenExposedDto.getCountryOrigin()) .setReportType(gaenExposedDto.getReportType()) .setDaysSinceOnsetOfSymptoms(gaenExposedDto.getDaysSinceOnset()) - .addAllVisitedCountries(efgsProperties.getUploadDiagnosisKeys().getCountryList()) + .addAllVisitedCountries(efgsProperties.getCountryList()) .build(); } @@ -78,7 +78,8 @@ public EfgsProto.DiagnosisKey dtoToDiagnosisKey(GaenExposedDto gaenExposedDto) { @Mapping(target = "countryOrigin", source = "origin"), @Mapping(target = "daysSinceOnset", ignore = true), @Mapping(target = "efgsSharing", ignore = true), - @Mapping(target = "batchTag", ignore = true) + @Mapping(target = "batchTag", ignore = true), + @Mapping(target = "visitedCountries", source = "visitedCountriesList") }) public abstract GaenExposedDto diagnosisKeyToDto(EfgsProto.DiagnosisKey diagnosisKey); diff --git a/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/mapper/VisitedMapper.java b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/mapper/VisitedMapper.java new file mode 100644 index 0000000..3a2a97f --- /dev/null +++ b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/mapper/VisitedMapper.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 Gobierno de España + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ +package es.gob.radarcovid.efgs.persistence.mapper; + +import java.util.Set; +import java.util.stream.Collectors; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.springframework.beans.factory.annotation.Autowired; + +import com.google.protobuf.ByteString; +import com.google.protobuf.ProtocolStringList; + +import es.gob.radarcovid.efgs.etc.EfgsProperties; +import es.gob.radarcovid.efgs.persistence.entity.VisitedEntity; + +@Mapper(componentModel = "spring") +public abstract class VisitedMapper { + + @Autowired + private EfgsProperties efgsProperties; + + public String entityToValue(VisitedEntity entity) { + return entity.getCountry(); + } + + @Mappings({ + @Mapping(target = "exposedId", ignore = true), + @Mapping(target = "gaenExposed", ignore = true), + @Mapping(target = "country", source = "value") + }) + public abstract VisitedEntity valueToEntity(String value); + + public Set protocolStringListToList(ProtocolStringList protocolStringList) { + if (protocolStringList == null) { + return null; + } + return protocolStringList.asByteStringList().stream() + .map(this::byteStringToValue) + .filter(efgsProperties.getCountryList()::contains) + .collect(Collectors.toSet()); + } + + public String byteStringToValue(ByteString byteString) { + return byteString.toStringUtf8().trim(); + } + +} diff --git a/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/model/GaenExposedDto.java b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/model/GaenExposedDto.java index 45ce6c7..b48547a 100644 --- a/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/model/GaenExposedDto.java +++ b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/model/GaenExposedDto.java @@ -9,11 +9,13 @@ */ package es.gob.radarcovid.efgs.persistence.model; -import eu.interop.federationgateway.model.EfgsProto; -import lombok.Data; - import java.io.Serializable; import java.time.LocalDateTime; +import java.util.HashSet; +import java.util.Set; + +import eu.interop.federationgateway.model.EfgsProto; +import lombok.Data; @Data public class GaenExposedDto implements Serializable { @@ -37,6 +39,8 @@ public class GaenExposedDto implements Serializable { private Boolean efgsSharing; private String batchTag; + + private Set visitedCountries = new HashSet<>(); public EfgsProto.ReportType getReportType() { return EfgsProto.ReportType.valueOf(reportType); diff --git a/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/repository/GaenExposedEntityJdbcRepository.java b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/repository/GaenExposedEntityJdbcRepository.java new file mode 100644 index 0000000..1d01da1 --- /dev/null +++ b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/repository/GaenExposedEntityJdbcRepository.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2020 Gobierno de España + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ +package es.gob.radarcovid.efgs.persistence.repository; + +import java.time.LocalDateTime; +import java.util.Set; + +public interface GaenExposedEntityJdbcRepository { + + void saveOnConflictUpdate(String key, int rollingStartNumber, int rollingPeriod, int transmissionRiskLevel, + LocalDateTime receivedAt, String countryOrigin, int reportType, int daysSinceOnset, boolean efgsSharing, + String batchTag, Set visitedCountries); + +} diff --git a/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/repository/GaenExposedEntityRepository.java b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/repository/GaenExposedEntityRepository.java index c5e0c1d..28e702d 100644 --- a/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/repository/GaenExposedEntityRepository.java +++ b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/repository/GaenExposedEntityRepository.java @@ -9,7 +9,6 @@ */ package es.gob.radarcovid.efgs.persistence.repository; -import java.time.LocalDateTime; import java.util.List; import org.springframework.data.domain.Pageable; @@ -22,40 +21,14 @@ import es.gob.radarcovid.efgs.persistence.entity.GaenExposedEntity; @Repository -public interface GaenExposedEntityRepository extends PagingAndSortingRepository { +public interface GaenExposedEntityRepository extends PagingAndSortingRepository, GaenExposedEntityJdbcRepository { List findAllByCountryOriginAndEfgsSharingIsTrueAndBatchTagIsNull(String countryOrigin, Pageable pageable); List findByCountryOriginAndEfgsSharingAndBatchTag(String countryOrigin, boolean efgsSharing, String batchTag); - + @Modifying @Query("update GaenExposedEntity set batchTag = :batchTag where key = :key") void updateBatchTag(@Param("key") String key, @Param("batchTag") String batchTag); - - @Modifying - @Query(value = "INSERT INTO {h-schema}t_gaen_exposed " - + " (key, rolling_start_number, rolling_period, transmission_risk_level, received_at, " - + " country_origin, report_type, days_since_onset, efgs_sharing, batch_tag) " - + "VALUES (:key, :rollingStartNumber, :rollingPeriod, :transmissionRiskLevel, :receivedAt, " - + " :countryOrigin, :reportType, :daysSinceOnset, :efgsSharing, :batchTag) " - + "ON CONFLICT ON CONSTRAINT gaen_exposed_key DO " - + " UPDATE SET rolling_start_number = :rollingStartNumber, " - + " rolling_period = :rollingPeriod, " - + " transmission_risk_level = :transmissionRiskLevel, " - + " report_type = :reportType, " - + " days_since_onset = :daysSinceOnset, " - + " batch_tag = :batchTag", - nativeQuery = true) - int saveUpdateOnConflict( - @Param("key") String key, - @Param("rollingStartNumber") int rollingStartNumber, - @Param("rollingPeriod") int rollingPeriod, - @Param("transmissionRiskLevel") int transmissionRiskLevel, - @Param("receivedAt") LocalDateTime receivedAt, - @Param("countryOrigin") String countryOrigin, - @Param("reportType") int reportType, - @Param("daysSinceOnset") int daysSinceOnset, - @Param("efgsSharing") boolean efgsSharing, - @Param("batchTag") String batchTag); } diff --git a/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/repository/impl/GaenExposedEntityJdbcRepositoryImpl.java b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/repository/impl/GaenExposedEntityJdbcRepositoryImpl.java new file mode 100644 index 0000000..ae941b3 --- /dev/null +++ b/efgs-server-service/src/main/java/es/gob/radarcovid/efgs/persistence/repository/impl/GaenExposedEntityJdbcRepositoryImpl.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020 Gobierno de España + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * SPDX-License-Identifier: MPL-2.0 + */ +package es.gob.radarcovid.efgs.persistence.repository.impl; + +import java.time.LocalDateTime; +import java.util.Set; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; + +import org.springframework.stereotype.Repository; + +import es.gob.radarcovid.efgs.persistence.repository.GaenExposedEntityJdbcRepository; + +@Repository +public class GaenExposedEntityJdbcRepositoryImpl implements GaenExposedEntityJdbcRepository { + + private static final String INSERT_GAEN_EXPOSED_ON_CONFLICT_UPDATE_SQL = "INSERT INTO {h-schema}t_gaen_exposed " + + " (key, rolling_start_number, rolling_period, transmission_risk_level, received_at, " + + " country_origin, report_type, days_since_onset, efgs_sharing, batch_tag) " + + "VALUES (:key, :rollingStartNumber, :rollingPeriod, :transmissionRiskLevel, :receivedAt, " + + " :countryOrigin, :reportType, :daysSinceOnset, :efgsSharing, :batchTag) " + + "ON CONFLICT ON CONSTRAINT gaen_exposed_key DO " + + " UPDATE SET rolling_start_number = :rollingStartNumber, " + + " rolling_period = :rollingPeriod, " + + " transmission_risk_level = :transmissionRiskLevel, " + + " report_type = :reportType, " + + " days_since_onset = :daysSinceOnset, " + + " batch_tag = :batchTag " + + "RETURNING pk_exposed_id"; + + private static final String INSERT_VISITED_ON_CONFLICT_DO_NOTHING_SQL = "INSERT INTO {h-schema}t_visited " + + " (pfk_exposed_id, country) " + + "VALUES (:exposedId, :country) " + + "ON CONFLICT ON CONSTRAINT pk_t_visited DO NOTHING"; + + @PersistenceContext + private EntityManager em; + + @Override + public void saveOnConflictUpdate(String key, int rollingStartNumber, int rollingPeriod, int transmissionRiskLevel, + LocalDateTime receivedAt, String countryOrigin, int reportType, int daysSinceOnset, boolean efgsSharing, + String batchTag, Set visitedCountries) { + int exposedId = (int) em.createNativeQuery(INSERT_GAEN_EXPOSED_ON_CONFLICT_UPDATE_SQL) + .setParameter("key", key) + .setParameter("rollingStartNumber", rollingStartNumber) + .setParameter("rollingPeriod", rollingPeriod) + .setParameter("transmissionRiskLevel", transmissionRiskLevel) + .setParameter("receivedAt", receivedAt) + .setParameter("countryOrigin", countryOrigin) + .setParameter("reportType", reportType) + .setParameter("daysSinceOnset", daysSinceOnset) + .setParameter("efgsSharing", efgsSharing) + .setParameter("batchTag", batchTag) + .getSingleResult(); + + visitedCountries.forEach(country -> { + em.createNativeQuery(INSERT_VISITED_ON_CONFLICT_DO_NOTHING_SQL) + .setParameter("exposedId", exposedId) + .setParameter("country", country) + .executeUpdate(); + }); + } +} diff --git a/sql/V0_8__gaen_efgs.sql b/sql/V0_8__gaen_efgs.sql index 54155a4..b608bdb 100644 --- a/sql/V0_8__gaen_efgs.sql +++ b/sql/V0_8__gaen_efgs.sql @@ -18,3 +18,15 @@ CREATE INDEX IN_GAEN_EXPOSED_COUNTRY_SHARING_RECEIVED CREATE INDEX IN_GAEN_EXPOSED_COUNTRY_SHARING_BATCH_TAG ON T_GAEN_EXPOSED(COUNTRY_ORIGIN, EFGS_SHARING, BATCH_TAG); +CREATE TABLE T_VISITED ( + PFK_EXPOSED_ID INTEGER NOT NULL, + COUNTRY CHAR(2), + CONSTRAINT PK_T_VISITED + PRIMARY KEY (PFK_EXPOSED_ID, COUNTRY), + CONSTRAINT R_GAEN_EXPOSED_VISITED + FOREIGN KEY (PFK_EXPOSED_ID) + REFERENCES T_GAEN_EXPOSED (PK_EXPOSED_ID) ON DELETE CASCADE +); + +CREATE INDEX IDX_VISITED_EXPOSED_ID + ON T_VISITED(PFK_EXPOSED_ID); \ No newline at end of file