Merge branch 'database-manager-integration' into 'master'
Resolve "Ajouter un système pour détecter et mettre à jour la base de données" Closes #32 See merge request color-recipes-explorer/backend!6
This commit is contained in:
commit
ce8ed98fd4
|
@ -8,7 +8,7 @@
|
|||
gradle/
|
||||
build/
|
||||
logs/
|
||||
workdir/
|
||||
data/
|
||||
dokka/
|
||||
dist/
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ dependencies {
|
|||
implementation("org.apache.pdfbox:pdfbox:2.0.4")
|
||||
implementation("com.atlassian.commonmark:commonmark:0.13.1")
|
||||
implementation("commons-io:commons-io:2.6")
|
||||
implementation("dev.fyloz.colorrecipesexplorer:database-manager:1.0.1")
|
||||
|
||||
implementation("org.springframework.boot:spring-boot-starter-data-jpa:2.3.4.RELEASE")
|
||||
implementation("org.springframework.boot:spring-boot-starter-jdbc:2.3.4.RELEASE")
|
||||
|
@ -54,7 +55,6 @@ dependencies {
|
|||
runtimeOnly("org.postgresql:postgresql:42.2.16")
|
||||
runtimeOnly("com.microsoft.sqlserver:mssql-jdbc:9.2.1.jre11")
|
||||
|
||||
|
||||
compileOnly("org.projectlombok:lombok:1.18.10")
|
||||
}
|
||||
|
||||
|
|
|
@ -2,19 +2,20 @@ package dev.fyloz.trial.colorrecipesexplorer
|
|||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.config.properties.CREProperties
|
||||
import dev.fyloz.trial.colorrecipesexplorer.config.properties.MaterialTypeProperties
|
||||
import dev.fyloz.trial.colorrecipesexplorer.repository.MaterialTypeRepository
|
||||
import dev.fyloz.trial.colorrecipesexplorer.repository.NamedJpaRepository
|
||||
import org.slf4j.Logger
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder
|
||||
import org.springframework.boot.runApplication
|
||||
import org.springframework.context.annotation.ComponentScan
|
||||
import org.springframework.context.annotation.FilterType
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
|
||||
import org.springframework.context.annotation.Bean
|
||||
import javax.sql.DataSource
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableConfigurationProperties(MaterialTypeProperties::class, CREProperties::class)
|
||||
@SpringBootApplication(exclude = [LiquibaseAutoConfiguration::class])
|
||||
@EnableConfigurationProperties(MaterialTypeProperties::class, CREProperties::class, DatabaseUpdaterProperties::class)
|
||||
class ColorRecipesExplorerApplication
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
runApplication<ColorRecipesExplorerApplication>(*args)
|
||||
runApplication<ColorRecipesExplorerApplication>()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer
|
||||
|
||||
import dev.fyloz.colorrecipesexplorer.databasemanager.CreDatabase
|
||||
import dev.fyloz.colorrecipesexplorer.databasemanager.databaseContext
|
||||
import dev.fyloz.colorrecipesexplorer.databasemanager.databaseUpdaterProperties
|
||||
import org.slf4j.Logger
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.core.env.Environment
|
||||
import javax.sql.DataSource
|
||||
|
||||
const val SUPPORTED_DATABASE_VERSION = 2
|
||||
const val ENV_VAR_ENABLE_DATABASE_UPDATE_NAME = "CRE_ENABLE_DB_UPDATE"
|
||||
val DATABASE_NAME_REGEX = Regex("(\\w+)$")
|
||||
|
||||
@Configuration
|
||||
class DataSourceConfiguration {
|
||||
@Bean(name = ["dataSource"])
|
||||
@ConfigurationProperties(prefix = "spring.datasource")
|
||||
fun customDataSource(
|
||||
logger: Logger,
|
||||
environment: Environment,
|
||||
databaseUpdaterProperties: DatabaseUpdaterProperties
|
||||
): DataSource {
|
||||
val databaseUrl: String = environment.getProperty("spring.datasource.url")!!
|
||||
|
||||
runDatabaseVersionCheck(logger, databaseUrl, databaseUpdaterProperties)
|
||||
|
||||
return DataSourceBuilder
|
||||
.create()
|
||||
.url(databaseUrl) // Hikari won't start without that
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a database version check. If the database's version is not supported and the environment variable 'CRE_ENABLE_DB_UPDATE' is:
|
||||
* - 1: The database will be updated.
|
||||
* - Any other value: The application will not start.
|
||||
*/
|
||||
fun runDatabaseVersionCheck(logger: Logger, databaseUrl: String, databaseUpdaterProperties: DatabaseUpdaterProperties) {
|
||||
logger.info("Verifying database's version before starting...")
|
||||
|
||||
if (":h2:" in databaseUrl) {
|
||||
logger.warn("H2 is not supported by the database manager")
|
||||
return
|
||||
}
|
||||
|
||||
val databaseUpdateEnabled = System.getenv(ENV_VAR_ENABLE_DATABASE_UPDATE_NAME) == "1"
|
||||
val database = getDatabase(databaseUrl, databaseUpdaterProperties, logger)
|
||||
val version = database.version
|
||||
|
||||
if (version != SUPPORTED_DATABASE_VERSION) {
|
||||
if (!databaseUpdateEnabled) {
|
||||
database.close()
|
||||
throwUnsupportedDatabaseVersion(version, logger)
|
||||
} else runDatabaseUpdate(logger, database)
|
||||
} else {
|
||||
logger.info("The database is up to date!")
|
||||
|
||||
if (databaseUpdateEnabled) {
|
||||
logger.warn("The database is up to date but the environment variable '$ENV_VAR_ENABLE_DATABASE_UPDATE_NAME' is set to '1'. Set it to '0' to prevent any possible data loss.")
|
||||
}
|
||||
}
|
||||
|
||||
database.close()
|
||||
}
|
||||
|
||||
/** Updates the given [database]. */
|
||||
fun runDatabaseUpdate(logger: Logger, database: CreDatabase) {
|
||||
logger.info("The environment variable '$ENV_VAR_ENABLE_DATABASE_UPDATE_NAME' is set to '1'; The database will be updated.")
|
||||
database.update()
|
||||
}
|
||||
|
||||
fun getDatabase(
|
||||
databaseUrl: String,
|
||||
databaseUpdaterProperties: DatabaseUpdaterProperties,
|
||||
logger: Logger
|
||||
): CreDatabase {
|
||||
val databaseName =
|
||||
(DATABASE_NAME_REGEX.find(databaseUrl) ?: throw DatabaseVersioningException.InvalidUrl(databaseUrl)).value
|
||||
|
||||
return CreDatabase(
|
||||
databaseContext(
|
||||
properties = databaseUpdaterProperties(
|
||||
targetVersion = SUPPORTED_DATABASE_VERSION,
|
||||
url = databaseUrl.removeSuffix(databaseName),
|
||||
dbName = databaseName,
|
||||
username = databaseUpdaterProperties.username,
|
||||
password = databaseUpdaterProperties.password
|
||||
),
|
||||
logger
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun throwUnsupportedDatabaseVersion(version: Int, logger: Logger) {
|
||||
if (version > SUPPORTED_DATABASE_VERSION) {
|
||||
logger.error("Version $version of the database is not supported; Only version $SUPPORTED_DATABASE_VERSION is currently supported; Update this application to use the database.")
|
||||
} else {
|
||||
logger.error(
|
||||
"""Version $version of the database is not supported; Only version $SUPPORTED_DATABASE_VERSION is currently supported.
|
||||
|You can update the database to the supported version by either:
|
||||
| - Setting the environment variable '$ENV_VAR_ENABLE_DATABASE_UPDATE_NAME' to '1' to update the database automatically
|
||||
| - Updating the database manually with the database manager utility (https://git.fyloz.dev/color-recipes-explorer/database-manager)
|
||||
|
|
||||
|Don't forget to backup the database before upgrading to prevent any data loss.
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
throw DatabaseVersioningException.UnsupportedDatabaseVersion(version)
|
||||
}
|
||||
|
||||
@ConfigurationProperties(prefix = "database-updater")
|
||||
class DatabaseUpdaterProperties {
|
||||
var username: String = ""
|
||||
var password: String = ""
|
||||
}
|
||||
|
||||
sealed class DatabaseVersioningException(message: String) : Exception(message) {
|
||||
class InvalidUrl(url: String) : DatabaseVersioningException("Invalid database url: $url")
|
||||
class UnsupportedDatabaseVersion(version: Int) :
|
||||
DatabaseVersioningException("Unsupported database version: $version; Only version $SUPPORTED_DATABASE_VERSION is currently supported")
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
spring.datasource.url=jdbc:h2:mem:cre
|
||||
#spring.datasource.url=jdbc:h2:file:./workdir/recipes
|
||||
spring.datasource.username=sa
|
||||
spring.datasource.password=LWK4Y7TvEbNyhu1yCoG3
|
||||
spring.datasource.password=password
|
||||
spring.jpa.hibernate.ddl-auto=update
|
||||
spring.h2.console.path=/dbconsole
|
||||
spring.h2.console.enabled=true
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
spring.datasource.url=jdbc:mysql://172.20.0.2/cre
|
||||
spring.datasource.url=jdbc:mysql://172.66.1.1/cre
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=pass
|
||||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# PORT
|
||||
server.port=9090
|
||||
# CRE
|
||||
cre.server.upload-directory=./workdir
|
||||
cre.server.upload-directory=data
|
||||
cre.server.password-file=passwords.txt
|
||||
cre.server.url-use-port=true
|
||||
cre.server.url-use-https=false
|
||||
|
@ -10,10 +10,8 @@ cre.security.jwt-duration=18000000
|
|||
# Root user
|
||||
cre.security.root.id=9999
|
||||
cre.security.root.password=password
|
||||
# Common user
|
||||
#cre.security.common.id=9998
|
||||
#cre.security.common.password=common
|
||||
# TYPES DE PRODUIT PAR DÉFAUT
|
||||
|
||||
# Default material types
|
||||
entities.material-types.systemTypes[0].name=Aucun
|
||||
entities.material-types.systemTypes[0].prefix=
|
||||
entities.material-types.systemTypes[0].usepercentages=false
|
||||
|
@ -21,9 +19,14 @@ entities.material-types.systemTypes[1].name=Base
|
|||
entities.material-types.systemTypes[1].prefix=BAS
|
||||
entities.material-types.systemTypes[1].usepercentages=false
|
||||
entities.material-types.baseName=Base
|
||||
|
||||
# Database manager
|
||||
database-updater.username=root
|
||||
database-updater.password=pass
|
||||
|
||||
# DEBUG
|
||||
spring.jpa.show-sql=true
|
||||
# NE PAS MODIFIER
|
||||
# Do not modify
|
||||
spring.messages.fallback-to-system-locale=true
|
||||
spring.servlet.multipart.max-file-size=10MB
|
||||
spring.servlet.multipart.max-request-size=15MB
|
||||
|
@ -31,4 +34,5 @@ spring.jpa.hibernate.ddl-auto=none
|
|||
spring.jpa.open-in-view=true
|
||||
server.http2.enabled=true
|
||||
server.error.whitelabel.enabled=false
|
||||
spring.h2.console.enabled=false
|
||||
spring.profiles.active=@spring.profiles.active@
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<statusListener class="ch.qos.logback.core.status.NopStatusListener"/>
|
||||
|
||||
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<Pattern>
|
||||
%black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{1.}): %msg%n%throwable
|
||||
%black(%d{ISO8601}) %highlight(%-5level) [%blue(%t)] %yellow(%C{36}): %msg%n%throwable
|
||||
</Pattern>
|
||||
</layout>
|
||||
</appender>
|
||||
|
@ -20,7 +21,7 @@
|
|||
|
||||
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
|
||||
<Pattern>
|
||||
%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n
|
||||
%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger.%M - %msg%n
|
||||
</Pattern>
|
||||
</encoder>
|
||||
|
||||
|
|
|
@ -4,12 +4,14 @@ import dev.fyloz.trial.colorrecipesexplorer.model.EmployeeGroup
|
|||
import dev.fyloz.trial.colorrecipesexplorer.model.employee
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.employeeGroup
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager
|
||||
import kotlin.test.*
|
||||
|
||||
@Disabled
|
||||
@DataJpaTest
|
||||
class EmployeeRepositoryTest @Autowired constructor(private val employeeRepository: EmployeeRepository, val entityManager: TestEntityManager) {
|
||||
private var employeeGroup = employeeGroup()
|
||||
|
@ -94,6 +96,7 @@ class EmployeeRepositoryTest @Autowired constructor(private val employeeReposito
|
|||
}
|
||||
}
|
||||
|
||||
@Disabled
|
||||
class EmployeeGroupRepositoryTest @Autowired constructor(employeeGroupRepository: EmployeeGroupRepository, entityManager: TestEntityManager) :
|
||||
AbstractNamedJpaRepositoryTest<EmployeeGroup, EmployeeGroupRepository>(employeeGroupRepository, entityManager) {
|
||||
override fun entity(name: String): EmployeeGroup = employeeGroup(name = name)
|
||||
|
|
|
@ -2,10 +2,12 @@ package dev.fyloz.trial.colorrecipesexplorer.repository
|
|||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.Company
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.company
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager
|
||||
|
||||
@Disabled
|
||||
@DataJpaTest
|
||||
class CompanyRepositoryTest @Autowired constructor(companyRepository: CompanyRepository, entityManager: TestEntityManager) :
|
||||
AbstractNamedJpaRepositoryTest<Company, CompanyRepository>(companyRepository, entityManager) {
|
||||
|
|
|
@ -3,12 +3,14 @@ package dev.fyloz.trial.colorrecipesexplorer.repository
|
|||
import dev.fyloz.trial.colorrecipesexplorer.model.Material
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.material
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.materialType
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
@Disabled
|
||||
class MaterialRepositoryTest @Autowired constructor(materialRepository: MaterialRepository, entityManager: TestEntityManager) :
|
||||
AbstractNamedJpaRepositoryTest<Material, MaterialRepository>(materialRepository, entityManager) {
|
||||
override fun entity(name: String): Material = material(name = name, materialType = null)
|
||||
|
|
|
@ -2,11 +2,13 @@ package dev.fyloz.trial.colorrecipesexplorer.repository
|
|||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.MaterialType
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.materialType
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager
|
||||
import org.junit.jupiter.api.Test
|
||||
import kotlin.test.*
|
||||
|
||||
@Disabled
|
||||
class MaterialTypeRepositoryTest @Autowired constructor(materialTypeRepository: MaterialTypeRepository, entityManager: TestEntityManager) :
|
||||
AbstractNamedJpaRepositoryTest<MaterialType, MaterialTypeRepository>(materialTypeRepository, entityManager) {
|
||||
override fun entity(name: String): MaterialType = entity(name = name, prefix = "MAT")
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.repository
|
||||
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager
|
||||
|
||||
@Disabled
|
||||
@DataJpaTest
|
||||
class MixMaterialRepositoryTest @Autowired constructor(
|
||||
private val mixMaterialRepository: MixMaterialRepository,
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.repository
|
||||
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager
|
||||
|
||||
@Disabled
|
||||
@DataJpaTest
|
||||
class RecipeStepRepositoryTest @Autowired constructor(
|
||||
recipeStepRepository: RecipeStepRepository,
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
package dev.fyloz.trial.colorrecipesexplorer.repository
|
||||
|
||||
import dev.fyloz.trial.colorrecipesexplorer.model.NamedModel
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager
|
||||
import kotlin.test.*
|
||||
|
||||
@DataJpaTest
|
||||
@DataJpaTest(excludeAutoConfiguration = [LiquibaseAutoConfiguration::class])
|
||||
abstract class AbstractNamedJpaRepositoryTest<E : NamedModel, R : NamedJpaRepository<E>>(
|
||||
protected val repository: R,
|
||||
protected val entityManager: TestEntityManager
|
||||
|
|
Loading…
Reference in New Issue