Compare commits
2 commits
f02124cbe8
...
664f9c1777
Author | SHA1 | Date | |
---|---|---|---|
664f9c1777 | |||
e8f816e7ec |
|
@ -90,6 +90,7 @@ kotlin {
|
|||
implementation "io.ktor:ktor-client-apache:$ktor_version"
|
||||
|
||||
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.mindrot:jbcrypt:0.4'
|
||||
|
|
|
@ -18,3 +18,9 @@ wiki_url = "https://wiki.kif.rocks/w/index.php?title=KIF470:Arbeitskreise&action
|
|||
|
||||
[twitter]
|
||||
timeline = "https://twitter.com/kiforbiter?ref_src=twsrc%5Etfw"
|
||||
|
||||
[database]
|
||||
type = "sqlite"
|
||||
url = ""
|
||||
username = ""
|
||||
password = ""
|
||||
|
|
|
@ -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 (s in against) {
|
||||
if (
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
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.calendar.initCalendar
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,11 +26,12 @@ class Calendar(calendar: HTMLElement) : View(calendar) {
|
|||
|
||||
private val htmlBody = document.body ?: createHtmlView()
|
||||
|
||||
val day = (calendarTable.dataset["day"]?.toIntOrNull() ?: -1).also { println(it) }
|
||||
val reloadOnFinish = (calendarTable.dataset["reload"]?.toBoolean() ?: false).also { println(it) }
|
||||
val referenceDate = (calendarTable.dataset["reference"]?.toLongOrNull() ?: -1L).also { println(it) }
|
||||
val nowDate = (calendarTable.dataset["now"]?.toLongOrNull() ?: -1L).also { println(it) }
|
||||
val timeDifference = (Date.now().toLong() - nowDate).also { println(it) }
|
||||
val day = (calendarTable.dataset["day"]?.toIntOrNull() ?: -1)
|
||||
val reloadOnFinish = (calendarTable.dataset["reload"]?.toBoolean() ?: false)
|
||||
val hideEmpty = (calendarTable.dataset["hide-empty"]?.toBoolean() ?: false)
|
||||
val referenceDate = (calendarTable.dataset["reference"]?.toLongOrNull() ?: -1L)
|
||||
val nowDate = (calendarTable.dataset["now"]?.toLongOrNull() ?: -1L)
|
||||
val timeDifference = (Date.now().toLong() - nowDate)
|
||||
|
||||
fun scrollVerticalBy(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
|
||||
scrollAllVerticalBy(pixel, scrollBehavior)
|
||||
|
|
|
@ -74,18 +74,12 @@ class CalendarBody(val calendar: Calendar, view: HTMLElement) : ViewCollection<C
|
|||
min = (min / 60 - 1) * 60
|
||||
max = (max / 60 + 2) * 60
|
||||
|
||||
if (min == minTime && max == maxTime) return
|
||||
|
||||
minTime = min
|
||||
maxTime = max
|
||||
|
||||
min = calendarBodies.map { it.minTime }.min() ?: min
|
||||
max = calendarBodies.map { it.maxTime }.max() ?: max
|
||||
|
||||
calendarBodies.filter { it != this }.forEach {
|
||||
it.updateRows()
|
||||
}
|
||||
|
||||
while (isNotEmpty() && min > first().time) {
|
||||
remove(first())
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import org.w3c.dom.HTMLElement
|
|||
import org.w3c.dom.HTMLSpanElement
|
||||
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 time = dataset["time"]?.toIntOrNull() ?: 0
|
||||
|
@ -49,8 +49,6 @@ class CalendarRow(calendar: CalendarBody, view: HTMLElement) : ViewCollection<Ca
|
|||
}
|
||||
row.html.appendChild(rowHeader)
|
||||
|
||||
row.html
|
||||
|
||||
val rooms = RoomRepository.all()
|
||||
|
||||
for (room in rooms) {
|
||||
|
|
|
@ -169,6 +169,10 @@
|
|||
background-color: var(--table-header-color) !important;
|
||||
}
|
||||
|
||||
.calendar-cell[data-empty = "true"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.calendar-tools {
|
||||
position: absolute;
|
||||
top: -5rem;
|
||||
|
|
|
@ -133,6 +133,20 @@ object Configuration {
|
|||
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 {
|
||||
var config = Config {
|
||||
addSpec(ServerSpec)
|
||||
|
@ -142,6 +156,7 @@ object Configuration {
|
|||
addSpec(GeneralSpec)
|
||||
addSpec(TwitterSpec)
|
||||
addSpec(ResoSpec)
|
||||
addSpec(DatabaseSpec)
|
||||
}.from.toml.resource("portal.toml")
|
||||
|
||||
for (file in Files.list(Paths.get("."))) {
|
||||
|
|
|
@ -26,14 +26,39 @@ object Connection {
|
|||
)
|
||||
|
||||
fun init() {
|
||||
val type = Configuration.Database.type
|
||||
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
|
||||
|
||||
try {
|
||||
create()
|
||||
} 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]: ")
|
||||
val result = readLine()
|
||||
|
|
|
@ -29,7 +29,7 @@ object DbWorkGroup : Table() {
|
|||
val accessible = bool("accessible")
|
||||
|
||||
val language = enumeration("language", Language::class)
|
||||
val leader = text("leader").default("[]")
|
||||
val leader = text("leader")
|
||||
|
||||
val length = integer("length")
|
||||
val constraints = text("constraints")
|
||||
|
@ -49,9 +49,9 @@ object DbRoom : Table() {
|
|||
val whiteboard = bool("whiteboard")
|
||||
val blackboard = bool("blackboard")
|
||||
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 updatedAt = long("updatedAt")
|
||||
|
@ -63,8 +63,8 @@ object DbSchedule : Table() {
|
|||
val roomId = long("room_id").index()
|
||||
val day = integer("day").index()
|
||||
val time = integer("time_slot")
|
||||
val lockRoom = bool("lock_room").default(false)
|
||||
val lockTime = bool("lock_time").default(false)
|
||||
val lockRoom = bool("lock_room")
|
||||
val lockTime = bool("lock_time")
|
||||
|
||||
val createdAt = long("createdAt")
|
||||
val updatedAt = long("updatedAt")
|
||||
|
|
|
@ -6,10 +6,12 @@ import de.kif.backend.prefix
|
|||
import de.kif.backend.repository.*
|
||||
import de.kif.backend.route.api.error
|
||||
import de.kif.backend.util.Backup
|
||||
import de.kif.backend.util.PushService
|
||||
import de.kif.backend.util.WikiImporter
|
||||
import de.kif.backend.view.respondMain
|
||||
import de.kif.common.RepositoryType
|
||||
import de.kif.common.model.Permission
|
||||
import de.kif.common.model.Post
|
||||
import io.ktor.application.call
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.http.HttpStatusCode
|
||||
|
@ -51,6 +53,10 @@ fun Route.account() {
|
|||
+"Sicherung"
|
||||
}
|
||||
|
||||
a(href = "$prefix/account/reload", classes = "form-btn") {
|
||||
+"Alle Geräte neu laden"
|
||||
}
|
||||
|
||||
if (user.checkPermission(Permission.SCHEDULE)) {
|
||||
a(href = "$prefix/account/import", classes = "form-btn") {
|
||||
+"Aus Wiki importieren"
|
||||
|
@ -516,4 +522,8 @@ fun Route.account() {
|
|||
call.error(HttpStatusCode.Unauthorized)
|
||||
}
|
||||
}
|
||||
get("/account/reload") {
|
||||
PushService.signature = Post.generateUrl()
|
||||
call.respondRedirect("$prefix/account")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -175,7 +175,8 @@ fun Route.board() {
|
|||
max,
|
||||
rooms,
|
||||
schedules,
|
||||
reloadAfterFinish = true
|
||||
reloadAfterFinish = true,
|
||||
hideEmptyRooms = true
|
||||
)
|
||||
}
|
||||
div("board-twitter") {
|
||||
|
|
|
@ -72,7 +72,8 @@ fun DIV.renderCalendar(
|
|||
to: Int,
|
||||
rooms: List<Room>,
|
||||
schedules: Map<Room, Map<Int, List<Schedule>>>,
|
||||
reloadAfterFinish: Boolean = false
|
||||
reloadAfterFinish: Boolean = false,
|
||||
hideEmptyRooms: Boolean = false
|
||||
) {
|
||||
val gridLabelWidth = 60
|
||||
val minutesOfDay = to - from
|
||||
|
@ -91,6 +92,7 @@ fun DIV.renderCalendar(
|
|||
attributes["data-reference"] = Configuration.Schedule.referenceDate.time.toString()
|
||||
attributes["data-now"] = now.timeInMillis.toString()
|
||||
attributes["data-reload"] = reloadAfterFinish.toString()
|
||||
attributes["data-hide-empty"] = hideEmptyRooms.toString()
|
||||
|
||||
div("calendar-table-box ${orientation.name.toLowerCase().replace("_", "-")}") {
|
||||
div("calendar-header") {
|
||||
|
@ -103,6 +105,7 @@ fun DIV.renderCalendar(
|
|||
for (room in rooms) {
|
||||
div("calendar-cell") {
|
||||
attributes["data-room"] = room.id.toString()
|
||||
attributes["data-empty"] = (hideEmptyRooms && room !in schedules).toString()
|
||||
|
||||
span {
|
||||
+room.name
|
||||
|
@ -147,6 +150,7 @@ fun DIV.renderCalendar(
|
|||
div("calendar-cell") {
|
||||
attributes["data-room"] = room.id.toString()
|
||||
attributes["data-blocked"] = blocked.toString()
|
||||
attributes["data-empty"] = (hideEmptyRooms && room !in schedules).toString()
|
||||
|
||||
title = room.name + " - " + timeString
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package de.kif.backend.route
|
||||
|
||||
import com.soywiz.klock.*
|
||||
import com.soywiz.klock.locale.german
|
||||
import de.kif.backend.Configuration
|
||||
import de.kif.backend.repository.RoomRepository
|
||||
import de.kif.backend.repository.ScheduleRepository
|
||||
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.Schedule
|
||||
import io.ktor.routing.Route
|
||||
|
@ -63,6 +63,8 @@ fun Route.wall() {
|
|||
wallStart + 2
|
||||
).map { genWallData(it) }
|
||||
|
||||
val rooms = RoomRepository.all()
|
||||
|
||||
var min = days.mapNotNull { it.min }.min() ?: 12 * 60
|
||||
val max = days.mapNotNull { it.max }.max() ?: 12 * 60
|
||||
|
||||
|
@ -70,18 +72,15 @@ fun Route.wall() {
|
|||
min = max
|
||||
}
|
||||
|
||||
val refDate = DateTime(Configuration.Schedule.referenceDate.time)
|
||||
val refDate = Configuration.Schedule.referenceDate.time
|
||||
|
||||
respondMain(true, true) {
|
||||
content {
|
||||
div("wall") {
|
||||
for (day in days) {
|
||||
|
||||
val date = refDate + day.number.days
|
||||
val dateString = DateFormat("EEEE, d. MMMM")
|
||||
.withLocale(KlockLocale.german)
|
||||
.format(date)
|
||||
|
||||
val date = refDate + (day.number * 1000 * 60 * 60 * 24)
|
||||
val dateString = formatDateWithoutYear(date, Configuration.Schedule.offset)
|
||||
|
||||
div("wall-box") {
|
||||
div("wall-name") {
|
||||
|
@ -95,8 +94,9 @@ fun Route.wall() {
|
|||
day.number,
|
||||
min,
|
||||
max,
|
||||
day.schedules.keys.toList().sortedBy { it.id },
|
||||
day.schedules
|
||||
rooms,
|
||||
day.schedules,
|
||||
hideEmptyRooms = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import kotlin.concurrent.thread
|
|||
object PushService {
|
||||
|
||||
internal var leastValidTimestamp = System.currentTimeMillis()
|
||||
val signature = Post.generateUrl()
|
||||
var signature = Post.generateUrl()
|
||||
|
||||
private val messages: MutableList<Pair<Long, Message>> = mutableListOf()
|
||||
|
||||
|
|
|
@ -32,3 +32,9 @@ backup_interval = 3600000
|
|||
|
||||
[twitter]
|
||||
timeline = ""
|
||||
|
||||
[database]
|
||||
type = "sqlite"
|
||||
url = ""
|
||||
username = ""
|
||||
password = ""
|
||||
|
|
Loading…
Reference in a new issue