Start migration of notesServices + controllers
This commit is contained in:
parent
573963b161
commit
52aae6773f
@ -7,7 +7,7 @@ import java.util.*
|
||||
interface Note : Entity<Note> {
|
||||
companion object : Entity.Factory<Note>()
|
||||
|
||||
val uuid: UUID
|
||||
var uuid: UUID
|
||||
var title: String
|
||||
var user: User
|
||||
var updatedAt: LocalDateTime
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package be.vandewalleh.extensions
|
||||
|
||||
import be.vandewalleh.kodein
|
||||
import be.vandewalleh.services.FullNoteDTOPatch
|
||||
import be.vandewalleh.services.UserService
|
||||
import io.ktor.application.*
|
||||
import io.ktor.auth.*
|
||||
@ -23,12 +24,8 @@ fun ApplicationCall.userId(): Int {
|
||||
return userService.getUserId(email)!!
|
||||
}
|
||||
|
||||
private class Tags(val tags: List<String>)
|
||||
class NoteCreate(val title: String, val tags: List<String>)
|
||||
|
||||
suspend fun ApplicationCall.receiveTags(): List<String> {
|
||||
return receive<Tags>().tags
|
||||
}
|
||||
suspend fun ApplicationCall.receiveNoteCreate(): NoteCreate = receive()
|
||||
|
||||
data class NotePatch(val tags: List<String>?, val title: String?)
|
||||
|
||||
suspend fun ApplicationCall.receiveNotePatch() = receive<NotePatch>()
|
||||
suspend fun ApplicationCall.receiveNotePatch() : FullNoteDTOPatch = receive()
|
||||
@ -1,22 +1,12 @@
|
||||
package be.vandewalleh.extensions
|
||||
|
||||
import be.vandewalleh.kodein
|
||||
import be.vandewalleh.services.NotesService
|
||||
import be.vandewalleh.tables.Notes
|
||||
import io.ktor.http.*
|
||||
import org.kodein.di.generic.instance
|
||||
|
||||
private val notesService by kodein.instance<NotesService>()
|
||||
import java.util.*
|
||||
|
||||
fun Parameters.noteTitle(): String {
|
||||
return this["noteTitle"]!!
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that returns a [Notes] ID from it's title and the currently logged in user.
|
||||
* returns null if none found
|
||||
*/
|
||||
fun Parameters.noteId(userId: Int): Int? {
|
||||
val title = noteTitle()
|
||||
return notesService.getNoteIdFromUserIdAndTitle(userId, title)
|
||||
fun Parameters.noteUuid(): UUID {
|
||||
return UUID.fromString(this["noteUuid"])
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
package be.vandewalleh.routing
|
||||
|
||||
import io.ktor.auth.*
|
||||
import io.ktor.routing.*
|
||||
import org.kodein.di.Kodein
|
||||
|
||||
fun Routing.chapters(kodein: Kodein) {
|
||||
authenticate {
|
||||
route("/notes/{noteTitle}/chapters/{chapterNumber}") {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,13 @@
|
||||
package be.vandewalleh.routing
|
||||
|
||||
import be.vandewalleh.extensions.noteTitle
|
||||
import be.vandewalleh.extensions.receiveNoteCreate
|
||||
import be.vandewalleh.extensions.respondStatus
|
||||
import be.vandewalleh.extensions.userId
|
||||
import be.vandewalleh.services.NotesService
|
||||
import io.ktor.application.*
|
||||
import io.ktor.auth.*
|
||||
import io.ktor.http.*
|
||||
import io.ktor.response.*
|
||||
import io.ktor.routing.*
|
||||
import org.kodein.di.Kodein
|
||||
@ -18,5 +22,19 @@ fun Routing.notes(kodein: Kodein) {
|
||||
val notes = notesService.getNotes(userId)
|
||||
call.respond(notes)
|
||||
}
|
||||
|
||||
post("/notes") {
|
||||
val userId = call.userId()
|
||||
val noteUuid = call.parameters.noteTitle()
|
||||
val note = call.receiveNoteCreate()
|
||||
val exists = notesService.noteExistsWithTitle(userId, note.title)
|
||||
|
||||
if (exists) {
|
||||
return@post call.respondStatus(HttpStatusCode.Conflict)
|
||||
}
|
||||
|
||||
notesService.createNote(userId, note.title, note.tags)
|
||||
call.respondStatus(HttpStatusCode.Created)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,5 @@ fun Routing.registerRoutes(kodein: Kodein) {
|
||||
login(kodein)
|
||||
notes(kodein)
|
||||
title(kodein)
|
||||
chapters(kodein)
|
||||
tags(kodein)
|
||||
}
|
||||
@ -1,6 +1,9 @@
|
||||
package be.vandewalleh.routing
|
||||
|
||||
import be.vandewalleh.extensions.*
|
||||
import be.vandewalleh.extensions.noteUuid
|
||||
import be.vandewalleh.extensions.receiveNotePatch
|
||||
import be.vandewalleh.extensions.respondStatus
|
||||
import be.vandewalleh.extensions.userId
|
||||
import be.vandewalleh.services.NotesService
|
||||
import io.ktor.application.*
|
||||
import io.ktor.auth.*
|
||||
@ -14,49 +17,39 @@ fun Routing.title(kodein: Kodein) {
|
||||
val notesService by kodein.instance<NotesService>()
|
||||
|
||||
authenticate {
|
||||
route("/notes/{noteTitle}") {
|
||||
post {
|
||||
val userId = call.userId()
|
||||
val title = call.parameters.noteTitle()
|
||||
val tags = call.receiveTags()
|
||||
val noteId = call.parameters.noteId(userId)
|
||||
|
||||
if (noteId != null) {
|
||||
return@post call.respondStatus(HttpStatusCode.Conflict)
|
||||
}
|
||||
|
||||
notesService.createNote(userId, title, tags)
|
||||
call.respondStatus(HttpStatusCode.Created)
|
||||
}
|
||||
|
||||
route("/notes/{noteUuid}") {
|
||||
get {
|
||||
val userId = call.userId()
|
||||
val noteId = call.parameters.noteId(userId)
|
||||
?: return@get call.respondStatus(HttpStatusCode.NotFound)
|
||||
val noteUuid = call.parameters.noteUuid()
|
||||
|
||||
val response = notesService.getTagsAndChapters(noteId)
|
||||
val exists = notesService.noteExists(userId, noteUuid)
|
||||
if (exists) return@get call.respondStatus(HttpStatusCode.NotFound)
|
||||
|
||||
val response = notesService.getNote(noteUuid)
|
||||
call.respond(response)
|
||||
}
|
||||
|
||||
patch {
|
||||
val notePatch = call.receiveNotePatch()
|
||||
if (notePatch.tags == null && notePatch.title == null)
|
||||
return@patch call.respondStatus(HttpStatusCode.BadRequest)
|
||||
|
||||
val userId = call.userId()
|
||||
val noteId = call.parameters.noteId(userId)
|
||||
?: return@patch call.respondStatus(HttpStatusCode.NotFound)
|
||||
val noteUuid = call.parameters.noteUuid()
|
||||
|
||||
notesService.updateNote(noteId, notePatch.tags, notePatch.title)
|
||||
val exists = notesService.noteExists(userId, noteUuid)
|
||||
if (exists) return@patch call.respondStatus(HttpStatusCode.NotFound)
|
||||
|
||||
val notePatch = call.receiveNotePatch().copy(uuid = noteUuid)
|
||||
|
||||
notesService.updateNote(notePatch)
|
||||
call.respondStatus(HttpStatusCode.OK)
|
||||
}
|
||||
|
||||
delete {
|
||||
val userId = call.userId()
|
||||
val noteId = call.parameters.noteId(userId)
|
||||
?: return@delete call.respondStatus(HttpStatusCode.NotFound)
|
||||
val noteUuid = call.parameters.noteUuid()
|
||||
|
||||
notesService.deleteNote(noteId)
|
||||
val exists = notesService.noteExists(userId, noteUuid)
|
||||
if (exists) return@delete call.respondStatus(HttpStatusCode.NotFound)
|
||||
|
||||
notesService.deleteNote(noteUuid)
|
||||
call.respondStatus(HttpStatusCode.OK)
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,11 +5,13 @@ import be.vandewalleh.tables.Notes
|
||||
import be.vandewalleh.tables.Tags
|
||||
import me.liuwj.ktorm.database.*
|
||||
import me.liuwj.ktorm.dsl.*
|
||||
import me.liuwj.ktorm.entity.*
|
||||
import org.kodein.di.Kodein
|
||||
import org.kodein.di.KodeinAware
|
||||
import org.kodein.di.generic.instance
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* service to handle database queries at the Notes level.
|
||||
@ -18,102 +20,140 @@ class NotesService(override val kodein: Kodein) : KodeinAware {
|
||||
private val db by instance<Database>()
|
||||
|
||||
/**
|
||||
* returns a list of [NotesDTO] associated with the userId
|
||||
* returns a list of [BasicNoteDTO] associated with the userId
|
||||
*/
|
||||
fun getNotes(userId: Int): List<NotesDTO> = db.from(Notes)
|
||||
.select(Notes.id, Notes.title, Notes.updatedAt)
|
||||
.where { Notes.userId eq userId }
|
||||
.orderBy(Notes.updatedAt.desc())
|
||||
.map { row ->
|
||||
val tags = db.from(Tags)
|
||||
.select(Tags.name)
|
||||
.where { Tags.noteId eq row[Notes.id]!! }
|
||||
.map { it[Tags.name]!! }
|
||||
fun getNotes(userId: Int): List<BasicNoteDTO> {
|
||||
val notes = db.sequenceOf(Notes)
|
||||
.filterColumns { listOf(it.uuid, it.title, it.updatedAt) }
|
||||
.filter { it.userId eq userId }
|
||||
.sortedByDescending { it.updatedAt }
|
||||
.toList()
|
||||
|
||||
val updatedAt = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(row[Notes.updatedAt]!!)
|
||||
if(notes.isEmpty()) return emptyList()
|
||||
|
||||
NotesDTO(row[Notes.title]!!, tags, updatedAt)
|
||||
val tags = db.sequenceOf(Tags)
|
||||
.filterColumns { listOf(it.noteUuid, it.name) }
|
||||
.filter { it.noteUuid inList notes.map { it.uuid } }
|
||||
.toList()
|
||||
|
||||
return notes.map { note ->
|
||||
val noteTags = tags.asSequence()
|
||||
.filter { it.note.uuid == note.uuid }
|
||||
.map { it.name }
|
||||
.toList()
|
||||
|
||||
BasicNoteDTO(note.uuid, note.title, noteTags, DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(note.updatedAt))
|
||||
}
|
||||
}
|
||||
|
||||
fun getNoteIdFromUserIdAndTitle(userId: Int, noteTitle: String): Int? = db.from(Notes)
|
||||
.select(Notes.id)
|
||||
.where { Notes.userId eq userId and (Notes.title eq noteTitle) }
|
||||
.limit(0, 1)
|
||||
.map { it[Notes.id]!! }
|
||||
.firstOrNull()
|
||||
fun noteExistsWithTitle(userId: Int, title: String): Boolean {
|
||||
TODO()
|
||||
}
|
||||
|
||||
fun noteExists(userId: Int, uuid: UUID): Boolean {
|
||||
TODO()
|
||||
}
|
||||
|
||||
fun createNote(userId: Int, title: String, tags: List<String>) {
|
||||
db.useTransaction {
|
||||
val noteId = db.insertAndGenerateKey(Notes) {
|
||||
val uuid = UUID.randomUUID()
|
||||
db.insert(Notes) {
|
||||
it.uuid to uuid
|
||||
it.title to title
|
||||
it.userId to userId
|
||||
it.updatedAt to LocalDateTime.now()
|
||||
}
|
||||
|
||||
tags.forEach { tagName ->
|
||||
db.insert(Tags) {
|
||||
it.name to tagName
|
||||
it.noteId to noteId
|
||||
db.batchInsert(Tags) {
|
||||
tags.forEach { tagName ->
|
||||
item {
|
||||
it.noteUuid to uuid
|
||||
it.name to tagName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getTagsAndChapters(noteId: Int): TagsChaptersDTO {
|
||||
fun getNote(noteUuid: UUID): FullNoteDTO {
|
||||
TODO()
|
||||
val tags = db.from(Tags)
|
||||
.select(Tags.name)
|
||||
.where { Tags.noteId eq noteId }
|
||||
.where { Tags.noteUuid eq noteUuid }
|
||||
.map { it[Tags.name]!! }
|
||||
.toList()
|
||||
|
||||
val chapters = db.from(Chapters)
|
||||
.select(Chapters.title, Chapters.content)
|
||||
.where { Chapters.noteId eq noteId }
|
||||
.where { Chapters.noteUuid eq noteUuid }
|
||||
.orderBy(Chapters.number.asc())
|
||||
.map { ChaptersDTO(it[Chapters.title]!!, it[Chapters.content]!!) }
|
||||
.map { ChapterDTO(it[Chapters.title]!!, it[Chapters.content]!!) }
|
||||
.toList()
|
||||
|
||||
return TagsChaptersDTO(tags, chapters)
|
||||
}
|
||||
|
||||
fun updateNote(noteId: Int, tags: List<String>?, title: String?): Unit =
|
||||
fun updateNote(patch: FullNoteDTOPatch) {
|
||||
if(patch.uuid == null) return
|
||||
db.useTransaction {
|
||||
if (title != null) {
|
||||
if (patch.title != null) {
|
||||
db.update(Notes) {
|
||||
it.title to title
|
||||
it.title to patch.title
|
||||
it.updatedAt to LocalDateTime.now()
|
||||
where { it.id eq noteId }
|
||||
where { it.uuid eq patch.uuid }
|
||||
}
|
||||
}
|
||||
|
||||
if (tags != null) {
|
||||
if (patch.tags != null) {
|
||||
// delete all tags
|
||||
db.delete(Tags) {
|
||||
it.noteId eq noteId
|
||||
it.noteUuid eq patch.uuid
|
||||
}
|
||||
|
||||
// put new ones
|
||||
tags.forEach { tagName ->
|
||||
patch.tags.forEach { tagName ->
|
||||
db.insert(Tags) {
|
||||
it.name to tagName
|
||||
it.noteId to noteId
|
||||
it.noteUuid to patch.uuid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteNote(noteId: Int): Unit =
|
||||
TODO("get chapters")
|
||||
}
|
||||
|
||||
fun deleteNote(noteUuid: UUID): Unit =
|
||||
db.useTransaction {
|
||||
db.delete(Notes) { it.id eq noteId }
|
||||
db.delete(Notes) { it.uuid eq noteUuid }
|
||||
}
|
||||
|
||||
fun getTags(userId: Int): List<String> = db.from(Tags)
|
||||
.leftJoin(Notes, on = Tags.noteId eq Notes.id)
|
||||
.leftJoin(Notes, on = Tags.noteUuid eq Notes.uuid)
|
||||
.select(Tags.name)
|
||||
.where { Notes.userId eq userId }
|
||||
.map { it[Tags.name]!! }
|
||||
}
|
||||
|
||||
data class ChaptersDTO(val title: String, val content: String)
|
||||
data class TagsChaptersDTO(val tags: List<String>, val chapters: List<ChaptersDTO>)
|
||||
data class NotesDTO(val title: String, val tags: List<String>, val updatedAt: String)
|
||||
data class ChapterDTO(val title: String, val content: String)
|
||||
data class FullNoteDTO(
|
||||
val uuid: UUID,
|
||||
val title: String,
|
||||
val updatedAt: String,
|
||||
val tags: List<String>,
|
||||
val chapters: List<ChapterDTO>
|
||||
)
|
||||
|
||||
data class FullNoteDTOPatch(
|
||||
val uuid: UUID? = null,
|
||||
val title: String? = null,
|
||||
val updatedAt: String? = null,
|
||||
val tags: List<String>? = null,
|
||||
val chapters: List<ChapterDTO>? = null
|
||||
)
|
||||
|
||||
data class BasicNoteDTO(
|
||||
val uuid: UUID,
|
||||
val title: String,
|
||||
val tags: List<String>,
|
||||
val updatedAt: String
|
||||
)
|
||||
Loading…
x
Reference in New Issue
Block a user