feat: Support CRUD functionality (#7)
The station search implementation only works via DB and is very slow. For a simple query, the answer takes about 1s or longer. That is 100 times slower than it should be. For now, however, this solution is adequate to achieve a first prototype that includes the core functionality. feat: Add station search
This commit is contained in:
parent
b5681181fb
commit
7fbd270019
|
@ -7,9 +7,9 @@ tasks.withType<JavaCompile>().configureEach {
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<Test>().configureEach {
|
tasks.withType<Test>().configureEach {
|
||||||
jvmArgs?.plusAssign("--enable-preview")
|
jvmArgs.plusAssign("--enable-preview")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<JavaExec>().configureEach {
|
tasks.withType<JavaExec>().configureEach {
|
||||||
jvmArgs?.plusAssign("--enable-preview")
|
jvmArgs.plusAssign("--enable-preview")
|
||||||
}
|
}
|
|
@ -53,8 +53,10 @@ normalization.runtimeClasspath.metaInf {
|
||||||
ignoreAttribute("Build-Timestamp")
|
ignoreAttribute("Build-Timestamp")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
tasks.register("cleanLibs") {
|
tasks.register("cleanLibs") {
|
||||||
delete("${buildDir}/libs")
|
delete("${layout.buildDirectory.get().asFile}/libs")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.build {
|
tasks.build {
|
||||||
|
|
|
@ -16,6 +16,6 @@ tasks.named("build") {
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register("cleanCache") {
|
tasks.register("cleanCache") {
|
||||||
delete("${buildDir}/jib-cache")
|
delete("${layout.buildDirectory.get().asFile}/jib-cache")
|
||||||
delete("${buildDir}/libs")
|
delete("${layout.buildDirectory.get().asFile}/libs")
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ val projectSourceCompatibility: String = rootProject.properties["projectSourceCo
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
compilerOptions {
|
compilerOptions {
|
||||||
freeCompilerArgs.add("-Xjvm-default=all")
|
freeCompilerArgs.addAll("-Xjvm-default=all", "-Xjsr305=strict")
|
||||||
jvmTarget.set(JvmTarget.fromTarget(projectSourceCompatibility))
|
jvmTarget.set(JvmTarget.fromTarget(projectSourceCompatibility))
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,10 +9,10 @@ apply(plugin="com.netflix.nebula.release")
|
||||||
tasks.register("writeVersionProperties") {
|
tasks.register("writeVersionProperties") {
|
||||||
group = "version"
|
group = "version"
|
||||||
mustRunAfter("release")
|
mustRunAfter("release")
|
||||||
outputs.file("$buildDir/version.properties")
|
outputs.file("${layout.buildDirectory.get().asFile}/version.properties")
|
||||||
val directory = buildDir
|
val directory = layout.buildDirectory.get().asFile
|
||||||
doLast {
|
doLast {
|
||||||
Files.createDirectories(directory.toPath())
|
Files.createDirectories(directory.toPath())
|
||||||
File("$buildDir/version.properties").writeText("VERSION=${project.version}\n")
|
File("${layout.buildDirectory.get().asFile}/version.properties").writeText("VERSION=${project.version}\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,18 +1,16 @@
|
||||||
import org.gradle.accessors.dm.LibrariesForLibs
|
import org.gradle.accessors.dm.LibrariesForLibs
|
||||||
|
import org.springframework.boot.gradle.tasks.bundling.BootJar
|
||||||
import java.time.ZonedDateTime
|
import java.time.ZonedDateTime
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
import java.time.format.DateTimeFormatter.ofPattern
|
import java.time.format.DateTimeFormatter.ofPattern
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("org.springframework.boot")
|
id("twomartens.spring-boot-base")
|
||||||
id("twomartens.java")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val libs = the<LibrariesForLibs>()
|
val libs = the<LibrariesForLibs>()
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(platform(libs.spring.boot))
|
|
||||||
|
|
||||||
implementation(libs.bundles.spring.boot)
|
implementation(libs.bundles.spring.boot)
|
||||||
testImplementation(libs.spring.boot.test)
|
testImplementation(libs.spring.boot.test)
|
||||||
}
|
}
|
||||||
|
@ -37,13 +35,6 @@ val integrationTestImplementation: Configuration by configurations.getting {
|
||||||
extendsFrom(configurations.testImplementation.get())
|
extendsFrom(configurations.testImplementation.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
|
||||||
configureEach {
|
|
||||||
exclude(group = "org.springframework.boot", module = "spring-boot-starter-logging")
|
|
||||||
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register<Test>("integrationTest") {
|
tasks.register<Test>("integrationTest") {
|
||||||
systemProperty("junit.jupiter.execution.parallel.enabled", true)
|
systemProperty("junit.jupiter.execution.parallel.enabled", true)
|
||||||
systemProperty("junit.jupiter.execution.parallel.mode.default", "concurrent")
|
systemProperty("junit.jupiter.execution.parallel.mode.default", "concurrent")
|
||||||
|
@ -76,5 +67,9 @@ tasks.jar {
|
||||||
|
|
||||||
springBoot {
|
springBoot {
|
||||||
buildInfo()
|
buildInfo()
|
||||||
mainClass.set("de.twomartens.timetable.MainApplicationKt")
|
mainClass.set(project.properties["mainClass"].toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.named<BootJar>("bootJar") {
|
||||||
|
enabled = true
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
import org.gradle.accessors.dm.LibrariesForLibs
|
||||||
|
import org.springframework.boot.gradle.tasks.bundling.BootJar
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("org.springframework.boot")
|
||||||
|
id("twomartens.java")
|
||||||
|
}
|
||||||
|
|
||||||
|
val libs = the<LibrariesForLibs>()
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(platform(libs.spring.boot))
|
||||||
|
implementation(libs.spring.boot.log4j)
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
configureEach {
|
||||||
|
exclude(group = "org.springframework.boot", module = "spring-boot-starter-logging")
|
||||||
|
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named<BootJar>("bootJar") {
|
||||||
|
enabled = false
|
||||||
|
}
|
|
@ -1,13 +1,13 @@
|
||||||
import org.gradle.accessors.dm.LibrariesForLibs
|
import org.gradle.accessors.dm.LibrariesForLibs
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("twomartens.spring-boot")
|
id("twomartens.spring-boot-application")
|
||||||
|
id("twomartens.spring-boot-cloud-base")
|
||||||
}
|
}
|
||||||
|
|
||||||
val libs = the<LibrariesForLibs>()
|
val libs = the<LibrariesForLibs>()
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(platform(libs.spring.cloud))
|
|
||||||
implementation(libs.bundles.spring.boot.server)
|
implementation(libs.bundles.spring.boot.server)
|
||||||
implementation(libs.spring.openapi)
|
implementation(libs.spring.openapi)
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import org.gradle.accessors.dm.LibrariesForLibs
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("twomartens.spring-boot-base")
|
||||||
|
}
|
||||||
|
|
||||||
|
val libs = the<LibrariesForLibs>()
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(platform(libs.spring.cloud))
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
projectname=timetable
|
projectname=timetable
|
||||||
projectgroup=de.2martens
|
projectgroup=de.2martens
|
||||||
projectSourceCompatibility=21
|
projectSourceCompatibility=21
|
||||||
|
mainClass=de.twomartens.timetable.MainApplicationKt
|
||||||
file.encoding=utf-8
|
file.encoding=utf-8
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
org.gradle.daemon=true
|
org.gradle.daemon=true
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
plugins {
|
||||||
|
id("twomartens.spring-boot-cloud-base")
|
||||||
|
id("twomartens.kotlin")
|
||||||
|
kotlin("kapt")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":common"))
|
||||||
|
implementation(project(":model"))
|
||||||
|
implementation(project(":support"))
|
||||||
|
|
||||||
|
implementation(libs.mapstruct.base)
|
||||||
|
annotationProcessor(libs.mapstruct.processor)
|
||||||
|
kapt(libs.mapstruct.processor)
|
||||||
|
|
||||||
|
implementation(libs.jaxb.impl)
|
||||||
|
implementation(libs.jakarta.xml.binding)
|
||||||
|
|
||||||
|
implementation(libs.spring.openapi)
|
||||||
|
implementation(libs.spring.boot.mongo)
|
||||||
|
implementation(libs.spring.cloud.leader.election)
|
||||||
|
implementation(libs.spring.cloud.starter.bus.kafka)
|
||||||
|
}
|
|
@ -13,7 +13,7 @@ open class ThreadPoolTaskSchedulerConfig {
|
||||||
open fun threadPoolTaskScheduler(): ThreadPoolTaskScheduler {
|
open fun threadPoolTaskScheduler(): ThreadPoolTaskScheduler {
|
||||||
val scheduler = ThreadPoolTaskScheduler()
|
val scheduler = ThreadPoolTaskScheduler()
|
||||||
scheduler.poolSize = POOL_SIZE
|
scheduler.poolSize = POOL_SIZE
|
||||||
scheduler.threadNamePrefix = THREAD_NAME_PREFIX
|
scheduler.setThreadNamePrefix(THREAD_NAME_PREFIX)
|
||||||
return scheduler
|
return scheduler
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -11,11 +11,7 @@ class ScheduledTasksCreatedEvent private constructor(source: Instant, originServ
|
||||||
destination: Destination)
|
destination: Destination)
|
||||||
: RemoteApplicationEvent(source, originService, destination) {
|
: RemoteApplicationEvent(source, originService, destination) {
|
||||||
|
|
||||||
private val creationTime: Instant
|
private val creationTime: Instant = source
|
||||||
|
|
||||||
init {
|
|
||||||
creationTime = source
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getSource(): Instant {
|
override fun getSource(): Instant {
|
||||||
return creationTime
|
return creationTime
|
|
@ -1,6 +1,9 @@
|
||||||
package de.twomartens.timetable.bahnApi.mapper
|
package de.twomartens.timetable.bahnApi.mapper
|
||||||
|
|
||||||
import de.twomartens.timetable.bahnApi.model.db.BahnStation
|
import de.twomartens.timetable.bahnApi.model.db.BahnStation
|
||||||
|
import de.twomartens.timetable.model.common.CountryCode
|
||||||
|
import de.twomartens.timetable.model.common.StationId
|
||||||
|
import de.twomartens.timetable.model.db.Station
|
||||||
import de.twomartens.timetable.types.NonEmptyString
|
import de.twomartens.timetable.types.NonEmptyString
|
||||||
import org.mapstruct.*
|
import org.mapstruct.*
|
||||||
|
|
||||||
|
@ -22,4 +25,16 @@ interface BahnStationMapper {
|
||||||
dto.db
|
dto.db
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Mapping(target = "id", ignore = true)
|
||||||
|
@Mapping(target = "created", ignore = true)
|
||||||
|
@Mapping(target = "lastModified", ignore = true)
|
||||||
|
fun mapToCommonDB(db: BahnStation, countryCode: String): Station {
|
||||||
|
return Station(
|
||||||
|
StationId.of(NonEmptyString(countryCode + "-" + db.eva.value.toString())),
|
||||||
|
CountryCode(NonEmptyString(countryCode)),
|
||||||
|
db.name,
|
||||||
|
listOf()
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,5 @@
|
||||||
package de.twomartens.timetable.bahnApi.model
|
package de.twomartens.timetable.bahnApi.model
|
||||||
|
|
||||||
import de.twomartens.timetable.model.common.StationId
|
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
value class Eva(val value: Int) {
|
value class Eva(val value: Int) {
|
||||||
init {
|
init {
|
||||||
|
@ -17,8 +15,8 @@ value class Eva(val value: Int) {
|
||||||
companion object {
|
companion object {
|
||||||
val UNKNOWN = Eva(-1)
|
val UNKNOWN = Eva(-1)
|
||||||
|
|
||||||
fun of(stationId: StationId): Eva {
|
fun of(stationId: String): Eva {
|
||||||
return Eva(stationId.stationIdWithinCountry.toInt())
|
return Eva(stationId.toInt())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,7 +12,7 @@ import java.time.Instant
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
|
||||||
@Document
|
@Document
|
||||||
@CompoundIndex(def = "{'eva': 1, 'fetchedDateTime': 1", unique = true)
|
@CompoundIndex(def = "{'eva': 1, 'fetchedDateTime': 1}", unique = true)
|
||||||
data class ScheduledFetchTask(
|
data class ScheduledFetchTask(
|
||||||
var eva: Eva,
|
var eva: Eva,
|
||||||
var fetchedDateTime: HourAtDay,
|
var fetchedDateTime: HourAtDay,
|
|
@ -8,7 +8,7 @@ import jakarta.xml.bind.annotation.XmlRootElement
|
||||||
@XmlRootElement(name = "stations")
|
@XmlRootElement(name = "stations")
|
||||||
@XmlAccessorType(XmlAccessType.FIELD)
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
data class BahnStations(
|
data class BahnStations(
|
||||||
@field:XmlElement(name = "station") var stations: List<BahnStation>
|
@field:XmlElement(name = "station") var stations: MutableList<BahnStation>
|
||||||
) {
|
) {
|
||||||
constructor() : this(listOf())
|
constructor() : this(mutableListOf())
|
||||||
}
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package de.twomartens.timetable.bahnApi.service
|
||||||
|
|
||||||
|
import de.twomartens.timetable.bahnApi.model.Eva
|
||||||
|
import de.twomartens.timetable.bahnApi.model.dto.BahnStation
|
||||||
|
import de.twomartens.timetable.bahnApi.model.dto.BahnStations
|
||||||
|
import de.twomartens.timetable.bahnApi.model.dto.BahnTimetable
|
||||||
|
import de.twomartens.timetable.bahnApi.property.BahnApiProperties
|
||||||
|
import de.twomartens.timetable.types.HourAtDay
|
||||||
|
import org.springframework.http.MediaType
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
import org.springframework.web.client.RestClient
|
||||||
|
import java.time.LocalTime
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class BahnApiService(
|
||||||
|
private val restClient: RestClient,
|
||||||
|
private val properties: BahnApiProperties
|
||||||
|
) {
|
||||||
|
fun fetchStations(pattern: String): List<BahnStation> {
|
||||||
|
val body = restClient.get()
|
||||||
|
.uri("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/station/${pattern}")
|
||||||
|
.headers {
|
||||||
|
it.accept = mutableListOf(MediaType.APPLICATION_XML)
|
||||||
|
it.contentType = MediaType.APPLICATION_XML
|
||||||
|
it.set("DB-Client-Id", properties.clientId)
|
||||||
|
it.set("DB-Api-Key", properties.clientSecret)
|
||||||
|
}
|
||||||
|
.retrieve()
|
||||||
|
.body(BahnStations::class.java)
|
||||||
|
return body?.stations ?: listOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fetchTimetable(eva: Eva, hourAtDay: HourAtDay): BahnTimetable {
|
||||||
|
val dateFormatter = DateTimeFormatter.ofPattern("yyMMdd")
|
||||||
|
val timeFormatter = DateTimeFormatter.ofPattern("HH")
|
||||||
|
val time = LocalTime.of(hourAtDay.hour.value, 0)
|
||||||
|
val body = restClient.get()
|
||||||
|
.uri("https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/" +
|
||||||
|
"${eva}/${hourAtDay.date.format(dateFormatter)}/${time.format(timeFormatter)}")
|
||||||
|
.headers {
|
||||||
|
it.accept = mutableListOf(MediaType.APPLICATION_XML)
|
||||||
|
it.contentType = MediaType.APPLICATION_XML
|
||||||
|
it.set("DB-Client-Id", properties.clientId)
|
||||||
|
it.set("DB-Api-Key", properties.clientSecret)
|
||||||
|
}
|
||||||
|
.retrieve()
|
||||||
|
.body(BahnTimetable::class.java)
|
||||||
|
return body!!
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
package de.twomartens.timetable.bahnApi.service
|
||||||
|
|
||||||
|
import de.twomartens.timetable.bahnApi.mapper.BahnStationMapper
|
||||||
|
import de.twomartens.timetable.bahnApi.mapper.BahnTimetableMapper
|
||||||
|
import de.twomartens.timetable.bahnApi.model.dto.BahnStation
|
||||||
|
import de.twomartens.timetable.bahnApi.model.dto.BahnTimetable
|
||||||
|
import de.twomartens.timetable.bahnApi.repository.BahnStationRepository
|
||||||
|
import de.twomartens.timetable.bahnApi.repository.BahnTimetableRepository
|
||||||
|
import de.twomartens.timetable.model.db.Station
|
||||||
|
import de.twomartens.timetable.model.repository.StationRepository
|
||||||
|
import de.twomartens.timetable.types.HourAtDay
|
||||||
|
import org.mapstruct.factory.Mappers
|
||||||
|
import org.springframework.data.mongodb.core.BulkOperations
|
||||||
|
import org.springframework.data.mongodb.core.MongoTemplate
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@Service
|
||||||
|
open class BahnDatabaseService(
|
||||||
|
private val bahnStationRepository: BahnStationRepository,
|
||||||
|
private val stationRepository: StationRepository,
|
||||||
|
private val bahnTimetableRepository: BahnTimetableRepository,
|
||||||
|
private val mongoTemplate: MongoTemplate
|
||||||
|
) {
|
||||||
|
private val bahnStationMapper = Mappers.getMapper(BahnStationMapper::class.java)
|
||||||
|
private val bahnTimetableMapper = Mappers.getMapper(BahnTimetableMapper::class.java)
|
||||||
|
|
||||||
|
fun storeStations(stations: List<BahnStation>) {
|
||||||
|
|
||||||
|
val existingStations = stationRepository.findAllByCountryCode(COUNTRY_CODE)
|
||||||
|
val commonStationMap = existingStations
|
||||||
|
.associateBy { it.stationId.stationIdWithinCountry }
|
||||||
|
val bahnStationMap = stations.asSequence()
|
||||||
|
.map(bahnStationMapper::mapToDB)
|
||||||
|
.associateBy { it.eva.toString() }
|
||||||
|
|
||||||
|
updateBahnStations(bahnStationMap)
|
||||||
|
deleteRemovedStations(existingStations, bahnStationMap)
|
||||||
|
updateStations(existingStations, bahnStationMap)
|
||||||
|
addNewStations(bahnStationMap, commonStationMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateBahnStations(bahnStationMap: Map<String, de.twomartens.timetable.bahnApi.model.db.BahnStation>) {
|
||||||
|
bahnStationRepository.deleteAll()
|
||||||
|
val bahnStations: List<de.twomartens.timetable.bahnApi.model.db.BahnStation> = buildList {
|
||||||
|
this.addAll(bahnStationMap.values)
|
||||||
|
}
|
||||||
|
|
||||||
|
mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED,
|
||||||
|
de.twomartens.timetable.bahnApi.model.db.BahnStation::class.java)
|
||||||
|
.insert(bahnStations)
|
||||||
|
.execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun deleteRemovedStations(
|
||||||
|
existingStations: List<Station>,
|
||||||
|
bahnStationMap: Map<String, de.twomartens.timetable.bahnApi.model.db.BahnStation>
|
||||||
|
) {
|
||||||
|
val deletedStations = existingStations
|
||||||
|
.filterNot { bahnStationMap.containsKey(it.stationId.stationIdWithinCountry) }
|
||||||
|
stationRepository.deleteAll(deletedStations)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateStations(
|
||||||
|
existingStations: List<Station>,
|
||||||
|
bahnStationMap: Map<String, de.twomartens.timetable.bahnApi.model.db.BahnStation>
|
||||||
|
) {
|
||||||
|
val updatedStations = existingStations
|
||||||
|
.filter { bahnStationMap.containsKey(it.stationId.stationIdWithinCountry) }
|
||||||
|
updatedStations.map {
|
||||||
|
it.name = bahnStationMap[it.stationId.stationIdWithinCountry]!!.name
|
||||||
|
}
|
||||||
|
stationRepository.saveAll(updatedStations)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addNewStations(
|
||||||
|
bahnStations: Map<String, de.twomartens.timetable.bahnApi.model.db.BahnStation>,
|
||||||
|
commonStationMap: Map<String, Station>
|
||||||
|
) {
|
||||||
|
val newStations = bahnStations.asSequence()
|
||||||
|
.filterNot { commonStationMap.containsKey(it.key) }
|
||||||
|
.map { bahnStationMapper.mapToCommonDB(it.value, COUNTRY_CODE) }
|
||||||
|
.toList()
|
||||||
|
|
||||||
|
mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED,
|
||||||
|
Station::class.java)
|
||||||
|
.insert(newStations)
|
||||||
|
.execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun storeTimetable(timetable: BahnTimetable, hourAtDay: HourAtDay) {
|
||||||
|
bahnTimetableRepository.save(bahnTimetableMapper.mapToDB(timetable, hourAtDay))
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val COUNTRY_CODE = "de"
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,7 @@ import java.time.ZonedDateTime
|
||||||
private const val PAST_TASK_EXECUTION_OFFSET = 1
|
private const val PAST_TASK_EXECUTION_OFFSET = 1
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class TaskScheduler(
|
class FetchTaskScheduler(
|
||||||
private val clock: Clock,
|
private val clock: Clock,
|
||||||
private val threadPoolTaskScheduler: ThreadPoolTaskScheduler,
|
private val threadPoolTaskScheduler: ThreadPoolTaskScheduler,
|
||||||
private val threadPoolTaskExecutor: ThreadPoolTaskExecutor,
|
private val threadPoolTaskExecutor: ThreadPoolTaskExecutor,
|
|
@ -1,5 +1,7 @@
|
||||||
package de.twomartens.timetable.bahnApi.service
|
package de.twomartens.timetable.bahnApi.service
|
||||||
|
|
||||||
|
import de.twomartens.support.model.LeadershipStatus
|
||||||
|
import de.twomartens.support.service.BusService
|
||||||
import de.twomartens.timetable.bahnApi.events.ScheduledTasksCreatedEvent
|
import de.twomartens.timetable.bahnApi.events.ScheduledTasksCreatedEvent
|
||||||
import de.twomartens.timetable.bahnApi.model.Eva
|
import de.twomartens.timetable.bahnApi.model.Eva
|
||||||
import de.twomartens.timetable.bahnApi.model.FetchDates
|
import de.twomartens.timetable.bahnApi.model.FetchDates
|
||||||
|
@ -7,8 +9,6 @@ import de.twomartens.timetable.bahnApi.model.TaskFactory
|
||||||
import de.twomartens.timetable.bahnApi.model.db.ScheduledFetchTask
|
import de.twomartens.timetable.bahnApi.model.db.ScheduledFetchTask
|
||||||
import de.twomartens.timetable.bahnApi.repository.ScheduledFetchTaskRepository
|
import de.twomartens.timetable.bahnApi.repository.ScheduledFetchTaskRepository
|
||||||
import de.twomartens.timetable.model.db.TswRoute
|
import de.twomartens.timetable.model.db.TswRoute
|
||||||
import de.twomartens.timetable.support.model.LeadershipStatus
|
|
||||||
import de.twomartens.timetable.support.service.BusService
|
|
||||||
import de.twomartens.timetable.types.Hour
|
import de.twomartens.timetable.types.Hour
|
||||||
import de.twomartens.timetable.types.HourAtDay
|
import de.twomartens.timetable.types.HourAtDay
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
|
@ -27,7 +27,7 @@ class ScheduledTaskService(
|
||||||
private val leaderProperties: LeaderProperties,
|
private val leaderProperties: LeaderProperties,
|
||||||
private val scheduledFetchTaskRepository: ScheduledFetchTaskRepository,
|
private val scheduledFetchTaskRepository: ScheduledFetchTaskRepository,
|
||||||
private val taskFactory: TaskFactory,
|
private val taskFactory: TaskFactory,
|
||||||
private val taskScheduler: TaskScheduler
|
private val fetchTaskScheduler: FetchTaskScheduler
|
||||||
) {
|
) {
|
||||||
private var createdTime: Instant = Instant.EPOCH
|
private var createdTime: Instant = Instant.EPOCH
|
||||||
private var lastUpdate: Instant = Instant.EPOCH
|
private var lastUpdate: Instant = Instant.EPOCH
|
||||||
|
@ -81,8 +81,8 @@ class ScheduledTaskService(
|
||||||
fetchDates: FetchDates
|
fetchDates: FetchDates
|
||||||
): List<ScheduledFetchTask> {
|
): List<ScheduledFetchTask> {
|
||||||
val newTasks = mutableListOf<ScheduledFetchTask>()
|
val newTasks = mutableListOf<ScheduledFetchTask>()
|
||||||
tswRoute.stationIds.forEach {
|
tswRoute.stations.forEach {
|
||||||
val stationId = it
|
val stationId = it.id
|
||||||
val eva = Eva.of(stationId)
|
val eva = Eva.of(stationId)
|
||||||
var hourAtDay = HourAtDay.of(Hour.of(23), fetchDates.previousDay)
|
var hourAtDay = HourAtDay.of(Hour.of(23), fetchDates.previousDay)
|
||||||
var newTask = taskFactory.createTaskAndUpdateCounter(eva, hourAtDay)
|
var newTask = taskFactory.createTaskAndUpdateCounter(eva, hourAtDay)
|
||||||
|
@ -103,7 +103,7 @@ class ScheduledTaskService(
|
||||||
|
|
||||||
private fun scheduleTasksIfLeader(tasksToSchedule: List<ScheduledFetchTask>) {
|
private fun scheduleTasksIfLeader(tasksToSchedule: List<ScheduledFetchTask>) {
|
||||||
if (leadershipStatus.isLeader) {
|
if (leadershipStatus.isLeader) {
|
||||||
taskScheduler.scheduleFetchTasks(tasksToSchedule)
|
fetchTaskScheduler.scheduleFetchTasks(tasksToSchedule)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package de.twomartens.timetable.bahnApi.tasks
|
||||||
|
|
||||||
import de.twomartens.timetable.bahnApi.model.Eva
|
import de.twomartens.timetable.bahnApi.model.Eva
|
||||||
import de.twomartens.timetable.bahnApi.service.BahnApiService
|
import de.twomartens.timetable.bahnApi.service.BahnApiService
|
||||||
import de.twomartens.timetable.bahnApi.service.TaskScheduler
|
import de.twomartens.timetable.bahnApi.service.FetchTaskScheduler
|
||||||
import de.twomartens.timetable.types.HourAtDay
|
import de.twomartens.timetable.types.HourAtDay
|
||||||
import mu.KotlinLogging
|
import mu.KotlinLogging
|
||||||
import org.springframework.scheduling.annotation.Async
|
import org.springframework.scheduling.annotation.Async
|
||||||
|
@ -12,7 +12,7 @@ open class FetchTimetableTask(
|
||||||
private val eva: Eva,
|
private val eva: Eva,
|
||||||
private val hourAtDay: HourAtDay,
|
private val hourAtDay: HourAtDay,
|
||||||
private val bahnApiService: BahnApiService,
|
private val bahnApiService: BahnApiService,
|
||||||
private val scheduler: TaskScheduler) : Runnable {
|
private val scheduler: FetchTaskScheduler) : Runnable {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
log.info {
|
log.info {
|
||||||
"Fetch timetable: [eva: $eva], [date: ${hourAtDay.date}], [hour: ${hourAtDay.hour}]"
|
"Fetch timetable: [eva: $eva], [date: ${hourAtDay.date}], [hour: ${hourAtDay.hour}]"
|
|
@ -0,0 +1,11 @@
|
||||||
|
package de.twomartens.timetable.types
|
||||||
|
|
||||||
|
@JvmInline
|
||||||
|
value class Email private constructor(val value: String) {
|
||||||
|
companion object {
|
||||||
|
fun of(email: NonEmptyString): Email {
|
||||||
|
require(email.value.contains("@")) { "Invalid email format" }
|
||||||
|
return Email(email.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package de.twomartens.timetable.types
|
||||||
|
|
||||||
|
@JvmInline
|
||||||
|
value class ZeroOrPositiveInteger(val value: Int) {
|
||||||
|
init {
|
||||||
|
require(value >= 0) {
|
||||||
|
"Value must be zero or positive integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
plugins {
|
||||||
|
id("twomartens.spring-boot-base")
|
||||||
|
id("twomartens.kotlin")
|
||||||
|
kotlin("kapt")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":common"))
|
||||||
|
implementation(libs.spring.boot.mongo)
|
||||||
|
|
||||||
|
implementation(libs.mapstruct.base)
|
||||||
|
annotationProcessor(libs.mapstruct.processor)
|
||||||
|
kapt(libs.mapstruct.processor)
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package de.twomartens.timetable.model.common
|
||||||
|
|
||||||
|
import de.twomartens.timetable.types.ZeroOrPositiveInteger
|
||||||
|
|
||||||
|
@JvmInline
|
||||||
|
value class CoachCapacity(val capacity: ZeroOrPositiveInteger)
|
|
@ -0,0 +1,12 @@
|
||||||
|
package de.twomartens.timetable.model.common
|
||||||
|
|
||||||
|
import de.twomartens.timetable.types.NonEmptyString
|
||||||
|
|
||||||
|
@JvmInline
|
||||||
|
value class DepotId private constructor(val id: String) {
|
||||||
|
companion object {
|
||||||
|
fun of(id: NonEmptyString): DepotId {
|
||||||
|
return DepotId(id.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package de.twomartens.timetable.model.common
|
||||||
|
|
||||||
|
import de.twomartens.timetable.types.NonEmptyString
|
||||||
|
|
||||||
|
@JvmInline
|
||||||
|
value class FormationId private constructor(val id: String) {
|
||||||
|
companion object {
|
||||||
|
fun of(id: NonEmptyString): FormationId {
|
||||||
|
return FormationId(id.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package de.twomartens.timetable.model.common
|
||||||
|
|
||||||
|
import de.twomartens.timetable.types.NonEmptyString
|
||||||
|
|
||||||
|
@JvmInline
|
||||||
|
value class PortalId private constructor(val id: String) {
|
||||||
|
companion object {
|
||||||
|
fun of(id: NonEmptyString): PortalId {
|
||||||
|
return PortalId(id.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package de.twomartens.timetable.model.common
|
||||||
|
|
||||||
|
import de.twomartens.timetable.types.NonEmptyString
|
||||||
|
|
||||||
|
@JvmInline
|
||||||
|
value class RouteId private constructor(val id: String) {
|
||||||
|
companion object {
|
||||||
|
fun of(id: NonEmptyString): RouteId {
|
||||||
|
return RouteId(id.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,8 +2,7 @@ package de.twomartens.timetable.model.common
|
||||||
|
|
||||||
import de.twomartens.timetable.types.NonEmptyString
|
import de.twomartens.timetable.types.NonEmptyString
|
||||||
|
|
||||||
@JvmInline
|
class StationId private constructor(val value: String) {
|
||||||
value class StationId private constructor(val value: String) {
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val idPattern = Regex("^\\w{2}-(?<countryStationId>\\w.*)")
|
private val idPattern = Regex("^\\w{2}-(?<countryStationId>\\w.*)")
|
|
@ -0,0 +1,12 @@
|
||||||
|
package de.twomartens.timetable.model.common
|
||||||
|
|
||||||
|
import de.twomartens.timetable.types.NonEmptyString
|
||||||
|
|
||||||
|
@JvmInline
|
||||||
|
value class TimetableId private constructor(val value: String) {
|
||||||
|
companion object {
|
||||||
|
fun of(id: NonEmptyString): TimetableId {
|
||||||
|
return TimetableId(id.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package de.twomartens.timetable.model.db
|
||||||
|
|
||||||
|
import de.twomartens.timetable.model.common.DepotId
|
||||||
|
import de.twomartens.timetable.model.dto.Station
|
||||||
|
import de.twomartens.timetable.model.dto.Track
|
||||||
|
import de.twomartens.timetable.types.NonEmptyString
|
||||||
|
|
||||||
|
data class Depot(
|
||||||
|
val id: DepotId,
|
||||||
|
val name: NonEmptyString,
|
||||||
|
val nearestStation: Station,
|
||||||
|
val tracks: List<Track>,
|
||||||
|
val travelDurations: List<TravelDuration>
|
||||||
|
)
|
|
@ -3,6 +3,7 @@ package de.twomartens.timetable.model.db
|
||||||
import de.twomartens.timetable.model.common.FormationId
|
import de.twomartens.timetable.model.common.FormationId
|
||||||
import de.twomartens.timetable.model.common.UserId
|
import de.twomartens.timetable.model.common.UserId
|
||||||
import de.twomartens.timetable.types.NonEmptyString
|
import de.twomartens.timetable.types.NonEmptyString
|
||||||
|
import de.twomartens.timetable.types.ZeroOrPositiveInteger
|
||||||
import org.bson.types.ObjectId
|
import org.bson.types.ObjectId
|
||||||
import org.springframework.data.annotation.CreatedDate
|
import org.springframework.data.annotation.CreatedDate
|
||||||
import org.springframework.data.annotation.Id
|
import org.springframework.data.annotation.Id
|
||||||
|
@ -17,8 +18,9 @@ data class Formation(
|
||||||
var userId: UserId,
|
var userId: UserId,
|
||||||
var formationId: FormationId,
|
var formationId: FormationId,
|
||||||
var name: NonEmptyString,
|
var name: NonEmptyString,
|
||||||
var trainSimWorldFormationId: FormationId,
|
var trainSimWorldFormationId: FormationId?,
|
||||||
var coaches: List<NonEmptyString>
|
var formation: String,
|
||||||
|
var length: ZeroOrPositiveInteger
|
||||||
) {
|
) {
|
||||||
@Id
|
@Id
|
||||||
var id: ObjectId = ObjectId()
|
var id: ObjectId = ObjectId()
|
|
@ -0,0 +1,12 @@
|
||||||
|
package de.twomartens.timetable.model.db
|
||||||
|
|
||||||
|
import de.twomartens.timetable.model.common.PortalId
|
||||||
|
import de.twomartens.timetable.model.dto.Station
|
||||||
|
import de.twomartens.timetable.types.NonEmptyString
|
||||||
|
|
||||||
|
data class Portal(
|
||||||
|
val id: PortalId,
|
||||||
|
val name: NonEmptyString,
|
||||||
|
val nearestStation: Station,
|
||||||
|
val travelDurations: List<TravelDuration>
|
||||||
|
)
|
|
@ -1,6 +1,8 @@
|
||||||
package de.twomartens.timetable.model.db
|
package de.twomartens.timetable.model.db
|
||||||
|
|
||||||
import de.twomartens.timetable.model.common.*
|
import de.twomartens.timetable.model.common.CountryCode
|
||||||
|
import de.twomartens.timetable.model.common.Platform
|
||||||
|
import de.twomartens.timetable.model.common.StationId
|
||||||
import de.twomartens.timetable.types.NonEmptyString
|
import de.twomartens.timetable.types.NonEmptyString
|
||||||
import org.bson.types.ObjectId
|
import org.bson.types.ObjectId
|
||||||
import org.springframework.data.annotation.CreatedDate
|
import org.springframework.data.annotation.CreatedDate
|
||||||
|
@ -11,14 +13,12 @@ import org.springframework.data.mongodb.core.mapping.Document
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
@Document
|
@Document
|
||||||
@CompoundIndex(def = "{'userId': 1, 'name': 1}", unique = true)
|
@CompoundIndex(def = "{stationId: 1, countryCode: 1}", unique = true)
|
||||||
data class TswRoute(
|
data class Station(
|
||||||
var userId: UserId,
|
var stationId: StationId,
|
||||||
var name: NonEmptyString,
|
|
||||||
var countryCode: CountryCode,
|
var countryCode: CountryCode,
|
||||||
var stationIds: List<StationId>,
|
var name: NonEmptyString,
|
||||||
var portals: List<Portal>,
|
var platforms: List<Platform>
|
||||||
var depots: List<Depot>
|
|
||||||
) {
|
) {
|
||||||
@Id
|
@Id
|
||||||
var id: ObjectId = ObjectId()
|
var id: ObjectId = ObjectId()
|
|
@ -0,0 +1,39 @@
|
||||||
|
package de.twomartens.timetable.model.db
|
||||||
|
|
||||||
|
import de.twomartens.timetable.model.common.RouteId
|
||||||
|
import de.twomartens.timetable.model.common.TimetableId
|
||||||
|
import de.twomartens.timetable.model.common.UserId
|
||||||
|
import de.twomartens.timetable.model.dto.TimetableState
|
||||||
|
import de.twomartens.timetable.types.NonEmptyString
|
||||||
|
import de.twomartens.timetable.types.ZeroOrPositiveInteger
|
||||||
|
import org.bson.types.ObjectId
|
||||||
|
import org.springframework.data.annotation.CreatedDate
|
||||||
|
import org.springframework.data.annotation.Id
|
||||||
|
import org.springframework.data.annotation.LastModifiedDate
|
||||||
|
import org.springframework.data.mongodb.core.index.CompoundIndex
|
||||||
|
import org.springframework.data.mongodb.core.mapping.Document
|
||||||
|
import java.time.Instant
|
||||||
|
import java.time.LocalDate
|
||||||
|
|
||||||
|
@Document
|
||||||
|
@CompoundIndex(def = "{userId: 1, timetableId: 1}", unique = true)
|
||||||
|
@CompoundIndex(def = "{userId: 1, routeId: 1}")
|
||||||
|
data class Timetable(
|
||||||
|
var userId: UserId,
|
||||||
|
var routeId: RouteId,
|
||||||
|
var routeName: String,
|
||||||
|
var timetableId: TimetableId,
|
||||||
|
var name: NonEmptyString,
|
||||||
|
var fetchDate: LocalDate,
|
||||||
|
var timetableState: TimetableState,
|
||||||
|
var numberOfServices: ZeroOrPositiveInteger
|
||||||
|
) {
|
||||||
|
@Id
|
||||||
|
var id: ObjectId = ObjectId()
|
||||||
|
|
||||||
|
@CreatedDate
|
||||||
|
lateinit var created: Instant
|
||||||
|
|
||||||
|
@LastModifiedDate
|
||||||
|
lateinit var lastModified: Instant
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package de.twomartens.timetable.model.db
|
||||||
|
|
||||||
|
import de.twomartens.timetable.model.dto.Formation
|
||||||
|
|
||||||
|
data class TravelDuration(
|
||||||
|
val formation: Formation,
|
||||||
|
val time: Long
|
||||||
|
)
|
|
@ -0,0 +1,35 @@
|
||||||
|
package de.twomartens.timetable.model.db
|
||||||
|
|
||||||
|
import de.twomartens.timetable.model.common.RouteId
|
||||||
|
import de.twomartens.timetable.model.common.UserId
|
||||||
|
import de.twomartens.timetable.model.dto.Country
|
||||||
|
import de.twomartens.timetable.model.dto.Station
|
||||||
|
import de.twomartens.timetable.types.NonEmptyString
|
||||||
|
import org.bson.types.ObjectId
|
||||||
|
import org.springframework.data.annotation.CreatedDate
|
||||||
|
import org.springframework.data.annotation.Id
|
||||||
|
import org.springframework.data.annotation.LastModifiedDate
|
||||||
|
import org.springframework.data.mongodb.core.index.CompoundIndex
|
||||||
|
import org.springframework.data.mongodb.core.mapping.Document
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
@Document
|
||||||
|
@CompoundIndex(def = "{'userId': 1, 'name': 1}", unique = true)
|
||||||
|
data class TswRoute(
|
||||||
|
var userId: UserId,
|
||||||
|
var routeId: RouteId,
|
||||||
|
var name: NonEmptyString,
|
||||||
|
var country: Country,
|
||||||
|
var stations: List<Station>,
|
||||||
|
var depots: List<Depot>,
|
||||||
|
var portals: List<Portal>
|
||||||
|
) {
|
||||||
|
@Id
|
||||||
|
var id: ObjectId = ObjectId()
|
||||||
|
|
||||||
|
@CreatedDate
|
||||||
|
lateinit var created: Instant
|
||||||
|
|
||||||
|
@LastModifiedDate
|
||||||
|
lateinit var lastModified: Instant
|
||||||
|
}
|
|
@ -1,18 +1,21 @@
|
||||||
package de.twomartens.timetable.model.db
|
package de.twomartens.timetable.model.db
|
||||||
|
|
||||||
import de.twomartens.timetable.model.common.UserId
|
import de.twomartens.timetable.model.common.UserId
|
||||||
|
import de.twomartens.timetable.types.Email
|
||||||
import de.twomartens.timetable.types.NonEmptyString
|
import de.twomartens.timetable.types.NonEmptyString
|
||||||
import org.bson.types.ObjectId
|
import org.bson.types.ObjectId
|
||||||
import org.springframework.data.annotation.CreatedDate
|
import org.springframework.data.annotation.CreatedDate
|
||||||
import org.springframework.data.annotation.Id
|
import org.springframework.data.annotation.Id
|
||||||
import org.springframework.data.annotation.LastModifiedDate
|
import org.springframework.data.annotation.LastModifiedDate
|
||||||
|
import org.springframework.data.mongodb.core.index.Indexed
|
||||||
import org.springframework.data.mongodb.core.mapping.Document
|
import org.springframework.data.mongodb.core.mapping.Document
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
@Document
|
@Document
|
||||||
data class User(
|
data class User(
|
||||||
var userId: UserId,
|
@Indexed(unique = true) var userId: UserId,
|
||||||
var name: NonEmptyString
|
var name: NonEmptyString,
|
||||||
|
var email: Email
|
||||||
) {
|
) {
|
||||||
@Id
|
@Id
|
||||||
var id: ObjectId = ObjectId()
|
var id: ObjectId = ObjectId()
|
|
@ -1,14 +1,11 @@
|
||||||
package de.twomartens.timetable.model.dto
|
package de.twomartens.timetable.model.dto
|
||||||
|
|
||||||
import de.twomartens.timetable.model.common.FormationId
|
|
||||||
import de.twomartens.timetable.model.common.Line
|
|
||||||
import de.twomartens.timetable.model.common.ServiceId
|
|
||||||
import java.time.LocalTime
|
import java.time.LocalTime
|
||||||
|
|
||||||
data class AdditionalService(
|
data class AdditionalService(
|
||||||
val id: ServiceId,
|
val id: String,
|
||||||
val line: Line,
|
val line: String,
|
||||||
val formationId: FormationId,
|
val formationId: String,
|
||||||
val direction: Direction,
|
val direction: Direction,
|
||||||
val start: Station,
|
val start: Station,
|
||||||
val destination: Station,
|
val destination: Station,
|
|
@ -1,12 +1,11 @@
|
||||||
package de.twomartens.timetable.model.dto
|
package de.twomartens.timetable.model.dto
|
||||||
|
|
||||||
import de.twomartens.timetable.types.NonEmptyString
|
|
||||||
import java.time.LocalTime
|
import java.time.LocalTime
|
||||||
|
|
||||||
data class AdditionalServiceStop(
|
data class AdditionalServiceStop(
|
||||||
val stop: Station,
|
val stop: Station,
|
||||||
val arrivalTime: LocalTime,
|
val arrivalTime: LocalTime,
|
||||||
val departureTime: LocalTime,
|
val departureTime: LocalTime,
|
||||||
val platformAndSection: NonEmptyString,
|
val platformAndSection: String,
|
||||||
val loading: Boolean
|
val loading: Boolean
|
||||||
)
|
)
|
|
@ -0,0 +1,6 @@
|
||||||
|
package de.twomartens.timetable.model.dto
|
||||||
|
|
||||||
|
data class Country(
|
||||||
|
val code: String,
|
||||||
|
val name: String
|
||||||
|
)
|
|
@ -0,0 +1,9 @@
|
||||||
|
package de.twomartens.timetable.model.dto
|
||||||
|
|
||||||
|
data class Depot(
|
||||||
|
val id: String,
|
||||||
|
val name: String,
|
||||||
|
val nearestStation: Station,
|
||||||
|
val tracks: List<Track>,
|
||||||
|
val travelDurations: List<TravelDuration>
|
||||||
|
)
|
|
@ -0,0 +1,9 @@
|
||||||
|
package de.twomartens.timetable.model.dto
|
||||||
|
|
||||||
|
data class Formation(
|
||||||
|
val id: String,
|
||||||
|
val name: String,
|
||||||
|
val trainSimWorldFormation: Formation?,
|
||||||
|
val formation: String,
|
||||||
|
val length: Int
|
||||||
|
)
|
|
@ -0,0 +1,8 @@
|
||||||
|
package de.twomartens.timetable.model.dto
|
||||||
|
|
||||||
|
data class Portal(
|
||||||
|
val id: String,
|
||||||
|
val name: String,
|
||||||
|
val nearestStation: Station,
|
||||||
|
val travelDurations: List<TravelDuration>
|
||||||
|
)
|
|
@ -0,0 +1,11 @@
|
||||||
|
package de.twomartens.timetable.model.dto
|
||||||
|
|
||||||
|
import java.time.LocalTime
|
||||||
|
|
||||||
|
data class Rotation(
|
||||||
|
val id: String,
|
||||||
|
val formationId: String,
|
||||||
|
val firstServiceStartTime: LocalTime,
|
||||||
|
val lastServiceEndTime: LocalTime,
|
||||||
|
val startsInVault: Boolean
|
||||||
|
)
|
|
@ -0,0 +1,11 @@
|
||||||
|
package de.twomartens.timetable.model.dto
|
||||||
|
|
||||||
|
data class ServiceFormationStage(
|
||||||
|
val id: String,
|
||||||
|
val line: String,
|
||||||
|
val direction: Direction,
|
||||||
|
val formation: String,
|
||||||
|
val formationReversed: Boolean,
|
||||||
|
val startStop: ServiceStop,
|
||||||
|
val destinationStop: ServiceStop
|
||||||
|
)
|
|
@ -1,13 +1,9 @@
|
||||||
package de.twomartens.timetable.model.dto
|
package de.twomartens.timetable.model.dto
|
||||||
|
|
||||||
import de.twomartens.timetable.model.common.FormationId
|
|
||||||
import de.twomartens.timetable.model.common.Line
|
|
||||||
import de.twomartens.timetable.model.common.ServiceId
|
|
||||||
|
|
||||||
data class ServiceLinkingStage(
|
data class ServiceLinkingStage(
|
||||||
val id: ServiceId,
|
val id: String,
|
||||||
val formationId: FormationId,
|
val formationId: String,
|
||||||
val line: Line,
|
val line: String,
|
||||||
val direction: Direction,
|
val direction: Direction,
|
||||||
val formationReversed: Boolean,
|
val formationReversed: Boolean,
|
||||||
val startStop: ServiceStop,
|
val startStop: ServiceStop,
|
|
@ -0,0 +1,15 @@
|
||||||
|
package de.twomartens.timetable.model.dto
|
||||||
|
|
||||||
|
import de.twomartens.timetable.model.common.Line
|
||||||
|
import de.twomartens.timetable.model.common.ServiceId
|
||||||
|
|
||||||
|
data class ServiceRotationStage(
|
||||||
|
val id: ServiceId,
|
||||||
|
val line: Line,
|
||||||
|
val originStop: String,
|
||||||
|
val virtualDestinations: List<String>,
|
||||||
|
val startingFrom: String,
|
||||||
|
val endingIn: String,
|
||||||
|
val serviceStartTime: String,
|
||||||
|
val stops: List<ServiceStop>
|
||||||
|
)
|
|
@ -1,11 +1,9 @@
|
||||||
package de.twomartens.timetable.model.dto
|
package de.twomartens.timetable.model.dto
|
||||||
|
|
||||||
import de.twomartens.timetable.types.NonEmptyString
|
|
||||||
|
|
||||||
data class ServiceStop(
|
data class ServiceStop(
|
||||||
val stop: Station,
|
val stop: Station,
|
||||||
val arrivalTime: String,
|
val arrivalTime: String,
|
||||||
val departureTime: String,
|
val departureTime: String,
|
||||||
val platform: NonEmptyString,
|
val platform: String,
|
||||||
val section: String
|
val section: String
|
||||||
)
|
)
|
|
@ -0,0 +1,9 @@
|
||||||
|
package de.twomartens.timetable.model.dto
|
||||||
|
|
||||||
|
import de.twomartens.timetable.model.common.Platform
|
||||||
|
|
||||||
|
data class Station(
|
||||||
|
val id: String,
|
||||||
|
val name: String,
|
||||||
|
val platforms: List<Platform>
|
||||||
|
)
|
|
@ -0,0 +1,13 @@
|
||||||
|
package de.twomartens.timetable.model.dto
|
||||||
|
|
||||||
|
import java.time.LocalDate
|
||||||
|
|
||||||
|
data class Timetable(
|
||||||
|
val id: String,
|
||||||
|
val name: String,
|
||||||
|
val routeId: String,
|
||||||
|
val routeName: String,
|
||||||
|
val date: LocalDate,
|
||||||
|
val state: TimetableState,
|
||||||
|
val numberOfServices: Int
|
||||||
|
)
|
|
@ -0,0 +1,7 @@
|
||||||
|
package de.twomartens.timetable.model.dto
|
||||||
|
|
||||||
|
data class Track(
|
||||||
|
val id: Int,
|
||||||
|
val name: String,
|
||||||
|
val capacity: Int
|
||||||
|
)
|
|
@ -0,0 +1,6 @@
|
||||||
|
package de.twomartens.timetable.model.dto
|
||||||
|
|
||||||
|
data class TravelDuration(
|
||||||
|
val formation: Formation,
|
||||||
|
val time: Long
|
||||||
|
)
|
|
@ -0,0 +1,13 @@
|
||||||
|
package de.twomartens.timetable.model.dto
|
||||||
|
|
||||||
|
data class TswRoute(
|
||||||
|
val id: String,
|
||||||
|
val name: String,
|
||||||
|
val country: Country,
|
||||||
|
val stations: List<Station>,
|
||||||
|
val firstStation: Station,
|
||||||
|
val lastStation: Station,
|
||||||
|
val numberOfStations: Int,
|
||||||
|
val depots: List<Depot>,
|
||||||
|
val portals: List<Portal>
|
||||||
|
)
|
|
@ -0,0 +1,7 @@
|
||||||
|
package de.twomartens.timetable.model.dto
|
||||||
|
|
||||||
|
data class User(
|
||||||
|
val id: String,
|
||||||
|
val name: String,
|
||||||
|
val email: String
|
||||||
|
)
|
|
@ -0,0 +1,36 @@
|
||||||
|
package de.twomartens.timetable.model.mapper
|
||||||
|
|
||||||
|
import de.twomartens.timetable.model.common.CountryCode
|
||||||
|
import de.twomartens.timetable.model.common.StationId
|
||||||
|
import de.twomartens.timetable.model.dto.Station
|
||||||
|
import de.twomartens.timetable.types.NonEmptyString
|
||||||
|
import org.mapstruct.*
|
||||||
|
|
||||||
|
@Mapper(
|
||||||
|
collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED,
|
||||||
|
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
|
||||||
|
unmappedTargetPolicy = ReportingPolicy.IGNORE
|
||||||
|
)
|
||||||
|
interface StationMapper {
|
||||||
|
@Mapping(target = "id", ignore = true)
|
||||||
|
@Mapping(target = "created", ignore = true)
|
||||||
|
@Mapping(target = "lastModified", ignore = true)
|
||||||
|
fun mapToDB(countryCode: CountryCode, dto: Station): de.twomartens.timetable.model.db.Station {
|
||||||
|
return de.twomartens.timetable.model.db.Station(
|
||||||
|
StationId.of(NonEmptyString(countryCode.countryCode.value + "-" + dto.id)),
|
||||||
|
countryCode,
|
||||||
|
NonEmptyString(dto.name),
|
||||||
|
dto.platforms
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mapStationsToDto(stations: List<de.twomartens.timetable.model.db.Station>): List<Station>
|
||||||
|
|
||||||
|
fun mapToDto(db: de.twomartens.timetable.model.db.Station): Station {
|
||||||
|
return Station(
|
||||||
|
db.stationId.stationIdWithinCountry,
|
||||||
|
db.name.value,
|
||||||
|
db.platforms
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package de.twomartens.timetable.model.repository
|
||||||
|
|
||||||
|
import de.twomartens.timetable.model.common.StationId
|
||||||
|
import de.twomartens.timetable.model.db.Station
|
||||||
|
import org.bson.types.ObjectId
|
||||||
|
import org.springframework.data.mongodb.repository.Aggregation
|
||||||
|
import org.springframework.data.mongodb.repository.MongoRepository
|
||||||
|
|
||||||
|
interface StationRepository : MongoRepository<Station, ObjectId> {
|
||||||
|
fun findByCountryCodeAndStationId(countryCode: String, stationId: StationId): Station?
|
||||||
|
fun findAllByCountryCode(countryCode: String): List<Station>
|
||||||
|
|
||||||
|
@Aggregation(pipeline = [
|
||||||
|
"{\$search: { index: \"stations\", returnStoredSource: true, compound: {must: [{phrase: {query: ?0, path: \"countryCode\"}},{autocomplete: {query: ?1,path: \"name\",tokenOrder: \"sequential\"}}]}}}",
|
||||||
|
"{\$limit: 10}",
|
||||||
|
"{\$lookup: { from: \"station\", localField: \"_id\", foreignField: \"_id\", as: \"document\" }}",
|
||||||
|
"{\$unwind: \"\$document\"}",
|
||||||
|
"{\$replaceWith: \"\$document\"}"
|
||||||
|
])
|
||||||
|
fun findAllByCountryCodeAndNameContainingIgnoreCase(countryCode: String, name: String): List<Station>
|
||||||
|
|
||||||
|
@Aggregation(pipeline = [
|
||||||
|
"{\$search: { index: \"stations\", returnStoredSource: true, autocomplete: {query: ?0, path: \"name\",tokenOrder: \"sequential\"}}}",
|
||||||
|
"{\$limit: 10}",
|
||||||
|
"{\$lookup: { from: \"station\", localField: \"_id\", foreignField: \"_id\", as: \"document\" }}",
|
||||||
|
"{\$unwind: \"\$document\"}",
|
||||||
|
"{\$replaceWith: \"\$document\"}"
|
||||||
|
])
|
||||||
|
fun findAllByNameContainingIgnoreCase(name: String): List<Station>
|
||||||
|
}
|
|
@ -1,17 +1,23 @@
|
||||||
plugins {
|
plugins {
|
||||||
id("twomartens.spring-boot-cloud")
|
id("twomartens.spring-boot-cloud-application")
|
||||||
id("twomartens.kotlin")
|
id("twomartens.kotlin")
|
||||||
kotlin("kapt")
|
kotlin("kapt")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(project(":bahnApi"))
|
||||||
implementation(project(":common"))
|
implementation(project(":common"))
|
||||||
implementation(libs.mapstruct.base)
|
implementation(project(":model"))
|
||||||
implementation(libs.bundles.spring.boot.security)
|
implementation(project(":support"))
|
||||||
|
|
||||||
implementation(libs.jaxb.impl)
|
implementation(libs.jaxb.impl)
|
||||||
implementation(libs.jakarta.xml.binding)
|
implementation(libs.jakarta.xml.binding)
|
||||||
|
|
||||||
|
implementation(libs.mapstruct.base)
|
||||||
annotationProcessor(libs.mapstruct.processor)
|
annotationProcessor(libs.mapstruct.processor)
|
||||||
kapt(libs.mapstruct.processor)
|
kapt(libs.mapstruct.processor)
|
||||||
|
|
||||||
|
implementation(libs.bundles.spring.boot.security)
|
||||||
implementation(libs.spring.cloud.starter.config)
|
implementation(libs.spring.cloud.starter.config)
|
||||||
implementation(libs.spring.cloud.leader.election)
|
implementation(libs.spring.cloud.leader.election)
|
||||||
implementation(libs.spring.cloud.starter.bus.kafka)
|
implementation(libs.spring.cloud.starter.bus.kafka)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package de.twomartens.timetable
|
package de.twomartens.timetable
|
||||||
|
|
||||||
import de.twomartens.timetable.support.model.LeadershipStatus
|
import de.twomartens.support.model.LeadershipStatus
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||||
import org.springframework.boot.context.event.ApplicationReadyEvent
|
import org.springframework.boot.context.event.ApplicationReadyEvent
|
||||||
import org.springframework.boot.runApplication
|
import org.springframework.boot.runApplication
|
||||||
|
@ -13,7 +13,7 @@ import org.springframework.scheduling.annotation.EnableScheduling
|
||||||
|
|
||||||
@EnableMongoAuditing
|
@EnableMongoAuditing
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
@SpringBootApplication
|
@SpringBootApplication(scanBasePackages = ["de.twomartens.support", "de.twomartens.timetable"])
|
||||||
open class MainApplication(
|
open class MainApplication(
|
||||||
private val leadershipStatus: LeadershipStatus,
|
private val leadershipStatus: LeadershipStatus,
|
||||||
private val leaderProperties: LeaderProperties
|
private val leaderProperties: LeaderProperties
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
package de.twomartens.timetable.auth
|
||||||
|
|
||||||
|
import de.twomartens.timetable.model.common.UserId
|
||||||
|
import de.twomartens.timetable.model.dto.User
|
||||||
|
import de.twomartens.timetable.types.Email
|
||||||
|
import de.twomartens.timetable.types.NonEmptyString
|
||||||
|
import io.swagger.v3.oas.annotations.Operation
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter
|
||||||
|
import io.swagger.v3.oas.annotations.media.Content
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponse
|
||||||
|
import io.swagger.v3.oas.annotations.security.SecurityRequirement
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag
|
||||||
|
import org.mapstruct.factory.Mappers
|
||||||
|
import org.springframework.http.HttpStatus
|
||||||
|
import org.springframework.http.ResponseEntity
|
||||||
|
import org.springframework.web.bind.annotation.*
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping(value = ["/v1/users"])
|
||||||
|
@Tag(name = "Users", description = "all requests relating to user resources")
|
||||||
|
class UserController(
|
||||||
|
private val userRepository: UserRepository
|
||||||
|
) {
|
||||||
|
|
||||||
|
private val mapper = Mappers.getMapper(UserMapper::class.java)
|
||||||
|
|
||||||
|
@Operation(
|
||||||
|
summary = "Store user",
|
||||||
|
responses = [ApiResponse(
|
||||||
|
responseCode = "200",
|
||||||
|
description = "User was updated",
|
||||||
|
content = [Content(
|
||||||
|
schema = Schema(implementation = User::class)
|
||||||
|
)]
|
||||||
|
), ApiResponse(
|
||||||
|
responseCode = "201",
|
||||||
|
description = "User was created",
|
||||||
|
content = [Content(
|
||||||
|
schema = Schema(implementation = User::class)
|
||||||
|
)]
|
||||||
|
), ApiResponse(
|
||||||
|
responseCode = "403",
|
||||||
|
description = "Access forbidden for user",
|
||||||
|
content = [Content(mediaType = "text/plain")]
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
@SecurityRequirement(name = "bearer")
|
||||||
|
@SecurityRequirement(name = "oauth2")
|
||||||
|
@PutMapping("/{userId}")
|
||||||
|
fun putUser(
|
||||||
|
@PathVariable @Parameter(description = "The id of the user",
|
||||||
|
example = "1",
|
||||||
|
required = true) userId: String,
|
||||||
|
@RequestBody(required = true) @io.swagger.v3.oas.annotations.parameters.RequestBody(
|
||||||
|
required = true,
|
||||||
|
content = [
|
||||||
|
Content(
|
||||||
|
schema = Schema(implementation = User::class)
|
||||||
|
)
|
||||||
|
]) body: User
|
||||||
|
): ResponseEntity<User> {
|
||||||
|
var created = false
|
||||||
|
|
||||||
|
val userIdConverted = UserId.of(NonEmptyString(userId))
|
||||||
|
var user = userRepository.findByUserId(userIdConverted)
|
||||||
|
if (user == null) {
|
||||||
|
created = true
|
||||||
|
user = mapper.mapToDB(body)
|
||||||
|
} else {
|
||||||
|
user.name = NonEmptyString(body.name)
|
||||||
|
user.email = Email.of(NonEmptyString(body.email))
|
||||||
|
}
|
||||||
|
|
||||||
|
userRepository.save(user)
|
||||||
|
|
||||||
|
val updatedUser = mapper.mapToDto(user)
|
||||||
|
return if (created) {
|
||||||
|
ResponseEntity.status(HttpStatus.CREATED).body(updatedUser)
|
||||||
|
} else {
|
||||||
|
ResponseEntity.ok(updatedUser)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package de.twomartens.timetable.auth
|
||||||
|
|
||||||
|
import de.twomartens.timetable.model.common.UserId
|
||||||
|
import de.twomartens.timetable.model.dto.User
|
||||||
|
import de.twomartens.timetable.types.Email
|
||||||
|
import de.twomartens.timetable.types.NonEmptyString
|
||||||
|
import org.mapstruct.*
|
||||||
|
|
||||||
|
@Mapper(
|
||||||
|
collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED,
|
||||||
|
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
|
||||||
|
unmappedTargetPolicy = ReportingPolicy.IGNORE
|
||||||
|
)
|
||||||
|
interface UserMapper {
|
||||||
|
|
||||||
|
@Mapping(target = "id", ignore = true)
|
||||||
|
@Mapping(target = "created", ignore = true)
|
||||||
|
@Mapping(target = "lastModified", ignore = true)
|
||||||
|
fun mapToDB(dto: User): de.twomartens.timetable.model.db.User {
|
||||||
|
return de.twomartens.timetable.model.db.User(
|
||||||
|
UserId.of(NonEmptyString(dto.id)),
|
||||||
|
NonEmptyString(dto.name),
|
||||||
|
Email.of(NonEmptyString(dto.email))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun mapToDto(db: de.twomartens.timetable.model.db.User): User {
|
||||||
|
return User(
|
||||||
|
db.userId.value,
|
||||||
|
db.name.value,
|
||||||
|
db.email.value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package de.twomartens.timetable.auth
|
||||||
|
|
||||||
|
import de.twomartens.timetable.model.common.UserId
|
||||||
|
import de.twomartens.timetable.model.db.User
|
||||||
|
import org.bson.types.ObjectId
|
||||||
|
import org.springframework.data.mongodb.repository.MongoRepository
|
||||||
|
|
||||||
|
interface UserRepository : MongoRepository<User, ObjectId> {
|
||||||
|
fun existsByUserId(userId: UserId): Boolean
|
||||||
|
fun findByUserId(userId: UserId): User?
|
||||||
|
}
|
|
@ -1,58 +0,0 @@
|
||||||
package de.twomartens.timetable.bahnApi.service
|
|
||||||
|
|
||||||
import de.twomartens.timetable.bahnApi.model.Eva
|
|
||||||
import de.twomartens.timetable.bahnApi.model.dto.BahnStation
|
|
||||||
import de.twomartens.timetable.bahnApi.model.dto.BahnStations
|
|
||||||
import de.twomartens.timetable.bahnApi.model.dto.BahnTimetable
|
|
||||||
import de.twomartens.timetable.bahnApi.property.BahnApiProperties
|
|
||||||
import de.twomartens.timetable.types.HourAtDay
|
|
||||||
import org.springframework.http.HttpEntity
|
|
||||||
import org.springframework.http.HttpHeaders
|
|
||||||
import org.springframework.http.HttpMethod
|
|
||||||
import org.springframework.http.MediaType
|
|
||||||
import org.springframework.stereotype.Service
|
|
||||||
import org.springframework.web.client.RestTemplate
|
|
||||||
import java.time.LocalTime
|
|
||||||
import java.time.format.DateTimeFormatter
|
|
||||||
|
|
||||||
@Service
|
|
||||||
class BahnApiService(
|
|
||||||
private val restTemplate: RestTemplate,
|
|
||||||
private val properties: BahnApiProperties
|
|
||||||
) {
|
|
||||||
fun fetchStations(pattern: String): List<BahnStation> {
|
|
||||||
val requestEntity = buildRequestEntity<BahnStations>()
|
|
||||||
val response = restTemplate.exchange(
|
|
||||||
"https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/station/${pattern}",
|
|
||||||
HttpMethod.GET,
|
|
||||||
requestEntity,
|
|
||||||
BahnStations::class.java
|
|
||||||
)
|
|
||||||
val body = response.body
|
|
||||||
return body?.stations ?: listOf()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun fetchTimetable(eva: Eva, hourAtDay: HourAtDay): BahnTimetable {
|
|
||||||
val requestEntity = buildRequestEntity<BahnTimetable>()
|
|
||||||
val dateFormatter = DateTimeFormatter.ofPattern("yyMMdd")
|
|
||||||
val timeFormatter = DateTimeFormatter.ofPattern("HH")
|
|
||||||
val time = LocalTime.of(hourAtDay.hour.value, 0)
|
|
||||||
val response = restTemplate.exchange(
|
|
||||||
"https://apis.deutschebahn.com/db-api-marketplace/apis/timetables/v1/plan/" +
|
|
||||||
"${eva}/${hourAtDay.date.format(dateFormatter)}/${time.format(timeFormatter)}",
|
|
||||||
HttpMethod.GET,
|
|
||||||
requestEntity,
|
|
||||||
BahnTimetable::class.java
|
|
||||||
)
|
|
||||||
return response.body!!
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <T> buildRequestEntity(): HttpEntity<T> {
|
|
||||||
val headers = HttpHeaders()
|
|
||||||
headers.accept = mutableListOf(MediaType.APPLICATION_XML)
|
|
||||||
headers.contentType = MediaType.APPLICATION_XML
|
|
||||||
headers.set("DB-Client-Id", properties.clientId)
|
|
||||||
headers.set("DB-Api-Key", properties.clientSecret)
|
|
||||||
return HttpEntity<T>(headers)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
package de.twomartens.timetable.bahnApi.service
|
|
||||||
|
|
||||||
import de.twomartens.timetable.bahnApi.mapper.BahnStationMapper
|
|
||||||
import de.twomartens.timetable.bahnApi.mapper.BahnTimetableMapper
|
|
||||||
import de.twomartens.timetable.bahnApi.model.dto.BahnStation
|
|
||||||
import de.twomartens.timetable.bahnApi.model.dto.BahnTimetable
|
|
||||||
import de.twomartens.timetable.bahnApi.repository.BahnStationRepository
|
|
||||||
import de.twomartens.timetable.bahnApi.repository.BahnTimetableRepository
|
|
||||||
import de.twomartens.timetable.types.HourAtDay
|
|
||||||
import org.mapstruct.factory.Mappers
|
|
||||||
import org.springframework.stereotype.Service
|
|
||||||
|
|
||||||
@Service
|
|
||||||
class BahnDatabaseService(
|
|
||||||
private val bahnStationRepository: BahnStationRepository,
|
|
||||||
private val bahnTimetableRepository: BahnTimetableRepository
|
|
||||||
) {
|
|
||||||
private val bahnStationMapper = Mappers.getMapper(BahnStationMapper::class.java)
|
|
||||||
private val bahnTimetableMapper = Mappers.getMapper(BahnTimetableMapper::class.java)
|
|
||||||
|
|
||||||
fun storeStations(stations: List<BahnStation>) {
|
|
||||||
bahnStationRepository.saveAll(stations
|
|
||||||
.map { bahnStationMapper.mapToDB(it) })
|
|
||||||
}
|
|
||||||
|
|
||||||
fun storeTimetable(timetable: BahnTimetable, hourAtDay: HourAtDay) {
|
|
||||||
bahnTimetableRepository.save(bahnTimetableMapper.mapToDB(timetable, hourAtDay))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +1,8 @@
|
||||||
package de.twomartens.timetable.support.configuration
|
package de.twomartens.timetable.configuration
|
||||||
|
|
||||||
import org.springframework.cloud.bus.jackson.RemoteApplicationEventScan
|
import org.springframework.cloud.bus.jackson.RemoteApplicationEventScan
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@RemoteApplicationEventScan(basePackages = ["de.twomartens.timetable"])
|
@RemoteApplicationEventScan(basePackages = ["de.twomartens.timetable", "de.twomartens.support"])
|
||||||
open class BusConfiguration
|
open class BusConfiguration
|
|
@ -1,4 +1,4 @@
|
||||||
package de.twomartens.timetable.support.configuration
|
package de.twomartens.timetable.configuration
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType
|
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType
|
||||||
import io.swagger.v3.oas.annotations.security.OAuthFlow
|
import io.swagger.v3.oas.annotations.security.OAuthFlow
|
|
@ -1,10 +1,11 @@
|
||||||
package de.twomartens.timetable.configuration
|
package de.twomartens.timetable.configuration
|
||||||
|
|
||||||
|
import de.twomartens.support.property.HealthCheckProperties
|
||||||
|
import de.twomartens.support.property.RestTemplateTimeoutProperties
|
||||||
|
import de.twomartens.support.property.StatusProbeProperties
|
||||||
|
import de.twomartens.support.property.TimeProperties
|
||||||
import de.twomartens.timetable.bahnApi.property.BahnApiProperties
|
import de.twomartens.timetable.bahnApi.property.BahnApiProperties
|
||||||
import de.twomartens.timetable.property.RestTemplateTimeoutProperties
|
|
||||||
import de.twomartens.timetable.property.ServiceProperties
|
import de.twomartens.timetable.property.ServiceProperties
|
||||||
import de.twomartens.timetable.property.StatusProbeProperties
|
|
||||||
import de.twomartens.timetable.property.TimeProperties
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties
|
import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||||
import org.springframework.cloud.kubernetes.commons.leader.LeaderProperties
|
import org.springframework.cloud.kubernetes.commons.leader.LeaderProperties
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
|
@ -12,5 +13,6 @@ import org.springframework.context.annotation.Configuration
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableConfigurationProperties(RestTemplateTimeoutProperties::class, ServiceProperties::class,
|
@EnableConfigurationProperties(RestTemplateTimeoutProperties::class, ServiceProperties::class,
|
||||||
StatusProbeProperties::class, TimeProperties::class, BahnApiProperties::class,
|
StatusProbeProperties::class, TimeProperties::class, BahnApiProperties::class,
|
||||||
|
HealthCheckProperties::class,
|
||||||
LeaderProperties::class)
|
LeaderProperties::class)
|
||||||
open class PropertyConfiguration
|
open class PropertyConfiguration
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package de.twomartens.timetable.support.configuration
|
package de.twomartens.timetable.configuration
|
||||||
|
|
||||||
import de.twomartens.timetable.support.interceptor.HeaderInterceptorRest
|
import de.twomartens.support.interceptor.HeaderInterceptorRest
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
import org.springframework.http.HttpMethod
|
import org.springframework.http.HttpMethod
|
||||||
import org.springframework.web.servlet.config.annotation.CorsRegistry
|
import org.springframework.web.servlet.config.annotation.CorsRegistry
|
||||||
|
@ -17,7 +17,8 @@ open class WebConfiguration(private val headerInterceptorRest: HeaderInterceptor
|
||||||
val registration = registry.addMapping("/**")
|
val registration = registry.addMapping("/**")
|
||||||
registration.allowedMethods(
|
registration.allowedMethods(
|
||||||
HttpMethod.GET.name(), HttpMethod.POST.name(),
|
HttpMethod.GET.name(), HttpMethod.POST.name(),
|
||||||
HttpMethod.PUT.name(), HttpMethod.HEAD.name()
|
HttpMethod.PUT.name(), HttpMethod.HEAD.name(),
|
||||||
|
HttpMethod.DELETE.name()
|
||||||
)
|
)
|
||||||
registration.allowCredentials(true)
|
registration.allowCredentials(true)
|
||||||
registration.allowedOrigins(
|
registration.allowedOrigins(
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue