Compare commits

...

2 commits

Author SHA1 Message Date
Lars Westermann 664f9c1777
Hard reload for info beamer 2019-06-13 06:45:07 +02:00
Lars Westermann e8f816e7ec
Bugfixes 2019-06-13 05:27:22 +02:00
17 changed files with 138 additions and 35 deletions

View file

@ -90,6 +90,7 @@ kotlin {
implementation "io.ktor:ktor-client-apache:$ktor_version" implementation "io.ktor:ktor-client-apache:$ktor_version"
implementation 'org.xerial:sqlite-jdbc:3.25.2' implementation 'org.xerial:sqlite-jdbc:3.25.2'
api 'mysql:mysql-connector-java:8.0.16'
implementation 'org.jetbrains.exposed:exposed:0.12.2' implementation 'org.jetbrains.exposed:exposed:0.12.2'
implementation 'org.mindrot:jbcrypt:0.4' implementation 'org.mindrot:jbcrypt:0.4'

View file

@ -18,3 +18,9 @@ wiki_url = "https://wiki.kif.rocks/w/index.php?title=KIF470:Arbeitskreise&action
[twitter] [twitter]
timeline = "https://twitter.com/kiforbiter?ref_src=twsrc%5Etfw" timeline = "https://twitter.com/kiforbiter?ref_src=twsrc%5Etfw"
[database]
type = "sqlite"
url = ""
username = ""
password = ""

View file

@ -69,6 +69,10 @@ fun checkConstraints(
} }
} }
if (schedule.workGroup.interested > schedule.room.places) {
errors += ConstraintError("The work group has more interested then the room has places")
}
for (leader in schedule.workGroup.leader) { for (leader in schedule.workGroup.leader) {
for (s in against) { for (s in against) {
if ( if (

View file

@ -1,5 +1,8 @@
package de.kif.frontend package de.kif.frontend
import de.kif.frontend.repository.RoomRepository
import de.kif.frontend.repository.ScheduleRepository
import de.kif.frontend.repository.WorkGroupRepository
import de.kif.frontend.views.board.initBoard import de.kif.frontend.views.board.initBoard
import de.kif.frontend.views.calendar.initCalendar import de.kif.frontend.views.calendar.initCalendar
import de.kif.frontend.views.initAnnouncement import de.kif.frontend.views.initAnnouncement
@ -61,4 +64,35 @@ fun main() = init {
} }
} }
} }
val url = window.location.pathname
if ("brett" in url || "wand" in url) {
ScheduleRepository.onCreate {
window.location.reload()
}
ScheduleRepository.onUpdate {
window.location.reload()
}
ScheduleRepository.onDelete {
window.location.reload()
}
RoomRepository.onCreate {
window.location.reload()
}
RoomRepository.onUpdate {
window.location.reload()
}
RoomRepository.onDelete {
window.location.reload()
}
WorkGroupRepository.onCreate {
window.location.reload()
}
WorkGroupRepository.onUpdate {
window.location.reload()
}
WorkGroupRepository.onDelete {
window.location.reload()
}
}
} }

View file

