Rename Label->Version, add version meta field
This commit is contained in:
@@ -129,9 +129,9 @@ fun Application.module() {
|
||||
patchAuth(Routes.Project.update, ProjectHandler::updateProject)
|
||||
deleteAuth(Routes.Project.delete, ProjectHandler::deleteProject)
|
||||
|
||||
postAuth(Routes.Label.new, ProjectHandler::createLabel)
|
||||
patchAuth(Routes.Label.update, ProjectHandler::updateLabel)
|
||||
deleteAuth(Routes.Label.delete, ProjectHandler::deleteLabel)
|
||||
postAuth(Routes.Version.new, ProjectHandler::createVersion)
|
||||
patchAuth(Routes.Version.update, ProjectHandler::updateVersion)
|
||||
deleteAuth(Routes.Version.delete, ProjectHandler::deleteVersion)
|
||||
|
||||
postAuth(Routes.Entry.new, ProjectHandler::createEntry)
|
||||
deleteAuth(Routes.Entry.delete, ProjectHandler::deleteEntry)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.jaytux.phoebench.server.db
|
||||
|
||||
import com.jaytux.phoebench.server.DotEnv
|
||||
import io.github.cdimascio.dotenv.Dotenv
|
||||
import org.jetbrains.exposed.v1.jdbc.Database
|
||||
import org.jetbrains.exposed.v1.jdbc.SchemaUtils
|
||||
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
|
||||
@@ -16,9 +15,9 @@ object DB {
|
||||
)
|
||||
|
||||
transaction {
|
||||
SchemaUtils.create(Users, Invites, RefreshTokens, Projects, Labels, Entries)
|
||||
SchemaUtils.create(Users, Invites, RefreshTokens, Projects, Versions, Entries)
|
||||
|
||||
val migration = MigrationUtils.statementsRequiredForDatabaseMigration(Users, Invites, RefreshTokens, Projects, Labels, Entries)
|
||||
val migration = MigrationUtils.statementsRequiredForDatabaseMigration(Users, Invites, RefreshTokens, Projects, Versions, Entries)
|
||||
try {
|
||||
migration.forEach {
|
||||
exec(it)
|
||||
|
||||
@@ -42,25 +42,26 @@ class Project(id: EntityID<Uuid>) : Entity<Uuid>(id) {
|
||||
var isPublic by Projects.isPublic
|
||||
|
||||
var owner by User referencedOn Projects.ownerId
|
||||
val labels by Label referrersOn Labels.projectId
|
||||
val labels by Version referrersOn Versions.projectId
|
||||
val entries by Entry referrersOn Entries.projectId
|
||||
}
|
||||
|
||||
class Label(id: EntityID<Uuid>) : Entity<Uuid>(id) {
|
||||
companion object : EntityClass<Uuid, Label>(Labels)
|
||||
class Version(id: EntityID<Uuid>) : Entity<Uuid>(id) {
|
||||
companion object : EntityClass<Uuid, Version>(Versions)
|
||||
|
||||
var label by Labels.label
|
||||
var color by Labels.color
|
||||
var projectId by Labels.projectId
|
||||
var label by Versions.label
|
||||
var color by Versions.color
|
||||
var meta by Versions.meta
|
||||
var projectId by Versions.projectId
|
||||
|
||||
var project by Project referencedOn Labels.projectId
|
||||
var project by Project referencedOn Versions.projectId
|
||||
}
|
||||
|
||||
class Entry(id: EntityID<Uuid>) : Entity<Uuid>(id) {
|
||||
companion object : EntityClass<Uuid, Entry>(Entries)
|
||||
|
||||
var projectId by Entries.projectId
|
||||
var labelId by Entries.labelId
|
||||
var versionId by Entries.versionId
|
||||
var timestamp by Entries.timestamp
|
||||
var warmups by Entries.warmups
|
||||
var measurements by Entries.measurements
|
||||
@@ -69,5 +70,5 @@ class Entry(id: EntityID<Uuid>) : Entity<Uuid>(id) {
|
||||
var hardware by Entries.hardware
|
||||
|
||||
var project by Project referencedOn Entries.projectId
|
||||
var label by Label referencedOn Entries.labelId
|
||||
var version by Version referencedOn Entries.versionId
|
||||
}
|
||||
@@ -34,19 +34,20 @@ object Projects : UuidTable() {
|
||||
}
|
||||
}
|
||||
|
||||
object Labels : UuidTable() {
|
||||
object Versions : UuidTable() {
|
||||
val label = varchar("label", 255)
|
||||
val color = varchar("color", 7)
|
||||
val meta = text("meta", eagerLoading = true)
|
||||
val projectId = reference("project_id", Projects, onDelete = ReferenceOption.CASCADE, onUpdate = ReferenceOption.CASCADE)
|
||||
}
|
||||
|
||||
object Entries : UuidTable() {
|
||||
val projectId = reference("project_id", Projects, onDelete = ReferenceOption.CASCADE, onUpdate = ReferenceOption.CASCADE)
|
||||
val labelId = reference("label", Labels, onDelete = ReferenceOption.CASCADE, onUpdate = ReferenceOption.CASCADE)
|
||||
val versionId = reference("version", Versions, onDelete = ReferenceOption.CASCADE, onUpdate = ReferenceOption.CASCADE)
|
||||
val timestamp = timestamp("timestamp").default(Clock.System.now())
|
||||
val warmups = list<Float>("warmups")
|
||||
val measurements = list<Float>("measurements")
|
||||
val unit = enumeration<TimeUnit>("unit")
|
||||
val input = varchar("input", 255).default("")
|
||||
val hardware = varchar("hardware", 255).default("")
|
||||
val input = varchar("input", 255)
|
||||
val hardware = varchar("hardware", 255)
|
||||
}
|
||||
@@ -6,27 +6,24 @@ import com.jaytux.phoebench.common.EntryRequest
|
||||
import com.jaytux.phoebench.common.EntryResponse
|
||||
import com.jaytux.phoebench.common.HomeEvent
|
||||
import com.jaytux.phoebench.common.HomeResponse
|
||||
import com.jaytux.phoebench.common.LabelRequest
|
||||
import com.jaytux.phoebench.common.LabelResponse
|
||||
import com.jaytux.phoebench.common.VersionRequest
|
||||
import com.jaytux.phoebench.common.VersionResponse
|
||||
import com.jaytux.phoebench.common.NamedID
|
||||
import com.jaytux.phoebench.common.PartialEntryRequest
|
||||
import com.jaytux.phoebench.common.PartialLabelRequest
|
||||
import com.jaytux.phoebench.common.PartialProjectRequest
|
||||
import com.jaytux.phoebench.common.PartialVersionRequest
|
||||
import com.jaytux.phoebench.common.ProjectEvent
|
||||
import com.jaytux.phoebench.common.ProjectRequest
|
||||
import com.jaytux.phoebench.common.ProjectResponse
|
||||
import com.jaytux.phoebench.server.Buses
|
||||
import com.jaytux.phoebench.server.SSEBus
|
||||
import com.jaytux.phoebench.server.db.Entries
|
||||
import com.jaytux.phoebench.server.db.Entry
|
||||
import com.jaytux.phoebench.server.db.Label
|
||||
import com.jaytux.phoebench.server.db.Labels
|
||||
import com.jaytux.phoebench.server.db.Version
|
||||
import com.jaytux.phoebench.server.db.Versions
|
||||
import com.jaytux.phoebench.server.db.Project
|
||||
import com.jaytux.phoebench.server.db.Projects
|
||||
import com.jaytux.phoebench.server.db.User
|
||||
import com.jaytux.phoebench.server.handlers.RouteError.Companion.success
|
||||
import io.ktor.http.HttpStatusCode
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jetbrains.exposed.v1.core.SortOrder
|
||||
import org.jetbrains.exposed.v1.core.Transaction
|
||||
@@ -55,8 +52,8 @@ object ProjectHandler {
|
||||
context(trns: Transaction)
|
||||
private fun Project.toResponse(user: User) = ProjectResponse(
|
||||
id.value, name, NamedID(owner.username, owner.id.value), isPublic, isEditableBy(user),
|
||||
labels.orderBy(Labels.label to SortOrder.ASC).map { LabelResponse(it.id.value, it.label, it.color) },
|
||||
entries.orderBy(Entries.timestamp to SortOrder.ASC).map { EntryResponse(it.id.value, it.label.id.value, it.timestamp, it.warmups, it.measurements, it.unit, it.input, it.hardware) })
|
||||
labels.orderBy(Versions.label to SortOrder.ASC).map { VersionResponse(it.id.value, it.label, it.color, it.meta) },
|
||||
entries.orderBy(Entries.timestamp to SortOrder.ASC).map { EntryResponse(it.id.value, it.version.id.value, it.timestamp, it.warmups, it.measurements, it.unit, it.input, it.hardware) })
|
||||
|
||||
fun home(user: User, req: EmptyRequest) = transaction {
|
||||
val own = user.projects.orderBy(Projects.name to SortOrder.ASC).map {
|
||||
@@ -127,49 +124,51 @@ object ProjectHandler {
|
||||
success(EmptyResponse())
|
||||
}
|
||||
|
||||
fun createLabel(user: User, req: LabelRequest) = transaction {
|
||||
fun createVersion(user: User, req: VersionRequest) = transaction {
|
||||
val proj = accessibleProject(user, req.projectId, true)
|
||||
if(req.color.length != 7) throw RouteError("Expected Hex-RGB color (7 characters).", HttpStatusCode.BadRequest)
|
||||
val lbl = Label.new {
|
||||
val ver = Version.new {
|
||||
label = req.name
|
||||
color = req.color
|
||||
project = proj
|
||||
meta = req.meta
|
||||
}
|
||||
|
||||
val res = LabelResponse(lbl.id.value, lbl.label, lbl.color)
|
||||
val res = VersionResponse(ver.id.value, ver.label, ver.color, ver.meta)
|
||||
ServerScope.launch {
|
||||
Buses.projectBus(req.projectId).sendAll(ProjectEvent.NewLabel(res))
|
||||
Buses.projectBus(req.projectId).sendAll(ProjectEvent.NewVersion(res))
|
||||
}
|
||||
|
||||
success(res)
|
||||
}
|
||||
|
||||
fun updateLabel(user: User, req: Pair<Uuid, PartialLabelRequest>) = transaction {
|
||||
val lbl = Label.findById(req.first) ?: throw RouteError("Invalid label ID.", HttpStatusCode.NotFound)
|
||||
lbl.project.isAccessible(user, true)
|
||||
fun updateVersion(user: User, req: Pair<Uuid, PartialVersionRequest>) = transaction {
|
||||
val ver = Version.findById(req.first) ?: throw RouteError("Invalid version ID.", HttpStatusCode.NotFound)
|
||||
ver.project.isAccessible(user, true)
|
||||
val changes = req.second
|
||||
changes.name?.let { lbl.label = it }
|
||||
changes.name?.let { ver.label = it }
|
||||
changes.color?.let {
|
||||
if(it.length != 7) throw RouteError("Expected Hex-RGB color (7 characters).", HttpStatusCode.BadRequest)
|
||||
lbl.color = it
|
||||
ver.color = it
|
||||
}
|
||||
changes.meta?.let { ver.meta = it }
|
||||
|
||||
ServerScope.launch {
|
||||
Buses.projectBus(lbl.projectId.value).sendAll(ProjectEvent.LabelChanged(
|
||||
LabelResponse(lbl.id.value, lbl.label, lbl.color)
|
||||
Buses.projectBus(ver.projectId.value).sendAll(ProjectEvent.VersionChanged(
|
||||
VersionResponse(ver.id.value, ver.label, ver.color, ver.meta)
|
||||
))
|
||||
}
|
||||
|
||||
success(EmptyResponse())
|
||||
}
|
||||
|
||||
fun deleteLabel(user: User, req: Uuid) = transaction {
|
||||
val lbl = Label.findById(req) ?: throw RouteError("Invalid label ID.", HttpStatusCode.NotFound)
|
||||
lbl.project.isAccessible(user, true)
|
||||
lbl.delete()
|
||||
fun deleteVersion(user: User, req: Uuid) = transaction {
|
||||
val ver = Version.findById(req) ?: throw RouteError("Invalid version ID.", HttpStatusCode.NotFound)
|
||||
ver.project.isAccessible(user, true)
|
||||
ver.delete()
|
||||
|
||||
ServerScope.launch {
|
||||
Buses.projectBus(lbl.id.value).sendAll(ProjectEvent.LabelDeleted(req))
|
||||
Buses.projectBus(ver.id.value).sendAll(ProjectEvent.VersionDeleted(req))
|
||||
}
|
||||
|
||||
success(EmptyResponse())
|
||||
@@ -178,9 +177,9 @@ object ProjectHandler {
|
||||
fun createEntry(user: User, req: EntryRequest) = transaction {
|
||||
val proj = accessibleProject(user, req.projectId, true)
|
||||
val entry = Entry.new {
|
||||
label = when(val l = Label.findById(req.label)) {
|
||||
null -> throw RouteError("Invalid label ID.", HttpStatusCode.NotFound)
|
||||
is Label if l.projectId.value != proj.id.value -> throw RouteError("Label is attached to a different project.", HttpStatusCode.Conflict)
|
||||
version = when(val l = Version.findById(req.version)) {
|
||||
null -> throw RouteError("Invalid version ID.", HttpStatusCode.NotFound)
|
||||
is Version if l.projectId.value != proj.id.value -> throw RouteError("Version is attached to a different project.", HttpStatusCode.Conflict)
|
||||
else -> l
|
||||
}
|
||||
project = proj
|
||||
@@ -192,7 +191,7 @@ object ProjectHandler {
|
||||
hardware = req.hardware
|
||||
}
|
||||
|
||||
val response = EntryResponse(entry.id.value, entry.label.id.value, entry.timestamp, entry.warmups, entry.measurements, entry.unit, entry.input, entry.hardware)
|
||||
val response = EntryResponse(entry.id.value, entry.version.id.value, entry.timestamp, entry.warmups, entry.measurements, entry.unit, entry.input, entry.hardware)
|
||||
ServerScope.launch {
|
||||
Buses.projectBus(proj.id.value).sendAll(ProjectEvent.NewEntry(response))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user