Refactor event group management and routing system
All checks were successful
SteamWarCI Build successful

This commit is contained in:
2025-05-08 17:32:12 +02:00
parent c633694222
commit e3179c69aa
11 changed files with 385 additions and 170 deletions

View File

@@ -47,6 +47,7 @@ public class EventFight implements Comparable<EventFight> {
private static final Statement create = table.insertFields(true, "eventID", "startTime", "spielmodus", "map", "teamBlue", "teamRed", "spectatePort"); 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 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); private static final Statement delete = table.delete(Table.PRIMARY);
@Getter @Getter
@@ -152,6 +153,11 @@ public class EventFight implements Comparable<EventFight> {
setFight.update(fight, fightID); setFight.update(fight, fightID);
} }
public void setGroup(EventGroup group) {
setGroup.update(group.getId(), fightID);
this.groupId = group.getId();
}
public boolean hasFinished() { public boolean hasFinished() {
return fight != 0 || ergebnis != 0; return fight != 0 || ergebnis != 0;
} }

View File

@@ -19,11 +19,7 @@
package de.steamwar.sql; package de.steamwar.sql;
import de.steamwar.sql.internal.Field; import de.steamwar.sql.internal.*;
import de.steamwar.sql.internal.SelectStatement;
import de.steamwar.sql.internal.SqlTypeMapper;
import de.steamwar.sql.internal.Table;
import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
@@ -32,7 +28,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@AllArgsConstructor
@Getter @Getter
@Setter @Setter
public class EventGroup { public class EventGroup {
@@ -45,8 +40,17 @@ public class EventGroup {
private static final SelectStatement<EventGroup> get = table.select(Table.PRIMARY); private static final SelectStatement<EventGroup> get = table.select(Table.PRIMARY);
private static final SelectStatement<EventGroup> byEvent = new SelectStatement<>(table, "SELECT * FROM EventGroup WHERE EventID = ?"); private static final SelectStatement<EventGroup> 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<EventGroup> get(Event eventID) { public static List<EventGroup> 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<EventGroup> get(int id) { public static Optional<EventGroup> get(int id) {
@@ -56,7 +60,10 @@ public class EventGroup {
@Field(keys = Table.PRIMARY) @Field(keys = Table.PRIMARY)
private final int id; private final int id;
@Field @Field(keys = "EVENT_NAME")
private int eventID;
@Field(keys = "EVENT_NAME")
private String name; private String name;
@Field @Field
@@ -71,6 +78,16 @@ public class EventGroup {
@Field @Field
private int pointsPerDraw; 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<Team, Integer> points; private Map<Team, Integer> points;
public List<EventFight> getFights() { public List<EventFight> getFights() {
@@ -88,8 +105,9 @@ public class EventGroup {
public Map<Team, Integer> calculatePoints() { public Map<Team, Integer> calculatePoints() {
if (points == null) { if (points == null) {
Map<Integer, Team> teams = new HashMap<>(); Map<Integer, Team> teams = new HashMap<>();
points = new HashMap<>();
for(EventFight fight : getFights()) { for (EventFight fight : getFights()) {
int blueTeamAdd = 0; int blueTeamAdd = 0;
int redTeamAdd = 0; int redTeamAdd = 0;
@@ -121,10 +139,23 @@ public class EventGroup {
return points; 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() { public boolean needsTieBreak() {
return calculatePoints().values().stream().sorted().limit(2).distinct().count() < 2; return calculatePoints().values().stream().sorted().limit(2).distinct().count() < 2;
} }
public void delete() {
delete.update(id);
}
public static enum EventGroupType { public static enum EventGroupType {
GROUP_STAGE, GROUP_STAGE,
ELIMINATION_STAGE ELIMINATION_STAGE

View File

@@ -42,11 +42,16 @@ public class EventRelation {
private static final SelectStatement<EventRelation> get = new SelectStatement<>(table, "SELECT * FROM EventRelation WHERE FromType = ? AND FromId = ?"); private static final SelectStatement<EventRelation> get = new SelectStatement<>(table, "SELECT * FROM EventRelation WHERE FromType = ? AND FromId = ?");
private static final SelectStatement<EventRelation> byId = new SelectStatement<>(table, "SELECT * FROM EventRelation WHERE id = ?"); private static final SelectStatement<EventRelation> byId = new SelectStatement<>(table, "SELECT * FROM EventRelation WHERE id = ?");
private static final SelectStatement<EventRelation> 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 insert = table.insertAll(true);
private static final Statement update = table.update(Table.PRIMARY, "fromType", "fromId", "fromPlace"); 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 updateTeam = table.update(Table.PRIMARY, "fightTeam");
private static final Statement delete = table.delete(Table.PRIMARY); private static final Statement delete = table.delete(Table.PRIMARY);
public static List<EventRelation> get(Event event) {
return byId.listSelect(event.getEventID());
}
public static EventRelation get(int id) { public static EventRelation get(int id) {
return byId.select(id); return byId.select(id);
} }

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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<GroupData>)
@Serializable
data class GroupData(val name: String, val fights: MutableList<Int>)
@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<String> {
return groups.groups.map { it.name }
}
}
}

View File

@@ -20,7 +20,6 @@
package de.steamwar.routes package de.steamwar.routes
import de.steamwar.ResponseError import de.steamwar.ResponseError
import de.steamwar.data.Groups
import de.steamwar.data.getCachedSkin import de.steamwar.data.getCachedSkin
import de.steamwar.plugins.SWAuthPrincipal import de.steamwar.plugins.SWAuthPrincipal
import de.steamwar.plugins.SWPermissionCheck import de.steamwar.plugins.SWPermissionCheck
@@ -102,9 +101,6 @@ fun Route.configureDataRoutes() {
} }
call.respond(YamlConfiguration.loadConfiguration(file).getStringList("Server.Maps")) call.respond(YamlConfiguration.loadConfiguration(file).getStringList("Server.Maps"))
} }
get("/groups") {
call.respond(Groups.getAllGroups())
}
} }
get("/server") { get("/server") {
try { try {

View File

@@ -20,12 +20,7 @@
package de.steamwar.routes package de.steamwar.routes
import de.steamwar.ResponseError import de.steamwar.ResponseError
import de.steamwar.data.Groups import de.steamwar.sql.*
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 io.ktor.http.* import io.ktor.http.*
import io.ktor.server.application.* import io.ktor.server.application.*
import io.ktor.server.request.* import io.ktor.server.request.*
@@ -45,7 +40,7 @@ data class ResponseEventFight(
val start: Long, val start: Long,
val ergebnis: Int, val ergebnis: Int,
val spectatePort: Int?, val spectatePort: Int?,
val group: String? val group: ResponseGroups?
) { ) {
constructor(eventFight: EventFight) : this( constructor(eventFight: EventFight) : this(
eventFight.fightID, eventFight.fightID,
@@ -56,7 +51,7 @@ data class ResponseEventFight(
eventFight.startTime.time, eventFight.startTime.time,
eventFight.ergebnis, eventFight.ergebnis,
eventFight.spectatePort, 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 start: Long? = null,
val spielmodus: String? = null, val spielmodus: String? = null,
val map: String? = null, val map: String? = null,
val group: String? = null, val group: Int? = null,
val spectatePort: Int? = null val spectatePort: Int? = null
) )
@@ -85,14 +80,14 @@ data class CreateEventFight(
val redTeam: Int, val redTeam: Int,
val start: Long, val start: Long,
val spectatePort: Int? = null, val spectatePort: Int? = null,
val group: String? = null val group: Int? = null
) )
fun Route.configureEventFightRoutes() { fun Route.configureEventFightRoutes() {
route("/fights") { route("/fights") {
install(SWPermissionCheck) { get {
allowMethod(HttpMethod.Get) val event = call.receiveEvent() ?: return@get
permission = UserPerm.MODERATION call.respond(EventFight.getEvent(event.eventID).map { ResponseEventFight(it) })
} }
post { post {
val fight = call.receiveNullable<CreateEventFight>() val fight = call.receiveNullable<CreateEventFight>()
@@ -100,6 +95,7 @@ fun Route.configureEventFightRoutes() {
call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid body")) call.respond(HttpStatusCode.BadRequest, ResponseError("Invalid body"))
return@post return@post
} }
val eventFight = EventFight.create( val eventFight = EventFight.create(
fight.event, fight.event,
Timestamp.from(Instant.ofEpochMilli(fight.start)), Timestamp.from(Instant.ofEpochMilli(fight.start)),
@@ -110,9 +106,7 @@ fun Route.configureEventFightRoutes() {
fight.spectatePort fight.spectatePort
) )
if (fight.group != null) { if (fight.group != null) {
if (fight.group != "null") { eventFight.groupId = fight.group
Groups.setGroup(eventFight.fightID, fight.group)
}
} }
call.respond(HttpStatusCode.Created, ResponseEventFight(eventFight)) call.respond(HttpStatusCode.Created, ResponseEventFight(eventFight))
} }
@@ -133,10 +127,10 @@ fun Route.configureEventFightRoutes() {
val spectatePort = updateFight.spectatePort ?: fight.spectatePort val spectatePort = updateFight.spectatePort ?: fight.spectatePort
if (updateFight.group != null) { if (updateFight.group != null) {
if (updateFight.group == "null") { if (updateFight.group == -1) {
Groups.resetGroup(fight.fightID, true) fight.groupId = null
} else { } else {
Groups.setGroup(fight.fightID, updateFight.group) fight.groupId = updateFight.group
} }
} }
fight.update(start, spielmodus, map, teamBlue, teamRed, spectatePort) fight.update(start, spielmodus, map, teamBlue, teamRed, spectatePort)

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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<CreateEventGroup>()
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<UpdateEventGroup>()
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
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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<CreateEventRelation>()
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<UpdateEventRelation>()
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
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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<List<Int>>()
team.forEach {
TeamTeilnahme.teilnehmen(it, event.eventID)
}
call.respond(HttpStatusCode.NoContent)
}
delete {
val event = call.receiveEvent() ?: return@delete
val team = call.receive<List<Int>>()
team.forEach {
TeamTeilnahme.notTeilnehmen(it, event.eventID)
}
call.respond(HttpStatusCode.NoContent)
}
}
}

View File

@@ -20,9 +20,10 @@
package de.steamwar.routes package de.steamwar.routes
import de.steamwar.ResponseError import de.steamwar.ResponseError
import de.steamwar.data.Groups
import de.steamwar.plugins.SWPermissionCheck import de.steamwar.plugins.SWPermissionCheck
import de.steamwar.sql.* import de.steamwar.sql.*
import de.steamwar.sql.EventGroup.EventGroupType
import de.steamwar.sql.EventRelation.FromType
import io.ktor.http.* import io.ktor.http.*
import io.ktor.server.application.* import io.ktor.server.application.*
import io.ktor.server.request.* 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) 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<Int, Int>
) {
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 @Serializable
data class ResponseEvent( data class ResponseEvent(
val id: Int, val id: Int,
@@ -49,7 +89,6 @@ data class ResponseEvent(
val maxTeamMembers: Int, val maxTeamMembers: Int,
val schemType: String?, val schemType: String?,
val publicSchemsOnly: Boolean, val publicSchemsOnly: Boolean,
val referees: List<ResponseUser>,
) { ) {
constructor(event: Event) : this( constructor(event: Event) : this(
event.eventID, event.eventID,
@@ -60,7 +99,6 @@ data class ResponseEvent(
event.maximumTeamMembers, event.maximumTeamMembers,
event.schematicType?.toDB(), event.schematicType?.toDB(),
event.publicSchemsOnly(), event.publicSchemsOnly(),
Referee.get(event.eventID).map { ResponseUser(SteamwarUser.get(it)) }
) )
} }
@@ -68,8 +106,20 @@ data class ResponseEvent(
data class ExtendedResponseEvent( data class ExtendedResponseEvent(
val event: ResponseEvent, val event: ResponseEvent,
val teams: List<ResponseTeam>, val teams: List<ResponseTeam>,
val fights: List<ResponseEventFight> val groups: List<ResponseGroups>,
) val fights: List<ResponseEventFight>,
val referees: List<ResponseUser>,
val relations: List<ResponseRelation>
) {
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 @Serializable
data class CreateEvent(val name: String, val start: Long, val end: Long) data class CreateEvent(val name: String, val start: Long, val end: Long)
@@ -111,49 +161,11 @@ fun Route.configureEventsRoute() {
} }
route("/{id}") { route("/{id}") {
get { get {
val id = call.parameters["id"]?.toIntOrNull() val event = call.receiveEvent() ?: return@get
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( call.respond(
ExtendedResponseEvent( ExtendedResponseEvent(event)
ResponseEvent(event),
TeamTeilnahme.getTeams(event.eventID).map { ResponseTeam(it) },
EventFight.getEvent(event.eventID).map { ResponseEventFight(it) })
) )
} }
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") { get("/csv") {
val event = call.receiveEvent() ?: return@get val event = call.receiveEvent() ?: return@get
@@ -164,7 +176,7 @@ fun Route.configureEventsRoute() {
csv.appendLine() csv.appendLine()
val blue = Team.get(it.teamBlue) val blue = Team.get(it.teamBlue)
val red = Team.get(it.teamRed) val red = Team.get(it.teamRed)
val winner = when(it.ergebnis) { val winner = when (it.ergebnis) {
1 -> blue.teamName 1 -> blue.teamName
2 -> red.teamName 2 -> red.teamName
3 -> "Tie" 3 -> "Tie"
@@ -176,7 +188,7 @@ fun Route.configureEventsRoute() {
Team.get(it.teamBlue).teamName, Team.get(it.teamBlue).teamName,
Team.get(it.teamRed).teamName, Team.get(it.teamRed).teamName,
winner, winner,
Groups.getGroup(it.fightID)?.name ?: "Ungrouped" it.group.map { it.name }.orElse("Ungrouped")
).joinToString(",") ).joinToString(",")
) )
} }
@@ -200,7 +212,9 @@ fun Route.configureEventsRoute() {
val end = updateEvent.end?.let { Timestamp.from(Instant.ofEpochMilli(it)) } ?: event.end val end = updateEvent.end?.let { Timestamp.from(Instant.ofEpochMilli(it)) } ?: event.end
val maxTeamMembers = updateEvent.maxTeamMembers ?: event.maximumTeamMembers 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() val publicSchemsOnly = updateEvent.publicSchemsOnly ?: event.publicSchemsOnly()
if (updateEvent.addReferee != null) { if (updateEvent.addReferee != null) {
@@ -231,6 +245,10 @@ fun Route.configureEventsRoute() {
event.delete() event.delete()
call.respond(HttpStatusCode.NoContent) call.respond(HttpStatusCode.NoContent)
} }
configureEventFightRoutes()
configureEventTeams()
configureEventGroups()
configureEventRelations()
} }
} }
} }

View File

@@ -28,7 +28,6 @@ fun Application.configureRoutes() {
authenticate("sw-auth", optional = true) { authenticate("sw-auth", optional = true) {
configureEventsRoute() configureEventsRoute()
configureDataRoutes() configureDataRoutes()
configureEventFightRoutes()
configureUserPerms() configureUserPerms()
configureStats() configureStats()
configurePage() configurePage()