diff --git a/build.gradle b/build.gradle index 6795713..e34ecfd 100644 --- a/build.gradle +++ b/build.gradle @@ -30,6 +30,8 @@ subprojects { fasterxmlJacksonVersion = '2.10.0' apacheCommonsCollectionsVersion = '4.4' apacheCommonsLangVersion = '3.9' + jsoupVersion = '1.13.1' + flywaydbVersion = '6.3.3' } group = 'com.bvn13.covid19' diff --git a/covid19-api/src/main/java/com/bvn13/covid19/api/controllers/MainController.java b/covid19-api/src/main/java/com/bvn13/covid19/api/controllers/ApiController.java similarity index 97% rename from covid19-api/src/main/java/com/bvn13/covid19/api/controllers/MainController.java rename to covid19-api/src/main/java/com/bvn13/covid19/api/controllers/ApiController.java index 1a0278d..d2f68e6 100644 --- a/covid19-api/src/main/java/com/bvn13/covid19/api/controllers/MainController.java +++ b/covid19-api/src/main/java/com/bvn13/covid19/api/controllers/ApiController.java @@ -34,8 +34,8 @@ import java.util.stream.Collectors; @RequiredArgsConstructor @RestController -@RequestMapping("/") -public class MainController { +@RequestMapping("/api") +public class ApiController { private final CovidStatsMaker covidStatsMaker; diff --git a/covid19-api/src/main/java/com/bvn13/covid19/api/repositories/CovidStatsRepository.java b/covid19-api/src/main/java/com/bvn13/covid19/api/repositories/CovidStatsRepository.java index b4ef620..f25c5b7 100644 --- a/covid19-api/src/main/java/com/bvn13/covid19/api/repositories/CovidStatsRepository.java +++ b/covid19-api/src/main/java/com/bvn13/covid19/api/repositories/CovidStatsRepository.java @@ -17,7 +17,7 @@ limitations under the License. package com.bvn13.covid19.api.repositories; import com.bvn13.covid19.model.entities.CovidStat; -import com.bvn13.covid19.model.entities.CovidUpdateInfo; +import com.bvn13.covid19.model.entities.CovidUpdate; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @@ -26,7 +26,7 @@ import java.util.Collection; @Repository public interface CovidStatsRepository extends JpaRepository { - Collection findAllByUpdateInfo(CovidUpdateInfo updateInfo); + Collection findAllByUpdateInfo(CovidUpdate updateInfo); Collection findAllByUpdateInfo_Id(long updateInfoId); } diff --git a/covid19-api/src/main/java/com/bvn13/covid19/api/repositories/CovidUpdateInfosRepository.java b/covid19-api/src/main/java/com/bvn13/covid19/api/repositories/CovidUpdateInfosRepository.java index 651d285..9b1a4e9 100644 --- a/covid19-api/src/main/java/com/bvn13/covid19/api/repositories/CovidUpdateInfosRepository.java +++ b/covid19-api/src/main/java/com/bvn13/covid19/api/repositories/CovidUpdateInfosRepository.java @@ -17,7 +17,7 @@ limitations under the License. package com.bvn13.covid19.api.repositories; import com.bvn13.covid19.api.dtos.CovidUpdateInfoDto; -import com.bvn13.covid19.model.entities.CovidUpdateInfo; +import com.bvn13.covid19.model.entities.CovidUpdate; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; @@ -26,11 +26,11 @@ import java.time.LocalDateTime; import java.util.Optional; @Repository -public interface CovidUpdateInfosRepository extends JpaRepository { +public interface CovidUpdateInfosRepository extends JpaRepository { - @Query("select new com.bvn13.covid19.api.dtos.CovidUpdateInfoDto(max(U.createdOn)) from CovidUpdateInfo U") + @Query("select new com.bvn13.covid19.api.dtos.CovidUpdateInfoDto(max(U.createdOn)) from CovidUpdate U") Optional findLastUpdateInfo(); - Optional findFirstByCreatedOn(LocalDateTime createdOn); + Optional findFirstByCreatedOn(LocalDateTime createdOn); } diff --git a/covid19-api/src/main/java/com/bvn13/covid19/api/service/CovidStatsMaker.java b/covid19-api/src/main/java/com/bvn13/covid19/api/service/CovidStatsMaker.java index 1878559..6430f68 100644 --- a/covid19-api/src/main/java/com/bvn13/covid19/api/service/CovidStatsMaker.java +++ b/covid19-api/src/main/java/com/bvn13/covid19/api/service/CovidStatsMaker.java @@ -19,7 +19,7 @@ package com.bvn13.covid19.api.service; import com.bvn13.covid19.api.repositories.CovidStatsRepository; import com.bvn13.covid19.api.repositories.CovidUpdateInfosRepository; import com.bvn13.covid19.model.entities.CovidStat; -import com.bvn13.covid19.model.entities.CovidUpdateInfo; +import com.bvn13.covid19.model.entities.CovidUpdate; import lombok.RequiredArgsConstructor; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Component; @@ -49,7 +49,7 @@ public class CovidStatsMaker { unless = "#result == null" ) @Transactional - public Optional findLastUpdateInfo() { + public Optional findLastUpdateInfo() { return updatesRepository.findLastUpdateInfo() .flatMap(updateInfo -> updatesRepository.findFirstByCreatedOn(updateInfo.getCreatedOn())); } diff --git a/covid19-api/src/main/resources/application.yaml b/covid19-api/src/main/resources/application.yaml index e0ac796..64fab79 100644 --- a/covid19-api/src/main/resources/application.yaml +++ b/covid19-api/src/main/resources/application.yaml @@ -1,3 +1,6 @@ +server: + port: 8080 + app: zone-id: Europe/Moscow @@ -11,6 +14,10 @@ spring: spec: expireAfterWrite=15m cache-names: covid-last-update-info, covid-stats-by-update-info-id + flyway: + locations: classpath:db/migration + schemas: covid + datasource: driver-class-name: org.postgresql.Driver url: jdbc:postgresql://localhost:5432/covid19 @@ -21,10 +28,11 @@ spring: show-sql: true hibernate: dialect: org.hibernate.dialect.PostgreSQL - ddl-auto: update + ddl-auto: validate properties: hibernate: + default_schema: covid use_sql_comments: true format_sql: true show_sql: true @@ -46,4 +54,5 @@ logging: sql: BasicBinder: trace pattern: - console: "%d{dd-MM-yyyy HH:mm:ss.SSS} %highlight(%-5level) %magenta([%thread]) %yellow(%logger.%M) - %msg%n" \ No newline at end of file + console: "%d{dd-MM-yyyy HH:mm:ss.SSS} %highlight(%-5level) %magenta([%thread]) %yellow(%logger.%M) - %msg%n" + diff --git a/covid19-model/build.gradle b/covid19-model/build.gradle index a43d389..34f6686 100644 --- a/covid19-model/build.gradle +++ b/covid19-model/build.gradle @@ -5,6 +5,10 @@ version = '0.0.1' dependencies { implementation 'org.springframework.boot:spring-boot-starter' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-validation' + + runtimeOnly 'org.postgresql:postgresql' + implementation 'org.flywaydb:flyway-core' testImplementation 'com.h2database:h2:1.4.194' } diff --git a/covid19-model/src/main/java/com/bvn13/covid19/model/Covid19ModelApplication.java b/covid19-model/src/main/java/com/bvn13/covid19/model/Covid19ModelApplication.java index 3c1f148..e506f85 100644 --- a/covid19-model/src/main/java/com/bvn13/covid19/model/Covid19ModelApplication.java +++ b/covid19-model/src/main/java/com/bvn13/covid19/model/Covid19ModelApplication.java @@ -1,14 +1,25 @@ +/* +Copyright [2020] [bvn13] + +Licensed 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 com.bvn13.covid19.model; -import com.bvn13.covid19.model.Covid19ModelConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Import; -//@SpringBootApplication -//@Import({ -// Covid19ModelConfig.class -//}) +@SpringBootApplication public class Covid19ModelApplication { public static void main(String[] args) { diff --git a/covid19-model/src/main/java/com/bvn13/covid19/model/Covid19ModelConfig.java b/covid19-model/src/main/java/com/bvn13/covid19/model/Covid19ModelConfig.java index f202943..db8ac02 100644 --- a/covid19-model/src/main/java/com/bvn13/covid19/model/Covid19ModelConfig.java +++ b/covid19-model/src/main/java/com/bvn13/covid19/model/Covid19ModelConfig.java @@ -19,7 +19,6 @@ package com.bvn13.covid19.model; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; -import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @Configuration @ComponentScan("com.bvn13.covid19.model") diff --git a/covid19-model/src/main/java/com/bvn13/covid19/model/entities/CovidStat.java b/covid19-model/src/main/java/com/bvn13/covid19/model/entities/CovidStat.java index 83736b4..2b70d1c 100644 --- a/covid19-model/src/main/java/com/bvn13/covid19/model/entities/CovidStat.java +++ b/covid19-model/src/main/java/com/bvn13/covid19/model/entities/CovidStat.java @@ -23,11 +23,12 @@ import java.time.LocalDateTime; @Data @Entity -@Table(name = "covid_statistics") +@Table(schema = "covid", name = "cvd_stats") public class CovidStat { @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE) + @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "cvd_stats_seq") + @SequenceGenerator(schema = "covid", name = "cvd_stats_seq", sequenceName = "cvd_stats_seq", allocationSize = 1) private long id; private LocalDateTime createdOn; @@ -37,8 +38,8 @@ public class CovidStat { private Region region; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "update_info_id") - private CovidUpdateInfo updateInfo; + @JoinColumn(name = "update_id") + private CovidUpdate updateInfo; private long sick; private long healed; diff --git a/covid19-model/src/main/java/com/bvn13/covid19/model/entities/CovidUpdateInfo.java b/covid19-model/src/main/java/com/bvn13/covid19/model/entities/CovidUpdate.java similarity index 68% rename from covid19-model/src/main/java/com/bvn13/covid19/model/entities/CovidUpdateInfo.java rename to covid19-model/src/main/java/com/bvn13/covid19/model/entities/CovidUpdate.java index b4cad21..2d959ed 100644 --- a/covid19-model/src/main/java/com/bvn13/covid19/model/entities/CovidUpdateInfo.java +++ b/covid19-model/src/main/java/com/bvn13/covid19/model/entities/CovidUpdate.java @@ -24,13 +24,14 @@ import java.time.ZonedDateTime; @Data @Entity -@Table(name = "update_info", uniqueConstraints = { - @UniqueConstraint(columnNames = {"createdOn"}) +@Table(schema = "covid", name = "cvd_updates", uniqueConstraints = { + @UniqueConstraint(name = "cvd_upd_created_uniq", columnNames = {"createdOn"}) }) -public class CovidUpdateInfo { +public class CovidUpdate { @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE) + @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "cvd_updates_seq") + @SequenceGenerator(schema = "covid", name = "cvd_updates_seq", sequenceName = "cvd_updates_seq", allocationSize = 1) private long id; private LocalDateTime createdOn; diff --git a/covid19-model/src/main/java/com/bvn13/covid19/model/entities/Region.java b/covid19-model/src/main/java/com/bvn13/covid19/model/entities/Region.java index 1e30395..5a8241a 100644 --- a/covid19-model/src/main/java/com/bvn13/covid19/model/entities/Region.java +++ b/covid19-model/src/main/java/com/bvn13/covid19/model/entities/Region.java @@ -18,19 +18,22 @@ package com.bvn13.covid19.model.entities; import lombok.Data; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; -import javax.persistence.UniqueConstraint; +import javax.persistence.*; +import javax.validation.constraints.NotBlank; @Data @Entity -@Table(name = "regions", uniqueConstraints = { - @UniqueConstraint(columnNames = "name") +@Table(schema = "covid", name = "regions", uniqueConstraints = { + @UniqueConstraint(name = "regions_name_uniq", columnNames = "name") }) public class Region { @Id + @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "cvd_regions_seq") + @SequenceGenerator(schema = "covid", name = "cvd_regions_seq", sequenceName = "cvd_regions_seq", allocationSize = 1) + private long id; + + @NotBlank private String name; } diff --git a/covid19-model/src/main/resources/application.yaml b/covid19-model/src/main/resources/application.yaml index 8b13789..02ff8fa 100644 --- a/covid19-model/src/main/resources/application.yaml +++ b/covid19-model/src/main/resources/application.yaml @@ -1 +1,32 @@ +spring: + application: + name: covid19-model + + flyway: + locations: classpath:db/migration + schemas: covid + + + datasource: + driver-class-name: org.postgresql.Driver + url: jdbc:postgresql://localhost:5432/covid19 + username: postgres + password: + + jpa: + show-sql: true + hibernate: + dialect: org.hibernate.dialect.PostgreSQL + ddl-auto: none + + properties: + hibernate: + default_schema: covid + use_sql_comments: true + format_sql: true + show_sql: true + jdbc: + lob: + non_contextual_creation: true + diff --git a/covid19-model/src/main/resources/db/migration/V000__init.sql b/covid19-model/src/main/resources/db/migration/V000__init.sql new file mode 100644 index 0000000..1e5723d --- /dev/null +++ b/covid19-model/src/main/resources/db/migration/V000__init.sql @@ -0,0 +1,51 @@ +--create schema covid; + +create sequence covid.cvd_regions_seq start 1 increment by 1; + +create table covid.regions +( + id bigint not null default nextval('covid.cvd_regions_seq') + constraint regions_pkey primary key, + name varchar(255) not null + constraint regions_name_uniq unique +); + +alter sequence covid.cvd_regions_seq owned by covid.regions.id; +alter sequence covid.cvd_regions_seq owner to covid19; +alter table covid.regions owner to covid19; + +create sequence covid.cvd_updates_seq start 1 increment by 1; + +create table covid.cvd_updates +( + id bigint not null default nextval('covid.cvd_updates_seq') + constraint cvd_updates_pkey primary key, + created_on timestamp + constraint cvd_upd_created_uniq unique, + datetime timestamp +); + +alter sequence covid.cvd_updates_seq owned by covid.cvd_updates.id; +alter sequence covid.cvd_updates_seq owner to covid19; +alter table covid.cvd_updates owner to covid19; + +create sequence covid.cvd_stats_seq start 1 increment by 1; + +create table if not exists covid.cvd_stats +( + id bigint not null default nextval('covid.cvd_stats_seq') + constraint cvd_stats_pkey primary key, + created_on timestamp, + died bigint not null, + healed bigint not null, + sick bigint not null, + region_id bigint + constraint fk_cvd_stats_region references covid.regions, + update_id bigint + constraint fk_cvd_stats_updates references covid.cvd_updates +); + +alter sequence covid.cvd_stats_seq owned by covid.cvd_stats.id; +alter sequence covid.cvd_stats_seq owner to covid19; +alter table covid_statistics owner to covid19; + diff --git a/covid19-model/src/main/resources/db/migration/V001__migrating_data.sql b/covid19-model/src/main/resources/db/migration/V001__migrating_data.sql new file mode 100644 index 0000000..811013a --- /dev/null +++ b/covid19-model/src/main/resources/db/migration/V001__migrating_data.sql @@ -0,0 +1,104 @@ +insert into covid.regions(id, name) VALUES +('1', 'Москва'), +('2', 'Московская область'), +('3', 'Санкт-Петербург'), +('4', 'Нижегородская область'), +('5', 'Республика Коми'), +('6', 'Ленинградская область'), +('7', 'Краснодарский край'), +('8', 'Мурманская область'), +('9', 'Красноярский край'), +('10', 'Республика Дагестан'), +('11', 'Брянская область'), +('12', 'Республика Башкортостан'), +('13', 'Тверская область'), +('14', 'Тульская область'), +('15', 'Республика Ингушетия'), +('16', 'Рязанская область'), +('17', 'Республика Марий Эл'), +('18', 'Ставропольский край'), +('19', 'Владимирская область'), +('20', 'Республика Мордовия'), +('21', 'Ростовская область'), +('22', 'Тюменская область'), +('23', 'Чеченская Республика'), +('24', 'Пермский край'), +('25', 'Курская область'), +('26', 'Тамбовская область'), +('27', 'Республика Чувашия'), +('28', 'Ивановская область'), +('29', 'Ханты-Мансийский АО'), +('30', 'Республика Татарстан'), +('31', 'Ульяновская область'), +('32', 'Смоленская область'), +('33', 'Калужская область'), +('34', 'Хабаровский край'), +('35', 'Пензенская область'), +('36', 'Оренбургская область'), +('37', 'Воронежская область'), +('38', 'Липецкая область'), +('39', 'Свердловская область'), +('40', 'Орловская область'), +('41', 'Калининградская область'), +('42', 'Кабардино-Балкарская Республика'), +('43', 'Республика Бурятия'), +('44', 'Кировская область'), +('45', 'Ямало-Ненецкий автономный округ'), +('46', 'Ярославская область'), +('47', 'Астраханская область'), +('48', 'Саратовская область'), +('49', 'Республика Северная Осетия — Алания'), +('50', 'Вологодская область'), +('51', 'Новосибирская область'), +('52', 'Республика Адыгея'), +('53', 'Белгородская область'), +('54', 'Новгородская область'), +('55', 'Волгоградская область'), +('56', 'Республика Калмыкия'), +('57', 'Приморский край'), +('58', 'Самарская область'), +('59', 'Алтайский край'), +('60', 'Магаданская область'), +('61', 'Удмуртская Республика'), +('62', 'Челябинская область'), +('63', 'Иркутская область'), +('64', 'Костромская область'), +('65', 'Карачаево-Черкесская Республика'), +('66', 'Республика Саха (Якутия)'), +('67', 'Республика Хакасия'), +('68', 'Республика Крым'), +('69', 'Псковская область'), +('70', 'Архангельская область'), +('71', 'Забайкальский край'), +('72', 'Омская область'), +('73', 'Камчатский край'), +('74', 'Кемеровская область'), +('75', 'Томская область'), +('76', 'Еврейская автономная область'), +('77', 'Сахалинская область'), +('78', 'Республика Карелия'), +('79', 'Амурская область'), +('80', 'Курганская область'), +('81', 'Севастополь'), +('82', 'Республика Тыва'), +('83', 'Республика Алтай'), +('84', 'Чукотский автономный округ'), +('85', 'Ненецкий автономный округ'); + +insert into covid.cvd_updates(created_on, datetime) +SELECT u.created_on, u.datetime from public.update_info u; + +insert into covid.cvd_stats(region_id, created_on, sick, healed, died, update_id) +select r.id, + s.created_on, + s.sick, + s.healed, + s.died, + u_new.id +from public.covid_statistics as s + inner join covid.regions as r + on s.region_id = r.name + inner join public.update_info as u_old + on u_old.id = s.update_info_id + inner join covid.cvd_updates as u_new + on u_new.datetime = u_old.datetime; \ No newline at end of file diff --git a/covid19-scheduler/build.gradle b/covid19-scheduler/build.gradle index 4adbef2..2aa726e 100644 --- a/covid19-scheduler/build.gradle +++ b/covid19-scheduler/build.gradle @@ -6,10 +6,15 @@ dependencies { compile(project(':covid19-model')) implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.apache.camel.springboot:camel-spring-boot-starter:3.1.0' + implementation "org.apache.camel.springboot:camel-spring-boot-starter:${camelVersion}" implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.jsoup:jsoup:1.13.1' + compileOnly "org.springframework.boot:spring-boot-configuration-processor:${springBootVersion}" + annotationProcessor "org.springframework.boot:spring-boot-configuration-processor:${springBootVersion}" + + implementation "org.jsoup:jsoup:${jsoupVersion}" + + implementation "org.apache.camel:camel-mail:${camelVersion}" runtimeOnly 'org.postgresql:postgresql' diff --git a/covid19-scheduler/src/main/java/com/bvn13/covid19/scheduler/Covid19SchedulerApplication.java b/covid19-scheduler/src/main/java/com/bvn13/covid19/scheduler/Covid19SchedulerApplication.java index 0d057fb..02c3de5 100644 --- a/covid19-scheduler/src/main/java/com/bvn13/covid19/scheduler/Covid19SchedulerApplication.java +++ b/covid19-scheduler/src/main/java/com/bvn13/covid19/scheduler/Covid19SchedulerApplication.java @@ -17,8 +17,10 @@ limitations under the License. package com.bvn13.covid19.scheduler; import com.bvn13.covid19.model.Covid19ModelConfig; +import com.bvn13.covid19.scheduler.updater.stopcoronovirusrf.MailConfig; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Import; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @@ -27,6 +29,7 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories; @Import({ Covid19ModelConfig.class }) +@EnableConfigurationProperties(MailConfig.class) public class Covid19SchedulerApplication { public static void main(String[] args) { diff --git a/covid19-scheduler/src/main/java/com/bvn13/covid19/scheduler/CovidUpdateInfosRepository.java b/covid19-scheduler/src/main/java/com/bvn13/covid19/scheduler/CovidUpdateInfosRepository.java index 9421766..6ec9f29 100644 --- a/covid19-scheduler/src/main/java/com/bvn13/covid19/scheduler/CovidUpdateInfosRepository.java +++ b/covid19-scheduler/src/main/java/com/bvn13/covid19/scheduler/CovidUpdateInfosRepository.java @@ -16,10 +16,10 @@ limitations under the License. package com.bvn13.covid19.scheduler; -import com.bvn13.covid19.model.entities.CovidUpdateInfo; +import com.bvn13.covid19.model.entities.CovidUpdate; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository -public interface CovidUpdateInfosRepository extends JpaRepository { +public interface CovidUpdateInfosRepository extends JpaRepository { } diff --git a/covid19-scheduler/src/main/java/com/bvn13/covid19/scheduler/updater/stopcoronovirusrf/MailConfig.java b/covid19-scheduler/src/main/java/com/bvn13/covid19/scheduler/updater/stopcoronovirusrf/MailConfig.java new file mode 100644 index 0000000..88ce6a7 --- /dev/null +++ b/covid19-scheduler/src/main/java/com/bvn13/covid19/scheduler/updater/stopcoronovirusrf/MailConfig.java @@ -0,0 +1,53 @@ +/* +Copyright [2020] [bvn13] + +Licensed 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 com.bvn13.covid19.scheduler.updater.stopcoronovirusrf; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; + +@ConfigurationProperties(prefix = "app.mail") +public class MailConfig { + + @NotBlank + private String username; + @NotBlank + private String password; + @NotBlank + private String host; + @Min(1) + @Max(65536) + private int port; + @NotBlank + private String sender; + @NotBlank + private String recipient; + @NotBlank + private String subject; + + public String constructEndpoint() { + return "smtp://" + host + ":" + port + + "?username=" + username + + "&password=" + password + + "&from=" + sender + + "&to=" + recipient + + "&subject=" + subject; + } + +} diff --git a/covid19-scheduler/src/main/java/com/bvn13/covid19/scheduler/updater/stopcoronovirusrf/StopcoronovirusRfService.java b/covid19-scheduler/src/main/java/com/bvn13/covid19/scheduler/updater/stopcoronovirusrf/StopcoronovirusRfService.java index 86e8a23..a1e7039 100644 --- a/covid19-scheduler/src/main/java/com/bvn13/covid19/scheduler/updater/stopcoronovirusrf/StopcoronovirusRfService.java +++ b/covid19-scheduler/src/main/java/com/bvn13/covid19/scheduler/updater/stopcoronovirusrf/StopcoronovirusRfService.java @@ -17,11 +17,11 @@ limitations under the License. package com.bvn13.covid19.scheduler.updater.stopcoronovirusrf; import com.bvn13.covid19.model.entities.CovidStat; +import com.bvn13.covid19.model.entities.CovidUpdate; import com.bvn13.covid19.model.entities.Region; -import com.bvn13.covid19.model.entities.CovidUpdateInfo; import com.bvn13.covid19.scheduler.CovidStatsRepository; -import com.bvn13.covid19.scheduler.RegionsRepository; import com.bvn13.covid19.scheduler.CovidUpdateInfosRepository; +import com.bvn13.covid19.scheduler.RegionsRepository; import com.bvn13.covid19.scheduler.updater.stopcoronovirusrf.model.RowData; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; @@ -33,7 +33,6 @@ import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Collection; -import java.util.Iterator; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -59,31 +58,10 @@ public class StopcoronovirusRfService { @Transactional public void saveRawData(String date, Collection rawData) { - ZonedDateTime zdt = parseZonedDateTime(date); - - CovidUpdateInfo updateInfo = new CovidUpdateInfo(); - updateInfo.setCreatedOn(LocalDateTime.now()); - updateInfo.setDatetime(zdt); - updateInfo = updatesRepository.save(updateInfo); - - Iterator iter = rawData.iterator(); - while (iter.hasNext()) { - RowData row = iter.next(); - - Region region = regionsRepository.findByName(row.getRegion()).orElseGet(() -> { - Region r = new Region(); - r.setName(row.getRegion()); - return regionsRepository.save(r); - }); - - CovidStat covidStat = new CovidStat(); - covidStat.setUpdateInfo(updateInfo); - covidStat.setRegion(region); - covidStat.setSick(Long.parseLong(row.getSick())); - covidStat.setHealed(Long.parseLong(row.getHealed())); - covidStat.setDied(Long.parseLong(row.getDied())); - - repository.save(covidStat); + ZonedDateTime dateOfData = parseZonedDateTime(date); + CovidUpdate updateInfo = createUpdateInfo(dateOfData); + for (RowData row : rawData) { + repository.save(createStats(row, updateInfo)); } } @@ -104,6 +82,31 @@ public class StopcoronovirusRfService { } } + private CovidUpdate createUpdateInfo(ZonedDateTime dateOfData) { + CovidUpdate updateInfo = new CovidUpdate(); + updateInfo.setCreatedOn(LocalDateTime.now()); + updateInfo.setDatetime(dateOfData); + return updatesRepository.save(updateInfo); + } + + private Region detectRegion(String region) { + return regionsRepository.findByName(region).orElseGet(() -> { + Region r = new Region(); + r.setName(region); + return regionsRepository.save(r); + }); + } + + private CovidStat createStats(RowData row, CovidUpdate updateInfo) { + CovidStat covidStat = new CovidStat(); + covidStat.setUpdateInfo(updateInfo); + covidStat.setRegion(detectRegion(row.getRegion())); + covidStat.setSick(Long.parseLong(row.getSick())); + covidStat.setHealed(Long.parseLong(row.getHealed())); + covidStat.setDied(Long.parseLong(row.getDied())); + return covidStat; + } + private int detectMonth(String m) { switch (m.trim().toLowerCase()) { case "январь": diff --git a/covid19-scheduler/src/main/java/com/bvn13/covid19/scheduler/updater/stopcoronovirusrf/StopcoronovirusRfUpdater.java b/covid19-scheduler/src/main/java/com/bvn13/covid19/scheduler/updater/stopcoronovirusrf/StopcoronovirusRfUpdater.java index 515eefa..6e582f3 100644 --- a/covid19-scheduler/src/main/java/com/bvn13/covid19/scheduler/updater/stopcoronovirusrf/StopcoronovirusRfUpdater.java +++ b/covid19-scheduler/src/main/java/com/bvn13/covid19/scheduler/updater/stopcoronovirusrf/StopcoronovirusRfUpdater.java @@ -19,7 +19,10 @@ package com.bvn13.covid19.scheduler.updater.stopcoronovirusrf; import com.bvn13.covid19.scheduler.updater.stopcoronovirusrf.model.RowData; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.camel.*; +import org.apache.camel.Body; +import org.apache.camel.Handler; +import org.apache.camel.Header; +import org.apache.camel.LoggingLevel; import org.apache.camel.builder.RouteBuilder; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -36,12 +39,12 @@ public class StopcoronovirusRfUpdater extends RouteBuilder { private final StopcoronovirusRfDataRetriever dataRetriever; private final StopcoronovirusRfService service; + private final MailConfig mailConfig; @Value("${app.timer.stopcoronovirusrf}") private int stopcoronovirusrfTimerSecons; private long stopcoronovirusrfTimerMillis; - @PostConstruct public void init() { stopcoronovirusrfTimerMillis = stopcoronovirusrfTimerSecons * 1000; @@ -50,6 +53,9 @@ public class StopcoronovirusRfUpdater extends RouteBuilder { @Override public void configure() throws Exception { + onException(RuntimeException.class) + .to(mailConfig.constructEndpoint()); + from("timer:stopcoronovirusrf?delay=1000&period="+stopcoronovirusrfTimerMillis) .log(LoggingLevel.DEBUG, log, "Start retrieving data from stopcoronovirus.rf") .process(dataRetriever::retrieveData) diff --git a/covid19-scheduler/src/main/resources/application.yaml b/covid19-scheduler/src/main/resources/application.yaml index dcb6b66..dbdb5ab 100644 --- a/covid19-scheduler/src/main/resources/application.yaml +++ b/covid19-scheduler/src/main/resources/application.yaml @@ -1,3 +1,6 @@ +server: + port: 8081 + app: user-agent: Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:74.0) Gecko/20100101 Firefox/74.0 zone-id: Europe/Moscow @@ -5,11 +8,21 @@ app: # IN SECONDS # 1 hour stopcoronovirusrf: 3600 + mail: + username: + password: + host: smtp.yandex.ru + port: 465 + to: + subject: Ошибка загрузки данных COVID19 spring: application: name: covid19-scheduler + flyway: + locations: classpath:db/migration + schemas: covid datasource: driver-class-name: org.postgresql.Driver @@ -21,10 +34,11 @@ spring: show-sql: true hibernate: dialect: org.hibernate.dialect.PostgreSQL - ddl-auto: update + ddl-auto: validate properties: hibernate: + default_schema: covid use_sql_comments: true format_sql: true show_sql: true diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 44e7c4d..a4b4429 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists