diff --git a/.env.dist b/.env.dist
index fe2f984..0f9db9e 100644
--- a/.env.dist
+++ b/.env.dist
@@ -1,10 +1,6 @@
-## can be generated with `openssl rand -base64 32`
-JWT_SECRET=
-#
-## can be generated with `openssl rand -base64 32`
+# mariadb
MYSQL_ROOT_PASSWORD=
-#
-## can be generated with `openssl rand -base64 32`
MYSQL_PASSWORD=
-# password should be the same as mysql_password
-PASSWORD=
+# simplenotes
+DB_PASSWORD=
+JWT_SECRET=
diff --git a/README.md b/README.md
index b76d9fb..b644fc7 100644
--- a/README.md
+++ b/README.md
@@ -15,5 +15,4 @@
## Configuration
The app is configured with environments variables.
-If no match is found within the env, a default value is read from a properties file in /app/src/main/resources/application.properties.
-Don't use the default values for secrets ! Every value inside *.env.dist* should be changed.
+If no match is found within the env, a default value is read from a yaml file in simplenotes-app/src/main/resources/application.yaml.
diff --git a/docker-compose.yml b/docker-compose.yml
index ef6f360..c3513d5 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -32,13 +32,13 @@ services:
- .env
environment:
- TZ=Europe/Brussels
- - HOST=0.0.0.0
- - JDBCURL=jdbc:mariadb://db:3306/simplenotes
- - DRIVERCLASSNAME=org.mariadb.jdbc.Driver
- - USERNAME=simplenotes
+ - SERVER_HOST=0.0.0.0
+ - DB_JDBC_URL=jdbc:mariadb://db:3306/simplenotes
+ - DB_DRIVER_CLASS_NAME=org.mariadb.jdbc.Driver
+ - DB_USERNAME=simplenotes
# .env:
# - JWT_SECRET
- # - PASSWORD
+ # - DB_PASSWORD
ports:
- 127.0.0.1:8080:8080
healthcheck:
diff --git a/simplenotes-app/build.gradle.kts b/simplenotes-app/build.gradle.kts
index 9519be1..fe693e8 100644
--- a/simplenotes-app/build.gradle.kts
+++ b/simplenotes-app/build.gradle.kts
@@ -30,9 +30,6 @@ dependencies {
implementation(Libs.micronaut)
kapt(Libs.micronautProcessor)
- testImplementation(Libs.micronaut)
- kaptTest(Libs.micronautProcessor)
-
testImplementation(Libs.junit)
testImplementation(Libs.assertJ)
testImplementation(Libs.http4kTestingHamkrest)
diff --git a/simplenotes-app/src/main/kotlin/be/simplenotes/app/Server.kt b/simplenotes-app/src/main/kotlin/be/simplenotes/app/Server.kt
index 54e6105..0b4cb1d 100644
--- a/simplenotes-app/src/main/kotlin/be/simplenotes/app/Server.kt
+++ b/simplenotes-app/src/main/kotlin/be/simplenotes/app/Server.kt
@@ -1,13 +1,13 @@
package be.simplenotes.app
-import io.micronaut.context.annotation.Context
import org.http4k.server.Http4kServer
import org.slf4j.LoggerFactory
import javax.annotation.PostConstruct
import javax.annotation.PreDestroy
+import javax.inject.Singleton
import be.simplenotes.config.ServerConfig as SimpleNotesServerConfig
-@Context
+@Singleton
class Server(
private val config: SimpleNotesServerConfig,
private val http4kServer: Http4kServer,
@@ -17,7 +17,7 @@ class Server(
@PostConstruct
fun start(): Server {
http4kServer.start()
- logger.info("Listening on http://${config.host}:${config.port}")
+ logger.info("Listening on http://${config.host}:${http4kServer.port()}")
return this
}
diff --git a/simplenotes-app/src/main/kotlin/be/simplenotes/app/SimpleNotes.kt b/simplenotes-app/src/main/kotlin/be/simplenotes/app/SimpleNotes.kt
index 8b5927a..1e03041 100644
--- a/simplenotes-app/src/main/kotlin/be/simplenotes/app/SimpleNotes.kt
+++ b/simplenotes-app/src/main/kotlin/be/simplenotes/app/SimpleNotes.kt
@@ -1,12 +1,10 @@
package be.simplenotes.app
import io.micronaut.context.ApplicationContext
+import java.lang.Runtime.getRuntime
fun main() {
- val ctx = ApplicationContext.run().start()
- Runtime.getRuntime().addShutdownHook(
- Thread {
- ctx.stop()
- }
- )
+ val ctx = ApplicationContext.run()
+ ctx.createBean(Server::class.java)
+ getRuntime().addShutdownHook(Thread { ctx.stop() })
}
diff --git a/simplenotes-app/src/main/resources/logback.xml b/simplenotes-app/src/main/resources/logback.xml
index a2bdf9f..13f8fa8 100644
--- a/simplenotes-app/src/main/resources/logback.xml
+++ b/simplenotes-app/src/main/resources/logback.xml
@@ -14,4 +14,5 @@
+
diff --git a/simplenotes-config/src/main/kotlin/be/simplenotes/config/Config.kt b/simplenotes-config/src/main/kotlin/be/simplenotes/config/Config.kt
index 963d4e4..75fd29b 100644
--- a/simplenotes-config/src/main/kotlin/be/simplenotes/config/Config.kt
+++ b/simplenotes-config/src/main/kotlin/be/simplenotes/config/Config.kt
@@ -1,8 +1,12 @@
package be.simplenotes.config
+import io.micronaut.context.annotation.ConfigurationInject
+import io.micronaut.context.annotation.ConfigurationProperties
import java.util.concurrent.TimeUnit
+import javax.inject.Singleton
-data class DataSourceConfig(
+@ConfigurationProperties("db")
+data class DataSourceConfig @ConfigurationInject constructor(
val jdbcUrl: String,
val driverClassName: String,
val username: String,
@@ -14,7 +18,8 @@ data class DataSourceConfig(
"username='$username', password='***', maximumPoolSize=$maximumPoolSize, connectionTimeout=$connectionTimeout)"
}
-data class JwtConfig(
+@ConfigurationProperties("jwt")
+data class JwtConfig @ConfigurationInject constructor(
val secret: String,
val validity: Long,
val timeUnit: TimeUnit,
@@ -22,7 +27,8 @@ data class JwtConfig(
override fun toString() = "JwtConfig(secret='***', validity=$validity, timeUnit=$timeUnit)"
}
-data class ServerConfig(
+@ConfigurationProperties("server")
+data class ServerConfig @ConfigurationInject constructor(
val host: String,
val port: Int,
)
diff --git a/simplenotes-config/src/main/kotlin/be/simplenotes/config/ConfigLoader.kt b/simplenotes-config/src/main/kotlin/be/simplenotes/config/ConfigLoader.kt
deleted file mode 100644
index c8bf4b2..0000000
--- a/simplenotes-config/src/main/kotlin/be/simplenotes/config/ConfigLoader.kt
+++ /dev/null
@@ -1,47 +0,0 @@
-package be.simplenotes.config
-
-import java.util.*
-import java.util.concurrent.TimeUnit
-import javax.inject.Singleton
-
-@Singleton
-class ConfigLoader {
- //region Config loading
- private val properties: Properties = javaClass
- .getResource("/application.properties")
- .openStream()
- .use {
- Properties().apply { load(it) }
- }
-
- private val env = System.getenv()
-
- private fun value(key: String): String =
- env[key.toUpperCase().replace(".", "_")]
- ?: properties.getProperty(key)
- ?: error("Missing config key $key")
- //endregion
-
- val jwtConfig
- get() = JwtConfig(
- secret = value("jwt.secret"),
- validity = value("jwt.validity").toLong(),
- timeUnit = TimeUnit.HOURS,
- )
-
- val dataSourceConfig
- get() = DataSourceConfig(
- jdbcUrl = value("jdbcUrl"),
- driverClassName = value("driverClassName"),
- username = value("username"),
- password = value("password"),
- maximumPoolSize = value("maximumPoolSize").toInt(),
- connectionTimeout = value("connectionTimeout").toLong()
- )
-
- val serverConfig
- get() = ServerConfig(
- host = value("host"),
- port = value("port").toInt(),
- )
-}
diff --git a/simplenotes-config/src/main/kotlin/be/simplenotes/config/ConfigModule.kt b/simplenotes-config/src/main/kotlin/be/simplenotes/config/ConfigModule.kt
deleted file mode 100644
index 64e6010..0000000
--- a/simplenotes-config/src/main/kotlin/be/simplenotes/config/ConfigModule.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package be.simplenotes.config
-
-import io.micronaut.context.annotation.Factory
-import javax.inject.Singleton
-
-@Factory
-class ConfigModule {
-
- @Singleton
- internal fun dataSourceConfig(configLoader: ConfigLoader) = configLoader.dataSourceConfig
-
- @Singleton
- internal fun jwtConfig(configLoader: ConfigLoader) = configLoader.jwtConfig
-
- @Singleton
- internal fun serverConfig(configLoader: ConfigLoader) = configLoader.serverConfig
-}
diff --git a/simplenotes-config/src/main/resources/application.properties b/simplenotes-config/src/main/resources/application.properties
deleted file mode 100644
index 9e93a26..0000000
--- a/simplenotes-config/src/main/resources/application.properties
+++ /dev/null
@@ -1,12 +0,0 @@
-host=localhost
-port=8080
-#
-jdbcUrl=jdbc:h2:./notes-db;
-driverClassName=org.h2.Driver
-username=h2
-password=
-maximumPoolSize=10
-connectionTimeout=3000
-#
-jwt.secret=PliLvfk7l4WF+cZJk66LR5Mpnh+ocbvJ2wfUCK2UCms=
-jwt.validity=24
diff --git a/simplenotes-config/src/main/resources/application.yaml b/simplenotes-config/src/main/resources/application.yaml
new file mode 100644
index 0000000..f68fe0c
--- /dev/null
+++ b/simplenotes-config/src/main/resources/application.yaml
@@ -0,0 +1,16 @@
+db:
+ jdbc-url: jdbc:h2:./notes-db;
+ driver-class-name: org.h2.Driver
+ username: h2
+ password: ''
+ connection-timeout: 3000
+ maximum-pool-size: 10
+
+jwt:
+ secret: 'PliLvfk7l4WF+cZJk66LR5Mpnh+ocbvJ2wfUCK2UCms='
+ validity: 24
+ time-unit: hours
+
+server:
+ host: localhost
+ port: 8080
diff --git a/simplenotes-persistance/build.gradle.kts b/simplenotes-persistance/build.gradle.kts
index 6cea2fd..86cfbfe 100644
--- a/simplenotes-persistance/build.gradle.kts
+++ b/simplenotes-persistance/build.gradle.kts
@@ -16,16 +16,14 @@ dependencies {
implementation(Libs.hikariCP)
implementation(Libs.ktormCore)
implementation(Libs.ktormMysql)
+ implementation(Libs.logbackClassic)
- implementation(Libs.mapstruct)
+ compileOnly(Libs.mapstruct)
kapt(Libs.mapstructProcessor)
implementation(Libs.micronaut)
kapt(Libs.micronautProcessor)
- testImplementation(Libs.micronaut)
- kaptTest(Libs.micronautProcessor)
-
testImplementation(Libs.junit)
testImplementation(Libs.assertJ)
testImplementation(Libs.logbackClassic)
diff --git a/simplenotes-persistance/src/main/kotlin/be/simplenotes/persistance/PersistanceModule.kt b/simplenotes-persistance/src/main/kotlin/be/simplenotes/persistance/PersistanceModule.kt
index 6ddc2a9..a943e1a 100644
--- a/simplenotes-persistance/src/main/kotlin/be/simplenotes/persistance/PersistanceModule.kt
+++ b/simplenotes-persistance/src/main/kotlin/be/simplenotes/persistance/PersistanceModule.kt
@@ -15,12 +15,6 @@ import javax.sql.DataSource
@Factory
class PersistanceModule {
- @Singleton
- internal fun noteConverter() = Mappers.getMapper(NoteConverter::class.java)
-
- @Singleton
- internal fun userConverter() = Mappers.getMapper(UserConverter::class.java)
-
@Singleton
internal fun database(migrations: DbMigrations, dataSource: DataSource): Database {
migrations.migrate()
diff --git a/simplenotes-persistance/src/main/kotlin/be/simplenotes/persistance/converters/NoteConverter.kt b/simplenotes-persistance/src/main/kotlin/be/simplenotes/persistance/converters/NoteConverter.kt
index 8643b39..43508ba 100644
--- a/simplenotes-persistance/src/main/kotlin/be/simplenotes/persistance/converters/NoteConverter.kt
+++ b/simplenotes-persistance/src/main/kotlin/be/simplenotes/persistance/converters/NoteConverter.kt
@@ -9,12 +9,13 @@ import org.mapstruct.Mappings
import org.mapstruct.ReportingPolicy
import java.time.LocalDateTime
import java.util.*
+import javax.inject.Singleton
-/**
- * This is an abstract class because kotlin default methods in interface are not seen as default in kapt
- * @see [KT-25960](https://youtrack.jetbrains.com/issue/KT-25960)
- */
-@Mapper(uses = [NoteEntityFactory::class, UserEntityFactory::class], unmappedTargetPolicy = ReportingPolicy.IGNORE)
+@Mapper(
+ uses = [NoteEntityFactory::class, UserEntityFactory::class],
+ unmappedTargetPolicy = ReportingPolicy.IGNORE,
+ componentModel = "jsr330"
+)
internal abstract class NoteConverter {
fun toNote(entity: NoteEntity, tags: Tags) =
@@ -80,4 +81,5 @@ internal abstract class NoteConverter {
typealias Tags = List
+@Singleton
internal class NoteEntityFactory : Entity.Factory()
diff --git a/simplenotes-persistance/src/main/kotlin/be/simplenotes/persistance/converters/UserConverter.kt b/simplenotes-persistance/src/main/kotlin/be/simplenotes/persistance/converters/UserConverter.kt
index 5c12dd5..6ad64e3 100644
--- a/simplenotes-persistance/src/main/kotlin/be/simplenotes/persistance/converters/UserConverter.kt
+++ b/simplenotes-persistance/src/main/kotlin/be/simplenotes/persistance/converters/UserConverter.kt
@@ -6,8 +6,13 @@ import be.simplenotes.types.User
import me.liuwj.ktorm.entity.Entity
import org.mapstruct.Mapper
import org.mapstruct.ReportingPolicy
+import javax.inject.Singleton
-@Mapper(uses = [UserEntityFactory::class], unmappedTargetPolicy = ReportingPolicy.IGNORE)
+@Mapper(
+ uses = [UserEntityFactory::class],
+ unmappedTargetPolicy = ReportingPolicy.IGNORE,
+ componentModel = "jsr330"
+)
internal interface UserConverter {
fun toUser(userEntity: UserEntity): User
fun toPersistedUser(userEntity: UserEntity): PersistedUser
@@ -15,4 +20,5 @@ internal interface UserConverter {
fun toEntity(user: PersistedUser): UserEntity
}
+@Singleton
internal class UserEntityFactory : Entity.Factory()
diff --git a/simplenotes-persistance/src/test/kotlin/be/simplenotes/persistance/converters/NoteConverterTest.kt b/simplenotes-persistance/src/test/kotlin/be/simplenotes/persistance/converters/NoteConverterTest.kt
index dee1786..72e0e94 100644
--- a/simplenotes-persistance/src/test/kotlin/be/simplenotes/persistance/converters/NoteConverterTest.kt
+++ b/simplenotes-persistance/src/test/kotlin/be/simplenotes/persistance/converters/NoteConverterTest.kt
@@ -2,23 +2,25 @@ package be.simplenotes.persistance.converters
import be.simplenotes.persistance.notes.NoteEntity
import be.simplenotes.types.*
+import io.micronaut.context.BeanContext
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
-import org.mapstruct.factory.Mappers
import java.time.LocalDateTime
import java.util.*
internal class NoteConverterTest {
+ private val ctx = BeanContext.run()
+ val converter = ctx.getBean(NoteConverter::class.java)
+
@Nested
@DisplayName("Entity -> Models")
inner class EntityToModels {
@Test
fun `convert NoteEntity to Note`() {
- val converter = Mappers.getMapper(NoteConverter::class.java)
val entity = NoteEntity {
title = "title"
markdown = "md"
@@ -39,7 +41,6 @@ internal class NoteConverterTest {
@Test
fun `convert NoteEntity to ExportedNote`() {
- val converter = Mappers.getMapper(NoteConverter::class.java)
val entity = NoteEntity {
title = "title"
markdown = "md"
@@ -62,7 +63,6 @@ internal class NoteConverterTest {
@Test
fun `convert NoteEntity to PersistedNoteMetadata`() {
- val converter = Mappers.getMapper(NoteConverter::class.java)
val entity = NoteEntity {
uuid = UUID.randomUUID()
title = "title"
@@ -89,7 +89,6 @@ internal class NoteConverterTest {
@Test
fun `convert Note to NoteEntity`() {
- val converter = Mappers.getMapper(NoteConverter::class.java)
val note = Note(NoteMetadata("title", emptyList()), "md", "html")
val entity = converter.toEntity(note, UUID.randomUUID(), 2, LocalDateTime.MIN)
@@ -103,7 +102,6 @@ internal class NoteConverterTest {
@Test
fun `convert PersistedNoteMetadata to NoteEntity`() {
- val converter = Mappers.getMapper(NoteConverter::class.java)
val persistedNoteMetadata =
PersistedNoteMetadata("title", emptyList(), LocalDateTime.MIN, UUID.randomUUID())
val entity = converter.toEntity(persistedNoteMetadata)
@@ -116,7 +114,6 @@ internal class NoteConverterTest {
@Test
fun `convert NoteMetadata to NoteEntity`() {
- val converter = Mappers.getMapper(NoteConverter::class.java)
val noteMetadata = NoteMetadata("title", emptyList())
val entity = converter.toEntity(noteMetadata)
@@ -126,7 +123,6 @@ internal class NoteConverterTest {
@Test
fun `convert PersistedNote to NoteEntity`() {
- val converter = Mappers.getMapper(NoteConverter::class.java)
val persistedNote = PersistedNote(
NoteMetadata("title", emptyList()),
markdown = "md",
@@ -148,7 +144,6 @@ internal class NoteConverterTest {
@Test
fun `convert ExportedNote to NoteEntity`() {
- val converter = Mappers.getMapper(NoteConverter::class.java)
val exportedNote = ExportedNote(
"title",
emptyList(),
diff --git a/simplenotes-persistance/src/test/kotlin/be/simplenotes/persistance/converters/UserConverterTest.kt b/simplenotes-persistance/src/test/kotlin/be/simplenotes/persistance/converters/UserConverterTest.kt
index 062ac93..8e59050 100644
--- a/simplenotes-persistance/src/test/kotlin/be/simplenotes/persistance/converters/UserConverterTest.kt
+++ b/simplenotes-persistance/src/test/kotlin/be/simplenotes/persistance/converters/UserConverterTest.kt
@@ -3,15 +3,17 @@ package be.simplenotes.persistance.converters
import be.simplenotes.persistance.users.UserEntity
import be.simplenotes.types.PersistedUser
import be.simplenotes.types.User
+import io.micronaut.context.BeanContext
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
-import org.mapstruct.factory.Mappers
internal class UserConverterTest {
+ private val ctx = BeanContext.run()
+ private val converter = ctx.getBean(UserConverter::class.java)
+
@Test
fun `convert UserEntity to User`() {
- val converter = Mappers.getMapper(UserConverter::class.java)
val entity = UserEntity {
username = "test"
password = "test2"
@@ -24,7 +26,6 @@ internal class UserConverterTest {
@Test
fun `convert UserEntity to PersistedUser`() {
- val converter = Mappers.getMapper(UserConverter::class.java)
val entity = UserEntity {
username = "test"
password = "test2"
@@ -37,7 +38,6 @@ internal class UserConverterTest {
@Test
fun `convert User to UserEntity`() {
- val converter = Mappers.getMapper(UserConverter::class.java)
val user = User("test", "test2")
val entity = converter.toEntity(user)
diff --git a/simplenotes-persistance/src/test/kotlin/be/simplenotes/persistance/notes/BaseNoteRepositoryImplTest.kt b/simplenotes-persistance/src/test/kotlin/be/simplenotes/persistance/notes/BaseNoteRepositoryImplTest.kt
index 1fce436..99f8473 100644
--- a/simplenotes-persistance/src/test/kotlin/be/simplenotes/persistance/notes/BaseNoteRepositoryImplTest.kt
+++ b/simplenotes-persistance/src/test/kotlin/be/simplenotes/persistance/notes/BaseNoteRepositoryImplTest.kt
@@ -16,7 +16,6 @@ import me.liuwj.ktorm.entity.toList
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.jupiter.api.*
-import org.mapstruct.factory.Mappers
import java.sql.SQLIntegrityConstraintViolationException
internal abstract class BaseNoteRepositoryImplTest : DbTest() {
@@ -142,7 +141,7 @@ internal abstract class BaseNoteRepositoryImplTest : DbTest() {
fun `find an existing note`() {
val fakeNote = noteRepo.insertFakeNote(user1)
- val converter = Mappers.getMapper(NoteConverter::class.java)
+ val converter = beanContext.getBean(NoteConverter::class.java)
val note = db.notes.find { it.title eq fakeNote.meta.title }!!
.let { entity ->