forked from SteamWar/SteamWar
Merge pull request 'Add event grouping' (#57) from event-brackets into main
Reviewed-on: SteamWar/SteamWar#57 Reviewed-by: YoyoNow <yoyonow@noreply.localhost>
This commit is contained in:
@@ -37,6 +37,8 @@ public class EventFight implements Comparable<EventFight> {
|
|||||||
|
|
||||||
private static final Table<EventFight> table = new Table<>(EventFight.class);
|
private static final Table<EventFight> table = new Table<>(EventFight.class);
|
||||||
private static final SelectStatement<EventFight> byId = table.select(Table.PRIMARY);
|
private static final SelectStatement<EventFight> byId = table.select(Table.PRIMARY);
|
||||||
|
private static final SelectStatement<EventFight> byGroup = new SelectStatement<EventFight>(table, "SELECT * FROM EventFight WHERE GroupID = ? ORDER BY StartTime ASC");
|
||||||
|
private static final SelectStatement<EventFight> byGroupLast = new SelectStatement<EventFight>(table, "SELECT * FROM EventFight WHERE GroupID = ? ORDER BY StartTime DESC LIMIT 1");
|
||||||
private static final SelectStatement<EventFight> allComing = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE StartTime > now() ORDER BY StartTime ASC");
|
private static final SelectStatement<EventFight> allComing = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE StartTime > now() ORDER BY StartTime ASC");
|
||||||
private static final SelectStatement<EventFight> event = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE EventID = ? ORDER BY StartTime ASC");
|
private static final SelectStatement<EventFight> event = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE EventID = ? ORDER BY StartTime ASC");
|
||||||
private static final SelectStatement<EventFight> activeFights = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE Fight IS NOT NULL AND StartTime < now() AND DATEDIFF(StartTime, now()) < 0");
|
private static final SelectStatement<EventFight> activeFights = new SelectStatement<>(table, "SELECT * FROM EventFight WHERE Fight IS NOT NULL AND StartTime < now() AND DATEDIFF(StartTime, now()) < 0");
|
||||||
@@ -46,6 +48,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
|
||||||
@@ -55,6 +58,14 @@ public class EventFight implements Comparable<EventFight> {
|
|||||||
return byId.select(fightID);
|
return byId.select(fightID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<EventFight> get(EventGroup group) {
|
||||||
|
return byGroup.listSelect(group.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<EventFight> getLast(EventGroup group) {
|
||||||
|
return Optional.ofNullable(byGroupLast.select(group.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
public static void loadAllComingFights() {
|
public static void loadAllComingFights() {
|
||||||
fights.clear();
|
fights.clear();
|
||||||
fights.addAll(allComing.listSelect());
|
fights.addAll(allComing.listSelect());
|
||||||
@@ -89,6 +100,10 @@ public class EventFight implements Comparable<EventFight> {
|
|||||||
private final int fightID;
|
private final int fightID;
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
|
@Field(nullable = true, def = "null")
|
||||||
|
private Integer groupId;
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
@Field
|
@Field
|
||||||
private Timestamp startTime;
|
private Timestamp startTime;
|
||||||
@Getter
|
@Getter
|
||||||
@@ -112,11 +127,35 @@ public class EventFight implements Comparable<EventFight> {
|
|||||||
@Field(nullable = true)
|
@Field(nullable = true)
|
||||||
private Integer spectatePort;
|
private Integer spectatePort;
|
||||||
@Getter
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Field(def = "1")
|
||||||
|
private int bestOf;
|
||||||
|
@Getter
|
||||||
@Field(def = "0")
|
@Field(def = "0")
|
||||||
private int ergebnis;
|
private int ergebnis;
|
||||||
@Field(nullable = true)
|
@Field(nullable = true)
|
||||||
private int fight;
|
private int fight;
|
||||||
|
|
||||||
|
public Optional<EventGroup> getGroup() {
|
||||||
|
return Optional.ofNullable(groupId).flatMap(EventGroup::get);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Team> getWinner() {
|
||||||
|
if(ergebnis == 0)
|
||||||
|
return Optional.empty();
|
||||||
|
return Optional.ofNullable(ergebnis == 1 ? Team.get(teamBlue) : Team.get(teamRed));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Team> getLosser() {
|
||||||
|
if(ergebnis == 0)
|
||||||
|
return Optional.empty();
|
||||||
|
return Optional.ofNullable(ergebnis == 1 ? Team.get(teamRed) : Team.get(teamBlue));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<EventRelation> getDependents() {
|
||||||
|
return EventRelation.getFightRelations(this);
|
||||||
|
}
|
||||||
|
|
||||||
public void setErgebnis(int winner) {
|
public void setErgebnis(int winner) {
|
||||||
this.ergebnis = winner;
|
this.ergebnis = winner;
|
||||||
setResult.update(winner, fightID);
|
setResult.update(winner, fightID);
|
||||||
@@ -128,6 +167,11 @@ public class EventFight implements Comparable<EventFight> {
|
|||||||
setFight.update(fight, fightID);
|
setFight.update(fight, fightID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setGroup(Integer group) {
|
||||||
|
setGroup.update(group, fightID);
|
||||||
|
this.groupId = group;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasFinished() {
|
public boolean hasFinished() {
|
||||||
return fight != 0 || ergebnis != 0;
|
return fight != 0 || ergebnis != 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
* 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.sql;
|
||||||
|
|
||||||
|
import de.steamwar.sql.internal.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class EventGroup {
|
||||||
|
static {
|
||||||
|
SqlTypeMapper.ordinalEnumMapper(EventGroupType.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Table<EventGroup> table = new Table<>(EventGroup.class);
|
||||||
|
|
||||||
|
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 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) {
|
||||||
|
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) {
|
||||||
|
return Optional.ofNullable(get.select(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Field(keys = Table.PRIMARY)
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
@Field(keys = "EVENT_NAME")
|
||||||
|
private int eventID;
|
||||||
|
|
||||||
|
@Field(keys = "EVENT_NAME")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Field
|
||||||
|
private EventGroupType type;
|
||||||
|
|
||||||
|
@Field
|
||||||
|
private int pointsPerWin;
|
||||||
|
|
||||||
|
@Field
|
||||||
|
private int pointsPerLoss;
|
||||||
|
|
||||||
|
@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<Team, Integer> points;
|
||||||
|
|
||||||
|
public List<EventFight> getFights() {
|
||||||
|
return EventFight.get(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Integer> getTeamsId() {
|
||||||
|
return getFights().stream().flatMap(fight -> Stream.of(fight.getTeamBlue(), fight.getTeamRed()))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Team> getTeams() {
|
||||||
|
return getTeamsId().stream().map(Team::get).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<EventFight> getLastFight() {
|
||||||
|
return EventFight.getLast(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<EventRelation> getDependents() {
|
||||||
|
return EventRelation.getGroupRelations(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Team, Integer> calculatePoints() {
|
||||||
|
if (points == null) {
|
||||||
|
Map<Integer, Integer> p = getTeamsId().stream().collect(Collectors.toMap(team -> team, team -> 0));
|
||||||
|
|
||||||
|
for (EventFight fight : getFights()) {
|
||||||
|
int blueTeamAdd = 0;
|
||||||
|
int redTeamAdd = 0;
|
||||||
|
|
||||||
|
if (!fight.hasFinished()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (fight.getErgebnis()) {
|
||||||
|
case 1:
|
||||||
|
blueTeamAdd += pointsPerWin;
|
||||||
|
redTeamAdd += pointsPerLoss;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
blueTeamAdd += pointsPerLoss;
|
||||||
|
redTeamAdd += pointsPerWin;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
if (fight.getFightID() != 0) {
|
||||||
|
blueTeamAdd += pointsPerDraw;
|
||||||
|
redTeamAdd += pointsPerDraw;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.put(fight.getTeamBlue(), p.get(fight.getTeamBlue()) + blueTeamAdd);
|
||||||
|
p.put(fight.getTeamRed(), p.get(fight.getTeamRed()) + redTeamAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
points = p.entrySet().stream().collect(Collectors.toMap(integerIntegerEntry -> Team.get(integerIntegerEntry.getKey()), Map.Entry::getValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(String name, EventGroupType type, int pointsPerWin, int pointsPerLoss, int pointsPerDraw) {
|
||||||
|
update.update(name, type, pointsPerWin, pointsPerLoss, pointsPerDraw, id);
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
* 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.sql;
|
||||||
|
|
||||||
|
import de.steamwar.sql.internal.*;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class EventRelation {
|
||||||
|
|
||||||
|
static {
|
||||||
|
SqlTypeMapper.ordinalEnumMapper(FightTeam.class);
|
||||||
|
SqlTypeMapper.ordinalEnumMapper(FromType.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Table<EventRelation> table = new Table<>(EventRelation.class);
|
||||||
|
|
||||||
|
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> 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<EventRelation> get(Event event) {
|
||||||
|
return byId.listSelect(event.getEventID());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EventRelation get(int id) {
|
||||||
|
return byId.select(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<EventRelation> getFightRelations(EventFight fight) {
|
||||||
|
return get.listSelect(FromType.FIGHT, fight.getFightID());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<EventRelation> getGroupRelations(EventGroup group) {
|
||||||
|
return get.listSelect(FromType.GROUP, group.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EventRelation create(EventFight fight, FightTeam fightTeam, FromType fromType, int fromId, int fromPlace) {
|
||||||
|
int id = insert.insertGetKey(fight.getFightID(), fightTeam, fromType, fromId, fromPlace);
|
||||||
|
return get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Field(keys = Table.PRIMARY)
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
@Field
|
||||||
|
private int fightId;
|
||||||
|
|
||||||
|
@Field
|
||||||
|
private FightTeam fightTeam;
|
||||||
|
|
||||||
|
@Field
|
||||||
|
private FromType fromType;
|
||||||
|
|
||||||
|
@Field
|
||||||
|
private int fromId;
|
||||||
|
|
||||||
|
@Field
|
||||||
|
private int fromPlace;
|
||||||
|
|
||||||
|
public EventFight getFight() {
|
||||||
|
return EventFight.get(fightId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<EventFight> getFromFight() {
|
||||||
|
if(fromType == FromType.FIGHT) {
|
||||||
|
return Optional.of(EventFight.get(fromId));
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<EventGroup> getFromGroup() {
|
||||||
|
if(fromType == FromType.GROUP) {
|
||||||
|
return EventGroup.get(fromId);
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() {
|
||||||
|
delete.update(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdateTeam(FightTeam team) {
|
||||||
|
updateTeam.update(id, team);
|
||||||
|
this.fightTeam = team;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFromFight(EventFight fight, int place) {
|
||||||
|
setFrom(fight.getFightID(), place, FromType.FIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFromGroup(EventGroup group, int place) {
|
||||||
|
setFrom(group.getId(), place, FromType.GROUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setFrom(int id, int place, FromType type) {
|
||||||
|
update.update(id, type, id, place);
|
||||||
|
this.fromType = type;
|
||||||
|
this.fromId = id;
|
||||||
|
this.fromPlace = place;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Team> getAdvancingTeam() {
|
||||||
|
if (fromType == FromType.FIGHT) {
|
||||||
|
if (fromPlace == 0) {
|
||||||
|
return getFromFight().flatMap(EventFight::getWinner);
|
||||||
|
} else {
|
||||||
|
return getFromFight().flatMap(EventFight::getLosser);
|
||||||
|
}
|
||||||
|
} else if (fromType == FromType.GROUP) {
|
||||||
|
return getFromGroup().map(EventGroup::calculatePoints)
|
||||||
|
.flatMap(points -> points.entrySet().stream()
|
||||||
|
.sorted(Map.Entry.comparingByValue())
|
||||||
|
.skip(fromPlace)
|
||||||
|
.findFirst()
|
||||||
|
.map(Map.Entry::getKey));
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean apply() {
|
||||||
|
Optional<Integer> team = getAdvancingTeam().map(Team::getTeamId);
|
||||||
|
if(!team.isPresent())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
EventFight fight = getFight();
|
||||||
|
if(fightTeam == FightTeam.RED) {
|
||||||
|
fight.update(
|
||||||
|
fight.getStartTime(),
|
||||||
|
fight.getSpielmodus(),
|
||||||
|
fight.getMap(),
|
||||||
|
team.get(),
|
||||||
|
fight.getTeamBlue(),
|
||||||
|
fight.getSpectatePort()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
fight.update(
|
||||||
|
fight.getStartTime(),
|
||||||
|
fight.getSpielmodus(),
|
||||||
|
fight.getMap(),
|
||||||
|
fight.getTeamRed(),
|
||||||
|
team.get(),
|
||||||
|
fight.getSpectatePort()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static enum FightTeam {
|
||||||
|
RED,
|
||||||
|
BLUE
|
||||||
|
}
|
||||||
|
|
||||||
|
public static enum FromType {
|
||||||
|
FIGHT,
|
||||||
|
GROUP
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
-3
@@ -33,6 +33,8 @@ import de.steamwar.fightsystem.states.OneShotStateDependent;
|
|||||||
import de.steamwar.fightsystem.winconditions.Wincondition;
|
import de.steamwar.fightsystem.winconditions.Wincondition;
|
||||||
import de.steamwar.network.NetworkSender;
|
import de.steamwar.network.NetworkSender;
|
||||||
import de.steamwar.network.packets.common.FightEndsPacket;
|
import de.steamwar.network.packets.common.FightEndsPacket;
|
||||||
|
import de.steamwar.sql.EventFight;
|
||||||
|
import de.steamwar.sql.EventRelation;
|
||||||
import de.steamwar.sql.SchematicNode;
|
import de.steamwar.sql.SchematicNode;
|
||||||
import de.steamwar.sql.SteamwarUser;
|
import de.steamwar.sql.SteamwarUser;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -70,12 +72,21 @@ public class FightStatistics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setEventResult() {
|
private void setEventResult() {
|
||||||
if (FightSystem.getLastWinner() == null)
|
if (FightSystem.getLastWinner() == null) {
|
||||||
Config.EventKampf.setErgebnis(0);
|
Config.EventKampf.setErgebnis(0);
|
||||||
else if (FightSystem.getLastWinner().isBlue())
|
} else if (FightSystem.getLastWinner().isBlue()) {
|
||||||
Config.EventKampf.setErgebnis(1);
|
Config.EventKampf.setErgebnis(1);
|
||||||
else
|
} else {
|
||||||
Config.EventKampf.setErgebnis(2);
|
Config.EventKampf.setErgebnis(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
Config.EventKampf.getDependents().forEach(EventRelation::apply);
|
||||||
|
|
||||||
|
Config.EventKampf.getGroup().ifPresent(group -> {
|
||||||
|
if (group.getLastFight().map(EventFight::getFightID).orElse(-1) == Config.EventKampf.getFightID() && !group.needsTieBreak()) {
|
||||||
|
group.getDependents().forEach(EventRelation::apply);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void disable() {
|
private void disable() {
|
||||||
|
|||||||
@@ -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 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -20,12 +20,12 @@
|
|||||||
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
|
||||||
import de.steamwar.sql.SchematicType
|
import de.steamwar.sql.SchematicType
|
||||||
import de.steamwar.sql.SteamwarUser
|
import de.steamwar.sql.SteamwarUser
|
||||||
|
import de.steamwar.sql.Team
|
||||||
import de.steamwar.sql.UserPerm
|
import de.steamwar.sql.UserPerm
|
||||||
import de.steamwar.sql.loadSchematicTypes
|
import de.steamwar.sql.loadSchematicTypes
|
||||||
import de.steamwar.util.fetchData
|
import de.steamwar.util.fetchData
|
||||||
@@ -78,6 +78,9 @@ fun Route.configureDataRoutes() {
|
|||||||
get("/users") {
|
get("/users") {
|
||||||
call.respond(SteamwarUser.getAll().map { ResponseUser(it) })
|
call.respond(SteamwarUser.getAll().map { ResponseUser(it) })
|
||||||
}
|
}
|
||||||
|
get("/teams") {
|
||||||
|
call.respond(Team.getAll().map { ResponseTeam(it) })
|
||||||
|
}
|
||||||
get("/schematicTypes") {
|
get("/schematicTypes") {
|
||||||
val types = mutableListOf<SchematicType>()
|
val types = mutableListOf<SchematicType>()
|
||||||
loadSchematicTypes(types, mutableMapOf())
|
loadSchematicTypes(types, mutableMapOf())
|
||||||
@@ -102,9 +105,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 {
|
||||||
|
|||||||
@@ -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,8 @@ 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?,
|
||||||
|
val hasFinished: Boolean
|
||||||
) {
|
) {
|
||||||
constructor(eventFight: EventFight) : this(
|
constructor(eventFight: EventFight) : this(
|
||||||
eventFight.fightID,
|
eventFight.fightID,
|
||||||
@@ -56,7 +52,8 @@ 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, short = true) },
|
||||||
|
eventFight.hasFinished()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,36 +69,39 @@ 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,
|
||||||
|
val ergebnis: Int? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class CreateEventFight(
|
data class CreateEventFight(
|
||||||
val event: Int,
|
|
||||||
val spielmodus: String,
|
val spielmodus: String,
|
||||||
val map: String,
|
val map: String,
|
||||||
val blueTeam: Int,
|
val blueTeam: Int,
|
||||||
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 event = call.receiveEvent() ?: return@post
|
||||||
|
|
||||||
val fight = call.receiveNullable<CreateEventFight>()
|
val fight = call.receiveNullable<CreateEventFight>()
|
||||||
if (fight == null) {
|
if (fight == null) {
|
||||||
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,
|
event.eventID,
|
||||||
Timestamp.from(Instant.ofEpochMilli(fight.start)),
|
Timestamp.from(Instant.ofEpochMilli(fight.start)),
|
||||||
fight.spielmodus,
|
fight.spielmodus,
|
||||||
fight.map,
|
fight.map,
|
||||||
@@ -110,9 +110,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,12 +131,17 @@ 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.setGroup(null)
|
||||||
} else {
|
} else {
|
||||||
Groups.setGroup(fight.fightID, updateFight.group)
|
fight.setGroup(updateFight.group)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (updateFight.ergebnis != null) {
|
||||||
|
fight.ergebnis = updateFight.ergebnis
|
||||||
|
}
|
||||||
|
|
||||||
fight.update(start, spielmodus, map, teamBlue, teamRed, spectatePort)
|
fight.update(start, spielmodus, map, teamBlue, teamRed, spectatePort)
|
||||||
call.respond(HttpStatusCode.OK, ResponseEventFight(fight))
|
call.respond(HttpStatusCode.OK, ResponseEventFight(fight))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* 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.Referee
|
||||||
|
import de.steamwar.sql.SteamwarUser
|
||||||
|
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 java.util.*
|
||||||
|
|
||||||
|
fun Route.configureEventRefereesRouting() {
|
||||||
|
route("/referees") {
|
||||||
|
get {
|
||||||
|
val event = call.receiveEvent() ?: return@get
|
||||||
|
call.respond(Referee.get(event.eventID).map { ResponseUser(SteamwarUser.get(it)) })
|
||||||
|
}
|
||||||
|
put {
|
||||||
|
val event = call.receiveEvent() ?: return@put
|
||||||
|
val referees = call.receive<List<String>>()
|
||||||
|
referees.forEach {
|
||||||
|
Referee.add(event.eventID, SteamwarUser.get(UUID.fromString(it)).id)
|
||||||
|
}
|
||||||
|
call.respond(Referee.get(event.eventID).map { ResponseUser(SteamwarUser.get(it)) })
|
||||||
|
}
|
||||||
|
delete {
|
||||||
|
val event = call.receiveEvent() ?: return@delete
|
||||||
|
val referees = call.receive<List<String>>()
|
||||||
|
referees.forEach {
|
||||||
|
Referee.remove(event.eventID, SteamwarUser.get(UUID.fromString(it)).id)
|
||||||
|
}
|
||||||
|
call.respond(Referee.get(event.eventID).map { ResponseUser(SteamwarUser.get(it)) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,11 @@ fun Route.configureEventsRoute() {
|
|||||||
event.delete()
|
event.delete()
|
||||||
call.respond(HttpStatusCode.NoContent)
|
call.respond(HttpStatusCode.NoContent)
|
||||||
}
|
}
|
||||||
|
configureEventFightRoutes()
|
||||||
|
configureEventTeams()
|
||||||
|
configureEventGroups()
|
||||||
|
configureEventRelations()
|
||||||
|
configureEventRefereesRouting()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import de.steamwar.plugins.SWAuthPrincipal
|
|||||||
import de.steamwar.plugins.SWPermissionCheck
|
import de.steamwar.plugins.SWPermissionCheck
|
||||||
import de.steamwar.sql.UserPerm
|
import de.steamwar.sql.UserPerm
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
import io.ktor.client.call.*
|
|
||||||
import io.ktor.client.engine.java.*
|
import io.ktor.client.engine.java.*
|
||||||
import io.ktor.client.plugins.*
|
import io.ktor.client.plugins.*
|
||||||
import io.ktor.client.plugins.contentnegotiation.*
|
import io.ktor.client.plugins.contentnegotiation.*
|
||||||
@@ -37,11 +36,13 @@ import io.ktor.server.auth.*
|
|||||||
import io.ktor.server.request.*
|
import io.ktor.server.request.*
|
||||||
import io.ktor.server.response.*
|
import io.ktor.server.response.*
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
import io.ktor.util.reflect.*
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.encodeToString
|
|
||||||
import kotlinx.serialization.json.*
|
import kotlinx.serialization.json.*
|
||||||
|
import java.time.Instant
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
import java.util.Base64
|
import java.util.Base64
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
val pathPageIdMap = mutableMapOf<String, Int>()
|
val pathPageIdMap = mutableMapOf<String, Int>()
|
||||||
var pageId = 1
|
var pageId = 1
|
||||||
@@ -90,6 +91,9 @@ data class PageResponse(
|
|||||||
@Serializable
|
@Serializable
|
||||||
data class CreatePageRequest(val path: String, val slug: String?, val title: String?)
|
data class CreatePageRequest(val path: String, val slug: String?, val title: String?)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class AddImageRequest(val name: String, val data: String)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class CreateBranchRequest(val branch: String)
|
data class CreateBranchRequest(val branch: String)
|
||||||
|
|
||||||
@@ -102,6 +106,9 @@ data class MergeBranchRequest(val branch: String, val message: String)
|
|||||||
@Serializable
|
@Serializable
|
||||||
data class DeletePageRequest(val sha: String, val message: String)
|
data class DeletePageRequest(val sha: String, val message: String)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class CreateGiteaPageRequest(val message: String, val content: String, val branch: String, val author: Identity)
|
||||||
|
|
||||||
fun Route.configurePage() {
|
fun Route.configurePage() {
|
||||||
val client = HttpClient(Java) {
|
val client = HttpClient(Java) {
|
||||||
install(ContentNegotiation) {
|
install(ContentNegotiation) {
|
||||||
@@ -113,69 +120,44 @@ fun Route.configurePage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun filesInDirectory(path: String, branch: String = "master", fileFilter: (name: String) -> Boolean = { true }): List<PageResponseList> {
|
||||||
|
val filesToCheck = mutableListOf(path)
|
||||||
|
val files = mutableListOf<PageResponseList>()
|
||||||
|
|
||||||
|
while (filesToCheck.isNotEmpty()) {
|
||||||
|
val path = filesToCheck.removeAt(0)
|
||||||
|
val res = client.get("repos/SteamWar/Website/contents/$path?ref=$branch")
|
||||||
|
val fileJson = Json.parseToJsonElement(res.bodyAsText())
|
||||||
|
|
||||||
|
if (fileJson is JsonArray) {
|
||||||
|
fileJson.forEach {
|
||||||
|
val obj = it.jsonObject
|
||||||
|
if (obj["type"]?.jsonPrimitive?.content == "dir") {
|
||||||
|
filesToCheck.add(obj["path"]?.jsonPrimitive?.content!!)
|
||||||
|
} else if (obj["type"]?.jsonPrimitive?.content == "file" && fileFilter(obj["name"]!!.jsonPrimitive.content)) {
|
||||||
|
files.add(PageResponseList(obj, pathPageIdMap.computeIfAbsent(obj["path"]?.jsonPrimitive?.content!!) { pageId++ }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
files.add(PageResponseList(fileJson.jsonObject, pathPageIdMap.computeIfAbsent(fileJson.jsonObject["path"]?.jsonPrimitive?.content!!) { pageId++ }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return files
|
||||||
|
}
|
||||||
|
|
||||||
route("page") {
|
route("page") {
|
||||||
install(SWPermissionCheck) {
|
install(SWPermissionCheck) {
|
||||||
permission = UserPerm.MODERATION
|
permission = UserPerm.MODERATION
|
||||||
}
|
}
|
||||||
get {
|
get {
|
||||||
val branch = call.request.queryParameters["branch"] ?: "master"
|
val branch = call.request.queryParameters["branch"] ?: "master"
|
||||||
val filesToCheck = mutableListOf("src/content")
|
|
||||||
val files = mutableListOf<PageResponseList>()
|
|
||||||
|
|
||||||
while (filesToCheck.isNotEmpty()) {
|
call.respond(filesInDirectory("/src/content", branch) {
|
||||||
val path = filesToCheck.removeAt(0)
|
it.endsWith(".md") || it.endsWith(".json")
|
||||||
val res = client.get("repos/SteamWar/Website/contents/$path?ref=$branch")
|
})
|
||||||
val fileJson = Json.parseToJsonElement(res.bodyAsText())
|
|
||||||
|
|
||||||
if (fileJson is JsonArray) {
|
|
||||||
fileJson.forEach {
|
|
||||||
val obj = it.jsonObject
|
|
||||||
if (obj["type"]?.jsonPrimitive?.content == "dir") {
|
|
||||||
filesToCheck.add(obj["path"]?.jsonPrimitive?.content!!)
|
|
||||||
} else if (obj["type"]?.jsonPrimitive?.content == "file" && (obj["name"]?.jsonPrimitive?.content?.endsWith(".md") == true || obj["name"]?.jsonPrimitive?.content?.endsWith(".json") == true)) {
|
|
||||||
files.add(PageResponseList(obj, pathPageIdMap.computeIfAbsent(obj["path"]?.jsonPrimitive?.content!!) { pageId++ }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
files.add(PageResponseList(fileJson.jsonObject, pathPageIdMap.computeIfAbsent(fileJson.jsonObject["path"]?.jsonPrimitive?.content!!) { pageId++ }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
call.respond(files)
|
|
||||||
}
|
|
||||||
get("branch") {
|
|
||||||
val res = client.get("repos/SteamWar/Website/branches")
|
|
||||||
call.respond(res.status, Json.parseToJsonElement(res.bodyAsText()).jsonArray.map { it.jsonObject["name"]?.jsonPrimitive?.content!! })
|
|
||||||
}
|
|
||||||
post("branch") {
|
|
||||||
@Serializable
|
|
||||||
data class CreateGiteaBranchRequest(val new_branch_name: String, val old_branch_name: String)
|
|
||||||
|
|
||||||
val branch = call.receive<CreateBranchRequest>().branch
|
|
||||||
val res = client.post("repos/SteamWar/Website/branches") {
|
|
||||||
contentType(ContentType.Application.Json)
|
|
||||||
setBody(CreateGiteaBranchRequest(branch, "master"))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class CreateGiteaMergeRequest(val base: String, val head: String, val title: String)
|
|
||||||
|
|
||||||
client.post("repos/SteamWar/Website/pulls") {
|
|
||||||
contentType(ContentType.Application.Json)
|
|
||||||
setBody(CreateGiteaMergeRequest("master", branch, "Merge branch $branch"))
|
|
||||||
}
|
|
||||||
|
|
||||||
call.respond(res.status)
|
|
||||||
}
|
|
||||||
delete("branch") {
|
|
||||||
val branch = call.receive<CreateBranchRequest>().branch
|
|
||||||
val res = client.delete("repos/SteamWar/Website/branches/$branch")
|
|
||||||
call.respond(res.status)
|
|
||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
@Serializable
|
|
||||||
data class CreateGiteaPageRequest(val message: String, val content: String, val branch: String, val author: Identity)
|
|
||||||
|
|
||||||
val req = call.receive<CreatePageRequest>()
|
val req = call.receive<CreatePageRequest>()
|
||||||
if(req.path.startsWith("src/content/")) {
|
if(req.path.startsWith("src/content/")) {
|
||||||
@@ -190,62 +172,119 @@ fun Route.configurePage() {
|
|||||||
---
|
---
|
||||||
title: ${req.title ?: "[Enter Title]"}
|
title: ${req.title ?: "[Enter Title]"}
|
||||||
description: [Enter Description]
|
description: [Enter Description]
|
||||||
slug: ${req.slug ?: "[Enter Slug]"}
|
key: ${req.slug ?: "[Enter Slug]"}
|
||||||
|
created: ${LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE)}
|
||||||
|
tags:
|
||||||
|
- test
|
||||||
---
|
---
|
||||||
|
|
||||||
# ${req.path}
|
# ${req.path}
|
||||||
""".trimIndent().toByteArray()),
|
""".trimIndent().toByteArray()),
|
||||||
call.request.queryParameters["branch"] ?: "master",
|
call.request.queryParameters["branch"] ?: "master",
|
||||||
Identity(call.principal<SWAuthPrincipal>()!!.user.userName, "admin-tool@steamwar.de"
|
Identity(call.principal<SWAuthPrincipal>()!!.user.userName, "admin-tool@steamwar.de"
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
call.respond(res.status)
|
call.respond(res.status)
|
||||||
}
|
}
|
||||||
get("{id}") {
|
route("branch") {
|
||||||
val id = call.parameters["id"]?.toIntOrNull() ?: return@get call.respond(HttpStatusCode.BadRequest, "Invalid id")
|
get {
|
||||||
val path = pathPageIdMap.entries.find { it.value == id }?.key ?: return@get call.respond(HttpStatusCode.NotFound, "Page not found")
|
val res = client.get("repos/SteamWar/Website/branches")
|
||||||
|
call.respond(res.status, Json.parseToJsonElement(res.bodyAsText()).jsonArray.map { it.jsonObject["name"]?.jsonPrimitive?.content!! })
|
||||||
val branch = call.request.queryParameters["branch"] ?: "master"
|
|
||||||
val res = client.get("repos/SteamWar/Website/contents/$path?ref=$branch")
|
|
||||||
val fileJson = Json.parseToJsonElement(res.bodyAsText())
|
|
||||||
if (fileJson is JsonArray) {
|
|
||||||
return@get call.respond(HttpStatusCode.BadRequest, "Invalid id")
|
|
||||||
}
|
}
|
||||||
|
post {
|
||||||
|
@Serializable
|
||||||
|
data class CreateGiteaBranchRequest(val new_branch_name: String, val old_branch_name: String)
|
||||||
|
|
||||||
val file = PageResponse(fileJson.jsonObject, id)
|
val branch = call.receive<CreateBranchRequest>().branch
|
||||||
call.respond(file)
|
val res = client.post("repos/SteamWar/Website/branches") {
|
||||||
|
contentType(ContentType.Application.Json)
|
||||||
|
setBody(CreateGiteaBranchRequest(branch, "master"))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class CreateGiteaMergeRequest(val base: String, val head: String, val title: String)
|
||||||
|
|
||||||
|
client.post("repos/SteamWar/Website/pulls") {
|
||||||
|
contentType(ContentType.Application.Json)
|
||||||
|
setBody(CreateGiteaMergeRequest("master", branch, "Merge branch $branch"))
|
||||||
|
}
|
||||||
|
|
||||||
|
call.respond(res.status)
|
||||||
|
}
|
||||||
|
delete {
|
||||||
|
val branch = call.receive<CreateBranchRequest>().branch
|
||||||
|
val res = client.delete("repos/SteamWar/Website/branches/$branch")
|
||||||
|
call.respond(res.status)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
route("{id}") {
|
||||||
|
get {
|
||||||
|
val id = call.parameters["id"]?.toIntOrNull() ?: return@get call.respond(HttpStatusCode.BadRequest, "Invalid id")
|
||||||
|
val path = pathPageIdMap.entries.find { it.value == id }?.key ?: return@get call.respond(HttpStatusCode.NotFound, "Page not found")
|
||||||
|
|
||||||
delete("{id}") {
|
val branch = call.request.queryParameters["branch"] ?: "master"
|
||||||
val data = call.receive<DeletePageRequest>()
|
val res = client.get("repos/SteamWar/Website/contents/$path?ref=$branch")
|
||||||
|
val fileJson = Json.parseToJsonElement(res.bodyAsText())
|
||||||
|
if (fileJson is JsonArray) {
|
||||||
|
return@get call.respond(HttpStatusCode.BadRequest, "Invalid id")
|
||||||
|
}
|
||||||
|
|
||||||
val path = pathPageIdMap.entries.find { it.value == call.parameters["id"]?.toIntOrNull() }?.key ?: return@delete call.respond(HttpStatusCode.NotFound, "Page not found")
|
val file = PageResponse(fileJson.jsonObject, id)
|
||||||
val branch = call.request.queryParameters["branch"] ?: "master"
|
call.respond(file)
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class DeleteGiteaPageRequest(val sha: String, val message: String, val branch: String, val author: Identity)
|
|
||||||
|
|
||||||
val res = client.delete("repos/SteamWar/Website/contents/$path") {
|
|
||||||
contentType(ContentType.Application.Json)
|
|
||||||
setBody(DeleteGiteaPageRequest(data.sha, data.message, branch, Identity(call.principal<SWAuthPrincipal>()!!.user.userName, "admin-tool@steamwar.de")))
|
|
||||||
}
|
}
|
||||||
|
delete {
|
||||||
|
val data = call.receive<DeletePageRequest>()
|
||||||
|
|
||||||
call.respond(res.status)
|
val path = pathPageIdMap.entries.find { it.value == call.parameters["id"]?.toIntOrNull() }?.key ?: return@delete call.respond(HttpStatusCode.NotFound, "Page not found")
|
||||||
|
val branch = call.request.queryParameters["branch"] ?: "master"
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class DeleteGiteaPageRequest(val sha: String, val message: String, val branch: String, val author: Identity)
|
||||||
|
|
||||||
|
val res = client.delete("repos/SteamWar/Website/contents/$path") {
|
||||||
|
contentType(ContentType.Application.Json)
|
||||||
|
setBody(DeleteGiteaPageRequest(data.sha, data.message, branch, Identity(call.principal<SWAuthPrincipal>()!!.user.userName, "admin-tool@steamwar.de")))
|
||||||
|
}
|
||||||
|
|
||||||
|
call.respond(res.status)
|
||||||
|
}
|
||||||
|
put {
|
||||||
|
@Serializable
|
||||||
|
data class UpdateGiteaPageRequest(val content: String, val sha: String, val message: String, val branch: String, val author: Identity)
|
||||||
|
|
||||||
|
val data = call.receive<UpdatePageRequest>()
|
||||||
|
val path = pathPageIdMap.entries.find { it.value == call.parameters["id"]?.toIntOrNull() }?.key ?: return@put call.respond(HttpStatusCode.NotFound, "Page not found")
|
||||||
|
|
||||||
|
val res = client.put("repos/SteamWar/Website/contents/$path") {
|
||||||
|
contentType(ContentType.Application.Json)
|
||||||
|
setBody(UpdateGiteaPageRequest(data.content, data.sha, data.message, (call.request.queryParameters["branch"] ?: "master"), Identity(call.principal<SWAuthPrincipal>()!!.user.userName, "admin-tool@steamwar.de")))
|
||||||
|
}
|
||||||
|
|
||||||
|
call.respond(res.status)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
route("images") {
|
||||||
|
get {
|
||||||
|
val branch = call.request.queryParameters["branch"] ?: "master"
|
||||||
|
|
||||||
put("{id}") {
|
call.respond(filesInDirectory("/src/images", branch))
|
||||||
@Serializable
|
|
||||||
data class UpdateGiteaPageRequest(val content: String, val sha: String, val message: String, val branch: String, val author: Identity)
|
|
||||||
|
|
||||||
val data = call.receive<UpdatePageRequest>()
|
|
||||||
val path = pathPageIdMap.entries.find { it.value == call.parameters["id"]?.toIntOrNull() }?.key ?: return@put call.respond(HttpStatusCode.NotFound, "Page not found")
|
|
||||||
|
|
||||||
val res = client.put("repos/SteamWar/Website/contents/$path") {
|
|
||||||
contentType(ContentType.Application.Json)
|
|
||||||
setBody(UpdateGiteaPageRequest(data.content, data.sha, data.message, (call.request.queryParameters["branch"] ?: "master"), Identity(call.principal<SWAuthPrincipal>()!!.user.userName, "admin-tool@steamwar.de")))
|
|
||||||
}
|
}
|
||||||
|
post {
|
||||||
|
val req = call.receive<AddImageRequest>()
|
||||||
|
|
||||||
call.respond(res.status)
|
client.post("repos/SteamWar/Website/contents/src/images/${req.name}") {
|
||||||
|
contentType(ContentType.Application.Json)
|
||||||
|
setBody(CreateGiteaPageRequest(
|
||||||
|
"Add Image ${req.name}",
|
||||||
|
req.data,
|
||||||
|
call.request.queryParameters["branch"] ?: "master",
|
||||||
|
Identity(call.principal<SWAuthPrincipal>()!!.user.userName, "admin-tool@steamwar.de"
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
call.respond(HttpStatusCode.Created)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user