From 7ad8b7039b45d02098d39aad55115b0e4f7b6785 Mon Sep 17 00:00:00 2001 From: Hubert Van De Walle Date: Mon, 12 Apr 2021 21:13:49 +0200 Subject: [PATCH] Update config --- .env.dist | 5 -- Dockerfile | 9 +-- app/src/SimpleNotes.kt | 6 +- app/src/controllers/HealthCheckController.kt | 14 ----- app/src/routes/BasicRoutes.kt | 4 -- config/resources/application.yaml | 9 +-- config/src/Config.kt | 32 ----------- config/src/DataConfig.kt | 58 ++++++++++++++++++++ docker-compose.yml | 43 ++------------- domain/src/HealthCheckService.kt | 13 ----- domain/src/NoteService.kt | 48 ++++++++-------- domain/src/UserService.kt | 36 +++++------- domain/test/UserServiceTest.kt | 5 -- persistence/src/PersistenceModule.kt | 4 +- persistence/test/DbTest.kt | 20 +------ search/build.gradle.kts | 1 + search/src/Extractors.kt | 19 +++---- search/src/NoteSearcherImpl.kt | 7 +-- search/src/SearchModule.kt | 3 +- search/test/NoteSearcherImplTest.kt | 13 +++-- views/src/NoteView.kt | 6 +- 21 files changed, 138 insertions(+), 217 deletions(-) delete mode 100644 app/src/controllers/HealthCheckController.kt delete mode 100644 config/src/Config.kt create mode 100644 config/src/DataConfig.kt delete mode 100644 domain/src/HealthCheckService.kt diff --git a/.env.dist b/.env.dist index 0f9db9e..211acef 100644 --- a/.env.dist +++ b/.env.dist @@ -1,6 +1 @@ -# mariadb -MYSQL_ROOT_PASSWORD= -MYSQL_PASSWORD= -# simplenotes -DB_PASSWORD= JWT_SECRET= diff --git a/Dockerfile b/Dockerfile index a3087c6..d3e7b6f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,18 +12,15 @@ FROM alpine RUN apk add --no-cache curl -ENV APPLICATION_USER simplenotes -RUN adduser -D -g '' $APPLICATION_USER - RUN mkdir /app -RUN chown -R $APPLICATION_USER /app - -USER $APPLICATION_USER +RUN mkdir /app/data COPY --from=jdkbuilder /myjdk /myjdk COPY app/build/libs/app-with-dependencies*.jar /app/simplenotes.jar WORKDIR /app +VOLUME /app/data + ENV SERVER_HOST 0.0.0.0 CMD [ \ diff --git a/app/src/SimpleNotes.kt b/app/src/SimpleNotes.kt index 1e03041..36f4089 100644 --- a/app/src/SimpleNotes.kt +++ b/app/src/SimpleNotes.kt @@ -4,7 +4,11 @@ import io.micronaut.context.ApplicationContext import java.lang.Runtime.getRuntime fun main() { - val ctx = ApplicationContext.run() + val env = if (System.getenv("ENV") == "dev") "dev" else "prod" + val ctx = ApplicationContext.builder() + .deduceEnvironment(false) + .environments(env) + .start() ctx.createBean(Server::class.java) getRuntime().addShutdownHook(Thread { ctx.stop() }) } diff --git a/app/src/controllers/HealthCheckController.kt b/app/src/controllers/HealthCheckController.kt deleted file mode 100644 index 0184a32..0000000 --- a/app/src/controllers/HealthCheckController.kt +++ /dev/null @@ -1,14 +0,0 @@ -package be.simplenotes.app.controllers - -import be.simplenotes.domain.HealthCheckService -import org.http4k.core.Request -import org.http4k.core.Response -import org.http4k.core.Status.Companion.OK -import org.http4k.core.Status.Companion.SERVICE_UNAVAILABLE -import javax.inject.Singleton - -@Singleton -class HealthCheckController(private val healthCheckService: HealthCheckService) { - fun healthCheck(@Suppress("UNUSED_PARAMETER") request: Request) = - if (healthCheckService.isOk()) Response(OK) else Response(SERVICE_UNAVAILABLE) -} diff --git a/app/src/routes/BasicRoutes.kt b/app/src/routes/BasicRoutes.kt index 08351cd..cb9041a 100644 --- a/app/src/routes/BasicRoutes.kt +++ b/app/src/routes/BasicRoutes.kt @@ -1,7 +1,6 @@ package be.simplenotes.app.routes import be.simplenotes.app.controllers.BaseController -import be.simplenotes.app.controllers.HealthCheckController import be.simplenotes.app.controllers.NoteController import be.simplenotes.app.controllers.UserController import be.simplenotes.app.filters.ImmutableFilter @@ -19,7 +18,6 @@ import javax.inject.Singleton @Singleton class BasicRoutes( - private val healthCheckController: HealthCheckController, private val baseCtrl: BaseController, private val userCtrl: UserController, private val noteCtrl: NoteController, @@ -52,8 +50,6 @@ class BasicRoutes( "/notes/public/{uuid}" bind GET to noteCtrl::public, ) ), - - "/health" bind GET to healthCheckController::healthCheck, staticHandler ) } diff --git a/config/resources/application.yaml b/config/resources/application.yaml index 11fb995..dc7064b 100644 --- a/config/resources/application.yaml +++ b/config/resources/application.yaml @@ -1,10 +1,3 @@ -db: - jdbc-url: jdbc:h2:./notes-db; - username: h2 - password: '' - connection-timeout: 3000 - maximum-pool-size: 10 - jwt: secret: 'PliLvfk7l4WF+cZJk66LR5Mpnh+ocbvJ2wfUCK2UCms=' validity: 24 @@ -13,3 +6,5 @@ jwt: server: host: localhost port: 8080 + +data-dir: ./data diff --git a/config/src/Config.kt b/config/src/Config.kt deleted file mode 100644 index fedb9b7..0000000 --- a/config/src/Config.kt +++ /dev/null @@ -1,32 +0,0 @@ -package be.simplenotes.config - -import io.micronaut.context.annotation.ConfigurationInject -import io.micronaut.context.annotation.ConfigurationProperties -import java.util.concurrent.TimeUnit - -@ConfigurationProperties("db") -data class DataSourceConfig @ConfigurationInject constructor( - val jdbcUrl: String, - val username: String, - val password: String, - val maximumPoolSize: Int, - val connectionTimeout: Long, -) { - override fun toString() = "DataSourceConfig(jdbcUrl='$jdbcUrl', username='$username', password='***', " + - "maximumPoolSize=$maximumPoolSize, connectionTimeout=$connectionTimeout)" -} - -@ConfigurationProperties("jwt") -data class JwtConfig @ConfigurationInject constructor( - val secret: String, - val validity: Long, - val timeUnit: TimeUnit, -) { - override fun toString() = "JwtConfig(secret='***', validity=$validity, timeUnit=$timeUnit)" -} - -@ConfigurationProperties("server") -data class ServerConfig @ConfigurationInject constructor( - val host: String, - val port: Int, -) diff --git a/config/src/DataConfig.kt b/config/src/DataConfig.kt new file mode 100644 index 0000000..dcc4732 --- /dev/null +++ b/config/src/DataConfig.kt @@ -0,0 +1,58 @@ +package be.simplenotes.config + +import io.micronaut.context.annotation.* +import java.nio.file.Path +import java.util.concurrent.TimeUnit +import javax.inject.Singleton + +data class DataConfig(val dataDir: String) + +data class DataSourceConfig( + val jdbcUrl: String, + val maximumPoolSize: Int, + val connectionTimeout: Long, +) + +@ConfigurationProperties("jwt") +data class JwtConfig @ConfigurationInject constructor( + val secret: String, + val validity: Long, + val timeUnit: TimeUnit, +) { + override fun toString() = "JwtConfig(secret='***', validity=$validity, timeUnit=$timeUnit)" +} + +@ConfigurationProperties("server") +data class ServerConfig @ConfigurationInject constructor( + val host: String, + val port: Int, +) + +@Factory +class ConfigFactory { + + @Singleton + @Requires(notEnv = ["test"]) + fun datasourceConfig(dataConfig: DataConfig) = DataSourceConfig( + jdbcUrl = "jdbc:h2:" + Path.of(dataConfig.dataDir, "simplenotes").normalize().toAbsolutePath(), + maximumPoolSize = 10, + connectionTimeout = 1000 + ) + + @Singleton + @Requires(env = ["test"]) + fun testDatasourceConfig() = DataSourceConfig( + jdbcUrl = "jdbc:h2:mem:regular;DB_CLOSE_DELAY=-1", + maximumPoolSize = 2, + connectionTimeout = 1000 + ) + + @Singleton + @Requires(notEnv = ["test"]) + fun dataConfig(@Property(name = "data-dir") dataDir: String) = DataConfig(dataDir) + + @Singleton + @Requires(env = ["test"]) + fun testDataConfig() = DataConfig("/tmp") + +} diff --git a/docker-compose.yml b/docker-compose.yml index 9a3cdbf..88f76b2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,54 +1,19 @@ version: '2.2' services: - - db: - image: mariadb:10.5.5 - container_name: simplenotes-mariadb - env_file: - - .env - environment: - - PUID=1000 - - PGID=1000 - - TZ=Europe/Brussels - - MYSQL_DATABASE=simplenotes - - MYSQL_USER=simplenotes - # .env: - # - MYSQL_ROOT_PASSWORD - # - MYSQL_PASSWORD - volumes: - - notes-db-volume:/var/lib/mysql - healthcheck: - test: "mysql --protocol=tcp -u simplenotes -p$MYSQL_PASSWORD -e 'show databases'" - interval: 5s - timeout: 1s - start_period: 2s - retries: 10 - simplenotes: image: hubv/simplenotes container_name: simplenotes env_file: - .env environment: + - PUID=1000 + - PGID=1000 - TZ=Europe/Brussels - - DB_JDBC_URL=jdbc:mariadb://db:3306/simplenotes - - DB_USERNAME=simplenotes # .env: # - JWT_SECRET - # - DB_PASSWORD ports: - 127.0.0.1:8080:8080 - healthcheck: - test: "curl --fail -s http://localhost:8080/health" - interval: 5s - timeout: 1s - start_period: 2s - retries: 3 - depends_on: - db: - condition: service_healthy + volumes: + - ./simplenotes-data:/app/data - -volumes: - notes-db-volume: diff --git a/domain/src/HealthCheckService.kt b/domain/src/HealthCheckService.kt deleted file mode 100644 index 8c52570..0000000 --- a/domain/src/HealthCheckService.kt +++ /dev/null @@ -1,13 +0,0 @@ -package be.simplenotes.domain - -import be.simplenotes.persistence.DbHealthCheck -import javax.inject.Singleton - -interface HealthCheckService { - fun isOk(): Boolean -} - -@Singleton -class HealthCheckServiceImpl(private val dbHealthCheck: DbHealthCheck) : HealthCheckService { - override fun isOk() = dbHealthCheck.isOk() -} diff --git a/domain/src/NoteService.kt b/domain/src/NoteService.kt index b46d50a..a406874 100644 --- a/domain/src/NoteService.kt +++ b/domain/src/NoteService.kt @@ -5,7 +5,6 @@ import be.simplenotes.domain.security.HtmlSanitizer import be.simplenotes.domain.utils.parseSearchTerms import be.simplenotes.persistence.repositories.NoteRepository import be.simplenotes.persistence.repositories.UserRepository -import be.simplenotes.persistence.transactions.TransactionService import be.simplenotes.search.NoteSearcher import be.simplenotes.types.LoggedInUser import be.simplenotes.types.Note @@ -22,31 +21,34 @@ class NoteService( private val noteRepository: NoteRepository, private val userRepository: UserRepository, private val searcher: NoteSearcher, - private val htmlSanitizer: HtmlSanitizer, - private val transaction: TransactionService, + private val htmlSanitizer: HtmlSanitizer ) { - fun create(user: LoggedInUser, markdownText: String) = transaction.use { - either.eager { - markdownService.renderDocument(markdownText) - .map { it.copy(html = htmlSanitizer.sanitize(user, it.html)) } - .map { Note(it.metadata, markdown = markdownText, html = it.html) } - .map { noteRepository.create(user.userId, it) } - .bind() - .also { searcher.indexNote(user.userId, it) } - } + fun create(user: LoggedInUser, markdownText: String) = either.eager { + markdownService.renderDocument(markdownText) + .map { it.copy(html = htmlSanitizer.sanitize(user, it.html)) } + .map { Note(title = it.metadata.title, tags = it.metadata.tags, markdown = markdownText, html = it.html) } + .map { noteRepository.create(user.userId, it) } + .bind() + .also { searcher.indexNote(user.userId, it) } } - fun update(user: LoggedInUser, uuid: UUID, markdownText: String) = transaction.use { + fun update(user: LoggedInUser, uuid: UUID, markdownText: String) = either.eager { markdownService.renderDocument(markdownText) .map { it.copy(html = htmlSanitizer.sanitize(user, it.html)) } - .map { Note(it.metadata, markdown = markdownText, html = it.html) } + .map { + Note( + title = it.metadata.title, + tags = it.metadata.tags, + markdown = markdownText, + html = it.html + ) + } .map { noteRepository.update(user.userId, uuid, it) } .bind() ?.also { searcher.updateIndex(user.userId, it) } } - } fun paginatedNotes( userId: Int, @@ -64,22 +66,22 @@ class NoteService( fun find(userId: Int, uuid: UUID) = noteRepository.find(userId, uuid) - fun trash(userId: Int, uuid: UUID): Boolean = transaction.use { + fun trash(userId: Int, uuid: UUID): Boolean { val res = noteRepository.delete(userId, uuid, permanent = false) if (res) searcher.deleteIndex(userId, uuid) - res + return res } - fun restore(userId: Int, uuid: UUID): Boolean = transaction.use { + fun restore(userId: Int, uuid: UUID): Boolean { val res = noteRepository.restore(userId, uuid) if (res) find(userId, uuid)?.let { note -> searcher.indexNote(userId, note) } - res + return res } - fun delete(userId: Int, uuid: UUID): Boolean = transaction.use { + fun delete(userId: Int, uuid: UUID): Boolean { val res = noteRepository.delete(userId, uuid, permanent = true) if (res) searcher.deleteIndex(userId, uuid) - res + return res } fun countDeleted(userId: Int) = noteRepository.count(userId, deleted = true) @@ -99,8 +101,8 @@ class NoteService( @PreDestroy fun dropAllIndexes() = searcher.dropAll() - fun makePublic(userId: Int, uuid: UUID) = transaction.use { noteRepository.makePublic(userId, uuid) } - fun makePrivate(userId: Int, uuid: UUID) = transaction.use { noteRepository.makePrivate(userId, uuid) } + fun makePublic(userId: Int, uuid: UUID) = noteRepository.makePublic(userId, uuid) + fun makePrivate(userId: Int, uuid: UUID) = noteRepository.makePrivate(userId, uuid) fun findPublic(uuid: UUID) = noteRepository.findPublic(uuid) } diff --git a/domain/src/UserService.kt b/domain/src/UserService.kt index fc11d9a..65cf163 100644 --- a/domain/src/UserService.kt +++ b/domain/src/UserService.kt @@ -9,7 +9,6 @@ import be.simplenotes.domain.security.PasswordHash import be.simplenotes.domain.security.SimpleJwt import be.simplenotes.domain.validation.UserValidations import be.simplenotes.persistence.repositories.UserRepository -import be.simplenotes.persistence.transactions.TransactionService import be.simplenotes.search.NoteSearcher import be.simplenotes.types.LoggedInUser import be.simplenotes.types.PersistedUser @@ -29,16 +28,13 @@ internal class UserServiceImpl( private val passwordHash: PasswordHash, private val jwt: SimpleJwt, private val searcher: NoteSearcher, - private val transactionService: TransactionService, ) : UserService { - override fun register(form: RegisterForm) = transactionService.use { - UserValidations.validateRegister(form) - .filterOrElse({ !userRepository.exists(it.username) }, { RegisterError.UserExists }) - .map { it.copy(password = passwordHash.crypt(it.password)) } - .map { userRepository.create(it) } - .leftIfNull { RegisterError.UserExists } - } + override fun register(form: RegisterForm) = UserValidations.validateRegister(form) + .filterOrElse({ !userRepository.exists(it.username) }, { RegisterError.UserExists }) + .map { it.copy(password = passwordHash.crypt(it.password)) } + .map { userRepository.create(it) } + .leftIfNull { RegisterError.UserExists } override fun login(form: LoginForm) = either.eager { UserValidations.validateLogin(form) @@ -50,18 +46,16 @@ internal class UserServiceImpl( .bind() } - override fun delete(form: DeleteForm) = transactionService.use { - either.eager { - val user = !UserValidations.validateDelete(form) - val persistedUser = !userRepository.find(user.username).rightIfNotNull { DeleteError.Unregistered } - !Either.conditionally( - passwordHash.verify(user.password, persistedUser.password), - { DeleteError.WrongPassword }, - { } - ) - !Either.conditionally(userRepository.delete(persistedUser.id), { DeleteError.Unregistered }, { }) - searcher.dropIndex(persistedUser.id) - } + override fun delete(form: DeleteForm) = either.eager { + val user = !UserValidations.validateDelete(form) + val persistedUser = !userRepository.find(user.username).rightIfNotNull { DeleteError.Unregistered } + !Either.conditionally( + passwordHash.verify(user.password, persistedUser.password), + { DeleteError.WrongPassword }, + { } + ) + !Either.conditionally(userRepository.delete(persistedUser.id), { DeleteError.Unregistered }, { }) + searcher.dropIndex(persistedUser.id) } } diff --git a/domain/test/UserServiceTest.kt b/domain/test/UserServiceTest.kt index 1f00845..3f7c7c9 100644 --- a/domain/test/UserServiceTest.kt +++ b/domain/test/UserServiceTest.kt @@ -9,7 +9,6 @@ import be.simplenotes.domain.security.UserJwtMapper import be.simplenotes.domain.testutils.isLeftOfType import be.simplenotes.domain.testutils.isRight import be.simplenotes.persistence.repositories.UserRepository -import be.simplenotes.persistence.transactions.TransactionService import be.simplenotes.types.PersistedUser import com.natpryce.hamkrest.assertion.assertThat import com.natpryce.hamkrest.equalTo @@ -23,16 +22,12 @@ internal class UserServiceTest { val passwordHash = BcryptPasswordHash(test = true) val jwtConfig = JwtConfig("a secret", 1, TimeUnit.HOURS) val simpleJwt = SimpleJwt(jwtConfig, UserJwtMapper()) - val noopTransactionService = object : TransactionService { - override fun use(block: () -> T) = block() - } val userService = UserServiceImpl( userRepository = userRepository, passwordHash = passwordHash, jwt = simpleJwt, searcher = mockk(), - transactionService = noopTransactionService ) @BeforeEach diff --git a/persistence/src/PersistenceModule.kt b/persistence/src/PersistenceModule.kt index ecd6171..ed76eb3 100644 --- a/persistence/src/PersistenceModule.kt +++ b/persistence/src/PersistenceModule.kt @@ -29,8 +29,8 @@ class PersistenceModule { val hikariConfig = HikariConfig().also { it.jdbcUrl = conf.jdbcUrl it.driverClassName = "org.h2.Driver" - it.username = conf.username - it.password = conf.password + it.username = "" + it.password = "" it.maximumPoolSize = conf.maximumPoolSize it.connectionTimeout = conf.connectionTimeout it.dataSourceProperties["CASE_INSENSITIVE_IDENTIFIERS"] = "TRUE" diff --git a/persistence/test/DbTest.kt b/persistence/test/DbTest.kt index 0d688ce..838216a 100644 --- a/persistence/test/DbTest.kt +++ b/persistence/test/DbTest.kt @@ -1,10 +1,9 @@ package be.simplenotes.persistence -import be.simplenotes.config.DataSourceConfig +import io.micronaut.context.ApplicationContext import io.micronaut.context.BeanContext import org.flywaydb.core.Flyway import org.junit.jupiter.api.AfterAll -import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.parallel.ResourceLock import javax.sql.DataSource @@ -12,25 +11,10 @@ import javax.sql.DataSource @ResourceLock("h2") abstract class DbTest { - val beanContext = BeanContext.build() + val beanContext = ApplicationContext.build().deduceEnvironment(false).environments("test").start() inline fun BeanContext.getBean(): T = getBean(T::class.java) - @BeforeAll - fun setComponent() { - beanContext - .registerSingleton( - DataSourceConfig( - jdbcUrl = "jdbc:h2:mem:regular;DB_CLOSE_DELAY=-1", - username = "h2", - password = "", - maximumPoolSize = 2, - connectionTimeout = 3000 - ) - ) - .start() - } - @BeforeEach fun beforeEach() { val migration = beanContext.getBean() diff --git a/search/build.gradle.kts b/search/build.gradle.kts index 6fb52c6..48de183 100644 --- a/search/build.gradle.kts +++ b/search/build.gradle.kts @@ -8,6 +8,7 @@ plugins { dependencies { implementation(project(":types")) + implementation(project(":config")) implementation(Libs.Lucene.core) implementation(Libs.Lucene.queryParser) diff --git a/search/src/Extractors.kt b/search/src/Extractors.kt index a45a7ab..4b43553 100644 --- a/search/src/Extractors.kt +++ b/search/src/Extractors.kt @@ -7,18 +7,15 @@ import org.apache.lucene.document.Field import org.apache.lucene.document.StringField import org.apache.lucene.document.TextField -internal fun PersistedNote.toDocument(): Document { - val note = this - return Document().apply { - // non searchable fields - add(StringField(uuidField, UuidFieldConverter.toDoc(note.uuid), Field.Store.YES)) - add(StringField(updatedAtField, LocalDateTimeFieldConverter.toDoc(note.updatedAt), Field.Store.YES)) +internal fun PersistedNote.toDocument() = Document().apply { + // non searchable fields + add(StringField(uuidField, UuidFieldConverter.toDoc(uuid), Field.Store.YES)) + add(StringField(updatedAtField, LocalDateTimeFieldConverter.toDoc(updatedAt), Field.Store.YES)) - // searchable fields - add(TextField(titleField, note.meta.title, Field.Store.YES)) - add(TextField(tagsField, TagsFieldConverter.toDoc(note.meta.tags), Field.Store.YES)) - add(TextField(contentField, note.markdown, Field.Store.YES)) - } + // searchable fields + add(TextField(titleField, title, Field.Store.YES)) + add(TextField(tagsField, TagsFieldConverter.toDoc(tags), Field.Store.YES)) + add(TextField(contentField, markdown, Field.Store.YES)) } internal fun Document.toNoteMeta() = PersistedNoteMetadata( diff --git a/search/src/NoteSearcherImpl.kt b/search/src/NoteSearcherImpl.kt index 26b7949..ca6e787 100644 --- a/search/src/NoteSearcherImpl.kt +++ b/search/src/NoteSearcherImpl.kt @@ -16,12 +16,7 @@ import javax.inject.Named import javax.inject.Singleton @Singleton -internal class NoteSearcherImpl( - @Named("search-index") - basePath: Path, -) : NoteSearcher { - - constructor() : this(Path.of("/tmp", "lucene")) +internal class NoteSearcherImpl(@Named("search-index") basePath: Path) : NoteSearcher { private val baseFile = basePath.toFile() diff --git a/search/src/SearchModule.kt b/search/src/SearchModule.kt index 4ab7866..fd5f7bc 100644 --- a/search/src/SearchModule.kt +++ b/search/src/SearchModule.kt @@ -1,5 +1,6 @@ package be.simplenotes.search +import be.simplenotes.config.DataConfig import io.micronaut.context.annotation.Factory import io.micronaut.context.annotation.Prototype import java.nio.file.Path @@ -10,5 +11,5 @@ class SearchModule { @Named("search-index") @Prototype - internal fun luceneIndex() = Path.of(".lucene") + internal fun luceneIndex(dataConfig: DataConfig) = Path.of(dataConfig.dataDir).resolve("index") } diff --git a/search/test/NoteSearcherImplTest.kt b/search/test/NoteSearcherImplTest.kt index 5cc0778..dc4eeca 100644 --- a/search/test/NoteSearcherImplTest.kt +++ b/search/test/NoteSearcherImplTest.kt @@ -1,6 +1,5 @@ package be.simplenotes.search -import be.simplenotes.types.NoteMetadata import be.simplenotes.types.PersistedNote import be.simplenotes.types.PersistedNoteMetadata import org.assertj.core.api.Assertions.assertThat @@ -9,6 +8,7 @@ import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.parallel.ResourceLock +import java.nio.file.Path import java.time.LocalDateTime import java.util.* @@ -16,7 +16,7 @@ import java.util.* internal class NoteSearcherImplTest { // region setup - private val searcher = NoteSearcherImpl() + private val searcher = NoteSearcherImpl(Path.of("/tmp", "lucene")) private fun index( title: String, @@ -25,11 +25,12 @@ internal class NoteSearcherImplTest { uuid: UUID = UUID.randomUUID(), ): PersistedNote { val note = PersistedNote( - NoteMetadata(title, tags), + title = title, + tags = tags, markdown = content, html = "", - LocalDateTime.MIN, - uuid, + updatedAt = LocalDateTime.MIN, + uuid = uuid, public = false ) searcher.indexNote(1, note) @@ -150,7 +151,7 @@ internal class NoteSearcherImplTest { @Test fun `update index`() { val note = index("first") - searcher.updateIndex(1, note.copy(meta = note.meta.copy(title = "new"))) + searcher.updateIndex(1, note.copy(title = "new")) assertThat(search("first")).isEmpty() assertThat(search("new")).hasSize(1) } diff --git a/views/src/NoteView.kt b/views/src/NoteView.kt index b98760c..54b5d48 100644 --- a/views/src/NoteView.kt +++ b/views/src/NoteView.kt @@ -121,7 +121,7 @@ class NoteView(@Named("styles") styles: String) : View(styles) { } fun renderedNote(loggedInUser: LoggedInUser?, note: PersistedNote, shared: Boolean) = renderPage( - note.meta.title, + note.title, loggedInUser = loggedInUser, scripts = listOf("/highlight.10.1.2.js", "/init-highlight.0.0.1.js") ) { @@ -136,9 +136,9 @@ class NoteView(@Named("styles") styles: String) : View(styles) { } div("flex items-center justify-between mb-4") { - h1("text-3xl fond-bold underline") { +note.meta.title } + h1("text-3xl fond-bold underline") { +note.title } span("space-x-2") { - note.meta.tags.forEach { + note.tags.forEach { a(href = "/notes?tag=$it", classes = "tag") { +"#$it" }