Commit 1bd1546f authored by Torge Hamann's avatar Torge Hamann 💡

Add support for single-player-teams

parent 529a4397
Pipeline #161727281 failed with stages
in 1 minute and 4 seconds
......@@ -276,6 +276,32 @@ public class TournamentController extends AbstractController {
});
}
@RequestMapping(method = RequestMethod.POST, endpoint = "/add-single-player-team", isSecured = false)
public Response addSinglePlayerTeam(
@RequestParam(name = "token") String token,
@RequestParam(name = "tournamentId") Integer tournamentId,
@RequestParam(name = "playerUuid") String playerUuid
) {
Optional<TournamentApiToken> clientToken = getToken(token);
if (clientToken.isEmpty()) {
return new Response(INVALID_TOKEN);
}
return wrapInTransaction(() -> {
final String clientUuid = clientToken.get().getClientUuid();
final Tournament tournament = getTournament(tournamentId);
final Map<String, List<String>> result = tournamentManagement.addSinglePlayerTeam(
clientUuid, tournament, playerUuid
);
checkErrors(result);
return getResponseWithTournament(tournament, clientUuid);
});
}
@RequestMapping(method = RequestMethod.POST, endpoint = "/remove-team", isSecured = false)
public Response removeTeam(
@RequestParam(name = "token") String token,
......
......@@ -16,7 +16,16 @@ public class TeamSerialization extends AbstractEntitySerializer<Team> {
HashMap<String, Object> teamSerialization = new HashMap<>();
teamSerialization.put("id", entity.getId());
teamSerialization.put("name", entity.getName());
final boolean isSinglePlayer = entity.isSinglePlayer();
teamSerialization.put("single-player", isSinglePlayer);
String teamName = entity.getName();
if (isSinglePlayer) {
final Player player = entity.getMembers().get(0);
teamName = player.optName().orElse(player.optTsUid().map(this::clientDisplay).orElse(""));
}
teamSerialization.put("name", teamName);
String creatorUuid = entity.getCreatorUuid();
teamSerialization.put("creator", clientDisplay(creatorUuid));
......
package de.fearnixx.jeak.tournament.controller.serialization;
import de.fearnixx.jeak.reflect.Inject;
import de.fearnixx.jeak.tournament.entities.team.Player;
import de.fearnixx.jeak.tournament.entities.team.Team;
import de.fearnixx.jeak.tournament.entities.tournament.Tournament;
import de.fearnixx.jeak.tournament.entities.tournament.TournamentClassifier;
import de.fearnixx.jeak.tournament.entities.tournament.TournamentLeadershipToken;
......@@ -67,15 +69,22 @@ public class TournamentSerialization extends AbstractEntitySerializer<Tournament
.map(
tp -> {
Map<String, Object> teamParticipationInfo = new HashMap<>();
teamParticipationInfo.put("id", tp.getTeam().getId());
teamParticipationInfo.put("name", tp.getTeam().getName());
final Team team = tp.getTeam();
teamParticipationInfo.put("id", team.getId());
String teamName = team.getName();
if (team.isSinglePlayer()) {
final Player player = team.getMembers().get(0);
teamName = player.optName().orElse(player.optTsUid().map(this::clientDisplay).orElse(""));
}
teamParticipationInfo.put("name", teamName);
final boolean isReady = tp.getState().equals(ParticipationState.READY);
teamParticipationInfo.put("state", tp.getState());
teamParticipationInfo.put("ready", isReady);
teamParticipationInfo.put("can-ready", !isReady &&
(tournamentLeaders.contains(uuid) || tp.getTeam().isLeader(uuid))
(tournamentLeaders.contains(uuid) || team.isLeader(uuid))
&& tp.getState() == ParticipationState.JOINED
);
......
......@@ -13,6 +13,8 @@ import java.util.stream.Collectors;
@Table(name = "TEAM")
public class Team implements Serializable {
public static final String SINGLE_PLAYER_TEAM_PREFIX = "#SPT#";
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "TEAM_ID")
......@@ -27,6 +29,9 @@ public class Team implements Serializable {
@Column(name = "JOIN_TOKEN")
private String joinToken = UUID.randomUUID().toString();
@Column(name = "SINGLE_PLAYER")
private boolean singlePlayer;
@OneToMany(mappedBy = "team", cascade = CascadeType.REFRESH)
private List<TournamentParticipation> tournamentParticipations = new ArrayList<>();
......@@ -49,8 +54,17 @@ public class Team implements Serializable {
}
public Team(String name, String creatorUuid) {
this(name, creatorUuid, false);
}
public Team(Player player) {
this(SINGLE_PLAYER_TEAM_PREFIX + player.getId() + "", player.optTsUid().orElse(""), true);
}
private Team(String name, String creatorUuid, boolean singlePlayer) {
this.name = name;
this.creatorUuid = creatorUuid;
this.singlePlayer = singlePlayer;
}
public Integer getId() {
......@@ -77,6 +91,10 @@ public class Team implements Serializable {
this.joinToken = joinToken;
}
public boolean isSinglePlayer() {
return singlePlayer;
}
public List<TournamentParticipation> getTournamentParticipations() {
return Collections.unmodifiableList(tournamentParticipations);
}
......@@ -112,6 +130,10 @@ public class Team implements Serializable {
}
public TeamMembership createMembership(Player player, boolean active) {
if (singlePlayer && !memberships.isEmpty()) {
throw new IllegalStateException("A player can not be added to a single player team!");
}
final TeamMembership teamMembership = new TeamMembership(this, player, active);
memberships.add(teamMembership);
return teamMembership;
......
......@@ -58,7 +58,7 @@ public class Tournament implements Serializable {
@OneToMany(mappedBy = "tournament", cascade = CascadeType.PERSIST)
private List<TournamentParticipation> tournamentParticipations = new ArrayList<>();
@OneToMany(cascade = CascadeType.REFRESH)
@OneToMany(cascade = CascadeType.ALL)
@JoinTable(
name = "TOURNAMENT_PARTICIPATION",
joinColumns = @JoinColumn(name = "TOURNAMENT_ID"),
......
......@@ -8,6 +8,7 @@ public class TournamentParameter {
public static final String STAGE_PATTERN = "stage_pattern";
public static final String GAME_TIME_TRACKING = "game_time_tracking";
public static final String SINGLE_PLAYER = "single_player";
public static final String MIN_TEAM_SIZE = "min_team_size";
public static final String MAX_TEAM_SIZE = "max_team_size";
......
......@@ -249,7 +249,7 @@ public class EncounterManagement extends AbstractManagement {
}
if (tournament.optParameter(TournamentParameter.GAME_TIME_TRACKING).isPresent() && scores.stream().filter(s -> s > 0).count() != 1) {
errors.put(POINTS_KEY, Collections.singletonList("There must exactly one non-zero score in game time tracking mode!"));
errors.put(POINTS_KEY, Collections.singletonList("There must be exactly one non-zero score in game time tracking mode!"));
return errors;
}
......
......@@ -23,6 +23,7 @@ public class TeamManagement extends AbstractManagement {
private static final String TEAM_ACTIVE_TOURNAMENT_MSG =
"The team is actively participating in a tournament and no changes are allowed!";
private static final String SINGLE_PLAYER_TEAM_NOT_EDITABLE_MSG = "A single-player-team can not be edited!";
private TypedQuery<Player> playerByNameQuery;
private TypedQuery<Player> playerByUUIDQuery;
......@@ -94,6 +95,10 @@ public class TeamManagement extends AbstractManagement {
return createSingleResult(TEAM_NAME_KEY, "The team name is invalid!");
}
if (team.isSinglePlayer()) {
return createSingleResult(TEAM_NAME_KEY, SINGLE_PLAYER_TEAM_NOT_EDITABLE_MSG);
}
newTeamName = optTeamName.get();
if (entityManagement.getTeamByName(newTeamName).isPresent()) {
......@@ -157,6 +162,10 @@ public class TeamManagement extends AbstractManagement {
return createSingleResult(TOKEN_KEY, "Invalid token for the team '" + teamName + "'");
}
if (team.isSinglePlayer()) {
return createSingleResult(TEAM_NAME_KEY, SINGLE_PLAYER_TEAM_NOT_EDITABLE_MSG);
}
if (checkActiveTournaments(team)) {
return createSingleResult(TEAM_ACTIVE_TOURNAMENT_KEY, TEAM_ACTIVE_TOURNAMENT_MSG);
}
......@@ -190,6 +199,11 @@ public class TeamManagement extends AbstractManagement {
if (optTeamMembership.isEmpty()) {
return createSingleResult("user", "You are not a member of the team '" + team.getName() + "'");
}
if (team.isSinglePlayer()) {
return createSingleResult(TEAM_NAME_KEY, SINGLE_PLAYER_TEAM_NOT_EDITABLE_MSG);
}
TeamMembership teamMembership = optTeamMembership.get();
if (teamMembership.isActive() && checkActiveTournaments(team)) {
......@@ -216,6 +230,10 @@ public class TeamManagement extends AbstractManagement {
return getNotAllowedResponse();
}
if (team.isSinglePlayer()) {
return createSingleResult(TEAM_NAME_KEY, SINGLE_PLAYER_TEAM_NOT_EDITABLE_MSG);
}
if (newJoinToken == null) {
messagingService.sendTextMessageToClient(
uuid, "The token for team '" + team.getName() + "': " + team.getJoinToken()
......@@ -243,6 +261,10 @@ public class TeamManagement extends AbstractManagement {
public Map<String, List<String>> leaderToken(String uuid, Team team, String leaderToken) {
boolean transactionWasActive = entityManagement.beginTransaction();
if (team.isSinglePlayer()) {
return createSingleResult(TEAM_NAME_KEY, SINGLE_PLAYER_TEAM_NOT_EDITABLE_MSG);
}
if (leaderToken == null) {
if (!team.isLeader(uuid)) {
return getNotAllowedResponse();
......@@ -312,6 +334,10 @@ public class TeamManagement extends AbstractManagement {
return getNotAllowedResponse();
}
if (team.isSinglePlayer()) {
return createSingleResult(TEAM_NAME_KEY, SINGLE_PLAYER_TEAM_NOT_EDITABLE_MSG);
}
String uuidToRemove;
if (leaderUuid == null) {
......@@ -434,6 +460,10 @@ public class TeamManagement extends AbstractManagement {
return getNotAllowedResponse();
}
if (team.isSinglePlayer()) {
return createSingleResult(TEAM_NAME_KEY, SINGLE_PLAYER_TEAM_NOT_EDITABLE_MSG);
}
if (checkActiveTournaments(team)) {
return createSingleResult(TEAM_ACTIVE_TOURNAMENT_KEY, TEAM_ACTIVE_TOURNAMENT_MSG);
}
......@@ -516,6 +546,10 @@ public class TeamManagement extends AbstractManagement {
return getNotAllowedResponse();
}
if (team.isSinglePlayer()) {
return createSingleResult(TEAM_NAME_KEY, SINGLE_PLAYER_TEAM_NOT_EDITABLE_MSG);
}
if (checkActiveTournaments(team)) {
return createSingleResult(TEAM_ACTIVE_TOURNAMENT_KEY, TEAM_ACTIVE_TOURNAMENT_MSG);
}
......@@ -585,6 +619,10 @@ public class TeamManagement extends AbstractManagement {
return getNotAllowedResponse();
}
if (team.isSinglePlayer()) {
return createSingleResult(TEAM_NAME_KEY, SINGLE_PLAYER_TEAM_NOT_EDITABLE_MSG);
}
if (checkActiveTournaments(team)) {
return createSingleResult(TEAM_ACTIVE_TOURNAMENT_KEY, TEAM_ACTIVE_TOURNAMENT_MSG);
}
......@@ -629,7 +667,7 @@ public class TeamManagement extends AbstractManagement {
}
private Optional<String> checkTeamName(String teamName) {
if (teamName.isBlank()) {
if (teamName.isBlank() || teamName.startsWith(Team.SINGLE_PLAYER_TEAM_PREFIX)) {
return Optional.empty();
}
......
......@@ -42,6 +42,7 @@ public class TournamentManagement extends AbstractManagement {
private TypedQuery<TournamentClassifier> classifierQuery;
private TypedQuery<Season> seasonQuery;
private TypedQuery<Player> playerByUidQuery;
public void init() {
classifierQuery = entityManagement.getEntityManager()
......@@ -49,6 +50,9 @@ public class TournamentManagement extends AbstractManagement {
seasonQuery = entityManagement.getEntityManager()
.createQuery("SELECT s FROM Season s WHERE name = :name", Season.class);
playerByUidQuery = entityManagement.getEntityManager()
.createQuery("SELECT p FROM Player p WHERE tsUid = :uuid", Player.class);
}
public Map<String, List<String>> createTournament(String uuid, String tournamentName) {
......@@ -165,6 +169,11 @@ public class TournamentManagement extends AbstractManagement {
return Map.of(TEAM_KEY, teamSizeErrors);
}
final boolean isSinglePlayerTournament = tournament.optParameter(TournamentParameter.SINGLE_PLAYER).isPresent();
if (team.isSinglePlayer() != isSinglePlayerTournament) {
return createSingleResult(TOURNAMENT_KEY, "The tournament" + (isSinglePlayerTournament ? " is " : " is not ") + " a single-player-tournament and the team is not eligible!");
}
tournament.createTournamentParticipation(team);
entityManagement.getEntityManager().persist(tournament);
......@@ -259,6 +268,52 @@ public class TournamentManagement extends AbstractManagement {
return new HashMap<>();
}
public Map<String, List<String>> addSinglePlayerTeam(String uuid, Tournament tournament, String playerUuid) {
entityManagement.beginTransaction();
List<Player> playerSearchResult = playerByUidQuery
.setParameter("uuid", playerUuid)
.getResultList();
Player player;
Team team;
boolean isNewTeam = true;
if (playerSearchResult.isEmpty()) {
player = Player.createByTsUid(playerUuid);
entityManagement.getEntityManager().persist(player);
entityManagement.getEntityManager().getTransaction().commit();
entityManagement.beginTransaction();
player = playerByUidQuery.setParameter("uuid", playerUuid).getResultList().get(0);
}else{
player = playerSearchResult.get(0);
}
List<Team> singlePlayerTeamSearchResult = entityManagement.getEntityManager()
.createQuery("SELECT t FROM Team t WHERE name = :name", Team.class)
.setParameter("name", Team.SINGLE_PLAYER_TEAM_PREFIX + player.getId())
.getResultList();
if (singlePlayerTeamSearchResult.isEmpty()) {
team = new Team(player);
} else {
team = singlePlayerTeamSearchResult.get(0);
isNewTeam = false;
}
if (isNewTeam) {
team = new Team(player);
team.createMembership(player, true);
team.createLeadership(playerUuid);
entityManagement.getEntityManager().persist(team);
}
return addTeam(uuid, tournament, team);
}
public Map<String, List<String>> addTeam(String uuid, Tournament tournament, Team team) {
boolean transactionWasActive = entityManagement.beginTransaction();
......@@ -278,6 +333,11 @@ public class TournamentManagement extends AbstractManagement {
return createSingleResult(TOURNAMENT_KEY, "At least one member of '" + team.getName() + "' is already actively participating in the tournament!");
}
final boolean isSinglePlayerTournament = tournament.optParameter(TournamentParameter.SINGLE_PLAYER).isPresent();
if (team.isSinglePlayer() != isSinglePlayerTournament) {
return createSingleResult(TOURNAMENT_KEY, "The tournament" + (isSinglePlayerTournament ? " is " : " is not ") + " a single-player-tournament and the team is not eligible!");
}
tournament.createTournamentParticipation(team);
entityManagement.getEntityManager().persist(tournament);
......@@ -664,6 +724,10 @@ public class TournamentManagement extends AbstractManagement {
tournament.createTournamentParameter(key, value);
entityManagement.getEntityManager().persist(tournament);
if (key.equals(TournamentParameter.SINGLE_PLAYER) && tournament.getTeams().stream().anyMatch(t -> !t.isSinglePlayer())) {
return createSingleResult("param:key", "The single-player-parameter can not be set, since non-single-player teams have already been added!");
}
message += key + "' was added and set to: " + value;
}
} else {
......
......@@ -171,7 +171,8 @@ CREATE TABLE TEAM (
TEAM_ID INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
NAME VARCHAR(100) NOT NULL UNIQUE,
CREATOR_UUID VARCHAR(60) NOT NULL,
JOIN_TOKEN VARCHAR(60) NOT NULL
JOIN_TOKEN VARCHAR(60) NOT NULL,
SINGLE_PLAYER BOOLEAN NOT NULL
);
CREATE TABLE PLAYER (
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment