diff --git a/src/main/java/fr/titionfire/ffsaf/data/model/CombModel.java b/src/main/java/fr/titionfire/ffsaf/data/model/CombModel.java new file mode 100644 index 0000000..f8fe1f7 --- /dev/null +++ b/src/main/java/fr/titionfire/ffsaf/data/model/CombModel.java @@ -0,0 +1,9 @@ +package fr.titionfire.ffsaf.data.model; + +import fr.titionfire.ffsaf.utils.ResultPrivacy; + +public interface CombModel { + Long getCombId(); + String getName(); + String getName(MembreModel model, ResultPrivacy privacy); +} diff --git a/src/main/java/fr/titionfire/ffsaf/data/model/CompetitionGuestModel.java b/src/main/java/fr/titionfire/ffsaf/data/model/CompetitionGuestModel.java index 697de65..4868c3a 100644 --- a/src/main/java/fr/titionfire/ffsaf/data/model/CompetitionGuestModel.java +++ b/src/main/java/fr/titionfire/ffsaf/data/model/CompetitionGuestModel.java @@ -2,6 +2,7 @@ package fr.titionfire.ffsaf.data.model; import fr.titionfire.ffsaf.utils.Categorie; import fr.titionfire.ffsaf.utils.Genre; +import fr.titionfire.ffsaf.utils.ResultPrivacy; import io.quarkus.runtime.annotations.RegisterForReflection; import jakarta.persistence.*; import lombok.AllArgsConstructor; @@ -17,7 +18,7 @@ import lombok.Setter; @Entity @Table(name = "competition_guest") -public class CompetitionGuestModel { +public class CompetitionGuestModel implements CombModel { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) Long id; @@ -44,7 +45,18 @@ public class CompetitionGuestModel { this.lname = s.substring(s.indexOf(" ") + 1); } + @Override + public Long getCombId() { + return this.id * -1; + } + + @Override public String getName() { - return fname + " " + lname; + return this.fname + " " + this.lname; + } + + @Override + public String getName(MembreModel model, ResultPrivacy privacy) { + return getName(); } } diff --git a/src/main/java/fr/titionfire/ffsaf/data/model/MatchModel.java b/src/main/java/fr/titionfire/ffsaf/data/model/MatchModel.java index a6b9d73..7fb7b9a 100644 --- a/src/main/java/fr/titionfire/ffsaf/data/model/MatchModel.java +++ b/src/main/java/fr/titionfire/ffsaf/data/model/MatchModel.java @@ -1,6 +1,7 @@ package fr.titionfire.ffsaf.data.model; import fr.titionfire.ffsaf.utils.CompetitionSystem; +import fr.titionfire.ffsaf.utils.ResultPrivacy; import fr.titionfire.ffsaf.utils.ScoreEmbeddable; import io.quarkus.runtime.annotations.RegisterForReflection; import jakarta.persistence.*; @@ -9,6 +10,7 @@ import lombok.*; import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Objects; @Getter @Setter @@ -65,19 +67,35 @@ public class MatchModel { @JoinColumn(name = "match", referencedColumnName = "id") List cardboard = new ArrayList<>(); + public String getC1Name(MembreModel model, ResultPrivacy privacy) { + if (c1_id != null) + return c1_id.getName(model, privacy); + if (c1_guest != null) + return c1_guest.getName(model, privacy); + return ""; + } + + public String getC2Name(MembreModel model, ResultPrivacy privacy) { + if (c2_id != null) + return c2_id.getName(model, privacy); + if (c2_guest != null) + return c2_guest.getName(model, privacy); + return ""; + } + public String getC1Name() { if (c1_id != null) - return c1_id.fname + " " + c1_id.lname; + return c1_id.getName(); if (c1_guest != null) - return c1_guest.fname + " " + c1_guest.lname; + return c1_guest.getName(); return ""; } public String getC2Name() { if (c2_id != null) - return c2_id.fname + " " + c2_id.lname; + return c2_id.getName(); if (c2_guest != null) - return c2_guest.fname + " " + c2_guest.lname; + return c2_guest.getName(); return ""; } @@ -94,4 +112,24 @@ public class MatchModel { } return sum; } + + public boolean isC1(Object comb) { + if (comb instanceof Long id_) { + if (id_ >= 0) + return Objects.equals(this.c1_id != null ? this.c1_id.getId() : null, id_); + else + return Objects.equals(this.c1_guest != null ? this.c1_guest.getId() : null, -id_); + } + return Objects.equals(this.c1_id, comb) || Objects.equals(this.c1_guest, comb); + } + + public boolean isC2(Object comb) { + if (comb instanceof Long id_) { + if (id_ >= 0) + return Objects.equals(this.c2_id != null ? this.c2_id.getId() : null, id_); + else + return Objects.equals(this.c2_guest != null ? this.c2_guest.getId() : null, -id_); + } + return Objects.equals(this.c2_id, comb) || Objects.equals(this.c2_guest, comb); + } } diff --git a/src/main/java/fr/titionfire/ffsaf/data/model/MembreModel.java b/src/main/java/fr/titionfire/ffsaf/data/model/MembreModel.java index 218c8c9..d83f232 100644 --- a/src/main/java/fr/titionfire/ffsaf/data/model/MembreModel.java +++ b/src/main/java/fr/titionfire/ffsaf/data/model/MembreModel.java @@ -1,9 +1,6 @@ package fr.titionfire.ffsaf.data.model; -import fr.titionfire.ffsaf.utils.Categorie; -import fr.titionfire.ffsaf.utils.Genre; -import fr.titionfire.ffsaf.utils.GradeArbitrage; -import fr.titionfire.ffsaf.utils.RoleAsso; +import fr.titionfire.ffsaf.utils.*; import io.quarkus.runtime.annotations.RegisterForReflection; import jakarta.persistence.*; import lombok.*; @@ -11,6 +8,7 @@ import org.eclipse.microprofile.openapi.annotations.media.Schema; import java.util.Date; import java.util.List; +import java.util.Objects; @Getter @Setter @@ -21,23 +19,23 @@ import java.util.List; @Entity @Table(name = "membre") -public class MembreModel implements LoggableModel { +public class MembreModel implements LoggableModel, CombModel { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Access(AccessType.PROPERTY) - @Schema(description = "L'identifiant du membre.", example = "1") + @Schema(description = "L'identifiant du membre.", examples = "1") Long id; - @Schema(description = "L'identifiant long du membre (userID).", example = "e81d1d35-d897-421e-8086-6c5e74d13c6e") + @Schema(description = "L'identifiant long du membre (userID).", examples = "e81d1d35-d897-421e-8086-6c5e74d13c6e") String userId; - @Schema(description = "Le nom du membre.", example = "Dupont") + @Schema(description = "Le nom du membre.", examples = "Dupont") String lname; - @Schema(description = "Le prénom du membre.", example = "Jean") + @Schema(description = "Le prénom du membre.", examples = "Jean") String fname; - @Schema(description = "La catégorie du membre.", example = "SENIOR") + @Schema(description = "La catégorie du membre.", examples = "SENIOR") Categorie categorie; @ManyToOne(fetch = FetchType.EAGER) @@ -45,29 +43,30 @@ public class MembreModel implements LoggableModel { @Schema(description = "Le club du membre.") ClubModel club; - @Schema(description = "Le genre du membre.", example = "H") + @Schema(description = "Le genre du membre.", examples = "H") Genre genre; - @Schema(description = "Le numéro de licence du membre.", example = "12345") + @Schema(description = "Le numéro de licence du membre.", examples = "12345") Integer licence; - @Schema(description = "Le pays du membre.", example = "FR") + @Schema(description = "Le pays du membre.", examples = "FR") String country; @Schema(description = "La date de naissance du membre.") Date birth_date; - @Schema(description = "L'adresse e-mail du membre.", example = "jean.dupont@example.com") + @Schema(description = "L'adresse e-mail du membre.", examples = "jean.dupont@examples.com") String email; - @Schema(description = "Le rôle du membre dans l'association.", example = "MEMBRE") + @Schema(description = "Le rôle du membre dans l'association.", examples = "MEMBRE") RoleAsso role; - @Schema(description = "Le grade d'arbitrage du membre.", example = "NA") + @Schema(description = "Le grade d'arbitrage du membre.", examples = "NA") GradeArbitrage grade_arbitrage; - @Schema(hidden = true) - String url_photo; + @Schema(description = "La confidentialité de ces résultats", examples = "PUBLIC") + @Column(nullable = false, columnDefinition = "smallint default 0") + ResultPrivacy resultPrivacy = ResultPrivacy.PUBLIC; @OneToMany(mappedBy = "membre", fetch = FetchType.LAZY, cascade = CascadeType.ALL) @Schema(description = "Les licences du membre. (optionnel)") @@ -100,4 +99,25 @@ public class MembreModel implements LoggableModel { ", grade_arbitrage=" + grade_arbitrage + '}'; } + + @Override + public Long getCombId() { + return this.id; + } + + @Override + public String getName() { + return this.fname + " " + this.lname; + } + + @Override + public String getName(MembreModel model, ResultPrivacy privacy) { + if (model == null || !Objects.equals(this.getId(), model.getId())) { + if (model == null && this.getResultPrivacy() != ResultPrivacy.PUBLIC) + return "Anonyme"; + if (this.getResultPrivacy().ordinal() > privacy.ordinal()) + return "Anonyme"; + } + return getName(); + } } diff --git a/src/main/java/fr/titionfire/ffsaf/domain/entity/MembreEntity.java b/src/main/java/fr/titionfire/ffsaf/domain/entity/MembreEntity.java deleted file mode 100644 index f979fb4..0000000 --- a/src/main/java/fr/titionfire/ffsaf/domain/entity/MembreEntity.java +++ /dev/null @@ -1,64 +0,0 @@ -package fr.titionfire.ffsaf.domain.entity; - -import fr.titionfire.ffsaf.data.model.MembreModel; -import fr.titionfire.ffsaf.utils.Categorie; -import fr.titionfire.ffsaf.utils.Genre; -import fr.titionfire.ffsaf.utils.GradeArbitrage; -import fr.titionfire.ffsaf.utils.RoleAsso; -import io.quarkus.runtime.annotations.RegisterForReflection; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; - -import java.util.Date; - -@Data -@Builder -@AllArgsConstructor -@RegisterForReflection -public class MembreEntity { - private long id; - private String lname = ""; - private String fname = ""; - private Categorie categorie; - private ClubEntity club; - private Genre genre; - private Integer licence; - private String country; - private Date birth_date; - private String email; - private RoleAsso role; - private GradeArbitrage grade_arbitrage; - private String url_photo; - - - public static MembreEntity fromModel(MembreModel model) { - if (model == null) - return null; - - return new MembreEntityBuilder() - .id(model.getId()) - .lname(model.getLname()) - .fname(model.getFname()) - .categorie(model.getCategorie()) - .club(ClubEntity.fromModel(model.getClub())) - .genre(model.getGenre()) - .licence(model.getLicence()) - .country(model.getCountry()) - .birth_date(model.getBirth_date()) - .email(model.getEmail()) - .role(model.getRole()) - .grade_arbitrage(model.getGrade_arbitrage()) - .url_photo(model.getUrl_photo()) - .build(); - } - - public static String getFullName(MembreModel model) { - return model.getFname() + " " + model.getLname(); - } - public String getFullName() { - return this.fname + " " + this.lname; - } - - -} diff --git a/src/main/java/fr/titionfire/ffsaf/domain/service/ResultService.java b/src/main/java/fr/titionfire/ffsaf/domain/service/ResultService.java index e83009c..6b7afeb 100644 --- a/src/main/java/fr/titionfire/ffsaf/domain/service/ResultService.java +++ b/src/main/java/fr/titionfire/ffsaf/domain/service/ResultService.java @@ -3,6 +3,7 @@ package fr.titionfire.ffsaf.domain.service; import fr.titionfire.ffsaf.data.model.*; import fr.titionfire.ffsaf.data.repository.*; import fr.titionfire.ffsaf.rest.data.ResultCategoryData; +import fr.titionfire.ffsaf.rest.exception.DBadRequestException; import fr.titionfire.ffsaf.rest.exception.DForbiddenException; import fr.titionfire.ffsaf.utils.*; import io.quarkus.hibernate.reactive.panache.common.WithSession; @@ -16,9 +17,8 @@ import lombok.Builder; import org.hibernate.reactive.mutiny.Mutiny; import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; @WithSession @@ -48,6 +48,50 @@ public class ResultService { private static final ResourceBundle BUNDLE = ResourceBundle.getBundle("lang.String"); + private static final HashMap combTempIds = new HashMap<>(); + + private static String getCombTempId(Long key) { + synchronized (combTempIds) { + if (!combTempIds.containsKey(key)) { + combTempIds.put(key, UUID.randomUUID().toString()); + } + return combTempIds.get(key); + } + } + + private static Long getCombTempId(String value) { + synchronized (combTempIds) { + for (Map.Entry entry : combTempIds.entrySet()) { + if (entry.getValue().equals(value)) { + return entry.getKey(); + } + } + return null; + } + } + + private static final HashMap clubTempIds = new HashMap<>(); + + private static Long getClubTempId(String key) { + synchronized (clubTempIds) { + if (!clubTempIds.containsKey(key)) { + clubTempIds.put(key, (System.currentTimeMillis() + clubTempIds.size()) * -1); + } + return clubTempIds.get(key); + } + } + + private static String getClubTempId(Long value) { + synchronized (clubTempIds) { + for (Map.Entry entry : clubTempIds.entrySet()) { + if (entry.getValue().equals(value)) { + return entry.getKey(); + } + } + return null; + } + } + public Uni> getList(SecurityCtx securityCtx) { return membreService.getByAccountId(securityCtx.getSubject()) .chain(m -> registerRepository.list("membre = ?1", m)) @@ -70,11 +114,10 @@ public class ResultService { } public Uni> getCategory(String uuid, SecurityCtx securityCtx) { + AtomicReference membreModel = new AtomicReference<>(); return hasAccess(uuid, securityCtx) - .chain(m -> categoryRepository.list("compet.uuid = ?1", uuid) - .chain(cats -> matchRepository.list( - "(c1_id = ?1 OR c2_id = ?1 OR True) AND category IN ?2", //TODO rm OR True - m.getMembre(), cats))) + .invoke(m -> membreModel.set(m.getMembre())) + .chain(m -> matchRepository.list("category.compet.uuid = ?1", uuid)) .map(matchModels -> { HashMap> map = new HashMap<>(); for (MatchModel matchModel : matchModels) { @@ -88,12 +131,11 @@ public class ResultService { .onItem() .transformToMulti(Multi.createFrom()::iterable) .onItem().call(list -> Mutiny.fetch(list.get(0).getCategory().getTree())) - .onItem().transform(this::getData) + .onItem().transform(list -> getData(list, membreModel.get())) .collect().asList(); - } - private ResultCategoryData getData(List matchModels) { + private ResultCategoryData getData(List matchModels, MembreModel membreModel) { ResultCategoryData out = new ResultCategoryData(); CategoryModel categoryModel = matchModels.get(0).getCategory(); @@ -102,12 +144,12 @@ public class ResultService { out.setLiceName(categoryModel.getLiceName() == null ? new String[]{} : categoryModel.getLiceName().split(";")); out.setGenTime(System.currentTimeMillis()); - getArray2(matchModels, out); - getTree(categoryModel.getTree(), out); + getArray2(matchModels, membreModel, out); + getTree(categoryModel.getTree(), membreModel, out); return out; } - private void getArray2(List matchModels_, ResultCategoryData out) { + private void getArray2(List matchModels_, MembreModel membreModel, ResultCategoryData out) { List matchModels = matchModels_.stream().filter(o -> o.getCategory_ord() >= 0).toList(); HashMap> matchMap = new HashMap<>(); @@ -121,31 +163,30 @@ public class ResultService { matchMap.forEach((c, matchEntities) -> { List matchs = matchEntities.stream() .sorted(Comparator.comparing(MatchModel::getCategory_ord)) - .map(ResultCategoryData.PouleArrayData::fromModel) + .map(o -> ResultCategoryData.PouleArrayData.fromModel(o, membreModel, + ResultPrivacy.REGISTERED_ONLY_NO_DETAILS)) .toList(); List rankArray = matchEntities.stream() - .flatMap(m -> Stream.of(m.getC1Name(), m.getC2Name())) + .flatMap(m -> Stream.of(m.getC1_id(), m.getC2_id(), m.getC1_guest(), m.getC2_guest())) .distinct() - .map(combName -> { + .filter(Objects::nonNull) + .map(comb -> { AtomicInteger w = new AtomicInteger(0); AtomicInteger pointMake = new AtomicInteger(0); AtomicInteger pointTake = new AtomicInteger(0); matchEntities.stream() - .filter(m -> m.isEnd() && (m.getC1Name().equals(combName) || m.getC2Name() - .equals(combName))) + .filter(m -> m.isEnd() && (m.isC1(comb) || m.isC2(comb))) .forEach(matchModel -> { int win = matchModel.win(); - if ((matchModel.getC1Name() - .equals(combName) && win > 0) || matchModel.getC2Name() - .equals(combName) && win < 0) + if ((matchModel.isC1(comb) && win > 0) || matchModel.isC2(comb) && win < 0) w.getAndIncrement(); for (ScoreEmbeddable score : matchModel.getScores()) { if (score.getS1() <= -900 || score.getS2() <= -900) continue; - if (matchModel.getC1Name().equals(combName)) { + if (matchModel.isC1(comb)) { pointMake.addAndGet(score.getS1()); pointTake.addAndGet(score.getS2()); } else { @@ -156,7 +197,8 @@ public class ResultService { }); float pointRate = (pointTake.get() == 0) ? pointMake.get() : (float) pointMake.get() / pointTake.get(); - return new ResultCategoryData.RankArray(0, combName, w.get(), + return new ResultCategoryData.RankArray(0, + comb.getName(membreModel, ResultPrivacy.REGISTERED_ONLY_NO_DETAILS), w.get(), pointMake.get(), pointTake.get(), pointRate); }) .sorted(Comparator @@ -180,29 +222,30 @@ public class ResultService { }); } - private static void convertTree(TreeModel src, TreeNode dst) { - dst.setData(ResultCategoryData.TreeData.from(src.getMatch())); + private static void convertTree(TreeModel src, TreeNode dst, MembreModel membreModel, + ResultPrivacy privacy) { + dst.setData(ResultCategoryData.TreeData.from(src.getMatch(), membreModel, privacy)); if (src.getLeft() != null) { dst.setLeft(new TreeNode<>()); - convertTree(src.getLeft(), dst.getLeft()); + convertTree(src.getLeft(), dst.getLeft(), membreModel, privacy); } if (src.getRight() != null) { dst.setRight(new TreeNode<>()); - convertTree(src.getRight(), dst.getRight()); + convertTree(src.getRight(), dst.getRight(), membreModel, privacy); } } public Uni getCategoryPublic(String uuid, long poule) { return matchRepository.list("category.compet.uuid = ?1 AND category.id = ?2", uuid, poule) .call(list -> Mutiny.fetch(list.get(0).getCategory().getTree())) - .map(this::getData); + .map(list -> getData(list, null)); } - private void getTree(List treeModels, ResultCategoryData out) { + private void getTree(List treeModels, MembreModel membreModel, ResultCategoryData out) { ArrayList> trees = new ArrayList<>(); treeModels.stream().filter(t -> t.getLevel() != 0).forEach(treeModel -> { TreeNode root = new TreeNode<>(); - convertTree(treeModel, root); + convertTree(treeModel, root, membreModel, ResultPrivacy.REGISTERED_ONLY_NO_DETAILS); trees.add(root); }); out.setTrees(trees); @@ -210,14 +253,14 @@ public class ResultService { public Uni getAllCombArray(String uuid, SecurityCtx securityCtx) { return hasAccess(uuid, securityCtx) - .chain(__ -> getAllCombArray(uuid)); + .chain(r -> getAllCombArray_(uuid, r.getMembre())); } public Uni getAllCombArrayPublic(String uuid) { - return getAllCombArray(uuid); + return getAllCombArray_(uuid, null); } - public Uni getAllCombArray(String uuid) { + private Uni getAllCombArray_(String uuid, MembreModel membreModel) { return registerRepository.list("competition.uuid = ?1", uuid) .chain(registers -> matchRepository.list("category.compet.uuid = ?1", uuid) .map(matchModels -> new Pair<>(registers, matchModels))) @@ -228,57 +271,42 @@ public class ResultService { CombsArrayData.CombsArrayDataBuilder builder = CombsArrayData.builder(); List combs = matchModels.stream() - .flatMap(m -> Stream.of(m.getC1Name(), m.getC2Name())) + .flatMap(m -> Stream.of(m.getC1_id(), m.getC2_id(), m.getC1_guest(), m.getC2_guest())) .filter(Objects::nonNull) .distinct() - .map(combName -> { + .map(comb -> { var builder2 = CombsArrayData.CombsData.builder(); AtomicInteger w = new AtomicInteger(0); AtomicInteger l = new AtomicInteger(0); AtomicInteger pointMake = new AtomicInteger(); AtomicInteger pointTake = new AtomicInteger(); - matchModels.stream() - .filter(m -> m.isEnd() && (m.getC1Name().equals(combName) - || m.getC2Name().equals(combName))) - .forEach(matchModel -> { - int win = matchModel.win(); - if ((combName.equals(matchModel.getC1Name()) && win > 0) || - combName.equals(matchModel.getC2Name()) && win < 0) { - w.getAndIncrement(); - } else { - l.getAndIncrement(); - } - - matchModel.getScores().stream() - .filter(s -> s.getS1() > -900 && s.getS2() > -900) - .forEach(score -> { - if (combName.equals(matchModel.getC1Name())) { - pointMake.addAndGet(score.getS1()); - pointTake.addAndGet(score.getS2()); - } else { - pointMake.addAndGet(score.getS2()); - pointTake.addAndGet(score.getS1()); - } - }); - }); + makeStat(matchModels, comb, w, l, pointMake, pointTake); Categorie categorie = null; - ClubModel club = null; + String clubName = null; Optional register = registers.stream() - .filter(r -> r.getName().equals(combName)).findFirst(); + .filter(r -> Objects.equals(r.getMembre(), comb)).findFirst(); if (register.isPresent()) { - categorie = register.get().getCategorie(); - club = register.get().getClub2(); + categorie = register.get().getCategorie2(); + ClubModel club = register.get().getClub2(); + clubName = (club == null) ? BUNDLE.getString("no.licence") : club.getName(); + } else if (comb instanceof CompetitionGuestModel guestModel) { + categorie = guestModel.getCategorie(); + clubName = guestModel.getClub(); + } else if (comb instanceof MembreModel model) { + categorie = model.getCategorie(); + clubName = (model.getClub() == null) ? BUNDLE.getString( + "no.licence") : model.getClub().getName(); } builder2.cat((categorie == null) ? "---" : categorie.getName(BUNDLE)); - builder2.name(combName); + builder2.name(comb.getName(membreModel, ResultPrivacy.REGISTERED_ONLY)); builder2.w(w.get()); builder2.l(l.get()); builder2.ratioVictoire((l.get() == 0) ? w.get() : (float) w.get() / l.get()); - builder2.club((club == null) ? BUNDLE.getString("no.licence") : club.getName()); + builder2.club(clubName); builder2.pointMake(pointMake.get()); builder2.pointTake(pointTake.get()); builder2.ratioPoint( @@ -298,62 +326,62 @@ public class ResultService { }); } - public Uni> getCombList(String uuid) { - return registerRepository.list("competition.uuid = ?1", uuid) + public Uni> getCombList(String uuid, ResultPrivacy privacy) { + return registerRepository.list("competition.uuid = ?1 AND membre.resultPrivacy <= ?2", uuid, privacy) .map(models -> { HashMap map = new HashMap<>(); - models.forEach(registerEmbeddable -> { - map.put(Utils.getFullName(registerEmbeddable.getMembre()), - registerEmbeddable.getMembre().getFname() + "¤" + registerEmbeddable.getMembre() - .getLname()); - }); + models.forEach( + r -> map.put(Utils.getFullName(r.getMembre()), getCombTempId(r.getMembre().getId()))); return map; }) .chain(map -> competitionGuestRepository.list("competition.uuid = ?1", uuid) .map(models -> { models.forEach(guestModel -> map.put(Utils.getFullName(guestModel), - guestModel.getFname() + "¤" + guestModel.getLname())); + getCombTempId(guestModel.getId() * -1))); return map; }) ); } - public Uni getCombArrayPublic(String uuid, String fname, String lname) { + public Uni getCombArrayPublic(String uuid, String combTempId, ResultPrivacy privacy) { CombArrayData.CombArrayDataBuilder builder = CombArrayData.builder(); - AtomicBoolean guest = new AtomicBoolean(false); - AtomicLong id = new AtomicLong(0); + Long id = getCombTempId(combTempId); + if (id == null) { + return Uni.createFrom().failure(new DForbiddenException("Comb not found")); + } - return registerRepository.find("membre.fname = ?1 AND membre.lname = ?2 AND competition.uuid = ?3", fname, - lname, uuid).firstResult() - .chain(registerModel -> { - if (registerModel == null) { - return competitionGuestRepository.find("fname = ?1 AND lname = ?2 AND competition.uuid = ?3", - fname, lname, uuid).firstResult() - .chain(guestModel -> { - builder.name(Utils.getFullName(guestModel)); - builder.club(guestModel.getClub()); - guest.set(true); - id.set(guestModel.getId()); - builder.cat((guestModel.getCategorie() == null) ? "---" : guestModel.getCategorie() - .getName(BUNDLE)); + Uni> uni; + if (id >= 0) { + uni = registerRepository.find("membre.id = ?1 AND competition.uuid = ?2 AND membre.resultPrivacy <= ?3", id, + uuid, privacy).firstResult() + .chain(Unchecked.function(registerModel -> { + if (registerModel == null) + throw new DBadRequestException("Combattant non inscrit"); - return matchRepository.list( - "category.compet.uuid = ?1 AND (c1_guest = ?2 OR c2_guest = ?2)", uuid, - guestModel); - }); - } - builder.name(Utils.getFullName(registerModel.getMembre())); - builder.club((registerModel.getClub2() == null) ? BUNDLE.getString( - "no.licence") : registerModel.getClub2().getName()); - id.set(registerModel.getMembre().getId()); - builder.cat((registerModel.getCategorie2() == null) ? "---" : registerModel.getCategorie2() - .getName(BUNDLE)); + builder.name(Utils.getFullName(registerModel.getMembre())); + builder.club((registerModel.getClub2() == null) ? BUNDLE.getString( + "no.licence") : registerModel.getClub2().getName()); + builder.cat((registerModel.getCategorie2() == null) ? "---" : registerModel.getCategorie2() + .getName(BUNDLE)); - return matchRepository.list("category.compet.uuid = ?1 AND (c1_id = ?2 OR c2_id = ?2)", uuid, - registerModel.getMembre()); - }) - .invoke(matchModels -> { + return matchRepository.list("category.compet.uuid = ?1 AND (c1_id = ?2 OR c2_id = ?2)", uuid, + registerModel.getMembre()); + })); + } else { + uni = competitionGuestRepository.find("id = ?1 AND competition.uuid = ?2", -id, uuid).firstResult() + .chain(guestModel -> { + builder.name(Utils.getFullName(guestModel)); + builder.club(guestModel.getClub()); + builder.cat((guestModel.getCategorie() == null) ? "---" : guestModel.getCategorie() + .getName(BUNDLE)); + + return matchRepository.list("category.compet.uuid = ?1 AND (c1_guest = ?2 OR c2_guest = ?2)", + uuid, guestModel); + }); + } + + return uni.invoke(matchModels -> { List pouleModels = matchModels.stream().map(MatchModel::getCategory).distinct() .toList(); List matchs = new ArrayList<>(); @@ -375,9 +403,7 @@ public class ResultService { AtomicInteger pointMake = new AtomicInteger(); AtomicInteger pointTake = new AtomicInteger(); - if ((!guest.get() && matchModel.getC1_id() != null && matchModel.getC1_id().getId() == id.get()) - || (guest.get() && matchModel.getC1_guest() != null && matchModel.getC1_guest() - .getId() == id.get())) { + if (matchModel.isC1(id)) { builder2.adv(Utils.getFullName(matchModel.getC2_id(), matchModel.getC2_guest())); if (matchModel.isEnd()) { matchModel.getScores().stream() @@ -456,105 +482,147 @@ public class ResultService { } } - public Uni> getClubList(String uuid) { // TODO add guest club + public Uni> getClubList(String uuid) { return registerRepository.list("competition.uuid = ?1", uuid) .map(registers -> { HashMap registerMap = new HashMap<>(); registers.stream().map(RegisterModel::getClub2).distinct().filter(Objects::nonNull) .forEach(registerClub -> registerMap.put(registerClub.getName(), registerClub.getId())); return registerMap; - }); + }) + .chain(map -> competitionGuestRepository.list("competition.uuid = ?1", uuid) + .map(guests -> { + guests.stream().map(CompetitionGuestModel::getClub).distinct() + .filter(Objects::nonNull) + .forEach(guestClub -> map.putIfAbsent(guestClub, + getClubTempId(guestClub))); + return map; + }) + ); } public Uni getClubArray(String uuid, SecurityCtx securityCtx) { - return hasAccess(uuid, securityCtx).chain(cm_register -> getClubArray(uuid, cm_register.getClub2())); + return hasAccess(uuid, securityCtx).chain(cm_register -> + registerRepository.list("competition.uuid = ?1 AND membre.club = ?2", uuid, cm_register.getClub2()) + .chain(registers -> matchRepository.list("category.compet.uuid = ?1", uuid) + .map(matchModels -> + getClubArray2(cm_register.getClub2().getName(), + registers.stream().map(o -> (CombModel) o.getMembre()).toList(), + matchModels, registers, cm_register.getMembre())))); } public Uni getClubArrayPublic(String uuid, Long id) { - return clubRepository.findById(id).chain(clubModel -> getClubArray(uuid, clubModel)); + if (id < 0) { + String clubName = getClubTempId(id); + if (clubName == null) { + return Uni.createFrom().failure(new DForbiddenException("Club not found")); + } + + return competitionGuestRepository.list("competition.uuid = ?1 AND club = ?2", uuid, clubName) + .call(list -> { + if (list.isEmpty()) + return Uni.createFrom().failure(new DBadRequestException("Club not found")); + return Uni.createFrom().voidItem(); + }) + .chain(guests -> matchRepository.list( + "category.compet.uuid = ?1 AND (c1_guest IN ?2 OR c2_guest IN ?2)", uuid, guests) + .map(matchModels -> + getClubArray2(clubName, guests.stream().map(o -> (CombModel) o).toList(), + matchModels, new ArrayList<>(), null))); + } else { + return clubRepository.findById(id).chain(clubModel -> + registerRepository.list("competition.uuid = ?1 AND membre.club = ?2", uuid, clubModel) + .chain(registers -> matchRepository.list("category.compet.uuid = ?1", uuid) + .map(matchModels -> + getClubArray2(clubModel.getName(), + registers.stream().map(o -> (CombModel) o.getMembre()).toList(), + matchModels, registers, null)))); + } } - public Uni getClubArray(String uuid, ClubModel clubModel) { + private ClubArrayData getClubArray2(String name, List combs, List matchModels, + List registers, MembreModel membreModel) { ClubArrayData.ClubArrayDataBuilder builder = ClubArrayData.builder(); - builder.name(clubModel.getName()); + builder.name(name); + builder.nb_insc(combs.size()); - return registerRepository.list("competition.uuid = ?1 AND membre.club = ?2", uuid, clubModel) - .chain(registers -> matchRepository.list("category.compet.uuid = ?1", uuid) - .map(matchModels -> new Pair<>(registers, matchModels))) - .map(pair -> { - List registers = pair.getKey(); - List matchModels = pair.getValue(); + AtomicInteger tt_win = new AtomicInteger(0); + AtomicInteger tt_match = new AtomicInteger(0); - builder.nb_insc(registers.size()); + List combData = combs.stream().map(comb -> { + var builder2 = ClubArrayData.CombData.builder(); + AtomicInteger w = new AtomicInteger(0); + AtomicInteger l = new AtomicInteger(0); + AtomicInteger pointMake = new AtomicInteger(); + AtomicInteger pointTake = new AtomicInteger(); - AtomicInteger tt_win = new AtomicInteger(0); - AtomicInteger tt_match = new AtomicInteger(0); + makeStat(matchModels, comb, w, l, pointMake, pointTake); - List combData = registers.stream().map(register -> { - var builder2 = ClubArrayData.CombData.builder(); - AtomicInteger w = new AtomicInteger(0); - AtomicInteger l = new AtomicInteger(0); - AtomicInteger pointMake = new AtomicInteger(); - AtomicInteger pointTake = new AtomicInteger(); + Categorie categorie = null; - matchModels.stream() - .filter(m -> m.isEnd() && (register.getMembre().equals(m.getC1_id()) - || register.getMembre().equals(m.getC2_id()))) - .forEach(matchModel -> { - int win = matchModel.win(); - if ((register.getMembre().equals(matchModel.getC1_id()) && win > 0) || - register.getMembre().equals(matchModel.getC2_id()) && win < 0) { - w.getAndIncrement(); - } else { - l.getAndIncrement(); - } + Optional register = registers.stream() + .filter(r -> Objects.equals(r.getMembre(), comb)).findFirst(); + if (register.isPresent()) { + categorie = register.get().getCategorie2(); + } else if (comb instanceof CompetitionGuestModel guestModel) { + categorie = guestModel.getCategorie(); + } else if (comb instanceof MembreModel model) { + categorie = model.getCategorie(); + } - matchModel.getScores().stream() - .filter(s -> s.getS1() > -900 && s.getS2() > -900) - .forEach(score -> { - if (register.getMembre().equals(matchModel.getC1_id())) { - pointMake.addAndGet(score.getS1()); - pointTake.addAndGet(score.getS2()); - } else { - pointMake.addAndGet(score.getS2()); - pointTake.addAndGet(score.getS1()); - } - }); - }); + builder2.cat((categorie == null) ? "---" : categorie.getName(BUNDLE)); + builder2.name(comb.getName(membreModel, ResultPrivacy.REGISTERED_ONLY)); + builder2.w(w.get()); + builder2.l(l.get()); + builder2.ratioVictoire((l.get() == 0) ? w.get() : (float) w.get() / l.get()); + builder2.pointMake(pointMake.get()); + builder2.pointTake(pointTake.get()); + builder2.ratioPoint((pointTake.get() == 0) ? pointMake.get() : (float) pointMake.get() / pointTake.get()); - Categorie categorie = register.getCategorie(); - if (categorie == null) - categorie = register.getMembre().getCategorie(); + tt_win.addAndGet(w.get()); + tt_match.addAndGet(w.get() + l.get()); - builder2.cat((categorie == null) ? "---" : categorie.getName(BUNDLE)); - builder2.name(register.getName()); - builder2.w(w.get()); - builder2.l(l.get()); - builder2.ratioVictoire((l.get() == 0) ? w.get() : (float) w.get() / l.get()); - builder2.pointMake(pointMake.get()); - builder2.pointTake(pointTake.get()); - builder2.ratioPoint( - (pointTake.get() == 0) ? pointMake.get() : (float) pointMake.get() / pointTake.get()); + return builder2.build(); + }) + .sorted(Comparator.comparing(ClubArrayData.CombData::name)) + .toList(); - tt_win.addAndGet(w.get()); - tt_match.addAndGet(w.get() + l.get()); + builder.nb_match(tt_match.get()); + builder.match_w(tt_win.get()); + builder.ratioVictoire((float) combData.stream().filter(c -> c.l + c.w != 0) + .mapToDouble(ClubArrayData.CombData::ratioVictoire).average().orElse(0L)); + builder.pointMake(combData.stream().mapToInt(ClubArrayData.CombData::pointMake).sum()); + builder.pointTake(combData.stream().mapToInt(ClubArrayData.CombData::pointTake).sum()); + builder.ratioPoint((float) combData.stream().filter(c -> c.l + c.w != 0) + .mapToDouble(ClubArrayData.CombData::ratioPoint).average().orElse(0L)); + builder.combs(combData); - return builder2.build(); - }) - .sorted(Comparator.comparing(ClubArrayData.CombData::name)) - .toList(); + return builder.build(); + } - builder.nb_match(tt_match.get()); - builder.match_w(tt_win.get()); - builder.ratioVictoire((float) combData.stream().filter(c -> c.l + c.w != 0) - .mapToDouble(ClubArrayData.CombData::ratioVictoire).average().orElse(0L)); - builder.pointMake(combData.stream().mapToInt(ClubArrayData.CombData::pointMake).sum()); - builder.pointTake(combData.stream().mapToInt(ClubArrayData.CombData::pointTake).sum()); - builder.ratioPoint((float) combData.stream().filter(c -> c.l + c.w != 0) - .mapToDouble(ClubArrayData.CombData::ratioPoint).average().orElse(0L)); - builder.combs(combData); + private static void makeStat(List matchModels, CombModel comb, AtomicInteger w, AtomicInteger l, + AtomicInteger pointMake, AtomicInteger pointTake) { + matchModels.stream() + .filter(m -> m.isEnd() && (m.isC1(comb) || m.isC2(comb))) + .forEach(matchModel -> { + int win = matchModel.win(); + if ((matchModel.isC1(comb) && win > 0) || matchModel.isC2(comb) && win < 0) { + w.getAndIncrement(); + } else { + l.getAndIncrement(); + } - return builder.build(); + matchModel.getScores().stream() + .filter(s -> s.getS1() > -900 && s.getS2() > -900) + .forEach(score -> { + if (matchModel.isC1(comb)) { + pointMake.addAndGet(score.getS1()); + pointTake.addAndGet(score.getS2()); + } else { + pointMake.addAndGet(score.getS2()); + pointTake.addAndGet(score.getS1()); + } + }); }); } diff --git a/src/main/java/fr/titionfire/ffsaf/rest/ExternalResultEndpoints.java b/src/main/java/fr/titionfire/ffsaf/rest/ExternalResultEndpoints.java index aee3914..cd9a543 100644 --- a/src/main/java/fr/titionfire/ffsaf/rest/ExternalResultEndpoints.java +++ b/src/main/java/fr/titionfire/ffsaf/rest/ExternalResultEndpoints.java @@ -2,6 +2,7 @@ package fr.titionfire.ffsaf.rest; import fr.titionfire.ffsaf.domain.service.ResultService; import fr.titionfire.ffsaf.domain.service.UpdateService; +import fr.titionfire.ffsaf.utils.ResultPrivacy; import io.smallrye.mutiny.Uni; import jakarta.inject.Inject; import jakarta.ws.rs.*; @@ -46,7 +47,7 @@ public class ExternalResultEndpoints { @Path("/comb/list") @Produces(MediaType.APPLICATION_JSON) public Uni> combList() { - return resultService.getCombList(id); + return resultService.getCombList(id, ResultPrivacy.PUBLIC); } @GET @@ -55,7 +56,7 @@ public class ExternalResultEndpoints { public Uni getArray(@QueryParam("comb") String comb) { if (comb.equals("0")) return Uni.createFrom().item(""); - return resultService.getCombArrayPublic(id, comb.substring(0, comb.indexOf('¤')), comb.substring(comb.indexOf('¤') + 1)); + return resultService.getCombArrayPublic(id, comb, ResultPrivacy.PUBLIC); } @GET diff --git a/src/main/java/fr/titionfire/ffsaf/rest/data/ResultCategoryData.java b/src/main/java/fr/titionfire/ffsaf/rest/data/ResultCategoryData.java index 3ff949f..1ea8279 100644 --- a/src/main/java/fr/titionfire/ffsaf/rest/data/ResultCategoryData.java +++ b/src/main/java/fr/titionfire/ffsaf/rest/data/ResultCategoryData.java @@ -1,6 +1,8 @@ package fr.titionfire.ffsaf.rest.data; import fr.titionfire.ffsaf.data.model.MatchModel; +import fr.titionfire.ffsaf.data.model.MembreModel; +import fr.titionfire.ffsaf.utils.ResultPrivacy; import fr.titionfire.ffsaf.utils.ScoreEmbeddable; import fr.titionfire.ffsaf.utils.TreeNode; import io.quarkus.runtime.annotations.RegisterForReflection; @@ -38,15 +40,15 @@ public class ResultCategoryData { @RegisterForReflection public record PouleArrayData(String red, boolean red_w, List score, boolean blue_w, String blue, boolean end) { - public static PouleArrayData fromModel(MatchModel matchModel) { + public static PouleArrayData fromModel(MatchModel matchModel, MembreModel membreModel, ResultPrivacy privacy) { return new PouleArrayData( - matchModel.getC1Name(), + matchModel.getC1Name(membreModel, privacy), matchModel.isEnd() && matchModel.win() > 0, matchModel.isEnd() ? matchModel.getScores().stream().map(s -> new Integer[]{s.getS1(), s.getS2()}).toList() : new ArrayList<>(), matchModel.isEnd() && matchModel.win() < 0, - matchModel.getC2Name(), + matchModel.getC2Name(membreModel, privacy), matchModel.isEnd()); } } @@ -54,8 +56,8 @@ public class ResultCategoryData { @RegisterForReflection public static record TreeData(long id, String c1FullName, String c2FullName, List scores, boolean end) { - public static TreeData from(MatchModel match) { - return new TreeData(match.getId(), match.getC1Name(), match.getC2Name(), match.getScores(), match.isEnd()); + public static TreeData from(MatchModel match, MembreModel membreModel, ResultPrivacy privacy) { + return new TreeData(match.getId(), match.getC1Name(membreModel, privacy), match.getC2Name(membreModel, privacy), match.getScores(), match.isEnd()); } } } diff --git a/src/main/java/fr/titionfire/ffsaf/rest/data/SimpleMembre.java b/src/main/java/fr/titionfire/ffsaf/rest/data/SimpleMembre.java index f2cf3fe..c8c5fa3 100644 --- a/src/main/java/fr/titionfire/ffsaf/rest/data/SimpleMembre.java +++ b/src/main/java/fr/titionfire/ffsaf/rest/data/SimpleMembre.java @@ -19,34 +19,32 @@ import java.util.Date; @AllArgsConstructor @RegisterForReflection public class SimpleMembre { - @Schema(description = "L'identifiant du membre.", example = "1") + @Schema(description = "L'identifiant du membre.", examples = "1") private long id; - @Schema(description = "L'identifiant long du membre (userID).", example = "e81d1d35-d897-421e-8086-6c5e74d13c6e") + @Schema(description = "L'identifiant long du membre (userID).", examples = "e81d1d35-d897-421e-8086-6c5e74d13c6e") private String userId; - @Schema(description = "Le nom du membre.", example = "Dupont") + @Schema(description = "Le nom du membre.", examples = "Dupont") private String lname = ""; - @Schema(description = "Le prénom du membre.", example = "Jean") + @Schema(description = "Le prénom du membre.", examples = "Jean") private String fname = ""; - @Schema(description = "La catégorie du membre.", example = "SENIOR") + @Schema(description = "La catégorie du membre.", examples = "SENIOR") private Categorie categorie; @Schema(description = "Le club du membre.") private SimpleClubModel club; - @Schema(description = "Le genre du membre.", example = "H") + @Schema(description = "Le genre du membre.", examples = "H") private Genre genre; - @Schema(description = "Le numéro de licence du membre.", example = "12345") + @Schema(description = "Le numéro de licence du membre.", examples = "12345") private Integer licence; - @Schema(description = "Le pays du membre.", example = "FR") + @Schema(description = "Le pays du membre.", examples = "FR") private String country; @Schema(description = "La date de naissance du membre.") private Date birth_date; - @Schema(description = "L'adresse e-mail du membre.", example = "jean.dupont@example.com") + @Schema(description = "L'adresse e-mail du membre.", examples = "jean.dupont@examples.com") private String email; - @Schema(description = "Le rôle du membre dans l'association.", example = "MEMBRE") + @Schema(description = "Le rôle du membre dans l'association.", examples = "MEMBRE") private RoleAsso role; - @Schema(description = "Le grade d'arbitrage du membre.", example = "N/A") + @Schema(description = "Le grade d'arbitrage du membre.", examples = "N/A") private GradeArbitrage grade_arbitrage; - @Schema(hidden = true) - private String url_photo; public static SimpleMembre fromModel(MembreModel model) { if (model == null) @@ -66,7 +64,6 @@ public class SimpleMembre { .email(model.getEmail()) .role(model.getRole()) .grade_arbitrage(model.getGrade_arbitrage()) - .url_photo(model.getUrl_photo()) .build(); } } diff --git a/src/main/java/fr/titionfire/ffsaf/utils/ResultPrivacy.java b/src/main/java/fr/titionfire/ffsaf/utils/ResultPrivacy.java new file mode 100644 index 0000000..6ae7042 --- /dev/null +++ b/src/main/java/fr/titionfire/ffsaf/utils/ResultPrivacy.java @@ -0,0 +1,8 @@ +package fr.titionfire.ffsaf.utils; + +public enum ResultPrivacy { + PUBLIC, + REGISTERED_ONLY, + REGISTERED_ONLY_NO_DETAILS, + PRIVATE; +} diff --git a/src/main/webapp/src/components/Nav.jsx b/src/main/webapp/src/components/Nav.jsx index 021255f..f3693f2 100644 --- a/src/main/webapp/src/components/Nav.jsx +++ b/src/main/webapp/src/components/Nav.jsx @@ -44,9 +44,9 @@ function AffiliationMenu() { } function CompMenu() { - const {is_authenticated, userinfo} = useAuth() + const {is_authenticated} = useAuth() - if (!is_authenticated || !userinfo?.roles?.includes("federation_admin")) + if (!is_authenticated) return <> return