@ -26,11 +26,12 @@ class Calendar(calendar: HTMLElement) : View(calendar) {
private val htmlBody = document.body ?: createHtmlView() private val htmlBody = document.body ?: createHtmlView()
val day = (calendarTable.dataset["day"]?.toIntOrNull() ?: -1).also { println(it) } val day = (calendarTable.dataset["day"]?.toIntOrNull() ?: -1)
val reloadOnFinish = (calendarTable.dataset["reload"]?.toBoolean() ?: false).also { println(it) } val reloadOnFinish = (calendarTable.dataset["reload"]?.toBoolean() ?: false)
val referenceDate = (calendarTable.dataset["reference"]?.toLongOrNull() ?: -1L).also { println(it) } val hideEmpty = (calendarTable.dataset["hide-empty"]?.toBoolean() ?: false)
val nowDate = (calendarTable.dataset["now"]?.toLongOrNull() ?: -1L).also { println(it) } val referenceDate = (calendarTable.dataset["reference"]?.toLongOrNull() ?: -1L)
val timeDifference = (Date.now().toLong() - nowDate).also { println(it) } val nowDate = (calendarTable.dataset["now"]?.toLongOrNull() ?: -1L)
val timeDifference = (Date.now().toLong() - nowDate)
fun scrollVerticalBy(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) { fun scrollVerticalBy(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
scrollAllVerticalBy(pixel, scrollBehavior) scrollAllVerticalBy(pixel, scrollBehavior)

View file

@ -74,18 +74,12 @@ class CalendarBody(val calendar: Calendar, view: HTMLElement) : ViewCollection<C
min = (min / 60 - 1) * 60 min = (min / 60 - 1) * 60
max = (max / 60 + 2) * 60 max = (max / 60 + 2) * 60
if (min == minTime && max == maxTime) return
minTime = min minTime = min
maxTime = max maxTime = max
min = calendarBodies.map { it.minTime }.min() ?: min min = calendarBodies.map { it.minTime }.min() ?: min
max = calendarBodies.map { it.maxTime }.max() ?: max max = calendarBodies.map { it.maxTime }.max() ?: max
calendarBodies.filter { it != this }.forEach {
it.updateRows()
}
while (isNotEmpty() && min > first().time) { while (isNotEmpty() && min > first().time) {
remove(first()) remove(first())
} }

View file

@ -8,7 +8,7 @@ import org.w3c.dom.HTMLElement
import org.w3c.dom.HTMLSpanElement import org.w3c.dom.HTMLSpanElement
import org.w3c.dom.set import org.w3c.dom.set
class CalendarRow(calendar: CalendarBody, view: HTMLElement) : ViewCollection<CalendarCell>(view) { class CalendarRow(val calendar: CalendarBody, view: HTMLElement) : ViewCollection<CalendarCell>(view) {
val day = calendar.day val day = calendar.day
val time = dataset["time"]?.toIntOrNull() ?: 0 val time = dataset["time"]?.toIntOrNull() ?: 0
@ -49,8 +49,6 @@ class CalendarRow(calendar: CalendarBody, view: HTMLElement) : ViewCollection<Ca
} }
row.html.appendChild(rowHeader) row.html.appendChild(rowHeader)
row.html
val rooms = RoomRepository.all() val rooms = RoomRepository.all()
for (room in rooms) { for (room in rooms) {

View file

@ -169,6 +169,10 @@
background-color: var(--table-header-color) !important; background-color: var(--table-header-color) !important;
} }
.calendar-cell[data-empty = "true"] {
display: none;
}
.calendar-tools { .calendar-tools {
position: absolute; position: absolute;
top: -5rem; top: -5rem;

View file

@ -133,6 +133,20 @@ object Configuration {
val time by c(ResoSpec.time) val time by c(ResoSpec.time)
} }
private object DatabaseSpec : ConfigSpec("database") {
val type by required<String>()
val url by required<String>()
val username by required<String>()
val password by required<String>()
}
object Database {
val type by c(DatabaseSpec.type)
val url by c(DatabaseSpec.url)
val username by c(DatabaseSpec.username)
val password by c(DatabaseSpec.password)
}
init { init {
var config = Config { var config = Config {
addSpec(ServerSpec) addSpec(ServerSpec)
@ -142,6 +156,7 @@ object Configuration {
addSpec(GeneralSpec) addSpec(GeneralSpec)
addSpec(TwitterSpec) addSpec(TwitterSpec)
addSpec(ResoSpec) addSpec(ResoSpec)
addSpec(DatabaseSpec)
}.from.toml.resource("portal.toml") }.from.toml.resource("portal.toml")
for (file in Files.list(Paths.get("."))) { for (file in Files.list(Paths.get("."))) {

View file

@ -26,14 +26,39 @@ object Connection {
) )
fun init() { fun init() {
val dbPath = Configuration.Path.databasePath.toString() val type = Configuration.Database.type
Database.connect("jdbc:sqlite:$dbPath", "org.sqlite.JDBC") val url = Configuration.Database.url
val username = Configuration.Database.username
val password = Configuration.Database.password
when (type) {
"mysql" -> {
Database.connect(
"jdbc:mysql://$url:3306/akplan?user=$username&password=$password&serverTimezone=UTC",
"com.mysql.cj.jdbc.Driver",
username,
password
)
}
"mariadb" -> {
Database.connect(
"jdbc:mariadb://$url:3306/akplan?user=$username&password=$password&serverTimezone=UTC",
"org.mariadb.jdbc.Driver",
username,
password
)
}
else -> {
val dbPath = Configuration.Path.databasePath.toString()
Database.connect("jdbc:sqlite:$dbPath", "org.sqlite.JDBC")
}
}
TransactionManager.manager.defaultIsolationLevel = TRANSACTION_SERIALIZABLE TransactionManager.manager.defaultIsolationLevel = TRANSACTION_SERIALIZABLE
try { try {
create() create()
} catch (e: ExposedSQLException) { } catch (e: ExposedSQLException) {
logger.error { "Cannot initialize the database!" } logger.error(e) { "Cannot initialize the database!" }
print("Do you want to recreate the database (you will lose all data)? [y/N]: ") print("Do you want to recreate the database (you will lose all data)? [y/N]: ")
val result = readLine() val result = readLine()

View file

@ -29,7 +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 leader = text("leader")
val length = integer("length") val length = integer("length")
val constraints = text("constraints") val constraints = text("constraints")
@ -49,9 +49,9 @@ object DbRoom : Table() {
val whiteboard = bool("whiteboard") val whiteboard = bool("whiteboard")
val blackboard = bool("blackboard") val blackboard = bool("blackboard")
val accessible = bool("accessible") val accessible = bool("accessible")
val pool = bool("pool").default(false) val pool = bool("pool")
val blocked = text("blocked").default("[]") val blocked = text("blocked")
val createdAt = long("createdAt") val createdAt = long("createdAt")
val updatedAt = long("updatedAt") val updatedAt = long("updatedAt")
@ -63,8 +63,8 @@ object DbSchedule : Table() {
val roomId = long("room_id").index() val roomId = long("room_id").index()
val day = integer("day").index() val day = integer("day").index()
val time = integer("time_slot") val time = integer("time_slot")
val lockRoom = bool("lock_room").default(false) val lockRoom = bool("lock_room")
val lockTime = bool("lock_time").default(false) val lockTime = bool("lock_time")
val createdAt = long("createdAt") val createdAt = long("createdAt")
val updatedAt = long("updatedAt") val updatedAt = long("updatedAt")

View file

@ -6,10 +6,12 @@ import de.kif.backend.prefix
import de.kif.backend.repository.* import de.kif.backend.repository.*
import de.kif.backend.route.api.error import de.kif.backend.route.api.error
import de.kif.backend.util.Backup import de.kif.backend.util.Backup
import de.kif.backend.util.PushService
import de.kif.backend.util.WikiImporter import de.kif.backend.util.WikiImporter
import de.kif.backend.view.respondMain import de.kif.backend.view.respondMain
import de.kif.common.RepositoryType import de.kif.common.RepositoryType
import de.kif.common.model.Permission import de.kif.common.model.Permission
import de.kif.common.model.Post
import io.ktor.application.call import io.ktor.application.call
import io.ktor.http.ContentType import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
@ -51,6 +53,10 @@ fun Route.account() {
+"Sicherung" +"Sicherung"
} }
a(href = "$prefix/account/reload", classes = "form-btn") {
+"Alle Geräte neu laden"
}
if (user.checkPermission(Permission.SCHEDULE)) { if (user.checkPermission(Permission.SCHEDULE)) {
a(href = "$prefix/account/import", classes = "form-btn") { a(href = "$prefix/account/import", classes = "form-btn") {
+"Aus Wiki importieren" +"Aus Wiki importieren"
@ -516,4 +522,8 @@ fun Route.account() {
call.error(HttpStatusCode.Unauthorized) call.error(HttpStatusCode.Unauthorized)
} }
} }
get("/account/reload") {
PushService.signature = Post.generateUrl()
call.respondRedirect("$prefix/account")
}
} }

View file

@ -175,7 +175,8 @@ fun Route.board() {
max, max,
rooms, rooms,
schedules, schedules,
reloadAfterFinish = true reloadAfterFinish = true,
hideEmptyRooms = true
) )
} }
div("board-twitter") { div("board-twitter") {

View file

@ -72,7 +72,8 @@ fun DIV.renderCalendar(
to: Int, to: Int,
rooms: List<Room>, rooms: List<Room>,
schedules: Map<Room, Map<Int, List<Schedule>>>, schedules: Map<Room, Map<Int, List<Schedule>>>,
reloadAfterFinish: Boolean = false reloadAfterFinish: Boolean = false,
hideEmptyRooms: Boolean = false
) { ) {
val gridLabelWidth = 60 val gridLabelWidth = 60
val minutesOfDay = to - from val minutesOfDay = to - from
@ -91,6 +92,7 @@ fun DIV.renderCalendar(
attributes["data-reference"] = Configuration.Schedule.referenceDate.time.toString() attributes["data-reference"] = Configuration.Schedule.referenceDate.time.toString()
attributes["data-now"] = now.timeInMillis.toString() attributes["data-now"] = now.timeInMillis.toString()
attributes["data-reload"] = reloadAfterFinish.toString() attributes["data-reload"] = reloadAfterFinish.toString()
attributes["data-hide-empty"] = hideEmptyRooms.toString()
div("calendar-table-box ${orientation.name.toLowerCase().replace("_", "-")}") { div("calendar-table-box ${orientation.name.toLowerCase().replace("_", "-")}") {
div("calendar-header") { div("calendar-header") {
@ -103,6 +105,7 @@ fun DIV.renderCalendar(
for (room in rooms) { for (room in rooms) {
div("calendar-cell") { div("calendar-cell") {
attributes["data-room"] = room.id.toString() attributes["data-room"] = room.id.toString()
attributes["data-empty"] = (hideEmptyRooms && room !in schedules).toString()
span { span {
+room.name +room.name
@ -147,6 +150,7 @@ fun DIV.renderCalendar(
div("calendar-cell") { div("calendar-cell") {
attributes["data-room"] = room.id.toString() attributes["data-room"] = room.id.toString()
attributes["data-blocked"] = blocked.toString() attributes["data-blocked"] = blocked.toString()
attributes["data-empty"] = (hideEmptyRooms && room !in schedules).toString()
title = room.name + " - " + timeString title = room.name + " - " + timeString

View file

@ -1,11 +1,11 @@
package de.kif.backend.route package de.kif.backend.route
import com.soywiz.klock.*
import com.soywiz.klock.locale.german
import de.kif.backend.Configuration import de.kif.backend.Configuration
import de.kif.backend.repository.RoomRepository import de.kif.backend.repository.RoomRepository
import de.kif.backend.repository.ScheduleRepository import de.kif.backend.repository.ScheduleRepository
import de.kif.backend.view.respondMain import de.kif.backend.view.respondMain
import de.kif.common.formatDate
import de.kif.common.formatDateWithoutYear
import de.kif.common.model.Room import de.kif.common.model.Room
import de.kif.common.model.Schedule import de.kif.common.model.Schedule
import io.ktor.routing.Route import io.ktor.routing.Route
@ -63,6 +63,8 @@ fun Route.wall() {
wallStart + 2 wallStart + 2
).map { genWallData(it) } ).map { genWallData(it) }
val rooms = RoomRepository.all()
var min = days.mapNotNull { it.min }.min() ?: 12 * 60 var min = days.mapNotNull { it.min }.min() ?: 12 * 60
val max = days.mapNotNull { it.max }.max() ?: 12 * 60 val max = days.mapNotNull { it.max }.max() ?: 12 * 60
@ -70,18 +72,15 @@ fun Route.wall() {
min = max min = max
} }
val refDate = DateTime(Configuration.Schedule.referenceDate.time) val refDate = Configuration.Schedule.referenceDate.time
respondMain(true, true) { respondMain(true, true) {
content { content {
div("wall") { div("wall") {
for (day in days) { for (day in days) {
val date = refDate + day.number.days val date = refDate + (day.number * 1000 * 60 * 60 * 24)
val dateString = DateFormat("EEEE, d. MMMM") val dateString = formatDateWithoutYear(date, Configuration.Schedule.offset)
.withLocale(KlockLocale.german)
.format(date)
div("wall-box") { div("wall-box") {
div("wall-name") { div("wall-name") {
@ -95,8 +94,9 @@ fun Route.wall() {
day.number, day.number,
min, min,
max, max,
day.schedules.keys.toList().sortedBy { it.id }, rooms,
day.schedules day.schedules,
hideEmptyRooms = true
) )
} }
} }

View file

@ -18,7 +18,7 @@ import kotlin.concurrent.thread
object PushService { object PushService {
internal var leastValidTimestamp = System.currentTimeMillis() internal var leastValidTimestamp = System.currentTimeMillis()
val signature = Post.generateUrl() var signature = Post.generateUrl()
private val messages: MutableList<Pair<Long, Message>> = mutableListOf() private val messages: MutableList<Pair<Long, Message>> = mutableListOf()

View file

@ -32,3 +32,9 @@ backup_interval = 3600000
[twitter] [twitter]
timeline = "" timeline = ""
[database]
type = "sqlite"
url = ""
username = ""
password = ""