feat: categorie on CM

This commit is contained in:
2025-11-24 15:56:15 +01:00
parent b78b3f005b
commit b1bcf75e56
28 changed files with 1343 additions and 43 deletions

View File

@@ -0,0 +1,231 @@
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.model.TreeModel;
import fr.titionfire.ffsaf.data.repository.CategoryRepository;
import fr.titionfire.ffsaf.data.repository.CompetitionRepository;
import fr.titionfire.ffsaf.data.repository.MatchRepository;
import fr.titionfire.ffsaf.data.repository.TreeRepository;
import fr.titionfire.ffsaf.net2.data.MatchEntity;
import fr.titionfire.ffsaf.net2.data.TreeEntity;
import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
import fr.titionfire.ffsaf.utils.TreeNode;
import fr.titionfire.ffsaf.ws.CompetitionWS;
import fr.titionfire.ffsaf.ws.PermLevel;
import io.quarkus.hibernate.reactive.panache.Panache;
import io.quarkus.hibernate.reactive.panache.common.WithSession;
import io.quarkus.runtime.annotations.RegisterForReflection;
import io.quarkus.websockets.next.WebSocketConnection;
import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.unchecked.Unchecked;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import lombok.Data;
import org.hibernate.reactive.mutiny.Mutiny;
import java.util.ArrayList;
import java.util.List;
@WithSession
@ApplicationScoped
@RegisterForReflection
public class RCategorie {
//private static final Logger LOGGER = Logger.getLogger(RCategorie.class);
@Inject
CategoryRepository categoryRepository;
@Inject
CompetitionRepository competitionRepository;
@Inject
MatchRepository matchRepository;
@Inject
TreeRepository treeRepository;
@WSReceiver(code = "getAllCategory", permission = PermLevel.VIEW)
public Uni<List<JustCategorie>> getAllCategory(WebSocketConnection connection, Object o) {
return categoryRepository.list("compet.uuid", connection.pathParam("uuid"))
.map(category -> category.stream().map(JustCategorie::from).toList());
}
@WSReceiver(code = "getFullCategory", permission = PermLevel.VIEW)
public Uni<FullCategory> getFullCategory(WebSocketConnection connection, Long id) {
FullCategory fullCategory = new FullCategory();
return categoryRepository.findById(id)
.invoke(Unchecked.consumer(o -> {
if (o == null)
throw new DNotFoundException("Catégorie non trouver");
}))
.invoke(cat -> {
fullCategory.setId(cat.getId());
fullCategory.setName(cat.getName());
fullCategory.setLiceName(cat.getLiceName());
fullCategory.setType(cat.getType());
})
.call(cat -> Mutiny.fetch(cat.getMatchs())
.map(matchModels -> matchModels.stream().filter(o -> o.getCategory_ord() >= 0)
.map(MatchEntity::fromModel).toList())
.invoke(fullCategory::setMatches))
.call(cat -> treeRepository.list("category = ?1 AND level != 0", cat.getId())
.map(treeModels -> treeModels.stream().map(TreeEntity::fromModel).toList())
.invoke(fullCategory::setTrees))
.map(__ -> fullCategory);
}
@WSReceiver(code = "createCategory", permission = PermLevel.ADMIN)
public Uni<Long> createCategory(WebSocketConnection connection, JustCategorie categorie) {
return competitionRepository.find("uuid", connection.pathParam("uuid")).firstResult()
.chain(cm -> {
CategoryModel categoryModel = new CategoryModel();
categoryModel.setName(categorie.name);
categoryModel.setCompet(cm);
categoryModel.setMatchs(new ArrayList<>());
categoryModel.setTree(new ArrayList<>());
categoryModel.setType(categorie.type);
categoryModel.setLiceName(categorie.liceName);
return categoryRepository.create(categoryModel);
})
.call(cat -> CompetitionWS.sendNotifyToOtherEditor(connection, "sendAddCategory",
JustCategorie.from(cat)))
.map(CategoryModel::getId);
}
@WSReceiver(code = "updateCategory", permission = PermLevel.ADMIN)
public Uni<Void> updateCategory(WebSocketConnection connection, JustCategorie categorie) {
return categoryRepository.findById(categorie.id)
.invoke(Unchecked.consumer(o -> {
if (o == null)
throw new DNotFoundException("Catégorie non trouver");
}))
.chain(cat -> {
cat.setName(categorie.name);
cat.setLiceName(categorie.liceName);
cat.setType(categorie.type);
return Panache.withTransaction(() -> categoryRepository.persist(cat));
})
.call(cat -> {
Uni<Long> uni = Uni.createFrom().nullItem();
if ((categorie.type() & 1) == 0)
uni = uni.chain(__ -> matchRepository.delete("category = ?1 AND category_ord >= 0", cat));
if ((categorie.type() & 2) == 0) {
uni = uni.chain(__ -> treeRepository.delete("category = ?1", cat.getId()))
.chain(__ -> matchRepository.delete("category = ?1 AND category_ord = -42", cat));
}
return uni;
})
.call(cat -> CompetitionWS.sendNotifyToOtherEditor(connection, "sendCategory", JustCategorie.from(cat)))
.replaceWithVoid();
}
private Uni<TreeModel> getOrCreateTreeNode(Long id, Long categorieId, int level) {
if (id == null) {
TreeModel treeModel = new TreeModel();
treeModel.setCategory(categorieId);
treeModel.setLevel(level);
return Panache.withTransaction(() -> treeRepository.persistAndFlush(treeModel));
} else {
return Panache.withTransaction(
() -> treeRepository.find("match.id = ?1", id).firstResult()
.invoke(t -> t.setLevel(level))
.chain(t -> treeRepository.persist(t)));
}
}
private Uni<Void> updateNode(TreeNode<Long> current, TreeModel currentTreeModel, CategoryModel category) {
return Uni.createFrom().item(currentTreeModel)
.chain(t -> {
if (current.getData() != null)
return Uni.createFrom().item(t);
MatchModel matchModel = new MatchModel();
matchModel.setCategory(category);
matchModel.setCategory_ord(-42);
matchModel.setEnd(false);
return matchRepository.create(matchModel).onItem()
.invoke(t::setMatch)
.chain(__ -> treeRepository.persistAndFlush(t));
})
.call(t -> {
if (current.getLeft() == null)
return Uni.createFrom().item(t);
return getOrCreateTreeNode(current.getLeft().getData(), category.getId(), 0)
.invoke(t::setLeft)
.call(treeModel -> updateNode(current.getLeft(), treeModel, category));
})
.call(t -> {
if (current.getRight() == null)
return Uni.createFrom().item(t);
return getOrCreateTreeNode(current.getRight().getData(), category.getId(), 0)
.invoke(t::setRight)
.call(treeModel -> updateNode(current.getRight(), treeModel, category));
})
.chain(t -> treeRepository.persist(t))
.replaceWithVoid();
}
@WSReceiver(code = "updateTrees", permission = PermLevel.ADMIN)
public Uni<Void> updateTrees(WebSocketConnection connection, TreeUpdate data) {
return categoryRepository.findById(data.categoryId)
.invoke(Unchecked.consumer(o -> {
if (o == null)
throw new DNotFoundException("Catégorie non trouver");
}))
.call(cat -> treeRepository.update("level = -1, left = NULL, right = NULL WHERE category = ?1",
cat.getId()))
.call(cat -> {
Uni<?> uni = Uni.createFrom().voidItem();
for (int i = 0; i < data.trees().size(); i++) {
TreeNode<Long> current = data.trees().get(i);
int finalI = i;
uni = uni.chain(() -> getOrCreateTreeNode(current.getData(), cat.getId(), finalI + 1)
.call(treeModel -> updateNode(current, treeModel, cat)));
}
Uni<?> finalUni = uni;
return Panache.withTransaction(() -> finalUni);
})
.call(cat -> treeRepository.list("category = ?1 AND level = -1", cat.getId())
.map(l -> l.stream().map(o -> o.getMatch().getId()).toList())
.call(__ -> treeRepository.delete("category = ?1 AND level = -1", cat.getId()))
.call(ids -> matchRepository.delete("id IN ?1", ids)))
.call(__ -> treeRepository.flush())
.call(cat -> treeRepository.list("category = ?1 AND level != 0", cat.getId())
.map(treeModels -> treeModels.stream().map(TreeEntity::fromModel).toList())
.chain(trees -> CompetitionWS.sendNotifyToOtherEditor(connection, "sendTreeCategory", trees)))
.replaceWithVoid();
}
@RegisterForReflection
public record JustCategorie(long id, String name, int type, String liceName) {
static JustCategorie from(CategoryModel m) {
return new JustCategorie(m.getId(), m.getName(), m.getType(), m.getLiceName());
}
}
@RegisterForReflection
public record TreeUpdate(long categoryId, List<TreeNode<Long>> trees) {
}
@Data
@RegisterForReflection
public static class FullCategory {
long id;
String name;
int type;
String liceName;
List<TreeEntity> trees = null;
List<MatchEntity> matches;
}
}

View File

@@ -1,5 +1,6 @@
package fr.titionfire.ffsaf.ws.recv;
import fr.titionfire.ffsaf.ws.PermLevel;
import io.quarkus.runtime.annotations.RegisterForReflection;
import java.lang.annotation.Retention;
@@ -11,4 +12,6 @@ public @interface WSReceiver {
String code();
PermLevel permission() default PermLevel.VIEW;
}