Add ak constraints
This commit is contained in:
parent
743e57395a
commit
70e1c2ec26
12 changed files with 336 additions and 86 deletions
|
@ -40,39 +40,80 @@ fun checkConstraints(
|
||||||
errors += ConstraintError("Work group requires accessible, but room does not have one!")
|
errors += ConstraintError("Work group requires accessible, but room does not have one!")
|
||||||
}
|
}
|
||||||
|
|
||||||
for (constraint in schedule.workGroup.constraints) {
|
for ((type, constraints) in schedule.workGroup.constraints.groupBy { it.type }) {
|
||||||
when (constraint.type) {
|
when (type) {
|
||||||
ConstraintType.OnlyOnDay -> {
|
ConstraintType.OnlyOnDay -> {
|
||||||
if (constraint.number.toInt() != schedule.day) {
|
val onlyOnDay = constraints.map { it.day == schedule.day }
|
||||||
errors += ConstraintError("Work group requires day ${constraint.number}, but is on ${schedule.day}!")
|
if (!onlyOnDay.any()) {
|
||||||
|
val dayList = constraints.mapNotNull { it.day }.distinct().sorted()
|
||||||
|
errors += ConstraintError("Work group requires days $dayList, but is on ${schedule.day}!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConstraintType.OnlyAfterTime -> {
|
|
||||||
if (constraint.number.toInt() > schedule.time) {
|
ConstraintType.NotOnDay -> {
|
||||||
errors += ConstraintError("Work group requires time after ${constraint.number}, but is on ${schedule.time}!")
|
val notOnDay = constraints.map { it.day == schedule.day }
|
||||||
|
if (notOnDay.any()) {
|
||||||
|
val dayList = constraints.mapNotNull { it.day }.distinct().sorted()
|
||||||
|
errors += ConstraintError("Work group requires not days $dayList, but is on ${schedule.day}!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConstraintType.NotAtSameTime -> {
|
|
||||||
val start = schedule.getAbsoluteStartTime()
|
ConstraintType.OnlyBeforeTime -> {
|
||||||
val end = schedule.getAbsoluteEndTime()
|
for (it in constraints) {
|
||||||
for (s in against) {
|
if (it.time == null) continue
|
||||||
if (
|
if (it.day == null) {
|
||||||
s.workGroup.id == constraint.number &&
|
if (it.time > schedule.time) {
|
||||||
start <= s.getAbsoluteEndTime() &&
|
errors += ConstraintError("Work group requires before time ${it.time}, but is on ${schedule.time}!")
|
||||||
s.getAbsoluteStartTime() <= end
|
}
|
||||||
) {
|
} else {
|
||||||
errors += ConstraintError("Work group requires not same time with ${s.workGroup.name}!")
|
if (it.day == schedule.day && it.time > schedule.time) {
|
||||||
|
errors += ConstraintError("Work group requires before time ${it.time} on day ${it.day}, but is on ${schedule.time}!")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConstraintType.OnlyAfterTime -> {
|
||||||
|
for (it in constraints) {
|
||||||
|
if (it.time == null) continue
|
||||||
|
if (it.day == null) {
|
||||||
|
if (it.time < schedule.time) {
|
||||||
|
errors += ConstraintError("Work group requires after time ${it.time}, but is on ${schedule.time}!")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (it.day == schedule.day && it.time < schedule.time) {
|
||||||
|
errors += ConstraintError("Work group requires after time ${it.time} on day ${it.day}, but is on ${schedule.time}!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstraintType.NotAtSameTime -> {
|
||||||
|
val start = schedule.getAbsoluteStartTime()
|
||||||
|
val end = schedule.getAbsoluteEndTime()
|
||||||
|
for (constraint in constraints) {
|
||||||
|
for (s in against) {
|
||||||
|
if (
|
||||||
|
s.workGroup.id == constraint.workGroup &&
|
||||||
|
start <= s.getAbsoluteEndTime() &&
|
||||||
|
s.getAbsoluteStartTime() <= end
|
||||||
|
) {
|
||||||
|
errors += ConstraintError("Work group requires not same time with ${s.workGroup.name}!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ConstraintType.OnlyAfterWorkGroup -> {
|
ConstraintType.OnlyAfterWorkGroup -> {
|
||||||
val start = schedule.getAbsoluteStartTime()
|
val start = schedule.getAbsoluteStartTime()
|
||||||
for (s in against) {
|
for (constraint in constraints) {
|
||||||
if (
|
for (s in against) {
|
||||||
s.workGroup.id == constraint.number &&
|
if (
|
||||||
s.getAbsoluteEndTime() > start
|
s.workGroup.id == constraint.workGroup &&
|
||||||
) {
|
s.getAbsoluteEndTime() > start
|
||||||
errors += ConstraintError("Work group requires after ${s.workGroup.name}!")
|
) {
|
||||||
|
errors += ConstraintError("Work group requires after ${s.workGroup.name}!")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,40 @@ import kotlinx.serialization.Serializable
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Constraint(
|
data class Constraint(
|
||||||
val type: ConstraintType,
|
val type: ConstraintType,
|
||||||
val number: Long
|
val day: Int? = null,
|
||||||
|
val time: Int? = null,
|
||||||
|
val workGroup: Long? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
enum class ConstraintType {
|
enum class ConstraintType {
|
||||||
OnlyOnDay, OnlyAfterTime, NotAtSameTime, OnlyAfterWorkGroup
|
|
||||||
|
/**
|
||||||
|
* Requires day, permits time and workGroup.
|
||||||
|
*/
|
||||||
|
OnlyOnDay,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requires day, permits time and workGroup.
|
||||||
|
*/
|
||||||
|
NotOnDay,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requires time, optionally allows day, permits workGroup.
|
||||||
|
*/
|
||||||
|
OnlyAfterTime,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requires time, optionally allows day, permits workGroup.
|
||||||
|
*/
|
||||||
|
OnlyBeforeTime,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requires workGroup, permits day and time.
|
||||||
|
*/
|
||||||
|
NotAtSameTime,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requires workGroup, permits day and time.
|
||||||
|
*/
|
||||||
|
OnlyAfterWorkGroup
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ data class WorkGroup(
|
||||||
val accessible: Boolean,
|
val accessible: Boolean,
|
||||||
val length: Int,
|
val length: Int,
|
||||||
val language: Language,
|
val language: Language,
|
||||||
|
val leader: List<String>,
|
||||||
val constraints: List<Constraint>,
|
val constraints: List<Constraint>,
|
||||||
override val createdAt: Long = 0,
|
override val createdAt: Long = 0,
|
||||||
override val updateAt: Long = 0
|
override val updateAt: Long = 0
|
||||||
|
|
|
@ -51,6 +51,44 @@ fun initWorkGroupConstraints() {
|
||||||
}.html)
|
}.html)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
addList.textView("Add not on day") {
|
||||||
|
onClick {
|
||||||
|
constraints.appendChild(View.wrap(createHtmlView<HTMLDivElement>()) {
|
||||||
|
classList += "input-group"
|
||||||
|
html.appendChild(TextView("Not day").apply {
|
||||||
|
classList += "form-btn"
|
||||||
|
onClick { this@wrap.html.remove() }
|
||||||
|
}.html)
|
||||||
|
html.appendChild(InputView(InputType.NUMBER).apply {
|
||||||
|
classList += "form-control"
|
||||||
|
html.name = "constraint-not-on-day-${index++}"
|
||||||
|
min = -1337.0
|
||||||
|
max = 1337.0
|
||||||
|
}.html)
|
||||||
|
}.html)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addList.textView("Add only before time") {
|
||||||
|
onClick {
|
||||||
|
constraints.appendChild(View.wrap(createHtmlView<HTMLDivElement>()) {
|
||||||
|
classList += "input-group"
|
||||||
|
html.appendChild(TextView("Before time").apply {
|
||||||
|
classList += "form-btn"
|
||||||
|
onClick { this@wrap.html.remove() }
|
||||||
|
}.html)
|
||||||
|
html.appendChild(InputView(InputType.TEXT).apply {
|
||||||
|
classList += "form-control"
|
||||||
|
html.name = "constraint-only-before-time-day-${index++}"
|
||||||
|
}.html)
|
||||||
|
html.appendChild(InputView(InputType.NUMBER).apply {
|
||||||
|
classList += "form-control"
|
||||||
|
html.name = "constraint-only-before-time-${index++}"
|
||||||
|
min = -1337.0
|
||||||
|
max = 133700.0
|
||||||
|
}.html)
|
||||||
|
}.html)
|
||||||
|
}
|
||||||
|
}
|
||||||
addList.textView("Add only after time") {
|
addList.textView("Add only after time") {
|
||||||
onClick {
|
onClick {
|
||||||
constraints.appendChild(View.wrap(createHtmlView<HTMLDivElement>()) {
|
constraints.appendChild(View.wrap(createHtmlView<HTMLDivElement>()) {
|
||||||
|
@ -59,6 +97,10 @@ fun initWorkGroupConstraints() {
|
||||||
classList += "form-btn"
|
classList += "form-btn"
|
||||||
onClick { this@wrap.html.remove() }
|
onClick { this@wrap.html.remove() }
|
||||||
}.html)
|
}.html)
|
||||||
|
html.appendChild(InputView(InputType.TEXT).apply {
|
||||||
|
classList += "form-control"
|
||||||
|
html.name = "constraint-only-after-time-day-${index++}"
|
||||||
|
}.html)
|
||||||
html.appendChild(InputView(InputType.NUMBER).apply {
|
html.appendChild(InputView(InputType.NUMBER).apply {
|
||||||
classList += "form-control"
|
classList += "form-control"
|
||||||
html.name = "constraint-only-after-time-${index++}"
|
html.name = "constraint-only-after-time-${index++}"
|
||||||
|
@ -125,7 +167,6 @@ fun initWorkGroupConstraints() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(constraints)
|
|
||||||
for (child in constraints.children.iterator()) {
|
for (child in constraints.children.iterator()) {
|
||||||
console.log(child)
|
console.log(child)
|
||||||
if (child.classList.contains("input-group")) {
|
if (child.classList.contains("input-group")) {
|
||||||
|
|
|
@ -15,7 +15,7 @@ import org.w3c.dom.get
|
||||||
|
|
||||||
class WorkGroupTableLine(view: HTMLElement) : TableLine(view) {
|
class WorkGroupTableLine(view: HTMLElement) : TableLine(view) {
|
||||||
|
|
||||||
var lineId = dataset["id"]?.toLongOrNull() ?: -1
|
private var lineId = dataset["id"]?.toLongOrNull() ?: -1
|
||||||
|
|
||||||
private val workGroup =
|
private val workGroup =
|
||||||
RepositoryDelegate(WorkGroupRepository, lineId)
|
RepositoryDelegate(WorkGroupRepository, lineId)
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
margin: 1px;
|
margin: 1px;
|
||||||
transition: border-color $transitionTime;
|
transition: border-color $transitionTime;
|
||||||
color: var(--text-primary-color);
|
color: var(--text-primary-color);
|
||||||
|
min-width: 0;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
border-color: var(--primary-color);
|
border-color: var(--primary-color);
|
||||||
|
@ -41,6 +42,16 @@ select:-moz-focusring {
|
||||||
padding-bottom: 0.3rem;
|
padding-bottom: 0.3rem;
|
||||||
padding-left: 0.2rem;
|
padding-left: 0.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: attr(data-hint);
|
||||||
|
position: absolute;
|
||||||
|
left: 100%;
|
||||||
|
color: var(--text-secondary-color);
|
||||||
|
line-height: 2.5rem;
|
||||||
|
margin-left: 1rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-switch {
|
.form-switch {
|
||||||
|
@ -177,7 +188,7 @@ form {
|
||||||
& > * {
|
& > * {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
flex-shrink: 1;
|
flex-basis: 0;
|
||||||
|
|
||||||
&:not(:first-child) {
|
&:not(:first-child) {
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
|
|
|
@ -90,7 +90,9 @@
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
width: 4rem;
|
width: 8rem;
|
||||||
|
flex-basis: 8rem;
|
||||||
|
flex-grow: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
|
@ -29,6 +29,7 @@ object DbWorkGroup : Table() {
|
||||||
val accessible = bool("accessible")
|
val accessible = bool("accessible")
|
||||||
|
|
||||||
val language = enumeration("language", Language::class)
|
val language = enumeration("language", Language::class)
|
||||||
|
val leader = text("leader").default("[]")
|
||||||
|
|
||||||
val length = integer("length")
|
val length = integer("length")
|
||||||
val constraints = text("constraints")
|
val constraints = text("constraints")
|
||||||
|
|
|
@ -12,6 +12,7 @@ import de.kif.common.model.WorkGroup
|
||||||
import de.westermann.kobserve.event.EventHandler
|
import de.westermann.kobserve.event.EventHandler
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.serialization.list
|
import kotlinx.serialization.list
|
||||||
|
import kotlinx.serialization.serializer
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
|
@ -35,6 +36,7 @@ object WorkGroupRepository : Repository<WorkGroup> {
|
||||||
val accessible = row[DbWorkGroup.accessible]
|
val accessible = row[DbWorkGroup.accessible]
|
||||||
val length = row[DbWorkGroup.length]
|
val length = row[DbWorkGroup.length]
|
||||||
val language = row[DbWorkGroup.language]
|
val language = row[DbWorkGroup.language]
|
||||||
|
val leader = Message.json.parse(String.serializer().list, row[DbWorkGroup.leader])
|
||||||
val constraints = Message.json.parse(Constraint.serializer().list, row[DbWorkGroup.constraints])
|
val constraints = Message.json.parse(Constraint.serializer().list, row[DbWorkGroup.constraints])
|
||||||
|
|
||||||
val createdAt = row[DbWorkGroup.createdAt]
|
val createdAt = row[DbWorkGroup.createdAt]
|
||||||
|
@ -56,6 +58,7 @@ object WorkGroupRepository : Repository<WorkGroup> {
|
||||||
accessible,
|
accessible,
|
||||||
length,
|
length,
|
||||||
language,
|
language,
|
||||||
|
leader,
|
||||||
constraints,
|
constraints,
|
||||||
createdAt,
|
createdAt,
|
||||||
updatedAt
|
updatedAt
|
||||||
|
@ -89,6 +92,7 @@ object WorkGroupRepository : Repository<WorkGroup> {
|
||||||
it[accessible] = model.accessible
|
it[accessible] = model.accessible
|
||||||
it[length] = model.length
|
it[length] = model.length
|
||||||
it[language] = model.language
|
it[language] = model.language
|
||||||
|
it[leader] = Message.json.stringify(String.serializer().list, model.leader)
|
||||||
it[constraints] = Message.json.stringify(Constraint.serializer().list, model.constraints)
|
it[constraints] = Message.json.stringify(Constraint.serializer().list, model.constraints)
|
||||||
|
|
||||||
it[createdAt] = now
|
it[createdAt] = now
|
||||||
|
@ -120,6 +124,7 @@ object WorkGroupRepository : Repository<WorkGroup> {
|
||||||
it[accessible] = model.accessible
|
it[accessible] = model.accessible
|
||||||
it[length] = model.length
|
it[length] = model.length
|
||||||
it[language] = model.language
|
it[language] = model.language
|
||||||
|
it[leader] = Message.json.stringify(String.serializer().list, model.leader)
|
||||||
it[constraints] = Message.json.stringify(Constraint.serializer().list, model.constraints)
|
it[constraints] = Message.json.stringify(Constraint.serializer().list, model.constraints)
|
||||||
|
|
||||||
it[updatedAt] = now
|
it[updatedAt] = now
|
||||||
|
|
|
@ -3,15 +3,12 @@ package de.kif.backend.route
|
||||||
import de.kif.backend.authenticateOrRedirect
|
import de.kif.backend.authenticateOrRedirect
|
||||||
import de.kif.backend.repository.TrackRepository
|
import de.kif.backend.repository.TrackRepository
|
||||||
import de.kif.backend.repository.WorkGroupRepository
|
import de.kif.backend.repository.WorkGroupRepository
|
||||||
import de.kif.backend.view.MainTemplate
|
|
||||||
import de.kif.backend.view.MenuTemplate
|
|
||||||
import de.kif.backend.view.TableTemplate
|
import de.kif.backend.view.TableTemplate
|
||||||
import de.kif.backend.view.respondMain
|
import de.kif.backend.view.respondMain
|
||||||
import de.kif.common.Search
|
import de.kif.common.Search
|
||||||
import de.kif.common.model.*
|
import de.kif.common.model.*
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
import io.ktor.html.insert
|
import io.ktor.html.insert
|
||||||
import io.ktor.html.respondHtmlTemplate
|
|
||||||
import io.ktor.request.receiveParameters
|
import io.ktor.request.receiveParameters
|
||||||
import io.ktor.response.respondRedirect
|
import io.ktor.response.respondRedirect
|
||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
|
@ -23,6 +20,8 @@ import kotlinx.css.Display
|
||||||
import kotlinx.html.*
|
import kotlinx.html.*
|
||||||
import kotlin.collections.set
|
import kotlin.collections.set
|
||||||
|
|
||||||
|
private const val separator = "###"
|
||||||
|
|
||||||
fun Route.workGroup() {
|
fun Route.workGroup() {
|
||||||
get("workgroups") {
|
get("workgroups") {
|
||||||
authenticateOrRedirect(Permission.WORK_GROUP) { user ->
|
authenticateOrRedirect(Permission.WORK_GROUP) { user ->
|
||||||
|
@ -152,11 +151,7 @@ fun Route.workGroup() {
|
||||||
val tracks = TrackRepository.all()
|
val tracks = TrackRepository.all()
|
||||||
|
|
||||||
val workGroups = editWorkGroup.constraints.mapNotNull {
|
val workGroups = editWorkGroup.constraints.mapNotNull {
|
||||||
when (it.type) {
|
it.workGroup
|
||||||
ConstraintType.NotAtSameTime -> it.number
|
|
||||||
ConstraintType.OnlyAfterWorkGroup -> it.number
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}.distinct().associateWith {
|
}.distinct().associateWith {
|
||||||
WorkGroupRepository.get(it)!!
|
WorkGroupRepository.get(it)!!
|
||||||
}
|
}
|
||||||
|
@ -270,6 +265,24 @@ fun Route.workGroup() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div("form-group") {
|
||||||
|
attributes["data-hint"] = "Use '$separator' to separate multiple leaders"
|
||||||
|
|
||||||
|
label {
|
||||||
|
htmlFor = "leader"
|
||||||
|
+"Leader"
|
||||||
|
}
|
||||||
|
input(
|
||||||
|
name = "leader",
|
||||||
|
classes = "form-control"
|
||||||
|
) {
|
||||||
|
id = "leader"
|
||||||
|
placeholder = "Leader"
|
||||||
|
|
||||||
|
value = editWorkGroup.leader.joinToString(" $separator ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
div("form-switch-group") {
|
div("form-switch-group") {
|
||||||
div("form-group form-switch") {
|
div("form-group form-switch") {
|
||||||
input(
|
input(
|
||||||
|
@ -383,22 +396,66 @@ fun Route.workGroup() {
|
||||||
classes = "form-control",
|
classes = "form-control",
|
||||||
type = InputType.number
|
type = InputType.number
|
||||||
) {
|
) {
|
||||||
value = constraint.number.toString()
|
value = constraint.day.toString()
|
||||||
|
|
||||||
min = "-1337"
|
min = "-1337"
|
||||||
max = "1337"
|
max = "1337"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ConstraintType.NotOnDay -> {
|
||||||
|
span("form-btn") {
|
||||||
|
+"Not day"
|
||||||
|
}
|
||||||
|
input(
|
||||||
|
name = "constraint-not-on-day-$index",
|
||||||
|
classes = "form-control",
|
||||||
|
type = InputType.number
|
||||||
|
) {
|
||||||
|
value = constraint.day.toString()
|
||||||
|
|
||||||
|
min = "-1337"
|
||||||
|
max = "1337"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConstraintType.OnlyBeforeTime -> {
|
||||||
|
span("form-btn") {
|
||||||
|
+"Before time"
|
||||||
|
}
|
||||||
|
input(
|
||||||
|
name = "constraint-only-before-time-day-$index",
|
||||||
|
classes = "form-control"
|
||||||
|
) {
|
||||||
|
value = constraint.day?.toString() ?: ""
|
||||||
|
placeholder = "day"
|
||||||
|
}
|
||||||
|
input(
|
||||||
|
name = "constraint-only-before-time-$index",
|
||||||
|
classes = "form-control",
|
||||||
|
type = InputType.number
|
||||||
|
) {
|
||||||
|
value = constraint.time.toString()
|
||||||
|
|
||||||
|
min = "-1337"
|
||||||
|
max = "133700"
|
||||||
|
}
|
||||||
|
}
|
||||||
ConstraintType.OnlyAfterTime -> {
|
ConstraintType.OnlyAfterTime -> {
|
||||||
span("form-btn") {
|
span("form-btn") {
|
||||||
+"After time"
|
+"After time"
|
||||||
}
|
}
|
||||||
|
input(
|
||||||
|
name = "constraint-only-after-time-day-$index",
|
||||||
|
classes = "form-control"
|
||||||
|
) {
|
||||||
|
value = constraint.day?.toString() ?: ""
|
||||||
|
placeholder = "day"
|
||||||
|
}
|
||||||
input(
|
input(
|
||||||
name = "constraint-only-after-time-$index",
|
name = "constraint-only-after-time-$index",
|
||||||
classes = "form-control",
|
classes = "form-control",
|
||||||
type = InputType.number
|
type = InputType.number
|
||||||
) {
|
) {
|
||||||
value = constraint.number.toString()
|
value = constraint.time.toString()
|
||||||
|
|
||||||
min = "-1337"
|
min = "-1337"
|
||||||
max = "133700"
|
max = "133700"
|
||||||
|
@ -415,8 +472,8 @@ fun Route.workGroup() {
|
||||||
|
|
||||||
option {
|
option {
|
||||||
selected = true
|
selected = true
|
||||||
value = constraint.number.toString()
|
value = constraint.workGroup.toString()
|
||||||
+(workGroups[constraint.number]?.name ?: "")
|
+(workGroups[constraint.workGroup!!]?.name ?: "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -431,8 +488,8 @@ fun Route.workGroup() {
|
||||||
|
|
||||||
option {
|
option {
|
||||||
selected = true
|
selected = true
|
||||||
value = constraint.number.toString()
|
value = constraint.workGroup.toString()
|
||||||
+(workGroups[constraint.number]?.name ?: "")
|
+(workGroups[constraint.workGroup!!]?.name ?: "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -490,25 +547,13 @@ fun Route.workGroup() {
|
||||||
editWorkGroup =
|
editWorkGroup =
|
||||||
editWorkGroup.copy(language = Language.values().find { l -> l.code == it } ?: Language.GERMAN)
|
editWorkGroup.copy(language = Language.values().find { l -> l.code == it } ?: Language.GERMAN)
|
||||||
}
|
}
|
||||||
|
params["leader"]?.let {
|
||||||
val constraints = params.mapNotNull { (key, value) ->
|
val leader = it.split("\\s*$separator+\\s*".toRegex())
|
||||||
when {
|
editWorkGroup = editWorkGroup.copy(leader = leader)
|
||||||
key.startsWith("constraint-only-on-day") -> {
|
|
||||||
value?.toLongOrNull()?.let { Constraint(ConstraintType.OnlyOnDay, it) }
|
|
||||||
}
|
|
||||||
key.startsWith("constraint-only-after-time") -> {
|
|
||||||
value?.toLongOrNull()?.let { Constraint(ConstraintType.OnlyAfterTime, it) }
|
|
||||||
}
|
|
||||||
key.startsWith("constraint-not-at-same-time") -> {
|
|
||||||
value?.toLongOrNull()?.let { Constraint(ConstraintType.NotAtSameTime, it) }
|
|
||||||
}
|
|
||||||
key.startsWith("constraint-only-after-work-group") -> {
|
|
||||||
value?.toLongOrNull()?.let { Constraint(ConstraintType.OnlyAfterWorkGroup, it) }
|
|
||||||
}
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val constraints = parseConstraintParam(params)
|
||||||
|
|
||||||
editWorkGroup = editWorkGroup.copy(constraints = constraints)
|
editWorkGroup = editWorkGroup.copy(constraints = constraints)
|
||||||
|
|
||||||
WorkGroupRepository.update(editWorkGroup)
|
WorkGroupRepository.update(editWorkGroup)
|
||||||
|
@ -628,6 +673,25 @@ fun Route.workGroup() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div("form-group") {
|
||||||
|
attributes["data-hint"] = "Use '$separator' to separate multiple leaders"
|
||||||
|
|
||||||
|
label {
|
||||||
|
htmlFor = "leader"
|
||||||
|
+"Leader"
|
||||||
|
}
|
||||||
|
input(
|
||||||
|
name = "leader",
|
||||||
|
classes = "form-control"
|
||||||
|
) {
|
||||||
|
id = "leader"
|
||||||
|
placeholder = "Leader"
|
||||||
|
|
||||||
|
value = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
div("form-switch-group") {
|
div("form-switch-group") {
|
||||||
div("form-group form-switch") {
|
div("form-group form-switch") {
|
||||||
input(
|
input(
|
||||||
|
@ -763,29 +827,14 @@ fun Route.workGroup() {
|
||||||
val language = (params["language"] ?: return@post).let {
|
val language = (params["language"] ?: return@post).let {
|
||||||
Language.values().find { l -> l.code == it } ?: Language.GERMAN
|
Language.values().find { l -> l.code == it } ?: Language.GERMAN
|
||||||
}
|
}
|
||||||
|
val leader = params["leader"]?.split("\\s*$separator+\\s*".toRegex()) ?: return@post
|
||||||
|
|
||||||
val internet = params["internet"] == "on"
|
val internet = params["internet"] == "on"
|
||||||
val whiteboard = params["whiteboard"] == "on"
|
val whiteboard = params["whiteboard"] == "on"
|
||||||
val blackboard = params["blackboard"] == "on"
|
val blackboard = params["blackboard"] == "on"
|
||||||
val accessible = params["accessible"] == "on"
|
val accessible = params["accessible"] == "on"
|
||||||
|
|
||||||
val constraints = params.mapNotNull { (key, value) ->
|
val constraints = parseConstraintParam(params)
|
||||||
when {
|
|
||||||
key.startsWith("constraint-only-on-day") -> {
|
|
||||||
value?.toLongOrNull()?.let { Constraint(ConstraintType.OnlyOnDay, it) }
|
|
||||||
}
|
|
||||||
key.startsWith("constraint-only-after-time") -> {
|
|
||||||
value?.toLongOrNull()?.let { Constraint(ConstraintType.OnlyAfterTime, it) }
|
|
||||||
}
|
|
||||||
key.startsWith("constraint-not-at-same-time") -> {
|
|
||||||
value?.toLongOrNull()?.let { Constraint(ConstraintType.NotAtSameTime, it) }
|
|
||||||
}
|
|
||||||
key.startsWith("constraint-only-after-work-group") -> {
|
|
||||||
value?.toLongOrNull()?.let { Constraint(ConstraintType.OnlyAfterWorkGroup, it) }
|
|
||||||
}
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val workGroup = WorkGroup(
|
val workGroup = WorkGroup(
|
||||||
null,
|
null,
|
||||||
|
@ -801,6 +850,7 @@ fun Route.workGroup() {
|
||||||
accessible = accessible,
|
accessible = accessible,
|
||||||
length = length,
|
length = length,
|
||||||
language = language,
|
language = language,
|
||||||
|
leader = leader,
|
||||||
constraints = constraints
|
constraints = constraints
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -820,3 +870,63 @@ fun Route.workGroup() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun parseConstraintParam(params: Map<String, String?>) = params.map { (key, value) ->
|
||||||
|
val id = key.substringAfterLast("-").toIntOrNull() ?: -1
|
||||||
|
id to when {
|
||||||
|
key.startsWith("constraint-only-on-day") -> {
|
||||||
|
value?.toIntOrNull()?.let { Constraint(ConstraintType.OnlyOnDay, day = it) }
|
||||||
|
}
|
||||||
|
key.startsWith("constraint-not-on-day") -> {
|
||||||
|
value?.toIntOrNull()?.let { Constraint(ConstraintType.NotOnDay, day = it) }
|
||||||
|
}
|
||||||
|
key.startsWith("constraint-only-after-time") -> {
|
||||||
|
if ("day" in key) {
|
||||||
|
value?.toIntOrNull()?.let { Constraint(ConstraintType.OnlyAfterTime, day = it) }
|
||||||
|
} else {
|
||||||
|
value?.toIntOrNull()?.let { Constraint(ConstraintType.OnlyAfterTime, time = it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
key.startsWith("constraint-only-before-time") -> {
|
||||||
|
if ("day" in key) {
|
||||||
|
value?.toIntOrNull()?.let { Constraint(ConstraintType.OnlyBeforeTime, day = it) }
|
||||||
|
} else {
|
||||||
|
value?.toIntOrNull()?.let { Constraint(ConstraintType.OnlyBeforeTime, time = it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
key.startsWith("constraint-not-at-same-time") -> {
|
||||||
|
value?.toLongOrNull()?.let { Constraint(ConstraintType.NotAtSameTime, workGroup = it) }
|
||||||
|
}
|
||||||
|
key.startsWith("constraint-only-after-work-group") -> {
|
||||||
|
value?.toLongOrNull()?.let { Constraint(ConstraintType.OnlyAfterWorkGroup, workGroup = it) }
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}.groupBy({ it.first }) {
|
||||||
|
it.second
|
||||||
|
}.mapNotNull { (_, c) ->
|
||||||
|
when {
|
||||||
|
c.isEmpty() -> null
|
||||||
|
c.size == 1 -> c.first()
|
||||||
|
c.size == 2 -> {
|
||||||
|
val c1 = c[0] ?: return@mapNotNull null
|
||||||
|
val c2 = c[1] ?: return@mapNotNull null
|
||||||
|
|
||||||
|
when {
|
||||||
|
c1.type != c2.type -> null
|
||||||
|
c1.type == ConstraintType.OnlyBeforeTime -> Constraint(
|
||||||
|
ConstraintType.OnlyBeforeTime,
|
||||||
|
day = c1.day ?: c2.day,
|
||||||
|
time = c1.time ?: c2.time
|
||||||
|
)
|
||||||
|
c1.type == ConstraintType.OnlyAfterTime -> Constraint(
|
||||||
|
ConstraintType.OnlyAfterTime,
|
||||||
|
day = c1.day ?: c2.day,
|
||||||
|
time = c1.time ?: c2.time
|
||||||
|
)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -49,25 +49,31 @@ data class Backup(
|
||||||
suspend fun import(data: String) {
|
suspend fun import(data: String) {
|
||||||
val backup = Message.json.parse(serializer(), data)
|
val backup = Message.json.parse(serializer(), data)
|
||||||
|
|
||||||
val userMap = backup.users.associateWith { UserRepository.create(it) }
|
backup.users.forEach { UserRepository.create(it) }
|
||||||
val postMap = backup.posts.associateWith { PostRepository.create(it) }
|
backup.posts.forEach { PostRepository.create(it) }
|
||||||
|
|
||||||
val roomMap = backup.rooms.associateWith { RoomRepository.create(it) }
|
backup.rooms.forEach { RoomRepository.create(it) }
|
||||||
val trackMap = backup.tracks.associateWith { TrackRepository.create(it) }
|
val roomMap = RoomRepository.all().associateWith { it.id!! }
|
||||||
val workGroupMap = backup.workGroups.associateWith {
|
|
||||||
|
backup.tracks.forEach { TrackRepository.create(it) }
|
||||||
|
val trackMap =TrackRepository.all().associateWith { it.id!! }
|
||||||
|
|
||||||
|
backup.workGroups.forEach {
|
||||||
var workGroup = it
|
var workGroup = it
|
||||||
val track = workGroup.track
|
val track = workGroup.track
|
||||||
if (track != null) {
|
if (track != null) {
|
||||||
workGroup = workGroup.copy(track = track.copy(id = trackMap[track] ?: return@associateWith -1L))
|
workGroup = workGroup.copy(track = track.copy(id = trackMap[track] ?: return@forEach))
|
||||||
}
|
}
|
||||||
|
|
||||||
WorkGroupRepository.create(workGroup)
|
WorkGroupRepository.create(workGroup)
|
||||||
}
|
}
|
||||||
val scheduleMap = backup.schedules.associateWith {
|
val workGroupMap = WorkGroupRepository.all().associateWith { it.id!! }
|
||||||
|
|
||||||
|
backup.schedules.forEach {
|
||||||
ScheduleRepository.create(
|
ScheduleRepository.create(
|
||||||
it.copy(
|
it.copy(
|
||||||
room = it.room.copy(id = roomMap[it.room] ?: return@associateWith -1L),
|
room = it.room.copy(id = roomMap[it.room] ?: return@forEach),
|
||||||
workGroup = it.workGroup.copy(id = workGroupMap[it.workGroup] ?: return@associateWith -1L)
|
workGroup = it.workGroup.copy(id = workGroupMap[it.workGroup] ?: return@forEach)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,6 +147,7 @@ object WikiImporter {
|
||||||
accessible = false,
|
accessible = false,
|
||||||
length = akLength,
|
length = akLength,
|
||||||
language = Language.GERMAN,
|
language = Language.GERMAN,
|
||||||
|
leader = listOf(who),
|
||||||
constraints = emptyList()
|
constraints = emptyList()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue