Working api.
This commit is contained in:
parent
2d8ad43494
commit
76324145e4
169
.gitignore
vendored
Normal file
169
.gitignore
vendored
Normal file
@ -0,0 +1,169 @@
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/kotlin,intellij,maven
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=kotlin,intellij,maven
|
||||
|
||||
### Intellij ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
### Intellij Patch ###
|
||||
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||
|
||||
# *.iml
|
||||
# modules.xml
|
||||
# .idea/misc.xml
|
||||
# *.ipr
|
||||
|
||||
# Sonarlint plugin
|
||||
# https://plugins.jetbrains.com/plugin/7973-sonarlint
|
||||
.idea/**/sonarlint/
|
||||
|
||||
# SonarQube Plugin
|
||||
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
|
||||
.idea/**/sonarIssues.xml
|
||||
|
||||
# Markdown Navigator plugin
|
||||
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
|
||||
.idea/**/markdown-navigator.xml
|
||||
.idea/**/markdown-navigator-enh.xml
|
||||
.idea/**/markdown-navigator/
|
||||
|
||||
# Cache file creation bug
|
||||
# See https://youtrack.jetbrains.com/issue/JBR-2257
|
||||
.idea/$CACHE_FILE$
|
||||
|
||||
# CodeStream plugin
|
||||
# https://plugins.jetbrains.com/plugin/12206-codestream
|
||||
.idea/codestream.xml
|
||||
|
||||
# Azure Toolkit for IntelliJ plugin
|
||||
# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
|
||||
.idea/**/azureSettings.xml
|
||||
|
||||
### Kotlin ###
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
replay_pid*
|
||||
|
||||
### Maven ###
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
|
||||
.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
# Eclipse m2e generated files
|
||||
# Eclipse Core
|
||||
.project
|
||||
# JDT-specific (Eclipse Java Development Tools)
|
||||
.classpath
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/kotlin,intellij,maven,dotenv
|
||||
|
||||
|
||||
|
||||
|
||||
.idea/
|
||||
data.db
|
||||
*.iml
|
15
README.md
Normal file
15
README.md
Normal file
@ -0,0 +1,15 @@
|
||||
# An alternative API to Google Keep
|
||||
|
||||
# Authentication
|
||||
|
||||
The api use two means of authentication:
|
||||
- A configurable `Authorization` that is set in a env variable, and that will only be used to create the second mean of authentication
|
||||
- Tokens used to do everything else.
|
||||
|
||||
|
||||
## HOW TO USE
|
||||
|
||||
- Do a maven install (cli or GUI)
|
||||
- Create a env variable `LDC_AUTH` containing the Auth header you want to use to create authentication keys.
|
||||
- java -jar liste-de-courses-XXX-jar-with-dependencies.jar
|
||||
- The jar is now running on localhost:7000
|
149
pom.xml
Normal file
149
pom.xml
Normal file
@ -0,0 +1,149 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
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>
|
||||
|
||||
<artifactId>liste-de-courses</artifactId>
|
||||
<groupId>fr.louveau-amine</groupId>
|
||||
<version>1.2-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>liste-de-courses</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<kotlin.code.style>official</kotlin.code.style>
|
||||
<kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget>
|
||||
<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
|
||||
<main.class>ServerKt</main.class>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>mavenCentral</id>
|
||||
<url>https://repo1.maven.org/maven2/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>jcenter</id>
|
||||
<name>jcenter</name>
|
||||
<url>https://jcenter.bintray.com</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>src/main/kotlin</sourceDirectory>
|
||||
<testSourceDirectory>src/test/kotlin</testSourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<version>1.4.32</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-compile</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals>
|
||||
<goal>test-compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>2.22.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>2.6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals> <goal>single</goal> </goals>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>${main.class}</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-test-junit</artifactId>
|
||||
<version>1.4.32</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
||||
<version>1.4.32</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<version>1.7.30</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.javalin</groupId>
|
||||
<artifactId>javalin</artifactId>
|
||||
<version>3.13.9</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.10.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
<version>3.31.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.exposed</groupId>
|
||||
<artifactId>exposed-core</artifactId>
|
||||
<version>0.31.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.exposed</groupId>
|
||||
<artifactId>exposed-dao</artifactId>
|
||||
<version>0.31.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.exposed</groupId>
|
||||
<artifactId>exposed-jdbc</artifactId>
|
||||
<version>0.31.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.module</groupId>
|
||||
<artifactId>jackson-module-kotlin</artifactId>
|
||||
<version>2.10.5</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
34
src/main/kotlin/KeysController.kt
Normal file
34
src/main/kotlin/KeysController.kt
Normal file
@ -0,0 +1,34 @@
|
||||
import dao.DB
|
||||
import dao.ItemView
|
||||
import dao.KeyView
|
||||
import io.javalin.apibuilder.CrudHandler
|
||||
import io.javalin.http.Context
|
||||
|
||||
class KeysController : CrudHandler {
|
||||
private val db: DB = DB()
|
||||
|
||||
override fun create(ctx: Context) {
|
||||
db.createKey(ctx)
|
||||
}
|
||||
|
||||
override fun delete(ctx: Context, resourceId: String) {
|
||||
db.deleteKey(ctx)
|
||||
}
|
||||
|
||||
override fun getAll(ctx: Context) {
|
||||
ctx.status(404)
|
||||
}
|
||||
|
||||
override fun getOne(ctx: Context, resourceId: String) {
|
||||
ctx.status(404)
|
||||
}
|
||||
|
||||
override fun update(ctx: Context, resourceId: String) {
|
||||
ctx.status(404)
|
||||
}
|
||||
|
||||
fun checkKey(ctx: Context) {
|
||||
db.checkKey(ctx)
|
||||
}
|
||||
|
||||
}
|
24
src/main/kotlin/ListItemsController.kt
Normal file
24
src/main/kotlin/ListItemsController.kt
Normal file
@ -0,0 +1,24 @@
|
||||
import dao.DB
|
||||
import dao.ItemPatchView
|
||||
import dao.ItemView
|
||||
import io.javalin.http.Context
|
||||
|
||||
class ListItemsController {
|
||||
private val db: DB = DB()
|
||||
|
||||
fun create(listId: String, ctx: Context) {
|
||||
db.createItem(listId.toInt(), ctx.body<ItemView>(), ctx)
|
||||
}
|
||||
|
||||
fun update(listId: String, itemId: String, ctx: Context) {
|
||||
db.updateItem(listId.toInt(), itemId.toInt(), ctx.body<ItemPatchView>(), ctx)
|
||||
}
|
||||
|
||||
fun delete(listId: String, itemId: String, ctx: Context) {
|
||||
db.deleteItem(listId.toInt(), itemId.toInt(), ctx)
|
||||
}
|
||||
|
||||
fun getListItems(ctx: Context, resourceId: String) {
|
||||
db.findListItems(resourceId.toInt(), ctx)
|
||||
}
|
||||
}
|
29
src/main/kotlin/ListsController.kt
Normal file
29
src/main/kotlin/ListsController.kt
Normal file
@ -0,0 +1,29 @@
|
||||
import dao.DB
|
||||
import dao.ListView
|
||||
import io.javalin.apibuilder.CrudHandler
|
||||
import io.javalin.http.Context
|
||||
|
||||
class ListsController : CrudHandler {
|
||||
private val db: DB = DB()
|
||||
|
||||
override fun create(ctx: Context) {
|
||||
db.createList(ctx.body<ListView>(), ctx)
|
||||
}
|
||||
|
||||
override fun delete(ctx: Context, resourceId: String) {
|
||||
db.deleteList(resourceId.toInt(), ctx)
|
||||
}
|
||||
|
||||
override fun getAll(ctx: Context) {
|
||||
db.getAllLists(ctx)
|
||||
}
|
||||
|
||||
override fun getOne(ctx: Context, resourceId: String) {
|
||||
db.findList(resourceId.toInt(), ctx)
|
||||
}
|
||||
|
||||
override fun update(ctx: Context, resourceId: String) {
|
||||
db.updateList(resourceId.toInt(), ctx.body<ListView>(), ctx)
|
||||
}
|
||||
|
||||
}
|
195
src/main/kotlin/dao/DB.kt
Normal file
195
src/main/kotlin/dao/DB.kt
Normal file
@ -0,0 +1,195 @@
|
||||
package dao
|
||||
|
||||
import io.javalin.http.Context
|
||||
import org.jetbrains.exposed.sql.and
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
|
||||
class DB {
|
||||
|
||||
/*
|
||||
* Lists
|
||||
*/
|
||||
fun createList(c: ListView, ctx: Context) {
|
||||
transaction {
|
||||
var i = List.new {
|
||||
name = c.name
|
||||
}
|
||||
ctx.json(i.toView())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun deleteList(resourceId: Int, ctx: Context) {
|
||||
transaction {
|
||||
val list = List.findById(resourceId)
|
||||
|
||||
if (list != null) {
|
||||
Item.find { Items.list eq list.id.value}.forEach { i -> i.delete() }
|
||||
}
|
||||
|
||||
list?.delete() ?: ctx.status(404)
|
||||
}
|
||||
}
|
||||
|
||||
fun getAllLists(ctx: Context) {
|
||||
transaction {
|
||||
ctx.json(List.all().map { it.toView() })
|
||||
}
|
||||
}
|
||||
|
||||
fun findList(resourceID: Int, ctx: Context) {
|
||||
transaction {
|
||||
val listOpt = List.findById(resourceID)
|
||||
if (listOpt != null) {
|
||||
ctx.json(listOpt.toView())
|
||||
} else {
|
||||
ctx.status(404)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateList(resourceID: Int, body: ListView, ctx: Context) {
|
||||
transaction {
|
||||
val list = List.findById(resourceID)
|
||||
if (list != null) {
|
||||
if (body.name != null) {
|
||||
list?.name = body.name
|
||||
}
|
||||
ctx.json(list.toView())
|
||||
} else {
|
||||
ctx.status(404)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Items
|
||||
*/
|
||||
fun findListItems(resourceID: Int, ctx: Context) {
|
||||
transaction {
|
||||
val listOpt = List.findById(resourceID)
|
||||
if (listOpt != null) {
|
||||
val items = Item.find { Items.list eq resourceID }
|
||||
.sortedBy { it.position }
|
||||
|
||||
ctx.json(listOpt.toViewWithItems(items))
|
||||
} else {
|
||||
ctx.status(404)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createItem(listId: Int, c: ItemView, ctx: Context) {
|
||||
transaction {
|
||||
val listOpt = List.findById(listId)
|
||||
if (listOpt != null) {
|
||||
var i = Item.new {
|
||||
list = listId
|
||||
content = c.content
|
||||
position = Item.all().count().toInt()
|
||||
checked = false
|
||||
}
|
||||
|
||||
ctx.json(i.toView())
|
||||
} else {
|
||||
ctx.status(404)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun deleteItem(listId: Int, itemId: Int, ctx: Context) {
|
||||
transaction {
|
||||
val listOpt = List.findById(listId)
|
||||
if (listOpt != null) {
|
||||
val item = Item.find { Items.list eq listId and (Items.id eq itemId) }.limit(1).firstOrNull()
|
||||
if (item != null) {
|
||||
item.delete()
|
||||
var i = 0
|
||||
Item.all()
|
||||
.sortedBy { it.position }
|
||||
.forEach {
|
||||
it.position = i
|
||||
i++
|
||||
}
|
||||
} else {
|
||||
ctx.status(404)
|
||||
}
|
||||
} else {
|
||||
ctx.status(404)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateItem(listId: Int, itemId: Int, body: ItemPatchView, ctx: Context) {
|
||||
transaction {
|
||||
val listOpt = List.findById(listId)
|
||||
if (listOpt != null) {
|
||||
val item = Item.find { Items.list eq listId and (Items.id eq itemId) }.limit(1).firstOrNull()
|
||||
if (item != null) {
|
||||
var p = body.position
|
||||
if (body.checked != null) {
|
||||
val allITems = Item.find { Items.list eq listId }.sortedBy { it.position }
|
||||
val firstChecked = allITems.firstOrNull { it.checked }
|
||||
p = firstChecked?.position ?: allITems.lastOrNull()?.position
|
||||
|
||||
item?.checked = body.checked
|
||||
}
|
||||
if (p != null) {
|
||||
var i = 0
|
||||
Item.find { Items.list eq listId and (Items.id neq itemId) }
|
||||
.sortedBy { it.position }
|
||||
.forEach {
|
||||
if (i == p) {
|
||||
i++
|
||||
}
|
||||
it.position = i
|
||||
i++
|
||||
}
|
||||
item?.position = p
|
||||
}
|
||||
if (body.content != null) {
|
||||
item?.content = body.content
|
||||
}
|
||||
ctx.json(item.toView())
|
||||
} else {
|
||||
ctx.status(404)
|
||||
}
|
||||
} else {
|
||||
ctx.status(404)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Api keys
|
||||
*/
|
||||
fun createKey(ctx: Context) {
|
||||
transaction {
|
||||
val allowedChars = ('A'..'Z') + ('a'..'z') + ('0'..'9')
|
||||
val k = (1..256)
|
||||
.map { allowedChars.random() }
|
||||
.joinToString("")
|
||||
var key = Key.new {
|
||||
value = k
|
||||
}
|
||||
ctx.json(key.toView())
|
||||
}
|
||||
}
|
||||
|
||||
fun checkKey(ctx: Context) {
|
||||
transaction {
|
||||
val key = ctx.body()
|
||||
if (Key.find { Keys.value eq key }.count() > 0L) ctx.status(301) else ctx.status(404)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteKey(ctx: Context) {
|
||||
transaction {
|
||||
val k = ctx.body<KeyView>()
|
||||
val key = Key.find { Keys.value eq k.value }.firstOrNull()
|
||||
key?.delete() ?: ctx.status(404)
|
||||
}
|
||||
}
|
||||
}
|
31
src/main/kotlin/dao/Items.kt
Normal file
31
src/main/kotlin/dao/Items.kt
Normal file
@ -0,0 +1,31 @@
|
||||
package dao
|
||||
|
||||
import org.jetbrains.exposed.dao.IntEntity
|
||||
import org.jetbrains.exposed.dao.IntEntityClass
|
||||
import org.jetbrains.exposed.dao.id.EntityID
|
||||
import org.jetbrains.exposed.dao.id.IntIdTable
|
||||
|
||||
object Items : IntIdTable() {
|
||||
val list = integer("list")
|
||||
val content = varchar("content", 256)
|
||||
val position = integer("position")
|
||||
val checked = bool("checked").default(false)
|
||||
}
|
||||
|
||||
class Item(id: EntityID<Int>) : IntEntity(id) {
|
||||
companion object : IntEntityClass<Item>(Items)
|
||||
|
||||
var list by Items.list
|
||||
var content by Items.content
|
||||
var position by Items.position
|
||||
var checked by Items.checked
|
||||
|
||||
|
||||
}
|
||||
fun Item.toView(): ItemView {
|
||||
return ItemView(this.id.value, this.content, this.checked, this.position)
|
||||
}
|
||||
|
||||
data class ItemView(val id: Int, val content: String, val checked: Boolean = false, val position: Int?)
|
||||
|
||||
data class ItemPatchView(val id: Int, val content: String?, val checked: Boolean?, val position: Int?)
|
23
src/main/kotlin/dao/Keys.kt
Normal file
23
src/main/kotlin/dao/Keys.kt
Normal file
@ -0,0 +1,23 @@
|
||||
package dao
|
||||
|
||||
import org.jetbrains.exposed.dao.IntEntity
|
||||
import org.jetbrains.exposed.dao.IntEntityClass
|
||||
import org.jetbrains.exposed.dao.id.EntityID
|
||||
import org.jetbrains.exposed.dao.id.IntIdTable
|
||||
|
||||
object Keys : IntIdTable() {
|
||||
val value = varchar("content", 256)
|
||||
}
|
||||
|
||||
class Key(id: EntityID<Int>) : IntEntity(id) {
|
||||
companion object : IntEntityClass<Key>(Keys)
|
||||
|
||||
var value by Keys.value
|
||||
|
||||
|
||||
}
|
||||
fun Key.toView(): KeyView {
|
||||
return KeyView(this.value)
|
||||
}
|
||||
|
||||
data class KeyView(val value: String)
|
29
src/main/kotlin/dao/Lists.kt
Normal file
29
src/main/kotlin/dao/Lists.kt
Normal file
@ -0,0 +1,29 @@
|
||||
package dao
|
||||
|
||||
import org.jetbrains.exposed.dao.IntEntity
|
||||
import org.jetbrains.exposed.dao.IntEntityClass
|
||||
import org.jetbrains.exposed.dao.id.EntityID
|
||||
import org.jetbrains.exposed.dao.id.IntIdTable
|
||||
|
||||
object Lists : IntIdTable() {
|
||||
val name = varchar("content", 256)
|
||||
}
|
||||
|
||||
class List(id: EntityID<Int>) : IntEntity(id) {
|
||||
companion object : IntEntityClass<List>(Lists)
|
||||
|
||||
var name by Lists.name
|
||||
|
||||
|
||||
}
|
||||
fun List.toView(): ListView {
|
||||
return ListView(this.id.value, this.name)
|
||||
}
|
||||
|
||||
fun List.toViewWithItems(items: kotlin.collections.List<Item>): ListViewWithItems {
|
||||
return ListViewWithItems(this.id.value, this.name, items.map { it.toView() })
|
||||
}
|
||||
|
||||
data class ListView(val id: Int, val name: String)
|
||||
|
||||
data class ListViewWithItems(val id: Int, val name: String, val items: kotlin.collections.List<ItemView>)
|
70
src/main/kotlin/server.kt
Normal file
70
src/main/kotlin/server.kt
Normal file
@ -0,0 +1,70 @@
|
||||
import dao.Items
|
||||
import dao.Key
|
||||
import dao.Keys
|
||||
import dao.Lists
|
||||
import io.javalin.Javalin
|
||||
import io.javalin.apibuilder.ApiBuilder.*
|
||||
import io.javalin.core.security.Role
|
||||
import io.javalin.core.security.SecurityUtil.roles
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import org.jetbrains.exposed.sql.SchemaUtils
|
||||
import org.jetbrains.exposed.sql.StdOutSqlLogger
|
||||
import org.jetbrains.exposed.sql.addLogger
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
|
||||
enum class ApiRole : Role { PUBLIC, BASIC_AUTHED, API_AUTHED }
|
||||
|
||||
fun main() {
|
||||
val app = Javalin.create {
|
||||
it.accessManager { handler, ctx, permittedRoles ->
|
||||
transaction {
|
||||
val k = ctx.header("X-API-KEY").orEmpty()
|
||||
Key.find {
|
||||
Keys.value eq k
|
||||
}.firstOrNull()
|
||||
val auth = ctx.header("Authorization").orEmpty()
|
||||
val isBasicAuthed = auth == System.getenv("LDC_AUTH")
|
||||
when {
|
||||
permittedRoles.contains(ApiRole.PUBLIC) -> handler.handle(ctx)
|
||||
permittedRoles.contains(ApiRole.BASIC_AUTHED) && isBasicAuthed -> handler.handle(ctx)
|
||||
permittedRoles.contains(ApiRole.API_AUTHED) && k != null -> handler.handle(ctx)
|
||||
else -> ctx.status(401).json("Unauthorized")
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start(7000)
|
||||
Database.connect("jdbc:sqlite:data.db", "org.sqlite.JDBC")
|
||||
transaction {
|
||||
addLogger(StdOutSqlLogger)
|
||||
SchemaUtils.create (Lists)
|
||||
SchemaUtils.create (Items)
|
||||
SchemaUtils.create (Keys)
|
||||
}
|
||||
|
||||
app.routes {
|
||||
path("api") {
|
||||
crud("keys/:key-id", KeysController(), roles(ApiRole.BASIC_AUTHED))
|
||||
crud("lists/:list-id", ListsController(), roles(ApiRole.API_AUTHED))
|
||||
}
|
||||
|
||||
post("/api/keys:check", { ctx ->
|
||||
KeysController().checkKey(ctx)
|
||||
}, roles(ApiRole.PUBLIC))
|
||||
|
||||
get("/api/lists/:list-id/items", { ctx ->
|
||||
ListItemsController().getListItems(ctx, ctx.pathParam("list-id"))
|
||||
}, roles(ApiRole.API_AUTHED))
|
||||
|
||||
post("/api/lists/:list-id/items", { ctx ->
|
||||
ListItemsController().create(ctx.pathParam("list-id"), ctx)
|
||||
}, roles(ApiRole.API_AUTHED))
|
||||
|
||||
delete("/api/lists/:list-id/items/:item-id", { ctx ->
|
||||
ListItemsController().delete(ctx.pathParam("list-id"), ctx.pathParam("item-id"), ctx)
|
||||
}, roles(ApiRole.API_AUTHED))
|
||||
|
||||
patch("/api/lists/:list-id/items/:item-id", { ctx ->
|
||||
ListItemsController().update(ctx.pathParam("list-id"), ctx.pathParam("item-id"), ctx)
|
||||
}, roles(ApiRole.API_AUTHED))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user