Compare commits
16 Commits
jigsaw
...
cd9fdd28e8
| Author | SHA1 | Date | |
|---|---|---|---|
| cd9fdd28e8 | |||
| c3fc6a4e88 | |||
| cb58a4fbe0 | |||
| 64059984d3 | |||
| fdc8d34f82 | |||
| 95ec674eb8 | |||
| ea7be84ec3 | |||
| c709f2b44d | |||
| 7995a0b3e0 | |||
| bfd562bc60 | |||
| 4fb85a52e4 | |||
| e64352f54c | |||
| c2c03e415e | |||
| 0260bea951 | |||
| 8b8dbd6fe5 | |||
| 536c6e7b79 |
+5
-97
@@ -1,24 +1,6 @@
|
|||||||
# Java
|
# Gradle
|
||||||
.mtj.tmp/
|
build/
|
||||||
*.class
|
.gradle
|
||||||
*.jar
|
|
||||||
*.war
|
|
||||||
*.ear
|
|
||||||
*.nar
|
|
||||||
hs_err_pid*
|
|
||||||
|
|
||||||
# Maven
|
|
||||||
target/
|
|
||||||
pom.xml.tag
|
|
||||||
pom.xml.releaseBackup
|
|
||||||
pom.xml.versionsBackup
|
|
||||||
pom.xml.next
|
|
||||||
pom.xml.bak
|
|
||||||
release.properties
|
|
||||||
dependency-reduced-pom.xml
|
|
||||||
buildNumber.properties
|
|
||||||
.mvn/timing.properties
|
|
||||||
.mvn/wrapper/maven-wrapper.jar
|
|
||||||
|
|
||||||
# IntelliJ
|
# IntelliJ
|
||||||
out/
|
out/
|
||||||
@@ -28,11 +10,8 @@ out/
|
|||||||
*.ipr
|
*.ipr
|
||||||
*.iws
|
*.iws
|
||||||
|
|
||||||
# Vue
|
|
||||||
node_modules
|
|
||||||
/dist
|
|
||||||
|
|
||||||
# Local env files
|
# Local env files
|
||||||
|
.env
|
||||||
.env.local
|
.env.local
|
||||||
.env.*.local
|
.env.*.local
|
||||||
|
|
||||||
@@ -49,85 +28,13 @@ pids
|
|||||||
*.seed
|
*.seed
|
||||||
*.pid.lock
|
*.pid.lock
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
||||||
lib-cov
|
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
|
||||||
coverage
|
|
||||||
|
|
||||||
# nyc test coverage
|
|
||||||
.nyc_output
|
|
||||||
|
|
||||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
|
||||||
.grunt
|
|
||||||
|
|
||||||
# Bower dependency directory (https://bower.io/)
|
|
||||||
bower_components
|
|
||||||
|
|
||||||
# node-waf configuration
|
|
||||||
.lock-wscript
|
|
||||||
|
|
||||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
||||||
build/Release
|
|
||||||
|
|
||||||
# Dependency directories
|
# Dependency directories
|
||||||
node_modules/
|
node_modules/
|
||||||
jspm_packages/
|
jspm_packages/
|
||||||
|
|
||||||
# TypeScript v1 declaration files
|
|
||||||
typings/
|
|
||||||
|
|
||||||
# Optional npm cache directory
|
|
||||||
.npm
|
|
||||||
|
|
||||||
# Optional eslint cache
|
|
||||||
.eslintcache
|
|
||||||
|
|
||||||
# Optional REPL history
|
|
||||||
.node_repl_history
|
|
||||||
|
|
||||||
# Output of 'npm pack'
|
|
||||||
*.tgz
|
|
||||||
|
|
||||||
# Yarn Integrity file
|
# Yarn Integrity file
|
||||||
.yarn-integrity
|
.yarn-integrity
|
||||||
|
|
||||||
# dotenv environment variables file
|
|
||||||
.env
|
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
|
||||||
.cache
|
|
||||||
|
|
||||||
# next.js build output
|
|
||||||
.next
|
|
||||||
|
|
||||||
# nuxt.js build output
|
|
||||||
.nuxt
|
|
||||||
|
|
||||||
# Nuxt generate
|
|
||||||
dist
|
|
||||||
|
|
||||||
# vuepress build output
|
|
||||||
.vuepress/dist
|
|
||||||
|
|
||||||
# Serverless directories
|
|
||||||
.serverless
|
|
||||||
|
|
||||||
# IDE / Editor
|
|
||||||
.idea
|
|
||||||
|
|
||||||
# Service worker
|
|
||||||
sw.*
|
|
||||||
*.private.env.json
|
|
||||||
|
|
||||||
# Certificates
|
|
||||||
data/
|
|
||||||
letsencrypt/
|
|
||||||
|
|
||||||
# generated resources
|
|
||||||
simplenotes-app/src/main/resources/css-manifest.json
|
|
||||||
simplenotes-app/src/main/resources/static/styles*
|
|
||||||
|
|
||||||
# h2 db
|
# h2 db
|
||||||
*.db
|
*.db
|
||||||
|
|
||||||
@@ -136,3 +43,4 @@ simplenotes-app/src/main/resources/static/styles*
|
|||||||
|
|
||||||
# python
|
# python
|
||||||
__pycache__
|
__pycache__
|
||||||
|
|
||||||
|
|||||||
+15
-28
@@ -1,29 +1,3 @@
|
|||||||
FROM maven:3.6.3-jdk-14 as builder
|
|
||||||
|
|
||||||
WORKDIR /tmp
|
|
||||||
|
|
||||||
# Cache dependencies
|
|
||||||
COPY pom.xml .
|
|
||||||
COPY simplenotes-test-resources/pom.xml simplenotes-test-resources/pom.xml
|
|
||||||
COPY simplenotes-types/pom.xml simplenotes-types/pom.xml
|
|
||||||
COPY simplenotes-config/pom.xml simplenotes-config/pom.xml
|
|
||||||
COPY simplenotes-persistance/pom.xml simplenotes-persistance/pom.xml
|
|
||||||
COPY simplenotes-search/pom.xml simplenotes-search/pom.xml
|
|
||||||
COPY simplenotes-domain/pom.xml simplenotes-domain/pom.xml
|
|
||||||
COPY simplenotes-app/pom.xml simplenotes-app/pom.xml
|
|
||||||
|
|
||||||
RUN mvn verify clean --fail-never
|
|
||||||
|
|
||||||
COPY simplenotes-test-resources/src simplenotes-test-resources/src
|
|
||||||
COPY simplenotes-types/src simplenotes-types/src
|
|
||||||
COPY simplenotes-config/src simplenotes-config/src
|
|
||||||
COPY simplenotes-persistance/src simplenotes-persistance/src
|
|
||||||
COPY simplenotes-search/src simplenotes-search/src
|
|
||||||
COPY simplenotes-domain/src simplenotes-domain/src
|
|
||||||
COPY simplenotes-app/src simplenotes-app/src
|
|
||||||
|
|
||||||
RUN mvn -Dstyle.color=always package
|
|
||||||
|
|
||||||
FROM openjdk:14-alpine as jdkbuilder
|
FROM openjdk:14-alpine as jdkbuilder
|
||||||
|
|
||||||
RUN apk add --no-cache binutils
|
RUN apk add --no-cache binutils
|
||||||
@@ -46,8 +20,21 @@ RUN chown -R $APPLICATION_USER /app
|
|||||||
|
|
||||||
USER $APPLICATION_USER
|
USER $APPLICATION_USER
|
||||||
|
|
||||||
COPY --from=builder /tmp/simplenotes-app/target/simplenotes-app-*.jar /app/simplenotes.jar
|
|
||||||
COPY --from=jdkbuilder /myjdk /myjdk
|
COPY --from=jdkbuilder /myjdk /myjdk
|
||||||
|
COPY simplenotes-app/build/libs/simplenotes-app-with-dependencies*.jar /app/simplenotes.jar
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
CMD ["/myjdk/bin/java", "-server", "-XX:+UnlockExperimentalVMOptions", "-Xms64m", "-Xmx256m", "-XX:+UseG1GC", "-XX:MaxGCPauseMillis=100", "-XX:+UseStringDeduplication", "-jar", "simplenotes.jar"]
|
CMD [ \
|
||||||
|
"/myjdk/bin/java", \
|
||||||
|
"--add-opens", \
|
||||||
|
"java.base/java.nio=ALL-UNNAMED", \
|
||||||
|
"-server", \
|
||||||
|
"-XX:+UnlockExperimentalVMOptions", \
|
||||||
|
"-Xms64m", \
|
||||||
|
"-Xmx256m", \
|
||||||
|
"-XX:+UseG1GC", \
|
||||||
|
"-XX:MaxGCPauseMillis=100", \
|
||||||
|
"-XX:+UseStringDeduplication", \
|
||||||
|
"-jar", \
|
||||||
|
"simplenotes.jar" \
|
||||||
|
]
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
org.gradle.caching=true
|
||||||
|
org.gradle.parallel=true
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
plugins {
|
||||||
|
`kotlin-dsl`
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlinDslPluginOptions {
|
||||||
|
experimentalWarning.set(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
gradlePluginPortal()
|
||||||
|
maven { setUrl("https://kotlin.bintray.com/kotlinx") }
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.10")
|
||||||
|
implementation("org.jetbrains.kotlin:kotlin-serialization:1.4.10")
|
||||||
|
implementation("com.github.jengelman.gradle.plugins:shadow:6.1.0")
|
||||||
|
implementation("org.jlleitschuh.gradle:ktlint-gradle:9.4.1")
|
||||||
|
implementation("com.github.ben-manes:gradle-versions-plugin:0.28.0")
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package be.simplenotes
|
||||||
|
|
||||||
|
import org.gradle.api.DefaultTask
|
||||||
|
import org.gradle.api.GradleException
|
||||||
|
import org.gradle.api.tasks.*
|
||||||
|
import org.gradle.kotlin.dsl.getByType
|
||||||
|
import java.io.File
|
||||||
|
import java.lang.ProcessBuilder.Redirect.PIPE
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
|
open class CssTask : DefaultTask() {
|
||||||
|
|
||||||
|
private val root = project.parent!!.rootDir
|
||||||
|
|
||||||
|
private val viewsProject = project
|
||||||
|
.parent
|
||||||
|
?.project(":simplenotes-views")
|
||||||
|
?: error("Missing :simplenotes-views")
|
||||||
|
|
||||||
|
@get:InputDirectory
|
||||||
|
val templatesDir = viewsProject.extensions
|
||||||
|
.getByType<SourceSetContainer>()
|
||||||
|
.asMap.getOrElse("main") { error("main sources not found") }
|
||||||
|
.allSource.srcDirs
|
||||||
|
.find { it.endsWith("kotlin") }
|
||||||
|
?: error("kotlin sources not found")
|
||||||
|
|
||||||
|
private val yarnRoot = File(project.rootDir, "css")
|
||||||
|
|
||||||
|
@get:InputDirectory
|
||||||
|
val postCssDir = File(project.rootDir, "css/src")
|
||||||
|
|
||||||
|
@get:InputFiles
|
||||||
|
val postCssConfig = listOf(
|
||||||
|
"tailwind.config.js",
|
||||||
|
"postcss.config.js",
|
||||||
|
"package.json"
|
||||||
|
).map { File(yarnRoot, it) }
|
||||||
|
|
||||||
|
@get:OutputDirectory
|
||||||
|
val outputRootDir = File(project.buildDir, "generated-resources/css")
|
||||||
|
|
||||||
|
private val cssIndex = File(postCssDir, "styles.pcss")
|
||||||
|
|
||||||
|
private val cssOutput = File(outputRootDir, "static/styles.css")
|
||||||
|
private val manifestOutput = File(outputRootDir, "css-manifest.json")
|
||||||
|
|
||||||
|
private val purgeGlob = "$templatesDir/**/*.kt"
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
fun generateCss() {
|
||||||
|
// TODO: auto yarn install ?
|
||||||
|
|
||||||
|
outputRootDir.deleteRecursively()
|
||||||
|
|
||||||
|
ProcessBuilder("yarn", "run", "postcss", "build", "$cssIndex", "--output", "$cssOutput")
|
||||||
|
.apply {
|
||||||
|
environment().let {
|
||||||
|
it["MANIFEST"] = "$manifestOutput"
|
||||||
|
it["NODE_ENV"] = "production"
|
||||||
|
it["PURGE"] = purgeGlob
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.redirectOutput(PIPE)
|
||||||
|
.redirectError(PIPE)
|
||||||
|
.directory(yarnRoot)
|
||||||
|
.start()
|
||||||
|
.apply {
|
||||||
|
thread { inputStream.use { it.copyTo(System.out) } }
|
||||||
|
thread { errorStream.use { it.copyTo(System.out) } }
|
||||||
|
waitFor(30, TimeUnit.SECONDS)
|
||||||
|
if (exitValue() != 0) throw GradleException(":/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
@file:Suppress("SpellCheckingInspection")
|
||||||
|
|
||||||
|
package be.simplenotes
|
||||||
|
|
||||||
|
object Libs {
|
||||||
|
const val arrowCoreData = "io.arrow-kt:arrow-core-data:0.11.0"
|
||||||
|
const val commonsCompress = "org.apache.commons:commons-compress:1.20"
|
||||||
|
const val flexmark = "com.vladsch.flexmark:flexmark:0.62.2"
|
||||||
|
const val flexmarkGfmTasklist = "com.vladsch.flexmark:flexmark-ext-gfm-tasklist:0.62.2"
|
||||||
|
const val flywayCore = "org.flywaydb:flyway-core:6.5.4"
|
||||||
|
const val h2 = "com.h2database:h2:1.4.200"
|
||||||
|
const val hikariCP = "com.zaxxer:HikariCP:3.4.3"
|
||||||
|
const val http4kCore = "org.http4k:http4k-core:3.268.0"
|
||||||
|
const val javaJwt = "com.auth0:java-jwt:3.10.3"
|
||||||
|
const val javaxServlet = "javax.servlet:javax.servlet-api:4.0.1"
|
||||||
|
const val jbcrypt = "org.mindrot:jbcrypt:0.4"
|
||||||
|
const val jettyServer = "org.eclipse.jetty:jetty-server:9.4.32.v20200930"
|
||||||
|
const val jettyServlet = "org.eclipse.jetty:jetty-servlet:9.4.32.v20200930"
|
||||||
|
const val koinCore = "org.koin:koin-core:2.1.6"
|
||||||
|
const val konform = "io.konform:konform-jvm:0.2.0"
|
||||||
|
const val kotlinxHtml = "org.jetbrains.kotlinx:kotlinx-html-jvm:0.7.1"
|
||||||
|
const val kotlinxSerializationJson = "org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.0.0"
|
||||||
|
const val ktormCore = "me.liuwj.ktorm:ktorm-core:3.0.0"
|
||||||
|
const val ktormMysql = "me.liuwj.ktorm:ktorm-support-mysql:3.0.0"
|
||||||
|
const val logbackClassic = "ch.qos.logback:logback-classic:1.2.3"
|
||||||
|
const val luceneAnalyzersCommon = "org.apache.lucene:lucene-analyzers-common:8.6.1"
|
||||||
|
const val luceneCore = "org.apache.lucene:lucene-core:8.6.1"
|
||||||
|
const val luceneQueryParser = "org.apache.lucene:lucene-queryparser:8.6.1"
|
||||||
|
const val mapstruct = "org.mapstruct:mapstruct:1.4.1.Final"
|
||||||
|
const val mapstructProcessor = "org.mapstruct:mapstruct-processor:1.4.1.Final"
|
||||||
|
const val mariadbClient = "org.mariadb.jdbc:mariadb-java-client:2.6.2"
|
||||||
|
const val owaspHtmlSanitizer = "com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20200713.1"
|
||||||
|
const val prettytime ="org.ocpsoft.prettytime:prettytime:4.0.5.Final"
|
||||||
|
const val slf4jApi = "org.slf4j:slf4j-api:1.7.25"
|
||||||
|
const val snakeyaml = "org.yaml:snakeyaml:1.26"
|
||||||
|
|
||||||
|
const val assertJ = "org.assertj:assertj-core:3.16.1"
|
||||||
|
const val hamkrest = "com.natpryce:hamkrest:1.7.0.3"
|
||||||
|
const val http4kTestingHamkrest = "org.http4k:http4k-testing-hamkrest:3.268.0"
|
||||||
|
const val junit = "org.junit.jupiter:junit-jupiter:5.6.2"
|
||||||
|
const val mockk = "io.mockk:mockk:1.10.0"
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package be.simplenotes
|
||||||
|
|
||||||
|
import org.gradle.kotlin.dsl.register
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
java apply false
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register<CssTask>("css")
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
val main by getting
|
||||||
|
val root = file("$buildDir/generated-resources/css")
|
||||||
|
main.resources.srcDir(root)
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package be.simplenotes
|
||||||
|
|
||||||
|
tasks.create("dockerBuild") {
|
||||||
|
dependsOn("package")
|
||||||
|
|
||||||
|
doLast {
|
||||||
|
exec {
|
||||||
|
commandLine("docker", "build", "-t", "hubv/simplenotes:latest", ".")
|
||||||
|
workingDir(rootProject.projectDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.create("dockerPush") {
|
||||||
|
dependsOn("dockerBuild")
|
||||||
|
|
||||||
|
doLast {
|
||||||
|
exec {
|
||||||
|
commandLine("docker", "push", "hubv/simplenotes:latest")
|
||||||
|
workingDir(rootProject.projectDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package be.simplenotes
|
||||||
|
|
||||||
|
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("com.github.johnrengelman.shadow")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType<ShadowJar> {
|
||||||
|
|
||||||
|
archiveAppendix.set("with-dependencies")
|
||||||
|
manifest.attributes["Main-Class"] = "be.simplenotes.app.SimpleNotesKt"
|
||||||
|
|
||||||
|
mergeServiceFiles()
|
||||||
|
|
||||||
|
File(rootProject.projectDir, "buildSrc/src/main/resources/exclusions")
|
||||||
|
.listFiles()!!
|
||||||
|
.flatMap {
|
||||||
|
it.readLines()
|
||||||
|
.asSequence()
|
||||||
|
.map { it.trim() }
|
||||||
|
.filterNot { it.isBlank() }
|
||||||
|
.filterNot { it.startsWith("#") }
|
||||||
|
.asIterable()
|
||||||
|
}.forEach { exclude(it) }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.create("package") {
|
||||||
|
tasks.getByName("build").dependsOn("package")
|
||||||
|
|
||||||
|
dependsOn("shadowJar")
|
||||||
|
dependsOn("css")
|
||||||
|
|
||||||
|
doLast {
|
||||||
|
println("SimpleNotes Packaged !")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package be.simplenotes
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("be.simplenotes.java-convention")
|
||||||
|
id("be.simplenotes.kotlin-convention")
|
||||||
|
id("be.simplenotes.junit-convention")
|
||||||
|
id("org.jlleitschuh.gradle.ktlint")
|
||||||
|
id("com.github.ben-manes.versions")
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package be.simplenotes
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
java
|
||||||
|
`java-library`
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
mavenCentral()
|
||||||
|
jcenter()
|
||||||
|
maven { url = uri("https://dl.bintray.com/arrow-kt/arrow-kt/") }
|
||||||
|
maven { url = uri("https://kotlin.bintray.com/kotlinx") }
|
||||||
|
}
|
||||||
|
|
||||||
|
group = "be.simplenotes"
|
||||||
|
version = "1.0-SNAPSHOT"
|
||||||
|
|
||||||
|
java {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_14
|
||||||
|
targetCompatibility = JavaVersion.VERSION_14
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType<JavaCompile> {
|
||||||
|
options.encoding = "UTF-8"
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package be.simplenotes
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
java apply false
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType<Test> {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
val test by getting
|
||||||
|
test.resources.srcDir("${rootProject.projectDir}/simplenotes-test-resources/src/test/resources")
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package be.simplenotes
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("stdlib-jdk8"))
|
||||||
|
implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.4.10"))
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType<KotlinCompile> {
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "14"
|
||||||
|
javaParameters = true
|
||||||
|
freeCompilerArgs = listOf(
|
||||||
|
"-Xinline-classes",
|
||||||
|
"-Xno-param-assertions",
|
||||||
|
"-Xno-call-assertions",
|
||||||
|
"-Xno-receiver-assertions"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package be.simplenotes
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("plugin.serialization")
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
META-INF/maven/**
|
||||||
|
META-INF/proguard/**
|
||||||
|
META-INF/*.kotlin_module
|
||||||
|
META-INF/DEPENDENCIES*
|
||||||
|
META-INF/NOTICE*
|
||||||
|
META-INF/LICENSE*
|
||||||
|
LICENSE*
|
||||||
|
META-INF/README*
|
||||||
|
META-INF/native-image/**
|
||||||
|
|
||||||
|
# Jetty
|
||||||
|
about.html
|
||||||
|
jetty-dir.css
|
||||||
|
server-ssl-cert.pem
|
||||||
@@ -0,0 +1,261 @@
|
|||||||
|
com/google/common/util/**
|
||||||
|
com/google/common/eventbus/**
|
||||||
|
com/google/common/reflect/**
|
||||||
|
com/google/common/escape/**
|
||||||
|
com/google/common/graph/**
|
||||||
|
com/google/common/html/**
|
||||||
|
com/google/common/hash/**
|
||||||
|
com/google/common/xml/**
|
||||||
|
com/google/common/io/**
|
||||||
|
com/google/common/cache/**
|
||||||
|
com/google/common/net/**
|
||||||
|
|
||||||
|
# Collections
|
||||||
|
com/google/common/collect/AbstractBiMap$1.class
|
||||||
|
com/google/common/collect/AbstractBiMap$BiMapEntry.class
|
||||||
|
com/google/common/collect/AbstractBiMap$EntrySet.class
|
||||||
|
com/google/common/collect/AbstractBiMap$Inverse.class
|
||||||
|
com/google/common/collect/AbstractBiMap$KeySet.class
|
||||||
|
com/google/common/collect/AbstractBiMap$ValueSet.class
|
||||||
|
com/google/common/collect/AbstractBiMap.class
|
||||||
|
com/google/common/collect/AbstractSortedKeySortedSetMultimap.class
|
||||||
|
com/google/common/collect/AbstractSortedMultiset$1DescendingMultisetImpl.class
|
||||||
|
com/google/common/collect/AbstractSortedMultiset.class
|
||||||
|
com/google/common/collect/AbstractTable$1.class
|
||||||
|
com/google/common/collect/AbstractTable$CellSet.class
|
||||||
|
com/google/common/collect/AbstractTable$Values.class
|
||||||
|
com/google/common/collect/AbstractTable.class
|
||||||
|
com/google/common/collect/ArrayListMultimap.class
|
||||||
|
com/google/common/collect/ArrayListMultimapGwtSerializationDependencies.class
|
||||||
|
com/google/common/collect/ArrayTable$1.class
|
||||||
|
com/google/common/collect/ArrayTable$2.class
|
||||||
|
com/google/common/collect/ArrayTable$3.class
|
||||||
|
com/google/common/collect/ArrayTable$ArrayMap$1.class
|
||||||
|
com/google/common/collect/ArrayTable$ArrayMap$2.class
|
||||||
|
com/google/common/collect/ArrayTable$ArrayMap.class
|
||||||
|
com/google/common/collect/ArrayTable$Column.class
|
||||||
|
com/google/common/collect/ArrayTable$ColumnMap.class
|
||||||
|
com/google/common/collect/ArrayTable$Row.class
|
||||||
|
com/google/common/collect/ArrayTable$RowMap.class
|
||||||
|
com/google/common/collect/ArrayTable.class
|
||||||
|
com/google/common/collect/ClassToInstanceMap.class
|
||||||
|
com/google/common/collect/CompactHashMap$1.class
|
||||||
|
com/google/common/collect/CompactHashMap$2.class
|
||||||
|
com/google/common/collect/CompactHashMap$3.class
|
||||||
|
com/google/common/collect/CompactHashMap$EntrySetView.class
|
||||||
|
com/google/common/collect/CompactHashMap$Itr.class
|
||||||
|
com/google/common/collect/CompactHashMap$KeySetView.class
|
||||||
|
com/google/common/collect/CompactHashMap$MapEntry.class
|
||||||
|
com/google/common/collect/CompactHashMap$ValuesView.class
|
||||||
|
com/google/common/collect/CompactHashMap.class
|
||||||
|
com/google/common/collect/CompactHashSet$1.class
|
||||||
|
com/google/common/collect/CompactHashSet.class
|
||||||
|
com/google/common/collect/CompactLinkedHashMap$1EntrySetImpl.class
|
||||||
|
com/google/common/collect/CompactLinkedHashMap$1KeySetImpl.class
|
||||||
|
com/google/common/collect/CompactLinkedHashMap$1ValuesImpl.class
|
||||||
|
com/google/common/collect/CompactLinkedHashMap.class
|
||||||
|
com/google/common/collect/CompactLinkedHashSet.class
|
||||||
|
com/google/common/collect/Comparators.class
|
||||||
|
com/google/common/collect/ComputationException.class
|
||||||
|
com/google/common/collect/ConcurrentHashMultiset$1.class
|
||||||
|
com/google/common/collect/ConcurrentHashMultiset$2.class
|
||||||
|
com/google/common/collect/ConcurrentHashMultiset$3.class
|
||||||
|
com/google/common/collect/ConcurrentHashMultiset$EntrySet.class
|
||||||
|
com/google/common/collect/ConcurrentHashMultiset$FieldSettersHolder.class
|
||||||
|
com/google/common/collect/ConcurrentHashMultiset.class
|
||||||
|
com/google/common/collect/DenseImmutableTable$1.class
|
||||||
|
com/google/common/collect/DenseImmutableTable$Column.class
|
||||||
|
com/google/common/collect/DenseImmutableTable$ColumnMap.class
|
||||||
|
com/google/common/collect/DenseImmutableTable$ImmutableArrayMap$1.class
|
||||||
|
com/google/common/collect/DenseImmutableTable$ImmutableArrayMap.class
|
||||||
|
com/google/common/collect/DenseImmutableTable$Row.class
|
||||||
|
com/google/common/collect/DenseImmutableTable$RowMap.class
|
||||||
|
com/google/common/collect/DenseImmutableTable.class
|
||||||
|
com/google/common/collect/DescendingImmutableSortedMultiset.class
|
||||||
|
com/google/common/collect/DescendingMultiset$1EntrySetImpl.class
|
||||||
|
com/google/common/collect/DescendingMultiset.class
|
||||||
|
com/google/common/collect/EnumBiMap.class
|
||||||
|
com/google/common/collect/EnumHashBiMap.class
|
||||||
|
com/google/common/collect/EnumMultiset$1.class
|
||||||
|
com/google/common/collect/EnumMultiset$2$1.class
|
||||||
|
com/google/common/collect/EnumMultiset$2.class
|
||||||
|
com/google/common/collect/EnumMultiset$Itr.class
|
||||||
|
com/google/common/collect/EnumMultiset.class
|
||||||
|
com/google/common/collect/EvictingQueue.class
|
||||||
|
com/google/common/collect/ForwardingBlockingDeque.class
|
||||||
|
com/google/common/collect/ForwardingDeque.class
|
||||||
|
com/google/common/collect/ForwardingImmutableCollection.class
|
||||||
|
com/google/common/collect/ForwardingImmutableList.class
|
||||||
|
com/google/common/collect/ForwardingImmutableMap.class
|
||||||
|
com/google/common/collect/ForwardingImmutableSet.class
|
||||||
|
com/google/common/collect/ForwardingIterator.class
|
||||||
|
com/google/common/collect/ForwardingListIterator.class
|
||||||
|
com/google/common/collect/ForwardingListMultimap.class
|
||||||
|
com/google/common/collect/ForwardingNavigableMap$StandardDescendingMap$1.class
|
||||||
|
com/google/common/collect/ForwardingNavigableMap$StandardDescendingMap.class
|
||||||
|
com/google/common/collect/ForwardingNavigableMap$StandardNavigableKeySet.class
|
||||||
|
com/google/common/collect/ForwardingNavigableMap.class
|
||||||
|
com/google/common/collect/ForwardingQueue.class
|
||||||
|
com/google/common/collect/ForwardingSetMultimap.class
|
||||||
|
com/google/common/collect/ForwardingSortedMultiset$StandardDescendingMultiset.class
|
||||||
|
com/google/common/collect/ForwardingSortedMultiset$StandardElementSet.class
|
||||||
|
com/google/common/collect/ForwardingSortedMultiset.class
|
||||||
|
com/google/common/collect/ForwardingSortedSetMultimap.class
|
||||||
|
com/google/common/collect/ForwardingTable.class
|
||||||
|
com/google/common/collect/GeneralRange.class
|
||||||
|
com/google/common/collect/GwtTransient.class
|
||||||
|
com/google/common/collect/HashBasedTable$Factory.class
|
||||||
|
com/google/common/collect/HashBasedTable.class
|
||||||
|
com/google/common/collect/HashBiMap$1$MapEntry.class
|
||||||
|
com/google/common/collect/HashBiMap$1.class
|
||||||
|
com/google/common/collect/HashBiMap$BiEntry.class
|
||||||
|
com/google/common/collect/HashBiMap$Inverse$1$InverseEntry.class
|
||||||
|
com/google/common/collect/HashBiMap$Inverse$1.class
|
||||||
|
com/google/common/collect/HashBiMap$Inverse$InverseKeySet$1.class
|
||||||
|
com/google/common/collect/HashBiMap$Inverse$InverseKeySet.class
|
||||||
|
com/google/common/collect/HashBiMap$Inverse.class
|
||||||
|
com/google/common/collect/HashBiMap$InverseSerializedForm.class
|
||||||
|
com/google/common/collect/HashBiMap$Itr.class
|
||||||
|
com/google/common/collect/HashBiMap$KeySet$1.class
|
||||||
|
com/google/common/collect/HashBiMap$KeySet.class
|
||||||
|
com/google/common/collect/HashBiMap.class
|
||||||
|
com/google/common/collect/HashMultimap.class
|
||||||
|
com/google/common/collect/HashMultimapGwtSerializationDependencies.class
|
||||||
|
com/google/common/collect/ImmutableClassToInstanceMap$1.class
|
||||||
|
com/google/common/collect/ImmutableClassToInstanceMap$Builder.class
|
||||||
|
com/google/common/collect/ImmutableClassToInstanceMap.class
|
||||||
|
com/google/common/collect/ImmutableSortedMultiset$Builder.class
|
||||||
|
com/google/common/collect/ImmutableSortedMultiset$SerializedForm.class
|
||||||
|
com/google/common/collect/ImmutableSortedMultiset.class
|
||||||
|
com/google/common/collect/ImmutableSortedMultisetFauxverideShim.class
|
||||||
|
com/google/common/collect/ImmutableTable$1.class
|
||||||
|
com/google/common/collect/ImmutableTable$Builder.class
|
||||||
|
com/google/common/collect/ImmutableTable$CollectorState.class
|
||||||
|
com/google/common/collect/ImmutableTable$MutableCell.class
|
||||||
|
com/google/common/collect/ImmutableTable$SerializedForm.class
|
||||||
|
com/google/common/collect/ImmutableTable.class
|
||||||
|
com/google/common/collect/Interner.class
|
||||||
|
com/google/common/collect/Interners$1.class
|
||||||
|
com/google/common/collect/Interners$InternerBuilder.class
|
||||||
|
com/google/common/collect/Interners$InternerFunction.class
|
||||||
|
com/google/common/collect/Interners$InternerImpl.class
|
||||||
|
com/google/common/collect/Interners.class
|
||||||
|
com/google/common/collect/LinkedHashMultimap$1.class
|
||||||
|
com/google/common/collect/LinkedHashMultimap$ValueEntry.class
|
||||||
|
com/google/common/collect/LinkedHashMultimap$ValueSet$1.class
|
||||||
|
com/google/common/collect/LinkedHashMultimap$ValueSet.class
|
||||||
|
com/google/common/collect/LinkedHashMultimap$ValueSetLink.class
|
||||||
|
com/google/common/collect/LinkedHashMultimap.class
|
||||||
|
com/google/common/collect/LinkedHashMultimapGwtSerializationDependencies.class
|
||||||
|
com/google/common/collect/LinkedListMultimap$1.class
|
||||||
|
com/google/common/collect/LinkedListMultimap$1EntriesImpl.class
|
||||||
|
com/google/common/collect/LinkedListMultimap$1KeySetImpl.class
|
||||||
|
com/google/common/collect/LinkedListMultimap$1ValuesImpl$1.class
|
||||||
|
com/google/common/collect/LinkedListMultimap$1ValuesImpl.class
|
||||||
|
com/google/common/collect/LinkedListMultimap$DistinctKeyIterator.class
|
||||||
|
com/google/common/collect/LinkedListMultimap$KeyList.class
|
||||||
|
com/google/common/collect/LinkedListMultimap$Node.class
|
||||||
|
com/google/common/collect/LinkedListMultimap$NodeIterator.class
|
||||||
|
com/google/common/collect/LinkedListMultimap$ValueForKeyIterator.class
|
||||||
|
com/google/common/collect/LinkedListMultimap.class
|
||||||
|
com/google/common/collect/MinMaxPriorityQueue$1.class
|
||||||
|
com/google/common/collect/MinMaxPriorityQueue$Builder.class
|
||||||
|
com/google/common/collect/MinMaxPriorityQueue$Heap.class
|
||||||
|
com/google/common/collect/MinMaxPriorityQueue$MoveDesc.class
|
||||||
|
com/google/common/collect/MinMaxPriorityQueue$QueueIterator.class
|
||||||
|
com/google/common/collect/MinMaxPriorityQueue.class
|
||||||
|
com/google/common/collect/MoreCollectors$ToOptionalState.class
|
||||||
|
com/google/common/collect/MoreCollectors.class
|
||||||
|
com/google/common/collect/MutableClassToInstanceMap$1.class
|
||||||
|
com/google/common/collect/MutableClassToInstanceMap$2$1.class
|
||||||
|
com/google/common/collect/MutableClassToInstanceMap$2.class
|
||||||
|
com/google/common/collect/MutableClassToInstanceMap$SerializedForm.class
|
||||||
|
com/google/common/collect/MutableClassToInstanceMap.class
|
||||||
|
com/google/common/collect/Queues.class
|
||||||
|
com/google/common/collect/RegularImmutableSortedMultiset.class
|
||||||
|
com/google/common/collect/RegularImmutableTable$1.class
|
||||||
|
com/google/common/collect/RegularImmutableTable$CellSet.class
|
||||||
|
com/google/common/collect/RegularImmutableTable$Values.class
|
||||||
|
com/google/common/collect/RegularImmutableTable.class
|
||||||
|
com/google/common/collect/RowSortedTable.class
|
||||||
|
com/google/common/collect/SingletonImmutableTable.class
|
||||||
|
com/google/common/collect/SortedMultisets$ElementSet.class
|
||||||
|
com/google/common/collect/SortedMultisets$NavigableElementSet.class
|
||||||
|
com/google/common/collect/SortedMultisets.class
|
||||||
|
com/google/common/collect/SparseImmutableTable.class
|
||||||
|
com/google/common/collect/StandardRowSortedTable$1.class
|
||||||
|
com/google/common/collect/StandardRowSortedTable$RowSortedMap.class
|
||||||
|
com/google/common/collect/StandardRowSortedTable.class
|
||||||
|
com/google/common/collect/StandardTable$1.class
|
||||||
|
com/google/common/collect/StandardTable$CellIterator.class
|
||||||
|
com/google/common/collect/StandardTable$Column$EntrySet.class
|
||||||
|
com/google/common/collect/StandardTable$Column$EntrySetIterator$1EntryImpl.class
|
||||||
|
com/google/common/collect/StandardTable$Column$EntrySetIterator.class
|
||||||
|
com/google/common/collect/StandardTable$Column$KeySet.class
|
||||||
|
com/google/common/collect/StandardTable$Column$Values.class
|
||||||
|
com/google/common/collect/StandardTable$Column.class
|
||||||
|
com/google/common/collect/StandardTable$ColumnKeyIterator.class
|
||||||
|
com/google/common/collect/StandardTable$ColumnKeySet.class
|
||||||
|
com/google/common/collect/StandardTable$ColumnMap$ColumnMapEntrySet$1.class
|
||||||
|
com/google/common/collect/StandardTable$ColumnMap$ColumnMapEntrySet.class
|
||||||
|
com/google/common/collect/StandardTable$ColumnMap$ColumnMapValues.class
|
||||||
|
com/google/common/collect/StandardTable$ColumnMap.class
|
||||||
|
com/google/common/collect/StandardTable$Row$1.class
|
||||||
|
com/google/common/collect/StandardTable$Row$2.class
|
||||||
|
com/google/common/collect/StandardTable$Row.class
|
||||||
|
com/google/common/collect/StandardTable$RowMap$EntrySet$1.class
|
||||||
|
com/google/common/collect/StandardTable$RowMap$EntrySet.class
|
||||||
|
com/google/common/collect/StandardTable$RowMap.class
|
||||||
|
com/google/common/collect/StandardTable$TableSet.class
|
||||||
|
com/google/common/collect/StandardTable.class
|
||||||
|
com/google/common/collect/Tables$1.class
|
||||||
|
com/google/common/collect/Tables$AbstractCell.class
|
||||||
|
com/google/common/collect/Tables$ImmutableCell.class
|
||||||
|
com/google/common/collect/Tables$TransformedTable$1.class
|
||||||
|
com/google/common/collect/Tables$TransformedTable$2.class
|
||||||
|
com/google/common/collect/Tables$TransformedTable$3.class
|
||||||
|
com/google/common/collect/Tables$TransformedTable.class
|
||||||
|
com/google/common/collect/Tables$TransposeTable$1.class
|
||||||
|
com/google/common/collect/Tables$TransposeTable.class
|
||||||
|
com/google/common/collect/Tables$UnmodifiableRowSortedMap.class
|
||||||
|
com/google/common/collect/Tables$UnmodifiableTable.class
|
||||||
|
com/google/common/collect/Tables.class
|
||||||
|
com/google/common/collect/TreeBasedTable$1.class
|
||||||
|
com/google/common/collect/TreeBasedTable$2.class
|
||||||
|
com/google/common/collect/TreeBasedTable$Factory.class
|
||||||
|
com/google/common/collect/TreeBasedTable$TreeRow.class
|
||||||
|
com/google/common/collect/TreeBasedTable.class
|
||||||
|
com/google/common/collect/TreeMultimap.class
|
||||||
|
com/google/common/collect/TreeMultiset$1.class
|
||||||
|
com/google/common/collect/TreeMultiset$2.class
|
||||||
|
com/google/common/collect/TreeMultiset$3.class
|
||||||
|
com/google/common/collect/TreeMultiset$4.class
|
||||||
|
com/google/common/collect/TreeMultiset$Aggregate$1.class
|
||||||
|
com/google/common/collect/TreeMultiset$Aggregate$2.class
|
||||||
|
com/google/common/collect/TreeMultiset$Aggregate.class
|
||||||
|
com/google/common/collect/TreeMultiset$AvlNode.class
|
||||||
|
com/google/common/collect/TreeMultiset$Reference.class
|
||||||
|
com/google/common/collect/TreeMultiset.class
|
||||||
|
com/google/common/collect/TreeRangeMap$1.class
|
||||||
|
com/google/common/collect/TreeRangeMap$AsMapOfRanges.class
|
||||||
|
com/google/common/collect/TreeRangeMap$RangeMapEntry.class
|
||||||
|
com/google/common/collect/TreeRangeMap$SubRangeMap$1$1.class
|
||||||
|
com/google/common/collect/TreeRangeMap$SubRangeMap$1.class
|
||||||
|
com/google/common/collect/TreeRangeMap$SubRangeMap$SubRangeMapAsMap$1.class
|
||||||
|
com/google/common/collect/TreeRangeMap$SubRangeMap$SubRangeMapAsMap$2.class
|
||||||
|
com/google/common/collect/TreeRangeMap$SubRangeMap$SubRangeMapAsMap$3.class
|
||||||
|
com/google/common/collect/TreeRangeMap$SubRangeMap$SubRangeMapAsMap$4.class
|
||||||
|
com/google/common/collect/TreeRangeMap$SubRangeMap$SubRangeMapAsMap.class
|
||||||
|
com/google/common/collect/TreeRangeMap$SubRangeMap.class
|
||||||
|
com/google/common/collect/TreeRangeMap.class
|
||||||
|
com/google/common/collect/TreeTraverser$1.class
|
||||||
|
com/google/common/collect/TreeTraverser$2$1.class
|
||||||
|
com/google/common/collect/TreeTraverser$2.class
|
||||||
|
com/google/common/collect/TreeTraverser$3$1.class
|
||||||
|
com/google/common/collect/TreeTraverser$3.class
|
||||||
|
com/google/common/collect/TreeTraverser$4.class
|
||||||
|
com/google/common/collect/TreeTraverser$BreadthFirstIterator.class
|
||||||
|
com/google/common/collect/TreeTraverser$PostOrderIterator.class
|
||||||
|
com/google/common/collect/TreeTraverser$PostOrderNode.class
|
||||||
|
com/google/common/collect/TreeTraverser$PreOrderIterator.class
|
||||||
|
com/google/common/collect/TreeTraverser.class
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ch/qos/logback/core/db/**
|
||||||
|
ch/qos/logback/classic/db/**
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
org/checkerframework/**
|
||||||
|
org/intellij/**
|
||||||
|
com/google/errorprone/**
|
||||||
|
com/google/thirdparty/**
|
||||||
|
com/google/j2objc/**
|
||||||
+1
-2
@@ -2,8 +2,7 @@
|
|||||||
"name": "css",
|
"name": "css",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"css": "NODE_ENV=dev MANIFEST=../simplenotes-app/src/main/resources/css-manifest.json postcss build src/styles.pcss --output ../simplenotes-app/src/main/resources/static/styles.css",
|
"//": "`gradle css`"
|
||||||
"css-purge": "NODE_ENV=production MANIFEST=../simplenotes-app/src/main/resources/css-manifest.json postcss build src/styles.pcss --output ../simplenotes-app/src/main/resources/static/styles.css"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"autoprefixer": "^9.8.6",
|
"autoprefixer": "^9.8.6",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
purge: {
|
purge: {
|
||||||
content: [
|
content: [
|
||||||
'../simplenotes-app/src/main/kotlin/be/simplenotes/app/views/**/*.kt'
|
process.env.PURGE
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
theme: {
|
theme: {
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
rm simplenotes-app/src/main/resources/css-manifest.json
|
|
||||||
rm simplenotes-app/src/main/resources/static/styles*
|
|
||||||
|
|
||||||
yarn --cwd css run css-purge \
|
|
||||||
&& docker build -t hubv/simplenotes:latest . \
|
|
||||||
&& docker push hubv/simplenotes:latest
|
|
||||||
Vendored
BIN
Binary file not shown.
+5
@@ -0,0 +1,5 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
@@ -0,0 +1,185 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2015 the original author or authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
NONSTOP* )
|
||||||
|
nonstop=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=`expr $i + 1`
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
0) set -- ;;
|
||||||
|
1) set -- "$args0" ;;
|
||||||
|
2) set -- "$args0" "$args1" ;;
|
||||||
|
3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Escape application args
|
||||||
|
save () {
|
||||||
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
|
echo " "
|
||||||
|
}
|
||||||
|
APP_ARGS=`save "$@"`
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
Vendored
+89
@@ -0,0 +1,89 @@
|
|||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
@@ -1,249 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<artifactId>simplenotes-parent</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
|
|
||||||
<modules>
|
|
||||||
<module>simplenotes-persistance</module>
|
|
||||||
<module>simplenotes-app</module>
|
|
||||||
<module>simplenotes-domain</module>
|
|
||||||
<module>simplenotes-search</module>
|
|
||||||
<module>simplenotes-types</module>
|
|
||||||
<module>simplenotes-config</module>
|
|
||||||
<module>simplenotes-test-resources</module>
|
|
||||||
</modules>
|
|
||||||
|
|
||||||
<packaging>pom</packaging>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<java.version>14</java.version>
|
|
||||||
<kotlin.version>1.4.10</kotlin.version>
|
|
||||||
<junit.version>5.6.2</junit.version>
|
|
||||||
|
|
||||||
<kotlin.code.style>official</kotlin.code.style>
|
|
||||||
<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
|
|
||||||
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
|
||||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
|
||||||
<kotlin.compiler.jvmTarget>${java.version}</kotlin.compiler.jvmTarget>
|
|
||||||
|
|
||||||
<org.mapstruct.version>1.4.1.Final</org.mapstruct.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jetbrains.kotlin</groupId>
|
|
||||||
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
|
||||||
<version>${kotlin.version}</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
|
|
||||||
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
|
|
||||||
|
|
||||||
<pluginManagement>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
|
||||||
<version>3.2.0</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
|
||||||
<version>3.2.4</version>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
|
||||||
<version>3.0.0-M5</version>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.maven.surefire</groupId>
|
|
||||||
<artifactId>surefire-junit-platform</artifactId>
|
|
||||||
<version>3.0.0-M5</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</pluginManagement>
|
|
||||||
|
|
||||||
<plugins>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-enforcer-plugin</artifactId>
|
|
||||||
<version>3.0.0-M3</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>enforce</id>
|
|
||||||
<goals>
|
|
||||||
<goal>enforce</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<rules>
|
|
||||||
<banDuplicatePomDependencyVersions/>
|
|
||||||
<requireMavenVersion>
|
|
||||||
<version>3.6</version>
|
|
||||||
</requireMavenVersion>
|
|
||||||
</rules>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<artifactId>kotlin-maven-plugin</artifactId>
|
|
||||||
<groupId>org.jetbrains.kotlin</groupId>
|
|
||||||
<version>${kotlin.version}</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>kapt</id>
|
|
||||||
<goals>
|
|
||||||
<goal>kapt</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<annotationProcessorPaths>
|
|
||||||
<annotationProcessorPath>
|
|
||||||
<groupId>org.mapstruct</groupId>
|
|
||||||
<artifactId>mapstruct-processor</artifactId>
|
|
||||||
<version>${org.mapstruct.version}</version>
|
|
||||||
</annotationProcessorPath>
|
|
||||||
</annotationProcessorPaths>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<id>compile</id>
|
|
||||||
<phase>process-sources</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>compile</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<id>test-compile</id>
|
|
||||||
<goals>
|
|
||||||
<goal>test-compile</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
<configuration>
|
|
||||||
<args>
|
|
||||||
<arg>-Xno-param-assertions</arg>
|
|
||||||
<arg>-Xno-call-assertions</arg>
|
|
||||||
<arg>-Xno-receiver-assertions</arg>
|
|
||||||
</args>
|
|
||||||
<compilerPlugins>
|
|
||||||
<plugin>kotlinx-serialization</plugin>
|
|
||||||
</compilerPlugins>
|
|
||||||
</configuration>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jetbrains.kotlin</groupId>
|
|
||||||
<artifactId>kotlin-maven-serialization</artifactId>
|
|
||||||
<version>${kotlin.version}</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<dependencyManagement>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jetbrains.kotlin</groupId>
|
|
||||||
<artifactId>kotlin-bom</artifactId>
|
|
||||||
<version>${kotlin.version}</version>
|
|
||||||
<type>pom</type>
|
|
||||||
<scope>import</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jetbrains.kotlinx</groupId>
|
|
||||||
<artifactId>kotlinx-serialization-json-jvm</artifactId>
|
|
||||||
<version>1.0.0</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.koin</groupId>
|
|
||||||
<artifactId>koin-core</artifactId>
|
|
||||||
<version>2.1.6</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>ch.qos.logback</groupId>
|
|
||||||
<artifactId>logback-classic</artifactId>
|
|
||||||
<version>1.2.3</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.arrow-kt</groupId>
|
|
||||||
<artifactId>arrow-core</artifactId>
|
|
||||||
<version>0.11.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-api</artifactId>
|
|
||||||
<version>1.7.25</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>me.liuwj.ktorm</groupId>
|
|
||||||
<artifactId>ktorm-core</artifactId>
|
|
||||||
<version>3.0.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>me.liuwj.ktorm</groupId>
|
|
||||||
<artifactId>ktorm-support-mysql</artifactId>
|
|
||||||
<version>3.0.0</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mapstruct</groupId>
|
|
||||||
<artifactId>mapstruct</artifactId>
|
|
||||||
<version>${org.mapstruct.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- region tests -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter</artifactId>
|
|
||||||
<version>${junit.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.mockk</groupId>
|
|
||||||
<artifactId>mockk</artifactId>
|
|
||||||
<version>1.10.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.natpryce</groupId>
|
|
||||||
<artifactId>hamkrest</artifactId>
|
|
||||||
<version>1.7.0.3</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.assertj</groupId>
|
|
||||||
<artifactId>assertj-core</artifactId>
|
|
||||||
<version>3.16.1</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- endregion -->
|
|
||||||
</dependencies>
|
|
||||||
</dependencyManagement>
|
|
||||||
|
|
||||||
<repositories>
|
|
||||||
<repository>
|
|
||||||
<id>jcenter</id>
|
|
||||||
<url>https://jcenter.bintray.com</url>
|
|
||||||
</repository>
|
|
||||||
<repository>
|
|
||||||
<id>arrow</id>
|
|
||||||
<url>https://dl.bintray.com/arrow-kt/arrow-kt/</url>
|
|
||||||
</repository>
|
|
||||||
<repository>
|
|
||||||
<id>kotlinx</id>
|
|
||||||
<url>https://kotlin.bintray.com/kotlinx</url>
|
|
||||||
</repository>
|
|
||||||
</repositories>
|
|
||||||
|
|
||||||
</project>
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
rootProject.name = "simplenotes"
|
||||||
|
include(":simplenotes-config")
|
||||||
|
include(":simplenotes-views")
|
||||||
|
include(":simplenotes-app")
|
||||||
|
include(":simplenotes-domain")
|
||||||
|
include(":simplenotes-search")
|
||||||
|
include(":simplenotes-types")
|
||||||
|
include(":simplenotes-persistance")
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import be.simplenotes.Libs
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("be.simplenotes.base")
|
||||||
|
id("be.simplenotes.kotlinx-serialization")
|
||||||
|
id("be.simplenotes.app-shadow")
|
||||||
|
id("be.simplenotes.app-css")
|
||||||
|
id("be.simplenotes.app-docker")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":simplenotes-persistance"))
|
||||||
|
implementation(project(":simplenotes-search"))
|
||||||
|
implementation(project(":simplenotes-domain"))
|
||||||
|
implementation(project(":simplenotes-types"))
|
||||||
|
implementation(project(":simplenotes-config"))
|
||||||
|
implementation(project(":simplenotes-views"))
|
||||||
|
|
||||||
|
implementation(Libs.koinCore)
|
||||||
|
implementation(Libs.arrowCoreData)
|
||||||
|
implementation(Libs.konform)
|
||||||
|
implementation(Libs.http4kCore)
|
||||||
|
implementation(Libs.jettyServer)
|
||||||
|
implementation(Libs.jettyServlet)
|
||||||
|
implementation(Libs.javaxServlet)
|
||||||
|
implementation(Libs.kotlinxSerializationJson)
|
||||||
|
implementation(Libs.logbackClassic)
|
||||||
|
implementation(Libs.ktormCore)
|
||||||
|
|
||||||
|
testImplementation(Libs.junit)
|
||||||
|
testImplementation(Libs.assertJ)
|
||||||
|
testImplementation(Libs.http4kTestingHamkrest)
|
||||||
|
}
|
||||||
@@ -1,207 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>simplenotes-parent</artifactId>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>simplenotes-app</artifactId>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<http4k.version>3.268.0</http4k.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<artifactId>simplenotes-persistance</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<artifactId>simplenotes-search</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<artifactId>simplenotes-domain</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<artifactId>simplenotes-config</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.http4k</groupId>
|
|
||||||
<artifactId>http4k-core</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.http4k</groupId>
|
|
||||||
<artifactId>http4k-server-jetty</artifactId>
|
|
||||||
</dependency>
|
|
||||||
-->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-server</artifactId>
|
|
||||||
<version>9.4.32.v20200930</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-servlet</artifactId>
|
|
||||||
<version>9.4.32.v20200930</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>javax.servlet</groupId>
|
|
||||||
<artifactId>javax.servlet-api</artifactId>
|
|
||||||
<version>4.0.1</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jetbrains.kotlinx</groupId>
|
|
||||||
<artifactId>kotlinx-html-jvm</artifactId>
|
|
||||||
<version>0.7.1</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jetbrains.kotlinx</groupId>
|
|
||||||
<artifactId>kotlinx-serialization-json-jvm</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.ocpsoft.prettytime</groupId>
|
|
||||||
<artifactId>prettytime</artifactId>
|
|
||||||
<version>4.0.5.Final</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>ch.qos.logback</groupId>
|
|
||||||
<artifactId>logback-classic</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.assertj</groupId>
|
|
||||||
<artifactId>assertj-core</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<artifactId>simplenotes-test-resources</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
<type>test-jar</type>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.http4k</groupId>
|
|
||||||
<artifactId>http4k-testing-hamkrest</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>me.liuwj.ktorm</groupId>
|
|
||||||
<artifactId>ktorm-core</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<dependencyManagement>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.http4k</groupId>
|
|
||||||
<artifactId>http4k-bom</artifactId>
|
|
||||||
<version>${http4k.version}</version>
|
|
||||||
<type>pom</type>
|
|
||||||
<scope>import</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</dependencyManagement>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>package</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>shade</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<minimizeJar>true</minimizeJar>
|
|
||||||
<transformers>
|
|
||||||
<transformer
|
|
||||||
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
|
||||||
<mainClass>be.simplenotes.app.SimpleNotesKt</mainClass>
|
|
||||||
</transformer>
|
|
||||||
</transformers>
|
|
||||||
<filters>
|
|
||||||
<filter>
|
|
||||||
<artifact>com.h2database:h2</artifact>
|
|
||||||
<includes>
|
|
||||||
<include>**</include>
|
|
||||||
</includes>
|
|
||||||
</filter>
|
|
||||||
<filter>
|
|
||||||
<artifact>org.mariadb.jdbc:mariadb-java-client</artifact>
|
|
||||||
<includes>
|
|
||||||
<include>**</include>
|
|
||||||
</includes>
|
|
||||||
</filter>
|
|
||||||
<filter>
|
|
||||||
<artifact>org.jetbrains.kotlin:kotlin-reflect</artifact>
|
|
||||||
<includes>
|
|
||||||
<include>**</include>
|
|
||||||
</includes>
|
|
||||||
</filter>
|
|
||||||
<filter>
|
|
||||||
<artifact>org.eclipse.jetty:*</artifact>
|
|
||||||
<includes>
|
|
||||||
<include>**</include>
|
|
||||||
</includes>
|
|
||||||
</filter>
|
|
||||||
<filter>
|
|
||||||
<artifact>org.apache.lucene:*</artifact>
|
|
||||||
<includes>
|
|
||||||
<include>**</include>
|
|
||||||
</includes>
|
|
||||||
</filter>
|
|
||||||
<filter>
|
|
||||||
<artifact>org.ocpsoft.prettytime:prettytime</artifact>
|
|
||||||
<includes>
|
|
||||||
<include>**</include>
|
|
||||||
</includes>
|
|
||||||
</filter>
|
|
||||||
<filter>
|
|
||||||
<artifact>*:*</artifact>
|
|
||||||
<excludes>
|
|
||||||
<exclude>META-INF/maven/**</exclude>
|
|
||||||
<exclude>META-INF/proguard/**</exclude>
|
|
||||||
<exclude>META-INF/*.kotlin_module</exclude>
|
|
||||||
<exclude>META-INF/DEPENDENCIES*</exclude>
|
|
||||||
<exclude>META-INF/NOTICE*</exclude>
|
|
||||||
<exclude>META-INF/LICENSE*</exclude>
|
|
||||||
<exclude>LICENSE*</exclude>
|
|
||||||
<exclude>META-INF/README*</exclude>
|
|
||||||
<exclude>META-INF/native-image/**</exclude>
|
|
||||||
</excludes>
|
|
||||||
</filter>
|
|
||||||
</filters>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
</project>
|
|
||||||
@@ -2,10 +2,12 @@ package be.simplenotes.app
|
|||||||
|
|
||||||
import be.simplenotes.app.extensions.addShutdownHook
|
import be.simplenotes.app.extensions.addShutdownHook
|
||||||
import be.simplenotes.app.modules.*
|
import be.simplenotes.app.modules.*
|
||||||
|
import be.simplenotes.config.configModule
|
||||||
import be.simplenotes.domain.domainModule
|
import be.simplenotes.domain.domainModule
|
||||||
import be.simplenotes.persistance.migrationModule
|
import be.simplenotes.persistance.migrationModule
|
||||||
import be.simplenotes.persistance.persistanceModule
|
import be.simplenotes.persistance.persistanceModule
|
||||||
import be.simplenotes.search.searchModule
|
import be.simplenotes.search.searchModule
|
||||||
|
import be.simplenotes.views.viewModule
|
||||||
import org.koin.core.context.startKoin
|
import org.koin.core.context.startKoin
|
||||||
import org.koin.core.context.unloadKoinModules
|
import org.koin.core.context.unloadKoinModules
|
||||||
|
|
||||||
@@ -16,10 +18,8 @@ fun main() {
|
|||||||
persistanceModule,
|
persistanceModule,
|
||||||
migrationModule,
|
migrationModule,
|
||||||
configModule,
|
configModule,
|
||||||
baseModule,
|
viewModule,
|
||||||
userModule,
|
controllerModule,
|
||||||
noteModule,
|
|
||||||
settingsModule,
|
|
||||||
domainModule,
|
domainModule,
|
||||||
searchModule,
|
searchModule,
|
||||||
apiModule,
|
apiModule,
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package be.simplenotes.app.api
|
|||||||
|
|
||||||
import be.simplenotes.app.extensions.auto
|
import be.simplenotes.app.extensions.auto
|
||||||
import be.simplenotes.app.utils.parseSearchTerms
|
import be.simplenotes.app.utils.parseSearchTerms
|
||||||
|
import be.simplenotes.domain.usecases.NoteService
|
||||||
|
import be.simplenotes.types.LoggedInUser
|
||||||
import be.simplenotes.types.PersistedNote
|
import be.simplenotes.types.PersistedNote
|
||||||
import be.simplenotes.types.PersistedNoteMetadata
|
import be.simplenotes.types.PersistedNoteMetadata
|
||||||
import be.simplenotes.domain.security.JwtPayload
|
|
||||||
import be.simplenotes.domain.usecases.NoteService
|
|
||||||
import kotlinx.serialization.Contextual
|
import kotlinx.serialization.Contextual
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@@ -20,38 +20,41 @@ import java.util.*
|
|||||||
|
|
||||||
class ApiNoteController(private val noteService: NoteService, private val json: Json) {
|
class ApiNoteController(private val noteService: NoteService, private val json: Json) {
|
||||||
|
|
||||||
fun createNote(request: Request, jwtPayload: JwtPayload): Response {
|
fun createNote(request: Request, loggedInUser: LoggedInUser): Response {
|
||||||
val content = noteContentLens(request)
|
val content = noteContentLens(request)
|
||||||
return noteService.create(jwtPayload.userId, content).fold(
|
return noteService.create(loggedInUser.userId, content).fold(
|
||||||
{ Response(BAD_REQUEST) },
|
{ Response(BAD_REQUEST) },
|
||||||
{ uuidContentLens(UuidContent(it.uuid), Response(OK)) }
|
{ uuidContentLens(UuidContent(it.uuid), Response(OK)) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun notes(request: Request, jwtPayload: JwtPayload): Response {
|
fun notes(@Suppress("UNUSED_PARAMETER") request: Request, loggedInUser: LoggedInUser): Response {
|
||||||
val notes = noteService.paginatedNotes(jwtPayload.userId, page = 1).notes
|
val notes = noteService.paginatedNotes(loggedInUser.userId, page = 1).notes
|
||||||
return persistedNotesMetadataLens(notes, Response(OK))
|
return persistedNotesMetadataLens(notes, Response(OK))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun note(request: Request, jwtPayload: JwtPayload): Response =
|
fun note(request: Request, loggedInUser: LoggedInUser): Response =
|
||||||
noteService.find(jwtPayload.userId, uuidLens(request))
|
noteService.find(loggedInUser.userId, uuidLens(request))
|
||||||
?.let { persistedNoteLens(it, Response(OK)) }
|
?.let { persistedNoteLens(it, Response(OK)) }
|
||||||
?: Response(NOT_FOUND)
|
?: Response(NOT_FOUND)
|
||||||
|
|
||||||
fun update(request: Request, jwtPayload: JwtPayload): Response {
|
fun update(request: Request, loggedInUser: LoggedInUser): Response {
|
||||||
val content = noteContentLens(request)
|
val content = noteContentLens(request)
|
||||||
return noteService.update(jwtPayload.userId, uuidLens(request), content).fold({
|
return noteService.update(loggedInUser.userId, uuidLens(request), content).fold(
|
||||||
|
{
|
||||||
Response(BAD_REQUEST)
|
Response(BAD_REQUEST)
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
if (it == null) Response(NOT_FOUND)
|
if (it == null) Response(NOT_FOUND)
|
||||||
else Response(OK)
|
else Response(OK)
|
||||||
})
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun search(request: Request, jwtPayload: JwtPayload): Response {
|
fun search(request: Request, loggedInUser: LoggedInUser): Response {
|
||||||
val query = searchContentLens(request)
|
val query = searchContentLens(request)
|
||||||
val terms = parseSearchTerms(query)
|
val terms = parseSearchTerms(query)
|
||||||
val notes = noteService.search(jwtPayload.userId, terms)
|
val notes = noteService.search(loggedInUser.userId, terms)
|
||||||
return persistedNotesMetadataLens(notes, Response(OK))
|
return persistedNotesMetadataLens(notes, Response(OK))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +64,6 @@ class ApiNoteController(private val noteService: NoteService, private val json:
|
|||||||
private val persistedNotesMetadataLens = json.auto<List<PersistedNoteMetadata>>().toLens()
|
private val persistedNotesMetadataLens = json.auto<List<PersistedNoteMetadata>>().toLens()
|
||||||
private val persistedNoteLens = json.auto<PersistedNote>().toLens()
|
private val persistedNoteLens = json.auto<PersistedNote>().toLens()
|
||||||
private val uuidLens = Path.uuid().of("uuid")
|
private val uuidLens = Path.uuid().of("uuid")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package be.simplenotes.app.controllers
|
package be.simplenotes.app.controllers
|
||||||
|
|
||||||
import be.simplenotes.app.extensions.html
|
import be.simplenotes.app.extensions.html
|
||||||
import be.simplenotes.app.views.BaseView
|
import be.simplenotes.types.LoggedInUser
|
||||||
import be.simplenotes.domain.security.JwtPayload
|
import be.simplenotes.views.BaseView
|
||||||
import org.http4k.core.Request
|
import org.http4k.core.Request
|
||||||
import org.http4k.core.Response
|
import org.http4k.core.Response
|
||||||
import org.http4k.core.Status.Companion.OK
|
import org.http4k.core.Status.Companion.OK
|
||||||
|
|
||||||
class BaseController(private val view: BaseView) {
|
class BaseController(private val view: BaseView) {
|
||||||
fun index(@Suppress("UNUSED_PARAMETER") request: Request, jwtPayload: JwtPayload?) =
|
fun index(@Suppress("UNUSED_PARAMETER") request: Request, loggedInUser: LoggedInUser?) =
|
||||||
Response(OK).html(view.renderHome(jwtPayload))
|
Response(OK).html(view.renderHome(loggedInUser))
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -7,6 +7,6 @@ import org.http4k.core.Status.Companion.OK
|
|||||||
import org.http4k.core.Status.Companion.SERVICE_UNAVAILABLE
|
import org.http4k.core.Status.Companion.SERVICE_UNAVAILABLE
|
||||||
|
|
||||||
class HealthCheckController(private val dbHealthCheck: DbHealthCheck) {
|
class HealthCheckController(private val dbHealthCheck: DbHealthCheck) {
|
||||||
fun healthCheck(request: Request) =
|
fun healthCheck(@Suppress("UNUSED_PARAMETER") request: Request) =
|
||||||
if (dbHealthCheck.isOk()) Response(OK) else Response(SERVICE_UNAVAILABLE)
|
if (dbHealthCheck.isOk()) Response(OK) else Response(SERVICE_UNAVAILABLE)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ package be.simplenotes.app.controllers
|
|||||||
import be.simplenotes.app.extensions.html
|
import be.simplenotes.app.extensions.html
|
||||||
import be.simplenotes.app.extensions.redirect
|
import be.simplenotes.app.extensions.redirect
|
||||||
import be.simplenotes.app.utils.parseSearchTerms
|
import be.simplenotes.app.utils.parseSearchTerms
|
||||||
import be.simplenotes.app.views.NoteView
|
|
||||||
import be.simplenotes.domain.security.JwtPayload
|
|
||||||
import be.simplenotes.domain.usecases.NoteService
|
import be.simplenotes.domain.usecases.NoteService
|
||||||
import be.simplenotes.domain.usecases.markdown.InvalidMeta
|
import be.simplenotes.domain.usecases.markdown.InvalidMeta
|
||||||
import be.simplenotes.domain.usecases.markdown.MissingMeta
|
import be.simplenotes.domain.usecases.markdown.MissingMeta
|
||||||
import be.simplenotes.domain.usecases.markdown.ValidationError
|
import be.simplenotes.domain.usecases.markdown.ValidationError
|
||||||
|
import be.simplenotes.types.LoggedInUser
|
||||||
|
import be.simplenotes.views.NoteView
|
||||||
import org.http4k.core.Method
|
import org.http4k.core.Method
|
||||||
import org.http4k.core.Request
|
import org.http4k.core.Request
|
||||||
import org.http4k.core.Response
|
import org.http4k.core.Response
|
||||||
@@ -25,18 +25,26 @@ class NoteController(
|
|||||||
private val noteService: NoteService,
|
private val noteService: NoteService,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun new(request: Request, jwtPayload: JwtPayload): Response {
|
fun new(request: Request, loggedInUser: LoggedInUser): Response {
|
||||||
if (request.method == Method.GET) return Response(OK).html(view.noteEditor(jwtPayload))
|
if (request.method == Method.GET) return Response(OK).html(view.noteEditor(loggedInUser))
|
||||||
|
|
||||||
val markdownForm = request.form("markdown") ?: ""
|
val markdownForm = request.form("markdown") ?: ""
|
||||||
|
|
||||||
return noteService.create(jwtPayload.userId, markdownForm).fold(
|
return noteService.create(loggedInUser.userId, markdownForm).fold(
|
||||||
{
|
{
|
||||||
val html = when (it) {
|
val html = when (it) {
|
||||||
MissingMeta -> view.noteEditor(jwtPayload, error = "Missing note metadata", textarea = markdownForm)
|
MissingMeta -> view.noteEditor(
|
||||||
InvalidMeta -> view.noteEditor(jwtPayload, error = "Invalid note metadata", textarea = markdownForm)
|
loggedInUser,
|
||||||
|
error = "Missing note metadata",
|
||||||
|
textarea = markdownForm
|
||||||
|
)
|
||||||
|
InvalidMeta -> view.noteEditor(
|
||||||
|
loggedInUser,
|
||||||
|
error = "Invalid note metadata",
|
||||||
|
textarea = markdownForm
|
||||||
|
)
|
||||||
is ValidationError -> view.noteEditor(
|
is ValidationError -> view.noteEditor(
|
||||||
jwtPayload,
|
loggedInUser,
|
||||||
validationErrors = it.validationErrors,
|
validationErrors = it.validationErrors,
|
||||||
textarea = markdownForm
|
textarea = markdownForm
|
||||||
)
|
)
|
||||||
@@ -49,66 +57,74 @@ class NoteController(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun list(request: Request, jwtPayload: JwtPayload): Response {
|
fun list(request: Request, loggedInUser: LoggedInUser): Response {
|
||||||
val currentPage = request.query("page")?.toIntOrNull()?.let(::abs) ?: 1
|
val currentPage = request.query("page")?.toIntOrNull()?.let(::abs) ?: 1
|
||||||
val tag = request.query("tag")
|
val tag = request.query("tag")
|
||||||
val (pages, notes) = noteService.paginatedNotes(jwtPayload.userId, currentPage, tag = tag)
|
val (pages, notes) = noteService.paginatedNotes(loggedInUser.userId, currentPage, tag = tag)
|
||||||
val deletedCount = noteService.countDeleted(jwtPayload.userId)
|
val deletedCount = noteService.countDeleted(loggedInUser.userId)
|
||||||
return Response(OK).html(view.notes(jwtPayload, notes, currentPage, pages, deletedCount, tag = tag))
|
return Response(OK).html(view.notes(loggedInUser, notes, currentPage, pages, deletedCount, tag = tag))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun search(request: Request, jwtPayload: JwtPayload): Response {
|
fun search(request: Request, loggedInUser: LoggedInUser): Response {
|
||||||
val query = request.form("search") ?: ""
|
val query = request.form("search") ?: ""
|
||||||
val terms = parseSearchTerms(query)
|
val terms = parseSearchTerms(query)
|
||||||
val notes = noteService.search(jwtPayload.userId, terms)
|
val notes = noteService.search(loggedInUser.userId, terms)
|
||||||
val deletedCount = noteService.countDeleted(jwtPayload.userId)
|
val deletedCount = noteService.countDeleted(loggedInUser.userId)
|
||||||
return Response(OK).html(view.search(jwtPayload, notes, query, deletedCount))
|
return Response(OK).html(view.search(loggedInUser, notes, query, deletedCount))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun note(request: Request, jwtPayload: JwtPayload): Response {
|
fun note(request: Request, loggedInUser: LoggedInUser): Response {
|
||||||
val noteUuid = request.uuidPath() ?: return Response(NOT_FOUND)
|
val noteUuid = request.uuidPath() ?: return Response(NOT_FOUND)
|
||||||
|
|
||||||
if (request.method == Method.POST) {
|
if (request.method == Method.POST) {
|
||||||
if (request.form("delete") != null) {
|
if (request.form("delete") != null) {
|
||||||
return if (noteService.trash(jwtPayload.userId, noteUuid))
|
return if (noteService.trash(loggedInUser.userId, noteUuid))
|
||||||
Response.redirect("/notes") // TODO: flash cookie to show success ?
|
Response.redirect("/notes") // TODO: flash cookie to show success ?
|
||||||
else
|
else
|
||||||
Response(NOT_FOUND) // TODO: show an error
|
Response(NOT_FOUND) // TODO: show an error
|
||||||
}
|
}
|
||||||
if (request.form("public") != null) {
|
if (request.form("public") != null) {
|
||||||
if (!noteService.makePublic(jwtPayload.userId, noteUuid)) return Response(NOT_FOUND)
|
if (!noteService.makePublic(loggedInUser.userId, noteUuid)) return Response(NOT_FOUND)
|
||||||
} else if (request.form("private") != null) {
|
} else if (request.form("private") != null) {
|
||||||
if (!noteService.makePrivate(jwtPayload.userId, noteUuid)) return Response(NOT_FOUND)
|
if (!noteService.makePrivate(loggedInUser.userId, noteUuid)) return Response(NOT_FOUND)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val note = noteService.find(jwtPayload.userId, noteUuid) ?: return Response(NOT_FOUND)
|
val note = noteService.find(loggedInUser.userId, noteUuid) ?: return Response(NOT_FOUND)
|
||||||
return Response(OK).html(view.renderedNote(jwtPayload, note, shared = false))
|
return Response(OK).html(view.renderedNote(loggedInUser, note, shared = false))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun public(request: Request, jwtPayload: JwtPayload?): Response {
|
fun public(request: Request, loggedInUser: LoggedInUser?): Response {
|
||||||
val noteUuid = request.uuidPath() ?: return Response(NOT_FOUND)
|
val noteUuid = request.uuidPath() ?: return Response(NOT_FOUND)
|
||||||
val note = noteService.findPublic(noteUuid) ?: return Response(NOT_FOUND)
|
val note = noteService.findPublic(noteUuid) ?: return Response(NOT_FOUND)
|
||||||
return Response(OK).html(view.renderedNote(jwtPayload, note, shared = true))
|
return Response(OK).html(view.renderedNote(loggedInUser, note, shared = true))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun edit(request: Request, jwtPayload: JwtPayload): Response {
|
fun edit(request: Request, loggedInUser: LoggedInUser): Response {
|
||||||
val noteUuid = request.uuidPath() ?: return Response(NOT_FOUND)
|
val noteUuid = request.uuidPath() ?: return Response(NOT_FOUND)
|
||||||
val note = noteService.find(jwtPayload.userId, noteUuid) ?: return Response(NOT_FOUND)
|
val note = noteService.find(loggedInUser.userId, noteUuid) ?: return Response(NOT_FOUND)
|
||||||
|
|
||||||
if (request.method == Method.GET) {
|
if (request.method == Method.GET) {
|
||||||
return Response(OK).html(view.noteEditor(jwtPayload, textarea = note.markdown))
|
return Response(OK).html(view.noteEditor(loggedInUser, textarea = note.markdown))
|
||||||
}
|
}
|
||||||
|
|
||||||
val markdownForm = request.form("markdown") ?: ""
|
val markdownForm = request.form("markdown") ?: ""
|
||||||
|
|
||||||
return noteService.update(jwtPayload.userId, note.uuid, markdownForm).fold(
|
return noteService.update(loggedInUser.userId, note.uuid, markdownForm).fold(
|
||||||
{
|
{
|
||||||
val html = when (it) {
|
val html = when (it) {
|
||||||
MissingMeta -> view.noteEditor(jwtPayload, error = "Missing note metadata", textarea = markdownForm)
|
MissingMeta -> view.noteEditor(
|
||||||
InvalidMeta -> view.noteEditor(jwtPayload, error = "Invalid note metadata", textarea = markdownForm)
|
loggedInUser,
|
||||||
|
error = "Missing note metadata",
|
||||||
|
textarea = markdownForm
|
||||||
|
)
|
||||||
|
InvalidMeta -> view.noteEditor(
|
||||||
|
loggedInUser,
|
||||||
|
error = "Invalid note metadata",
|
||||||
|
textarea = markdownForm
|
||||||
|
)
|
||||||
is ValidationError -> view.noteEditor(
|
is ValidationError -> view.noteEditor(
|
||||||
jwtPayload,
|
loggedInUser,
|
||||||
validationErrors = it.validationErrors,
|
validationErrors = it.validationErrors,
|
||||||
textarea = markdownForm
|
textarea = markdownForm
|
||||||
)
|
)
|
||||||
@@ -121,21 +137,21 @@ class NoteController(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun trash(request: Request, jwtPayload: JwtPayload): Response {
|
fun trash(request: Request, loggedInUser: LoggedInUser): Response {
|
||||||
val currentPage = request.query("page")?.toIntOrNull()?.let(::abs) ?: 1
|
val currentPage = request.query("page")?.toIntOrNull()?.let(::abs) ?: 1
|
||||||
val tag = request.query("tag")
|
val tag = request.query("tag")
|
||||||
val (pages, notes) = noteService.paginatedNotes(jwtPayload.userId, currentPage, tag = tag, deleted = true)
|
val (pages, notes) = noteService.paginatedNotes(loggedInUser.userId, currentPage, tag = tag, deleted = true)
|
||||||
return Response(OK).html(view.trash(jwtPayload, notes, currentPage, pages))
|
return Response(OK).html(view.trash(loggedInUser, notes, currentPage, pages))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleted(request: Request, jwtPayload: JwtPayload): Response {
|
fun deleted(request: Request, loggedInUser: LoggedInUser): Response {
|
||||||
val uuid = request.uuidPath() ?: return Response(NOT_FOUND)
|
val uuid = request.uuidPath() ?: return Response(NOT_FOUND)
|
||||||
return if (request.form("delete") != null)
|
return if (request.form("delete") != null)
|
||||||
if (noteService.delete(jwtPayload.userId, uuid))
|
if (noteService.delete(loggedInUser.userId, uuid))
|
||||||
Response.redirect("/notes/trash")
|
Response.redirect("/notes/trash")
|
||||||
else
|
else
|
||||||
Response(NOT_FOUND)
|
Response(NOT_FOUND)
|
||||||
else if (noteService.restore(jwtPayload.userId, uuid))
|
else if (noteService.restore(loggedInUser.userId, uuid))
|
||||||
Response.redirect("/notes/$uuid")
|
Response.redirect("/notes/$uuid")
|
||||||
else
|
else
|
||||||
Response(NOT_FOUND)
|
Response(NOT_FOUND)
|
||||||
|
|||||||
+17
-14
@@ -2,11 +2,11 @@ package be.simplenotes.app.controllers
|
|||||||
|
|
||||||
import be.simplenotes.app.extensions.html
|
import be.simplenotes.app.extensions.html
|
||||||
import be.simplenotes.app.extensions.redirect
|
import be.simplenotes.app.extensions.redirect
|
||||||
import be.simplenotes.app.views.SettingView
|
|
||||||
import be.simplenotes.domain.security.JwtPayload
|
|
||||||
import be.simplenotes.domain.usecases.UserService
|
import be.simplenotes.domain.usecases.UserService
|
||||||
import be.simplenotes.domain.usecases.users.delete.DeleteError
|
import be.simplenotes.domain.usecases.users.delete.DeleteError
|
||||||
import be.simplenotes.domain.usecases.users.delete.DeleteForm
|
import be.simplenotes.domain.usecases.users.delete.DeleteForm
|
||||||
|
import be.simplenotes.types.LoggedInUser
|
||||||
|
import be.simplenotes.views.SettingView
|
||||||
import org.http4k.core.*
|
import org.http4k.core.*
|
||||||
import org.http4k.core.body.form
|
import org.http4k.core.body.form
|
||||||
import org.http4k.core.cookie.invalidateCookie
|
import org.http4k.core.cookie.invalidateCookie
|
||||||
@@ -15,11 +15,11 @@ class SettingsController(
|
|||||||
private val userService: UserService,
|
private val userService: UserService,
|
||||||
private val settingView: SettingView,
|
private val settingView: SettingView,
|
||||||
) {
|
) {
|
||||||
fun settings(request: Request, jwtPayload: JwtPayload): Response {
|
fun settings(request: Request, loggedInUser: LoggedInUser): Response {
|
||||||
if (request.method == Method.GET)
|
if (request.method == Method.GET)
|
||||||
return Response(Status.OK).html(settingView.settings(jwtPayload))
|
return Response(Status.OK).html(settingView.settings(loggedInUser))
|
||||||
|
|
||||||
val deleteForm = request.deleteForm(jwtPayload)
|
val deleteForm = request.deleteForm(loggedInUser)
|
||||||
val result = userService.delete(deleteForm)
|
val result = userService.delete(deleteForm)
|
||||||
|
|
||||||
return result.fold(
|
return result.fold(
|
||||||
@@ -28,13 +28,13 @@ class SettingsController(
|
|||||||
DeleteError.Unregistered -> Response.redirect("/").invalidateCookie("Bearer")
|
DeleteError.Unregistered -> Response.redirect("/").invalidateCookie("Bearer")
|
||||||
DeleteError.WrongPassword -> Response(Status.OK).html(
|
DeleteError.WrongPassword -> Response(Status.OK).html(
|
||||||
settingView.settings(
|
settingView.settings(
|
||||||
jwtPayload,
|
loggedInUser,
|
||||||
error = "Wrong password"
|
error = "Wrong password"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
is DeleteError.InvalidForm -> Response(Status.OK).html(
|
is DeleteError.InvalidForm -> Response(Status.OK).html(
|
||||||
settingView.settings(
|
settingView.settings(
|
||||||
jwtPayload,
|
loggedInUser,
|
||||||
validationErrors = it.validationErrors
|
validationErrors = it.validationErrors
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -53,23 +53,26 @@ class SettingsController(
|
|||||||
.header("Content-Type", contentType)
|
.header("Content-Type", contentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun export(request: Request, jwtPayload: JwtPayload): Response {
|
fun export(request: Request, loggedInUser: LoggedInUser): Response {
|
||||||
val isDownload = request.form("download") != null
|
val isDownload = request.form("download") != null
|
||||||
|
|
||||||
return if (isDownload) {
|
return if (isDownload) {
|
||||||
val filename = "simplenotes-export-${jwtPayload.username}"
|
val filename = "simplenotes-export-${loggedInUser.username}"
|
||||||
if (request.form("format") == "zip") {
|
if (request.form("format") == "zip") {
|
||||||
val zip = userService.exportAsZip(jwtPayload.userId)
|
val zip = userService.exportAsZip(loggedInUser.userId)
|
||||||
Response(Status.OK)
|
Response(Status.OK)
|
||||||
.with(attachment("$filename.zip", "application/zip"))
|
.with(attachment("$filename.zip", "application/zip"))
|
||||||
.body(zip)
|
.body(zip)
|
||||||
} else
|
} else
|
||||||
Response(Status.OK)
|
Response(Status.OK)
|
||||||
.with(attachment("$filename.json", "application/json"))
|
.with(attachment("$filename.json", "application/json"))
|
||||||
.body(userService.exportAsJson(jwtPayload.userId))
|
.body(userService.exportAsJson(loggedInUser.userId))
|
||||||
} else Response(Status.OK).body(userService.exportAsJson(jwtPayload.userId)).header("Content-Type", "application/json")
|
} else Response(Status.OK).body(userService.exportAsJson(loggedInUser.userId)).header(
|
||||||
|
"Content-Type",
|
||||||
|
"application/json"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Request.deleteForm(jwtPayload: JwtPayload) =
|
private fun Request.deleteForm(loggedInUser: LoggedInUser) =
|
||||||
DeleteForm(jwtPayload.username, form("password"), form("checked") != null)
|
DeleteForm(loggedInUser.username, form("password"), form("checked") != null)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ package be.simplenotes.app.controllers
|
|||||||
import be.simplenotes.app.extensions.html
|
import be.simplenotes.app.extensions.html
|
||||||
import be.simplenotes.app.extensions.isSecure
|
import be.simplenotes.app.extensions.isSecure
|
||||||
import be.simplenotes.app.extensions.redirect
|
import be.simplenotes.app.extensions.redirect
|
||||||
import be.simplenotes.app.views.UserView
|
import be.simplenotes.config.JwtConfig
|
||||||
import be.simplenotes.domain.security.JwtPayload
|
|
||||||
import be.simplenotes.domain.usecases.UserService
|
import be.simplenotes.domain.usecases.UserService
|
||||||
import be.simplenotes.domain.usecases.users.login.*
|
import be.simplenotes.domain.usecases.users.login.*
|
||||||
import be.simplenotes.domain.usecases.users.register.InvalidRegisterForm
|
import be.simplenotes.domain.usecases.users.register.InvalidRegisterForm
|
||||||
import be.simplenotes.domain.usecases.users.register.RegisterForm
|
import be.simplenotes.domain.usecases.users.register.RegisterForm
|
||||||
import be.simplenotes.domain.usecases.users.register.UserExists
|
import be.simplenotes.domain.usecases.users.register.UserExists
|
||||||
import be.simplenotes.config.JwtConfig
|
import be.simplenotes.types.LoggedInUser
|
||||||
|
import be.simplenotes.views.UserView
|
||||||
import org.http4k.core.Method.GET
|
import org.http4k.core.Method.GET
|
||||||
import org.http4k.core.Request
|
import org.http4k.core.Request
|
||||||
import org.http4k.core.Response
|
import org.http4k.core.Response
|
||||||
@@ -27,9 +27,9 @@ class UserController(
|
|||||||
private val userView: UserView,
|
private val userView: UserView,
|
||||||
private val jwtConfig: JwtConfig,
|
private val jwtConfig: JwtConfig,
|
||||||
) {
|
) {
|
||||||
fun register(request: Request, jwtPayload: JwtPayload?): Response {
|
fun register(request: Request, loggedInUser: LoggedInUser?): Response {
|
||||||
if (request.method == GET) return Response(OK).html(
|
if (request.method == GET) return Response(OK).html(
|
||||||
userView.register(jwtPayload)
|
userView.register(loggedInUser)
|
||||||
)
|
)
|
||||||
|
|
||||||
val result = userService.register(request.registerForm())
|
val result = userService.register(request.registerForm())
|
||||||
@@ -38,12 +38,12 @@ class UserController(
|
|||||||
{
|
{
|
||||||
val html = when (it) {
|
val html = when (it) {
|
||||||
UserExists -> userView.register(
|
UserExists -> userView.register(
|
||||||
jwtPayload,
|
loggedInUser,
|
||||||
error = "User already exists"
|
error = "User already exists"
|
||||||
)
|
)
|
||||||
is InvalidRegisterForm ->
|
is InvalidRegisterForm ->
|
||||||
userView.register(
|
userView.register(
|
||||||
jwtPayload,
|
loggedInUser,
|
||||||
validationErrors = it.validationErrors
|
validationErrors = it.validationErrors
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -58,9 +58,9 @@ class UserController(
|
|||||||
private fun Request.registerForm() = RegisterForm(form("username"), form("password"))
|
private fun Request.registerForm() = RegisterForm(form("username"), form("password"))
|
||||||
private fun Request.loginForm(): LoginForm = registerForm()
|
private fun Request.loginForm(): LoginForm = registerForm()
|
||||||
|
|
||||||
fun login(request: Request, jwtPayload: JwtPayload?): Response {
|
fun login(request: Request, loggedInUser: LoggedInUser?): Response {
|
||||||
if (request.method == GET) return Response(OK).html(
|
if (request.method == GET) return Response(OK).html(
|
||||||
userView.login(jwtPayload)
|
userView.login(loggedInUser)
|
||||||
)
|
)
|
||||||
|
|
||||||
val result = userService.login(request.loginForm())
|
val result = userService.login(request.loginForm())
|
||||||
@@ -70,17 +70,17 @@ class UserController(
|
|||||||
val html = when (it) {
|
val html = when (it) {
|
||||||
Unregistered ->
|
Unregistered ->
|
||||||
userView.login(
|
userView.login(
|
||||||
jwtPayload,
|
loggedInUser,
|
||||||
error = "User does not exist"
|
error = "User does not exist"
|
||||||
)
|
)
|
||||||
WrongPassword ->
|
WrongPassword ->
|
||||||
userView.login(
|
userView.login(
|
||||||
jwtPayload,
|
loggedInUser,
|
||||||
error = "Wrong password"
|
error = "Wrong password"
|
||||||
)
|
)
|
||||||
is InvalidLoginForm ->
|
is InvalidLoginForm ->
|
||||||
userView.login(
|
userView.login(
|
||||||
jwtPayload,
|
loggedInUser,
|
||||||
validationErrors = it.validationErrors
|
validationErrors = it.validationErrors
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ fun Request.isSecure() = header("X-Forwarded-Proto")?.contains("https") ?: false
|
|||||||
|
|
||||||
val bodyLens = httpBodyRoot(
|
val bodyLens = httpBodyRoot(
|
||||||
listOf(Meta(true, "body", ParamMeta.ObjectParam, "body")),
|
listOf(Meta(true, "body", ParamMeta.ObjectParam, "body")),
|
||||||
ContentType.APPLICATION_JSON.withNoDirectives(), ContentNegotiation.StrictNoDirective
|
ContentType.APPLICATION_JSON.withNoDirectives(),
|
||||||
|
ContentNegotiation.StrictNoDirective
|
||||||
).map(
|
).map(
|
||||||
{ it.payload.asString() },
|
{ it.payload.asString() },
|
||||||
{ Body(it) }
|
{ Body(it) }
|
||||||
|
|||||||
-15
@@ -1,15 +0,0 @@
|
|||||||
package be.simplenotes.app.extensions
|
|
||||||
|
|
||||||
import kotlinx.html.*
|
|
||||||
|
|
||||||
class SUMMARY(consumer: TagConsumer<*>) :
|
|
||||||
HTMLTag(
|
|
||||||
"summary", consumer, emptyMap(),
|
|
||||||
inlineTag = true,
|
|
||||||
emptyTag = false
|
|
||||||
),
|
|
||||||
HtmlInlineTag
|
|
||||||
|
|
||||||
fun DETAILS.summary(block: SUMMARY.() -> Unit = {}) {
|
|
||||||
SUMMARY(consumer).visit(block)
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package be.simplenotes.app.filters
|
package be.simplenotes.app.filters
|
||||||
|
|
||||||
import be.simplenotes.app.extensions.redirect
|
import be.simplenotes.app.extensions.redirect
|
||||||
import be.simplenotes.domain.security.JwtPayload
|
|
||||||
import be.simplenotes.domain.security.JwtPayloadExtractor
|
import be.simplenotes.domain.security.JwtPayloadExtractor
|
||||||
|
import be.simplenotes.types.LoggedInUser
|
||||||
import org.http4k.core.*
|
import org.http4k.core.*
|
||||||
import org.http4k.core.Status.Companion.UNAUTHORIZED
|
import org.http4k.core.Status.Companion.UNAUTHORIZED
|
||||||
import org.http4k.core.cookie.cookie
|
import org.http4k.core.cookie.cookie
|
||||||
@@ -25,7 +25,7 @@ class AuthFilter(
|
|||||||
JwtSource.Header -> it.bearerTokenHeader()
|
JwtSource.Header -> it.bearerTokenHeader()
|
||||||
JwtSource.Cookie -> it.bearerTokenCookie()
|
JwtSource.Cookie -> it.bearerTokenCookie()
|
||||||
}
|
}
|
||||||
val jwtPayload = token?.let { token -> extractor(token) }
|
val jwtPayload = token?.let { extractor(token) }
|
||||||
when {
|
when {
|
||||||
jwtPayload != null -> {
|
jwtPayload != null -> {
|
||||||
ctx[it][authKey] = jwtPayload
|
ctx[it][authKey] = jwtPayload
|
||||||
@@ -40,7 +40,7 @@ class AuthFilter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Request.jwtPayload(ctx: RequestContexts): JwtPayload? = ctx[this][authKey]
|
fun Request.jwtPayload(ctx: RequestContexts): LoggedInUser? = ctx[this][authKey]
|
||||||
|
|
||||||
enum class JwtSource {
|
enum class JwtSource {
|
||||||
Header, Cookie
|
Header, Cookie
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package be.simplenotes.app.filters
|
package be.simplenotes.app.filters
|
||||||
|
|
||||||
import be.simplenotes.app.extensions.html
|
import be.simplenotes.app.extensions.html
|
||||||
import be.simplenotes.app.views.ErrorView
|
import be.simplenotes.views.ErrorView
|
||||||
import be.simplenotes.app.views.ErrorView.Type.*
|
import be.simplenotes.views.ErrorView.Type.*
|
||||||
import org.http4k.core.*
|
import org.http4k.core.*
|
||||||
import org.http4k.core.Status.Companion.INTERNAL_SERVER_ERROR
|
import org.http4k.core.Status.Companion.INTERNAL_SERVER_ERROR
|
||||||
import org.http4k.core.Status.Companion.NOT_FOUND
|
import org.http4k.core.Status.Companion.NOT_FOUND
|
||||||
|
|||||||
@@ -12,9 +12,12 @@ import org.http4k.servlet.asServlet
|
|||||||
|
|
||||||
class Jetty(private val port: Int, private val server: Server) : ServerConfig {
|
class Jetty(private val port: Int, private val server: Server) : ServerConfig {
|
||||||
constructor(port: Int = 8000) : this(port, http(port))
|
constructor(port: Int = 8000) : this(port, http(port))
|
||||||
constructor(port: Int, vararg inConnectors: ConnectorBuilder) : this(port, Server().apply {
|
constructor(port: Int, vararg inConnectors: ConnectorBuilder) : this(
|
||||||
|
port,
|
||||||
|
Server().apply {
|
||||||
inConnectors.forEach { addConnector(it(this)) }
|
inConnectors.forEach { addConnector(it(this)) }
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
override fun toServer(httpHandler: HttpHandler): Http4kServer {
|
override fun toServer(httpHandler: HttpHandler): Http4kServer {
|
||||||
server.insertHandler(httpHandler.toJettyHandler())
|
server.insertHandler(httpHandler.toJettyHandler())
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
package be.simplenotes.app.modules
|
|
||||||
|
|
||||||
import be.simplenotes.app.Config
|
|
||||||
import org.koin.dsl.module
|
|
||||||
|
|
||||||
val configModule = module {
|
|
||||||
single { Config() }
|
|
||||||
single { get<Config>().dataSourceConfig }
|
|
||||||
single { get<Config>().jwtConfig }
|
|
||||||
single { get<Config>().serverConfig }
|
|
||||||
}
|
|
||||||
@@ -1,29 +1,12 @@
|
|||||||
package be.simplenotes.app.modules
|
package be.simplenotes.app.modules
|
||||||
|
|
||||||
import be.simplenotes.app.controllers.*
|
import be.simplenotes.app.controllers.*
|
||||||
import be.simplenotes.app.views.BaseView
|
|
||||||
import be.simplenotes.app.views.NoteView
|
|
||||||
import be.simplenotes.app.views.SettingView
|
|
||||||
import be.simplenotes.app.views.UserView
|
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
|
|
||||||
val userModule = module {
|
val controllerModule = module {
|
||||||
single { UserController(get(), get(), get()) }
|
single { UserController(get(), get(), get()) }
|
||||||
single { UserView(get()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
val baseModule = module {
|
|
||||||
single { HealthCheckController(get()) }
|
single { HealthCheckController(get()) }
|
||||||
single { BaseController(get()) }
|
single { BaseController(get()) }
|
||||||
single { BaseView(get()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
val noteModule = module {
|
|
||||||
single { NoteController(get(), get()) }
|
single { NoteController(get(), get()) }
|
||||||
single { NoteView(get()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
val settingsModule = module {
|
|
||||||
single { SettingsController(get(), get()) }
|
single { SettingsController(get(), get()) }
|
||||||
single { SettingView(get()) }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import be.simplenotes.app.jetty.Jetty
|
|||||||
import be.simplenotes.app.routes.Router
|
import be.simplenotes.app.routes.Router
|
||||||
import be.simplenotes.app.utils.StaticFileResolver
|
import be.simplenotes.app.utils.StaticFileResolver
|
||||||
import be.simplenotes.app.utils.StaticFileResolverImpl
|
import be.simplenotes.app.utils.StaticFileResolverImpl
|
||||||
import be.simplenotes.app.views.ErrorView
|
|
||||||
import be.simplenotes.config.ServerConfig
|
import be.simplenotes.config.ServerConfig
|
||||||
import org.eclipse.jetty.server.ServerConnector
|
import org.eclipse.jetty.server.ServerConnector
|
||||||
import org.http4k.core.Filter
|
import org.http4k.core.Filter
|
||||||
@@ -59,5 +58,5 @@ val serverModule = module {
|
|||||||
single<Filter>(AuthType.Required.qualifier) { AuthFilter(get(), AuthType.Required, get()) }
|
single<Filter>(AuthType.Required.qualifier) { AuthFilter(get(), AuthType.Required, get()) }
|
||||||
single { ErrorFilter(get()) }
|
single { ErrorFilter(get()) }
|
||||||
single { TransactionFilter(get()) }
|
single { TransactionFilter(get()) }
|
||||||
single { ErrorView(get()) }
|
single(named("styles")) { get<StaticFileResolver>().resolve("styles.css") }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import be.simplenotes.app.api.ApiNoteController
|
|||||||
import be.simplenotes.app.api.ApiUserController
|
import be.simplenotes.app.api.ApiUserController
|
||||||
import be.simplenotes.app.controllers.*
|
import be.simplenotes.app.controllers.*
|
||||||
import be.simplenotes.app.filters.*
|
import be.simplenotes.app.filters.*
|
||||||
import be.simplenotes.domain.security.JwtPayload
|
import be.simplenotes.types.LoggedInUser
|
||||||
import org.http4k.core.*
|
import org.http4k.core.*
|
||||||
import org.http4k.core.Method.*
|
import org.http4k.core.Method.*
|
||||||
import org.http4k.filter.ResponseFilters.GZip
|
import org.http4k.filter.ResponseFilters.GZip
|
||||||
@@ -102,5 +102,5 @@ class Router(
|
|||||||
this to transactionFilter.then { handler(it, it.jwtPayload(contexts)) }
|
this to transactionFilter.then { handler(it, it.jwtPayload(contexts)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private typealias PublicHandler = (Request, JwtPayload?) -> Response
|
private typealias PublicHandler = (Request, LoggedInUser?) -> Response
|
||||||
private typealias ProtectedHandler = (Request, JwtPayload) -> Response
|
private typealias ProtectedHandler = (Request, LoggedInUser) -> Response
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import java.util.*
|
|||||||
|
|
||||||
internal class UuidSerializer : KSerializer<UUID> {
|
internal class UuidSerializer : KSerializer<UUID> {
|
||||||
override val descriptor: SerialDescriptor
|
override val descriptor: SerialDescriptor
|
||||||
get() = PrimitiveSerialDescriptor("LocalDateTime", PrimitiveKind.STRING)
|
get() = PrimitiveSerialDescriptor("UUID", PrimitiveKind.STRING)
|
||||||
|
|
||||||
override fun serialize(encoder: Encoder, value: UUID) {
|
override fun serialize(encoder: Encoder, value: UUID) {
|
||||||
encoder.encodeString(value.toString())
|
encoder.encodeString(value.toString())
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
package be.simplenotes.app.utils
|
|
||||||
|
|
||||||
import org.ocpsoft.prettytime.PrettyTime
|
|
||||||
import java.time.LocalDateTime
|
|
||||||
import java.time.ZoneId
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
private val prettyTime = PrettyTime()
|
|
||||||
|
|
||||||
fun LocalDateTime.toTimeAgo(): String = prettyTime.format(Date.from(atZone(ZoneId.systemDefault()).toInstant()))
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package be.simplenotes.app.filters
|
package be.simplenotes.app.filters
|
||||||
|
|
||||||
import be.simplenotes.domain.security.JwtPayload
|
import be.simplenotes.config.JwtConfig
|
||||||
import be.simplenotes.domain.security.JwtPayloadExtractor
|
import be.simplenotes.domain.security.JwtPayloadExtractor
|
||||||
import be.simplenotes.domain.security.SimpleJwt
|
import be.simplenotes.domain.security.SimpleJwt
|
||||||
import be.simplenotes.config.JwtConfig
|
import be.simplenotes.types.LoggedInUser
|
||||||
import com.natpryce.hamkrest.assertion.assertThat
|
import com.natpryce.hamkrest.assertion.assertThat
|
||||||
import org.http4k.core.*
|
import org.http4k.core.*
|
||||||
import org.http4k.core.Method.GET
|
import org.http4k.core.Method.GET
|
||||||
@@ -58,7 +58,7 @@ internal class AuthFilterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `it should allow a valid token`() {
|
fun `it should allow a valid token`() {
|
||||||
val jwtPayload = JwtPayload(1, "user")
|
val jwtPayload = LoggedInUser(1, "user")
|
||||||
val token = simpleJwt.sign(jwtPayload)
|
val token = simpleJwt.sign(jwtPayload)
|
||||||
val response = app(Request(GET, "/optional").cookie("Bearer", token))
|
val response = app(Request(GET, "/optional").cookie("Bearer", token))
|
||||||
assertThat(response, hasStatus(OK))
|
assertThat(response, hasStatus(OK))
|
||||||
@@ -84,7 +84,7 @@ internal class AuthFilterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `it should allow a valid token"`() {
|
fun `it should allow a valid token"`() {
|
||||||
val jwtPayload = JwtPayload(1, "user")
|
val jwtPayload = LoggedInUser(1, "user")
|
||||||
val token = simpleJwt.sign(jwtPayload)
|
val token = simpleJwt.sign(jwtPayload)
|
||||||
val response = app(Request(GET, "/protected").cookie("Bearer", token))
|
val response = app(Request(GET, "/protected").cookie("Bearer", token))
|
||||||
assertThat(response, hasStatus(OK))
|
assertThat(response, hasStatus(OK))
|
||||||
|
|||||||
@@ -30,7 +30,9 @@ internal class SearchTermsParserKtTest {
|
|||||||
createResult("tag:'example' title:'other' end", title = "other", tag = "example", all = "end"),
|
createResult("tag:'example' title:'other' end", title = "other", tag = "example", all = "end"),
|
||||||
createResult(
|
createResult(
|
||||||
"tag:'example abc' title:'other with words' this is the end ",
|
"tag:'example abc' title:'other with words' this is the end ",
|
||||||
title = "other with words", tag = "example abc", all = "this is the end"
|
title = "other with words",
|
||||||
|
tag = "example abc",
|
||||||
|
all = "this is the end"
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import be.simplenotes.Libs
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("be.simplenotes.base")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(Libs.koinCore)
|
||||||
|
}
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>simplenotes-parent</artifactId>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>simplenotes-config</artifactId>
|
|
||||||
|
|
||||||
|
|
||||||
</project>
|
|
||||||
+2
-5
@@ -1,12 +1,9 @@
|
|||||||
package be.simplenotes.app
|
package be.simplenotes.config
|
||||||
|
|
||||||
import be.simplenotes.config.DataSourceConfig
|
|
||||||
import be.simplenotes.config.JwtConfig
|
|
||||||
import be.simplenotes.config.ServerConfig
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class Config {
|
class ConfigLoader {
|
||||||
//region Config loading
|
//region Config loading
|
||||||
private val properties: Properties = javaClass
|
private val properties: Properties = javaClass
|
||||||
.getResource("/application.properties")
|
.getResource("/application.properties")
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package be.simplenotes.config
|
||||||
|
|
||||||
|
import org.koin.dsl.module
|
||||||
|
|
||||||
|
val configModule = module {
|
||||||
|
single { ConfigLoader() }
|
||||||
|
single { get<ConfigLoader>().dataSourceConfig }
|
||||||
|
single { get<ConfigLoader>().jwtConfig }
|
||||||
|
single { get<ConfigLoader>().serverConfig }
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import be.simplenotes.Libs
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("be.simplenotes.base")
|
||||||
|
id("be.simplenotes.kotlinx-serialization")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":simplenotes-config"))
|
||||||
|
implementation(project(":simplenotes-types"))
|
||||||
|
implementation(project(":simplenotes-persistance"))
|
||||||
|
implementation(project(":simplenotes-search"))
|
||||||
|
|
||||||
|
implementation(Libs.kotlinxSerializationJson)
|
||||||
|
implementation(Libs.koinCore)
|
||||||
|
implementation(Libs.arrowCoreData)
|
||||||
|
implementation(Libs.konform)
|
||||||
|
implementation(Libs.jbcrypt)
|
||||||
|
implementation(Libs.javaJwt)
|
||||||
|
implementation(Libs.flexmark)
|
||||||
|
implementation(Libs.flexmarkGfmTasklist)
|
||||||
|
implementation(Libs.snakeyaml)
|
||||||
|
implementation(Libs.owaspHtmlSanitizer)
|
||||||
|
implementation(Libs.commonsCompress)
|
||||||
|
|
||||||
|
testImplementation(Libs.hamkrest)
|
||||||
|
testImplementation(Libs.junit)
|
||||||
|
testImplementation(Libs.mockk)
|
||||||
|
}
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>simplenotes-parent</artifactId>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>simplenotes-domain</artifactId>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<artifactId>simplenotes-config</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<artifactId>simplenotes-test-resources</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
<type>test-jar</type>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.koin</groupId>
|
|
||||||
<artifactId>koin-core</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.arrow-kt</groupId>
|
|
||||||
<artifactId>arrow-core</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.natpryce</groupId>
|
|
||||||
<artifactId>hamkrest</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.mockk</groupId>
|
|
||||||
<artifactId>mockk</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.konform</groupId>
|
|
||||||
<artifactId>konform-jvm</artifactId>
|
|
||||||
<version>0.2.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mindrot</groupId>
|
|
||||||
<artifactId>jbcrypt</artifactId>
|
|
||||||
<version>0.4</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.auth0</groupId>
|
|
||||||
<artifactId>java-jwt</artifactId>
|
|
||||||
<version>3.10.3</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.vladsch.flexmark</groupId>
|
|
||||||
<artifactId>flexmark</artifactId>
|
|
||||||
<version>0.62.2</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.vladsch.flexmark</groupId>
|
|
||||||
<artifactId>flexmark-ext-gfm-tasklist</artifactId>
|
|
||||||
<version>0.62.2</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.yaml</groupId>
|
|
||||||
<artifactId>snakeyaml</artifactId>
|
|
||||||
<version>1.26</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.googlecode.owasp-java-html-sanitizer</groupId>
|
|
||||||
<artifactId>owasp-java-html-sanitizer</artifactId>
|
|
||||||
<version>20200713.1</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.commons</groupId>
|
|
||||||
<artifactId>commons-compress</artifactId>
|
|
||||||
<version>1.20</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<artifactId>simplenotes-types</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<artifactId>simplenotes-persistance</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<artifactId>simplenotes-search</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
</project>
|
|
||||||
+3
-7
@@ -1,18 +1,14 @@
|
|||||||
package be.simplenotes.domain.security
|
package be.simplenotes.domain.security
|
||||||
|
|
||||||
import be.simplenotes.types.PersistedUser
|
import be.simplenotes.types.LoggedInUser
|
||||||
import com.auth0.jwt.exceptions.JWTVerificationException
|
import com.auth0.jwt.exceptions.JWTVerificationException
|
||||||
|
|
||||||
data class JwtPayload(val userId: Int, val username: String) {
|
|
||||||
constructor(user: PersistedUser) : this(user.id, user.username)
|
|
||||||
}
|
|
||||||
|
|
||||||
class JwtPayloadExtractor(private val jwt: SimpleJwt) {
|
class JwtPayloadExtractor(private val jwt: SimpleJwt) {
|
||||||
operator fun invoke(token: String): JwtPayload? = try {
|
operator fun invoke(token: String): LoggedInUser? = try {
|
||||||
val decodedJWT = jwt.verifier.verify(token)
|
val decodedJWT = jwt.verifier.verify(token)
|
||||||
val id = decodedJWT.getClaim(userIdField).asInt() ?: null
|
val id = decodedJWT.getClaim(userIdField).asInt() ?: null
|
||||||
val username = decodedJWT.getClaim(usernameField).asString() ?: null
|
val username = decodedJWT.getClaim(usernameField).asString() ?: null
|
||||||
id?.let { username?.let { JwtPayload(id, username) } }
|
id?.let { username?.let { LoggedInUser(id, username) } }
|
||||||
} catch (e: JWTVerificationException) {
|
} catch (e: JWTVerificationException) {
|
||||||
null
|
null
|
||||||
} catch (e: IllegalArgumentException) {
|
} catch (e: IllegalArgumentException) {
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package be.simplenotes.domain.security
|
package be.simplenotes.domain.security
|
||||||
|
|
||||||
import be.simplenotes.config.JwtConfig
|
import be.simplenotes.config.JwtConfig
|
||||||
|
import be.simplenotes.types.LoggedInUser
|
||||||
import com.auth0.jwt.JWT
|
import com.auth0.jwt.JWT
|
||||||
import com.auth0.jwt.JWTVerifier
|
import com.auth0.jwt.JWTVerifier
|
||||||
import com.auth0.jwt.algorithms.Algorithm
|
import com.auth0.jwt.algorithms.Algorithm
|
||||||
@@ -15,9 +16,9 @@ class SimpleJwt(jwtConfig: JwtConfig) {
|
|||||||
private val algorithm = Algorithm.HMAC256(jwtConfig.secret)
|
private val algorithm = Algorithm.HMAC256(jwtConfig.secret)
|
||||||
|
|
||||||
val verifier: JWTVerifier = JWT.require(algorithm).build()
|
val verifier: JWTVerifier = JWT.require(algorithm).build()
|
||||||
fun sign(jwtPayload: JwtPayload): String = JWT.create()
|
fun sign(loggedInUser: LoggedInUser): String = JWT.create()
|
||||||
.withClaim(userIdField, jwtPayload.userId)
|
.withClaim(userIdField, loggedInUser.userId)
|
||||||
.withClaim(usernameField, jwtPayload.username)
|
.withClaim(usernameField, loggedInUser.username)
|
||||||
.withExpiresAt(getExpiration())
|
.withExpiresAt(getExpiration())
|
||||||
.sign(algorithm)
|
.sign(algorithm)
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
package be.simplenotes.domain.usecases
|
package be.simplenotes.domain.usecases
|
||||||
|
|
||||||
import arrow.core.Either
|
import arrow.core.computations.either
|
||||||
import arrow.core.extensions.fx
|
|
||||||
import be.simplenotes.types.Note
|
|
||||||
import be.simplenotes.types.PersistedNote
|
|
||||||
import be.simplenotes.types.PersistedNoteMetadata
|
|
||||||
import be.simplenotes.domain.security.HtmlSanitizer
|
import be.simplenotes.domain.security.HtmlSanitizer
|
||||||
import be.simplenotes.domain.usecases.markdown.MarkdownConverter
|
import be.simplenotes.domain.usecases.markdown.MarkdownConverter
|
||||||
import be.simplenotes.domain.usecases.markdown.MarkdownParsingError
|
import be.simplenotes.domain.usecases.markdown.MarkdownParsingError
|
||||||
@@ -12,6 +8,9 @@ import be.simplenotes.persistance.repositories.NoteRepository
|
|||||||
import be.simplenotes.persistance.repositories.UserRepository
|
import be.simplenotes.persistance.repositories.UserRepository
|
||||||
import be.simplenotes.search.NoteSearcher
|
import be.simplenotes.search.NoteSearcher
|
||||||
import be.simplenotes.search.SearchTerms
|
import be.simplenotes.search.SearchTerms
|
||||||
|
import be.simplenotes.types.Note
|
||||||
|
import be.simplenotes.types.PersistedNote
|
||||||
|
import be.simplenotes.types.PersistedNoteMetadata
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class NoteService(
|
class NoteService(
|
||||||
@@ -21,7 +20,7 @@ class NoteService(
|
|||||||
private val searcher: NoteSearcher,
|
private val searcher: NoteSearcher,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun create(userId: Int, markdownText: String) = Either.fx<MarkdownParsingError, PersistedNote> {
|
fun create(userId: Int, markdownText: String) = either.eager<MarkdownParsingError, PersistedNote> {
|
||||||
val persistedNote = !markdownConverter.renderDocument(markdownText)
|
val persistedNote = !markdownConverter.renderDocument(markdownText)
|
||||||
.map { it.copy(html = HtmlSanitizer.sanitize(it.html)) }
|
.map { it.copy(html = HtmlSanitizer.sanitize(it.html)) }
|
||||||
.map { Note(it.metadata, markdown = markdownText, html = it.html) }
|
.map { Note(it.metadata, markdown = markdownText, html = it.html) }
|
||||||
@@ -31,7 +30,7 @@ class NoteService(
|
|||||||
persistedNote
|
persistedNote
|
||||||
}
|
}
|
||||||
|
|
||||||
fun update(userId: Int, uuid: UUID, markdownText: String) = Either.fx<MarkdownParsingError, PersistedNote?> {
|
fun update(userId: Int, uuid: UUID, markdownText: String) = either.eager<MarkdownParsingError, PersistedNote?> {
|
||||||
val persistedNote = !markdownConverter.renderDocument(markdownText)
|
val persistedNote = !markdownConverter.renderDocument(markdownText)
|
||||||
.map { it.copy(html = HtmlSanitizer.sanitize(it.html)) }
|
.map { it.copy(html = HtmlSanitizer.sanitize(it.html)) }
|
||||||
.map { Note(it.metadata, markdown = markdownText, html = it.html) }
|
.map { Note(it.metadata, markdown = markdownText, html = it.html) }
|
||||||
|
|||||||
+1
-2
@@ -1,7 +1,7 @@
|
|||||||
package be.simplenotes.domain.usecases.export
|
package be.simplenotes.domain.usecases.export
|
||||||
|
|
||||||
import be.simplenotes.types.ExportedNote
|
|
||||||
import be.simplenotes.persistance.repositories.NoteRepository
|
import be.simplenotes.persistance.repositories.NoteRepository
|
||||||
|
import be.simplenotes.types.ExportedNote
|
||||||
import kotlinx.serialization.builtins.ListSerializer
|
import kotlinx.serialization.builtins.ListSerializer
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry
|
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry
|
||||||
@@ -31,7 +31,6 @@ internal class ExportUseCaseImpl(private val noteRepository: NoteRepository, pri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ZipOutput : AutoCloseable {
|
class ZipOutput : AutoCloseable {
|
||||||
val outputStream = ByteArrayOutputStream()
|
val outputStream = ByteArrayOutputStream()
|
||||||
private val zipOutputStream = ZipArchiveOutputStream(outputStream)
|
private val zipOutputStream = ZipArchiveOutputStream(outputStream)
|
||||||
|
|||||||
+4
-4
@@ -1,11 +1,11 @@
|
|||||||
package be.simplenotes.domain.usecases.markdown
|
package be.simplenotes.domain.usecases.markdown
|
||||||
|
|
||||||
import arrow.core.Either
|
import arrow.core.Either
|
||||||
import arrow.core.extensions.fx
|
import arrow.core.computations.either
|
||||||
import arrow.core.left
|
import arrow.core.left
|
||||||
import arrow.core.right
|
import arrow.core.right
|
||||||
import be.simplenotes.types.NoteMetadata
|
|
||||||
import be.simplenotes.domain.validation.NoteValidations
|
import be.simplenotes.domain.validation.NoteValidations
|
||||||
|
import be.simplenotes.types.NoteMetadata
|
||||||
import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension
|
import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension
|
||||||
import com.vladsch.flexmark.html.HtmlRenderer
|
import com.vladsch.flexmark.html.HtmlRenderer
|
||||||
import com.vladsch.flexmark.parser.Parser
|
import com.vladsch.flexmark.parser.Parser
|
||||||
@@ -73,10 +73,10 @@ internal class MarkdownConverterImpl : MarkdownConverter {
|
|||||||
|
|
||||||
private fun renderMarkdown(markdown: String) = parser.parse(markdown).run(renderer::render)
|
private fun renderMarkdown(markdown: String) = parser.parse(markdown).run(renderer::render)
|
||||||
|
|
||||||
override fun renderDocument(input: String) = Either.fx<MarkdownParsingError, Document> {
|
override fun renderDocument(input: String) = either.eager<MarkdownParsingError, Document> {
|
||||||
val (meta, md) = !splitMetaFromDocument(input)
|
val (meta, md) = !splitMetaFromDocument(input)
|
||||||
val parsedMeta = !parseMeta(meta)
|
val parsedMeta = !parseMeta(meta)
|
||||||
!NoteValidations.validateMetadata(parsedMeta).toEither { }.swap()
|
!Either.fromNullable(NoteValidations.validateMetadata(parsedMeta)).swap()
|
||||||
val html = renderMarkdown(md)
|
val html = renderMarkdown(md)
|
||||||
Document(parsedMeta, html)
|
Document(parsedMeta, html)
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-8
@@ -1,27 +1,27 @@
|
|||||||
package be.simplenotes.domain.usecases.users.delete
|
package be.simplenotes.domain.usecases.users.delete
|
||||||
|
|
||||||
import arrow.core.Either
|
import arrow.core.Either
|
||||||
import arrow.core.extensions.fx
|
import arrow.core.computations.either
|
||||||
import arrow.core.rightIfNotNull
|
import arrow.core.rightIfNotNull
|
||||||
import be.simplenotes.domain.security.PasswordHash
|
import be.simplenotes.domain.security.PasswordHash
|
||||||
import be.simplenotes.persistance.repositories.UserRepository
|
|
||||||
import be.simplenotes.domain.validation.UserValidations
|
import be.simplenotes.domain.validation.UserValidations
|
||||||
|
import be.simplenotes.persistance.repositories.UserRepository
|
||||||
import be.simplenotes.search.NoteSearcher
|
import be.simplenotes.search.NoteSearcher
|
||||||
|
|
||||||
internal class DeleteUseCaseImpl(
|
internal class DeleteUseCaseImpl(
|
||||||
private val userRepository: UserRepository,
|
private val userRepository: UserRepository,
|
||||||
private val passwordHash: PasswordHash,
|
private val passwordHash: PasswordHash,
|
||||||
private val searcher: NoteSearcher,
|
private val searcher: NoteSearcher,
|
||||||
) : DeleteUseCase {
|
) : DeleteUseCase {
|
||||||
override fun delete(form: DeleteForm) = Either.fx<DeleteError, Unit> {
|
override fun delete(form: DeleteForm) = either.eager<DeleteError, Unit> {
|
||||||
val user = !UserValidations.validateDelete(form)
|
val user = !UserValidations.validateDelete(form)
|
||||||
val persistedUser = !userRepository.find(user.username).rightIfNotNull { DeleteError.Unregistered }
|
val persistedUser = !userRepository.find(user.username).rightIfNotNull { DeleteError.Unregistered }
|
||||||
!Either.cond(
|
!Either.conditionally(
|
||||||
passwordHash.verify(user.password, persistedUser.password),
|
passwordHash.verify(user.password, persistedUser.password),
|
||||||
{ Unit },
|
{ DeleteError.WrongPassword },
|
||||||
{ DeleteError.WrongPassword }
|
{ Unit }
|
||||||
)
|
)
|
||||||
!Either.cond(userRepository.delete(persistedUser.id), { Unit }, { DeleteError.Unregistered })
|
!Either.conditionally(userRepository.delete(persistedUser.id), { DeleteError.Unregistered }, { Unit })
|
||||||
searcher.dropIndex(persistedUser.id)
|
searcher.dropIndex(persistedUser.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-5
@@ -1,25 +1,24 @@
|
|||||||
package be.simplenotes.domain.usecases.users.login
|
package be.simplenotes.domain.usecases.users.login
|
||||||
|
|
||||||
import arrow.core.Either
|
import arrow.core.computations.either
|
||||||
import arrow.core.extensions.fx
|
|
||||||
import arrow.core.filterOrElse
|
import arrow.core.filterOrElse
|
||||||
import arrow.core.rightIfNotNull
|
import arrow.core.rightIfNotNull
|
||||||
import be.simplenotes.domain.security.JwtPayload
|
|
||||||
import be.simplenotes.domain.security.PasswordHash
|
import be.simplenotes.domain.security.PasswordHash
|
||||||
import be.simplenotes.domain.security.SimpleJwt
|
import be.simplenotes.domain.security.SimpleJwt
|
||||||
import be.simplenotes.domain.validation.UserValidations
|
import be.simplenotes.domain.validation.UserValidations
|
||||||
import be.simplenotes.persistance.repositories.UserRepository
|
import be.simplenotes.persistance.repositories.UserRepository
|
||||||
|
import be.simplenotes.types.LoggedInUser
|
||||||
|
|
||||||
internal class LoginUseCaseImpl(
|
internal class LoginUseCaseImpl(
|
||||||
private val userRepository: UserRepository,
|
private val userRepository: UserRepository,
|
||||||
private val passwordHash: PasswordHash,
|
private val passwordHash: PasswordHash,
|
||||||
private val jwt: SimpleJwt
|
private val jwt: SimpleJwt
|
||||||
) : LoginUseCase {
|
) : LoginUseCase {
|
||||||
override fun login(form: LoginForm) = Either.fx<LoginError, Token> {
|
override fun login(form: LoginForm) = either.eager<LoginError, Token> {
|
||||||
val user = !UserValidations.validateLogin(form)
|
val user = !UserValidations.validateLogin(form)
|
||||||
!userRepository.find(user.username)
|
!userRepository.find(user.username)
|
||||||
.rightIfNotNull { Unregistered }
|
.rightIfNotNull { Unregistered }
|
||||||
.filterOrElse({ passwordHash.verify(form.password!!, it.password) }, { WrongPassword })
|
.filterOrElse({ passwordHash.verify(form.password!!, it.password) }, { WrongPassword })
|
||||||
.map { jwt.sign(JwtPayload(it)) }
|
.map { jwt.sign(LoggedInUser(it)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -3,10 +3,10 @@ package be.simplenotes.domain.usecases.users.register
|
|||||||
import arrow.core.Either
|
import arrow.core.Either
|
||||||
import arrow.core.filterOrElse
|
import arrow.core.filterOrElse
|
||||||
import arrow.core.leftIfNull
|
import arrow.core.leftIfNull
|
||||||
import be.simplenotes.types.PersistedUser
|
|
||||||
import be.simplenotes.domain.security.PasswordHash
|
import be.simplenotes.domain.security.PasswordHash
|
||||||
import be.simplenotes.domain.validation.UserValidations
|
import be.simplenotes.domain.validation.UserValidations
|
||||||
import be.simplenotes.persistance.repositories.UserRepository
|
import be.simplenotes.persistance.repositories.UserRepository
|
||||||
|
import be.simplenotes.types.PersistedUser
|
||||||
|
|
||||||
internal class RegisterUseCaseImpl(
|
internal class RegisterUseCaseImpl(
|
||||||
private val userRepository: UserRepository,
|
private val userRepository: UserRepository,
|
||||||
|
|||||||
+1
-1
@@ -1,8 +1,8 @@
|
|||||||
package be.simplenotes.domain.usecases.users.register
|
package be.simplenotes.domain.usecases.users.register
|
||||||
|
|
||||||
import arrow.core.Either
|
import arrow.core.Either
|
||||||
import be.simplenotes.types.PersistedUser
|
|
||||||
import be.simplenotes.domain.usecases.users.login.LoginForm
|
import be.simplenotes.domain.usecases.users.login.LoginForm
|
||||||
|
import be.simplenotes.types.PersistedUser
|
||||||
import io.konform.validation.ValidationErrors
|
import io.konform.validation.ValidationErrors
|
||||||
|
|
||||||
sealed class RegisterError
|
sealed class RegisterError
|
||||||
|
|||||||
+4
-5
@@ -1,8 +1,7 @@
|
|||||||
package be.simplenotes.domain.validation
|
package be.simplenotes.domain.validation
|
||||||
|
|
||||||
import arrow.core.*
|
|
||||||
import be.simplenotes.types.NoteMetadata
|
|
||||||
import be.simplenotes.domain.usecases.markdown.ValidationError
|
import be.simplenotes.domain.usecases.markdown.ValidationError
|
||||||
|
import be.simplenotes.types.NoteMetadata
|
||||||
import io.konform.validation.Validation
|
import io.konform.validation.Validation
|
||||||
import io.konform.validation.jsonschema.maxItems
|
import io.konform.validation.jsonschema.maxItems
|
||||||
import io.konform.validation.jsonschema.maxLength
|
import io.konform.validation.jsonschema.maxLength
|
||||||
@@ -28,9 +27,9 @@ internal object NoteValidations {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun validateMetadata(meta: NoteMetadata): Option<ValidationError> {
|
fun validateMetadata(meta: NoteMetadata): ValidationError? {
|
||||||
val errors = metaValidator.validate(meta).errors
|
val errors = metaValidator.validate(meta).errors
|
||||||
return if (errors.isEmpty()) none()
|
return if (errors.isEmpty()) null
|
||||||
else return ValidationError(errors).some()
|
else return ValidationError(errors)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -3,13 +3,13 @@ package be.simplenotes.domain.validation
|
|||||||
import arrow.core.Either
|
import arrow.core.Either
|
||||||
import arrow.core.left
|
import arrow.core.left
|
||||||
import arrow.core.right
|
import arrow.core.right
|
||||||
import be.simplenotes.types.User
|
|
||||||
import be.simplenotes.domain.usecases.users.delete.DeleteError
|
import be.simplenotes.domain.usecases.users.delete.DeleteError
|
||||||
import be.simplenotes.domain.usecases.users.delete.DeleteForm
|
import be.simplenotes.domain.usecases.users.delete.DeleteForm
|
||||||
import be.simplenotes.domain.usecases.users.login.InvalidLoginForm
|
import be.simplenotes.domain.usecases.users.login.InvalidLoginForm
|
||||||
import be.simplenotes.domain.usecases.users.login.LoginForm
|
import be.simplenotes.domain.usecases.users.login.LoginForm
|
||||||
import be.simplenotes.domain.usecases.users.register.InvalidRegisterForm
|
import be.simplenotes.domain.usecases.users.register.InvalidRegisterForm
|
||||||
import be.simplenotes.domain.usecases.users.register.RegisterForm
|
import be.simplenotes.domain.usecases.users.register.RegisterForm
|
||||||
|
import be.simplenotes.types.User
|
||||||
import io.konform.validation.Validation
|
import io.konform.validation.Validation
|
||||||
import io.konform.validation.jsonschema.maxLength
|
import io.konform.validation.jsonschema.maxLength
|
||||||
import io.konform.validation.jsonschema.minLength
|
import io.konform.validation.jsonschema.minLength
|
||||||
|
|||||||
+4
-3
@@ -1,7 +1,8 @@
|
|||||||
package be.simplenotes.domain.security
|
package be.simplenotes.domain.security
|
||||||
|
|
||||||
import be.simplenotes.domain.usecases.users.login.Token
|
|
||||||
import be.simplenotes.config.JwtConfig
|
import be.simplenotes.config.JwtConfig
|
||||||
|
import be.simplenotes.domain.usecases.users.login.Token
|
||||||
|
import be.simplenotes.types.LoggedInUser
|
||||||
import com.auth0.jwt.JWT
|
import com.auth0.jwt.JWT
|
||||||
import com.auth0.jwt.algorithms.Algorithm
|
import com.auth0.jwt.algorithms.Algorithm
|
||||||
import com.natpryce.hamkrest.absent
|
import com.natpryce.hamkrest.absent
|
||||||
@@ -13,7 +14,7 @@ import org.junit.jupiter.params.provider.MethodSource
|
|||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
|
|
||||||
internal class JwtPayloadExtractorTest {
|
internal class LoggedInUserExtractorTest {
|
||||||
private val jwtConfig = JwtConfig("a secret", 1, TimeUnit.HOURS)
|
private val jwtConfig = JwtConfig("a secret", 1, TimeUnit.HOURS)
|
||||||
private val simpleJwt = SimpleJwt(jwtConfig)
|
private val simpleJwt = SimpleJwt(jwtConfig)
|
||||||
private val jwtPayloadExtractor = JwtPayloadExtractor(simpleJwt)
|
private val jwtPayloadExtractor = JwtPayloadExtractor(simpleJwt)
|
||||||
@@ -45,6 +46,6 @@ internal class JwtPayloadExtractorTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `parse valid token`() {
|
fun `parse valid token`() {
|
||||||
val token = createToken(username = "someone", id = 1)
|
val token = createToken(username = "someone", id = 1)
|
||||||
assertThat(jwtPayloadExtractor(token), equalTo(JwtPayload(1, "someone")))
|
assertThat(jwtPayloadExtractor(token), equalTo(LoggedInUser(1, "someone")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
-3
@@ -1,12 +1,12 @@
|
|||||||
package be.simplenotes.domain.usecases.users.login
|
package be.simplenotes.domain.usecases.users.login
|
||||||
|
|
||||||
import be.simplenotes.types.PersistedUser
|
import be.simplenotes.config.JwtConfig
|
||||||
import be.simplenotes.domain.security.BcryptPasswordHash
|
import be.simplenotes.domain.security.BcryptPasswordHash
|
||||||
import be.simplenotes.domain.security.SimpleJwt
|
import be.simplenotes.domain.security.SimpleJwt
|
||||||
import be.simplenotes.persistance.repositories.UserRepository
|
|
||||||
import be.simplenotes.config.JwtConfig
|
|
||||||
import be.simplenotes.domain.testutils.isLeftOfType
|
import be.simplenotes.domain.testutils.isLeftOfType
|
||||||
import be.simplenotes.domain.testutils.isRight
|
import be.simplenotes.domain.testutils.isRight
|
||||||
|
import be.simplenotes.persistance.repositories.UserRepository
|
||||||
|
import be.simplenotes.types.PersistedUser
|
||||||
import com.natpryce.hamkrest.assertion.assertThat
|
import com.natpryce.hamkrest.assertion.assertThat
|
||||||
import io.mockk.*
|
import io.mockk.*
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
|
|||||||
+1
-1
@@ -1,10 +1,10 @@
|
|||||||
package be.simplenotes.domain.usecases.users.register
|
package be.simplenotes.domain.usecases.users.register
|
||||||
|
|
||||||
import be.simplenotes.types.PersistedUser
|
|
||||||
import be.simplenotes.domain.security.BcryptPasswordHash
|
import be.simplenotes.domain.security.BcryptPasswordHash
|
||||||
import be.simplenotes.domain.testutils.isLeftOfType
|
import be.simplenotes.domain.testutils.isLeftOfType
|
||||||
import be.simplenotes.domain.testutils.isRight
|
import be.simplenotes.domain.testutils.isRight
|
||||||
import be.simplenotes.persistance.repositories.UserRepository
|
import be.simplenotes.persistance.repositories.UserRepository
|
||||||
|
import be.simplenotes.types.PersistedUser
|
||||||
import com.natpryce.hamkrest.assertion.assertThat
|
import com.natpryce.hamkrest.assertion.assertThat
|
||||||
import com.natpryce.hamkrest.equalTo
|
import com.natpryce.hamkrest.equalTo
|
||||||
import io.mockk.*
|
import io.mockk.*
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import be.simplenotes.Libs
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("be.simplenotes.base")
|
||||||
|
kotlin("kapt")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":simplenotes-types"))
|
||||||
|
implementation(project(":simplenotes-config"))
|
||||||
|
|
||||||
|
implementation(Libs.mapstruct)
|
||||||
|
implementation(Libs.koinCore)
|
||||||
|
implementation(Libs.mariadbClient)
|
||||||
|
implementation(Libs.h2)
|
||||||
|
implementation(Libs.flywayCore)
|
||||||
|
implementation(Libs.hikariCP)
|
||||||
|
implementation(Libs.ktormCore)
|
||||||
|
implementation(Libs.ktormMysql)
|
||||||
|
|
||||||
|
kapt(Libs.mapstructProcessor)
|
||||||
|
|
||||||
|
testImplementation(Libs.junit)
|
||||||
|
testImplementation(Libs.assertJ)
|
||||||
|
}
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>simplenotes-parent</artifactId>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>simplenotes-persistance</artifactId>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mapstruct</groupId>
|
|
||||||
<artifactId>mapstruct</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<artifactId>simplenotes-types</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<artifactId>simplenotes-config</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<artifactId>simplenotes-test-resources</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
<type>test-jar</type>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.koin</groupId>
|
|
||||||
<artifactId>koin-core</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.assertj</groupId>
|
|
||||||
<artifactId>assertj-core</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mariadb.jdbc</groupId>
|
|
||||||
<artifactId>mariadb-java-client</artifactId>
|
|
||||||
<version>2.6.2</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.h2database</groupId>
|
|
||||||
<artifactId>h2</artifactId>
|
|
||||||
<version>1.4.200</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.flywaydb</groupId>
|
|
||||||
<artifactId>flyway-core</artifactId>
|
|
||||||
<version>6.5.4</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.zaxxer</groupId>
|
|
||||||
<artifactId>HikariCP</artifactId>
|
|
||||||
<version>3.4.3</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>me.liuwj.ktorm</groupId>
|
|
||||||
<artifactId>ktorm-core</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>me.liuwj.ktorm</groupId>
|
|
||||||
<artifactId>ktorm-support-mysql</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
</project>
|
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
package be.simplenotes.persistance
|
package be.simplenotes.persistance
|
||||||
|
|
||||||
|
import be.simplenotes.config.DataSourceConfig
|
||||||
import be.simplenotes.persistance.utils.DbType
|
import be.simplenotes.persistance.utils.DbType
|
||||||
import be.simplenotes.persistance.utils.type
|
import be.simplenotes.persistance.utils.type
|
||||||
import be.simplenotes.config.DataSourceConfig
|
|
||||||
import me.liuwj.ktorm.database.Database
|
import me.liuwj.ktorm.database.Database
|
||||||
import me.liuwj.ktorm.database.asIterable
|
import me.liuwj.ktorm.database.asIterable
|
||||||
|
import me.liuwj.ktorm.database.use
|
||||||
import java.sql.SQLTransientException
|
import java.sql.SQLTransientException
|
||||||
|
|
||||||
interface DbHealthCheck {
|
interface DbHealthCheck {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package be.simplenotes.persistance
|
package be.simplenotes.persistance
|
||||||
|
|
||||||
|
import be.simplenotes.config.DataSourceConfig
|
||||||
import be.simplenotes.persistance.utils.DbType
|
import be.simplenotes.persistance.utils.DbType
|
||||||
import be.simplenotes.persistance.utils.type
|
import be.simplenotes.persistance.utils.type
|
||||||
import be.simplenotes.config.DataSourceConfig
|
|
||||||
import org.flywaydb.core.Flyway
|
import org.flywaydb.core.Flyway
|
||||||
import javax.sql.DataSource
|
import javax.sql.DataSource
|
||||||
|
|
||||||
|
|||||||
+8
-5
@@ -1,20 +1,20 @@
|
|||||||
package be.simplenotes.persistance.converters
|
package be.simplenotes.persistance.converters
|
||||||
|
|
||||||
import be.simplenotes.types.*
|
|
||||||
import be.simplenotes.persistance.notes.NoteEntity
|
import be.simplenotes.persistance.notes.NoteEntity
|
||||||
|
import be.simplenotes.types.*
|
||||||
import me.liuwj.ktorm.entity.Entity
|
import me.liuwj.ktorm.entity.Entity
|
||||||
import org.mapstruct.Mapper
|
import org.mapstruct.Mapper
|
||||||
import org.mapstruct.Mapping
|
import org.mapstruct.Mapping
|
||||||
import org.mapstruct.Mappings
|
import org.mapstruct.Mappings
|
||||||
|
import org.mapstruct.ReportingPolicy
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is an abstract class because kotlin default methods in interface are not seen as default in kapt
|
* 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)
|
* @see [KT-25960](https://youtrack.jetbrains.com/issue/KT-25960)
|
||||||
*/
|
*/
|
||||||
@Mapper(uses = [NoteEntityFactory::class, UserEntityFactory::class])
|
@Mapper(uses = [NoteEntityFactory::class, UserEntityFactory::class], unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||||
internal abstract class NoteConverter {
|
internal abstract class NoteConverter {
|
||||||
|
|
||||||
fun toNote(entity: NoteEntity, tags: Tags) =
|
fun toNote(entity: NoteEntity, tags: Tags) =
|
||||||
@@ -34,7 +34,11 @@ internal abstract class NoteConverter {
|
|||||||
|
|
||||||
fun toPersistedNote(entity: NoteEntity, tags: Tags) = PersistedNote(
|
fun toPersistedNote(entity: NoteEntity, tags: Tags) = PersistedNote(
|
||||||
NoteMetadata(title = entity.title, tags = tags),
|
NoteMetadata(title = entity.title, tags = tags),
|
||||||
entity.markdown, entity.html, entity.updatedAt, entity.uuid, entity.public
|
entity.markdown,
|
||||||
|
entity.html,
|
||||||
|
entity.updatedAt,
|
||||||
|
entity.uuid,
|
||||||
|
entity.public
|
||||||
)
|
)
|
||||||
|
|
||||||
@Mappings(
|
@Mappings(
|
||||||
@@ -72,7 +76,6 @@ internal abstract class NoteConverter {
|
|||||||
|
|
||||||
@Mapping(target = "deleted", source = "trash")
|
@Mapping(target = "deleted", source = "trash")
|
||||||
abstract fun toEntity(exportedNote: ExportedNote): NoteEntity
|
abstract fun toEntity(exportedNote: ExportedNote): NoteEntity
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typealias Tags = List<String>
|
typealias Tags = List<String>
|
||||||
|
|||||||
+3
-2
@@ -1,12 +1,13 @@
|
|||||||
package be.simplenotes.persistance.converters
|
package be.simplenotes.persistance.converters
|
||||||
|
|
||||||
|
import be.simplenotes.persistance.users.UserEntity
|
||||||
import be.simplenotes.types.PersistedUser
|
import be.simplenotes.types.PersistedUser
|
||||||
import be.simplenotes.types.User
|
import be.simplenotes.types.User
|
||||||
import be.simplenotes.persistance.users.UserEntity
|
|
||||||
import me.liuwj.ktorm.entity.Entity
|
import me.liuwj.ktorm.entity.Entity
|
||||||
import org.mapstruct.Mapper
|
import org.mapstruct.Mapper
|
||||||
|
import org.mapstruct.ReportingPolicy
|
||||||
|
|
||||||
@Mapper(uses = [UserEntityFactory::class])
|
@Mapper(uses = [UserEntityFactory::class], unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||||
internal interface UserConverter {
|
internal interface UserConverter {
|
||||||
fun toUser(userEntity: UserEntity): User
|
fun toUser(userEntity: UserEntity): User
|
||||||
fun toPersistedUser(userEntity: UserEntity): PersistedUser
|
fun toPersistedUser(userEntity: UserEntity): PersistedUser
|
||||||
|
|||||||
+2
-3
@@ -1,11 +1,11 @@
|
|||||||
package be.simplenotes.persistance.notes
|
package be.simplenotes.persistance.notes
|
||||||
|
|
||||||
|
import be.simplenotes.persistance.converters.NoteConverter
|
||||||
|
import be.simplenotes.persistance.repositories.NoteRepository
|
||||||
import be.simplenotes.types.ExportedNote
|
import be.simplenotes.types.ExportedNote
|
||||||
import be.simplenotes.types.Note
|
import be.simplenotes.types.Note
|
||||||
import be.simplenotes.types.PersistedNote
|
import be.simplenotes.types.PersistedNote
|
||||||
import be.simplenotes.types.PersistedNoteMetadata
|
import be.simplenotes.types.PersistedNoteMetadata
|
||||||
import be.simplenotes.persistance.converters.NoteConverter
|
|
||||||
import be.simplenotes.persistance.repositories.NoteRepository
|
|
||||||
import me.liuwj.ktorm.database.Database
|
import me.liuwj.ktorm.database.Database
|
||||||
import me.liuwj.ktorm.dsl.*
|
import me.liuwj.ktorm.dsl.*
|
||||||
import me.liuwj.ktorm.entity.*
|
import me.liuwj.ktorm.entity.*
|
||||||
@@ -211,5 +211,4 @@ internal class NoteRepositoryImpl(private val db: Database, private val converte
|
|||||||
.filter { it.noteUuid inList map { note -> note.uuid } }
|
.filter { it.noteUuid inList map { note -> note.uuid } }
|
||||||
.groupByTo(HashMap(), { it.note.uuid }, { it.name })
|
.groupByTo(HashMap(), { it.note.uuid }, { it.name })
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
package be.simplenotes.persistance.users
|
package be.simplenotes.persistance.users
|
||||||
|
|
||||||
import be.simplenotes.types.PersistedUser
|
|
||||||
import be.simplenotes.types.User
|
|
||||||
import be.simplenotes.persistance.converters.UserConverter
|
import be.simplenotes.persistance.converters.UserConverter
|
||||||
import be.simplenotes.persistance.repositories.UserRepository
|
import be.simplenotes.persistance.repositories.UserRepository
|
||||||
|
import be.simplenotes.types.PersistedUser
|
||||||
|
import be.simplenotes.types.User
|
||||||
import me.liuwj.ktorm.database.Database
|
import me.liuwj.ktorm.database.Database
|
||||||
import me.liuwj.ktorm.dsl.*
|
import me.liuwj.ktorm.dsl.*
|
||||||
import me.liuwj.ktorm.entity.any
|
import me.liuwj.ktorm.entity.any
|
||||||
|
|||||||
+6
-5
@@ -26,10 +26,14 @@ internal class NoteConverterTest {
|
|||||||
}
|
}
|
||||||
val tags = listOf("a", "b")
|
val tags = listOf("a", "b")
|
||||||
val note = converter.toNote(entity, tags)
|
val note = converter.toNote(entity, tags)
|
||||||
val expectedNote = Note(NoteMetadata(
|
val expectedNote = Note(
|
||||||
|
NoteMetadata(
|
||||||
title = "title",
|
title = "title",
|
||||||
tags = tags,
|
tags = tags,
|
||||||
), markdown = "md", html = "html")
|
),
|
||||||
|
markdown = "md",
|
||||||
|
html = "html"
|
||||||
|
)
|
||||||
assertThat(note).isEqualTo(expectedNote)
|
assertThat(note).isEqualTo(expectedNote)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +81,6 @@ internal class NoteConverterTest {
|
|||||||
)
|
)
|
||||||
assertThat(note).isEqualTo(expectedNote)
|
assertThat(note).isEqualTo(expectedNote)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@@ -162,7 +165,5 @@ internal class NoteConverterTest {
|
|||||||
.hasFieldOrPropertyWithValue("updatedAt", exportedNote.updatedAt)
|
.hasFieldOrPropertyWithValue("updatedAt", exportedNote.updatedAt)
|
||||||
.hasFieldOrPropertyWithValue("deleted", true)
|
.hasFieldOrPropertyWithValue("deleted", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,8 +1,8 @@
|
|||||||
package be.simplenotes.persistance.converters
|
package be.simplenotes.persistance.converters
|
||||||
|
|
||||||
|
import be.simplenotes.persistance.users.UserEntity
|
||||||
import be.simplenotes.types.PersistedUser
|
import be.simplenotes.types.PersistedUser
|
||||||
import be.simplenotes.types.User
|
import be.simplenotes.types.User
|
||||||
import be.simplenotes.persistance.users.UserEntity
|
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.mapstruct.factory.Mappers
|
import org.mapstruct.factory.Mappers
|
||||||
|
|||||||
+1
-2
@@ -1,14 +1,13 @@
|
|||||||
package be.simplenotes.persistance.notes
|
package be.simplenotes.persistance.notes
|
||||||
|
|
||||||
|
import be.simplenotes.config.DataSourceConfig
|
||||||
import be.simplenotes.persistance.DbMigrations
|
import be.simplenotes.persistance.DbMigrations
|
||||||
import be.simplenotes.persistance.converters.NoteConverter
|
import be.simplenotes.persistance.converters.NoteConverter
|
||||||
import be.simplenotes.persistance.migrationModule
|
import be.simplenotes.persistance.migrationModule
|
||||||
import be.simplenotes.persistance.persistanceModule
|
import be.simplenotes.persistance.persistanceModule
|
||||||
import be.simplenotes.config.DataSourceConfig
|
|
||||||
import be.simplenotes.persistance.repositories.NoteRepository
|
import be.simplenotes.persistance.repositories.NoteRepository
|
||||||
import be.simplenotes.persistance.repositories.UserRepository
|
import be.simplenotes.persistance.repositories.UserRepository
|
||||||
import be.simplenotes.types.*
|
import be.simplenotes.types.*
|
||||||
import be.simplenotes.types.*
|
|
||||||
import me.liuwj.ktorm.database.Database
|
import me.liuwj.ktorm.database.Database
|
||||||
import me.liuwj.ktorm.dsl.eq
|
import me.liuwj.ktorm.dsl.eq
|
||||||
import me.liuwj.ktorm.entity.filter
|
import me.liuwj.ktorm.entity.filter
|
||||||
|
|||||||
+3
-3
@@ -1,11 +1,11 @@
|
|||||||
package be.simplenotes.persistance.users
|
package be.simplenotes.persistance.users
|
||||||
|
|
||||||
import be.simplenotes.types.User
|
import be.simplenotes.config.DataSourceConfig
|
||||||
import be.simplenotes.persistance.repositories.UserRepository
|
|
||||||
import be.simplenotes.persistance.DbMigrations
|
import be.simplenotes.persistance.DbMigrations
|
||||||
import be.simplenotes.persistance.migrationModule
|
import be.simplenotes.persistance.migrationModule
|
||||||
import be.simplenotes.persistance.persistanceModule
|
import be.simplenotes.persistance.persistanceModule
|
||||||
import be.simplenotes.config.DataSourceConfig
|
import be.simplenotes.persistance.repositories.UserRepository
|
||||||
|
import be.simplenotes.types.User
|
||||||
import me.liuwj.ktorm.database.*
|
import me.liuwj.ktorm.database.*
|
||||||
import me.liuwj.ktorm.dsl.*
|
import me.liuwj.ktorm.dsl.*
|
||||||
import me.liuwj.ktorm.entity.*
|
import me.liuwj.ktorm.entity.*
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import be.simplenotes.Libs
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("be.simplenotes.base")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":simplenotes-types"))
|
||||||
|
|
||||||
|
implementation(Libs.luceneCore)
|
||||||
|
implementation(Libs.luceneQueryParser)
|
||||||
|
implementation(Libs.luceneAnalyzersCommon)
|
||||||
|
implementation(Libs.slf4jApi)
|
||||||
|
implementation(Libs.koinCore)
|
||||||
|
|
||||||
|
testImplementation(Libs.junit)
|
||||||
|
testImplementation(Libs.assertJ)
|
||||||
|
}
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>simplenotes-parent</artifactId>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>simplenotes-search</artifactId>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<lucene.version>8.6.1</lucene.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<artifactId>simplenotes-types</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.lucene</groupId>
|
|
||||||
<artifactId>lucene-core</artifactId>
|
|
||||||
<version>${lucene.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.lucene</groupId>
|
|
||||||
<artifactId>lucene-analyzers-common</artifactId>
|
|
||||||
<version>${lucene.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.lucene</groupId>
|
|
||||||
<artifactId>lucene-queryparser</artifactId>
|
|
||||||
<version>${lucene.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-api</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.koin</groupId>
|
|
||||||
<artifactId>koin-core</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.junit.jupiter</groupId>
|
|
||||||
<artifactId>junit-jupiter</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.assertj</groupId>
|
|
||||||
<artifactId>assertj-core</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<artifactId>simplenotes-test-resources</artifactId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
<type>test-jar</type>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
|
|
||||||
</project>
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package be.simplenotes.search
|
package be.simplenotes.search
|
||||||
|
|
||||||
import be.simplenotes.types.PersistedNote
|
import be.simplenotes.types.PersistedNote
|
||||||
import be.simplenotes.search.utils.rmdir
|
|
||||||
import org.apache.lucene.analysis.standard.StandardAnalyzer
|
import org.apache.lucene.analysis.standard.StandardAnalyzer
|
||||||
import org.apache.lucene.document.Document
|
import org.apache.lucene.document.Document
|
||||||
import org.apache.lucene.index.*
|
import org.apache.lucene.index.*
|
||||||
@@ -90,7 +89,11 @@ internal class NoteSearcherImpl(basePath: Path = Path.of("/tmp", "lucene")) : No
|
|||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dropIndex(userId: Int) = rmdir(File(baseFile, userId.toString()).toPath())
|
override fun dropIndex(userId: Int) {
|
||||||
|
File(baseFile, userId.toString()).deleteRecursively()
|
||||||
|
}
|
||||||
|
|
||||||
override fun dropAll() = rmdir(baseFile.toPath())
|
override fun dropAll() {
|
||||||
|
baseFile.deleteRecursively()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
package be.simplenotes.search.utils
|
|
||||||
|
|
||||||
import java.io.IOException
|
|
||||||
import java.nio.file.FileVisitResult
|
|
||||||
import java.nio.file.Files
|
|
||||||
import java.nio.file.Path
|
|
||||||
import java.nio.file.SimpleFileVisitor
|
|
||||||
import java.nio.file.attribute.BasicFileAttributes
|
|
||||||
|
|
||||||
internal fun rmdir(path: Path) {
|
|
||||||
try {
|
|
||||||
Files.walkFileTree(
|
|
||||||
path,
|
|
||||||
object : SimpleFileVisitor<Path>() {
|
|
||||||
override fun visitFile(file: Path, attrs: BasicFileAttributes?): FileVisitResult {
|
|
||||||
Files.delete(file)
|
|
||||||
return FileVisitResult.CONTINUE
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun postVisitDirectory(dir: Path, exc: IOException?): FileVisitResult {
|
|
||||||
Files.delete(dir)
|
|
||||||
return FileVisitResult.CONTINUE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} catch (e: IOException) {
|
|
||||||
// This is fine
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -24,12 +24,14 @@ internal class NoteSearcherImplTest {
|
|||||||
content: String = "",
|
content: String = "",
|
||||||
uuid: UUID = UUID.randomUUID(),
|
uuid: UUID = UUID.randomUUID(),
|
||||||
): PersistedNote {
|
): PersistedNote {
|
||||||
val note = PersistedNote(NoteMetadata(title, tags),
|
val note = PersistedNote(
|
||||||
|
NoteMetadata(title, tags),
|
||||||
markdown = content,
|
markdown = content,
|
||||||
html = "",
|
html = "",
|
||||||
LocalDateTime.MIN,
|
LocalDateTime.MIN,
|
||||||
uuid,
|
uuid,
|
||||||
public = false)
|
public = false
|
||||||
|
)
|
||||||
searcher.indexNote(1, note)
|
searcher.indexNote(1, note)
|
||||||
return note
|
return note
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>simplenotes-parent</artifactId>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>simplenotes-test-resources</artifactId>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<goals>
|
|
||||||
<goal>test-jar</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</project>
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import be.simplenotes.Libs
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("be.simplenotes.base")
|
||||||
|
id("be.simplenotes.kotlinx-serialization")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(Libs.kotlinxSerializationJson)
|
||||||
|
}
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<artifactId>simplenotes-parent</artifactId>
|
|
||||||
<groupId>be.simplenotes</groupId>
|
|
||||||
<version>1.0-SNAPSHOT</version>
|
|
||||||
</parent>
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<artifactId>simplenotes-types</artifactId>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jetbrains.kotlinx</groupId>
|
|
||||||
<artifactId>kotlinx-serialization-json-jvm</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
</project>
|
|
||||||
@@ -2,3 +2,6 @@ package be.simplenotes.types
|
|||||||
|
|
||||||
data class User(val username: String, val password: String)
|
data class User(val username: String, val password: String)
|
||||||
data class PersistedUser(val username: String, val password: String, val id: Int)
|
data class PersistedUser(val username: String, val password: String, val id: Int)
|
||||||
|
data class LoggedInUser(val userId: Int, val username: String) {
|
||||||
|
constructor(user: PersistedUser) : this(user.id, user.username)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import be.simplenotes.Libs
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("be.simplenotes.base")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":simplenotes-types"))
|
||||||
|
|
||||||
|
implementation(Libs.koinCore)
|
||||||
|
implementation(Libs.konform)
|
||||||
|
implementation(Libs.kotlinxHtml)
|
||||||
|
implementation(Libs.prettytime)
|
||||||
|
}
|
||||||
+5
-6
@@ -1,15 +1,14 @@
|
|||||||
package be.simplenotes.app.views
|
package be.simplenotes.views
|
||||||
|
|
||||||
import be.simplenotes.app.utils.StaticFileResolver
|
import be.simplenotes.types.LoggedInUser
|
||||||
import be.simplenotes.domain.security.JwtPayload
|
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
import kotlinx.html.ThScope.col
|
import kotlinx.html.ThScope.col
|
||||||
|
|
||||||
class BaseView(staticFileResolver: StaticFileResolver) : View(staticFileResolver) {
|
class BaseView(styles: String) : View(styles) {
|
||||||
fun renderHome(jwtPayload: JwtPayload?) = renderPage(
|
fun renderHome(loggedInUser: LoggedInUser?) = renderPage(
|
||||||
title = "Home",
|
title = "Home",
|
||||||
description = "A fast and simple note taking website",
|
description = "A fast and simple note taking website",
|
||||||
jwtPayload = jwtPayload
|
loggedInUser = loggedInUser
|
||||||
) {
|
) {
|
||||||
section("text-center my-2 p-2") {
|
section("text-center my-2 p-2") {
|
||||||
h1("text-5xl casual") {
|
h1("text-5xl casual") {
|
||||||
+5
-6
@@ -1,12 +1,11 @@
|
|||||||
package be.simplenotes.app.views
|
package be.simplenotes.views
|
||||||
|
|
||||||
import be.simplenotes.app.utils.StaticFileResolver
|
import be.simplenotes.views.components.Alert
|
||||||
import be.simplenotes.app.views.components.Alert
|
import be.simplenotes.views.components.alert
|
||||||
import be.simplenotes.app.views.components.alert
|
|
||||||
import kotlinx.html.a
|
import kotlinx.html.a
|
||||||
import kotlinx.html.div
|
import kotlinx.html.div
|
||||||
|
|
||||||
class ErrorView(staticFileResolver: StaticFileResolver) : View(staticFileResolver) {
|
class ErrorView(styles: String) : View(styles) {
|
||||||
|
|
||||||
enum class Type(val title: String) {
|
enum class Type(val title: String) {
|
||||||
SqlTransientError("Database unavailable"),
|
SqlTransientError("Database unavailable"),
|
||||||
@@ -14,7 +13,7 @@ class ErrorView(staticFileResolver: StaticFileResolver) : View(staticFileResolve
|
|||||||
Other("Error"),
|
Other("Error"),
|
||||||
}
|
}
|
||||||
|
|
||||||
fun error(errorType: Type) = renderPage(errorType.title, jwtPayload = null) {
|
fun error(errorType: Type) = renderPage(errorType.title, loggedInUser = null) {
|
||||||
div("container mx-auto p-4") {
|
div("container mx-auto p-4") {
|
||||||
when (errorType) {
|
when (errorType) {
|
||||||
Type.SqlTransientError -> alert(
|
Type.SqlTransientError -> alert(
|
||||||
+19
-17
@@ -1,21 +1,20 @@
|
|||||||
package be.simplenotes.app.views
|
package be.simplenotes.views
|
||||||
|
|
||||||
import be.simplenotes.app.utils.StaticFileResolver
|
import be.simplenotes.types.LoggedInUser
|
||||||
import be.simplenotes.app.views.components.*
|
|
||||||
import be.simplenotes.types.PersistedNote
|
import be.simplenotes.types.PersistedNote
|
||||||
import be.simplenotes.types.PersistedNoteMetadata
|
import be.simplenotes.types.PersistedNoteMetadata
|
||||||
import be.simplenotes.domain.security.JwtPayload
|
import be.simplenotes.views.components.*
|
||||||
import io.konform.validation.ValidationError
|
import io.konform.validation.ValidationError
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
|
|
||||||
class NoteView(staticFileResolver: StaticFileResolver) : View(staticFileResolver) {
|
class NoteView(styles: String) : View(styles) {
|
||||||
|
|
||||||
fun noteEditor(
|
fun noteEditor(
|
||||||
jwtPayload: JwtPayload,
|
loggedInUser: LoggedInUser,
|
||||||
error: String? = null,
|
error: String? = null,
|
||||||
textarea: String? = null,
|
textarea: String? = null,
|
||||||
validationErrors: List<ValidationError> = emptyList(),
|
validationErrors: List<ValidationError> = emptyList(),
|
||||||
) = renderPage(title = "New note", jwtPayload = jwtPayload) {
|
) = renderPage(title = "New note", loggedInUser = loggedInUser) {
|
||||||
div("container mx-auto p-4") {
|
div("container mx-auto p-4") {
|
||||||
error?.let { alert(Alert.Warning, error) }
|
error?.let { alert(Alert.Warning, error) }
|
||||||
validationErrors.forEach {
|
validationErrors.forEach {
|
||||||
@@ -38,7 +37,9 @@ class NoteView(staticFileResolver: StaticFileResolver) : View(staticFileResolver
|
|||||||
|tags: []
|
|tags: []
|
||||||
|---
|
|---
|
||||||
|
|
|
|
||||||
""".trimMargin("|")
|
""".trimMargin(
|
||||||
|
"|"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
submitButton("Save")
|
submitButton("Save")
|
||||||
}
|
}
|
||||||
@@ -46,13 +47,13 @@ class NoteView(staticFileResolver: StaticFileResolver) : View(staticFileResolver
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun notes(
|
fun notes(
|
||||||
jwtPayload: JwtPayload,
|
loggedInUser: LoggedInUser,
|
||||||
notes: List<PersistedNoteMetadata>,
|
notes: List<PersistedNoteMetadata>,
|
||||||
currentPage: Int,
|
currentPage: Int,
|
||||||
numberOfPages: Int,
|
numberOfPages: Int,
|
||||||
numberOfDeletedNotes: Int,
|
numberOfDeletedNotes: Int,
|
||||||
tag: String?,
|
tag: String?,
|
||||||
) = renderPage(title = "Notes", jwtPayload = jwtPayload) {
|
) = renderPage(title = "Notes", loggedInUser = loggedInUser) {
|
||||||
div("container mx-auto p-4") {
|
div("container mx-auto p-4") {
|
||||||
noteListHeader(numberOfDeletedNotes)
|
noteListHeader(numberOfDeletedNotes)
|
||||||
if (notes.isNotEmpty())
|
if (notes.isNotEmpty())
|
||||||
@@ -68,11 +69,11 @@ class NoteView(staticFileResolver: StaticFileResolver) : View(staticFileResolver
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun search(
|
fun search(
|
||||||
jwtPayload: JwtPayload,
|
loggedInUser: LoggedInUser,
|
||||||
notes: List<PersistedNoteMetadata>,
|
notes: List<PersistedNoteMetadata>,
|
||||||
query: String,
|
query: String,
|
||||||
numberOfDeletedNotes: Int,
|
numberOfDeletedNotes: Int,
|
||||||
) = renderPage("Notes", jwtPayload = jwtPayload) {
|
) = renderPage("Notes", loggedInUser = loggedInUser) {
|
||||||
div("container mx-auto p-4") {
|
div("container mx-auto p-4") {
|
||||||
noteListHeader(numberOfDeletedNotes, query)
|
noteListHeader(numberOfDeletedNotes, query)
|
||||||
noteTable(notes)
|
noteTable(notes)
|
||||||
@@ -80,11 +81,11 @@ class NoteView(staticFileResolver: StaticFileResolver) : View(staticFileResolver
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun trash(
|
fun trash(
|
||||||
jwtPayload: JwtPayload,
|
loggedInUser: LoggedInUser,
|
||||||
notes: List<PersistedNoteMetadata>,
|
notes: List<PersistedNoteMetadata>,
|
||||||
currentPage: Int,
|
currentPage: Int,
|
||||||
numberOfPages: Int,
|
numberOfPages: Int,
|
||||||
) = renderPage(title = "Notes", jwtPayload = jwtPayload) {
|
) = renderPage(title = "Notes", loggedInUser = loggedInUser) {
|
||||||
div("container mx-auto p-4") {
|
div("container mx-auto p-4") {
|
||||||
div("flex justify-between mb-4") {
|
div("flex justify-between mb-4") {
|
||||||
h1("text-2xl underline") { +"Deleted notes" }
|
h1("text-2xl underline") { +"Deleted notes" }
|
||||||
@@ -116,9 +117,9 @@ class NoteView(staticFileResolver: StaticFileResolver) : View(staticFileResolver
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun renderedNote(jwtPayload: JwtPayload?, note: PersistedNote, shared: Boolean) = renderPage(
|
fun renderedNote(loggedInUser: LoggedInUser?, note: PersistedNote, shared: Boolean) = renderPage(
|
||||||
note.meta.title,
|
note.meta.title,
|
||||||
jwtPayload = jwtPayload,
|
loggedInUser = loggedInUser,
|
||||||
scripts = listOf("/highlight.10.1.2.js", "/init-highlight.0.0.1.js")
|
scripts = listOf("/highlight.10.1.2.js", "/init-highlight.0.0.1.js")
|
||||||
) {
|
) {
|
||||||
div("container mx-auto p-4") {
|
div("container mx-auto p-4") {
|
||||||
@@ -182,7 +183,8 @@ class NoteView(staticFileResolver: StaticFileResolver) : View(staticFileResolver
|
|||||||
button(
|
button(
|
||||||
type = ButtonType.submit,
|
type = ButtonType.submit,
|
||||||
name = if (note.public) "private" else "public",
|
name = if (note.public) "private" else "public",
|
||||||
classes = "font-semibold border-b-4 ${if (!note.public) "border-teal-200" else "border-green-500"}" +
|
classes = "font-semibold border-b-4 " +
|
||||||
|
(if (!note.public) "border-teal-200" else "border-green-500") +
|
||||||
" p-2 rounded-r bg-teal-200 text-gray-800"
|
" p-2 rounded-r bg-teal-200 text-gray-800"
|
||||||
) {
|
) {
|
||||||
+"Public"
|
+"Public"
|
||||||
+14
-13
@@ -1,37 +1,38 @@
|
|||||||
package be.simplenotes.app.views
|
package be.simplenotes.views
|
||||||
|
|
||||||
import be.simplenotes.app.extensions.summary
|
import be.simplenotes.types.LoggedInUser
|
||||||
import be.simplenotes.app.utils.StaticFileResolver
|
import be.simplenotes.views.components.Alert
|
||||||
import be.simplenotes.app.views.components.Alert
|
import be.simplenotes.views.components.alert
|
||||||
import be.simplenotes.app.views.components.alert
|
import be.simplenotes.views.components.input
|
||||||
import be.simplenotes.app.views.components.input
|
import be.simplenotes.views.extensions.summary
|
||||||
import be.simplenotes.domain.security.JwtPayload
|
|
||||||
import io.konform.validation.ValidationError
|
import io.konform.validation.ValidationError
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
import kotlinx.html.ButtonType.submit
|
import kotlinx.html.ButtonType.submit
|
||||||
|
|
||||||
class SettingView(staticFileResolver: StaticFileResolver) : View(staticFileResolver) {
|
class SettingView(styles: String) : View(styles) {
|
||||||
|
|
||||||
fun settings(
|
fun settings(
|
||||||
jwtPayload: JwtPayload,
|
loggedInUser: LoggedInUser,
|
||||||
error: String? = null,
|
error: String? = null,
|
||||||
validationErrors: List<ValidationError> = emptyList(),
|
validationErrors: List<ValidationError> = emptyList(),
|
||||||
) = renderPage("Settings", jwtPayload = jwtPayload) {
|
) = renderPage("Settings", loggedInUser = loggedInUser) {
|
||||||
div("container mx-auto") {
|
div("container mx-auto") {
|
||||||
|
|
||||||
section("m-4 p-4 bg-gray-800 rounded") {
|
section("m-4 p-4 bg-gray-800 rounded") {
|
||||||
h1("text-xl") {
|
h1("text-xl") {
|
||||||
+"Welcome "
|
+"Welcome "
|
||||||
span("text-teal-200 font-semibold") { +jwtPayload.username }
|
span("text-teal-200 font-semibold") { +loggedInUser.username }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
section("m-4 p-2 bg-gray-800 rounded flex flex-wrap justify-around items-end") {
|
section("m-4 p-2 bg-gray-800 rounded flex flex-wrap justify-around items-end") {
|
||||||
|
|
||||||
form(classes = "m-2", method = FormMethod.post, action = "/export") {
|
form(classes = "m-2", method = FormMethod.post, action = "/export") {
|
||||||
button(name = "display",
|
button(
|
||||||
|
name = "display",
|
||||||
classes = "inline btn btn-teal block",
|
classes = "inline btn btn-teal block",
|
||||||
type = submit) { +"Display my data" }
|
type = submit
|
||||||
|
) { +"Display my data" }
|
||||||
}
|
}
|
||||||
|
|
||||||
form(classes = "m-2", method = FormMethod.post, action = "/export") {
|
form(classes = "m-2", method = FormMethod.post, action = "/export") {
|
||||||
+13
-14
@@ -1,23 +1,22 @@
|
|||||||
package be.simplenotes.app.views
|
package be.simplenotes.views
|
||||||
|
|
||||||
import be.simplenotes.app.utils.StaticFileResolver
|
import be.simplenotes.types.LoggedInUser
|
||||||
import be.simplenotes.app.views.components.Alert
|
import be.simplenotes.views.components.Alert
|
||||||
import be.simplenotes.app.views.components.alert
|
import be.simplenotes.views.components.alert
|
||||||
import be.simplenotes.app.views.components.input
|
import be.simplenotes.views.components.input
|
||||||
import be.simplenotes.app.views.components.submitButton
|
import be.simplenotes.views.components.submitButton
|
||||||
import be.simplenotes.domain.security.JwtPayload
|
|
||||||
import io.konform.validation.ValidationError
|
import io.konform.validation.ValidationError
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
|
|
||||||
class UserView(staticFileResolver: StaticFileResolver) : View(staticFileResolver) {
|
class UserView(styles: String) : View(styles) {
|
||||||
fun register(
|
fun register(
|
||||||
jwtPayload: JwtPayload?,
|
loggedInUser: LoggedInUser?,
|
||||||
error: String? = null,
|
error: String? = null,
|
||||||
validationErrors: List<ValidationError> = emptyList(),
|
validationErrors: List<ValidationError> = emptyList(),
|
||||||
) = accountForm(
|
) = accountForm(
|
||||||
"Register",
|
"Register",
|
||||||
"Registration page",
|
"Registration page",
|
||||||
jwtPayload,
|
loggedInUser,
|
||||||
error,
|
error,
|
||||||
validationErrors,
|
validationErrors,
|
||||||
"Create an account",
|
"Create an account",
|
||||||
@@ -28,11 +27,11 @@ class UserView(staticFileResolver: StaticFileResolver) : View(staticFileResolver
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun login(
|
fun login(
|
||||||
jwtPayload: JwtPayload?,
|
loggedInUser: LoggedInUser?,
|
||||||
error: String? = null,
|
error: String? = null,
|
||||||
validationErrors: List<ValidationError> = emptyList(),
|
validationErrors: List<ValidationError> = emptyList(),
|
||||||
new: Boolean = false,
|
new: Boolean = false,
|
||||||
) = accountForm("Login", "Login page", jwtPayload, error, validationErrors, "Sign In", "Sign In", new) {
|
) = accountForm("Login", "Login page", loggedInUser, error, validationErrors, "Sign In", "Sign In", new) {
|
||||||
+"Don't have an account yet? "
|
+"Don't have an account yet? "
|
||||||
a(href = "/register", classes = "no-underline text-blue-500 hover:text-blue-400 font-bold") {
|
a(href = "/register", classes = "no-underline text-blue-500 hover:text-blue-400 font-bold") {
|
||||||
+"Create an account"
|
+"Create an account"
|
||||||
@@ -42,14 +41,14 @@ class UserView(staticFileResolver: StaticFileResolver) : View(staticFileResolver
|
|||||||
private fun accountForm(
|
private fun accountForm(
|
||||||
title: String,
|
title: String,
|
||||||
description: String,
|
description: String,
|
||||||
jwtPayload: JwtPayload?,
|
loggedInUser: LoggedInUser?,
|
||||||
error: String? = null,
|
error: String? = null,
|
||||||
validationErrors: List<ValidationError> = emptyList(),
|
validationErrors: List<ValidationError> = emptyList(),
|
||||||
h1: String,
|
h1: String,
|
||||||
submit: String,
|
submit: String,
|
||||||
new: Boolean = false,
|
new: Boolean = false,
|
||||||
footer: FlowContent.() -> Unit,
|
footer: FlowContent.() -> Unit,
|
||||||
) = renderPage(title = title, description, jwtPayload = jwtPayload) {
|
) = renderPage(title = title, description, loggedInUser = loggedInUser) {
|
||||||
div("centered container mx-auto flex justify-center items-center") {
|
div("centered container mx-auto flex justify-center items-center") {
|
||||||
div("w-full md:w-1/2 lg:w-1/3 m-4") {
|
div("w-full md:w-1/2 lg:w-1/3 m-4") {
|
||||||
div("p-8 mb-6") {
|
div("p-8 mb-6") {
|
||||||
+7
-10
@@ -1,19 +1,16 @@
|
|||||||
package be.simplenotes.app.views
|
package be.simplenotes.views
|
||||||
|
|
||||||
import be.simplenotes.app.utils.StaticFileResolver
|
import be.simplenotes.types.LoggedInUser
|
||||||
import be.simplenotes.app.views.components.navbar
|
import be.simplenotes.views.components.navbar
|
||||||
import be.simplenotes.domain.security.JwtPayload
|
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
import kotlinx.html.stream.appendHTML
|
import kotlinx.html.stream.appendHTML
|
||||||
|
|
||||||
abstract class View(staticFileResolver: StaticFileResolver) {
|
abstract class View(private val styles: String) {
|
||||||
|
|
||||||
private val styles = staticFileResolver.resolve("styles.css")!!
|
|
||||||
|
|
||||||
fun renderPage(
|
fun renderPage(
|
||||||
title: String,
|
title: String,
|
||||||
description: String? = null,
|
description: String? = null,
|
||||||
jwtPayload: JwtPayload?,
|
loggedInUser: LoggedInUser?,
|
||||||
scripts: List<String> = emptyList(),
|
scripts: List<String> = emptyList(),
|
||||||
body: MAIN.() -> Unit = {},
|
body: MAIN.() -> Unit = {},
|
||||||
) = buildString {
|
) = buildString {
|
||||||
@@ -25,7 +22,7 @@ abstract class View(staticFileResolver: StaticFileResolver) {
|
|||||||
meta(name = "viewport", content = "width=device-width, initial-scale=1")
|
meta(name = "viewport", content = "width=device-width, initial-scale=1")
|
||||||
title("$title - SimpleNotes")
|
title("$title - SimpleNotes")
|
||||||
description?.let { meta(name = "description", content = it) }
|
description?.let { meta(name = "description", content = it) }
|
||||||
link(rel = "preload", href = "/recursive-0.0.1.woff2"){
|
link(rel = "preload", href = "/recursive-0.0.1.woff2") {
|
||||||
attributes["as"] = "font"
|
attributes["as"] = "font"
|
||||||
attributes["type"] = "font/woff2"
|
attributes["type"] = "font/woff2"
|
||||||
attributes["crossorigin"] = "anonymous"
|
attributes["crossorigin"] = "anonymous"
|
||||||
@@ -37,7 +34,7 @@ abstract class View(staticFileResolver: StaticFileResolver) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
body("bg-gray-900 text-white") {
|
body("bg-gray-900 text-white") {
|
||||||
navbar(jwtPayload)
|
navbar(loggedInUser)
|
||||||
main { body() }
|
main { body() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user