Skip to content

Commit

Permalink
small improvements to improve frontend experience.
Browse files Browse the repository at this point in the history
  • Loading branch information
jvorhauer committed Feb 20, 2024
1 parent f8846db commit 523e7ba
Show file tree
Hide file tree
Showing 7 changed files with 28 additions and 10 deletions.
18 changes: 14 additions & 4 deletions src/main/kotlin/blog/model/Note.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ import kotlinx.coroutines.future.await
import blog.read.Reader

data class CreateNoteRequest(val title: String, val body: String) {
fun toCommand(user: String, replyTo: ActorRef<StatusReply<NoteResponse>>) = CreateNote(user, title, body, replyTo)
fun toCommand(user: String, replyTo: ActorRef<StatusReply<NoteResponse>>) = CreateNote(user, Encode.forHtml(title), Encode.forHtml(body), replyTo)
}

data class UpdateNoteRequest(val id: String, val title: String?, val body: String?) {
fun toCommand(user: String, rt: ActorRef<StatusReply<NoteResponse>>) = UpdateNote(user, id, title, body, rt)
fun toCommand(user: String, rt: ActorRef<StatusReply<NoteResponse>>) = UpdateNote(user, id, title.encode(), body.encode(), rt)
}

data class CreateNote(
Expand All @@ -33,7 +33,7 @@ data class CreateNote(
val replyTo: ActorRef<StatusReply<NoteResponse>>,
val id: String = nextId()
) : Command {
fun toEvent() = NoteCreated(id, user, Encode.forHtml(title), Encode.forHtml(body))
fun toEvent() = NoteCreated(id, user, title, body)
}

data class UpdateNote(val user: String, val id: String, val title: String?, val body: String?, val replyTo: ActorRef<StatusReply<NoteResponse>>): Command {
Expand Down Expand Up @@ -63,7 +63,7 @@ data class Note(
): Entity {
constructor(id: String, user: String, title: String, body: String): this(id, user, title, slugify(title), body)
fun update(nu: NoteUpdated): Note = this.copy(title = nu.title ?: this.title, slug = slugify(nu.title ?: this.title), body = nu.body ?: this.body)
fun toResponse() = NoteResponse(id, user, DTF.format(created), title, slug, body)
fun toResponse() = NoteResponse(id, user, DTF.format(created), title, slug, body.replace("\n", "<br>"))
}

data class NoteResponse(
Expand Down Expand Up @@ -100,6 +100,16 @@ fun Route.notesRoute(processor: ActorRef<Command>, reader: Reader, scheduler: Sc
val note = reader.findNote(id) ?: return@get call.respond(HttpStatusCode.NotFound, "note not found for $id")
call.respond(note.toResponse())
}
put {
val unr = call.receive<UpdateNoteRequest>()
val userId = user(call) ?: return@put call.respond(HttpStatusCode.Unauthorized, "Unauthorized")
AskPattern.ask(processor, { rt -> unr.toCommand(userId, rt) }, timeout, scheduler).await().let {
when {
it.isSuccess -> call.respond(HttpStatusCode.OK, it.value)
else -> call.respond(HttpStatusCode.BadRequest, it.error.localizedMessage)
}
}
}
delete("{id?}") {
val id = call.parameters["id"] ?: return@delete call.respond(HttpStatusCode.NotFound, "note id not specified")
reader.findNote(id) ?: return@delete call.respond(HttpStatusCode.NotFound, "note not found for $id")
Expand Down
5 changes: 3 additions & 2 deletions src/main/kotlin/blog/model/Task.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import akka.actor.typed.ActorRef
import akka.actor.typed.Scheduler
import akka.actor.typed.javadsl.AskPattern.ask
import akka.pattern.StatusReply
import org.owasp.encoder.Encode
import io.hypersistence.tsid.TSID
import io.ktor.http.*
import io.ktor.server.application.*
Expand Down Expand Up @@ -48,11 +49,11 @@ data class Task(
}

data class CreateTaskRequest(val title: String, val body: String, val due: LocalDateTime): Request {
fun toCommand(user: String, replyTo: ActorRef<StatusReply<TaskResponse>>) = CreateTask(user, title, body, due, replyTo)
fun toCommand(user: String, replyTo: ActorRef<StatusReply<TaskResponse>>) = CreateTask(user, Encode.forHtml(title), Encode.forHtml(body), due, replyTo)
}

data class UpdateTaskRequest(val id: String, val title: String?, val body: String?, val due: LocalDateTime?, val status: TaskStatus?): Request {
fun toCommand(user: String, replyTo: ActorRef<StatusReply<TaskResponse>>) = UpdateTask(user, id, title, body, due, status, replyTo)
fun toCommand(user: String, replyTo: ActorRef<StatusReply<TaskResponse>>) = UpdateTask(user, id, title.encode(), body.encode(), due, status, replyTo)
}


Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/blog/model/User.kt
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ fun Route.usersRoute(processor: ActorRef<Command>, reader: Reader, scheduler: Sc
}
get("/notes") {
val userId = user(call) ?: return@get call.respond(Unauthorized, "Unauthorized")
call.respond(reader.findNotesForUser(userId).map { it.toResponse() })
call.respond(reader.findNotesForUser(userId).sortedBy { it.created }.map { it.toResponse() })
}
}
get("{id?}") {
Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/blog/model/model.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import java.time.Duration
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.Locale
import org.owasp.encoder.Encode
import io.hypersistence.tsid.TSID
import io.ktor.server.application.*
import io.ktor.server.auth.*
Expand Down Expand Up @@ -43,6 +44,7 @@ fun nextId(): String = idFactory.generate().toString()
fun slugify(s: String): String = s.trim().replace(" ", " ").lowercase().replace("[^ a-z0-9]".toRegex(), "").replace(' ', '-')

fun String.hashed() = Hasher.hash(this)
fun String?.encode(): String? = if (this == null) null else Encode.forHtml(this)

data class Counts(
val users: Int,
Expand Down
1 change: 0 additions & 1 deletion src/main/kotlin/blog/read/Reader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ class Reader(
fun counts(): Counts = Counts(users.size, notes.size, tasks.size)

fun processEvent(e: Event) {
logger.info("processEvent: {}", e)
when (e) {
is UserCreated -> users[e.id] = e.toEntity()
is UserDeleted -> users.remove(e.id)
Expand Down
6 changes: 6 additions & 0 deletions src/test/kotlin/blog/model/NoteTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import akka.pattern.StatusReply
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import java.util.UUID
import org.owasp.encoder.Encode

class NoteTests {

Expand Down Expand Up @@ -65,6 +66,11 @@ class NoteTests {
assertThat(updated.user).isEqualTo(userId)
assertThat(updated.title).isEqualTo(run.title)
assertThat(updated.body).isEqualTo(run.body)

var str = Encode.forHtml("")
assertThat(str).isEmpty()
str = Encode.forHtml(null)
assertThat(str).isNotNull();
}

@Test
Expand Down
4 changes: 2 additions & 2 deletions src/test/requests/users-v2.http
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ Content-Type: application/json
Authorization: Bearer {{authorized}}

{
"title": "My First Note",
"body": "Note taking in its simplest form :-)"
"title": "My Second Note",
"body": "More notes is just better!"
}

### get-all-notes
Expand Down

0 comments on commit 523e7ba

Please sign in to comment.