feat: cm table matches & scores

This commit is contained in:
2025-12-07 15:12:48 +01:00
parent bb901392fc
commit 489bfeb354
9 changed files with 735 additions and 52 deletions

View File

@@ -1,18 +1,17 @@
package fr.titionfire.ffsaf.ws.recv;
import fr.titionfire.ffsaf.data.model.CategoryModel;
import fr.titionfire.ffsaf.data.model.MatchModel;
import fr.titionfire.ffsaf.data.repository.CategoryRepository;
import fr.titionfire.ffsaf.data.repository.CombRepository;
import fr.titionfire.ffsaf.data.repository.CompetitionGuestRepository;
import fr.titionfire.ffsaf.data.repository.MatchRepository;
import fr.titionfire.ffsaf.data.model.*;
import fr.titionfire.ffsaf.data.repository.*;
import fr.titionfire.ffsaf.domain.entity.MatchEntity;
import fr.titionfire.ffsaf.domain.entity.TreeEntity;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
import fr.titionfire.ffsaf.utils.ScoreEmbeddable;
import fr.titionfire.ffsaf.ws.PermLevel;
import fr.titionfire.ffsaf.ws.send.SSMatch;
import io.quarkus.hibernate.reactive.panache.Panache;
import io.quarkus.hibernate.reactive.panache.common.WithSession;
import io.quarkus.panache.common.Sort;
import io.quarkus.runtime.annotations.RegisterForReflection;
import io.quarkus.websockets.next.WebSocketConnection;
import io.smallrye.mutiny.Uni;
@@ -21,9 +20,7 @@ import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.jboss.logging.Logger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.*;
import java.util.stream.Stream;
@WithSession
@@ -41,6 +38,9 @@ public class RMatch {
@Inject
CategoryRepository categoryRepository;
@Inject
TreeRepository treeRepository;
@Inject
CompetitionGuestRepository competitionGuestRepository;
@@ -140,6 +140,140 @@ public class RMatch {
.replaceWithVoid();
}
@WSReceiver(code = "updateMatchScore", permission = PermLevel.TABLE)
public Uni<Void> updateMatchScore(WebSocketConnection connection, MatchScore score) {
return getById(score.matchId(), connection)
.chain(matchModel -> {
int old_win = matchModel.win();
Optional<ScoreEmbeddable> optional = matchModel.getScores().stream()
.filter(s -> s.getN_round() == score.n_round()).findAny();
boolean b = score.s1() != -1000 || score.s2() != -1000;
if (optional.isPresent()) {
if (b) {
optional.get().setS1(score.s1());
optional.get().setS2(score.s2());
} else {
matchModel.getScores().remove(optional.get());
}
} else if (b) {
matchModel.getScores().add(new ScoreEmbeddable(score.n_round(), score.s1(), score.s2()));
}
return Panache.withTransaction(() -> matchRepository.persist(matchModel))
.call(mm -> {
if (mm.isEnd() && mm.win() != old_win && mm.getCategory_ord() == -42) {
return updateEndAndTree(mm, new ArrayList<>())
.call(l -> SSMatch.sendMatch(connection, l));
}
return Uni.createFrom().nullItem();
});
})
.call(mm -> SSMatch.sendMatch(connection, MatchEntity.fromModel(mm)))
.replaceWithVoid();
}
@WSReceiver(code = "updateMatchEnd", permission = PermLevel.TABLE)
public Uni<Void> updateMatchEnd(WebSocketConnection connection, MatchEnd matchEnd) {
List<MatchEntity> toSend = new ArrayList<>();
return getById(matchEnd.matchId(), connection)
.chain(mm -> {
if (mm.getCategory_ord() == -42 && mm.win() == 0) { // Tournois
mm.setDate(null);
mm.setEnd(false);
} else {
mm.setDate((matchEnd.end) ? new Date() : null);
mm.setEnd(matchEnd.end);
}
return Panache.withTransaction(() -> matchRepository.persist(mm));
})
.invoke(mm -> toSend.add(MatchEntity.fromModel(mm)))
.chain(mm -> updateEndAndTree(mm, toSend))
.call(__ -> SSMatch.sendMatch(connection, toSend))
.replaceWithVoid();
}
private Uni<List<MatchEntity>> updateEndAndTree(MatchModel mm, List<MatchEntity> toSend) {
return (mm.getCategory_ord() != -42) ?
Uni.createFrom().item(toSend) :
treeRepository.list("category = ?1 AND level != 0", Sort.ascending("level"), mm.getCategory().getId())
.chain(treeModels -> {
List<TreeModel> node = treeModels.stream().flatMap(t -> t.flat().stream()).toList();
List<TreeEntity> trees = treeModels.stream().map(TreeEntity::fromModel).toList();
for (int i = 0; i < trees.size() - 1; i++) {
TreeEntity.setAssociated(trees.get(i), trees.get(i + 1));
}
TreeEntity root = trees.stream()
.filter(t -> t.getMatchNode(mm.getId()) != null)
.findFirst()
.orElseThrow();
TreeEntity currentNode = root.getMatchNode(mm.getId());
if (currentNode == null) {
LOGGER.error(
"currentNode is empty for " + mm.getId() + " in " + mm.getCategory().getId());
return Uni.createFrom().voidItem();
}
TreeEntity parent = TreeEntity.getParent(root, currentNode);
if (parent == null) {
LOGGER.error("parent is empty for " + mm.getId() + " in " + mm.getCategory().getId());
return Uni.createFrom().voidItem();
}
int w = mm.win();
MembreModel toSetWin = null;
MembreModel toSetLose = null;
CompetitionGuestModel toSetWinGuest = null;
CompetitionGuestModel toSetLoseGuest = null;
if (mm.isEnd() && w != 0) {
toSetWin = (w > 0) ? mm.getC1_id() : mm.getC2_id();
toSetLose = (w > 0) ? mm.getC2_id() : mm.getC1_id();
toSetWinGuest = (w > 0) ? mm.getC1_guest() : mm.getC2_guest();
toSetLoseGuest = (w > 0) ? mm.getC2_guest() : mm.getC1_guest();
}
MatchModel modelWin = node.stream()
.filter(n -> Objects.equals(n.getId(), parent.getId()))
.findAny()
.map(TreeModel::getMatch)
.orElseThrow();
MatchModel modelLose = (parent.getAssociatedNode() == null) ? null : node.stream()
.filter(n -> Objects.equals(n.getId(), parent.getAssociatedNode().getId()))
.findAny()
.map(TreeModel::getMatch)
.orElseThrow();
if (currentNode.equals(parent.getLeft())) {
modelWin.setC1_id(toSetWin);
modelWin.setC1_guest(toSetWinGuest);
if (modelLose != null) {
modelLose.setC1_id(toSetLose);
modelLose.setC1_guest(toSetLoseGuest);
}
} else if (currentNode.equals(parent.getRight())) {
modelWin.setC2_id(toSetWin);
modelWin.setC2_guest(toSetWinGuest);
if (modelLose != null) {
modelLose.setC2_id(toSetLose);
modelLose.setC2_guest(toSetLoseGuest);
}
}
return Panache.withTransaction(() -> matchRepository.persist(modelWin)
.invoke(mm2 -> toSend.add(MatchEntity.fromModel(mm2)))
.call(__ -> modelLose == null ? Uni.createFrom().nullItem() :
matchRepository.persist(modelLose)
.invoke(mm2 -> toSend.add(MatchEntity.fromModel(mm2)))
)
.replaceWithVoid());
})
.map(__ -> toSend);
}
@WSReceiver(code = "deleteMatch", permission = PermLevel.ADMIN)
public Uni<Void> deleteMatch(WebSocketConnection connection, Long idMatch) {
return getById(idMatch, connection)
@@ -190,6 +324,14 @@ public class RMatch {
public record MatchComb(long id, Long c1, Long c2) {
}
@RegisterForReflection
public record MatchScore(long matchId, int n_round, int s1, int s2) {
}
@RegisterForReflection
public record MatchEnd(long matchId, boolean end) {
}
@RegisterForReflection
public record MatchOrder(long id, long pos) {
}