From e3179c69aaea55cad49617baaf62770973d3b98c Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Thu, 8 May 2025 17:32:12 +0200 Subject: [PATCH] Refactor event group management and routing system --- .../SQL/src/de/steamwar/sql/EventFight.java | 6 + .../SQL/src/de/steamwar/sql/EventGroup.java | 49 ++++++-- .../src/de/steamwar/sql/EventRelation.java | 5 + WebsiteBackend/src/de/steamwar/data/Groups.kt | 89 -------------- WebsiteBackend/src/de/steamwar/routes/Data.kt | 4 - .../src/de/steamwar/routes/EventFights.kt | 32 ++--- .../src/de/steamwar/routes/EventGroups.kt | 94 +++++++++++++++ .../src/de/steamwar/routes/EventRelations.kt | 109 +++++++++++++++++ .../src/de/steamwar/routes/EventTeams.kt | 52 ++++++++ .../src/de/steamwar/routes/Events.kt | 114 ++++++++++-------- .../src/de/steamwar/routes/Routes.kt | 1 - 11 files changed, 385 insertions(+), 170 deletions(-) delete mode 100644 WebsiteBackend/src/de/steamwar/data/Groups.kt create mode 100644 WebsiteBackend/src/de/steamwar/routes/EventGroups.kt create mode 100644 WebsiteBackend/src/de/steamwar/routes/EventRelations.kt create mode 100644 WebsiteBackend/src/de/steamwar/routes/EventTeams.kt diff --git a/CommonCore/SQL/src/de/steamwar/sql/EventFight.java b/CommonCore/SQL/src/de/steamwar/sql/EventFight.java index e231fc70..d23e7411 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/EventFight.java +++ b/CommonCore/SQL/src/de/steamwar/sql/EventFight.java @@ -47,6 +47,7 @@ public class EventFight implements Comparable { private static final Statement create = table.insertFields(true, "eventID", "startTime", "spielmodus", "map", "teamBlue", "teamRed", "spectatePort"); private static final Statement update = table.update(Table.PRIMARY, "startTime", "spielModus", "map", "teamBlue", "teamRed", "spectatePort"); + private static final Statement setGroup = table.update(Table.PRIMARY, "GroupID"); private static final Statement delete = table.delete(Table.PRIMARY); @Getter @@ -152,6 +153,11 @@ public class EventFight implements Comparable { setFight.update(fight, fightID); } + public void setGroup(EventGroup group) { + setGroup.update(group.getId(), fightID); + this.groupId = group.getId(); + } + public boolean hasFinished() { return fight != 0 || ergebnis != 0; } diff --git a/CommonCore/SQL/src/de/steamwar/sql/EventGroup.java b/CommonCore/SQL/src/de/steamwar/sql/EventGroup.java index c5c00580..166e7eb1 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/EventGroup.java +++ b/CommonCore/SQL/src/de/steamwar/sql/EventGroup.java @@ -19,11 +19,7 @@ package de.steamwar.sql; -import de.steamwar.sql.internal.Field; -import de.steamwar.sql.internal.SelectStatement; -import de.steamwar.sql.internal.SqlTypeMapper; -import de.steamwar.sql.internal.Table; -import lombok.AllArgsConstructor; +import de.steamwar.sql.internal.*; import lombok.Getter; import lombok.Setter; @@ -32,7 +28,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -@AllArgsConstructor @Getter @Setter public class EventGroup { @@ -45,8 +40,17 @@ public class EventGroup { private static final SelectStatement get = table.select(Table.PRIMARY); private static final SelectStatement byEvent = new SelectStatement<>(table, "SELECT * FROM EventGroup WHERE EventID = ?"); + private static final Statement insert = table.insertFields(true, "EventID", "Name", "Type"); + private static final Statement update = table.update(Table.PRIMARY, "Name", "Type", "PointsPerWin", "PointsPerLoss", "PointsPerDraw"); + private static final Statement delete = table.delete(Table.PRIMARY); + public static List get(Event eventID) { - return byEvent.listSelect(eventID); + return byEvent.listSelect(eventID.getEventID()); + } + + public static EventGroup create(Event event, String name, EventGroupType type) { + int key = insert.insertGetKey(event.getEventID(), name, type); + return EventGroup.get(key).get(); } public static Optional get(int id) { @@ -56,7 +60,10 @@ public class EventGroup { @Field(keys = Table.PRIMARY) private final int id; - @Field + @Field(keys = "EVENT_NAME") + private int eventID; + + @Field(keys = "EVENT_NAME") private String name; @Field @@ -71,6 +78,16 @@ public class EventGroup { @Field private int pointsPerDraw; + public EventGroup(int id, int eventID, String name, EventGroupType type, int pointsPerWin, int pointsPerLoss, int pointsPerDraw) { + this.id = id; + this.eventID = eventID; + this.name = name; + this.type = type; + this.pointsPerWin = pointsPerWin; + this.pointsPerLoss = pointsPerLoss; + this.pointsPerDraw = pointsPerDraw; + } + private Map points; public List getFights() { @@ -88,8 +105,9 @@ public class EventGroup { public Map calculatePoints() { if (points == null) { Map teams = new HashMap<>(); + points = new HashMap<>(); - for(EventFight fight : getFights()) { + for (EventFight fight : getFights()) { int blueTeamAdd = 0; int redTeamAdd = 0; @@ -121,10 +139,23 @@ public class EventGroup { return points; } + public void update(String name, EventGroupType type, int pointsPerWin, int pointsPerLoss, int pointsPerDraw) { + update.update(id, name, type, pointsPerWin, pointsPerLoss, pointsPerDraw); + this.name = name; + this.type = type; + this.pointsPerWin = pointsPerWin; + this.pointsPerLoss = pointsPerLoss; + this.pointsPerDraw = pointsPerDraw; + } + public boolean needsTieBreak() { return calculatePoints().values().stream().sorted().limit(2).distinct().count() < 2; } + public void delete() { + delete.update(id); + } + public static enum EventGroupType { GROUP_STAGE, ELIMINATION_STAGE diff --git a/CommonCore/SQL/src/de/steamwar/sql/EventRelation.java b/CommonCore/SQL/src/de/steamwar/sql/EventRelation.java index 13b35f02..28c756ee 100644 --- a/CommonCore/SQL/src/de/steamwar/sql/EventRelation.java +++ b/CommonCore/SQL/src/de/steamwar/sql/EventRelation.java @@ -42,11 +42,16 @@ public class EventRelation { private static final SelectStatement get = new SelectStatement<>(table, "SELECT * FROM EventRelation WHERE FromType = ? AND FromId = ?"); private static final SelectStatement byId = new SelectStatement<>(table, "SELECT * FROM EventRelation WHERE id = ?"); + private static final SelectStatement byEvent = new SelectStatement<>(table, "SELECT ER.* FROM EventRelation ER JOIN EventFight EF ON EF.id = ER.fightId WHERE EF.EventID = ?"); private static final Statement insert = table.insertAll(true); private static final Statement update = table.update(Table.PRIMARY, "fromType", "fromId", "fromPlace"); private static final Statement updateTeam = table.update(Table.PRIMARY, "fightTeam"); private static final Statement delete = table.delete(Table.PRIMARY); + public static List get(Event event) { + return byId.listSelect(event.getEventID()); + } + public static EventRelation get(int id) { return byId.select(id); } diff --git a/WebsiteBackend/src/de/steamwar/data/Groups.kt b/WebsiteBackend/src/de/steamwar/data/Groups.kt deleted file mode 100644 index 2ecff054..00000000 --- a/WebsiteBackend/src/de/steamwar/data/Groups.kt +++ /dev/null @@ -1,89 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2024 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 . - */ - -package de.steamwar.data - -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.Serializable -import kotlinx.serialization.cbor.Cbor -import kotlinx.serialization.decodeFromByteArray -import kotlinx.serialization.encodeToByteArray - -@Serializable -data class GroupsData(val groups: MutableList) - -@Serializable -data class GroupData(val name: String, val fights: MutableList) - -@OptIn(ExperimentalSerializationApi::class) -class Groups { - companion object { - private var groups: GroupsData = if (kGroupsFile.exists()) { - Cbor.decodeFromByteArray(kGroupsFile.readBytes()) - } else { - if (!kGroupsFile.parentFile.exists()) { - kGroupsFile.parentFile.mkdirs() - } - kGroupsFile.createNewFile() - kGroupsFile.writeBytes(Cbor.encodeToByteArray(GroupsData(mutableListOf()))) - - GroupsData(mutableListOf()) - } - - fun getGroup(name: String): GroupData? { - return groups.groups.find { it.name == name } - } - - fun getGroup(fight: Int): GroupData? { - return groups.groups.find { it.fights.contains(fight) } - } - - fun getOrCreateGroup(name: String): GroupData { - val group = getGroup(name) - if (group != null) { - return group - } - val newGroup = GroupData(name, mutableListOf()) - groups.groups.add(newGroup) - return newGroup - } - - fun resetGroup(fight: Int, save: Boolean = false) { - val oldGroup = getGroup(fight) - oldGroup?.fights?.remove(fight) - if(oldGroup?.fights?.isEmpty() == true) { - groups.groups.remove(oldGroup) - } - if(save) { - kGroupsFile.writeBytes(Cbor.encodeToByteArray(groups)) - } - } - - fun setGroup(fight: Int, group: String) { - resetGroup(fight) - val newGroup = getOrCreateGroup(group) - newGroup.fights.add(fight) - kGroupsFile.writeBytes(Cbor.encodeToByteArray(groups)) - } - - fun getAllGroups(): List { - return groups.groups.map { it.name } - } - } -} \ No newline at end of file diff --git a/WebsiteBackend/src/de/steamwar/routes/Data.kt b/WebsiteBackend/src/de/steamwar/routes/Data.kt index 0a2dd3ae..6af82bfe 100644 --- a/WebsiteBackend/src/de/steamwar/routes/Data.kt +++ b/WebsiteBackend/src/de/steamwar/routes/Data.kt @@ -20,7 +20,6 @@ package de.steamwar.routes import de.steamwar.ResponseError -import de.steamwar.data.Groups import de.steamwar.data.getCachedSkin import de.steamwar.plugins.SWAuthPrincipal import de.steamwar.plugins.SWPermissionCheck @@ -102,9 +101,6 @@ fun Route.configureDataRoutes() { } call.respond(YamlConfiguration.loadConfiguration(file).getStringList("Server.Maps")) } - get("/groups") { - call.respond(Groups.getAllGroups()) - } } get("/server") { try { diff --git a/WebsiteBackend/src/de/steamwar/routes/EventFights.kt b/WebsiteBackend/src/de/steamwar/routes/EventFights.kt index e95ea89d..1f0e63c5 100644 --- a/WebsiteBackend/src/de/steamwar/routes/EventFights.kt +++ b/WebsiteBackend/src/de/steamwar/routes/EventFights.kt @@ -20,12 +20,7 @@ package de.steamwar.routes import de.steamwar.ResponseError -import de.steamwar.data.Groups -import de.steamwar.plugins.SWPermissionCheck -import de.steamwar.sql.EventFight -import de.steamwar.sql.SteamwarUser -import de.steamwar.sql.Team -import de.steamwar.sql.UserPerm +import de.steamwar.sql.* import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.request.* @@ -45,7 +40,7 @@ data class ResponseEventFight( val start: Long, val ergebnis: Int, val spectatePort: Int?, - val group: String? + val group: ResponseGroups? ) { constructor(eventFight: EventFight) : this( eventFight.fightID, @@ -56,7 +51,7 @@ data class ResponseEventFight( eventFight.startTime.time, eventFight.ergebnis, eventFight.spectatePort, - Groups.getGroup(eventFight.fightID)?.name + eventFight.group.orElse(null)?.let { ResponseGroups(it) } ) } @@ -72,7 +67,7 @@ data class UpdateEventFight( val start: Long? = null, val spielmodus: String? = null, val map: String? = null, - val group: String? = null, + val group: Int? = null, val spectatePort: Int? = null ) @@ -85,14 +80,14 @@ data class CreateEventFight( val redTeam: Int, val start: Long, val spectatePort: Int? = null, - val group: String? = null + val group: Int? = null ) fun Route.configureEventFightRoutes() { route("/fights") { - install(SWPermissionCheck) { - allowMethod(HttpMethod.Get) - permission = UserPerm.MODERATION + get { + val event = call.receiveEvent() ?: return@get + call.respond(EventFight.getEvent(event.eventID).map { ResponseEventFight(it) }) } post { val fight = call.receiveNullable() @@ -100,6 +95,7 @@ fun Route.configureEventFightRoutes() { call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid body")) return@post } + val eventFight = EventFight.create( fight.event, Timestamp.from(Instant.ofEpochMilli(fight.start)), @@ -110,9 +106,7 @@ fun Route.configureEventFightRoutes() { fight.spectatePort ) if (fight.group != null) { - if (fight.group != "null") { - Groups.setGroup(eventFight.fightID, fight.group) - } + eventFight.groupId = fight.group } call.respond(HttpStatusCode.Created, ResponseEventFight(eventFight)) } @@ -133,10 +127,10 @@ fun Route.configureEventFightRoutes() { val spectatePort = updateFight.spectatePort ?: fight.spectatePort if (updateFight.group != null) { - if (updateFight.group == "null") { - Groups.resetGroup(fight.fightID, true) + if (updateFight.group == -1) { + fight.groupId = null } else { - Groups.setGroup(fight.fightID, updateFight.group) + fight.groupId = updateFight.group } } fight.update(start, spielmodus, map, teamBlue, teamRed, spectatePort) diff --git a/WebsiteBackend/src/de/steamwar/routes/EventGroups.kt b/WebsiteBackend/src/de/steamwar/routes/EventGroups.kt new file mode 100644 index 00000000..38260e74 --- /dev/null +++ b/WebsiteBackend/src/de/steamwar/routes/EventGroups.kt @@ -0,0 +1,94 @@ +/* + * 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 . + */ + +package de.steamwar.routes + +import de.steamwar.sql.EventGroup +import de.steamwar.sql.EventGroup.EventGroupType +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 + +@Serializable +data class CreateEventGroup(val name: String, val type: EventGroupType) + +@Serializable +data class UpdateEventGroup( + val name: String? = null, + val type: EventGroupType? = null, + val pointsPerWin: Int? = null, + val pointsPerLoss: Int? = null, + val pointsPerDraw: Int? = null, +) + +fun Route.configureEventGroups() { + route("/groups") { + get { + val event = call.receiveEvent() ?: return@get + call.respond(EventGroup.get(event).map { ResponseGroups(it) }) + } + post { + val event = call.receiveEvent() ?: return@post + val createEventGroup = call.receive() + val group = EventGroup.create(event, createEventGroup.name, createEventGroup.type) + call.respond(ResponseGroups(group)) + } + route("/{group}") { + get { + val group = call.receiveEventGroup() ?: return@get + call.respond(ResponseGroups(group)) + } + put { + val group = call.receiveEventGroup() ?: return@put + val updateEventGroup = call.receive() + val name = updateEventGroup.name ?: group.name + val type = updateEventGroup.type ?: group.type + val pointsPerWin = updateEventGroup.pointsPerWin ?: group.pointsPerWin + val pointsPerLoss = updateEventGroup.pointsPerLoss ?: group.pointsPerLoss + val pointsPerDraw = updateEventGroup.pointsPerDraw ?: group.pointsPerDraw + group.update(name, type, pointsPerWin, pointsPerLoss, pointsPerDraw) + call.respond(ResponseGroups(EventGroup.get(group.id).orElse(null) ?: return@put)) + } + delete { + val group = call.receiveEventGroup() ?: return@delete + group.delete() + call.respond(HttpStatusCode.NoContent) + } + } + } +} + +suspend fun ApplicationCall.receiveEventGroup(): EventGroup? { + val groupId = parameters["group"]?.toIntOrNull() + if (groupId == null) { + respond(HttpStatusCode.BadRequest) + return null + } + + val group = EventGroup.get(groupId).orElse(null) + if (group == null) { + respond(HttpStatusCode.NotFound) + return null + } + + return group +} \ No newline at end of file diff --git a/WebsiteBackend/src/de/steamwar/routes/EventRelations.kt b/WebsiteBackend/src/de/steamwar/routes/EventRelations.kt new file mode 100644 index 00000000..c8af5866 --- /dev/null +++ b/WebsiteBackend/src/de/steamwar/routes/EventRelations.kt @@ -0,0 +1,109 @@ +/* + * 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 . + */ + +package de.steamwar.routes + +import de.steamwar.sql.EventFight +import de.steamwar.sql.EventGroup +import de.steamwar.sql.EventRelation +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 + +@Serializable +data class CreateEventRelation(val fightId: Int, val team: EventRelation.FightTeam, val fromType: EventRelation.FromType, val fromId: Int, val fromPlace: Int) + +@Serializable +data class UpdateEventRelation(val team: EventRelation.FightTeam? = null, val from: UpdateFromRelation? = null) + +@Serializable +data class UpdateFromRelation(val fromType: EventRelation.FromType, val fromId: Int, val fromPlace: Int) + +fun Route.configureEventRelations() { + route("/relations") { + get { + val event = call.receiveEvent() ?: return@get + + call.respond(EventRelation.get(event).map { ResponseRelation(it) }) + } + post { + val create = call.receive() + + val fight = EventFight.get(create.fightId) ?: return@post call.respond(HttpStatusCode.NotFound) + + when (create.fromType) { + EventRelation.FromType.FIGHT -> EventFight.get(create.fromId) ?: return@post call.respond(HttpStatusCode.BadRequest) + EventRelation.FromType.GROUP -> EventGroup.get(create.fromId) ?: return@post call.respond(HttpStatusCode.BadRequest) + } + + val relation = EventRelation.create(fight, create.team, create.fromType, create.fromId, create.fromPlace) + + call.respond(ResponseRelation(relation)) + } + route("/{relation}") { + get { + val relation = call.receiveEventRelation() ?: return@get + call.respond(ResponseRelation(relation)) + } + put { + val relation = call.receiveEventRelation() ?: return@put + val update = call.receive() + + update.from?.let { + when(it.fromType) { + EventRelation.FromType.FIGHT -> relation.setFromFight(EventFight.get(it.fromId) ?: return@put call.respond(HttpStatusCode.BadRequest), + it.fromPlace + ) + EventRelation.FromType.GROUP -> relation.setFromGroup(EventGroup.get(it.fromId).orElse(null) ?: return@put call.respond(HttpStatusCode.BadRequest), + it.fromPlace + ) + } + } + + update.team?.let { relation.setUpdateTeam(it) } + + call.respond(ResponseRelation(EventRelation.get(relation.id))) + } + delete { + val relation = call.receiveEventRelation() ?: return@delete + relation.delete() + call.respond(HttpStatusCode.NoContent) + } + } + } +} + +suspend fun ApplicationCall.receiveEventRelation(): EventRelation? { + val relationId = parameters["relation"]?.toIntOrNull() + if (relationId == null) { + respond(HttpStatusCode.BadRequest) + return null + } + + val relation = EventRelation.get(relationId) + if (relation == null) { + respond(HttpStatusCode.NotFound) + return null + } + + return relation +} \ No newline at end of file diff --git a/WebsiteBackend/src/de/steamwar/routes/EventTeams.kt b/WebsiteBackend/src/de/steamwar/routes/EventTeams.kt new file mode 100644 index 00000000..caacc0a9 --- /dev/null +++ b/WebsiteBackend/src/de/steamwar/routes/EventTeams.kt @@ -0,0 +1,52 @@ +/* + * 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 . + */ + +package de.steamwar.routes + +import de.steamwar.sql.TeamTeilnahme +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.request.* +import io.ktor.server.response.* +import io.ktor.server.routing.* + +fun Route.configureEventTeams() { + route("/teams") { + get { + val event = call.receiveEvent() ?: return@get + call.respond(TeamTeilnahme.getTeams(event.eventID).map { ResponseTeam(it) }) + } + put { + val event = call.receiveEvent() ?: return@put + val team = call.receive>() + team.forEach { + TeamTeilnahme.teilnehmen(it, event.eventID) + } + call.respond(HttpStatusCode.NoContent) + } + delete { + val event = call.receiveEvent() ?: return@delete + val team = call.receive>() + team.forEach { + TeamTeilnahme.notTeilnehmen(it, event.eventID) + } + call.respond(HttpStatusCode.NoContent) + } + } +} \ No newline at end of file diff --git a/WebsiteBackend/src/de/steamwar/routes/Events.kt b/WebsiteBackend/src/de/steamwar/routes/Events.kt index d40cdd3b..1ef7ba83 100644 --- a/WebsiteBackend/src/de/steamwar/routes/Events.kt +++ b/WebsiteBackend/src/de/steamwar/routes/Events.kt @@ -20,9 +20,10 @@ package de.steamwar.routes import de.steamwar.ResponseError -import de.steamwar.data.Groups import de.steamwar.plugins.SWPermissionCheck import de.steamwar.sql.* +import de.steamwar.sql.EventGroup.EventGroupType +import de.steamwar.sql.EventRelation.FromType import io.ktor.http.* import io.ktor.server.application.* import io.ktor.server.request.* @@ -39,6 +40,45 @@ data class ShortEvent(val id: Int, val name: String, val start: Long, val end: L constructor(event: Event) : this(event.eventID, event.eventName, event.start.time, event.end.time) } +@Serializable +data class ResponseGroups( + val id: Int, + val name: String, + val pointsPerWin: Int, + val pointsPerLoss: Int, + val pointsPerDraw: Int, + val type: EventGroupType, + val points: Map +) { + constructor(group: EventGroup, short: Boolean = false) : this( + group.id, + group.name, + group.pointsPerWin, + group.pointsPerLoss, + group.pointsPerDraw, + group.type, + if (short) mapOf() else group.calculatePoints().mapKeys { it.key.teamId }) +} + +@Serializable +data class ResponseRelation( + val id: Int, + val fight: ResponseEventFight, + val type: FromType, + val fromFight: ResponseEventFight? = null, + val fromGroup: ResponseGroups? = null, + val fromPlace: Int +) { + constructor(relation: EventRelation) : this( + relation.id, + ResponseEventFight(relation.fight), + relation.fromType, + relation.fromFight.map { ResponseEventFight(it) }.orElse(null), + relation.fromGroup.map { ResponseGroups(it) }.orElse(null), + relation.fromPlace + ) +} + @Serializable data class ResponseEvent( val id: Int, @@ -49,7 +89,6 @@ data class ResponseEvent( val maxTeamMembers: Int, val schemType: String?, val publicSchemsOnly: Boolean, - val referees: List, ) { constructor(event: Event) : this( event.eventID, @@ -60,7 +99,6 @@ data class ResponseEvent( event.maximumTeamMembers, event.schematicType?.toDB(), event.publicSchemsOnly(), - Referee.get(event.eventID).map { ResponseUser(SteamwarUser.get(it)) } ) } @@ -68,8 +106,20 @@ data class ResponseEvent( data class ExtendedResponseEvent( val event: ResponseEvent, val teams: List, - val fights: List -) + val groups: List, + val fights: List, + val referees: List, + val relations: List +) { + constructor(event: Event) : this( + ResponseEvent(event), + TeamTeilnahme.getTeams(event.eventID).map { ResponseTeam(it) }, + EventGroup.get(event).map { ResponseGroups(it) }, + EventFight.getEvent(event.eventID).map { ResponseEventFight(it) }, + Referee.get(event.eventID).map { ResponseUser(SteamwarUser.get(it)) }, + EventRelation.get(event).map { ResponseRelation(it) } + ) +} @Serializable data class CreateEvent(val name: String, val start: Long, val end: Long) @@ -111,49 +161,11 @@ fun Route.configureEventsRoute() { } route("/{id}") { get { - val id = call.parameters["id"]?.toIntOrNull() - if (id == null) { - call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid ID")) - return@get - } - val event = Event.get(id) - if (event == null) { - call.respond(HttpStatusCode.NotFound, ResponseError("Event not found")) - return@get - } + val event = call.receiveEvent() ?: return@get call.respond( - ExtendedResponseEvent( - ResponseEvent(event), - TeamTeilnahme.getTeams(event.eventID).map { ResponseTeam(it) }, - EventFight.getEvent(event.eventID).map { ResponseEventFight(it) }) + ExtendedResponseEvent(event) ) } - get("/teams") { - val id = call.parameters["id"]?.toIntOrNull() - if (id == null) { - call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid ID")) - return@get - } - val event = Event.get(id) - if (event == null) { - call.respond(HttpStatusCode.NotFound, ResponseError("Event not found")) - return@get - } - call.respond(TeamTeilnahme.getTeams(event.eventID).map { ResponseTeam(it) }) - } - get("/fights") { - val id = call.parameters["id"]?.toIntOrNull() - if (id == null) { - call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid ID")) - return@get - } - val event = Event.get(id) - if (event == null) { - call.respond(HttpStatusCode.NotFound, ResponseError("Event not found")) - return@get - } - call.respond(EventFight.getEvent(event.eventID).map { ResponseEventFight(it) }) - } get("/csv") { val event = call.receiveEvent() ?: return@get @@ -164,7 +176,7 @@ fun Route.configureEventsRoute() { csv.appendLine() val blue = Team.get(it.teamBlue) val red = Team.get(it.teamRed) - val winner = when(it.ergebnis) { + val winner = when (it.ergebnis) { 1 -> blue.teamName 2 -> red.teamName 3 -> "Tie" @@ -176,7 +188,7 @@ fun Route.configureEventsRoute() { Team.get(it.teamBlue).teamName, Team.get(it.teamRed).teamName, winner, - Groups.getGroup(it.fightID)?.name ?: "Ungrouped" + it.group.map { it.name }.orElse("Ungrouped") ).joinToString(",") ) } @@ -200,7 +212,9 @@ fun Route.configureEventsRoute() { val end = updateEvent.end?.let { Timestamp.from(Instant.ofEpochMilli(it)) } ?: event.end val maxTeamMembers = updateEvent.maxTeamMembers ?: event.maximumTeamMembers - val schemType = if (updateEvent.schemType == "null") null else updateEvent.schemType?.let { SchematicType.fromDB(it) } ?: event.schematicType + val schemType = + if (updateEvent.schemType == "null") null else updateEvent.schemType?.let { SchematicType.fromDB(it) } + ?: event.schematicType val publicSchemsOnly = updateEvent.publicSchemsOnly ?: event.publicSchemsOnly() if (updateEvent.addReferee != null) { @@ -231,6 +245,10 @@ fun Route.configureEventsRoute() { event.delete() call.respond(HttpStatusCode.NoContent) } + configureEventFightRoutes() + configureEventTeams() + configureEventGroups() + configureEventRelations() } } } diff --git a/WebsiteBackend/src/de/steamwar/routes/Routes.kt b/WebsiteBackend/src/de/steamwar/routes/Routes.kt index 388f8055..f4e883ee 100644 --- a/WebsiteBackend/src/de/steamwar/routes/Routes.kt +++ b/WebsiteBackend/src/de/steamwar/routes/Routes.kt @@ -28,7 +28,6 @@ fun Application.configureRoutes() { authenticate("sw-auth", optional = true) { configureEventsRoute() configureDataRoutes() - configureEventFightRoutes() configureUserPerms() configureStats() configurePage()