Files
SteamWar/WebsiteBackend/src/de/steamwar/routes/EventFights.kt
T
2025-10-23 17:56:43 +02:00

171 lines
5.6 KiB
Kotlin

/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.routes
import de.steamwar.ResponseError
import de.steamwar.sql.*
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import kotlinx.serialization.Serializable
import java.sql.Timestamp
import java.time.Instant
@Serializable
data class ResponseEventFight(
val id: Int,
val spielmodus: String,
val map: String,
val blueTeam: ResponseTeam,
val redTeam: ResponseTeam,
val start: Long,
val ergebnis: Int,
val spectatePort: Int?,
val group: ResponseGroups?,
val hasFinished: Boolean
) {
constructor(eventFight: EventFight) : this(
eventFight.fightID,
eventFight.spielmodus,
eventFight.map,
ResponseTeam(Team.get(eventFight.teamBlue)),
ResponseTeam(Team.get(eventFight.teamRed)),
eventFight.startTime.time,
eventFight.ergebnis,
eventFight.spectatePort,
eventFight.group.orElse(null)?.let { ResponseGroups(it, short = true) },
eventFight.hasFinished()
)
}
@Serializable
data class ResponseTeam(val id: Int, val name: String, val kuerzel: String, val color: String) {
constructor(team: Team) : this(team.teamId, team.teamName, team.teamKuerzel, team.teamColor)
}
@Serializable
data class UpdateEventFight(
val blueTeam: Int? = null,
val redTeam: Int? = null,
val start: Long? = null,
val spielmodus: String? = null,
val map: String? = null,
val group: Int? = null,
val spectatePort: Int? = null,
val ergebnis: Int? = null,
)
@Serializable
data class CreateEventFight(
val spielmodus: String,
val map: String,
val blueTeam: Int,
val redTeam: Int,
val start: Long,
val spectatePort: Int? = null,
val group: Int? = null
)
fun Route.configureEventFightRoutes() {
route("/fights") {
get {
val event = call.receiveEvent() ?: return@get
call.respond(EventFight.getEvent(event.eventID).map { ResponseEventFight(it) })
}
post {
val event = call.receiveEvent() ?: return@post
val fight = call.receiveNullable<CreateEventFight>()
if (fight == null) {
call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid body"))
return@post
}
val eventFight = EventFight.create(
event.eventID,
Timestamp.from(Instant.ofEpochMilli(fight.start)),
fight.spielmodus,
fight.map,
fight.blueTeam,
fight.redTeam,
fight.spectatePort
)
if (fight.group != null) {
eventFight.setGroup(fight.group)
}
call.respond(HttpStatusCode.Created, ResponseEventFight(eventFight))
}
route("/{fight}") {
put {
val fight = call.receiveFight() ?: return@put
val updateFight = call.receiveNullable<UpdateEventFight>()
if (updateFight == null) {
call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid body"))
return@put
}
val teamBlue = updateFight.blueTeam ?: fight.teamBlue
val teamRed = updateFight.redTeam ?: fight.teamRed
val start = updateFight.start?.let { Timestamp.from(Instant.ofEpochMilli(it)) } ?: fight.startTime
val spielmodus = updateFight.spielmodus ?: fight.spielmodus
val map = updateFight.map ?: fight.map
val spectatePort = updateFight.spectatePort ?: fight.spectatePort
if (updateFight.group != null) {
if (updateFight.group == -1) {
fight.setGroup(null)
} else {
fight.setGroup(updateFight.group)
}
}
if (updateFight.ergebnis != null) {
fight.ergebnis = updateFight.ergebnis
}
fight.update(start, spielmodus, map, teamBlue, teamRed, spectatePort)
call.respond(HttpStatusCode.OK, ResponseEventFight(fight))
}
delete {
val fight = call.receiveFight() ?: return@delete
fight.delete()
call.respond(HttpStatusCode.OK)
}
}
}
}
suspend fun ApplicationCall.receiveFight(fieldName: String = "fight"): EventFight? {
val fightId = parameters[fieldName]?.toIntOrNull()
if (fightId == null) {
respond(HttpStatusCode.BadRequest, ResponseError("Invalid fight ID"))
return null
}
val fight = EventFight.get(fightId)
if (fight == null) {
respond(HttpStatusCode.NotFound, ResponseError("Fight not found"))
return null
}
return fight
}