Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 09a51edd5f | |||
| 354fbfede9 | |||
| ef5b707697 | |||
| 489bfeb354 | |||
| bb901392fc | |||
| 6f61db6817 | |||
| 00701fb874 | |||
| 936392f8bd | |||
| f6d4bb0fe4 | |||
| 160c7d59e3 | |||
| 9689201a8c | |||
| 083d72fbfa | |||
| 1c7466d883 | |||
| c9c8c8536d | |||
| b1bcf75e56 | |||
| b78b3f005b | |||
| a83088387b | |||
| 22fa896ee0 | |||
| f8976deb91 | |||
| eb9badb4a1 | |||
| 661fcdb16b | |||
| b2ad633b21 | |||
| 1b5bf8ba6c | |||
| bf75d9d036 | |||
| 9457c5749a | |||
| c7f56881cd | |||
| aebcd62aa9 | |||
| c2eecf4906 | |||
| 87b3bc12e0 | |||
| 3d3d63e58c | |||
| 81c115c655 | |||
| a7ba1d16a4 | |||
| 645949a2f6 | |||
| beb40db1b1 | |||
| 61a4af6ff1 | |||
| d9fc68298c | |||
| fccea5bf6a | |||
| ee476cd0e2 | |||
| b320d7db37 | |||
| 80fef98e07 | |||
| 7e80703c04 | |||
| cc4a3e4e06 | |||
| 9e28356f2c | |||
| 77d66813c7 | |||
| 7625da1d4b | |||
| 4262845074 | |||
| b84e10de44 | |||
| ac6563ac95 | |||
| baf57c3464 | |||
| d1c7f37a94 |
@ -76,6 +76,7 @@ jobs:
|
||||
key: ${{ secrets.SSH_KEY }}
|
||||
script: |
|
||||
cd ${{ secrets.TARGET_DIR }}
|
||||
docker logs ffsaf > "log/ffsaf_logs_$(date +"%Y-%m-%d_%H-%M-%S").log" 2>&1
|
||||
docker stop ffsaf
|
||||
docker rm ffsaf
|
||||
docker compose up --build -d ffsaf
|
||||
|
||||
5
pom.xml
@ -133,6 +133,11 @@
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-mailer</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-websockets-next</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
@ -21,8 +21,7 @@ public class AffiliationRequestModel {
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
long siret;
|
||||
String RNA;
|
||||
String state_id;
|
||||
String address;
|
||||
String contact;
|
||||
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
package fr.titionfire.ffsaf.data.model;
|
||||
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@RegisterForReflection
|
||||
|
||||
@Entity
|
||||
@Table(name = "cardboard")
|
||||
public class CardboardModel {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "comb", referencedColumnName = "id")
|
||||
MembreModel comb;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "guest_comb", referencedColumnName = "id")
|
||||
CompetitionGuestModel guestComb;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "match", referencedColumnName = "id")
|
||||
MatchModel match;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "compet", referencedColumnName = "id")
|
||||
CompetitionModel compet;
|
||||
|
||||
int red;
|
||||
int yellow;
|
||||
}
|
||||
@ -42,4 +42,6 @@ public class CategoryModel {
|
||||
List<TreeModel> tree;
|
||||
|
||||
Integer type;
|
||||
|
||||
String liceName = "1";
|
||||
}
|
||||
|
||||
@ -55,11 +55,8 @@ public class ClubModel implements LoggableModel {
|
||||
@Schema(description = "Adresse postale du club", example = "1 rue de l'exemple, 75000 Paris")
|
||||
String address;
|
||||
|
||||
@Schema(description = "RNA du club", example = "W123456789")
|
||||
String RNA;
|
||||
|
||||
@Schema(description = "Numéro SIRET du club", example = "12345678901234")
|
||||
Long SIRET;
|
||||
@Schema(description = "Numéro SIRET ou RNA du club", example = "12345678901234")
|
||||
String StateId;
|
||||
|
||||
@Schema(description = "Numéro d'affiliation du club", example = "12345")
|
||||
Long no_affiliation;
|
||||
|
||||
@ -0,0 +1,50 @@
|
||||
package fr.titionfire.ffsaf.data.model;
|
||||
|
||||
import fr.titionfire.ffsaf.utils.Categorie;
|
||||
import fr.titionfire.ffsaf.utils.Genre;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@RegisterForReflection
|
||||
|
||||
@Entity
|
||||
@Table(name = "competition_guest")
|
||||
public class CompetitionGuestModel {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "competition", referencedColumnName = "id")
|
||||
CompetitionModel competition;
|
||||
|
||||
String lname = "";
|
||||
String fname = "";
|
||||
|
||||
Categorie categorie = null;
|
||||
|
||||
String club = null;
|
||||
|
||||
Genre genre = null;
|
||||
|
||||
String country = "fr";
|
||||
|
||||
Integer weight = null;
|
||||
|
||||
public CompetitionGuestModel(String s) {
|
||||
this.fname = s.substring(0, s.indexOf(" "));
|
||||
this.lname = s.substring(s.indexOf(" ") + 1);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return fname + " " + lname;
|
||||
}
|
||||
}
|
||||
@ -55,10 +55,18 @@ public class CompetitionModel {
|
||||
@OneToMany(mappedBy = "competition", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
List<RegisterModel> insc;
|
||||
|
||||
@OneToMany(mappedBy = "competition", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
List<CompetitionGuestModel> guests = new ArrayList<>();
|
||||
|
||||
|
||||
List<Long> banMembre = new ArrayList<>();
|
||||
|
||||
String owner;
|
||||
|
||||
List<String> admin = new ArrayList<>();
|
||||
@Column(name = "table_")
|
||||
List<String> table = new ArrayList<>();
|
||||
|
||||
String data1;
|
||||
String data2;
|
||||
String data3;
|
||||
|
||||
@ -30,8 +30,10 @@ public class LogModel {
|
||||
|
||||
Long target_id;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
String target_name;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
String message;
|
||||
|
||||
public enum ActionType {
|
||||
|
||||
@ -7,6 +7,7 @@ import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@ -32,13 +33,17 @@ public class MatchModel {
|
||||
@JoinColumn(name = "c1", referencedColumnName = "id")
|
||||
MembreModel c1_id = null;
|
||||
|
||||
String c1_str = null;
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "c1_guest", referencedColumnName = "id")
|
||||
CompetitionGuestModel c1_guest = null;
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "c2", referencedColumnName = "id")
|
||||
MembreModel c2_id = null;
|
||||
|
||||
String c2_str = null;
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "c2_guest", referencedColumnName = "id")
|
||||
CompetitionGuestModel c2_guest = null;
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "id_category", referencedColumnName = "id")
|
||||
@ -48,9 +53,41 @@ public class MatchModel {
|
||||
|
||||
boolean isEnd = true;
|
||||
|
||||
Date date = null;
|
||||
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "score", joinColumns = @JoinColumn(name = "id_match"))
|
||||
List<ScoreEmbeddable> scores = new ArrayList<>();
|
||||
|
||||
char poule = 'A';
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "match", referencedColumnName = "id")
|
||||
List<CardboardModel> cardboard = new ArrayList<>();
|
||||
|
||||
public String getC1Name() {
|
||||
if (c1_id == null)
|
||||
return c1_guest.fname + " " + c1_guest.lname;
|
||||
return c1_id.fname + " " + c1_id.lname;
|
||||
}
|
||||
|
||||
public String getC2Name() {
|
||||
if (c2_id == null)
|
||||
return c2_guest.fname + " " + c2_guest.lname;
|
||||
return c2_id.fname + " " + c2_id.lname;
|
||||
}
|
||||
|
||||
public int win() {
|
||||
int sum = 0;
|
||||
for (ScoreEmbeddable score : this.getScores()) {
|
||||
if (score.getS1() == -1000 || score.getS2() == -1000)
|
||||
continue;
|
||||
|
||||
if (score.getS1() > score.getS2())
|
||||
sum++;
|
||||
else if (score.getS1() < score.getS2())
|
||||
sum--;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,4 +82,22 @@ public class MembreModel implements LoggableModel {
|
||||
public LogModel.ObjectType getObjectType() {
|
||||
return LogModel.ObjectType.Membre;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MembreModel{" +
|
||||
"id=" + id +
|
||||
", userId='" + userId + '\'' +
|
||||
", lname='" + lname + '\'' +
|
||||
", fname='" + fname + '\'' +
|
||||
", categorie=" + categorie +
|
||||
", genre=" + genre +
|
||||
", licence=" + licence +
|
||||
", country='" + country + '\'' +
|
||||
", birth_date=" + birth_date +
|
||||
", email='" + email + '\'' +
|
||||
", role=" + role +
|
||||
", grade_arbitrage=" + grade_arbitrage +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,8 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.OnDelete;
|
||||
import org.hibernate.annotations.OnDeleteAction;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ -38,6 +40,7 @@ public class RegisterModel {
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "club")
|
||||
@OnDelete(action = OnDeleteAction.SET_NULL)
|
||||
ClubModel club = null;
|
||||
|
||||
@Column(nullable = false, columnDefinition = "boolean default false")
|
||||
@ -53,4 +56,14 @@ public class RegisterModel {
|
||||
this.categorie = categorie;
|
||||
this.club = club;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return membre.fname + " " + membre.lname;
|
||||
}
|
||||
|
||||
public ClubModel getClub2() {
|
||||
if (club == null)
|
||||
return membre.club;
|
||||
return club;
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,9 @@ import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@ -36,4 +39,20 @@ public class TreeModel {
|
||||
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
|
||||
@JoinColumn(referencedColumnName = "id")
|
||||
TreeModel right;
|
||||
|
||||
public List<TreeModel> flat() {
|
||||
List<TreeModel> out = new ArrayList<>();
|
||||
this.flat(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
private void flat(List<TreeModel> out) {
|
||||
out.add(this);
|
||||
|
||||
if (this.right != null)
|
||||
this.right.flat(out);
|
||||
|
||||
if (this.left != null)
|
||||
this.left.flat(out);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,19 @@
|
||||
package fr.titionfire.ffsaf.data.repository;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.CategoryModel;
|
||||
import fr.titionfire.ffsaf.utils.CompetitionSystem;
|
||||
import io.quarkus.hibernate.reactive.panache.Panache;
|
||||
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
@ApplicationScoped
|
||||
public class CategoryRepository implements PanacheRepositoryBase<CategoryModel, Long> {
|
||||
|
||||
public Uni<CategoryModel> create(CategoryModel categoryModel) {
|
||||
categoryModel.setSystem(CompetitionSystem.INTERNAL);
|
||||
return Panache.withTransaction(() -> this.persist(categoryModel)
|
||||
.invoke(categoryModel1 -> categoryModel1.setSystemId(categoryModel1.getId())))
|
||||
.chain(this::persist);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
package fr.titionfire.ffsaf.data.repository;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.CompetitionGuestModel;
|
||||
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
@ApplicationScoped
|
||||
public class CompetitionGuestRepository implements PanacheRepositoryBase<CompetitionGuestModel, Long> {
|
||||
}
|
||||
@ -1,9 +1,30 @@
|
||||
package fr.titionfire.ffsaf.data.repository;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.MatchModel;
|
||||
import fr.titionfire.ffsaf.utils.CompetitionSystem;
|
||||
import io.quarkus.hibernate.reactive.panache.Panache;
|
||||
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ApplicationScoped
|
||||
public class MatchRepository implements PanacheRepositoryBase<MatchModel, Long> {
|
||||
|
||||
public Uni<MatchModel> create(MatchModel matchModel) {
|
||||
matchModel.setSystem(CompetitionSystem.INTERNAL);
|
||||
return Panache.withTransaction(() -> this.persistAndFlush(matchModel)
|
||||
.invoke(matchModel1 -> matchModel1.setSystemId(matchModel1.getId())))
|
||||
.chain(this::persist);
|
||||
}
|
||||
|
||||
public Uni<Void> create(List<MatchModel> matchModel) {
|
||||
matchModel.forEach(model -> model.setSystem(CompetitionSystem.INTERNAL));
|
||||
return Panache.withTransaction(() -> this.persist(matchModel)
|
||||
.call(__ -> this.flush())
|
||||
.invoke(__ -> matchModel.forEach(model -> model.setSystemId(model.getId())))
|
||||
.map(__ -> matchModel))
|
||||
.chain(this::persist);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,8 +2,22 @@ package fr.titionfire.ffsaf.data.repository;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.TreeModel;
|
||||
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
|
||||
import io.quarkus.hibernate.reactive.panache.common.WithTransaction;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
@ApplicationScoped
|
||||
public class TreeRepository implements PanacheRepositoryBase<TreeModel, Long> {
|
||||
|
||||
@WithTransaction
|
||||
public Uni<Boolean> deleteTree(TreeModel entity) {
|
||||
Uni<Boolean> uni = Uni.createFrom().item(false);
|
||||
if (entity == null)
|
||||
return uni;
|
||||
if (entity.getLeft() != null)
|
||||
uni = uni.chain(__ -> this.deleteTree(entity.getLeft()));
|
||||
if (entity.getRight() != null)
|
||||
uni = uni.chain(__ -> this.deleteTree(entity.getRight()));
|
||||
return uni.chain(__ -> this.deleteById(entity.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
package fr.titionfire.ffsaf.domain.entity;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.CardboardModel;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@RegisterForReflection
|
||||
public class CardboardEntity {
|
||||
long comb_id;
|
||||
long match_id;
|
||||
long compet_id;
|
||||
|
||||
int red;
|
||||
int yellow;
|
||||
|
||||
public static CardboardEntity fromModel(CardboardModel model) {
|
||||
return new CardboardEntity(model.getComb().getId(), model.getMatch().getId(), model.getCompet().getId(),
|
||||
model.getRed(), model.getYellow());
|
||||
}
|
||||
}
|
||||
@ -22,8 +22,7 @@ public class ClubEntity {
|
||||
private String training_location;
|
||||
private String training_day_time;
|
||||
private String contact_intern;
|
||||
private String RNA;
|
||||
private Long SIRET;
|
||||
private String StateId;
|
||||
private Long no_affiliation;
|
||||
private boolean international;
|
||||
|
||||
@ -41,8 +40,7 @@ public class ClubEntity {
|
||||
.training_location(model.getTraining_location())
|
||||
.training_day_time(model.getTraining_day_time())
|
||||
.contact_intern(model.getContact_intern())
|
||||
.RNA(model.getRNA())
|
||||
.SIRET(model.getSIRET())
|
||||
.StateId(model.getStateId())
|
||||
.no_affiliation(model.getNo_affiliation())
|
||||
.international(model.isInternational())
|
||||
.build();
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
package fr.titionfire.ffsaf.domain.entity;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.CompetitionGuestModel;
|
||||
import fr.titionfire.ffsaf.data.model.MembreModel;
|
||||
import fr.titionfire.ffsaf.data.model.RegisterModel;
|
||||
import fr.titionfire.ffsaf.utils.Categorie;
|
||||
import fr.titionfire.ffsaf.utils.Genre;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@RegisterForReflection
|
||||
public class CombEntity {
|
||||
private long id;
|
||||
private String lname;
|
||||
private String fname;
|
||||
Categorie categorie;
|
||||
Long club;
|
||||
String club_str;
|
||||
Genre genre;
|
||||
String country;
|
||||
int overCategory;
|
||||
Integer weight;
|
||||
|
||||
public static CombEntity fromModel(MembreModel model) {
|
||||
if (model == null)
|
||||
return null;
|
||||
|
||||
return new CombEntity(model.getId(), model.getLname(), model.getFname(), model.getCategorie(),
|
||||
model.getClub() == null ? null : model.getClub().getId(),
|
||||
model.getClub() == null ? "Sans club" : model.getClub().getName(), model.getGenre(), model.getCountry(),
|
||||
0, null);
|
||||
}
|
||||
|
||||
|
||||
public static CombEntity fromModel(CompetitionGuestModel model) {
|
||||
if (model == null)
|
||||
return null;
|
||||
|
||||
return new CombEntity(model.getId() * -1, model.getLname(), model.getFname(), model.getCategorie(), null,
|
||||
model.getClub(), model.getGenre(), model.getCountry(), 0, model.getWeight());
|
||||
}
|
||||
|
||||
public static CombEntity fromModel(RegisterModel registerModel) {
|
||||
if (registerModel == null || registerModel.getMembre() == null)
|
||||
return null;
|
||||
MembreModel model = registerModel.getMembre();
|
||||
|
||||
return new CombEntity(model.getId(), model.getLname(), model.getFname(), registerModel.getCategorie(),
|
||||
registerModel.getClub2() == null ? null : registerModel.getClub2().getId(),
|
||||
registerModel.getClub2() == null ? "Sans club" : registerModel.getClub2().getName(), model.getGenre(),
|
||||
model.getCountry(), registerModel.getOverCategory(), registerModel.getWeight());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package fr.titionfire.ffsaf.domain.entity;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.MatchModel;
|
||||
import fr.titionfire.ffsaf.utils.ScoreEmbeddable;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@RegisterForReflection
|
||||
public class MatchEntity {
|
||||
private long id;
|
||||
private CombEntity c1;
|
||||
private CombEntity c2;
|
||||
private long categorie_ord = 0;
|
||||
private boolean isEnd;
|
||||
private long categorie;
|
||||
private Date date;
|
||||
private List<ScoreEmbeddable> scores;
|
||||
private char poule;
|
||||
private List<CardboardEntity> cardboard;
|
||||
|
||||
public static MatchEntity fromModel(MatchModel model) {
|
||||
if (model == null)
|
||||
return null;
|
||||
return new MatchEntity(model.getId(),
|
||||
(model.getC1_id() == null) ? CombEntity.fromModel(model.getC1_guest()) : CombEntity.fromModel(
|
||||
model.getC1_id()),
|
||||
(model.getC2_id() == null) ? CombEntity.fromModel(model.getC2_guest()) : CombEntity.fromModel(
|
||||
model.getC2_id()),
|
||||
model.getCategory_ord(), model.isEnd(), model.getCategory().getId(), model.getDate(),
|
||||
model.getScores(),
|
||||
model.getPoule(),
|
||||
(model.getCardboard() == null) ? new ArrayList<>() : model.getCardboard().stream()
|
||||
.map(CardboardEntity::fromModel).toList());
|
||||
}
|
||||
|
||||
public int win() {
|
||||
int sum = 0;
|
||||
for (ScoreEmbeddable score : scores) {
|
||||
if (score.getS1() == -1000 || score.getS2() == -1000)
|
||||
continue;
|
||||
|
||||
if (score.getS1() > score.getS2())
|
||||
sum++;
|
||||
else if (score.getS1() < score.getS2())
|
||||
sum--;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
package fr.titionfire.ffsaf.domain.entity;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.TreeModel;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@RegisterForReflection
|
||||
public class TreeEntity {
|
||||
private Long id;
|
||||
private Long categorie;
|
||||
private Integer level;
|
||||
private MatchEntity match;
|
||||
private TreeEntity left;
|
||||
private TreeEntity right;
|
||||
private TreeEntity associatedNode;
|
||||
|
||||
public static TreeEntity fromModel(TreeModel model) {
|
||||
if (model == null)
|
||||
return null;
|
||||
|
||||
return new TreeEntity(model.getId(), model.getCategory(), model.getLevel(), MatchEntity.fromModel(model.getMatch()), fromModel(model.getLeft()),
|
||||
fromModel(model.getRight()), null);
|
||||
}
|
||||
|
||||
public TreeEntity getMatchNode(Long matchId) {
|
||||
if (this.match != null && this.match.getId() == matchId) {
|
||||
return this;
|
||||
} else {
|
||||
if (this.left != null) {
|
||||
TreeEntity left = this.left.getMatchNode(matchId);
|
||||
if (left != null) {
|
||||
return left;
|
||||
}
|
||||
}
|
||||
if (this.right != null) {
|
||||
TreeEntity right = this.right.getMatchNode(matchId);
|
||||
if (right != null) {
|
||||
return right;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static TreeEntity getParent(TreeEntity current, TreeEntity target) {
|
||||
if (current == null) {
|
||||
return null;
|
||||
} else if (current.equals(target)) {
|
||||
return null;
|
||||
} else if (target.equals(current.left) || target.equals(current.right)) {
|
||||
return current;
|
||||
} else {
|
||||
TreeEntity left = getParent(current.left, target);
|
||||
if (left != null)
|
||||
return left;
|
||||
return getParent(current.right, target);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setAssociated(TreeEntity current, TreeEntity next) {
|
||||
if (current == null || next == null) {
|
||||
return;
|
||||
}
|
||||
current.setAssociatedNode(next);
|
||||
setAssociated(current.getLeft(), next.getLeft());
|
||||
setAssociated(current.getRight(), next.getRight());
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,8 @@ package fr.titionfire.ffsaf.domain.service;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.*;
|
||||
import fr.titionfire.ffsaf.data.repository.*;
|
||||
import fr.titionfire.ffsaf.rest.client.SirenService;
|
||||
import fr.titionfire.ffsaf.rest.client.StateIdService;
|
||||
import fr.titionfire.ffsaf.rest.data.SimpleAffiliation;
|
||||
import fr.titionfire.ffsaf.rest.data.SimpleReqAffiliation;
|
||||
import fr.titionfire.ffsaf.rest.exception.DBadRequestException;
|
||||
@ -21,15 +23,19 @@ import io.smallrye.mutiny.unchecked.Unchecked;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
import org.hibernate.reactive.mutiny.Mutiny;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@WithSession
|
||||
@ApplicationScoped
|
||||
public class AffiliationService {
|
||||
private static final Logger LOGGER = Logger.getLogger(AffiliationService.class);
|
||||
|
||||
@Inject
|
||||
CombRepository combRepository;
|
||||
@ -58,6 +64,12 @@ public class AffiliationService {
|
||||
@Inject
|
||||
LoggerService ls;
|
||||
|
||||
@RestClient
|
||||
StateIdService stateIdService;
|
||||
|
||||
@RestClient
|
||||
SirenService sirenService;
|
||||
|
||||
@ConfigProperty(name = "upload_dir")
|
||||
String media;
|
||||
|
||||
@ -71,6 +83,8 @@ public class AffiliationService {
|
||||
public Uni<AffiliationRequestModel> pre_save(AffiliationRequestForm form, boolean unique) {
|
||||
AffiliationRequestModel affModel = form.toModel();
|
||||
int currentSaison = Utils.getSaison();
|
||||
List<String> out = new ArrayList<>();
|
||||
out.add(affModel.getState_id());
|
||||
|
||||
return Uni.createFrom().item(affModel)
|
||||
.invoke(Unchecked.consumer(model -> {
|
||||
@ -78,14 +92,26 @@ public class AffiliationService {
|
||||
throw new DBadRequestException("Saison non valid");
|
||||
}
|
||||
}))
|
||||
.chain(() -> repositoryRequest.count("siret = ?1 and saison = ?2", affModel.getSiret(),
|
||||
affModel.getSaison()))
|
||||
.onItem().invoke(Unchecked.consumer(count -> {
|
||||
if (count != 0 && unique) {
|
||||
throw new DBadRequestException("Demande d'affiliation déjà existante");
|
||||
}
|
||||
}))
|
||||
.chain(() -> clubRepository.find("SIRET = ?1", affModel.getSiret()).firstResult().chain(club ->
|
||||
.chain(() -> ((affModel.getState_id().charAt(0) == 'W') ? stateIdService.get_rna(
|
||||
affModel.getState_id()) : sirenService.get_unite(affModel.getState_id())
|
||||
.chain(stateIdService::getAssoDataFromUnit)).onItem().transform(o -> {
|
||||
if (o.getRna() != null && !o.getRna().isBlank())
|
||||
out.add(o.getRna());
|
||||
if (o.getSiren() != null && !o.getSiren().isBlank())
|
||||
out.add(o.getSiren());
|
||||
if (o.getIdentite().getSiret_siege() != null && !o.getIdentite().getSiret_siege().isBlank())
|
||||
out.add(o.getIdentite().getSiret_siege());
|
||||
return out;
|
||||
}).onFailure().recoverWithItem(out)
|
||||
.chain(a -> repositoryRequest.count("state_id IN ?1 and saison = ?2",
|
||||
out, affModel.getSaison()))
|
||||
.onItem().invoke(Unchecked.consumer(count -> {
|
||||
if (count != 0 && unique) {
|
||||
throw new DBadRequestException("Demande d'affiliation déjà existante");
|
||||
}
|
||||
}))
|
||||
)
|
||||
.chain(() -> clubRepository.find("StateId IN ?1", out).firstResult().chain(club ->
|
||||
repository.count("club = ?1 and saison = ?2", club, affModel.getSaison())))
|
||||
.onItem().invoke(Unchecked.consumer(count -> {
|
||||
if (count != 0) {
|
||||
@ -122,7 +148,6 @@ public class AffiliationService {
|
||||
.onItem().ifNull().failWith(new DNotFoundException("Demande d'affiliation non trouvé"))
|
||||
.chain(origine -> {
|
||||
origine.setName(model.getName());
|
||||
origine.setRNA(model.getRNA());
|
||||
origine.setAddress(model.getAddress());
|
||||
origine.setContact(model.getContact());
|
||||
origine.setM1_lname(model.getM1_lname());
|
||||
@ -146,6 +171,9 @@ public class AffiliationService {
|
||||
}
|
||||
|
||||
public Uni<String> save(AffiliationRequestForm form) {
|
||||
LOGGER.debug("Affiliation Request Created");
|
||||
LOGGER.debug(form.toString());
|
||||
|
||||
// noinspection ResultOfMethodCallIgnored,ReactiveStreamsUnusedPublisher
|
||||
return pre_save(form, true)
|
||||
.chain(model -> Panache.withTransaction(() -> repositoryRequest.persist(model)))
|
||||
@ -169,12 +197,14 @@ public class AffiliationService {
|
||||
}
|
||||
|
||||
public Uni<?> saveAdmin(AffiliationRequestSaveForm form) {
|
||||
LOGGER.debug("Affiliation Request Saved");
|
||||
LOGGER.debug(form.toString());
|
||||
|
||||
return repositoryRequest.findById(form.getId())
|
||||
.onItem().ifNull().failWith(new DNotFoundException("Demande d'affiliation non trouvé"))
|
||||
.map(model -> {
|
||||
model.setName(form.getName());
|
||||
model.setSiret(form.getSiret());
|
||||
model.setRNA(form.getRna());
|
||||
model.setState_id(form.getState_id());
|
||||
model.setAddress(form.getAddress());
|
||||
model.setContact(form.getContact());
|
||||
|
||||
@ -259,7 +289,9 @@ public class AffiliationService {
|
||||
}).call(m -> Panache.withTransaction(() -> combRepository.persist(m)));
|
||||
}
|
||||
})
|
||||
.call(m -> ((m.getUserId() == null) ? keycloakService.initCompte(m.getId()) :
|
||||
.call(m -> ((m.getUserId() == null) ? keycloakService.initCompte(m.getId())
|
||||
.onFailure().invoke(t -> LOGGER.warnf("Failed to init account: %s", t.getMessage())).onFailure()
|
||||
.recoverWithNull() :
|
||||
keycloakService.setClubGroupMembre(m, club).map(__ -> m.getUserId()))
|
||||
.call(userId -> keycloakService.setAutoRoleMembre(userId, m.getRole(), m.getGrade_arbitrage()))
|
||||
.call(userId -> keycloakService.setEmail(userId, m.getEmail())))
|
||||
@ -267,19 +299,24 @@ public class AffiliationService {
|
||||
.call(l1 -> l1 != null && l1.stream().anyMatch(l -> l.getSaison() == saison) ?
|
||||
Uni.createFrom().nullItem() :
|
||||
Panache.withTransaction(() -> licenceRepository.persist(
|
||||
new LicenceModel(null, m, club.getId(), saison, null, true, false)))
|
||||
new LicenceModel(null, m, club.getId(), saison, null, true, false)))
|
||||
.call(licenceModel -> ls.logA(LogModel.ActionType.ADD, m.getObjectName(),
|
||||
licenceModel))));
|
||||
}
|
||||
|
||||
public Uni<?> accept(AffiliationRequestSaveForm form) {
|
||||
LOGGER.debug("Affiliation Request Accepted");
|
||||
LOGGER.debug(form.toString());
|
||||
|
||||
return repositoryRequest.findById(form.getId())
|
||||
.onItem().ifNull().failWith(new DNotFoundException("Demande d'affiliation non trouvé"))
|
||||
.chain(req ->
|
||||
clubRepository.find("SIRET = ?1", form.getSiret()).firstResult()
|
||||
clubRepository.find("StateId = ?1", form.getState_id()).firstResult()
|
||||
.chain(model -> (model == null) ? acceptNew(form, req) : acceptOld(form, req, model))
|
||||
.call(club -> setMembre(form.new Member(1), club, req.getSaison())
|
||||
.call(__ -> setMembre(form.new Member(2), club, req.getSaison())
|
||||
.call(club -> setMembre(form.new Member(1), club, req.getSaison()).onFailure()
|
||||
.recoverWithNull()
|
||||
.call(__ -> setMembre(form.new Member(2), club, req.getSaison()).onFailure()
|
||||
.recoverWithNull()
|
||||
.call(___ -> setMembre(form.new Member(3), club, req.getSaison()))))
|
||||
.onItem()
|
||||
.invoke(model -> Uni.createFrom()
|
||||
@ -298,13 +335,13 @@ public class AffiliationService {
|
||||
}
|
||||
|
||||
private Uni<ClubModel> acceptNew(AffiliationRequestSaveForm form, AffiliationRequestModel model) {
|
||||
LOGGER.debug("New Club Accepted");
|
||||
return Uni.createFrom().nullItem()
|
||||
.chain(() -> {
|
||||
ClubModel club = new ClubModel();
|
||||
club.setName(form.getName());
|
||||
club.setCountry("FR");
|
||||
club.setSIRET(form.getSiret());
|
||||
club.setRNA(form.getRna());
|
||||
club.setStateId(form.getState_id());
|
||||
club.setAddress(form.getAddress());
|
||||
club.setContact_intern(form.getContact());
|
||||
club.setAffiliations(new ArrayList<>());
|
||||
@ -336,17 +373,24 @@ public class AffiliationService {
|
||||
}
|
||||
|
||||
private Uni<ClubModel> acceptOld(AffiliationRequestSaveForm form, AffiliationRequestModel model, ClubModel club) {
|
||||
AtomicBoolean nameChange = new AtomicBoolean(false);
|
||||
LOGGER.debug("Old Club Accepted");
|
||||
return Uni.createFrom().nullItem()
|
||||
.chain(() -> {
|
||||
club.setName(form.getName());
|
||||
if (!form.getName().equals(club.getName())) {
|
||||
club.setName(form.getName());
|
||||
nameChange.set(true);
|
||||
}
|
||||
club.setCountry("FR");
|
||||
club.setSIRET(form.getSiret());
|
||||
club.setRNA(form.getRna());
|
||||
club.setStateId(form.getState_id());
|
||||
club.setAddress(form.getAddress());
|
||||
club.setContact_intern(form.getContact());
|
||||
return Panache.withTransaction(() -> clubRepository.persist(club)
|
||||
.chain(() -> repository.persist(new AffiliationModel(null, club, model.getSaison())))
|
||||
.chain(() -> repositoryRequest.delete(model)));
|
||||
.chain(() -> repository.persist(new AffiliationModel(null, club, model.getSaison())))
|
||||
.chain(() -> repositoryRequest.delete(model)))
|
||||
.call(() -> nameChange.get() ? keycloakService.updateGroupFromClub(
|
||||
club) // update group in keycloak
|
||||
: Uni.createFrom().nullItem());
|
||||
})
|
||||
.map(__ -> club);
|
||||
}
|
||||
@ -354,7 +398,7 @@ public class AffiliationService {
|
||||
public Uni<SimpleReqAffiliation> getRequest(long id) {
|
||||
return repositoryRequest.findById(id).map(SimpleReqAffiliation::fromModel)
|
||||
.onItem().ifNull().failWith(new DNotFoundException("Demande d'affiliation non trouvé"))
|
||||
.call(out -> clubRepository.find("SIRET = ?1", out.getSiret()).firstResult().invoke(c -> {
|
||||
.call(out -> clubRepository.find("StateId = ?1", out.getStateId()).firstResult().invoke(c -> {
|
||||
if (c != null) {
|
||||
out.setClub(c.getId());
|
||||
out.setClub_name(c.getName());
|
||||
@ -367,7 +411,7 @@ public class AffiliationService {
|
||||
public Uni<List<SimpleAffiliation>> getCurrentSaisonAffiliation() {
|
||||
return repositoryRequest.list("saison = ?1 or saison = ?1 + 1", Utils.getSaison())
|
||||
.map(models -> models.stream()
|
||||
.map(model -> new SimpleAffiliation(model.getId() * -1, model.getSiret(), model.getSaison(),
|
||||
.map(model -> new SimpleAffiliation(model.getId() * -1, model.getState_id(), model.getSaison(),
|
||||
false)).toList())
|
||||
.chain(aff -> repository.list("saison = ?1", Utils.getSaison())
|
||||
.map(models -> models.stream().map(SimpleAffiliation::fromModel).toList())
|
||||
@ -379,9 +423,9 @@ public class AffiliationService {
|
||||
return clubRepository.findById(id)
|
||||
.onItem().ifNull().failWith(new DNotFoundException("Club non trouvé"))
|
||||
.call(model -> Mutiny.fetch(model.getAffiliations()))
|
||||
.chain(model -> repositoryRequest.list("siret = ?1", model.getSIRET())
|
||||
.chain(model -> repositoryRequest.list("state_id = ?1", model.getStateId())
|
||||
.map(reqs -> reqs.stream().map(req ->
|
||||
new SimpleAffiliation(req.getId() * -1, model.getId(), req.getSaison(), false)))
|
||||
new SimpleAffiliation(req.getId() * -1, model.getStateId(), req.getSaison(), false)))
|
||||
.map(aff2 -> Stream.concat(aff2,
|
||||
model.getAffiliations().stream().map(SimpleAffiliation::fromModel)).toList())
|
||||
);
|
||||
@ -411,9 +455,9 @@ public class AffiliationService {
|
||||
return Panache.withTransaction(() -> repository.deleteById(id));
|
||||
}
|
||||
|
||||
public Uni<?> deleteReqAffiliation(long id, String reason) {
|
||||
public Uni<?> deleteReqAffiliation(long id, String reason, boolean federationAdmin) {
|
||||
return repositoryRequest.findById(id)
|
||||
.call(aff -> reactiveMailer.send(
|
||||
.call(aff -> federationAdmin ? reactiveMailer.send(
|
||||
Mail.withText(aff.getM1_email(),
|
||||
"FFSAF - Votre demande d'affiliation a été rejetée.",
|
||||
String.format(
|
||||
@ -430,7 +474,7 @@ public class AffiliationService {
|
||||
""", aff.getName(), reason)
|
||||
).setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("contact@ffsaf.fr")
|
||||
.addTo(aff.getM2_email(), aff.getM3_email())
|
||||
))
|
||||
) : Uni.createFrom().nullItem())
|
||||
.chain(aff -> Panache.withTransaction(() -> repositoryRequest.delete(aff)))
|
||||
.call(__ -> Utils.deleteMedia(id, media, "aff_request/logo"))
|
||||
.call(__ -> Utils.deleteMedia(id, media, "aff_request/status"));
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
package fr.titionfire.ffsaf.domain.service;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.MatchModel;
|
||||
import fr.titionfire.ffsaf.data.model.MembreModel;
|
||||
import fr.titionfire.ffsaf.data.model.CategoryModel;
|
||||
import fr.titionfire.ffsaf.data.model.TreeModel;
|
||||
import fr.titionfire.ffsaf.data.model.*;
|
||||
import fr.titionfire.ffsaf.data.repository.*;
|
||||
import fr.titionfire.ffsaf.rest.data.CategoryData;
|
||||
import fr.titionfire.ffsaf.rest.data.CategoryFullData;
|
||||
@ -45,10 +42,13 @@ public class CategoryService {
|
||||
@Inject
|
||||
CompetPermService permService;
|
||||
|
||||
@Inject
|
||||
CompetitionGuestRepository competitionGuestRepository;
|
||||
|
||||
public Uni<CategoryData> getByIdAdmin(SecurityCtx securityCtx, CompetitionSystem system, Long id) {
|
||||
return repository.find("systemId = ?1 AND system = ?2", id, system)
|
||||
.firstResult()
|
||||
.onItem().ifNull().failWith(() -> new RuntimeException("Poule not found"))
|
||||
.onItem().ifNull().failWith(() -> new RuntimeException("Category not found"))
|
||||
.call(data -> permService.hasAdminViewPerm(securityCtx, data.getCompet()))
|
||||
.map(CategoryData::fromModel);
|
||||
}
|
||||
@ -171,6 +171,15 @@ public class CategoryService {
|
||||
.invoke(o2 -> o2.forEach(m -> o.membres.put(m.getId(), m)))
|
||||
)
|
||||
)
|
||||
.call(o -> Mutiny.fetch(o.category.getCompet().getGuests())
|
||||
.invoke(o2 -> o2.forEach(m -> o.guest.put(m.getFname() + " " + m.getLname(), m)))
|
||||
.map(o2 -> data.getMatches().stream().flatMap(m -> Stream.of(m.getC1_str(), m.getC2_str())
|
||||
.filter(Objects::nonNull)).distinct().filter(s -> !o.guest.containsKey(s)).map(
|
||||
CompetitionGuestModel::new).toList())
|
||||
.call(o3 -> o3.isEmpty() ? Uni.createFrom().nullItem() :
|
||||
Uni.join().all(o3.stream().map(o4 -> competitionGuestRepository.persist(o4)).toList())
|
||||
.andFailFast())
|
||||
.invoke(o2 -> o2.forEach(m -> o.guest.put(m.getFname() + " " + m.getLname(), m))))
|
||||
.invoke(in -> {
|
||||
ArrayList<TreeModel> node = new ArrayList<>();
|
||||
for (TreeModel treeModel : in.category.getTree())
|
||||
@ -214,8 +223,8 @@ public class CategoryService {
|
||||
}
|
||||
mm.setCategory(in.category);
|
||||
mm.setCategory_ord(m.getCategory_ord());
|
||||
mm.setC1_str(m.getC1_str());
|
||||
mm.setC2_str(m.getC2_str());
|
||||
mm.setC1_guest(in.guest.getOrDefault(m.getC1_str(), null));
|
||||
mm.setC2_guest(in.guest.getOrDefault(m.getC2_str(), null));
|
||||
mm.setC1_id(in.membres.getOrDefault(m.getC1_id(), null));
|
||||
mm.setC2_id(in.membres.getOrDefault(m.getC2_id(), null));
|
||||
mm.setEnd(m.isEnd());
|
||||
@ -238,6 +247,7 @@ public class CategoryService {
|
||||
private static class WorkData {
|
||||
CategoryModel category;
|
||||
HashMap<Long, MembreModel> membres = new HashMap<>();
|
||||
HashMap<String, CompetitionGuestModel> guest = new HashMap<>();
|
||||
List<MatchModel> match = new ArrayList<>();
|
||||
List<Long> toRmMatch;
|
||||
List<TreeModel> unlinkNode;
|
||||
@ -246,7 +256,7 @@ public class CategoryService {
|
||||
|
||||
public Uni<?> delete(SecurityCtx securityCtx, CompetitionSystem system, Long id) {
|
||||
return repository.find("systemId = ?1 AND system = ?2", id, system).firstResult()
|
||||
.onItem().ifNull().failWith(() -> new RuntimeException("Poule not found"))
|
||||
.onItem().ifNull().failWith(() -> new RuntimeException("Category not found"))
|
||||
.call(o -> permService.hasEditPerm(securityCtx, o.getCompet()))
|
||||
.call(o -> Mutiny.fetch(o.getTree())
|
||||
.call(o2 -> o2.isEmpty() ? Uni.createFrom().nullItem() :
|
||||
@ -260,7 +270,7 @@ public class CategoryService {
|
||||
Panache.withTransaction(() -> treeRepository.delete("id IN ?1", in)))
|
||||
)
|
||||
)
|
||||
.call(o -> matchRepository.delete("poule.id = ?1", o.getId()))
|
||||
.call(o -> matchRepository.delete("category.id = ?1", o.getId()))
|
||||
.chain(model -> Panache.withTransaction(() -> repository.delete("id", model.getId())));
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@ import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||
import org.hibernate.reactive.mutiny.Mutiny;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static fr.titionfire.ffsaf.net2.Client_Thread.MAPPER;
|
||||
@ -193,12 +194,17 @@ public class ClubService {
|
||||
}
|
||||
|
||||
public Uni<String> update(long id, FullClubForm input) {
|
||||
AtomicBoolean nameChange = new AtomicBoolean(false);
|
||||
|
||||
return repository.findById(id).call(m -> Mutiny.fetch(m.getContact()))
|
||||
.onItem().transformToUni(Unchecked.function(m -> {
|
||||
TypeReference<HashMap<Contact, String>> typeRef = new TypeReference<>() {
|
||||
};
|
||||
|
||||
m.setName(input.getName());
|
||||
if (!input.getName().equals(m.getName())) {
|
||||
m.setName(input.getName());
|
||||
nameChange.set(true);
|
||||
}
|
||||
m.setCountry(input.getCountry());
|
||||
m.setInternational(input.isInternational());
|
||||
|
||||
@ -211,11 +217,9 @@ public class ClubService {
|
||||
m.setTraining_day_time(input.getTraining_day_time());
|
||||
ls.logChange("Contact interne", m.getContact_intern(), input.getContact_intern(), m);
|
||||
m.setContact_intern(input.getContact_intern());
|
||||
ls.logChange("N° RNA", m.getRNA(), input.getRna(), m);
|
||||
m.setRNA(input.getRna());
|
||||
if (input.getSiret() != null && !input.getSiret().isBlank()) {
|
||||
ls.logChange("N° SIRET", m.getSIRET(), input.getSiret(), m);
|
||||
m.setSIRET(Long.parseLong(input.getSiret()));
|
||||
if (input.getState_id() != null && !input.getState_id().isBlank()) {
|
||||
ls.logChange("N° SIRET", m.getClubId(), input.getState_id(), m);
|
||||
m.setStateId(input.getState_id());
|
||||
}
|
||||
ls.logChange("Adresse administrative", m.getAddress(), input.getAddress(), m);
|
||||
m.setAddress(input.getAddress());
|
||||
@ -230,6 +234,8 @@ public class ClubService {
|
||||
}
|
||||
return Panache.withTransaction(() -> repository.persist(m)).call(() -> ls.append());
|
||||
}))
|
||||
.call(clubModel -> nameChange.get() ? keycloakService.updateGroupFromClub(clubModel) // update group in keycloak
|
||||
: Uni.createFrom().nullItem())
|
||||
.invoke(membreModel -> SReqClub.sendIfNeed(serverCustom.clients,
|
||||
SimpleClubModel.fromModel(membreModel)))
|
||||
.map(__ -> "OK");
|
||||
@ -251,9 +257,8 @@ public class ClubService {
|
||||
clubModel.setTraining_location(input.getTraining_location());
|
||||
clubModel.setTraining_day_time(input.getTraining_day_time());
|
||||
clubModel.setContact_intern(input.getContact_intern());
|
||||
clubModel.setRNA(input.getRna());
|
||||
if (input.getSiret() != null && !input.getSiret().isBlank())
|
||||
clubModel.setSIRET(Long.parseLong(input.getSiret()));
|
||||
if (input.getState_id() != null && !input.getState_id().isBlank())
|
||||
clubModel.setStateId(input.getState_id());
|
||||
clubModel.setAddress(input.getAddress());
|
||||
|
||||
try {
|
||||
@ -300,9 +305,9 @@ public class ClubService {
|
||||
.call(clubModel -> Mutiny.fetch(clubModel.getAffiliations()))
|
||||
.invoke(clubModel -> {
|
||||
data.setName(clubModel.getName());
|
||||
data.setSiret(clubModel.getSIRET());
|
||||
data.setRna(clubModel.getRNA());
|
||||
data.setState_id(clubModel.getStateId());
|
||||
data.setAddress(clubModel.getAddress());
|
||||
data.setContact(clubModel.getContact_intern());
|
||||
data.setSaison(
|
||||
clubModel.getAffiliations().stream().max(Comparator.comparing(AffiliationModel::getSaison))
|
||||
.map(AffiliationModel::getSaison).map(i -> Math.min(i + 1, Utils.getSaison() + 1))
|
||||
|
||||
@ -89,7 +89,7 @@ public class CompetPermService {
|
||||
.onFailure().call(throwable -> cacheAccess.invalidate(securityCtx.getSubject()));
|
||||
|
||||
Uni<HashMap<Long, String>> none = cacheNoneAccess.getAsync(securityCtx.getSubject(),
|
||||
k -> competitionRepository.list("system = ?1", CompetitionSystem.NONE)
|
||||
k -> competitionRepository.list("system = ?1", CompetitionSystem.INTERNAL)
|
||||
.map(competitionModels -> {
|
||||
HashMap<Long, String> map = new HashMap<>();
|
||||
for (CompetitionModel model : competitionModels) {
|
||||
@ -184,7 +184,7 @@ public class CompetPermService {
|
||||
if (!securityCtx.isInClubGroup(o.getClub().getId())) // Only membre club pass here
|
||||
throw new DForbiddenException();
|
||||
|
||||
if (o.getSystem() == CompetitionSystem.NONE)
|
||||
if (o.getSystem() == CompetitionSystem.INTERNAL)
|
||||
if (securityCtx.roleHas("club_president") || securityCtx.roleHas("club_respo_intra")
|
||||
|| securityCtx.roleHas("club_secretaire") || securityCtx.roleHas("club_tresorier"))
|
||||
return Uni.createFrom().nullItem();
|
||||
@ -219,13 +219,58 @@ public class CompetPermService {
|
||||
if (o.getSystem() == CompetitionSystem.SAFCA)
|
||||
return hasSafcaEditPerm(securityCtx, o.getId());
|
||||
|
||||
if (!securityCtx.isInClubGroup(o.getClub().getId())) // Only membre club pass here
|
||||
throw new DForbiddenException();
|
||||
|
||||
if (o.getSystem() == CompetitionSystem.NONE)
|
||||
if (securityCtx.isClubAdmin())
|
||||
if (o.getSystem() == CompetitionSystem.INTERNAL) {
|
||||
if (securityCtx.isInClubGroup(o.getClub().getId()) && securityCtx.isClubAdmin())
|
||||
return Uni.createFrom().nullItem();
|
||||
|
||||
if (o.getAdmin().contains(securityCtx.getSubject()))
|
||||
return Uni.createFrom().nullItem();
|
||||
|
||||
throw new DForbiddenException();
|
||||
}
|
||||
|
||||
throw new DForbiddenException();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has edit perm
|
||||
*/
|
||||
public Uni<CompetitionModel> hasTablePerm(SecurityCtx securityCtx, CompetitionModel competitionModel) {
|
||||
return hasTablePerm(securityCtx, Uni.createFrom().item(competitionModel));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has edit perm
|
||||
*/
|
||||
public Uni<CompetitionModel> hasTablePerm(SecurityCtx securityCtx, long id) {
|
||||
return hasTablePerm(securityCtx, competitionRepository.findById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has edit perm
|
||||
*/
|
||||
public Uni<CompetitionModel> hasTablePerm(SecurityCtx securityCtx, Uni<CompetitionModel> in) {
|
||||
return in.call(Unchecked.function(o -> {
|
||||
if (securityCtx.getSubject().equals(o.getOwner()) || securityCtx.roleHas("federation_admin"))
|
||||
return Uni.createFrom().nullItem();
|
||||
|
||||
if (o.getSystem() == CompetitionSystem.SAFCA)
|
||||
return hasSafcaTablePerm(securityCtx, o.getId());
|
||||
|
||||
if (o.getSystem() == CompetitionSystem.INTERNAL) {
|
||||
if (securityCtx.isInClubGroup(o.getClub().getId()) && securityCtx.isClubAdmin())
|
||||
return Uni.createFrom().nullItem();
|
||||
|
||||
if (o.getAdmin().contains(securityCtx.getSubject()))
|
||||
return Uni.createFrom().nullItem();
|
||||
if (o.getTable().contains(securityCtx.getSubject()))
|
||||
return Uni.createFrom().nullItem();
|
||||
|
||||
throw new DForbiddenException();
|
||||
}
|
||||
|
||||
throw new DForbiddenException();
|
||||
})
|
||||
);
|
||||
@ -236,8 +281,8 @@ public class CompetPermService {
|
||||
Uni.createFrom().nullItem()
|
||||
:
|
||||
getSafcaConfig(id).chain(Unchecked.function(o -> {
|
||||
if (!o.admin().contains(UUID.fromString(securityCtx.getSubject())) && !o.table()
|
||||
.contains(UUID.fromString(securityCtx.getSubject())))
|
||||
if (!o.admin().contains(UUID.fromString(securityCtx.getSubject()))
|
||||
&& !o.table().contains(UUID.fromString(securityCtx.getSubject())))
|
||||
throw new DForbiddenException();
|
||||
return Uni.createFrom().nullItem();
|
||||
}));
|
||||
@ -253,4 +298,16 @@ public class CompetPermService {
|
||||
return Uni.createFrom().nullItem();
|
||||
}));
|
||||
}
|
||||
|
||||
private Uni<?> hasSafcaTablePerm(SecurityCtx securityCtx, long id) {
|
||||
return securityCtx.roleHas("safca_super_admin") ?
|
||||
Uni.createFrom().nullItem()
|
||||
:
|
||||
getSafcaConfig(id).chain(Unchecked.function(o -> {
|
||||
if (!o.admin().contains(UUID.fromString(securityCtx.getSubject()))
|
||||
&& !o.table().contains(UUID.fromString(securityCtx.getSubject())))
|
||||
throw new DForbiddenException();
|
||||
return Uni.createFrom().nullItem();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
package fr.titionfire.ffsaf.domain.service;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.CompetitionModel;
|
||||
import fr.titionfire.ffsaf.data.model.HelloAssoRegisterModel;
|
||||
import fr.titionfire.ffsaf.data.model.MembreModel;
|
||||
import fr.titionfire.ffsaf.data.model.RegisterModel;
|
||||
import fr.titionfire.ffsaf.data.model.*;
|
||||
import fr.titionfire.ffsaf.data.repository.*;
|
||||
import fr.titionfire.ffsaf.net2.ServerCustom;
|
||||
import fr.titionfire.ffsaf.net2.data.SimpleCompet;
|
||||
@ -16,10 +13,9 @@ import fr.titionfire.ffsaf.rest.data.SimpleCompetData;
|
||||
import fr.titionfire.ffsaf.rest.data.SimpleRegisterComb;
|
||||
import fr.titionfire.ffsaf.rest.exception.DBadRequestException;
|
||||
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
|
||||
import fr.titionfire.ffsaf.utils.CompetitionSystem;
|
||||
import fr.titionfire.ffsaf.utils.RegisterMode;
|
||||
import fr.titionfire.ffsaf.utils.SecurityCtx;
|
||||
import fr.titionfire.ffsaf.utils.Utils;
|
||||
import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
|
||||
import fr.titionfire.ffsaf.utils.*;
|
||||
import fr.titionfire.ffsaf.ws.send.SRegister;
|
||||
import io.quarkus.cache.Cache;
|
||||
import io.quarkus.cache.CacheName;
|
||||
import io.quarkus.hibernate.reactive.panache.Panache;
|
||||
@ -64,6 +60,9 @@ public class CompetitionService {
|
||||
@Inject
|
||||
CombRepository combRepository;
|
||||
|
||||
@Inject
|
||||
CompetitionGuestRepository competitionGuestRepository;
|
||||
|
||||
@Inject
|
||||
ServerCustom serverCustom;
|
||||
|
||||
@ -83,6 +82,9 @@ public class CompetitionService {
|
||||
@Inject
|
||||
Vertx vertx;
|
||||
|
||||
@Inject
|
||||
SRegister sRegister;
|
||||
|
||||
@Inject
|
||||
@CacheName("safca-config")
|
||||
Cache cache;
|
||||
@ -103,12 +105,13 @@ public class CompetitionService {
|
||||
if (id == 0) {
|
||||
return Uni.createFrom()
|
||||
.item(new CompetitionData(null, "", "", "", "", new Date(), new Date(),
|
||||
CompetitionSystem.NONE, RegisterMode.FREE, new Date(), new Date(), true,
|
||||
CompetitionSystem.INTERNAL, RegisterMode.FREE, new Date(), new Date(), true,
|
||||
null, "", "", null, true, "", "", "", ""));
|
||||
}
|
||||
return permService.hasAdminViewPerm(securityCtx, id)
|
||||
.chain(competitionModel -> Mutiny.fetch(competitionModel.getInsc())
|
||||
.map(insc -> CompetitionData.fromModel(competitionModel).addInsc(insc)))
|
||||
.chain(insc -> Mutiny.fetch(competitionModel.getGuests())
|
||||
.map(guest -> CompetitionData.fromModel(competitionModel).addInsc(insc, guest))))
|
||||
.chain(data ->
|
||||
vertx.getOrCreateContext().executeBlocking(() -> {
|
||||
keycloakService.getUser(UUID.fromString(data.getOwner()))
|
||||
@ -175,6 +178,7 @@ public class CompetitionService {
|
||||
model.setSystem(data.getSystem());
|
||||
model.setClub(clubModel);
|
||||
model.setInsc(new ArrayList<>());
|
||||
model.setGuests(new ArrayList<>());
|
||||
model.setUuid(UUID.randomUUID().toString());
|
||||
model.setOwner(securityCtx.getSubject());
|
||||
|
||||
@ -184,7 +188,7 @@ public class CompetitionService {
|
||||
}).map(CompetitionData::fromModel)
|
||||
.call(c -> (c.getSystem() == CompetitionSystem.SAFCA) ? cacheAccess.invalidate(
|
||||
securityCtx.getSubject()) : Uni.createFrom().nullItem())
|
||||
.call(c -> (c.getSystem() == CompetitionSystem.NONE) ? cacheNoneAccess.invalidate(
|
||||
.call(c -> (c.getSystem() == CompetitionSystem.INTERNAL) ? cacheNoneAccess.invalidate(
|
||||
securityCtx.getSubject()) : Uni.createFrom().nullItem());
|
||||
} else {
|
||||
return permService.hasEditPerm(securityCtx, data.getId())
|
||||
@ -208,7 +212,7 @@ public class CompetitionService {
|
||||
}).map(CompetitionData::fromModel)
|
||||
.call(c -> (c.getSystem() == CompetitionSystem.SAFCA) ? cacheAccess.invalidate(
|
||||
securityCtx.getSubject()) : Uni.createFrom().nullItem())
|
||||
.call(c -> (c.getSystem() == CompetitionSystem.NONE) ? cacheNoneAccess.invalidate(
|
||||
.call(c -> (c.getSystem() == CompetitionSystem.INTERNAL) ? cacheNoneAccess.invalidate(
|
||||
securityCtx.getSubject()) : Uni.createFrom().nullItem());
|
||||
}
|
||||
}
|
||||
@ -235,11 +239,18 @@ public class CompetitionService {
|
||||
public Uni<List<SimpleRegisterComb>> getRegister(SecurityCtx securityCtx, Long id, String source) {
|
||||
if ("admin".equals(source))
|
||||
return permService.hasEditPerm(securityCtx, id)
|
||||
.chain(c -> Mutiny.fetch(c.getInsc()))
|
||||
.onItem().transformToMulti(Multi.createFrom()::iterable)
|
||||
.onItem().call(combModel -> Mutiny.fetch(combModel.getMembre().getLicences()))
|
||||
.map(combModel -> SimpleRegisterComb.fromModel(combModel, combModel.getMembre().getLicences()))
|
||||
.collect().asList();
|
||||
.chain(c -> {
|
||||
Uni<List<SimpleRegisterComb>> uni = Mutiny.fetch(c.getInsc())
|
||||
.onItem().transformToMulti(Multi.createFrom()::iterable)
|
||||
.onItem().call(combModel -> Mutiny.fetch(combModel.getMembre().getLicences()))
|
||||
.map(cm -> SimpleRegisterComb.fromModel(cm, cm.getMembre().getLicences()))
|
||||
.collect().asList();
|
||||
return uni
|
||||
.call(l -> Mutiny.fetch(c.getGuests())
|
||||
.map(guest -> guest.stream().map(SimpleRegisterComb::fromModel).toList())
|
||||
.invoke(l::addAll));
|
||||
});
|
||||
|
||||
if ("club".equals(source))
|
||||
return Uni.createFrom().nullItem()
|
||||
.invoke(Unchecked.consumer(__ -> {
|
||||
@ -262,17 +273,44 @@ public class CompetitionService {
|
||||
public Uni<SimpleRegisterComb> addRegisterComb(SecurityCtx securityCtx, Long id, RegisterRequestData data,
|
||||
String source) {
|
||||
if ("admin".equals(source))
|
||||
return permService.hasEditPerm(securityCtx, id)
|
||||
.chain(c -> findComb(data.getLicence(), data.getFname(), data.getLname())
|
||||
.call(combModel -> {
|
||||
if (c.getBanMembre() == null)
|
||||
c.setBanMembre(new ArrayList<>());
|
||||
c.getBanMembre().remove(combModel.getId());
|
||||
return Panache.withTransaction(() -> repository.persist(c));
|
||||
})
|
||||
.chain(combModel -> updateRegister(data, c, combModel, true)))
|
||||
.chain(r -> Mutiny.fetch(r.getMembre().getLicences())
|
||||
.map(licences -> SimpleRegisterComb.fromModel(r, licences)));
|
||||
if (data.getLicence() != -1) { // not a guest
|
||||
return permService.hasEditPerm(securityCtx, id)
|
||||
.chain(c -> findComb(data.getLicence(), data.getFname(), data.getLname())
|
||||
.call(combModel -> Mutiny.fetch(combModel.getLicences()))
|
||||
.call(combModel -> {
|
||||
if (c.getBanMembre() == null)
|
||||
c.setBanMembre(new ArrayList<>());
|
||||
c.getBanMembre().remove(combModel.getId());
|
||||
return Panache.withTransaction(() -> repository.persist(c));
|
||||
})
|
||||
.chain(combModel -> updateRegister(data, c, combModel, true)))
|
||||
.map(r -> SimpleRegisterComb.fromModel(r, r.getMembre().getLicences()));
|
||||
} else {
|
||||
return permService.hasEditPerm(securityCtx, id)
|
||||
.chain(c -> competitionGuestRepository.findById(data.getId() * -1)
|
||||
.map(g -> {
|
||||
if (g != null)
|
||||
return g;
|
||||
CompetitionGuestModel model = new CompetitionGuestModel();
|
||||
model.setCompetition(c);
|
||||
return model;
|
||||
}))
|
||||
.chain(model -> {
|
||||
model.setFname(data.getFname());
|
||||
model.setLname(data.getLname());
|
||||
model.setGenre(data.getGenre());
|
||||
model.setClub(data.getClub());
|
||||
model.setCountry(data.getCountry());
|
||||
model.setWeight(data.getWeight());
|
||||
model.setCategorie(data.getCategorie());
|
||||
|
||||
return Panache.withTransaction(() -> competitionGuestRepository.persist(model))
|
||||
.call(r -> model.getCompetition().getSystem() == CompetitionSystem.INTERNAL ?
|
||||
sRegister.sendRegister(model.getCompetition().getUuid(),
|
||||
r) : Uni.createFrom().voidItem());
|
||||
})
|
||||
.map(SimpleRegisterComb::fromModel);
|
||||
}
|
||||
if ("club".equals(source))
|
||||
return repository.findById(id)
|
||||
.invoke(Unchecked.consumer(cm -> {
|
||||
@ -283,6 +321,7 @@ public class CompetitionService {
|
||||
throw new DBadRequestException("Inscription fermée");
|
||||
}))
|
||||
.chain(c -> findComb(data.getLicence(), data.getFname(), data.getLname())
|
||||
.call(combModel -> Mutiny.fetch(combModel.getLicences()))
|
||||
.invoke(Unchecked.consumer(model -> {
|
||||
if (!securityCtx.isInClubGroup(model.getClub().getId()))
|
||||
throw new DForbiddenException();
|
||||
@ -291,8 +330,7 @@ public class CompetitionService {
|
||||
"Vous n'avez pas le droit d'inscrire ce membre (par décision de l'administrateur de la compétition)");
|
||||
}))
|
||||
.chain(combModel -> updateRegister(data, c, combModel, false)))
|
||||
.chain(r -> Mutiny.fetch(r.getMembre().getLicences())
|
||||
.map(licences -> SimpleRegisterComb.fromModel(r, licences)));
|
||||
.map(r -> SimpleRegisterComb.fromModel(r, r.getMembre().getLicences()));
|
||||
|
||||
return repository.findById(id)
|
||||
.invoke(Unchecked.consumer(cm -> {
|
||||
@ -347,15 +385,18 @@ public class CompetitionService {
|
||||
SReqRegister.sendIfNeed(serverCustom.clients,
|
||||
new CompetitionData.SimpleRegister(r.getMembre().getId(),
|
||||
r.getOverCategory(), r.getWeight(), r.getCategorie(),
|
||||
(r.getClub() == null) ? null : r.getClub().getId()), c.getId());
|
||||
(r.getClub() == null) ? null : r.getClub().getId(),
|
||||
(r.getClub() == null) ? null : r.getClub().getName()), c.getId());
|
||||
}
|
||||
return r;
|
||||
}))
|
||||
.chain(r -> Panache.withTransaction(() -> registerRepository.persist(r)));
|
||||
.chain(r -> Panache.withTransaction(() -> registerRepository.persist(r)))
|
||||
.call(r -> c.getSystem() == CompetitionSystem.INTERNAL ?
|
||||
sRegister.sendRegister(c.getUuid(), r) : Uni.createFrom().voidItem());
|
||||
}
|
||||
|
||||
private Uni<MembreModel> findComb(Long licence, String fname, String lname) {
|
||||
if (licence != null && licence != 0) {
|
||||
if (licence != null && licence > 0) {
|
||||
return combRepository.find("licence = ?1", licence).firstResult()
|
||||
.invoke(Unchecked.consumer(combModel -> {
|
||||
if (combModel == null)
|
||||
@ -398,30 +439,45 @@ public class CompetitionService {
|
||||
if (new Date().before(cm.getStartRegister()) || new Date().after(cm.getEndRegister()))
|
||||
throw new DBadRequestException("Inscription fermée");
|
||||
}))
|
||||
.call(cm -> membreService.getByAccountId(securityCtx.getSubject())
|
||||
.call(cm -> membreService.getById(combId)
|
||||
.invoke(Unchecked.consumer(model -> {
|
||||
if (model == null)
|
||||
throw new DNotFoundException("Membre " + combId + " n'existe pas");
|
||||
if (!securityCtx.isInClubGroup(model.getClub().getId()))
|
||||
throw new DForbiddenException();
|
||||
})))
|
||||
.chain(c -> deleteRegister(combId, c, false));
|
||||
|
||||
return repository.findById(id)
|
||||
.invoke(Unchecked.consumer(cm -> {
|
||||
if (cm.getRegisterMode() != RegisterMode.FREE)
|
||||
throw new DForbiddenException();
|
||||
if (new Date().before(cm.getStartRegister()) || new Date().after(cm.getEndRegister()))
|
||||
throw new DBadRequestException("Inscription fermée");
|
||||
}))
|
||||
.call(cm -> membreService.getByAccountId(securityCtx.getSubject())
|
||||
.invoke(Unchecked.consumer(model -> {
|
||||
if (cm.getRegisterMode() != RegisterMode.FREE || !Objects.equals(model.getId(), combId))
|
||||
throw new DForbiddenException();
|
||||
if (new Date().before(cm.getStartRegister()) || new Date().after(cm.getEndRegister()))
|
||||
throw new DBadRequestException("Inscription fermée");
|
||||
})))
|
||||
.chain(c -> deleteRegister(combId, c, false));
|
||||
}
|
||||
|
||||
private Uni<Void> deleteRegister(Long combId, CompetitionModel c, boolean admin) {
|
||||
if (admin && combId < 0) {
|
||||
return competitionGuestRepository.find("competition = ?1 AND id = ?2", c, combId * -1).firstResult()
|
||||
.onFailure().transform(t -> new DBadRequestException("Combattant non inscrit"))
|
||||
.call(Unchecked.function(
|
||||
model -> Panache.withTransaction(() -> competitionGuestRepository.delete(model))
|
||||
.call(r -> c.getSystem() == CompetitionSystem.INTERNAL ?
|
||||
sRegister.sendRegisterRemove(c.getUuid(), combId) : Uni.createFrom()
|
||||
.voidItem())))
|
||||
.replaceWithVoid();
|
||||
}
|
||||
return registerRepository.find("competition = ?1 AND membre.id = ?2", c, combId).firstResult()
|
||||
.onFailure().transform(t -> new DBadRequestException("Combattant non inscrit"))
|
||||
.call(Unchecked.function(registerModel -> {
|
||||
if (!admin && registerModel.isLockEdit())
|
||||
throw new DForbiddenException("Modification bloquée par l'administrateur de la compétition");
|
||||
return Panache.withTransaction(() -> registerRepository.delete(registerModel));
|
||||
return Panache.withTransaction(() -> registerRepository.delete(registerModel))
|
||||
.call(r -> c.getSystem() == CompetitionSystem.INTERNAL ?
|
||||
sRegister.sendRegisterRemove(c.getUuid(), combId) : Uni.createFrom().voidItem());
|
||||
}))
|
||||
.replaceWithVoid();
|
||||
}
|
||||
@ -528,8 +584,13 @@ public class CompetitionService {
|
||||
continue;
|
||||
|
||||
uni = uni.call(__ -> Panache.withTransaction(
|
||||
() -> registerRepository.delete("competition = ?1 AND membre = ?2",
|
||||
reg.getCompetition(), reg.getMembre())));
|
||||
() -> registerRepository.delete("competition = ?1 AND membre = ?2",
|
||||
reg.getCompetition(), reg.getMembre())))
|
||||
.call(r -> reg.getCompetition().getSystem() == CompetitionSystem.INTERNAL ?
|
||||
sRegister.sendRegisterRemove(reg.getCompetition().getUuid(),
|
||||
reg.getMembre().getId()) : Uni.createFrom().voidItem()).onFailure()
|
||||
.recoverWithNull()
|
||||
;
|
||||
}
|
||||
|
||||
return uni;
|
||||
@ -541,7 +602,8 @@ public class CompetitionService {
|
||||
public Uni<Response> registerHelloAsso(NotificationData data) {
|
||||
String organizationSlug = data.getOrganizationSlug();
|
||||
String formSlug = data.getFormSlug();
|
||||
RegisterRequestData req = new RegisterRequestData(null, "", "", null, 0, false);
|
||||
RegisterRequestData req = new RegisterRequestData(null, "", "", null, 0, false, null, Categorie.CADET, Genre.NA,
|
||||
null, "fr");
|
||||
|
||||
return repository.find("data1 = ?1 AND data2 = ?2", organizationSlug, formSlug).firstResult()
|
||||
.onFailure().recoverWithNull()
|
||||
|
||||
@ -85,6 +85,31 @@ public class KeycloakService {
|
||||
return Uni.createFrom().item(club::getClubId);
|
||||
}
|
||||
|
||||
public Uni<String> updateGroupFromClub(ClubModel club) {
|
||||
if (club.getClubId() == null) {
|
||||
return getGroupFromClub(club);
|
||||
} else {
|
||||
LOGGER.infof("Updating name of club group %d-%s...", club.getId(), club.getName());
|
||||
return vertx.getOrCreateContext().executeBlocking(() -> {
|
||||
GroupRepresentation clubGroup =
|
||||
keycloak.realm(realm).groups().groups().stream().filter(g -> g.getName().equals("club"))
|
||||
.findAny()
|
||||
.orElseThrow(() -> new KeycloakException("Fail to fetch group %s".formatted("club")));
|
||||
|
||||
keycloak.realm(realm).groups().group(clubGroup.getId()).getSubGroups(0, 1000, true).stream()
|
||||
.filter(g -> g.getName().startsWith(club.getId() + "-")).findAny()
|
||||
.ifPresent(groupRepresentation -> {
|
||||
groupRepresentation.setName(club.getId() + "-" + club.getName());
|
||||
keycloak.realm(realm).groups().group(groupRepresentation.getId())
|
||||
.update(groupRepresentation);
|
||||
});
|
||||
|
||||
return club.getClubId();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public Uni<String> getUserFromMember(MembreModel membreModel) {
|
||||
if (membreModel.getUserId() == null) {
|
||||
return Uni.createFrom()
|
||||
@ -199,16 +224,16 @@ public class KeycloakService {
|
||||
|
||||
public Uni<String> initCompte(long id) {
|
||||
return membreService.getById(id).invoke(Unchecked.consumer(membreModel -> {
|
||||
if (membreModel.getUserId() != null)
|
||||
throw new KeycloakException("User already linked to the user id=" + id);
|
||||
if (membreModel.getEmail() == null)
|
||||
throw new KeycloakException("User email is null");
|
||||
if (membreModel.getFname() == null || membreModel.getLname() == null)
|
||||
throw new KeycloakException("User name is null");
|
||||
})).chain(membreModel -> creatUser(membreModel).chain(user -> {
|
||||
LOGGER.infof("Set user id %s to membre %s", user.getId(), membreModel.getId());
|
||||
return membreService.setUserId(membreModel.getId(), user.getId()).map(__ -> user.getId());
|
||||
}));
|
||||
if (membreModel.getUserId() != null)
|
||||
throw new KeycloakException("User already linked to the user id=" + id);
|
||||
if (membreModel.getEmail() == null)
|
||||
throw new KeycloakException("User email is null");
|
||||
if (membreModel.getFname() == null || membreModel.getLname() == null)
|
||||
throw new KeycloakException("User name is null");
|
||||
})).chain(membreModel -> creatUser(membreModel).chain(user -> {
|
||||
LOGGER.infof("Set user id %s to membre %s", user.getId(), membreModel.getId());
|
||||
return membreService.setUserId(membreModel.getId(), user.getId()).map(__ -> user.getId());
|
||||
}));
|
||||
}
|
||||
|
||||
private Uni<UserRepresentation> creatUser(MembreModel membreModel) {
|
||||
@ -231,9 +256,6 @@ public class KeycloakService {
|
||||
user.setEmail(membreModel.getEmail());
|
||||
user.setEnabled(true);
|
||||
|
||||
user.setRequiredActions(List.of(RequiredAction.VERIFY_EMAIL.name(),
|
||||
RequiredAction.UPDATE_PASSWORD.name()));
|
||||
|
||||
try (Response response = keycloak.realm(realm).users().create(user)) {
|
||||
if (!response.getStatusInfo().equals(Response.Status.CREATED) && !response.getStatusInfo()
|
||||
.equals(Response.Status.CONFLICT))
|
||||
@ -245,13 +267,6 @@ public class KeycloakService {
|
||||
return getUser(login).orElseThrow(
|
||||
() -> new KeycloakException("Fail to fetch user %s".formatted(finalLogin)));
|
||||
})
|
||||
.call(user -> enabled_email ?
|
||||
vertx.getOrCreateContext().executeBlocking(() -> {
|
||||
keycloak.realm(realm).users().get(user.getId())
|
||||
.executeActionsEmail(List.of(RequiredAction.VERIFY_EMAIL.name(),
|
||||
RequiredAction.UPDATE_PASSWORD.name()));
|
||||
return null;
|
||||
}) : Uni.createFrom().nullItem())
|
||||
.invoke(user -> membreModel.setUserId(user.getId()))
|
||||
.call(user -> updateRole(user.getId(), List.of("safca_user"), List.of()))
|
||||
.call(user -> enabled_email ? reactiveMailer.send(
|
||||
@ -261,14 +276,14 @@ public class KeycloakService {
|
||||
"""
|
||||
Bonjour,
|
||||
|
||||
Suite à votre première inscription %sà la Fédération Française de Soft Armored Fighting (FFSAF), votre compte pour accéder à l'intranet a été créé.
|
||||
Ce compte vous permettra de consulter vos informations, de vous inscrire aux compétitions et de consulter vos résultats.
|
||||
|
||||
Vous allez recevoir dans les prochaines minutes un email vous demandant de vérifier votre email et de définir un mot de passe.
|
||||
Suite à votre première inscription %sà la Fédération Française de Soft Armored Fighting (FFSAF), votre compte intranet a été créé.
|
||||
Ce compte vous permettra de consulter vos informations et, dans un futur proche, de vous inscrire aux compétitions ainsi que d'en consulter les résultats.
|
||||
|
||||
L'intranet est accessible à l'adresse suivante : https://intra.ffsaf.fr
|
||||
Votre nom d'utilisateur est : %s
|
||||
|
||||
Pour définir votre mot de passe, rendez-vous sur l'intranet > "Connexion" > "Mot de passe oublié ?"
|
||||
|
||||
Si vous n'avez pas demandé cette inscription, veuillez contacter le support à l'adresse support@ffsaf.fr.
|
||||
(Pas de panique, nous ne vous enverrons pas de message autre que ce concernant votre compte)
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@ import io.smallrye.mutiny.unchecked.Unchecked;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import org.hibernate.reactive.mutiny.Mutiny;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
@ -26,6 +27,7 @@ import java.util.function.Function;
|
||||
@WithSession
|
||||
@ApplicationScoped
|
||||
public class LicenceService {
|
||||
private static final Logger LOGGER = Logger.getLogger(LicenceService.class);
|
||||
|
||||
@Inject
|
||||
LicenceRepository repository;
|
||||
@ -125,7 +127,9 @@ public class LicenceService {
|
||||
.chain(() -> combRepository.persist(membreModel))
|
||||
: Uni.createFrom().nullItem())
|
||||
.call(__ -> (membreModel.getUserId() == null) ?
|
||||
keycloakService.initCompte(membreModel.getId())
|
||||
keycloakService.initCompte(membreModel.getId()).onFailure()
|
||||
.invoke(t -> LOGGER.infof("Failed to init account: %s", t.getMessage())).onFailure()
|
||||
.recoverWithNull()
|
||||
: Uni.createFrom().nullItem());
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
package fr.titionfire.ffsaf.domain.service;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.CompetitionGuestModel;
|
||||
import fr.titionfire.ffsaf.data.model.MatchModel;
|
||||
import fr.titionfire.ffsaf.data.repository.CombRepository;
|
||||
import fr.titionfire.ffsaf.data.repository.MatchRepository;
|
||||
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.rest.data.MatchData;
|
||||
import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
|
||||
import fr.titionfire.ffsaf.utils.CompetitionSystem;
|
||||
@ -33,6 +35,9 @@ public class MatchService {
|
||||
@Inject
|
||||
CompetPermService permService;
|
||||
|
||||
@Inject
|
||||
CompetitionGuestRepository competitionGuestRepository;
|
||||
|
||||
public Uni<MatchData> getByIdAdmin(SecurityCtx securityCtx, CompetitionSystem system, Long id) {
|
||||
return repository.find("systemId = ?1 AND system = ?2", id, system).firstResult()
|
||||
.onItem().ifNull().failWith(() -> new DNotFoundException("Match not found"))
|
||||
@ -75,8 +80,6 @@ public class MatchService {
|
||||
}
|
||||
)
|
||||
.chain(o -> {
|
||||
o.setC1_str(data.getC1_str());
|
||||
o.setC2_str(data.getC2_str());
|
||||
o.setCategory_ord(data.getCategory_ord());
|
||||
o.getScores().clear();
|
||||
o.getScores().addAll(data.getScores());
|
||||
@ -88,6 +91,20 @@ public class MatchService {
|
||||
.chain(() -> (data.getC1_id() == null) ?
|
||||
Uni.createFrom().nullItem() : combRepository.findById(data.getC2_id()))
|
||||
.invoke(o::setC2_id)
|
||||
.chain(() -> (data.getC1_str() == null) ?
|
||||
Uni.createFrom()
|
||||
.item((CompetitionGuestModel) null) : competitionGuestRepository.find(
|
||||
"fname = ?1 AND lname = ?2",
|
||||
data.getC1_str().substring(0, data.getC1_str().indexOf(" ")),
|
||||
data.getC1_str().substring(data.getC1_str().indexOf(" ") + 1)).firstResult())
|
||||
.invoke(o::setC1_guest)
|
||||
.chain(() -> (data.getC2_str() == null) ?
|
||||
Uni.createFrom()
|
||||
.item((CompetitionGuestModel) null) : competitionGuestRepository.find(
|
||||
"fname = ?1 AND lname = ?2",
|
||||
data.getC2_str().substring(0, data.getC2_str().indexOf(" ")),
|
||||
data.getC2_str().substring(data.getC2_str().indexOf(" ") + 1)).firstResult())
|
||||
.invoke(o::setC2_guest)
|
||||
.chain(() -> Panache.withTransaction(() -> repository.persist(o)));
|
||||
})
|
||||
.map(MatchData::fromModel);
|
||||
|
||||
@ -13,6 +13,7 @@ import fr.titionfire.ffsaf.rest.data.SimpleMembre;
|
||||
import fr.titionfire.ffsaf.rest.data.SimpleMembreInOutData;
|
||||
import fr.titionfire.ffsaf.rest.exception.DBadRequestException;
|
||||
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
|
||||
import fr.titionfire.ffsaf.rest.exception.DInternalError;
|
||||
import fr.titionfire.ffsaf.rest.from.FullMemberForm;
|
||||
import fr.titionfire.ffsaf.utils.*;
|
||||
import io.quarkus.hibernate.reactive.panache.Panache;
|
||||
@ -102,15 +103,47 @@ public class MembreService {
|
||||
return baseUni;
|
||||
}
|
||||
|
||||
private Sort getSort(String order) {
|
||||
|
||||
Sort sort;
|
||||
if (order == null || order.isBlank()) {
|
||||
sort = Sort.ascending("fname", "lname");
|
||||
} else {
|
||||
sort = Sort.empty();
|
||||
|
||||
for (String e : order.split(",")) {
|
||||
String[] split = e.split(" ");
|
||||
if (split.length == 2) {
|
||||
sort = sort.and(split[0],
|
||||
split[1].equals("n") ? Sort.Direction.Ascending : Sort.Direction.Descending);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sort;
|
||||
}
|
||||
|
||||
public Uni<PageResult<SimpleMembre>> searchAdmin(int limit, int page, String search, String club,
|
||||
int licenceRequest, int payState) {
|
||||
int licenceRequest, int payState, String order, String categorie) {
|
||||
if (search == null)
|
||||
search = "";
|
||||
search = "%" + search.replaceAll(" ", "% %") + "%";
|
||||
|
||||
String categorieFilter;
|
||||
if (categorie == null || categorie.isBlank())
|
||||
categorieFilter = " True";
|
||||
else
|
||||
categorieFilter = "categorie = " + Categorie.valueOf(categorie).ordinal();
|
||||
|
||||
String finalSearch = search;
|
||||
Uni<List<LicenceModel>> baseUni = getLicenceListe(licenceRequest, payState);
|
||||
|
||||
Sort sort = getSort(order);
|
||||
if (sort == null)
|
||||
return Uni.createFrom().failure(new DInternalError("Erreur lors calcul du trie"));
|
||||
|
||||
return baseUni
|
||||
.map(l -> l.stream().map(l2 -> l2.getMembre().getId()).toList())
|
||||
.chain(ids -> {
|
||||
@ -120,18 +153,18 @@ public class MembreService {
|
||||
|
||||
if (club == null || club.isBlank()) {
|
||||
query = repository.find(
|
||||
"id " + idf + " ?2 AND (" + FIND_NAME_REQUEST + ")",
|
||||
Sort.ascending("fname", "lname"), finalSearch, ids)
|
||||
"id " + idf + " ?2 AND (" + FIND_NAME_REQUEST + ") AND " + categorieFilter,
|
||||
sort, finalSearch, ids)
|
||||
.page(Page.ofSize(limit));
|
||||
} else {
|
||||
if (club.equals("null")) {
|
||||
query = repository.find(
|
||||
"id " + idf + " ?2 AND club IS NULL AND (" + FIND_NAME_REQUEST + ")",
|
||||
Sort.ascending("fname", "lname"), finalSearch, ids).page(Page.ofSize(limit));
|
||||
"id " + idf + " ?2 AND club IS NULL AND (" + FIND_NAME_REQUEST + ") AND " + categorieFilter,
|
||||
sort, finalSearch, ids).page(Page.ofSize(limit));
|
||||
} else {
|
||||
query = repository.find(
|
||||
"id " + idf + " ?3 AND LOWER(club.name) LIKE LOWER(?2) AND (" + FIND_NAME_REQUEST + ")",
|
||||
Sort.ascending("fname", "lname"), finalSearch, club + "%", ids)
|
||||
"id " + idf + " ?3 AND LOWER(club.name) LIKE LOWER(?2) AND (" + FIND_NAME_REQUEST + ") AND " + categorieFilter,
|
||||
sort, finalSearch, club, ids)
|
||||
.page(Page.ofSize(limit));
|
||||
}
|
||||
}
|
||||
@ -140,7 +173,7 @@ public class MembreService {
|
||||
}
|
||||
|
||||
public Uni<PageResult<SimpleMembre>> search(int limit, int page, String search, int licenceRequest, int payState,
|
||||
String subject) {
|
||||
String order, String categorie, String subject) {
|
||||
if (search == null)
|
||||
search = "";
|
||||
search = "%" + search.replaceAll(" ", "% %") + "%";
|
||||
@ -149,6 +182,16 @@ public class MembreService {
|
||||
|
||||
Uni<List<LicenceModel>> baseUni = getLicenceListe(licenceRequest, payState);
|
||||
|
||||
String categorieFilter;
|
||||
if (categorie == null || categorie.isBlank())
|
||||
categorieFilter = " True";
|
||||
else
|
||||
categorieFilter = "categorie = " + Categorie.valueOf(categorie).ordinal();
|
||||
|
||||
Sort sort = getSort(order);
|
||||
if (sort == null)
|
||||
return Uni.createFrom().failure(new DInternalError("Erreur lors calcul du trie"));
|
||||
|
||||
return baseUni
|
||||
.map(l -> l.stream().map(l2 -> l2.getMembre().getId()).toList())
|
||||
.chain(ids -> {
|
||||
@ -157,8 +200,8 @@ public class MembreService {
|
||||
return repository.find("userId = ?1", subject).firstResult()
|
||||
.chain(membreModel -> {
|
||||
PanacheQuery<MembreModel> query = repository.find(
|
||||
"id " + idf + " ?3 AND club = ?2 AND (" + FIND_NAME_REQUEST + ")",
|
||||
Sort.ascending("fname", "lname"), finalSearch, membreModel.getClub(), ids)
|
||||
"id " + idf + " ?3 AND club = ?2 AND (" + FIND_NAME_REQUEST + ") AND " + categorieFilter,
|
||||
sort, finalSearch, membreModel.getClub(), ids)
|
||||
.page(Page.ofSize(limit));
|
||||
return getPageResult(query, limit, page);
|
||||
});
|
||||
@ -197,6 +240,11 @@ public class MembreService {
|
||||
return Uni.createFrom().nullItem();
|
||||
AtomicReference<ClubModel> clubModel = new AtomicReference<>();
|
||||
|
||||
LOGGER.debugf("Membre import (size=%d)", data2.size());
|
||||
for (SimpleMembreInOutData simpleMembreInOutData : data2) {
|
||||
LOGGER.debugf("-> %s", simpleMembreInOutData.toString());
|
||||
}
|
||||
|
||||
return repository.find("userId = ?1", subject).firstResult()
|
||||
.chain(membreModel -> {
|
||||
clubModel.set(membreModel.getClub());
|
||||
@ -205,20 +253,24 @@ public class MembreService {
|
||||
return repository.list("licence IN ?1 OR LOWER(lname || ' ' || fname) IN ?2 OR email IN ?3",
|
||||
data2.stream().map(SimpleMembreInOutData::getLicence).filter(Objects::nonNull).toList(),
|
||||
data2.stream().map(o -> (o.getNom() + " " + o.getPrenom()).toLowerCase()).toList(),
|
||||
data2.stream().map(SimpleMembreInOutData::getEmail).filter(Objects::nonNull).toList());
|
||||
data2.stream().map(SimpleMembreInOutData::getEmail).filter(o -> o != null && !o.isBlank())
|
||||
.toList());
|
||||
})
|
||||
.call(Unchecked.function(membres -> {
|
||||
for (MembreModel membreModel : membres) {
|
||||
if (!Objects.equals(membreModel.getClub(), clubModel.get()))
|
||||
if (!Objects.equals(membreModel.getClub(), clubModel.get())) {
|
||||
LOGGER.info("Similar membres found: " + membreModel);
|
||||
throw new DForbiddenException(
|
||||
"Le membre n°" + membreModel.getLicence() + " n'appartient pas à votre club");
|
||||
}
|
||||
}
|
||||
Uni<Void> uniResult = Uni.createFrom().voidItem();
|
||||
for (SimpleMembreInOutData dataIn : data2) {
|
||||
MembreModel model = membres.stream()
|
||||
.filter(m -> Objects.equals(m.getLicence(), dataIn.getLicence()) || m.getLname()
|
||||
.equals(dataIn.getNom()) && m.getFname().equals(dataIn.getPrenom()) ||
|
||||
Objects.equals(m.getFname(), dataIn.getEmail())).findFirst()
|
||||
.filter(m -> (dataIn.getLicence() != null && Objects.equals(m.getLicence(),
|
||||
dataIn.getLicence())) || m.getLname().equals(dataIn.getNom()) && m.getFname()
|
||||
.equals(dataIn.getPrenom()) || (dataIn.getEmail() != null && !dataIn.getEmail()
|
||||
.isBlank() && Objects.equals(m.getFname(), dataIn.getEmail()))).findFirst()
|
||||
.orElseGet(() -> {
|
||||
MembreModel mm = new MembreModel();
|
||||
mm.setClub(clubModel.get());
|
||||
@ -226,16 +278,23 @@ public class MembreService {
|
||||
mm.setCountry("FR");
|
||||
return mm;
|
||||
});
|
||||
if (model.getId() != null) {
|
||||
LOGGER.debugf("updating -> %s", dataIn.toString());
|
||||
} else {
|
||||
LOGGER.debugf("creating -> %s", dataIn.toString());
|
||||
}
|
||||
|
||||
if (model.getEmail() != null) {
|
||||
if (model.getEmail() != null && !model.getEmail().isBlank()) {
|
||||
if (model.getLicence() != null && !model.getLicence().equals(dataIn.getLicence())) {
|
||||
throw new DBadRequestException("Email déja utiliser");
|
||||
LOGGER.info("Similar membres found: " + model);
|
||||
throw new DBadRequestException("Email '" + model.getEmail() + "' déja utiliser");
|
||||
}
|
||||
|
||||
if (StringSimilarity.similarity(model.getLname().toUpperCase(),
|
||||
dataIn.getNom().toUpperCase()) > 3 || StringSimilarity.similarity(
|
||||
model.getFname().toUpperCase(), dataIn.getPrenom().toUpperCase()) > 3) {
|
||||
throw new DBadRequestException("Email déja utiliser");
|
||||
LOGGER.info("Similar membres found: " + model);
|
||||
throw new DBadRequestException("Email '" + model.getEmail() + "' déja utiliser");
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,6 +303,7 @@ public class MembreService {
|
||||
if ((!add && StringSimilarity.similarity(model.getLname().toUpperCase(),
|
||||
dataIn.getNom().toUpperCase()) > 3) || (!add && StringSimilarity.similarity(
|
||||
model.getFname().toUpperCase(), dataIn.getPrenom().toUpperCase()) > 3)) {
|
||||
LOGGER.info("Similar membres found: " + model);
|
||||
throw new DBadRequestException(
|
||||
"Pour enregistrer un nouveau membre, veuillez laisser le champ licence vide.");
|
||||
}
|
||||
@ -319,7 +379,7 @@ public class MembreService {
|
||||
return update(repository.findById(id)
|
||||
.call(__ -> repository.count("email LIKE ?1 AND id != ?2", membre.getEmail(), id)
|
||||
.invoke(Unchecked.consumer(c -> {
|
||||
if (c > 0)
|
||||
if (c > 0 && !membre.getEmail().isBlank())
|
||||
throw new DBadRequestException("Email déjà utiliser");
|
||||
})))
|
||||
.chain(membreModel -> clubRepository.findById(membre.getClub())
|
||||
@ -341,7 +401,7 @@ public class MembreService {
|
||||
return update(repository.findById(id)
|
||||
.call(__ -> repository.count("email LIKE ?1 AND id != ?2", membre.getEmail(), id)
|
||||
.invoke(Unchecked.consumer(c -> {
|
||||
if (c > 0)
|
||||
if (c > 0 && !membre.getEmail().isBlank())
|
||||
throw new DBadRequestException("Email déjà utiliser");
|
||||
})))
|
||||
.invoke(Unchecked.consumer(membreModel -> {
|
||||
|
||||
@ -0,0 +1,400 @@
|
||||
package fr.titionfire.ffsaf.domain.service;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.*;
|
||||
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.RegisterRepository;
|
||||
import fr.titionfire.ffsaf.rest.data.ResultCategoryData;
|
||||
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
|
||||
import fr.titionfire.ffsaf.utils.*;
|
||||
import io.quarkus.hibernate.reactive.panache.common.WithSession;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import io.smallrye.mutiny.Multi;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import io.smallrye.mutiny.unchecked.Unchecked;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import lombok.Builder;
|
||||
import org.hibernate.reactive.mutiny.Mutiny;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@WithSession
|
||||
@ApplicationScoped
|
||||
public class ResultService {
|
||||
|
||||
@Inject
|
||||
CompetitionRepository compRepository;
|
||||
|
||||
@Inject
|
||||
RegisterRepository registerRepository;
|
||||
|
||||
@Inject
|
||||
MembreService membreService;
|
||||
|
||||
@Inject
|
||||
CategoryRepository categoryRepository;
|
||||
|
||||
@Inject
|
||||
MatchRepository matchRepository;
|
||||
|
||||
private static final ResourceBundle BUNDLE = ResourceBundle.getBundle("lang.String");
|
||||
|
||||
public Uni<List<Object[]>> getList(SecurityCtx securityCtx) {
|
||||
return membreService.getByAccountId(securityCtx.getSubject())
|
||||
.chain(m -> registerRepository.list("membre = ?1", m))
|
||||
.onItem().transformToMulti(Multi.createFrom()::iterable)
|
||||
.onItem().call(r -> Mutiny.fetch(r.getCompetition()))
|
||||
.onItem().transform(r -> new Object[]{r.getCompetition().getUuid(), r.getCompetition().getName(),
|
||||
r.getCompetition().getDate()})
|
||||
.collect().asList();
|
||||
}
|
||||
|
||||
public Uni<List<ResultCategoryData>> getCategory(String uuid, SecurityCtx securityCtx) {
|
||||
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)))
|
||||
.map(matchModels -> {
|
||||
HashMap<Long, List<MatchModel>> map = new HashMap<>();
|
||||
for (MatchModel matchModel : matchModels) {
|
||||
if (!map.containsKey(matchModel.getCategory().getId()))
|
||||
map.put(matchModel.getCategory().getId(), new ArrayList<>());
|
||||
map.get(matchModel.getCategory().getId()).add(matchModel);
|
||||
}
|
||||
|
||||
return map.values();
|
||||
})
|
||||
.onItem()
|
||||
.transformToMulti(Multi.createFrom()::iterable)
|
||||
.onItem().call(list -> Mutiny.fetch(list.get(0).getCategory().getTree()))
|
||||
.onItem().transform(this::getData)
|
||||
.collect().asList();
|
||||
|
||||
}
|
||||
|
||||
private ResultCategoryData getData(List<MatchModel> matchModels) {
|
||||
ResultCategoryData out = new ResultCategoryData();
|
||||
|
||||
CategoryModel categoryModel = matchModels.get(0).getCategory();
|
||||
out.setName(categoryModel.getName());
|
||||
out.setType(categoryModel.getType());
|
||||
|
||||
getArray2(matchModels, out);
|
||||
getTree(categoryModel.getTree(), out);
|
||||
return out;
|
||||
}
|
||||
|
||||
private void getArray2(List<MatchModel> matchModels_, ResultCategoryData out) {
|
||||
List<MatchModel> matchModels = matchModels_.stream().filter(o -> o.getCategory_ord() >= 0).toList();
|
||||
|
||||
HashMap<Character, List<MatchModel>> matchMap = new HashMap<>();
|
||||
for (MatchModel model : matchModels) {
|
||||
char g = model.getPoule();
|
||||
if (!matchMap.containsKey(g))
|
||||
matchMap.put(g, new ArrayList<>());
|
||||
matchMap.get(g).add(model);
|
||||
}
|
||||
|
||||
matchMap.forEach((c, matchEntities) -> {
|
||||
List<ResultCategoryData.PouleArrayData> matchs = matchEntities.stream()
|
||||
.sorted(Comparator.comparing(MatchModel::getCategory_ord))
|
||||
.map(ResultCategoryData.PouleArrayData::fromModel)
|
||||
.toList();
|
||||
|
||||
List<ResultCategoryData.RankArray> rankArray = matchEntities.stream()
|
||||
.flatMap(m -> Stream.of(m.getC1Name(), m.getC2Name()))
|
||||
.distinct()
|
||||
.map(combName -> {
|
||||
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)))
|
||||
.forEach(matchModel -> {
|
||||
int win = matchModel.win();
|
||||
if ((matchModel.getC1Name()
|
||||
.equals(combName) && win > 0) || matchModel.getC2Name()
|
||||
.equals(combName) && win < 0)
|
||||
w.getAndIncrement();
|
||||
|
||||
for (ScoreEmbeddable score : matchModel.getScores()) {
|
||||
if (score.getS1() <= -900 || score.getS2() <= -900)
|
||||
continue;
|
||||
if (matchModel.getC1Name().equals(combName)) {
|
||||
pointMake.addAndGet(score.getS1());
|
||||
pointTake.addAndGet(score.getS2());
|
||||
} else {
|
||||
pointMake.addAndGet(score.getS2());
|
||||
pointTake.addAndGet(score.getS1());
|
||||
}
|
||||
}
|
||||
});
|
||||
float pointRate = (pointTake.get() == 0) ? pointMake.get() : (float) pointMake.get() / pointTake.get();
|
||||
|
||||
return new ResultCategoryData.RankArray(0, combName, w.get(),
|
||||
pointMake.get(), pointTake.get(), pointRate);
|
||||
})
|
||||
.sorted(Comparator
|
||||
.comparing(ResultCategoryData.RankArray::getWin)
|
||||
.thenComparing(ResultCategoryData.RankArray::getPointRate).reversed())
|
||||
.toList();
|
||||
out.getMatchs().put(c, matchs);
|
||||
|
||||
int lastWin = -1;
|
||||
float pointRate = 0;
|
||||
int rank = 0;
|
||||
for (ResultCategoryData.RankArray rankArray1 : rankArray) {
|
||||
if (rankArray1.getWin() != lastWin || pointRate != rankArray1.getPointRate()) {
|
||||
lastWin = rankArray1.getWin();
|
||||
pointRate = rankArray1.getPointRate();
|
||||
rank++;
|
||||
}
|
||||
rankArray1.setRank(rank);
|
||||
}
|
||||
out.getRankArray().put(c, rankArray);
|
||||
});
|
||||
}
|
||||
|
||||
private static void convertTree(TreeModel src, TreeNode<ResultCategoryData.TreeData> dst) {
|
||||
dst.setData(ResultCategoryData.TreeData.from(src.getMatch()));
|
||||
if (src.getLeft() != null) {
|
||||
dst.setLeft(new TreeNode<>());
|
||||
convertTree(src.getLeft(), dst.getLeft());
|
||||
}
|
||||
if (src.getRight() != null) {
|
||||
dst.setRight(new TreeNode<>());
|
||||
convertTree(src.getRight(), dst.getRight());
|
||||
}
|
||||
}
|
||||
|
||||
private void getTree(List<TreeModel> treeModels, ResultCategoryData out) {
|
||||
ArrayList<TreeNode<ResultCategoryData.TreeData>> trees = new ArrayList<>();
|
||||
treeModels.stream().filter(t -> t.getLevel() != 0).forEach(treeModel -> {
|
||||
TreeNode<ResultCategoryData.TreeData> root = new TreeNode<>();
|
||||
convertTree(treeModel, root);
|
||||
trees.add(root);
|
||||
});
|
||||
out.setTrees(trees);
|
||||
}
|
||||
|
||||
public Uni<CombsArrayData> getAllCombArray(String uuid, SecurityCtx securityCtx) {
|
||||
return hasAccess(uuid, securityCtx)
|
||||
.chain(cm_register -> registerRepository.list("competition.uuid = ?1", uuid)
|
||||
.chain(registers -> matchRepository.list("category.compet.uuid = ?1", uuid)
|
||||
.map(matchModels -> new Pair<>(registers, matchModels)))
|
||||
.map(pair -> {
|
||||
List<RegisterModel> registers = pair.getKey();
|
||||
List<MatchModel> matchModels = pair.getValue();
|
||||
|
||||
CombsArrayData.CombsArrayDataBuilder builder = CombsArrayData.builder();
|
||||
|
||||
List<CombsArrayData.CombsData> combs = matchModels.stream()
|
||||
.flatMap(m -> Stream.of(m.getC1Name(), m.getC2Name()))
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.map(combName -> {
|
||||
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());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Categorie categorie = null;
|
||||
ClubModel club = null;
|
||||
|
||||
Optional<RegisterModel> register = registers.stream()
|
||||
.filter(r -> r.getName().equals(combName)).findFirst();
|
||||
if (register.isPresent()) {
|
||||
categorie = register.get().getCategorie();
|
||||
club = register.get().getClub2();
|
||||
}
|
||||
|
||||
builder2.cat((categorie == null) ? "---" : categorie.getName(BUNDLE));
|
||||
builder2.name(combName);
|
||||
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.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(CombsArrayData.CombsData::name))
|
||||
.toList();
|
||||
|
||||
builder.nb_insc(combs.size());
|
||||
builder.tt_match((int) matchModels.stream().filter(MatchModel::isEnd).count());
|
||||
builder.point(combs.stream().mapToInt(CombsArrayData.CombsData::pointMake).sum());
|
||||
builder.combs(combs);
|
||||
|
||||
return builder.build();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@Builder
|
||||
@RegisterForReflection
|
||||
public static record CombsArrayData(int nb_insc, int tt_match, long point, List<CombsData> combs) {
|
||||
@Builder
|
||||
@RegisterForReflection
|
||||
public static record CombsData(String cat, String club, String name, int w, int l, float ratioVictoire,
|
||||
float ratioPoint, int pointMake, int pointTake) {
|
||||
}
|
||||
}
|
||||
|
||||
public Uni<ClubArrayData> getClubArray(String uuid, SecurityCtx securityCtx) {
|
||||
ClubArrayData.ClubArrayDataBuilder builder = ClubArrayData.builder();
|
||||
|
||||
return hasAccess(uuid, securityCtx)
|
||||
.invoke(cm_register -> builder.name(cm_register.getClub2().getName()))
|
||||
.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 -> new Pair<>(registers, matchModels)))
|
||||
.map(pair -> {
|
||||
List<RegisterModel> registers = pair.getKey();
|
||||
List<MatchModel> matchModels = pair.getValue();
|
||||
|
||||
builder.nb_insc(registers.size());
|
||||
|
||||
AtomicInteger tt_win = new AtomicInteger(0);
|
||||
AtomicInteger tt_match = new AtomicInteger(0);
|
||||
|
||||
List<ClubArrayData.CombData> 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();
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Categorie categorie = register.getCategorie();
|
||||
if (categorie == null)
|
||||
categorie = register.getMembre().getCategorie();
|
||||
|
||||
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());
|
||||
|
||||
tt_win.addAndGet(w.get());
|
||||
tt_match.addAndGet(w.get() + l.get());
|
||||
|
||||
return builder2.build();
|
||||
})
|
||||
.sorted(Comparator.comparing(ClubArrayData.CombData::name))
|
||||
.toList();
|
||||
|
||||
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 builder.build();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@Builder
|
||||
@RegisterForReflection
|
||||
public static record ClubArrayData(String name, int nb_insc, int nb_match, int match_w, float ratioVictoire,
|
||||
float ratioPoint, int pointMake, int pointTake, List<CombData> combs) {
|
||||
@Builder
|
||||
@RegisterForReflection
|
||||
public static record CombData(String cat, String name, int w, int l, float ratioVictoire,
|
||||
float ratioPoint, int pointMake, int pointTake) {
|
||||
}
|
||||
}
|
||||
|
||||
private Uni<RegisterModel> hasAccess(String uuid, SecurityCtx securityCtx) {
|
||||
return registerRepository.find("membre.userId = ?1 AND competition.uuid = ?2", securityCtx.getSubject(), uuid)
|
||||
.firstResult()
|
||||
.invoke(Unchecked.consumer(o -> {
|
||||
if (o == null)
|
||||
throw new DForbiddenException("Access denied");
|
||||
}));
|
||||
}
|
||||
|
||||
private Uni<RegisterModel> hasAccess(Long compId, SecurityCtx securityCtx) {
|
||||
return registerRepository.find("membre.userId = ?1 AND competition.id = ?2", securityCtx.getSubject(), compId)
|
||||
.firstResult()
|
||||
.invoke(Unchecked.consumer(o -> {
|
||||
if (o == null)
|
||||
throw new DForbiddenException("Access denied");
|
||||
}));
|
||||
}
|
||||
}
|
||||
@ -92,7 +92,7 @@ public class AffiliationRequestEndpoints {
|
||||
|
||||
@DELETE
|
||||
@Path("/{id}")
|
||||
@RolesAllowed({"federation_admin"})
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Operation(summary = "Supprime une demande d'affiliation", description = "Cette méthode supprime une demande " +
|
||||
"d'affiliation pour l'identifiant spécifié.")
|
||||
@ -107,7 +107,7 @@ public class AffiliationRequestEndpoints {
|
||||
if (o.getClub() == null && !securityCtx.roleHas("federation_admin"))
|
||||
throw new DForbiddenException();
|
||||
})).invoke(o -> checkPerm.accept(o.getClub()))
|
||||
.chain(o -> service.deleteReqAffiliation(id, reason));
|
||||
.chain(o -> service.deleteReqAffiliation(id, reason, securityCtx.roleHas("federation_admin")));
|
||||
}
|
||||
|
||||
@PUT
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
package fr.titionfire.ffsaf.rest;
|
||||
|
||||
import fr.titionfire.ffsaf.rest.client.SirenService;
|
||||
import fr.titionfire.ffsaf.rest.data.UniteLegaleRoot;
|
||||
import fr.titionfire.ffsaf.rest.client.StateIdService;
|
||||
import fr.titionfire.ffsaf.rest.data.AssoData;
|
||||
import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import jakarta.ws.rs.*;
|
||||
@ -12,18 +13,24 @@ import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
@Path("api/asso")
|
||||
public class AssoEndpoints {
|
||||
|
||||
@RestClient
|
||||
StateIdService stateIdService;
|
||||
|
||||
@RestClient
|
||||
SirenService sirenService;
|
||||
|
||||
@GET
|
||||
@Path("siren/{siren}")
|
||||
@Path("state_id/{stateId}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Operation(hidden = true)
|
||||
public Uni<UniteLegaleRoot> getInfoSiren(@PathParam("siren") String siren) {
|
||||
return sirenService.get_unite(siren).onFailure().transform(throwable -> {
|
||||
public Uni<AssoData> getAssoInfo(@PathParam("stateId") String stateId) {
|
||||
return ((stateId.charAt(0) == 'W') ? stateIdService.get_rna(stateId) : sirenService.get_unite(
|
||||
stateId).chain(stateIdService::getAssoDataFromUnit)).onFailure().transform(throwable -> {
|
||||
if (throwable instanceof WebApplicationException exception) {
|
||||
if (exception.getResponse().getStatus() == 404)
|
||||
return new DNotFoundException("Service momentanément indisponible");
|
||||
if (exception.getResponse().getStatus() == 400)
|
||||
return new DNotFoundException("Siret introuvable");
|
||||
return new DNotFoundException("Asso introuvable");
|
||||
}
|
||||
return throwable;
|
||||
});
|
||||
|
||||
@ -29,6 +29,7 @@ import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
|
||||
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
@ -69,7 +70,8 @@ public class ClubEndpoints {
|
||||
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
|
||||
})
|
||||
public Uni<List<SimpleClubModel>> getAll() {
|
||||
return clubService.getAll().map(clubModels -> clubModels.stream().map(SimpleClubModel::fromModel).toList());
|
||||
return clubService.getAll().map(clubModels -> clubModels.stream().map(SimpleClubModel::fromModel).sorted(
|
||||
Comparator.comparing(SimpleClubModel::getName)).toList());
|
||||
}
|
||||
|
||||
@GET
|
||||
|
||||
@ -58,13 +58,15 @@ public class MembreAdminEndpoints {
|
||||
@Parameter(description = "Page à consulter") @QueryParam("page") Integer page,
|
||||
@Parameter(description = "Text à rechercher") @QueryParam("search") String search,
|
||||
@Parameter(description = "Club à filter") @QueryParam("club") String club,
|
||||
@Parameter(description = "Etat de la demande de licence: 0 -> sans demande, 1 -> avec demande ou validée, 2 -> toute les demande non validée, 3 -> validée, 4 -> tout, 5 -> demande complete, 6 -> demande incomplete") @QueryParam("licenceRequest") int licenceRequest,
|
||||
@Parameter(description = "Etat du payment: 0 -> non payer, 1 -> payer, 2 -> tout") @QueryParam("payment") int payment) {
|
||||
@Parameter(description = "Catégorie à filter") @QueryParam("categorie") String categorie,
|
||||
@Parameter(description = "État de la demande de licence: 0 -> sans demande, 1 -> avec demande ou validée, 2 -> toute les demande non validée, 3 -> validée, 4 -> tout, 5 -> demande complete, 6 -> demande incomplete") @QueryParam("licenceRequest") int licenceRequest,
|
||||
@Parameter(description = "État du payment: 0 -> non payer, 1 -> payer, 2 -> tout") @QueryParam("payment") int payment,
|
||||
@Parameter(description = "Ordre") @QueryParam("order") String order) {
|
||||
if (limit == null)
|
||||
limit = 50;
|
||||
if (page == null || page < 1)
|
||||
page = 1;
|
||||
return membreService.searchAdmin(limit, page - 1, search, club, licenceRequest, payment);
|
||||
return membreService.searchAdmin(limit, page - 1, search, club, licenceRequest, payment, order, categorie);
|
||||
}
|
||||
|
||||
@GET
|
||||
|
||||
@ -50,13 +50,15 @@ public class MembreClubEndpoints {
|
||||
@Parameter(description = "Nombre max de résulta (max 50)") @QueryParam("limit") Integer limit,
|
||||
@Parameter(description = "Page à consulter") @QueryParam("page") Integer page,
|
||||
@Parameter(description = "Text à rechercher") @QueryParam("search") String search,
|
||||
@Parameter(description = "Catégorie à filter") @QueryParam("categorie") String categorie,
|
||||
@Parameter(description = "Etat de la demande de licence: 0 -> sans demande, 1 -> avec demande ou validée, 2 -> toute les demande non validée, 3 -> validée, 4 -> tout, 5 -> demande complete, 6 -> demande incomplete") @QueryParam("licenceRequest") int licenceRequest,
|
||||
@Parameter(description = "Etat du payment: 0 -> non payer, 1 -> payer, 2 -> tout") @QueryParam("payment") int payment) {
|
||||
@Parameter(description = "Etat du payment: 0 -> non payer, 1 -> payer, 2 -> tout") @QueryParam("payment") int payment,
|
||||
@Parameter(description = "Ordre") @QueryParam("order") String order) {
|
||||
if (limit == null)
|
||||
limit = 50;
|
||||
if (page == null || page < 1)
|
||||
page = 1;
|
||||
return membreService.search(limit, page - 1, search, licenceRequest, payment, securityCtx.getSubject());
|
||||
return membreService.search(limit, page - 1, search, licenceRequest, payment, order, categorie, securityCtx.getSubject());
|
||||
}
|
||||
|
||||
@GET
|
||||
|
||||
48
src/main/java/fr/titionfire/ffsaf/rest/ResultEndpoints.java
Normal file
@ -0,0 +1,48 @@
|
||||
package fr.titionfire.ffsaf.rest;
|
||||
|
||||
import fr.titionfire.ffsaf.domain.service.ResultService;
|
||||
import fr.titionfire.ffsaf.rest.data.ResultCategoryData;
|
||||
import fr.titionfire.ffsaf.utils.SecurityCtx;
|
||||
import io.quarkus.security.Authenticated;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Authenticated
|
||||
@Path("api/result")
|
||||
public class ResultEndpoints {
|
||||
|
||||
@Inject
|
||||
ResultService resultService;
|
||||
|
||||
@Inject
|
||||
SecurityCtx securityCtx;
|
||||
|
||||
@GET
|
||||
@Path("list")
|
||||
public Uni<List<Object[]>> getList() {
|
||||
return resultService.getList(securityCtx);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{uuid}")
|
||||
public Uni<List<ResultCategoryData>> getCategory(@PathParam("uuid") String uuid) {
|
||||
return resultService.getCategory(uuid, securityCtx);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{uuid}/club")
|
||||
public Uni<ResultService.ClubArrayData> getClub(@PathParam("uuid") String uuid) {
|
||||
return resultService.getClubArray(uuid, securityCtx);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{uuid}/comb")
|
||||
public Uni<ResultService.CombsArrayData> getComb(@PathParam("uuid") String uuid) {
|
||||
return resultService.getAllCombArray(uuid, securityCtx);
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package fr.titionfire.ffsaf.rest.client;
|
||||
|
||||
import fr.titionfire.ffsaf.rest.data.UniteLegaleRoot;
|
||||
import io.quarkus.cache.CacheResult;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
@ -15,5 +16,6 @@ public interface SirenService {
|
||||
|
||||
@GET
|
||||
@Path("/v3/unites_legales/{SIREN}")
|
||||
@CacheResult(cacheName = "AssoData_siren")
|
||||
Uni<UniteLegaleRoot> get_unite(@PathParam("SIREN") String siren);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package fr.titionfire.ffsaf.rest.client;
|
||||
|
||||
import fr.titionfire.ffsaf.rest.data.AssoData;
|
||||
import fr.titionfire.ffsaf.rest.data.UniteLegaleRoot;
|
||||
import io.quarkus.cache.CacheResult;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
|
||||
|
||||
@Path("/")
|
||||
@RegisterRestClient
|
||||
public interface StateIdService {
|
||||
|
||||
@GET
|
||||
@Path("/associations/{rna}")
|
||||
@CacheResult(cacheName = "AssoData_rna")
|
||||
Uni<AssoData> get_rna(@PathParam("rna") String rna);
|
||||
|
||||
default Uni<AssoData> getAssoDataFromUnit(UniteLegaleRoot u) {
|
||||
AssoData assoData = new AssoData();
|
||||
assoData.setSiren(u.getUnite_legale().getSiren());
|
||||
assoData.setRna(u.getUnite_legale().getIdentifiant_association());
|
||||
|
||||
AssoData.Identite identite = new AssoData.Identite();
|
||||
identite.setNom(u.getUnite_legale().getDenomination());
|
||||
identite.setSiret_siege(u.getUnite_legale().getEtablissement_siege().getSiret());
|
||||
assoData.setIdentite(identite);
|
||||
|
||||
AssoData.Address address = new AssoData.Address();
|
||||
StringBuilder voie = new StringBuilder();
|
||||
if (u.getUnite_legale().getEtablissement_siege().getNumero_voie() != null)
|
||||
voie.append(u.getUnite_legale().getEtablissement_siege().getNumero_voie()).append(' ');
|
||||
if (u.getUnite_legale().getEtablissement_siege().getType_voie() != null)
|
||||
voie.append(u.getUnite_legale().getEtablissement_siege().getType_voie()).append(' ');
|
||||
if (u.getUnite_legale().getEtablissement_siege().getLibelle_voie() != null)
|
||||
voie.append(u.getUnite_legale().getEtablissement_siege().getLibelle_voie()).append(' ');
|
||||
address.setVoie(voie.toString().trim());
|
||||
address.setComplement(u.getUnite_legale().getEtablissement_siege().getComplement_adresse());
|
||||
address.setCode_postal(u.getUnite_legale().getEtablissement_siege().getCode_postal());
|
||||
address.setCommune(
|
||||
new AssoData.Commune(u.getUnite_legale().getEtablissement_siege().getLibelle_commune()));
|
||||
assoData.setCoordonnees(new AssoData.Coordonnee(address));
|
||||
|
||||
return Uni.createFrom().item(assoData);
|
||||
}
|
||||
}
|
||||
48
src/main/java/fr/titionfire/ffsaf/rest/data/AssoData.java
Normal file
@ -0,0 +1,48 @@
|
||||
package fr.titionfire.ffsaf.rest.data;
|
||||
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@RegisterForReflection
|
||||
public class AssoData {
|
||||
String siren;
|
||||
String rna;
|
||||
Identite identite;
|
||||
Coordonnee coordonnees;
|
||||
|
||||
@Data
|
||||
@RegisterForReflection
|
||||
public static class Identite {
|
||||
String nom;
|
||||
String siret_siege;
|
||||
}
|
||||
|
||||
@Data
|
||||
@RegisterForReflection
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class Coordonnee {
|
||||
Address adresse_gestion;
|
||||
}
|
||||
|
||||
@Data
|
||||
@RegisterForReflection
|
||||
public static class Address {
|
||||
String voie;
|
||||
String complement;
|
||||
String code_postal;
|
||||
String pays;
|
||||
Commune commune;
|
||||
}
|
||||
|
||||
@Data
|
||||
@RegisterForReflection
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class Commune {
|
||||
String nom;
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package fr.titionfire.ffsaf.rest.data;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.CompetitionGuestModel;
|
||||
import fr.titionfire.ffsaf.data.model.CompetitionModel;
|
||||
import fr.titionfire.ffsaf.data.model.RegisterModel;
|
||||
import fr.titionfire.ffsaf.utils.Categorie;
|
||||
@ -11,6 +12,7 @@ import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@ -57,9 +59,9 @@ public class CompetitionData {
|
||||
model.getAdresse(), "", model.getDate(), model.getTodate(), null,
|
||||
model.getRegisterMode(), model.getStartRegister(), model.getEndRegister(), model.isPublicVisible(),
|
||||
null, model.getClub().getName(), "", null, false,
|
||||
"","", "","");
|
||||
"", "", "", "");
|
||||
|
||||
if (model.getRegisterMode() == RegisterMode.HELLOASSO){
|
||||
if (model.getRegisterMode() == RegisterMode.HELLOASSO) {
|
||||
out.setData1(model.getData1());
|
||||
out.setData2(model.getData2());
|
||||
}
|
||||
@ -67,10 +69,15 @@ public class CompetitionData {
|
||||
return out;
|
||||
}
|
||||
|
||||
public CompetitionData addInsc(List<RegisterModel> insc) {
|
||||
this.registers = insc.stream()
|
||||
.map(i -> new SimpleRegister(i.getMembre().getId(), i.getOverCategory(), i.getWeight(),
|
||||
i.getCategorie(), (i.getClub() == null) ? null : i.getClub().getId())).toList();
|
||||
public CompetitionData addInsc(List<RegisterModel> insc, List<CompetitionGuestModel> guests) {
|
||||
this.registers = Stream.concat(
|
||||
insc.stream()
|
||||
.map(i -> new SimpleRegister(i.getMembre().getId(), i.getOverCategory(), i.getWeight(),
|
||||
i.getCategorie(), (i.getClub() == null) ? null : i.getClub().getId(),
|
||||
(i.getClub() == null) ? null : i.getClub().getName())),
|
||||
guests.stream()
|
||||
.map(i -> new SimpleRegister(i.getId() * -1, 0, i.getWeight(),
|
||||
i.getCategorie(), null, i.getClub()))).toList();
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -83,5 +90,6 @@ public class CompetitionData {
|
||||
Integer weight;
|
||||
Categorie categorie;
|
||||
Long club;
|
||||
String club_str;
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,8 +28,10 @@ public class MatchData {
|
||||
return null;
|
||||
|
||||
return new MatchData(model.getSystemId(),
|
||||
(model.getC1_id() == null) ? null : model.getC1_id().getId(), model.getC1_str(),
|
||||
(model.getC2_id() == null) ? null : model.getC2_id().getId(), model.getC2_str(),
|
||||
(model.getC1_id() == null) ? null : model.getC1_id().getId(),
|
||||
(model.getC1_guest() == null) ? null : model.getC1_guest().getName(),
|
||||
(model.getC2_id() == null) ? null : model.getC2_id().getId(),
|
||||
(model.getC2_guest() == null) ? null : model.getC2_guest().getName(),
|
||||
model.getCategory().getId(), model.getCategory_ord(), model.isEnd(), model.getPoule(),
|
||||
model.getScores());
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package fr.titionfire.ffsaf.rest.data;
|
||||
|
||||
import fr.titionfire.ffsaf.utils.Categorie;
|
||||
import fr.titionfire.ffsaf.utils.Genre;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
@ -17,4 +19,11 @@ public class RegisterRequestData {
|
||||
private Integer weight;
|
||||
private int overCategory;
|
||||
private boolean lockEdit = false;
|
||||
|
||||
// for guest registration only
|
||||
private Long id = null;
|
||||
private Categorie categorie = Categorie.CADET;
|
||||
private Genre genre = Genre.NA;
|
||||
private String club = null;
|
||||
private String country = null;
|
||||
}
|
||||
|
||||
@ -17,9 +17,9 @@ import java.util.List;
|
||||
@RegisterForReflection
|
||||
public class RenewAffData {
|
||||
String name;
|
||||
Long siret;
|
||||
String rna;
|
||||
String state_id;
|
||||
String address;
|
||||
String contact;
|
||||
int saison;
|
||||
List<RenewMember> members;
|
||||
|
||||
|
||||
@ -0,0 +1,59 @@
|
||||
package fr.titionfire.ffsaf.rest.data;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.MatchModel;
|
||||
import fr.titionfire.ffsaf.utils.ScoreEmbeddable;
|
||||
import fr.titionfire.ffsaf.utils.TreeNode;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@RegisterForReflection
|
||||
public class ResultCategoryData {
|
||||
int type;
|
||||
String name;
|
||||
HashMap<Character, List<PouleArrayData>> matchs = new HashMap<>();
|
||||
HashMap<Character, List<RankArray>> rankArray = new HashMap<>();
|
||||
ArrayList<TreeNode<TreeData>> trees;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@RegisterForReflection
|
||||
public static class RankArray {
|
||||
int rank;
|
||||
String name;
|
||||
int win;
|
||||
int pointMake;
|
||||
int pointTake;
|
||||
float pointRate;
|
||||
}
|
||||
|
||||
@RegisterForReflection
|
||||
public record PouleArrayData(String red, boolean red_w, List<Integer[]> score, boolean blue_w, String blue, boolean end) {
|
||||
public static PouleArrayData fromModel(MatchModel matchModel) {
|
||||
return new PouleArrayData(
|
||||
matchModel.getC1Name(),
|
||||
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.isEnd());
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterForReflection
|
||||
public static record TreeData(long id, String c1FullName, String c2FullName, List<ScoreEmbeddable> scores,
|
||||
boolean end) {
|
||||
public static TreeData from(MatchModel match) {
|
||||
return new TreeData(match.getId(), match.getC1Name(), match.getC2Name(), match.getScores(), match.isEnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14,8 +14,8 @@ import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
public class SimpleAffiliation {
|
||||
@Schema(description = "L'identifiant de l'affiliation.", example = "1")
|
||||
private Long id;
|
||||
@Schema(description = "L'identifiant du club associé à l'affiliation.", example = "123")
|
||||
private Long club;
|
||||
@Schema(description = "L'identifiant du club associé à l'affiliation si id > 0 sinon n° SIRET ou RNA du club.", example = "123")
|
||||
private String club;
|
||||
@Schema(description = "La saison de l'affiliation.", example = "2022")
|
||||
private int saison;
|
||||
@Schema(description = "Indique si l'affiliation est validée ou non.", example = "true")
|
||||
@ -27,7 +27,7 @@ public class SimpleAffiliation {
|
||||
|
||||
return new SimpleAffiliationBuilder()
|
||||
.id(model.getId())
|
||||
.club(model.getClub().getId())
|
||||
.club(String.valueOf(model.getClub().getId()))
|
||||
.saison(model.getSaison())
|
||||
.validate(true)
|
||||
.build();
|
||||
|
||||
@ -36,10 +36,8 @@ public class SimpleClub {
|
||||
private String contact_intern;
|
||||
@Schema(description = "Adresse postale du club", example = "1 rue de l'exemple, 75000 Paris")
|
||||
private String address;
|
||||
@Schema(description = "RNA du club", example = "W123456789")
|
||||
private String RNA;
|
||||
@Schema(description = "Numéro SIRET du club", example = "12345678901234")
|
||||
private Long SIRET;
|
||||
@Schema(description = "Numéro SIRET ou RNA du club", example = "12345678901234")
|
||||
private String state_id;
|
||||
@Schema(description = "Numéro d'affiliation du club", example = "12345")
|
||||
private Long no_affiliation;
|
||||
@Schema(description = "Club international", example = "false")
|
||||
@ -60,8 +58,7 @@ public class SimpleClub {
|
||||
.training_location(model.getTraining_location())
|
||||
.training_day_time(model.getTraining_day_time())
|
||||
.contact_intern(model.getContact_intern())
|
||||
.RNA(model.getRNA())
|
||||
.SIRET(model.getSIRET())
|
||||
.state_id(model.getStateId())
|
||||
.no_affiliation(model.getNo_affiliation())
|
||||
.international(model.isInternational())
|
||||
.address(model.getAddress())
|
||||
|
||||
@ -20,8 +20,8 @@ public class SimpleClubList {
|
||||
String name;
|
||||
@Schema(description = "Pays du club", example = "FR")
|
||||
String country;
|
||||
@Schema(description = "Numéro SIRET du club", example = "12345678901234")
|
||||
Long siret;
|
||||
@Schema(description = "Numéro SIRET ou RNA du club", example = "12345678901234")
|
||||
String state_id;
|
||||
@Schema(description = "Numéro d'affiliation du club", example = "12345")
|
||||
Long no_affiliation;
|
||||
|
||||
@ -29,7 +29,7 @@ public class SimpleClubList {
|
||||
if (model == null)
|
||||
return null;
|
||||
|
||||
return new SimpleClubList(model.getId(), model.getName(), model.getCountry(), model.getSIRET(),
|
||||
return new SimpleClubList(model.getId(), model.getName(), model.getCountry(), model.getStateId(),
|
||||
model.getNo_affiliation());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
package fr.titionfire.ffsaf.rest.data;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.CompetitionGuestModel;
|
||||
import fr.titionfire.ffsaf.data.model.LicenceModel;
|
||||
import fr.titionfire.ffsaf.data.model.MembreModel;
|
||||
import fr.titionfire.ffsaf.data.model.RegisterModel;
|
||||
import fr.titionfire.ffsaf.net2.data.SimpleClubModel;
|
||||
import fr.titionfire.ffsaf.utils.Categorie;
|
||||
import fr.titionfire.ffsaf.utils.Genre;
|
||||
import fr.titionfire.ffsaf.utils.Utils;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import lombok.AllArgsConstructor;
|
||||
@ -18,8 +21,9 @@ public class SimpleRegisterComb {
|
||||
private long id;
|
||||
private String fname;
|
||||
private String lname;
|
||||
private String genre;
|
||||
private String categorie;
|
||||
private Genre genre;
|
||||
private String country;
|
||||
private Categorie categorie;
|
||||
private SimpleClubModel club;
|
||||
private Integer licence;
|
||||
private Integer weight;
|
||||
@ -30,11 +34,18 @@ public class SimpleRegisterComb {
|
||||
public static SimpleRegisterComb fromModel(RegisterModel register, List<LicenceModel> licences) {
|
||||
MembreModel membreModel = register.getMembre();
|
||||
return new SimpleRegisterComb(membreModel.getId(), membreModel.getFname(), membreModel.getLname(),
|
||||
membreModel.getGenre().name(),
|
||||
(register.getCategorie() == null) ? "Catégorie inconnue" : register.getCategorie().getName(),
|
||||
membreModel.getGenre(), membreModel.getCountry(),
|
||||
(register.getCategorie() == null) ? null : register.getCategorie(),
|
||||
SimpleClubModel.fromModel(register.getClub()), membreModel.getLicence(), register.getWeight(),
|
||||
register.getOverCategory(),
|
||||
licences.stream().anyMatch(l -> l.isValidate() && l.getSaison() == Utils.getSaison()),
|
||||
register.isLockEdit());
|
||||
}
|
||||
|
||||
public static SimpleRegisterComb fromModel(CompetitionGuestModel guest) {
|
||||
return new SimpleRegisterComb(guest.getId() * -1, guest.getFname(), guest.getLname(),
|
||||
guest.getGenre(), guest.getCountry(), guest.getCategorie(),
|
||||
new SimpleClubModel(null, guest.getClub(), "fr", null),
|
||||
null, guest.getWeight(), 0, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,10 +25,8 @@ public class SimpleReqAffiliation {
|
||||
Long club_no_aff;
|
||||
@Schema(description = "Nom du club demander", example = "Association sportive")
|
||||
String name;
|
||||
@Schema(description = "Numéro SIRET de l'association", example = "12345678901234")
|
||||
long siret;
|
||||
@Schema(description = "Numéro RNA de l'association", example = "W123456789")
|
||||
String RNA;
|
||||
@Schema(description = "Numéro SIRET ou RNA de l'association", example = "12345678901234")
|
||||
String stateId;
|
||||
@Schema(description = "Adresse de l'association", example = "1 rue de l'exemple, 75000 Paris")
|
||||
String address;
|
||||
@Schema(description = "Email de contact de l'association", example = "test@test.fr")
|
||||
@ -45,8 +43,7 @@ public class SimpleReqAffiliation {
|
||||
return new SimpleReqAffiliation.SimpleReqAffiliationBuilder()
|
||||
.id(model.getId())
|
||||
.name(model.getName())
|
||||
.siret(model.getSiret())
|
||||
.RNA(model.getRNA())
|
||||
.stateId(model.getState_id())
|
||||
.address(model.getAddress())
|
||||
.saison(model.getSaison())
|
||||
.contact(model.getContact())
|
||||
|
||||
@ -16,8 +16,8 @@ public class SimpleReqAffiliationResume {
|
||||
Long id;
|
||||
@Schema(description = "Le nom de l'association.", example = "Association sportive")
|
||||
String name;
|
||||
@Schema(description = "Le numéro SIRET de l'association.", example = "12345678901234")
|
||||
long siret;
|
||||
@Schema(description = "Le numéro SIRET ou RNA de l'association.", example = "12345678901234")
|
||||
String stateId;
|
||||
@Schema(description = "La saison de l'affiliation.", example = "2025")
|
||||
int saison;
|
||||
|
||||
@ -25,10 +25,10 @@ public class SimpleReqAffiliationResume {
|
||||
if (model == null)
|
||||
return null;
|
||||
|
||||
return new SimpleReqAffiliationResume.SimpleReqAffiliationResumeBuilder()
|
||||
return new SimpleReqAffiliationResumeBuilder()
|
||||
.id(model.getId())
|
||||
.name(model.getName())
|
||||
.siret(model.getSiret())
|
||||
.stateId(model.getState_id())
|
||||
.saison(model.getSaison())
|
||||
.build();
|
||||
}
|
||||
|
||||
@ -33,8 +33,8 @@ public class UniteLegaleRoot {
|
||||
public String etat_administratif;
|
||||
public String identifiant_association;
|
||||
public String nic_siege;
|
||||
public Object nom;
|
||||
public Object nom_usage;
|
||||
public String nom;
|
||||
public String nom_usage;
|
||||
public int nombre_periodes;
|
||||
public String nomenclature_activite_principale;
|
||||
public Object prenom_1;
|
||||
@ -67,7 +67,7 @@ public class UniteLegaleRoot {
|
||||
private Object code_pays_etranger_2;
|
||||
private String code_postal;
|
||||
private Object code_postal_2;
|
||||
private Object complement_adresse;
|
||||
private String complement_adresse;
|
||||
private Object complement_adresse2;
|
||||
private String date_creation;
|
||||
private String date_debut;
|
||||
|
||||
@ -11,7 +11,7 @@ import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
import org.jboss.resteasy.reactive.PartType;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@ToString(exclude = {"status", "logo"})
|
||||
public class AffiliationRequestForm {
|
||||
@Schema(description = "L'identifiant de l'affiliation. (null si nouvelle demande d'affiliation)")
|
||||
@FormParam("id")
|
||||
@ -21,13 +21,9 @@ public class AffiliationRequestForm {
|
||||
@FormParam("name")
|
||||
private String name = null;
|
||||
|
||||
@Schema(description = "Le numéro SIRET de l'association.", example = "12345678901234", required = true)
|
||||
@FormParam("siret")
|
||||
private Long siret = null;
|
||||
|
||||
@Schema(description = "Le numéro RNA de l'association. (peut être null)", example = "W123456789")
|
||||
@FormParam("rna")
|
||||
private String rna = null;
|
||||
@Schema(description = "Le numéro SIRET/RNA de l'association.", example = "12345678901234", required = true)
|
||||
@FormParam("state_id")
|
||||
private String state_id = null;
|
||||
|
||||
@Schema(description = "L'adresse de l'association.", example = "1 rue de l'exemple, 75000 Paris", required = true)
|
||||
@FormParam("adresse")
|
||||
@ -114,8 +110,7 @@ public class AffiliationRequestForm {
|
||||
public AffiliationRequestModel toModel() {
|
||||
AffiliationRequestModel model = new AffiliationRequestModel();
|
||||
model.setName(this.getName());
|
||||
model.setSiret(this.getSiret());
|
||||
model.setRNA(this.getRna());
|
||||
model.setState_id(this.getState_id());
|
||||
model.setAddress(this.getAdresse());
|
||||
model.setSaison(this.getSaison());
|
||||
model.setContact(this.getContact());
|
||||
|
||||
@ -4,12 +4,10 @@ import fr.titionfire.ffsaf.utils.RoleAsso;
|
||||
import jakarta.ws.rs.FormParam;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
import org.jboss.resteasy.reactive.PartType;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
public class AffiliationRequestSaveForm {
|
||||
@Schema(description = "L'identifiant de l'affiliation.", example = "1", required = true)
|
||||
@FormParam("id")
|
||||
@ -19,13 +17,9 @@ public class AffiliationRequestSaveForm {
|
||||
@FormParam("name")
|
||||
private String name = null;
|
||||
|
||||
@Schema(description = "Le numéro SIRET de l'association.", example = "12345678901234", required = true)
|
||||
@FormParam("siret")
|
||||
private Long siret = null;
|
||||
|
||||
@Schema(description = "Le numéro RNA de l'association. (peut être null)", example = "W123456789")
|
||||
@FormParam("rna")
|
||||
private String rna = null;
|
||||
@Schema(description = "Le numéro SIRET ou RNA de l'association.", example = "12345678901234", required = true)
|
||||
@FormParam("state_id")
|
||||
private String state_id = null;
|
||||
|
||||
@Schema(description = "L'adresse de l'association.", example = "1 rue de l'exemple, 75000 Paris", required = true)
|
||||
@FormParam("address")
|
||||
@ -171,4 +165,38 @@ public class AffiliationRequestSaveForm {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AffiliationRequestSaveForm{" +
|
||||
"id=" + id +
|
||||
", name='" + name + '\'' +
|
||||
", state_id=" + state_id +
|
||||
", address='" + address + '\'' +
|
||||
", contact='" + contact + '\'' +
|
||||
", status_len=" + status.length +
|
||||
", logo_len=" + logo.length +
|
||||
", m1_mode=" + m1_mode +
|
||||
", m1_role=" + m1_role +
|
||||
", m1_lincence='" + m1_lincence + '\'' +
|
||||
", m1_lname='" + m1_lname + '\'' +
|
||||
", m1_fname='" + m1_fname + '\'' +
|
||||
", m1_email='" + m1_email + '\'' +
|
||||
", m1_email_mode=" + m1_email_mode +
|
||||
", m2_mode=" + m2_mode +
|
||||
", m2_role=" + m2_role +
|
||||
", m2_lincence='" + m2_lincence + '\'' +
|
||||
", m2_lname='" + m2_lname + '\'' +
|
||||
", m2_fname='" + m2_fname + '\'' +
|
||||
", m2_email='" + m2_email + '\'' +
|
||||
", m2_email_mode=" + m2_email_mode +
|
||||
", m3_mode=" + m3_mode +
|
||||
", m3_role=" + m3_role +
|
||||
", m3_lincence='" + m3_lincence + '\'' +
|
||||
", m3_lname='" + m3_lname + '\'' +
|
||||
", m3_fname='" + m3_fname + '\'' +
|
||||
", m3_email='" + m3_email + '\'' +
|
||||
", m3_email_mode=" + m3_email_mode +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,13 +43,9 @@ public class FullClubForm {
|
||||
@Schema(description = "Adresse postale du club", example = "1 rue de l'exemple, 75000 Paris", required = true)
|
||||
private String address = null;
|
||||
|
||||
@FormParam("rna")
|
||||
@Schema(description = "RNA du club", example = "W123456789")
|
||||
private String rna = null;
|
||||
|
||||
@FormParam("siret")
|
||||
@Schema(description = "Numéro SIRET du club", example = "12345678901234", required = true)
|
||||
private String siret = null;
|
||||
@FormParam("state_id")
|
||||
@Schema(description = "Numéro SIRET ou RNA du club", example = "12345678901234", required = true)
|
||||
private String state_id = null;
|
||||
|
||||
@FormParam("international")
|
||||
@Schema(description = "Club international", example = "false", required = true)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
package fr.titionfire.ffsaf.utils;
|
||||
|
||||
public enum CompetitionSystem {
|
||||
SAFCA, NONE
|
||||
SAFCA, INTERNAL
|
||||
}
|
||||
|
||||
35
src/main/java/fr/titionfire/ffsaf/utils/TreeNode.java
Normal file
@ -0,0 +1,35 @@
|
||||
package fr.titionfire.ffsaf.utils;
|
||||
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@RegisterForReflection
|
||||
public class TreeNode<T> {
|
||||
private T data;
|
||||
private TreeNode<T> left;
|
||||
private TreeNode<T> right;
|
||||
|
||||
public TreeNode(T data) {
|
||||
this(data, null, null);
|
||||
}
|
||||
|
||||
public int death() {
|
||||
int dg = 0;
|
||||
int dd = 0;
|
||||
|
||||
if (this.right != null)
|
||||
dg = this.right.death();
|
||||
|
||||
if (this.left != null)
|
||||
dg = this.left.death();
|
||||
|
||||
return 1 + Math.max(dg, dd);
|
||||
}
|
||||
}
|
||||
206
src/main/java/fr/titionfire/ffsaf/ws/CompetitionWS.java
Normal file
@ -0,0 +1,206 @@
|
||||
package fr.titionfire.ffsaf.ws;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import fr.titionfire.ffsaf.data.repository.CompetitionRepository;
|
||||
import fr.titionfire.ffsaf.domain.service.CompetPermService;
|
||||
import fr.titionfire.ffsaf.net2.MessageType;
|
||||
import fr.titionfire.ffsaf.utils.SecurityCtx;
|
||||
import fr.titionfire.ffsaf.ws.data.WelcomeInfo;
|
||||
import fr.titionfire.ffsaf.ws.recv.RCategorie;
|
||||
import fr.titionfire.ffsaf.ws.recv.RMatch;
|
||||
import fr.titionfire.ffsaf.ws.recv.RRegister;
|
||||
import fr.titionfire.ffsaf.ws.recv.WSReceiver;
|
||||
import fr.titionfire.ffsaf.ws.send.JsonUni;
|
||||
import io.quarkus.hibernate.reactive.panache.common.WithSession;
|
||||
import io.quarkus.security.Authenticated;
|
||||
import io.quarkus.websockets.next.*;
|
||||
import io.smallrye.mutiny.Multi;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import io.smallrye.mutiny.unchecked.Unchecked;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.ForbiddenException;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
|
||||
import static fr.titionfire.ffsaf.net2.Client_Thread.MAPPER;
|
||||
|
||||
@Authenticated
|
||||
@WebSocket(path = "api/ws/competition/{uuid}")
|
||||
public class CompetitionWS {
|
||||
private static final Logger LOGGER = Logger.getLogger(CompetitionWS.class);
|
||||
|
||||
private static final HashMap<WebSocketConnection, HashMap<UUID, JsonUni<?>>> waitingResponse = new HashMap<>();
|
||||
|
||||
@Inject
|
||||
RMatch rMatch;
|
||||
|
||||
@Inject
|
||||
RCategorie rCategorie;
|
||||
|
||||
@Inject
|
||||
RRegister rRegister;
|
||||
|
||||
@Inject
|
||||
SecurityCtx securityCtx;
|
||||
|
||||
@Inject
|
||||
CompetPermService competPermService;
|
||||
|
||||
@Inject
|
||||
CompetitionRepository competitionRepository;
|
||||
|
||||
HashMap<Method, Object> wsMethods = new HashMap<>();
|
||||
|
||||
public void getWSReceiverMethods(Class<?> clazz, Object object) {
|
||||
for (Method method : clazz.getDeclaredMethods()) {
|
||||
if (method.isAnnotationPresent(WSReceiver.class)) {
|
||||
if (method.getParameterCount() <= 1) {
|
||||
LOGGER.warnf("@WSReceiver has no parameters for method %s", method.getName());
|
||||
continue;
|
||||
}
|
||||
if (!method.getReturnType().equals(Uni.class)) {
|
||||
LOGGER.warnf("@WSReceiver has returned unexpected type %s", method.getReturnType());
|
||||
continue;
|
||||
}
|
||||
// method.setAccessible(true);
|
||||
wsMethods.put(method, object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
void init() {
|
||||
getWSReceiverMethods(RMatch.class, rMatch);
|
||||
getWSReceiverMethods(RCategorie.class, rCategorie);
|
||||
getWSReceiverMethods(RRegister.class, rRegister);
|
||||
}
|
||||
|
||||
@OnOpen
|
||||
@WithSession
|
||||
Uni<MessageOut> open(WebSocketConnection connection) {
|
||||
LOGGER.infof("Opening CompetitionWS for %s", connection.pathParam("uuid"));
|
||||
LOGGER.debugf("Active connections: %d", connection.getOpenConnections().size());
|
||||
|
||||
return competitionRepository.find("uuid", connection.pathParam("uuid")).firstResult()
|
||||
.invoke(Unchecked.consumer(cm -> {
|
||||
if (cm == null)
|
||||
throw new ForbiddenException();
|
||||
}))
|
||||
.call(cm -> competPermService.hasEditPerm(securityCtx, cm).map(__ -> PermLevel.ADMIN)
|
||||
.onFailure()
|
||||
.recoverWithUni(competPermService.hasTablePerm(securityCtx, cm).map(__ -> PermLevel.TABLE))
|
||||
.onFailure()
|
||||
.recoverWithUni(competPermService.hasViewPerm(securityCtx, cm).map(__ -> PermLevel.VIEW))
|
||||
.invoke(prem -> connection.userData().put(UserData.TypedKey.forString("prem"), prem.toString()))
|
||||
.invoke(prem -> LOGGER.infof("Connection permission: %s", prem))
|
||||
.onFailure().transform(t -> new ForbiddenException()))
|
||||
.invoke(__ -> {
|
||||
connection.userData().put(UserData.TypedKey.forString("subject"), securityCtx.getSubject());
|
||||
waitingResponse.put(connection, new HashMap<>());
|
||||
})
|
||||
.map(cm -> {
|
||||
WelcomeInfo welcomeInfo = new WelcomeInfo();
|
||||
|
||||
welcomeInfo.setName(cm.getName());
|
||||
welcomeInfo.setPerm(connection.userData().get(UserData.TypedKey.forString("prem")));
|
||||
|
||||
return new MessageOut(UUID.randomUUID(), "welcomeInfo", MessageType.NOTIFY, welcomeInfo);
|
||||
});
|
||||
}
|
||||
|
||||
@OnClose
|
||||
void close(WebSocketConnection connection) {
|
||||
LOGGER.infof("Closing CompetitionWS for %s ", connection.pathParam("uuid"));
|
||||
LOGGER.debugf("Active connections: %d", connection.getOpenConnections().size());
|
||||
|
||||
waitingResponse.remove(connection);
|
||||
}
|
||||
|
||||
private MessageOut makeReply(MessageIn message, Object data) {
|
||||
return new MessageOut(message.uuid(), message.code(), MessageType.REPLY, data);
|
||||
}
|
||||
|
||||
private MessageOut makeError(MessageIn message, Object data) {
|
||||
return new MessageOut(message.uuid(), message.code(), MessageType.ERROR, data);
|
||||
}
|
||||
|
||||
@OnTextMessage
|
||||
Multi<MessageOut> processAsync(WebSocketConnection connection, MessageIn message) {
|
||||
System.out.println(message);
|
||||
if (message.type() == MessageType.REPLY || message.type() == MessageType.ERROR) {
|
||||
try {
|
||||
JsonUni<?> jsonUni = waitingResponse.get(connection).get(message.uuid());
|
||||
if (jsonUni == null) {
|
||||
LOGGER.debugf("No JsonUni found for %s", message.uuid());
|
||||
if (message.type() == MessageType.ERROR)
|
||||
LOGGER.errorf("request %s make error %s", message.uuid(), message.data());
|
||||
return null;
|
||||
}
|
||||
waitingResponse.get(connection).remove(message.uuid());
|
||||
|
||||
if (message.type() == MessageType.ERROR)
|
||||
return jsonUni.castAndError(message.data()).onFailure()
|
||||
.invoke(t -> LOGGER.error(t.getMessage(), t))
|
||||
.replaceWith((MessageOut) null).toMulti().filter(__ -> false);
|
||||
|
||||
return jsonUni.castAndChain(message.data()).onFailure()
|
||||
.invoke(t -> LOGGER.error(t.getMessage(), t))
|
||||
.replaceWith((MessageOut) null).toMulti().filter(__ -> false);
|
||||
} catch (JsonProcessingException e) {
|
||||
LOGGER.warn(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
for (Map.Entry<Method, Object> entry : wsMethods.entrySet()) {
|
||||
Method method = entry.getKey();
|
||||
WSReceiver wsReceiver = method.getAnnotation(WSReceiver.class);
|
||||
PermLevel perm = PermLevel.valueOf(connection.userData().get(UserData.TypedKey.forString("prem")));
|
||||
if (wsReceiver.code().equalsIgnoreCase(message.code())) {
|
||||
if (wsReceiver.permission().ordinal() > perm.ordinal())
|
||||
return Uni.createFrom().item(makeError(message, "Permission denied")).toMulti();
|
||||
return ((Uni<?>) method.invoke(entry.getValue(), connection,
|
||||
MAPPER.treeToValue(message.data(), method.getParameterTypes()[1])))
|
||||
.map(o -> makeReply(message, o))
|
||||
.onFailure()
|
||||
.recoverWithItem(t -> {
|
||||
LOGGER.error(t.getMessage(), t);
|
||||
return makeError(message, t.getMessage());
|
||||
}).toMulti()
|
||||
.filter(__ -> message.type() == MessageType.REQUEST);
|
||||
}
|
||||
}
|
||||
return Uni.createFrom().item(makeError(message, "No receiver method found")).toMulti();
|
||||
} catch (IllegalAccessException | InvocationTargetException | JsonProcessingException e) {
|
||||
LOGGER.warn(e.getMessage(), e);
|
||||
return Uni.createFrom().item(makeError(message, e.getMessage())).toMulti();
|
||||
}
|
||||
|
||||
// return Uni.createFrom().item(new Message<>(message.uuid(), message.code(), MessageType.REPLY, "ko"));
|
||||
}
|
||||
|
||||
public static Uni<Void> sendNotifyToOtherEditor(WebSocketConnection connection, String code, Object data) {
|
||||
String uuid = connection.pathParam("uuid");
|
||||
|
||||
List<Uni<Void>> queue = new ArrayList<>();
|
||||
queue.add(Uni.createFrom().voidItem()); // For avoid empty queue
|
||||
|
||||
connection.getOpenConnections().forEach(c -> {
|
||||
if (uuid.equals(c.pathParam("uuid"))) {
|
||||
queue.add(c.sendText(new MessageOut(UUID.randomUUID(), code, MessageType.NOTIFY, data)));
|
||||
}
|
||||
});
|
||||
|
||||
return Uni.join().all(queue).andCollectFailures().onFailure().recoverWithNull().replaceWithVoid();
|
||||
}
|
||||
|
||||
@OnError
|
||||
Uni<Void> error(WebSocketConnection connection, ForbiddenException t) {
|
||||
return connection.close(CloseReason.INTERNAL_SERVER_ERROR);
|
||||
//return "forbidden: " + securityCtx.getSubject();
|
||||
}
|
||||
}
|
||||
12
src/main/java/fr/titionfire/ffsaf/ws/MessageIn.java
Normal file
@ -0,0 +1,12 @@
|
||||
package fr.titionfire.ffsaf.ws;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import fr.titionfire.ffsaf.net2.MessageType;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@RegisterForReflection
|
||||
public record MessageIn (UUID uuid, String code, MessageType type, JsonNode data){
|
||||
|
||||
}
|
||||
11
src/main/java/fr/titionfire/ffsaf/ws/MessageOut.java
Normal file
@ -0,0 +1,11 @@
|
||||
package fr.titionfire.ffsaf.ws;
|
||||
|
||||
import fr.titionfire.ffsaf.net2.MessageType;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@RegisterForReflection
|
||||
public record MessageOut(UUID uuid, String code, MessageType type, Object data){
|
||||
|
||||
}
|
||||
8
src/main/java/fr/titionfire/ffsaf/ws/PermLevel.java
Normal file
@ -0,0 +1,8 @@
|
||||
package fr.titionfire.ffsaf.ws;
|
||||
|
||||
public enum PermLevel {
|
||||
NONE,
|
||||
VIEW,
|
||||
TABLE,
|
||||
ADMIN,
|
||||
}
|
||||
11
src/main/java/fr/titionfire/ffsaf/ws/data/WelcomeInfo.java
Normal file
@ -0,0 +1,11 @@
|
||||
package fr.titionfire.ffsaf.ws.data;
|
||||
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@RegisterForReflection
|
||||
public class WelcomeInfo {
|
||||
private String name;
|
||||
private String perm;
|
||||
}
|
||||
229
src/main/java/fr/titionfire/ffsaf/ws/recv/RCategorie.java
Normal file
@ -0,0 +1,229 @@
|
||||
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.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.TreeNode;
|
||||
import fr.titionfire.ffsaf.ws.PermLevel;
|
||||
import fr.titionfire.ffsaf.ws.send.SSCategorie;
|
||||
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;
|
||||
|
||||
private Uni<CategoryModel> getById(long id, WebSocketConnection connection) {
|
||||
return categoryRepository.findById(id)
|
||||
.invoke(Unchecked.consumer(o -> {
|
||||
if (o == null)
|
||||
throw new DNotFoundException("Catégorie non trouver");
|
||||
if (!o.getCompet().getUuid().equals(connection.pathParam("uuid")))
|
||||
throw new DForbiddenException("Permission denied");
|
||||
}));
|
||||
}
|
||||
|
||||
@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 getById(id, connection)
|
||||
.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 -> SSCategorie.sendAddCategory(connection, cat))
|
||||
.map(CategoryModel::getId);
|
||||
}
|
||||
|
||||
@WSReceiver(code = "updateCategory", permission = PermLevel.ADMIN)
|
||||
public Uni<Void> updateCategory(WebSocketConnection connection, JustCategorie categorie) {
|
||||
return getById(categorie.id, connection)
|
||||
.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 -> SSCategorie.sendCategory(connection, 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 getById(data.categoryId, connection)
|
||||
.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 -> SSCategorie.sendTreeCategory(connection, trees)))
|
||||
.replaceWithVoid();
|
||||
}
|
||||
|
||||
@RegisterForReflection
|
||||
public record JustCategorie(long id, String name, int type, String liceName) {
|
||||
public 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;
|
||||
}
|
||||
}
|
||||
346
src/main/java/fr/titionfire/ffsaf/ws/recv/RMatch.java
Normal file
@ -0,0 +1,346 @@
|
||||
package fr.titionfire.ffsaf.ws.recv;
|
||||
|
||||
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;
|
||||
import io.smallrye.mutiny.unchecked.Unchecked;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@WithSession
|
||||
@ApplicationScoped
|
||||
@RegisterForReflection
|
||||
public class RMatch {
|
||||
private static final Logger LOGGER = Logger.getLogger(RMatch.class);
|
||||
|
||||
@Inject
|
||||
MatchRepository matchRepository;
|
||||
|
||||
@Inject
|
||||
CombRepository combRepository;
|
||||
|
||||
@Inject
|
||||
CategoryRepository categoryRepository;
|
||||
|
||||
@Inject
|
||||
TreeRepository treeRepository;
|
||||
|
||||
@Inject
|
||||
CompetitionGuestRepository competitionGuestRepository;
|
||||
|
||||
private Uni<MatchModel> getById(long id, WebSocketConnection connection) {
|
||||
return matchRepository.findById(id)
|
||||
.invoke(Unchecked.consumer(o -> {
|
||||
if (o == null)
|
||||
throw new DNotFoundException("Matche non trouver");
|
||||
if (!o.getCategory().getCompet().getUuid().equals(connection.pathParam("uuid")))
|
||||
throw new DForbiddenException("Permission denied");
|
||||
}));
|
||||
}
|
||||
|
||||
private Uni<MatchModel> creatMatch(CategoryModel categoryModel, AddMatch m) {
|
||||
return Uni.createFrom().item(() -> {
|
||||
MatchModel matchModel = new MatchModel();
|
||||
|
||||
matchModel.setCategory(categoryModel);
|
||||
matchModel.setCategory_ord(m.categorie_ord);
|
||||
matchModel.setEnd(false);
|
||||
matchModel.setPoule(m.poule);
|
||||
|
||||
return matchModel;
|
||||
})
|
||||
.call(mm -> m.c1() >= 0 ?
|
||||
combRepository.findById(m.c1()).invoke(mm::setC1_id) :
|
||||
competitionGuestRepository.findById(m.c1() * -1).invoke(mm::setC1_guest))
|
||||
.call(mm -> m.c2() >= 0 ?
|
||||
combRepository.findById(m.c2()).invoke(mm::setC2_id) :
|
||||
competitionGuestRepository.findById(m.c2() * -1).invoke(mm::setC2_guest));
|
||||
}
|
||||
|
||||
@WSReceiver(code = "addMatch", permission = PermLevel.ADMIN)
|
||||
public Uni<Void> addMatch(WebSocketConnection connection, AddMatch m) {
|
||||
return categoryRepository.findById(m.categorie)
|
||||
.invoke(Unchecked.consumer(o -> {
|
||||
if (o == null)
|
||||
throw new DNotFoundException("Catégorie non trouver");
|
||||
if (!o.getCompet().getUuid().equals(connection.pathParam("uuid")))
|
||||
throw new DForbiddenException("Permission denied");
|
||||
}))
|
||||
.chain(categoryModel -> creatMatch(categoryModel, m))
|
||||
.chain(mm -> Panache.withTransaction(() -> matchRepository.create(mm)))
|
||||
.call(mm -> SSMatch.sendMatch(connection, MatchEntity.fromModel(mm)))
|
||||
.replaceWithVoid();
|
||||
}
|
||||
|
||||
@WSReceiver(code = "updateMatchComb", permission = PermLevel.ADMIN)
|
||||
public Uni<Void> updateMatchComb(WebSocketConnection connection, MatchComb match) {
|
||||
return getById(match.id(), connection)
|
||||
.call(mm -> match.c1() != null ?
|
||||
match.c1() >= 0 ?
|
||||
combRepository.findById(match.c1()).invoke(model -> {
|
||||
mm.setC1_id(model);
|
||||
mm.setC1_guest(null);
|
||||
}) :
|
||||
competitionGuestRepository.findById(match.c1() * -1).invoke(model -> {
|
||||
mm.setC1_id(null);
|
||||
mm.setC1_guest(model);
|
||||
|
||||
}) :
|
||||
Uni.createFrom().nullItem().invoke(__ -> {
|
||||
mm.setC1_id(null);
|
||||
mm.setC1_guest(null);
|
||||
}))
|
||||
.call(mm -> match.c2() != null ?
|
||||
match.c2() >= 0 ?
|
||||
combRepository.findById(match.c2()).invoke(model -> {
|
||||
mm.setC2_id(model);
|
||||
mm.setC2_guest(null);
|
||||
}) :
|
||||
competitionGuestRepository.findById(match.c2() * -1).invoke(model -> {
|
||||
mm.setC2_id(null);
|
||||
mm.setC2_guest(model);
|
||||
}) :
|
||||
Uni.createFrom().nullItem().invoke(__ -> {
|
||||
mm.setC2_id(null);
|
||||
mm.setC2_guest(null);
|
||||
}))
|
||||
.chain(mm -> Panache.withTransaction(() -> matchRepository.persist(mm)))
|
||||
.call(mm -> SSMatch.sendMatch(connection, MatchEntity.fromModel(mm)))
|
||||
.replaceWithVoid();
|
||||
}
|
||||
|
||||
@WSReceiver(code = "updateMatchOrder", permission = PermLevel.ADMIN)
|
||||
public Uni<Void> updateMatchComb(WebSocketConnection connection, MatchOrder order) {
|
||||
return getById(order.id(), connection)
|
||||
.call(m -> matchRepository.update(
|
||||
"category_ord = category_ord + 1 WHERE category_ord >= ?1 AND category_ord < ?2", order.pos,
|
||||
m.getCategory_ord()))
|
||||
.call(m -> matchRepository.update(
|
||||
"category_ord = category_ord - 1 WHERE category_ord <= ?1 AND category_ord > ?2", order.pos,
|
||||
m.getCategory_ord()))
|
||||
.invoke(m -> m.setCategory_ord(order.pos))
|
||||
.call(m -> Panache.withTransaction(() -> matchRepository.persist(m)))
|
||||
.call(mm -> SSMatch.sendMatchOrder(connection, order))
|
||||
.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)
|
||||
.chain(matchModel -> Panache.withTransaction(() -> matchRepository.delete(matchModel)))
|
||||
.call(__ -> SSMatch.sendDeleteMatch(connection, idMatch))
|
||||
.replaceWithVoid();
|
||||
}
|
||||
|
||||
@WSReceiver(code = "recalculateMatch", permission = PermLevel.ADMIN)
|
||||
public Uni<Void> recalculateMatch(WebSocketConnection connection, RecalculateMatch data) {
|
||||
ArrayList<MatchEntity> matches = new ArrayList<>();
|
||||
return categoryRepository.findById(data.categorie)
|
||||
.invoke(Unchecked.consumer(o -> {
|
||||
if (o == null)
|
||||
throw new DNotFoundException("Catégorie non trouver");
|
||||
if (!o.getCompet().getUuid().equals(connection.pathParam("uuid")))
|
||||
throw new DForbiddenException("Permission denied");
|
||||
}))
|
||||
.call(cm -> matchRepository.delete("id IN ?1 AND category = ?2", data.matchesToRemove, cm)
|
||||
.call(__ -> SSMatch.sendDeleteMatch(connection, data.matchesToRemove)))
|
||||
.call(cm -> matchRepository.list("id IN ?1 AND category = ?2",
|
||||
Stream.concat(data.matchOrderToUpdate.keySet().stream(),
|
||||
data.matchPouleToUpdate.keySet().stream())
|
||||
.distinct().toList(), cm)
|
||||
.invoke(matchModels -> matchModels.forEach(model -> {
|
||||
if (data.matchPouleToUpdate.containsKey(model.getId()))
|
||||
model.setPoule(data.matchPouleToUpdate.get(model.getId()));
|
||||
if (data.matchOrderToUpdate.containsKey(model.getId()))
|
||||
model.setCategory_ord(data.matchOrderToUpdate.get(model.getId()));
|
||||
}))
|
||||
.call(mm -> Panache.withTransaction(() -> matchRepository.persist(mm)))
|
||||
.invoke(mm -> matches.addAll(mm.stream().map(MatchEntity::fromModel).toList()))
|
||||
)
|
||||
.chain(categoryModel -> {
|
||||
Uni<List<MatchModel>> uni = Uni.createFrom().item(new ArrayList<>());
|
||||
for (AddMatch match : data.newMatch)
|
||||
uni = uni.call(l -> creatMatch(categoryModel, match).invoke(l::add));
|
||||
return uni;
|
||||
}
|
||||
)
|
||||
.chain(mm -> Panache.withTransaction(() -> matchRepository.create(mm))
|
||||
.invoke(__ -> matches.addAll(mm.stream().map(MatchEntity::fromModel).toList())))
|
||||
.call(__ -> SSMatch.sendMatch(connection, matches))
|
||||
.replaceWithVoid();
|
||||
}
|
||||
|
||||
@RegisterForReflection
|
||||
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) {
|
||||
}
|
||||
|
||||
@RegisterForReflection
|
||||
public record AddMatch(long categorie, long categorie_ord, char poule, long c1, long c2) {
|
||||
}
|
||||
|
||||
public record RecalculateMatch(long categorie, List<AddMatch> newMatch, HashMap<Long, Integer> matchOrderToUpdate,
|
||||
HashMap<Long, Character> matchPouleToUpdate, List<Long> matchesToRemove) {
|
||||
}
|
||||
}
|
||||
37
src/main/java/fr/titionfire/ffsaf/ws/recv/RRegister.java
Normal file
@ -0,0 +1,37 @@
|
||||
package fr.titionfire.ffsaf.ws.recv;
|
||||
|
||||
import fr.titionfire.ffsaf.data.repository.CompetitionRepository;
|
||||
import fr.titionfire.ffsaf.domain.entity.CombEntity;
|
||||
import fr.titionfire.ffsaf.ws.PermLevel;
|
||||
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 jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import org.hibernate.reactive.mutiny.Mutiny;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@WithSession
|
||||
@ApplicationScoped
|
||||
@RegisterForReflection
|
||||
public class RRegister {
|
||||
|
||||
@Inject
|
||||
CompetitionRepository competitionRepository;
|
||||
|
||||
@WSReceiver(code = "getRegister", permission = PermLevel.ADMIN)
|
||||
public Uni<List<CombEntity>> getRegister(WebSocketConnection connection, Object o) {
|
||||
return competitionRepository.find("uuid", connection.pathParam("uuid")).firstResult()
|
||||
.call(cm -> Mutiny.fetch(cm.getInsc()))
|
||||
.call(cm -> Mutiny.fetch(cm.getGuests()))
|
||||
.map(cm -> {
|
||||
ArrayList<CombEntity> combEntities = new ArrayList<>();
|
||||
combEntities.addAll(cm.getInsc().stream().map(CombEntity::fromModel).toList());
|
||||
combEntities.addAll(cm.getGuests().stream().map(CombEntity::fromModel).toList());
|
||||
return combEntities;
|
||||
});
|
||||
}
|
||||
}
|
||||
17
src/main/java/fr/titionfire/ffsaf/ws/recv/WSReceiver.java
Normal file
@ -0,0 +1,17 @@
|
||||
package fr.titionfire.ffsaf.ws.recv;
|
||||
|
||||
import fr.titionfire.ffsaf.ws.PermLevel;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@RegisterForReflection
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface WSReceiver {
|
||||
|
||||
String code();
|
||||
|
||||
PermLevel permission() default PermLevel.VIEW;
|
||||
|
||||
}
|
||||
33
src/main/java/fr/titionfire/ffsaf/ws/send/JsonUni.java
Normal file
@ -0,0 +1,33 @@
|
||||
package fr.titionfire.ffsaf.ws.send;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import io.smallrye.mutiny.unchecked.Unchecked;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import static fr.titionfire.ffsaf.net2.Client_Thread.MAPPER;
|
||||
|
||||
@RegisterForReflection
|
||||
public class JsonUni<T> {
|
||||
|
||||
private final Class<T> clazz;
|
||||
private final Function<? super T, Uni<?>> mapper;
|
||||
|
||||
public JsonUni(Class<T> clazz, Function<? super T, Uni<?>> mapper) {
|
||||
this.clazz = clazz;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
public Uni<?> castAndChain(JsonNode message) throws JsonProcessingException {
|
||||
return Uni.createFrom().item(MAPPER.treeToValue(message, clazz)).chain(mapper);
|
||||
}
|
||||
|
||||
public Uni<?> castAndError(JsonNode message) throws JsonProcessingException {
|
||||
return Uni.createFrom().item((T) null).invoke(Unchecked.consumer(__ -> {
|
||||
throw new WSClientError(MAPPER.treeToValue(message, String.class));
|
||||
})).chain(mapper);
|
||||
}
|
||||
}
|
||||
53
src/main/java/fr/titionfire/ffsaf/ws/send/SRegister.java
Normal file
@ -0,0 +1,53 @@
|
||||
package fr.titionfire.ffsaf.ws.send;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.CompetitionGuestModel;
|
||||
import fr.titionfire.ffsaf.data.model.RegisterModel;
|
||||
import fr.titionfire.ffsaf.domain.entity.CombEntity;
|
||||
import fr.titionfire.ffsaf.net2.MessageType;
|
||||
import fr.titionfire.ffsaf.ws.CompetitionWS;
|
||||
import fr.titionfire.ffsaf.ws.MessageOut;
|
||||
import fr.titionfire.ffsaf.ws.PermLevel;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import io.quarkus.websockets.next.OpenConnections;
|
||||
import io.quarkus.websockets.next.UserData;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@ApplicationScoped
|
||||
@RegisterForReflection
|
||||
public class SRegister {
|
||||
|
||||
@SuppressWarnings("CdiInjectionPointsInspection")
|
||||
@Inject
|
||||
OpenConnections connections;
|
||||
|
||||
public Uni<Void> sendRegister(String uuid, RegisterModel registerModel) {
|
||||
return send(uuid, "sendRegister", CombEntity.fromModel(registerModel));
|
||||
}
|
||||
|
||||
public Uni<Void> sendRegister(String uuid, CompetitionGuestModel model) {
|
||||
return send(uuid, "sendRegister", CombEntity.fromModel(model));
|
||||
}
|
||||
|
||||
public Uni<Void> sendRegisterRemove(String uuid, Long combId) {
|
||||
return send(uuid, "sendRegisterRemove", combId);
|
||||
}
|
||||
|
||||
public Uni<Void> send(String uuid, String code, Object data) {
|
||||
List<Uni<Void>> queue = connections.findByEndpointId(CompetitionWS.class.getCanonicalName()).stream()
|
||||
.filter(c -> c.pathParam("uuid").equals(uuid) && PermLevel.valueOf(
|
||||
c.userData().get(UserData.TypedKey.forString("prem"))).ordinal() >= PermLevel.ADMIN.ordinal())
|
||||
.map(c -> c.sendText(
|
||||
new MessageOut(UUID.randomUUID(), code, MessageType.NOTIFY, data)))
|
||||
.toList();
|
||||
|
||||
if (queue.isEmpty())
|
||||
return Uni.createFrom().voidItem();
|
||||
return Uni.join().all(queue).andCollectFailures().replaceWithVoid();
|
||||
}
|
||||
|
||||
}
|
||||
33
src/main/java/fr/titionfire/ffsaf/ws/send/SSCategorie.java
Normal file
@ -0,0 +1,33 @@
|
||||
package fr.titionfire.ffsaf.ws.send;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.CategoryModel;
|
||||
import fr.titionfire.ffsaf.domain.entity.TreeEntity;
|
||||
import fr.titionfire.ffsaf.ws.CompetitionWS;
|
||||
import fr.titionfire.ffsaf.ws.recv.RCategorie;
|
||||
import io.quarkus.websockets.next.WebSocketConnection;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SSCategorie {
|
||||
|
||||
public static Uni<Void> sendAddCategory(WebSocketConnection connection, CategoryModel category) {
|
||||
return SSCategorie.sendAddCategory(connection, RCategorie.JustCategorie.from(category));
|
||||
}
|
||||
|
||||
public static Uni<Void> sendAddCategory(WebSocketConnection connection, RCategorie.JustCategorie justCategorie) {
|
||||
return CompetitionWS.sendNotifyToOtherEditor(connection, "sendAddCategory", justCategorie);
|
||||
}
|
||||
|
||||
public static Uni<Void> sendCategory(WebSocketConnection connection, CategoryModel category) {
|
||||
return SSCategorie.sendCategory(connection, RCategorie.JustCategorie.from(category));
|
||||
}
|
||||
|
||||
public static Uni<Void> sendCategory(WebSocketConnection connection, RCategorie.JustCategorie justCategorie) {
|
||||
return CompetitionWS.sendNotifyToOtherEditor(connection, "sendCategory", justCategorie);
|
||||
}
|
||||
|
||||
public static Uni<Void> sendTreeCategory(WebSocketConnection connection, List<TreeEntity> treeEntities) {
|
||||
return CompetitionWS.sendNotifyToOtherEditor(connection, "sendTreeCategory", treeEntities);
|
||||
}
|
||||
}
|
||||
32
src/main/java/fr/titionfire/ffsaf/ws/send/SSMatch.java
Normal file
@ -0,0 +1,32 @@
|
||||
package fr.titionfire.ffsaf.ws.send;
|
||||
|
||||
import fr.titionfire.ffsaf.domain.entity.MatchEntity;
|
||||
import fr.titionfire.ffsaf.ws.CompetitionWS;
|
||||
import fr.titionfire.ffsaf.ws.recv.RMatch;
|
||||
import io.quarkus.websockets.next.WebSocketConnection;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SSMatch {
|
||||
|
||||
public static Uni<Void> sendMatch(WebSocketConnection connection, MatchEntity matchEntity) {
|
||||
return SSMatch.sendMatch(connection, List.of(matchEntity));
|
||||
}
|
||||
|
||||
public static Uni<Void> sendMatch(WebSocketConnection connection, List<MatchEntity> matchEntities) {
|
||||
return CompetitionWS.sendNotifyToOtherEditor(connection, "sendMatch", matchEntities);
|
||||
}
|
||||
|
||||
public static Uni<Void> sendMatchOrder(WebSocketConnection connection, RMatch.MatchOrder matchOrder) {
|
||||
return CompetitionWS.sendNotifyToOtherEditor(connection, "sendMatchOrder", matchOrder);
|
||||
}
|
||||
|
||||
public static Uni<Void> sendDeleteMatch(WebSocketConnection connection, Long l) {
|
||||
return SSMatch.sendDeleteMatch(connection, List.of(l));
|
||||
}
|
||||
|
||||
public static Uni<Void> sendDeleteMatch(WebSocketConnection connection, List<Long> longs) {
|
||||
return CompetitionWS.sendNotifyToOtherEditor(connection, "sendDeleteMatch", longs);
|
||||
}
|
||||
}
|
||||
13
src/main/java/fr/titionfire/ffsaf/ws/send/WSClientError.java
Normal file
@ -0,0 +1,13 @@
|
||||
package fr.titionfire.ffsaf.ws.send;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serial;
|
||||
|
||||
public class WSClientError extends IOException {
|
||||
@Serial
|
||||
private static final long serialVersionUID = -3790479241838684450L;
|
||||
|
||||
public WSClientError(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@ -43,6 +43,10 @@ notif.affRequest.mail=
|
||||
|
||||
siren-api.key=siren-ap
|
||||
quarkus.rest-client."fr.titionfire.ffsaf.rest.client.SirenService".url=https://data.siren-api.fr/
|
||||
quarkus.rest-client."fr.titionfire.ffsaf.rest.client.StateIdService".url=https://www.data-asso.fr/api/
|
||||
|
||||
quarkus.websockets-next.server.auto-ping-interval=PT10s
|
||||
quarkus.websockets-next.client.connection-idle-timeout=PT30s
|
||||
|
||||
#Login
|
||||
quarkus.oidc.token-state-manager.split-tokens=true
|
||||
|
||||
16
src/main/resources/lang/String.properties
Normal file
@ -0,0 +1,16 @@
|
||||
filtre.all=--tout--
|
||||
no.licence=Non licenci\u00E9
|
||||
|
||||
|
||||
# Categories
|
||||
Cat.SUPER_MINI=Super Mini
|
||||
Cat.MINI_POUSSIN=Mini Poussin
|
||||
Cat.POUSSIN= Poussin
|
||||
Cat.BENJAMIN=Benjamin
|
||||
Cat.MINIME=Minime
|
||||
Cat.CADET=Cadet
|
||||
Cat.JUNIOR=Junior
|
||||
Cat.SENIOR1=Senior 1
|
||||
Cat.SENIOR2=Senior 2
|
||||
Cat.VETERAN1=V\u00E9t\u00E9ran 1
|
||||
Cat.VETERAN2=V\u00E9t\u00E9ran 2
|
||||
@ -8,12 +8,8 @@
|
||||
|
||||
<link href="/index.css" rel="stylesheet">
|
||||
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
|
||||
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||
integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
|
||||
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
|
||||
@ -27,11 +23,8 @@
|
||||
<div class="spinner"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" crossorigin="anonymous"></script>
|
||||
<script async type="module" src="/src/main.jsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
52
src/main/webapp/package-lock.json
generated
@ -8,6 +8,9 @@
|
||||
"name": "webapp",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.5.1",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.5.1",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.5.1",
|
||||
@ -399,6 +402,55 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@dnd-kit/accessibility": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz",
|
||||
"integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@dnd-kit/core": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz",
|
||||
"integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==",
|
||||
"dependencies": {
|
||||
"@dnd-kit/accessibility": "^3.1.1",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@dnd-kit/sortable": {
|
||||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/sortable/-/sortable-10.0.0.tgz",
|
||||
"integrity": "sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==",
|
||||
"dependencies": {
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@dnd-kit/core": "^6.3.0",
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@dnd-kit/utilities": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz",
|
||||
"integrity": "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/is-prop-valid": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz",
|
||||
|
||||
@ -10,6 +10,9 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.5.1",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.5.1",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.5.1",
|
||||
|
||||
@ -38,18 +38,22 @@ async function getData() {
|
||||
|
||||
let icon = null;
|
||||
if (d.uuid !== null) {
|
||||
const img = await getMeta(`${api_url}/api/club/${d.uuid}/logo`);
|
||||
let ratio = img.naturalHeight / img.naturalWidth;
|
||||
try {
|
||||
const img = await getMeta(`${api_url}/api/club/${d.uuid}/logo`);
|
||||
let ratio = img.naturalHeight / img.naturalWidth;
|
||||
|
||||
icon = L.icon({
|
||||
iconUrl: `${api_url}/api/club/${d.uuid}/logo`,
|
||||
icon = L.icon({
|
||||
iconUrl: `${api_url}/api/club/${d.uuid}/logo`,
|
||||
|
||||
iconSize: [50, 50 * ratio], // size of the icon
|
||||
//shadowSize: [50, 64], // size of the shadow
|
||||
iconAnchor: [25, 50 * ratio], // point of the icon which will correspond to marker's location
|
||||
//shadowAnchor: [4, 62], // the same for the shadow
|
||||
popupAnchor: [0, -50 * ratio] // point from which the popup should open relative to the iconAnchor
|
||||
});
|
||||
iconSize: [50, 50 * ratio], // size of the icon
|
||||
//shadowSize: [50, 64], // size of the shadow
|
||||
iconAnchor: [25, 50 * ratio], // point of the icon which will correspond to marker's location
|
||||
//shadowAnchor: [4, 62], // the same for the shadow
|
||||
popupAnchor: [0, -50 * ratio] // point from which the popup should open relative to the iconAnchor
|
||||
});
|
||||
}catch (e) {
|
||||
console.log("Error loading image for club", d.name, e);
|
||||
}
|
||||
}
|
||||
|
||||
for (const m of d.training_location) {
|
||||
|
||||
1
src/main/webapp/public/flags/svg/ad.svg
Normal file
|
After Width: | Height: | Size: 54 KiB |
1
src/main/webapp/public/flags/svg/ae.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="600" viewBox="0 0 12 6"><path fill="#00843d" d="M0 0h12v6H0z"/><path fill="#fff" d="M0 2h12v4H0z"/><path d="M0 4h12v2H0z"/><path fill="#c8102e" d="M0 0h3v6H0z"/></svg>
|
||||
|
After Width: | Height: | Size: 228 B |
1
src/main/webapp/public/flags/svg/af.svg
Normal file
|
After Width: | Height: | Size: 217 KiB |
1
src/main/webapp/public/flags/svg/ag.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="600" viewBox="0 0 138 92"><path fill="#fff" d="M0 0h138v92H0z"/><path d="M0 0h138l-9 46H9z"/><path fill="#fcd116" d="M69 46 39 36l15.288-2.926-13.004-8.555 15.244 3.147-8.741-12.879 12.879 8.741-3.147-15.244 8.555 13.004L69 6l2.926 15.288 8.555-13.004-3.147 15.244 12.879-8.741-8.741 12.879 15.244-3.147-13.004 8.555L99 36z"/><path fill="#0072c6" d="M9 36h120v20H9z"/><path fill="#ce1126" d="m0 0 69 92 69-92v92H0z"/></svg>
|
||||
|
After Width: | Height: | Size: 483 B |
1
src/main/webapp/public/flags/svg/ai.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="600"><clipPath id="a"><path d="M0 0v150h700v150H600zm600 0H300v350H0v-50z"/></clipPath><path fill="#012169" d="M0 0h1200v600H0z"/><path stroke="#fff" stroke-width="60" d="m0 0 600 300m0-300L0 300"/><path stroke="#c8102e" stroke-width="40" d="m0 0 600 300m0-300L0 300" clip-path="url(#a)"/><path stroke="#fff" stroke-width="100" d="M300 0v350M0 150h700"/><path stroke="#c8102e" stroke-width="60" d="M300 0v350M0 150h700"/><path fill="#012169" d="M0 300h600V0h200v400H0z"/><path fill="#fff" d="M784.8 156c0 151.011 17.51 203.045 52.565 238.1C858.27 414.853 867.539 422.662 900 444c32.461-21.337 41.729-29.146 62.636-49.9 35.053-35.055 52.564-87.089 52.564-238.1-25.497 10.917-40.026 16.209-61.051 15.885-18.809-.29-38.737-9.024-54.149-15.885-15.412 6.86-35.34 15.595-54.148 15.885-21.026.324-35.555-4.968-61.052-15.885"/><g transform="matrix(3.50845 0 0 3.34488 -47.153 -59.398)"><path fill="#f90" d="M271 87c1.543 3.63 6.49 7.637 7.85 9.601-1.731 1.964-2.077 1.75-1.85 5.399 3.01-3.15 3.064-3.478 5-3 4.241 4.232.759 13.321-2.746 15.297-3.504 2.108-2.868-.073-8.12 2.569 2.408 2.059 5.198-.302 7.478.329 1.239 1.47-.589 4.149.374 6.672 2.015-.194 1.773-4.262 2.242-5.737C282.7 112.726 291.55 108.957 292 104c1.866-.876 3.731-.274 6 1-1.13-4.644-4.868-4.594-5.87-6.044-2.385-3.645-4.499-7.803-9.593-8.881-3.867-.82-3.578.246-6.056-1.444-1.543-1.202-6.231-3.474-5.481-1.631"/><circle cx="281.317" cy="91.128" r=".806" fill="#fff"/></g><g transform="matrix(-1.639 -2.95744 3.10207 -1.56258 1034.545 1220.517)"><path fill="#f90" d="M271 87c1.543 3.63 6.49 7.637 7.85 9.601-1.731 1.964-2.077 1.75-1.85 5.399 3.01-3.15 3.064-3.478 5-3 4.241 4.232.759 13.321-2.746 15.297-3.504 2.108-2.868-.073-8.12 2.569 2.408 2.059 5.198-.302 7.478.329 1.239 1.47-.589 4.149.374 6.672 2.015-.194 1.773-4.262 2.242-5.737C282.7 112.726 291.55 108.957 292 104c1.866-.876 3.731-.274 6 1-1.13-4.644-4.868-4.594-5.87-6.044-2.385-3.645-4.499-7.803-9.593-8.881-3.867-.82-3.578.246-6.056-1.444-1.543-1.202-6.231-3.474-5.481-1.631"/><circle cx="281.317" cy="91.128" r=".806" fill="#fff"/></g><g transform="matrix(-1.80698 2.86712 -3.00733 -1.72273 1682.51 -336.808)"><path fill="#f90" d="M271 87c1.543 3.63 6.49 7.637 7.85 9.601-1.731 1.964-2.077 1.75-1.85 5.399 3.01-3.15 3.064-3.478 5-3 4.241 4.232.759 13.321-2.746 15.297-3.504 2.108-2.868-.073-8.12 2.569 2.408 2.059 5.198-.302 7.478.329 1.239 1.47-.589 4.149.374 6.672 2.015-.194 1.773-4.262 2.242-5.737C282.7 112.726 291.55 108.957 292 104c1.866-.876 3.731-.274 6 1-1.13-4.644-4.868-4.594-5.87-6.044-2.385-3.645-4.499-7.803-9.593-8.881-3.867-.82-3.578.246-6.056-1.444-1.543-1.202-6.231-3.474-5.481-1.631"/><circle cx="281.317" cy="91.128" r=".806" fill="#fff"/></g><path fill="#9cf" d="M813.698 362.055c6.72 12.755 14.602 22.979 23.668 32.044C858.272 414.854 867.539 422.663 900 444c32.461-21.337 41.73-29.146 62.637-49.9 9.065-9.066 16.945-19.29 23.665-32.045z"/></svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
1
src/main/webapp/public/flags/svg/al.svg
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
1
src/main/webapp/public/flags/svg/am.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="600"><path fill="#F2A800" d="M0 0h1200v600H0z"/><path fill="#0033A0" d="M0 0h1200v400H0z"/><path fill="#D90012" d="M0 0h1200v200H0z"/></svg>
|
||||
|
After Width: | Height: | Size: 201 B |
1
src/main/webapp/public/flags/svg/ao.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="600"><path d="M0 0h900v600H0z"/><path fill="#cc092f" d="M0 0h900v300H0z"/><path d="M390.858 205.797h36.644l11.112-34.537 11.41 34.537h36.64l-29.433 21.926 11.409 35.135-30.026-21.324-29.731 21.324 11.41-35.135z" fill="#ffcb00" fill-rule="evenodd"/><path d="m524.801 394.706-28.827-22.53c29.127-23.724 48.052-60.064 48.052-100.605 0-61.866-44.144-113.824-102.411-126.137l4.504-21.025c8.11 1.803 17.624 5.217 25.432 7.916l7.51-12.608c8.1 3.9 17.118 7.803 24.621 12.608l-5.703 13.518c7.51 4.808 16.575 12.251 21.616 18.112l11.277-8.809c6.008 6.604 13.218 13.507 18.323 20.721l-10.211 10.512c6.594 9.68 9.143 14.135 14.004 25.287l14.327-3.36c2.706 8.408 6.814 18.702 8.32 27.408l-13.566 5.332c1.62 6.766 3.718 18.584 3.583 28.525-.011.598-.056 1.276-.056 1.878l14.167 2.021c-.6 8.712-.897 18.625-2.704 27.333h-14.714c-2.1 9.005-4.81 20.02-8.11 28.425l12.308 7.213c-3.901 7.805-7.8 17.117-12.908 24.626l-13.514-5.703c-5.11 7.505-10.81 14.71-17.118 21.321l8.706 11.41c-2.398 2.1-4.502 4.205-6.908 6.61m-63.362-2.704 21.772 13.12c-2.03 1.857-8.112 5.006-9.724 5.644l3.56 13.666c-8.407 2.708-17.42 6.608-26.724 8.412l-5.405-13.513c-8.71 1.8-17.416 3-26.427 3l-1.807 14.114c-8.406-.598-18.617 0-27.928-2.102v-14.11c-8.411-1.506-16.519-3.606-24.324-6.312l-6.91 12.322c-7.207-3.01-16.816-6.615-24.628-11.416l5.108-13.514c-6.31-3.307-12.015-7.509-17.42-11.72l13.515-17.118c22.226 17.722 50.153 28.228 80.787 28.228 16.221 0 32.132-2.697 46.555-8.7" fill="#ffcb00" fill-rule="evenodd"/><path d="M552.192 426.811 408.462 317.43l-1.31 1.866 143.36 109.573-8.509 10.647-139.753-89.64c-37.839-23.726-36.337-42.344-28.528-62.466l6.608-16.217c3.605 21.023 25.223 36.944 47.748 54.658l126.914 97.497zm36.084 32.6a2.23 2.23 0 0 1-2.23-2.238 2.23 2.23 0 0 1 2.23-2.232c1.237 0 2.24 1 2.24 2.232a2.238 2.238 0 0 1-2.24 2.239m-8.59-6.308a2.24 2.24 0 0 1-2.237-2.235 2.236 2.236 0 1 1 2.237 2.235m-8.79-7.006c-1.232 0-2.236-1-2.236-2.231a2.236 2.236 0 0 1 4.47 0c0 1.231-1 2.231-2.234 2.231m29.554 12.4-43.065-33.365-12.514 16.127 37.41 26.235c3.005 2.1 3.3 11.718 14.407 13.222 4.513.596 7.508-2.71 7.508-2.71 4.84-5.892 3.521-14.003-3.746-19.51" fill="#ffcb00" fill-rule="evenodd"/></svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
1
src/main/webapp/public/flags/svg/aq.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="900" height="600" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path fill="#009edb" d="M0 0h900v600H0Z"/><path d="M435.583 51.758c-.47-.08-.957.322-1.474 1.318-2.452 4.904-3.45 8.81-4.142 11.8-.655 2.901-5.053 2.911-6.892 3.524-1.839.613-2.169 6.417-3.983 4.062-5.75-7.433-9.504-7.74-14.408-7.126-2.913 1.456 4.522 5.287 2.453 9.807-14.711 0-17.163 4.904-19.615 19.615-4.597-4.444-8.888 6.283-22.067 9.807.23 3.142 1.532 11.265 0 14.713-.172.86 2.806 2.67 1.852 6.28-.95 3.61-8.054 4.652-9.236 9.034-1.184 4.382 3.018 3.291 2.153 6.47-.866 3.178-4.728 3.345-2.66 14.15-.46 1.991-4.37 5.747-4.37 5.747s-2.827 3.17 1.39 7.594c-6.943 5.393-6.483 17.347-6.292 21.829-7.048-1.84-12.26 2.45-12.26 2.45l2.45 9.81c-19.614 7.354-26.587 1.913-29.497 5.36-2.873 4.33-10.228 6.188-24.643 6.927-2.554.286-4.09 4.875-12.059 4.875-7.356-2.452-12.26-12.26-22.067-19.615l-22.067-7.357c-7.356-4.904-9.808-9.806-19.615-14.71l-17.162-7.358c-12.26-7.354-20.763-32.716-26.97-26.97 0 17.164 4.903 41.682 14.71 53.942 7.356 4.904 9.809 7.356 17.165 9.808 4.903 7.356 4.901 7.356 12.257 12.26-12.258 4.902-12.258 2.45-17.162 14.71 7.586 2.681 2.758 6.301 6.743 9.462 3.984 3.16 6.283 1.953 9.425 4.253 2.22-.767.994-3.908.994-3.908s2.836-5.133 4.905-2.45c4.215 10.265 9.808 7.355 9.808 7.355.613 2.452-1.151 8.043.267 8.966 4.405 2.834.344 9.653 1.11 10.573 4.598 1.84 5.134-7.586 6.552-7.204 1.417.386 1.878-.075 4.33-.075 0 9.806 0 9.806 4.903 19.614 0 0-5.515.076-7.393.766 2.95 7.74-12.298 15.86-12.068 19.078-.536 1.609 2.453 25.516 4.751 29.193 1.457 2.3-14.712 0-14.712 0 0 19.615 4.905 24.518 24.52 26.97 0 0-3.526-6.742-2.453-7.355 5.286-4.828 4.905 9.807 4.905 9.807 20.993 8.888-2.452 6.36 7.355 19.615l9.807-2.45c2.452 26.97 7.355 12.259 2.453 41.682h12.257v14.71c24.519-7.356 17.164 4.903 31.875 9.807l17.162 4.902 19.615 9.81v-4.905s30.19 1.762 33.178 2.758c6.59.307 2.835-7.277 12.643-7.277.65 0 11.186 7.106 14.05-2.184-.723 9.554 18.437 5.094 22.573 5.016 4.522 0 30.496 17.317 45.207 12.414 7.204-2.607 7.204-12.105 12.107-10.727 1.608 0 9.807 22.067 9.807 22.067 2.758 6.82 2.74 8.706-.562 16.435-1.846 5.353 4.205 8.039-6.325 15.161-8.08 4.823-4.008 6.722-5.999 11.721-2.604 3.465-10.656 3.441-9.41 8.555 1.531 4.903 17.24 2.836 19.843 14.33 3.18 1.648 2.876-3.87 8.71-4.035 2.915-.08 3.214 5.1 6.492 4.255 5.138-1.347 4.262-2.903 9.318-.22 3.754-14.251 7.587 11.032 31.723 2.526 4.693-.804 10.166 4.951 11.547 4.71 1.38-.24 5.181-9.312 7.13-9.582 1.95-.27 2.667 2.826 4.929 2.55 2.265-.278 8.911-9.135 11.234-9.4 2.324-.262 2.067 6.99 3.031 6.895a381.5 381.5 0 0 1 1.51-.151l12.26-2.453s-2.145 6.13-2.299 7.818c.671.247 5.67-5.556 9.382-7.891 3.715-2.331 6.753-8.398 8.865-2.389 4.77-6.308 7.738-5.559 14.027-7.634 5.73-9.67 11.707-8.905 14.16-9.519 4.902 0 6.666.153 9.807 2.453.995-2.528-4.905-4.905-4.905-4.905s5.056-14.098 16.55-16.319c.612-3.064-9.501-9.502-6.743-15.556 10.573-.307 24.136-8.044 24.52-9.807-.69-4.443-5.136-5.593-4.905-9.807 2.758.306 12.26 0 12.26 0-7.355-12.26-2.452-14.711 0-26.97l7.354 2.452c4.905-7.356 4.906-7.357 14.713-9.81 2.528-14.173-4.14-15.4-4.905-29.421 13.024 2.375 5.21-19.997 24.52-19.615-2.453-29.423 4.902-22.067 7.354-41.682-9.042 0-15.476-9.884-14.863-10.65 9.807-12.26-4.6-15.246 10.112-25.054-7.356-17.163-9.96-15.785-2.604-32.948-29.421 7.356-12.259-7.356-49.036-14.712 4.902-7.356 14.71-19.613 4.902-26.97 2.452-4.902 6.36-7.432 6.36-12.335 0-3.678-8.026-18.217-6.627-26.856-5.268-8.41-5.862-12.299-7.088-17.203-2.452-14.71 0-24.518 0-26.97-2.452-4.903-7.356-9.807-12.26-12.259-4.902-2.452-6.512.23-11.416 2.682-2.376-.23.56-3.77-3.464-6.472-4.869.822-7.197-1.43-9.599-5.826-5.164-2.327-11.936-3.351-25.23-7.894-4.946-.864-6.682-1.414-10.973-2.027-1.8-.114-3.66 4.732-5.68 6.618-2.022 1.887-4.205.813-4.205.813 0-6.36-8.966-16.166-7.892-24.671-4.023-1.264-2.72 1.877-7.326 2.653-2.834.251-7.233-9.854-10.833-9.854-2.145-.384-30.34 14.863-38.54-7.74-1.38-1.763-7.753 3.695-11.647-2.3-2.758-11.11-7.662-7.203-12.872-12.413-7.049.767-11.954 4.6-19.31 2.684-9.807-2.681-33.175-4.982-43.52-5.365-1.379-5.862-2.629-10.428-4.04-10.665zM164.095 164.099c-2.068.078-4.597-.305-3.754 2.99 1.227-2.53 3.678-2.836 3.754-2.99zm-1.417 7.644c-1.017.025-2.97.382-2.337 2.854 1.227-2.53 2.835-2.682 2.91-2.836 0 0-.234-.027-.573-.018zm15.546 36.262c.077.153 1.148.534 2.374 3.064.844-3.295-2.374-3.064-2.374-3.064zm560.834 144.504c-.716 1.611-.589 3.222.152 4.37 1.329-1.993.206-2.914-.152-4.37z" fill="#fff" stroke="#fff" stroke-width="2" stroke-linejoin="round"/></svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
1
src/main/webapp/public/flags/svg/ar.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg width="800" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.0" height="500"><path fill="#74acdf" d="M0 0h800v500H0z"/><path fill="#fff" d="M0 166.67h800v166.67H0z"/><g id="c"><path id="a" stroke-width="1.112" stroke="#85340a" fill="#f6b40e" d="m396.84 251.31 28.454 61.992s.49 1.185 1.28.859c.79-.327.299-1.512.299-1.512l-23.715-63.956m-.68 24.12c-.347 9.428 5.452 14.613 4.694 23.032-.757 8.42 3.867 13.18 4.94 16.454 1.073 3.274-1.16 5.232-.198 5.698.963.466 3.07-2.12 2.383-6.775-.687-4.655-4.22-6.037-3.39-16.32.83-10.283-4.206-12.678-2.98-22.058"/><use xlink:href="#a" transform="rotate(22.5 400 250)"/><use xlink:href="#a" transform="rotate(45 400 250)"/><use xlink:href="#a" transform="rotate(67.5 400 250)"/><path id="b" fill="#85340a" d="M404.31 274.41c.453 9.054 5.587 13.063 4.579 21.314 2.213-6.525-3.124-11.583-2.82-21.22m-7.649-23.757 19.487 42.577-16.329-43.887"/><use xlink:href="#b" transform="rotate(22.5 400 250)"/><use xlink:href="#b" transform="rotate(45 400 250)"/><use xlink:href="#b" transform="rotate(67.5 400 250)"/></g><use xlink:href="#c" transform="rotate(90 400 250)"/><use xlink:href="#c" transform="rotate(180 400 250)"/><use xlink:href="#c" transform="rotate(270 400 250)"/><circle r="27.778" stroke="#85340a" cy="250" cx="400" stroke-width="1.5" fill="#f6b40e"/><path id="h" fill="#843511" d="M409.47 244.06c-1.897 0-3.713.822-4.781 2.531 2.136 1.923 6.856 2.132 10.062-.219a7.333 7.333 0 0 0-5.281-2.312zm-.031.438c1.846-.034 3.571.814 3.812 1.656-2.136 2.35-5.55 2.146-7.687.437.935-1.495 2.439-2.067 3.875-2.094z"/><use xlink:href="#d" transform="matrix(-1 0 0 1 800.25 0)"/><use xlink:href="#e" transform="matrix(-1 0 0 1 800.25 0)"/><use xlink:href="#f" transform="translate(18.862)"/><use xlink:href="#g" transform="matrix(-1 0 0 1 800.25 0)"/><path d="M395.75 253.84c-.913.167-1.563.977-1.563 1.906 0 1.062.878 1.906 1.938 1.906a1.89 1.89 0 0 0 1.563-.812c.739.556 1.764.615 2.312.625.084.002.193 0 .25 0 .548-.01 1.573-.069 2.313-.625.36.516.935.812 1.562.812 1.06 0 1.938-.844 1.938-1.906 0-.929-.65-1.74-1.563-1.906.513.18.844.676.844 1.219a1.28 1.28 0 0 1-1.281 1.281c-.68 0-1.242-.54-1.282-1.219-.208.417-1.034 1.655-2.656 1.719-1.622-.064-2.447-1.302-2.656-1.719-.04.679-.6 1.219-1.281 1.219a1.28 1.28 0 0 1-1.281-1.281c0-.542.33-1.038.843-1.219zM397.84 259.53c-2.138 0-2.983 1.937-4.906 3.219 1.068-.427 1.91-1.27 3.406-2.125 1.496-.855 2.772.187 3.625.187h.031c.853 0 2.13-1.041 3.625-.187 1.497.856 2.369 1.698 3.438 2.125-1.924-1.282-2.8-3.219-4.938-3.219-.426 0-1.271.23-2.125.656h-.031c-.853-.426-1.698-.656-2.125-.656z" fill="#85340a"/><path d="M397.12 262.06c-.844.037-1.96.207-3.563.688 3.848-.855 4.697.437 6.407.437h.03c1.71 0 2.56-1.292 6.407-.438-4.274-1.282-5.124-.437-6.406-.437h-.031c-.802 0-1.437-.312-2.844-.25z" fill="#85340a"/><path d="M393.75 262.72c-.248.003-.519.005-.813.031 4.488.428 2.331 3 7.032 3h.03c4.702 0 2.575-2.572 7.063-3-4.7-.426-3.214 2.344-7.062 2.344h-.031c-3.608 0-2.496-2.421-6.22-2.375zM403.85 269.66a3.848 3.848 0 0 0-3.846-3.846 3.848 3.848 0 0 0-3.847 3.846 3.955 3.955 0 0 1 3.847-3.04 3.952 3.952 0 0 1 3.846 3.04z" fill="#85340a"/><path id="e" fill="#85340a" d="M382.73 244.02c4.915-4.273 11.11-4.915 14.53-1.709.837 1.121 1.373 2.32 1.593 3.57.43 2.433-.33 5.062-2.236 7.756.215-.001.643.212.856.427 1.697-3.244 2.297-6.577 1.74-9.746a13.815 13.815 0 0 0-.67-2.436c-4.7-3.845-11.11-4.272-15.81 2.138z"/><path id="d" fill="#85340a" d="M390.42 242.74c2.777 0 3.419.642 4.7 1.71 1.284 1.068 1.924.854 2.137 1.068.213.215 0 .854-.426.64s-1.284-.64-2.564-1.708c-1.283-1.07-2.563-1.069-3.846-1.069-3.846 0-5.983 3.205-6.41 2.991-.426-.214 2.137-3.632 6.41-3.632z"/><use xlink:href="#h" transform="translate(-19.181)"/><circle id="f" cy="246.15" cx="390.54" r="1.923" fill="#85340a"/><path id="g" fill="#85340a" d="M385.29 247.44c3.633 2.778 7.265 2.564 9.402 1.282 2.136-1.282 2.136-1.709 1.71-1.709-.427 0-.853.427-2.564 1.281-1.71.856-4.273.856-8.546-.854z"/></svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
1
src/main/webapp/public/flags/svg/as.svg
Normal file
|
After Width: | Height: | Size: 47 KiB |
1
src/main/webapp/public/flags/svg/at.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="600"><path fill="#c8102e" d="M0 0h900v600H0z"/><path fill="#fff" d="M0 200h900v200H0z"/></svg>
|
||||
|
After Width: | Height: | Size: 154 B |
1
src/main/webapp/public/flags/svg/au.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1280" height="640" viewBox="0 0 10080 5040"><defs><clipPath id="a"><path d="M0 0h6v3H0z"/></clipPath><clipPath id="b"><path d="M0 0v1.5h6V3zm6 0H3v3H0z"/></clipPath><path id="c" d="m0-360 69.421 215.845 212.038-80.301L155.99-35.603l194.985 115.71-225.881 19.651 31.105 224.59L0 160l-156.198 164.349 31.105-224.59-225.881-19.651 194.986-115.711-125.471-188.853 212.038 80.301z"/><path id="d" d="M0-210 54.86-75.508l144.862 10.614L88.765 28.842l34.67 141.052L0 93.334l-123.435 76.56 34.67-141.052-110.957-93.736L-54.86-75.508z"/></defs><path fill="#012169" d="M0 0h10080v5040H0z"/><path d="m0 0 6 3m0-3L0 3" stroke="#fff" stroke-width=".6" clip-path="url(#a)" transform="scale(840)"/><path d="m0 0 6 3m0-3L0 3" stroke="#e4002b" stroke-width=".4" clip-path="url(#b)" transform="scale(840)"/><path d="M2520 0v2520M0 1260h5040" stroke="#fff" stroke-width="840"/><path d="M2520 0v2520M0 1260h5040" stroke="#e4002b" stroke-width="504"/><g fill="#fff"><use xlink:href="#c" transform="matrix(2.1 0 0 2.1 2520 3780)"/><use xlink:href="#c" x="7560" y="4200"/><use xlink:href="#c" x="6300" y="2205"/><use xlink:href="#c" x="7560" y="840"/><use xlink:href="#c" x="8680" y="1869"/><use xlink:href="#d" x="8064" y="2730"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
src/main/webapp/public/flags/svg/aw.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="600" viewBox="0 0 27 18"><path fill="#418fde" d="M0 0h27v18H0V0z"/><path fill="#ffd100" d="M0 12h27v1H0v1h27v1H0v-3z"/><path fill="#EF3340" stroke="#FFF" stroke-width=".2" stroke-miterlimit="10" d="M4.625 3.375 4 1.35l-.625 2.025L1.35 4l2.025.625L4 6.65l.625-2.025L6.65 4z"/></svg>
|
||||
|
After Width: | Height: | Size: 341 B |
1
src/main/webapp/public/flags/svg/ax.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="520" height="340" viewBox="0 0 52 34"><path d="M0 0h52v34H0Z" fill="#0064AD"/><path d="M0 17h52M21 0v34" stroke-width="10" stroke="#FFD300"/><path d="M0 17h52M21 0v34" stroke-width="4" stroke="#DA0E15"/></svg>
|
||||
|
After Width: | Height: | Size: 256 B |
1
src/main/webapp/public/flags/svg/az.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="600"><path fill="#509e2f" d="M0 0h1200v600H0z"/><path fill="#ef3340" d="M0 0h1200v400H0z"/><path fill="#00b5e2" d="M0 0h1200v200H0z"/><circle cx="570" cy="300" r="90" fill="#fff"/><circle cx="590" cy="300" r="75" fill="#ef3340"/><path d="m670 250 9.567 26.903 25.788-12.258-12.258 25.788L720 300l-26.903 9.567 12.258 25.788-25.788-12.258L670 350l-9.567-26.903-25.788 12.258 12.258-25.788L620 300l26.903-9.567-12.258-25.788 25.788 12.258z" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 519 B |
1
src/main/webapp/public/flags/svg/ba.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="800" height="400" viewBox="0 0 16 8"><path fill="#002395" d="M0 0h16v8H0z"/><path d="M4.24 0h8v8z" fill="#fecb00"/><g id="b"><path d="M2.353.525 2.8-.85 3.247.525l-1.17-.85h1.446z" fill="#fff" id="a"/><use xlink:href="#a" x="1" y="1"/><use xlink:href="#a" x="2" y="2"/></g><use xlink:href="#b" x="3" y="3"/><use xlink:href="#b" x="6" y="6"/></svg>
|
||||
|
After Width: | Height: | Size: 437 B |
1
src/main/webapp/public/flags/svg/bb.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1500" height="1000" viewBox="0 0 24000 16000"><path fill="#00267f" d="M0 0h24000v16000H0z"/><path fill="#ffc726" d="M8000 0h8000v16000H8000z"/><path id="a" fill="#000" d="M12000 4124c-260 709-525 1447-1092 2012 176-58 484-110 682-105v2982l-842 125c-30-3-40-50-40-114-81-926-300-1704-552-2509-18-110-337-530-91-456 30 4 359 138 307 74-448-464-1103-798-1739-897-56-14-89 14-39 79 844 1299 1550 2832 1544 4651 328 0 1123-194 1452-194v2104h415l95-5876z"/><use xlink:href="#a" transform="matrix(-1 0 0 1 24000 0)"/></svg>
|
||||
|
After Width: | Height: | Size: 606 B |
1
src/main/webapp/public/flags/svg/bd.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 6"><path fill="#006a4e" d="M0 0h10v6H0z"/><circle cx="4.5" cy="3" r="2" fill="#f42a41"/></svg>
|
||||
|
After Width: | Height: | Size: 150 B |
1
src/main/webapp/public/flags/svg/be.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="780"><path fill="#ef3340" d="M0 0h900v780H0z"/><path fill="#fdda25" d="M0 0h600v780H0z"/><path d="M0 0h300v780H0z"/></svg>
|
||||
|
After Width: | Height: | Size: 182 B |
1
src/main/webapp/public/flags/svg/bf.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="900" height="600" version="1.0"><path fill="#009e49" d="M0 0h900v600H0z"/><path fill="#ef2b2d" d="M0 0h900v300H0z"/><g fill="#fcd116" transform="translate(450 300)"><g id="b"><path id="a" d="M0-100V0h50" transform="rotate(18 0 -100)"/><use xlink:href="#a" transform="scale(-1 1)"/></g><use xlink:href="#b" transform="rotate(72)"/><use xlink:href="#b" transform="rotate(144)"/><use xlink:href="#b" transform="rotate(216)"/><use xlink:href="#b" transform="rotate(288)"/></g></svg>
|
||||
|
After Width: | Height: | Size: 568 B |
1
src/main/webapp/public/flags/svg/bg.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="600" viewBox="0 0 5 3"><path fill="#fff" d="M0 0h5v3H0z"/><path fill="#00966E" d="M0 1h5v2H0z"/><path fill="#D62612" d="M0 2h5v1H0z"/></svg>
|
||||
|
After Width: | Height: | Size: 201 B |