Compare commits

..

No commits in common. "master" and "dev-comp" have entirely different histories.

193 changed files with 5312 additions and 16192 deletions

View File

@ -17,38 +17,17 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Cache Maven packages
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Cache node modules
id: cache-npm
uses: actions/cache@v4
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- name: Set up JDK 17 - name: Set up JDK 17
uses: actions/setup-java@v4 uses: actions/setup-java@v4
with: with:
java-version: '21' java-version: '17.0.12'
distribution: 'graalvm' distribution: 'graalvm'
cache: 'maven'
- name: Set up Node.js - name: Set up Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: '22' node-version: '18'
cache: 'npm' cache: 'npm'
cache-dependency-path: src/main/webapp/package-lock.json cache-dependency-path: src/main/webapp/package-lock.json

1
.gitignore vendored
View File

@ -50,4 +50,3 @@ nb-configuration.xml
/media/ /media/
/media-ext/ /media-ext/
/sign.jpg /sign.jpg
/.gitea/workflows/test.yml

View File

@ -1,22 +1,8 @@
# FFSAF - Intranet # ffsaf-site
## Introduction et context This project uses Quarkus, the Supersonic Subatomic Java Framework.
Lintranet de la Fédération française de Soft Armored Fighting a pour but centralise la prise de licences des adhérents If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ .
et laffiliation des clubs. Il permet aussi de recueillir les résultats des compétitions organisées par les clubs et,
plus récemment, den faciliter lorganisation grâce à un outil intégré.
Le système de prise de licence se divise en trois parties :
* Un formulaire public pour la première demande daffiliation ;
* Un espace club, accessible après validation, pour la saisie des informations relatives aux demandes de licence des
adhérents ;
* Un espace fédération pour accepter les demandes de licences et daffiliation.
Un espace membre permet enfin à chaque adhérent de télécharger son attestation de licence.
Pour les compétitions, le système permet la création de catégories, de poules et de matchs, avec génération automatique
des matchs au sein dune poule. Il supporte plusieurs lices, assure la synchronisation en temps réel des modifications
entre toutes les instances de lapplication web et publie automatiquement les résultats sur le site de lorganisateur.
## Running the application in dev mode ## Running the application in dev mode
@ -66,3 +52,34 @@ Or, if you don't have GraalVM installed, you can run the native executable build
You can then execute your native executable with: `./target/ffsaf-site-1.0-SNAPSHOT-runner` You can then execute your native executable with: `./target/ffsaf-site-1.0-SNAPSHOT-runner`
If you want to learn more about building native executables, please consult https://quarkus.io/guides/maven-tooling. If you want to learn more about building native executables, please consult https://quarkus.io/guides/maven-tooling.
## Related Guides
- Reactive MySQL client ([guide](https://quarkus.io/guides/reactive-sql-clients)): Connect to the MySQL database using the reactive pattern
- RESTEasy Reactive ([guide](https://quarkus.io/guides/resteasy-reactive)): A Jakarta REST implementation utilizing build time processing and Vert.x.
This extension is not compatible with the quarkus-resteasy extension, or any of the extensions that depend on it.
- Hibernate ORM with Panache ([guide](https://quarkus.io/guides/hibernate-orm-panache)): Simplify your persistence code for Hibernate ORM via the
active record or the repository pattern
- Reactive PostgreSQL client ([guide](https://quarkus.io/guides/reactive-sql-clients)): Connect to the PostgreSQL database using the reactive pattern
## Provided Code
### Hibernate ORM
Create your first JPA entity
[Related guide section...](https://quarkus.io/guides/hibernate-orm)
[Related Hibernate with Panache section...](https://quarkus.io/guides/hibernate-orm-panache)
### RESTEasy Reactive
Easily start your Reactive RESTful Web Services
[Related guide section...](https://quarkus.io/guides/getting-started-reactive#reactive-jax-rs-resources)
### RESTEasy Reactive Qute
Create your web page using Quarkus RESTEasy Reactive & Qute
[Related guide section...](https://quarkus.io/guides/qute#type-safe-templates)

View File

@ -20,11 +20,6 @@ services:
- default - default
- intra - intra
- nginx - nginx
healthcheck:
test: [ "CMD", "curl", "-f", "https://intra.ffsaf.fr/api" ]
interval: 30s
timeout: 5s
retries: 3
ffsaf-db: ffsaf-db:
image: public.ecr.aws/docker/library/postgres:17.2 image: public.ecr.aws/docker/library/postgres:17.2

18
pom.xml
View File

@ -11,7 +11,7 @@
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id> <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id> <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.30.5</quarkus.platform.version> <quarkus.platform.version>3.16.4</quarkus.platform.version>
<skipITs>true</skipITs> <skipITs>true</skipITs>
<surefire-plugin.version>3.2.3</surefire-plugin.version> <surefire-plugin.version>3.2.3</surefire-plugin.version>
</properties> </properties>
@ -56,15 +56,19 @@
<artifactId>quarkus-rest-client-jackson</artifactId> <artifactId>quarkus-rest-client-jackson</artifactId>
</dependency> </dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-mssql-client</artifactId>
<version>4.4.1</version>
</dependency>
<dependency> <dependency>
<groupId>io.quarkus</groupId> <groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId> <artifactId>quarkus-arc</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.quarkiverse.antivirus</groupId> <groupId>io.quarkiverse.tika</groupId>
<artifactId>quarkus-antivirus</artifactId> <artifactId>quarkus-tika</artifactId>
<version>1.3.0</version> <version>2.0.4</version>
</dependency> </dependency>
<dependency> <dependency>
@ -92,7 +96,7 @@
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<version>1.18.42</version> <version>1.18.22</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@ -123,7 +127,7 @@
<dependency> <dependency>
<groupId>org.apache.xmlgraphics</groupId> <groupId>org.apache.xmlgraphics</groupId>
<artifactId>fop</artifactId> <artifactId>fop</artifactId>
<version>2.11</version> <version>2.6</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.quarkus</groupId> <groupId>io.quarkus</groupId>

View File

@ -1,48 +0,0 @@
package fr.titionfire.ffsaf;
import fr.titionfire.ffsaf.domain.service.TradService;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.container.PreMatching;
import jakarta.ws.rs.ext.Provider;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
@Provider
@PreMatching
public class UserInfoProvider implements ContainerRequestFilter {
private static final List<Locale> SUPPORTED_LANGUAGES = Arrays.asList(
Locale.FRENCH,
Locale.ENGLISH
);
@Override
public void filter(ContainerRequestContext requestContext) {
List<Locale> acceptableLanguages = requestContext.getAcceptableLanguages();
Locale selectedLocale = findFirstSupportedLanguage(acceptableLanguages);
if (selectedLocale == null)
selectedLocale = TradService.fallbackLocale;
requestContext.setProperty("userLocale", selectedLocale);
}
private Locale findFirstSupportedLanguage(List<Locale> acceptableLanguages) {
for (Locale acceptableLanguage : acceptableLanguages) {
// Vérifie si la langue est dans la liste des langues supportées
if (SUPPORTED_LANGUAGES.contains(acceptableLanguage)) {
return acceptableLanguage;
}
// Vérifie aussi par tag de langue (ex: "fr-FR" -> "fr")
String languageTag = acceptableLanguage.getLanguage();
for (Locale supportedLanguage : SUPPORTED_LANGUAGES) {
if (supportedLanguage.getLanguage().equals(languageTag)) {
return supportedLanguage;
}
}
}
return null;
}
}

View File

@ -1,64 +0,0 @@
package fr.titionfire.ffsaf.data.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.quarkus.runtime.annotations.RegisterForReflection;
import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.CreationTimestamp;
import java.util.Date;
import java.util.Objects;
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@RegisterForReflection
@Entity
@Table(name = "card")
public class CardModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
Long comb;
Long match;
Long category;
@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "competition", referencedColumnName = "id")
CompetitionModel competition;
@JsonProperty("competition")
Long competitionId;
CardType type;
String reason;
@CreationTimestamp
Date date;
@Column(nullable = false, columnDefinition = "boolean default false")
boolean teamCard = false;
public boolean hasEffect(MatchModel match) {
return switch (this.type) {
case BLUE -> false;
case YELLOW -> Objects.equals(this.match, match.getId());
case RED -> Objects.equals(this.category, match.getCategory().getId())
|| Objects.equals(this.match, match.getId());
case BLACK -> true;
};
}
public enum CardType {
BLUE,
YELLOW,
RED,
BLACK
}
}

View File

@ -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;
}

View File

@ -1,89 +0,0 @@
package fr.titionfire.ffsaf.data.model;
import fr.titionfire.ffsaf.utils.Categorie;
import io.quarkus.runtime.annotations.RegisterForReflection;
import jakarta.persistence.*;
import lombok.*;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@RegisterForReflection
@Entity
@Table(name = "category_preset")
public class CatPresetModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "competition", referencedColumnName = "id")
CompetitionModel competition;
String name = "";
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "category_preset_catconfig", joinColumns = @JoinColumn(name = "id_preset"))
List<CategorieEmbeddable> categories;
SwordType swordType = SwordType.NONE;
ShieldType shieldType = ShieldType.NONE;
/*
* 1 - 1 - Casque
* 2 - 2 - Gorgerin
* 3 - 4 - Coquille et Protection pelvienne
* 4 - 8 - Gant main(s) armée(s)
* 5 - 16 - Gant main bouclier
* 6 - 32 - Plastron
* 7 - 64 - Protection de bras armé(s)
* 8 - 128 - Protection de bras de bouclier
* 9 - 256 - Protection de jambes
* 10 - 512 - Protection de genoux
* 11 - 1024 - Protection de coudes
* 12 - 2048 - Protection dorsale
* 13 - 4096 - Protection de pieds
*/
int mandatoryProtection1 = 0;
int mandatoryProtection2 = 0;
@ManyToMany(mappedBy = "categoriesInscrites", fetch = FetchType.LAZY)
private List<RegisterModel> registers = new ArrayList<>();
@ManyToMany(mappedBy = "categoriesInscrites", fetch = FetchType.LAZY)
private List<CompetitionGuestModel> guest = new ArrayList<>();
public enum SwordType {
NONE,
ONE_HAND,
TWO_HAND,
SABER
}
public enum ShieldType {
NONE,
STANDARD,
ROUND,
TEARDROP,
BUCKLER
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@RegisterForReflection
@Embeddable
public static class CategorieEmbeddable {
Categorie categorie;
long roundDuration;
long pauseDuration;
}
}

View File

@ -44,8 +44,4 @@ public class CategoryModel {
Integer type; Integer type;
String liceName = "1"; String liceName = "1";
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "id_preset", referencedColumnName = "id")
CatPresetModel preset;
} }

View File

@ -1,38 +0,0 @@
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;
import org.hibernate.annotations.CreationTimestamp;
import java.util.Date;
import java.util.List;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@RegisterForReflection
@Entity
@Table(name = "card_team")
public class ClubCardModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
Long competition;
String teamUuid;
String teamName;
CardModel.CardType type;
String reason;
@CreationTimestamp
Date date;
List<Long> cardIds;
}

View File

@ -1,9 +0,0 @@
package fr.titionfire.ffsaf.data.model;
import fr.titionfire.ffsaf.utils.ResultPrivacy;
public interface CombModel {
Long getCombId();
String getName();
String getName(MembreModel model, ResultPrivacy privacy);
}

View File

@ -2,7 +2,6 @@ package fr.titionfire.ffsaf.data.model;
import fr.titionfire.ffsaf.utils.Categorie; import fr.titionfire.ffsaf.utils.Categorie;
import fr.titionfire.ffsaf.utils.Genre; import fr.titionfire.ffsaf.utils.Genre;
import fr.titionfire.ffsaf.utils.ResultPrivacy;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
import jakarta.persistence.*; import jakarta.persistence.*;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@ -10,11 +9,6 @@ import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
@Getter @Getter
@Setter @Setter
@AllArgsConstructor @AllArgsConstructor
@ -23,7 +17,7 @@ import java.util.stream.Stream;
@Entity @Entity
@Table(name = "competition_guest") @Table(name = "competition_guest")
public class CompetitionGuestModel implements CombModel { public class CompetitionGuestModel {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
Long id; Long id;
@ -44,72 +38,13 @@ public class CompetitionGuestModel implements CombModel {
String country = "fr"; String country = "fr";
Integer weight = null; Integer weight = null;
Integer weightReal = null;
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
@JoinTable(
name = "groupe_membre",
joinColumns = @JoinColumn(name = "groupe_id"),
inverseJoinColumns = @JoinColumn(name = "membre_id")
)
List<MembreModel> comb = new ArrayList<>();
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
@JoinTable(
name = "groupe_guest",
joinColumns = @JoinColumn(name = "groupe_id"),
inverseJoinColumns = @JoinColumn(name = "guest_id")
)
List<CompetitionGuestModel> guest = new ArrayList<>();
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@JoinTable(
name = "categories_insc_guest",
joinColumns = @JoinColumn(name = "guest_id"),
inverseJoinColumns = @JoinColumn(name = "category_id")
)
List<CatPresetModel> categoriesInscrites = new ArrayList<>();
public CompetitionGuestModel(String s) { public CompetitionGuestModel(String s) {
this.fname = s.substring(0, s.indexOf(" ")); this.fname = s.substring(0, s.indexOf(" "));
this.lname = s.substring(s.indexOf(" ") + 1); this.lname = s.substring(s.indexOf(" ") + 1);
} }
@Override
public Long getCombId() {
return this.id * -1;
}
@Override
public String getName() { public String getName() {
if (this.isTeam()) return fname + " " + lname;
return this.fname;
return this.fname + " " + this.lname;
}
@Override
public String getName(MembreModel model, ResultPrivacy privacy) {
return getName();
}
public boolean isTeam() {
return "__team".equals(this.lname);
}
public boolean isInTeam(Object comb_) {
if (!this.isTeam())
return false;
if (comb_ instanceof Long id_) {
if (id_ >= 0)
return comb.stream().anyMatch(membre -> Objects.equals(membre.getId(), id_));
else
return guest.stream().anyMatch(guestModel -> Objects.equals(guestModel.getId(), -id_));
}
return Stream.concat(comb.stream(), guest.stream()).anyMatch(c -> Objects.equals(c, comb_));
}
public Integer getWeight2() {
return (this.weightReal != null) ? this.weightReal : this.weight;
} }
} }

View File

@ -1,6 +1,5 @@
package fr.titionfire.ffsaf.data.model; package fr.titionfire.ffsaf.data.model;
import fr.titionfire.ffsaf.utils.Categorie;
import fr.titionfire.ffsaf.utils.CompetitionSystem; import fr.titionfire.ffsaf.utils.CompetitionSystem;
import fr.titionfire.ffsaf.utils.RegisterMode; import fr.titionfire.ffsaf.utils.RegisterMode;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
@ -59,10 +58,6 @@ public class CompetitionModel {
@OneToMany(mappedBy = "competition", fetch = FetchType.LAZY, cascade = CascadeType.ALL) @OneToMany(mappedBy = "competition", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
List<CompetitionGuestModel> guests = new ArrayList<>(); List<CompetitionGuestModel> guests = new ArrayList<>();
@OneToMany(mappedBy = "competition", fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
List<CatPresetModel> catPreset = new ArrayList<>();
List<Categorie> requiredWeight = new ArrayList<>();
List<Long> banMembre = new ArrayList<>(); List<Long> banMembre = new ArrayList<>();
@ -72,15 +67,8 @@ public class CompetitionModel {
@Column(name = "table_") @Column(name = "table_")
List<String> table = new ArrayList<>(); List<String> table = new ArrayList<>();
@Column(columnDefinition = "TEXT")
String data1; String data1;
@Column(columnDefinition = "TEXT")
String data2; String data2;
@Column(columnDefinition = "TEXT")
String data3; String data3;
@Column(columnDefinition = "TEXT")
String data4; String data4;
@Column(columnDefinition = "TEXT")
String config;
} }

View File

@ -41,7 +41,7 @@ public class LogModel {
} }
public enum ObjectType { public enum ObjectType {
Membre, Affiliation, Licence, Club, Competition, Register, Selection Membre, Affiliation, Licence, Club, Competition, Register
} }
} }

View File

@ -1,7 +1,6 @@
package fr.titionfire.ffsaf.data.model; package fr.titionfire.ffsaf.data.model;
import fr.titionfire.ffsaf.utils.CompetitionSystem; import fr.titionfire.ffsaf.utils.CompetitionSystem;
import fr.titionfire.ffsaf.utils.ResultPrivacy;
import fr.titionfire.ffsaf.utils.ScoreEmbeddable; import fr.titionfire.ffsaf.utils.ScoreEmbeddable;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
import jakarta.persistence.*; import jakarta.persistence.*;
@ -10,7 +9,6 @@ import lombok.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Objects;
@Getter @Getter
@Setter @Setter
@ -63,35 +61,23 @@ public class MatchModel {
char poule = 'A'; char poule = 'A';
public String getC1Name(MembreModel model, ResultPrivacy privacy) { @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
if (c1_id != null) @JoinColumn(name = "match", referencedColumnName = "id")
return c1_id.getName(model, privacy); List<CardboardModel> cardboard = new ArrayList<>();
if (c1_guest != null)
return c1_guest.getName(model, privacy);
return "";
}
public String getC2Name(MembreModel model, ResultPrivacy privacy) {
if (c2_id != null)
return c2_id.getName(model, privacy);
if (c2_guest != null)
return c2_guest.getName(model, privacy);
return "";
}
public String getC1Name() { public String getC1Name() {
if (c1_id != null) if (c1_id != null)
return c1_id.getName(); return c1_id.fname + " " + c1_id.lname;
if (c1_guest != null) if (c1_guest != null)
return c1_guest.getName(); return c1_guest.fname + " " + c1_guest.lname;
return ""; return "";
} }
public String getC2Name() { public String getC2Name() {
if (c2_id != null) if (c2_id != null)
return c2_id.getName(); return c2_id.fname + " " + c2_id.lname;
if (c2_guest != null) if (c2_guest != null)
return c2_guest.getName(); return c2_guest.fname + " " + c2_guest.lname;
return ""; return "";
} }
@ -108,30 +94,4 @@ public class MatchModel {
} }
return sum; return sum;
} }
public boolean isC1(Object comb) {
if (this.c1_guest != null && this.c1_guest.isInTeam(comb))
return true;
if (comb instanceof Long id_) {
if (id_ >= 0)
return Objects.equals(this.c1_id != null ? this.c1_id.getId() : null, id_);
else
return Objects.equals(this.c1_guest != null ? this.c1_guest.getId() : null, -id_);
}
return Objects.equals(this.c1_id, comb) || Objects.equals(this.c1_guest, comb);
}
public boolean isC2(Object comb) {
if (this.c2_guest != null && this.c2_guest.isInTeam(comb))
return true;
if (comb instanceof Long id_) {
if (id_ >= 0)
return Objects.equals(this.c2_id != null ? this.c2_id.getId() : null, id_);
else
return Objects.equals(this.c2_guest != null ? this.c2_guest.getId() : null, -id_);
}
return Objects.equals(this.c2_id, comb) || Objects.equals(this.c2_guest, comb);
}
} }

View File

@ -1,6 +1,9 @@
package fr.titionfire.ffsaf.data.model; package fr.titionfire.ffsaf.data.model;
import fr.titionfire.ffsaf.utils.*; import fr.titionfire.ffsaf.utils.Categorie;
import fr.titionfire.ffsaf.utils.Genre;
import fr.titionfire.ffsaf.utils.GradeArbitrage;
import fr.titionfire.ffsaf.utils.RoleAsso;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
import jakarta.persistence.*; import jakarta.persistence.*;
import lombok.*; import lombok.*;
@ -8,7 +11,6 @@ import org.eclipse.microprofile.openapi.annotations.media.Schema;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Objects;
@Getter @Getter
@Setter @Setter
@ -19,23 +21,23 @@ import java.util.Objects;
@Entity @Entity
@Table(name = "membre") @Table(name = "membre")
public class MembreModel implements LoggableModel, CombModel { public class MembreModel implements LoggableModel {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
@Access(AccessType.PROPERTY) @Access(AccessType.PROPERTY)
@Schema(description = "L'identifiant du membre.", examples = "1") @Schema(description = "L'identifiant du membre.", example = "1")
Long id; Long id;
@Schema(description = "L'identifiant long du membre (userID).", examples = "e81d1d35-d897-421e-8086-6c5e74d13c6e") @Schema(description = "L'identifiant long du membre (userID).", example = "e81d1d35-d897-421e-8086-6c5e74d13c6e")
String userId; String userId;
@Schema(description = "Le nom du membre.", examples = "Dupont") @Schema(description = "Le nom du membre.", example = "Dupont")
String lname; String lname;
@Schema(description = "Le prénom du membre.", examples = "Jean") @Schema(description = "Le prénom du membre.", example = "Jean")
String fname; String fname;
@Schema(description = "La catégorie du membre.", examples = "SENIOR") @Schema(description = "La catégorie du membre.", example = "SENIOR")
Categorie categorie; Categorie categorie;
@ManyToOne(fetch = FetchType.EAGER) @ManyToOne(fetch = FetchType.EAGER)
@ -43,39 +45,34 @@ public class MembreModel implements LoggableModel, CombModel {
@Schema(description = "Le club du membre.") @Schema(description = "Le club du membre.")
ClubModel club; ClubModel club;
@Schema(description = "Le genre du membre.", examples = "H") @Schema(description = "Le genre du membre.", example = "H")
Genre genre; Genre genre;
@Schema(description = "Le numéro de licence du membre.", examples = "12345") @Schema(description = "Le numéro de licence du membre.", example = "12345")
Integer licence; Integer licence;
@Schema(description = "Le pays du membre.", examples = "FR") @Schema(description = "Le pays du membre.", example = "FR")
String country; String country;
@Schema(description = "La date de naissance du membre.") @Schema(description = "La date de naissance du membre.")
Date birth_date; Date birth_date;
@Schema(description = "L'adresse e-mail du membre.", examples = "jean.dupont@examples.com") @Schema(description = "L'adresse e-mail du membre.", example = "jean.dupont@example.com")
String email; String email;
@Schema(description = "Le rôle du membre dans l'association.", examples = "MEMBRE") @Schema(description = "Le rôle du membre dans l'association.", example = "MEMBRE")
RoleAsso role; RoleAsso role;
@Schema(description = "Le grade d'arbitrage du membre.", examples = "NA") @Schema(description = "Le grade d'arbitrage du membre.", example = "NA")
GradeArbitrage grade_arbitrage; GradeArbitrage grade_arbitrage;
@Schema(description = "La confidentialité de ces résultats", examples = "PUBLIC") @Schema(hidden = true)
@Column(nullable = false, columnDefinition = "smallint default 0") String url_photo;
ResultPrivacy resultPrivacy = ResultPrivacy.PUBLIC;
@OneToMany(mappedBy = "membre", fetch = FetchType.LAZY, cascade = CascadeType.ALL) @OneToMany(mappedBy = "membre", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@Schema(description = "Les licences du membre. (optionnel)") @Schema(description = "Les licences du membre. (optionnel)")
List<LicenceModel> licences; List<LicenceModel> licences;
@OneToMany(mappedBy = "membre", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@Schema(description = "Les séléctions du membre. (optionnel)")
List<SelectionModel> selections;
@Override @Override
public String getObjectName() { public String getObjectName() {
return fname + " " + lname; return fname + " " + lname;
@ -103,25 +100,4 @@ public class MembreModel implements LoggableModel, CombModel {
", grade_arbitrage=" + grade_arbitrage + ", grade_arbitrage=" + grade_arbitrage +
'}'; '}';
} }
@Override
public Long getCombId() {
return this.id;
}
@Override
public String getName() {
return this.fname + " " + this.lname;
}
@Override
public String getName(MembreModel model, ResultPrivacy privacy) {
if (model == null || !Objects.equals(this.getId(), model.getId())) {
if (model == null && this.getResultPrivacy() != ResultPrivacy.PUBLIC)
return "Anonyme";
if (this.getResultPrivacy().ordinal() > privacy.ordinal())
return "Anonyme";
}
return getName();
}
} }

View File

@ -11,9 +11,6 @@ import lombok.Setter;
import org.hibernate.annotations.OnDelete; import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction; import org.hibernate.annotations.OnDeleteAction;
import java.util.ArrayList;
import java.util.List;
@Getter @Getter
@Setter @Setter
@AllArgsConstructor @AllArgsConstructor
@ -38,7 +35,6 @@ public class RegisterModel {
MembreModel membre; MembreModel membre;
Integer weight; Integer weight;
Integer weightReal;
int overCategory = 0; int overCategory = 0;
Categorie categorie; Categorie categorie;
@ -50,17 +46,6 @@ public class RegisterModel {
@Column(nullable = false, columnDefinition = "boolean default false") @Column(nullable = false, columnDefinition = "boolean default false")
boolean lockEdit = false; boolean lockEdit = false;
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@JoinTable(
name = "categories_insc_comb",
joinColumns = {
@JoinColumn(name = "id_competition", referencedColumnName = "id_competition"),
@JoinColumn(name = "id_membre", referencedColumnName = "id_membre")
},
inverseJoinColumns = @JoinColumn(name = "category_id")
)
List<CatPresetModel> categoriesInscrites = new ArrayList<>();
public RegisterModel(CompetitionModel competition, MembreModel membre, Integer weight, int overCategory, public RegisterModel(CompetitionModel competition, MembreModel membre, Integer weight, int overCategory,
Categorie categorie, ClubModel club) { Categorie categorie, ClubModel club) {
this.id = new RegisterId(competition.getId(), membre.getId()); this.id = new RegisterId(competition.getId(), membre.getId());
@ -81,19 +66,4 @@ public class RegisterModel {
return membre.club; return membre.club;
return club; return club;
} }
public Categorie getCategorie2() {
Categorie tmp = this.categorie;
if (tmp == null)
tmp = membre.getCategorie();
if (tmp == null)
return null;
return Categorie.values()[Math.min(tmp.ordinal() + this.overCategory, Categorie.values().length - 1)];
}
public Integer getWeight2() {
if (weightReal != null)
return weightReal;
return weight;
}
} }

View File

@ -1,44 +0,0 @@
package fr.titionfire.ffsaf.data.model;
import fr.titionfire.ffsaf.utils.Categorie;
import io.quarkus.runtime.annotations.RegisterForReflection;
import jakarta.persistence.*;
import lombok.*;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@RegisterForReflection
@Entity
@Table(name = "selection")
public class SelectionModel implements LoggableModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Schema(description = "L'identifiant de la séléction.")
Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "membre", referencedColumnName = "id")
@Schema(description = "Le membre de la séléction. (optionnel)")
MembreModel membre;
@Schema(description = "La saison de la séléction.", examples = "2025")
int saison;
@Schema(description = "Catégorie de la séléction.")
Categorie categorie;
@Override
public String getObjectName() {
return "selection " + id.toString();
}
@Override
public LogModel.ObjectType getObjectType() {
return LogModel.ObjectType.Selection;
}
}

View File

@ -1,10 +0,0 @@
package fr.titionfire.ffsaf.data.repository;
import fr.titionfire.ffsaf.data.model.CardModel;
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class CardRepository implements PanacheRepositoryBase<CardModel, Long> {
}

View File

@ -1,9 +1,9 @@
package fr.titionfire.ffsaf.data.repository; package fr.titionfire.ffsaf.data.repository;
import fr.titionfire.ffsaf.data.model.SelectionModel; import fr.titionfire.ffsaf.data.model.CardboardModel;
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase; import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped @ApplicationScoped
public class SelectionRepository implements PanacheRepositoryBase<SelectionModel, Long> { public class CardboardRepository implements PanacheRepositoryBase<CardboardModel, Long> {
} }

View File

@ -1,9 +0,0 @@
package fr.titionfire.ffsaf.data.repository;
import fr.titionfire.ffsaf.data.model.CatPresetModel;
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class CatPresetRepository implements PanacheRepositoryBase<CatPresetModel, Long> {
}

View File

@ -2,17 +2,8 @@ package fr.titionfire.ffsaf.data.repository;
import fr.titionfire.ffsaf.data.model.CheckoutModel; import fr.titionfire.ffsaf.data.model.CheckoutModel;
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase; import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped @ApplicationScoped
public class CheckoutRepository implements PanacheRepositoryBase<CheckoutModel, Long> { public class CheckoutRepository implements PanacheRepositoryBase<CheckoutModel, Long> {
public Uni<Long> countByLicenseId(long id) {
return getSession()
.chain(s -> s
.createNativeQuery("SELECT COUNT(*) FROM ffsaf__checkout WHERE ?1 = ANY(license_ids)", Long.class)
.setParameter(1, id)
.getSingleResult());
}
} }

View File

@ -1,10 +0,0 @@
package fr.titionfire.ffsaf.data.repository;
import fr.titionfire.ffsaf.data.model.ClubCardModel;
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class ClubCardRepository implements PanacheRepositoryBase<ClubCardModel, Long> {
}

View File

@ -0,0 +1,26 @@
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() != null ? model.getComb().getId() : model.getGuestComb().getId() * -1,
model.getMatch().getId(),
model.getCompet().getId(),
model.getRed(), model.getYellow());
}
}

View File

@ -9,10 +9,6 @@ import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@RegisterForReflection @RegisterForReflection
@ -27,7 +23,6 @@ public class CombEntity {
String country; String country;
int overCategory; int overCategory;
Integer weight; Integer weight;
List<CombEntity> teamMembers;
public static CombEntity fromModel(MembreModel model) { public static CombEntity fromModel(MembreModel model) {
if (model == null) if (model == null)
@ -36,7 +31,7 @@ public class CombEntity {
return new CombEntity(model.getId(), model.getLname(), model.getFname(), model.getCategorie(), return new CombEntity(model.getId(), model.getLname(), model.getFname(), model.getCategorie(),
model.getClub() == null ? null : model.getClub().getClubId(), model.getClub() == null ? null : model.getClub().getClubId(),
model.getClub() == null ? "Sans club" : model.getClub().getName(), model.getGenre(), model.getCountry(), model.getClub() == null ? "Sans club" : model.getClub().getName(), model.getGenre(), model.getCountry(),
0, null, new ArrayList<>()); 0, null);
} }
@ -45,9 +40,7 @@ public class CombEntity {
return null; return null;
return new CombEntity(model.getId() * -1, model.getLname(), model.getFname(), model.getCategorie(), null, return new CombEntity(model.getId() * -1, model.getLname(), model.getFname(), model.getCategorie(), null,
model.getClub(), model.getGenre(), model.getCountry(), 0, model.getWeight(), model.getClub(), model.getGenre(), model.getCountry(), 0, model.getWeight());
Stream.concat(model.getComb().stream().map(CombEntity::fromModel),
model.getGuest().stream().map(CombEntity::fromModel)).toList());
} }
public static CombEntity fromModel(RegisterModel registerModel) { public static CombEntity fromModel(RegisterModel registerModel) {
@ -58,6 +51,6 @@ public class CombEntity {
return new CombEntity(model.getId(), model.getLname(), model.getFname(), registerModel.getCategorie(), return new CombEntity(model.getId(), model.getLname(), model.getFname(), registerModel.getCategorie(),
registerModel.getClub2() == null ? null : registerModel.getClub2().getClubId(), registerModel.getClub2() == null ? null : registerModel.getClub2().getClubId(),
registerModel.getClub2() == null ? "Sans club" : registerModel.getClub2().getName(), model.getGenre(), registerModel.getClub2() == null ? "Sans club" : registerModel.getClub2().getName(), model.getGenre(),
model.getCountry(), registerModel.getOverCategory(), registerModel.getWeight(), new ArrayList<>()); model.getCountry(), registerModel.getOverCategory(), registerModel.getWeight());
} }
} }

View File

@ -6,6 +6,7 @@ import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -22,6 +23,7 @@ public class MatchEntity {
private Date date; private Date date;
private List<ScoreEmbeddable> scores; private List<ScoreEmbeddable> scores;
private char poule; private char poule;
private List<CardboardEntity> cardboard;
public static MatchEntity fromModel(MatchModel model) { public static MatchEntity fromModel(MatchModel model) {
if (model == null) if (model == null)
@ -33,6 +35,22 @@ public class MatchEntity {
model.getC2_id()), model.getC2_id()),
model.getCategory_ord(), model.isEnd(), model.getCategory().getId(), model.getDate(), model.getCategory_ord(), model.isEnd(), model.getCategory().getId(), model.getDate(),
model.getScores(), model.getScores(),
model.getPoule()); 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;
} }
} }

View File

@ -1,176 +0,0 @@
package fr.titionfire.ffsaf.domain.entity;
import fr.titionfire.ffsaf.data.model.*;
import fr.titionfire.ffsaf.utils.ResultPrivacy;
import fr.titionfire.ffsaf.utils.ScoreEmbeddable;
import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.Getter;
import java.util.*;
@RegisterForReflection
public class MatchModelExtend {
final MatchModel match;
@Getter
boolean isEnd = false;
@Getter
List<ScoreEmbeddable> scoresToPrint = new ArrayList<>();
@Getter
List<ScoreEmbeddable> scoresToCompute = new ArrayList<>();
@Getter
int win = 0;
public MatchModelExtend(MatchModel match, List<CardModel> cards) {
this.match = match;
List<Long> combIds = extractCombIds(match);
List<CardModel> cards2 = cards.stream().filter(c -> combIds.contains(c.getComb()) && c.hasEffect(match))
.sorted(Comparator.comparing(CardModel::getType).reversed()).toList();
for (ScoreEmbeddable score : match.getScores()) {
if (score.getS1() == -1000 || score.getS2() == -1000)
continue;
this.scoresToCompute.add(virtualScore(score, cards2, false));
}
calc_win_end(cards2);
for (ScoreEmbeddable score : match.getScores()) {
if (score.getS1() == -1000 || score.getS2() == -1000)
continue;
this.scoresToPrint.add(virtualScore(score, cards2, true));
}
if (this.isEnd && this.scoresToPrint.isEmpty()) {
this.scoresToPrint.add(virtualScore(new ScoreEmbeddable(0, 0, 0), cards2, true));
}
}
private ScoreEmbeddable virtualScore(ScoreEmbeddable score, List<CardModel> cards2, boolean toPrint) {
if (cards2.size() > 1) {
if (!Objects.equals(cards2.get(0).getComb(), cards2.get(1).getComb()))
return new ScoreEmbeddable(score.getN_round(), toPrint ? -997 : 0, toPrint ? -997 : 0);
}
if (!cards2.isEmpty()) {
if (isC1(cards2.get(0).getComb()))
return new ScoreEmbeddable(score.getN_round(), toPrint ? -997 : 0, 10);
else
return new ScoreEmbeddable(score.getN_round(), 10, toPrint ? -997 : 0);
}
if (score.getS1() < -900 && score.getS2() < -900)
return new ScoreEmbeddable(score.getN_round(), toPrint ? score.getS1() : 0, toPrint ? score.getS2() : 0);
else if (score.getS1() < -900)
return new ScoreEmbeddable(score.getN_round(), toPrint ? score.getS1() : 0, 10);
else if (score.getS2() < -900)
return new ScoreEmbeddable(score.getN_round(), 10, toPrint ? score.getS2() : 0);
return new ScoreEmbeddable(score.getN_round(), score.getS1(), score.getS2());
}
private void calc_win_end(List<CardModel> cards2) {
if (cards2.size() > 1) {
if (!Objects.equals(cards2.get(0).getComb(), cards2.get(1).getComb())) {
this.win = 0;
this.isEnd = true;
return;
}
}
if (!cards2.isEmpty()) {
if (match.isC1(cards2.get(0).getComb())) {
this.win = -1;
} else if (match.isC2(cards2.get(0).getComb())) {
this.win = 1;
}
this.isEnd = true;
return;
}
for (ScoreEmbeddable score : this.scoresToCompute) {
if (score.getS1() > score.getS2())
win++;
else if (score.getS1() < score.getS2())
win--;
}
this.isEnd = match.isEnd();
}
private List<Long> extractCombIds(MatchModel match) {
List<Long> ids = new ArrayList<>();
if (match.getC1_id() != null)
ids.add(match.getC1_id().getId());
if (match.getC2_id() != null)
ids.add(match.getC2_id().getId());
if (match.getC1_guest() != null)
ids.add(match.getC1_guest().getId() * -1);
if (match.getC2_guest() != null)
ids.add(match.getC2_guest().getId() * -1);
return ids;
}
//--------------- Delegation methods to MatchModel ---------------
public Long getId() {
return match.getId();
}
public MembreModel getC1_id() {
return match.getC1_id();
}
public CompetitionGuestModel getC1_guest() {
return match.getC1_guest();
}
public MembreModel getC2_id() {
return match.getC2_id();
}
public CompetitionGuestModel getC2_guest() {
return match.getC2_guest();
}
public CategoryModel getCategory() {
return match.getCategory();
}
public long getCategory_ord() {
return match.getCategory_ord();
}
public Date getDate() {
return match.getDate();
}
public char getPoule() {
return match.getPoule();
}
public String getC1Name(MembreModel model, ResultPrivacy privacy) {
return match.getC1Name(model, privacy);
}
public String getC2Name(MembreModel model, ResultPrivacy privacy) {
return match.getC2Name(model, privacy);
}
public String getC2Name() {
return match.getC2Name();
}
public String getC1Name() {
return match.getC1Name();
}
public boolean isC1(Object comb) {
return match.isC1(comb);
}
public boolean isC2(Object comb) {
return match.isC2(comb);
}
}

View File

@ -0,0 +1,64 @@
package fr.titionfire.ffsaf.domain.entity;
import fr.titionfire.ffsaf.data.model.MembreModel;
import fr.titionfire.ffsaf.utils.Categorie;
import fr.titionfire.ffsaf.utils.Genre;
import fr.titionfire.ffsaf.utils.GradeArbitrage;
import fr.titionfire.ffsaf.utils.RoleAsso;
import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import java.util.Date;
@Data
@Builder
@AllArgsConstructor
@RegisterForReflection
public class MembreEntity {
private long id;
private String lname = "";
private String fname = "";
private Categorie categorie;
private ClubEntity club;
private Genre genre;
private Integer licence;
private String country;
private Date birth_date;
private String email;
private RoleAsso role;
private GradeArbitrage grade_arbitrage;
private String url_photo;
public static MembreEntity fromModel(MembreModel model) {
if (model == null)
return null;
return new MembreEntityBuilder()
.id(model.getId())
.lname(model.getLname())
.fname(model.getFname())
.categorie(model.getCategorie())
.club(ClubEntity.fromModel(model.getClub()))
.genre(model.getGenre())
.licence(model.getLicence())
.country(model.getCountry())
.birth_date(model.getBirth_date())
.email(model.getEmail())
.role(model.getRole())
.grade_arbitrage(model.getGrade_arbitrage())
.url_photo(model.getUrl_photo())
.build();
}
public static String getFullName(MembreModel model) {
return model.getFname() + " " + model.getLname();
}
public String getFullName() {
return this.fname + " " + this.lname;
}
}

View File

@ -64,9 +64,6 @@ public class AffiliationService {
@Inject @Inject
LoggerService ls; LoggerService ls;
@Inject
VirusScannerService scanner;
@RestClient @RestClient
StateIdService stateIdService; StateIdService stateIdService;
@ -79,9 +76,6 @@ public class AffiliationService {
@ConfigProperty(name = "notif.affRequest.mail") @ConfigProperty(name = "notif.affRequest.mail")
List<String> mails; List<String> mails;
@Inject
TradService trad;
public Uni<List<AffiliationRequestModel>> getAllReq() { public Uni<List<AffiliationRequestModel>> getAllReq() {
return repositoryRequest.listAll(); return repositoryRequest.listAll();
} }
@ -95,7 +89,7 @@ public class AffiliationService {
return Uni.createFrom().item(affModel) return Uni.createFrom().item(affModel)
.invoke(Unchecked.consumer(model -> { .invoke(Unchecked.consumer(model -> {
if (model.getSaison() != currentSaison && model.getSaison() != currentSaison + 1) { if (model.getSaison() != currentSaison && model.getSaison() != currentSaison + 1) {
throw new DBadRequestException(trad.t("saison.non.valid")); throw new DBadRequestException("Saison non valid");
} }
})) }))
.chain(() -> ((affModel.getState_id().charAt(0) == 'W') ? stateIdService.get_rna( .chain(() -> ((affModel.getState_id().charAt(0) == 'W') ? stateIdService.get_rna(
@ -113,7 +107,7 @@ public class AffiliationService {
out, affModel.getSaison())) out, affModel.getSaison()))
.onItem().invoke(Unchecked.consumer(count -> { .onItem().invoke(Unchecked.consumer(count -> {
if (count != 0 && unique) { if (count != 0 && unique) {
throw new DBadRequestException(trad.t("demande.d.affiliation.deja.existante")); throw new DBadRequestException("Demande d'affiliation déjà existante");
} }
})) }))
) )
@ -121,28 +115,28 @@ public class AffiliationService {
repository.count("club = ?1 and saison = ?2", club, affModel.getSaison()))) repository.count("club = ?1 and saison = ?2", club, affModel.getSaison())))
.onItem().invoke(Unchecked.consumer(count -> { .onItem().invoke(Unchecked.consumer(count -> {
if (count != 0) { if (count != 0) {
throw new DBadRequestException(trad.t("affiliation.deja.existante")); throw new DBadRequestException("Affiliation déjà existante");
} }
})) }))
.map(o -> affModel) .map(o -> affModel)
.call(model -> ((model.getM1_lincence() != -1) ? combRepository.find("licence", .call(model -> ((model.getM1_lincence() != -1) ? combRepository.find("licence",
model.getM1_lincence()).count().invoke(Unchecked.consumer(count -> { model.getM1_lincence()).count().invoke(Unchecked.consumer(count -> {
if (count == 0) { if (count == 0) {
throw new DBadRequestException(trad.t("licence.membre.n.1.inconnue")); throw new DBadRequestException("Licence membre n°1 inconnue");
} }
})) : Uni.createFrom().nullItem()) })) : Uni.createFrom().nullItem())
) )
.call(model -> ((model.getM2_lincence() != -1) ? combRepository.find("licence", .call(model -> ((model.getM2_lincence() != -1) ? combRepository.find("licence",
model.getM2_lincence()).count().invoke(Unchecked.consumer(count -> { model.getM2_lincence()).count().invoke(Unchecked.consumer(count -> {
if (count == 0) { if (count == 0) {
throw new DBadRequestException(trad.t("licence.membre.n.2.inconnue")); throw new DBadRequestException("Licence membre n°2 inconnue");
} }
})) : Uni.createFrom().nullItem()) })) : Uni.createFrom().nullItem())
) )
.call(model -> ((model.getM3_lincence() != -1) ? combRepository.find("licence", .call(model -> ((model.getM3_lincence() != -1) ? combRepository.find("licence",
model.getM3_lincence()).count().invoke(Unchecked.consumer(count -> { model.getM3_lincence()).count().invoke(Unchecked.consumer(count -> {
if (count == 0) { if (count == 0) {
throw new DBadRequestException(trad.t("licence.membre.n.3.inconnue")); throw new DBadRequestException("Licence membre n°3 inconnue");
} }
})) : Uni.createFrom().nullItem()) })) : Uni.createFrom().nullItem())
); );
@ -151,7 +145,7 @@ public class AffiliationService {
public Uni<?> saveEdit(AffiliationRequestForm form) { public Uni<?> saveEdit(AffiliationRequestForm form) {
return pre_save(form, false) return pre_save(form, false)
.chain(model -> repositoryRequest.findById(form.getId()) .chain(model -> repositoryRequest.findById(form.getId())
.onItem().ifNull().failWith(new DNotFoundException(trad.t("demande.d.affiliation.non.trouve"))) .onItem().ifNull().failWith(new DNotFoundException("Demande d'affiliation non trouvé"))
.chain(origine -> { .chain(origine -> {
origine.setName(model.getName()); origine.setName(model.getName());
origine.setAddress(model.getAddress()); origine.setAddress(model.getAddress());
@ -180,12 +174,15 @@ public class AffiliationService {
LOGGER.debug("Affiliation Request Created"); LOGGER.debug("Affiliation Request Created");
LOGGER.debug(form.toString()); LOGGER.debug(form.toString());
// noinspection ReactiveStreamsUnusedPublisher // noinspection ResultOfMethodCallIgnored,ReactiveStreamsUnusedPublisher
return pre_save(form, true) return pre_save(form, true)
.chain(model -> Panache.withTransaction(() -> repositoryRequest.persist(model))) .chain(model -> Panache.withTransaction(() -> repositoryRequest.persist(model)))
.onItem() .onItem()
.invoke(m -> Utils.uploadFile(scanner, form.getLogo(), m.getId(), media, "aff_request/logo")) .invoke(model -> Uni.createFrom().future(Utils.replacePhoto(model.getId(), form.getLogo(), media,
.invoke(m -> Utils.uploadFile(scanner, form.getStatus(), m.getId(), media, "aff_request/status")) "aff_request/logo")))
.onItem()
.invoke(model -> Uni.createFrom().future(Utils.replacePhoto(model.getId(), form.getStatus(), media,
"aff_request/status")))
.call(model -> reactiveMailer.send( .call(model -> reactiveMailer.send(
Mail.withText("no-reply@ffsaf.fr", Mail.withText("no-reply@ffsaf.fr",
"[NOTIF] FFSAF - Nouvelle demande d'affiliation", "[NOTIF] FFSAF - Nouvelle demande d'affiliation",
@ -204,7 +201,7 @@ public class AffiliationService {
LOGGER.debug(form.toString()); LOGGER.debug(form.toString());
return repositoryRequest.findById(form.getId()) return repositoryRequest.findById(form.getId())
.onItem().ifNull().failWith(new DNotFoundException(trad.t("demande.d.affiliation.non.trouve"))) .onItem().ifNull().failWith(new DNotFoundException("Demande d'affiliation non trouvé"))
.map(model -> { .map(model -> {
model.setName(form.getName()); model.setName(form.getName());
model.setState_id(form.getState_id()); model.setState_id(form.getState_id());
@ -248,8 +245,11 @@ public class AffiliationService {
}) })
.chain(model -> Panache.withTransaction(() -> repositoryRequest.persist(model))) .chain(model -> Panache.withTransaction(() -> repositoryRequest.persist(model)))
.onItem() .onItem()
.invoke(m -> Utils.uploadFile(scanner, form.getLogo(), m.getId(), media, "aff_request/logo")) .invoke(model -> Uni.createFrom().future(Utils.replacePhoto(model.getId(), form.getLogo(), media,
.invoke(m -> Utils.uploadFile(scanner, form.getStatus(), m.getId(), media, "aff_request/status")) "aff_request/logo")))
.onItem()
.invoke(model -> Uni.createFrom().future(Utils.replacePhoto(model.getId(), form.getStatus(), media,
"aff_request/status")))
.map(__ -> "Ok"); .map(__ -> "Ok");
} }
@ -309,7 +309,7 @@ public class AffiliationService {
LOGGER.debug(form.toString()); LOGGER.debug(form.toString());
return repositoryRequest.findById(form.getId()) return repositoryRequest.findById(form.getId())
.onItem().ifNull().failWith(new DNotFoundException(trad.t("demande.d.affiliation.non.trouve"))) .onItem().ifNull().failWith(new DNotFoundException("Demande d'affiliation non trouvé"))
.chain(req -> .chain(req ->
clubRepository.find("StateId = ?1", form.getState_id()).firstResult() clubRepository.find("StateId = ?1", form.getState_id()).firstResult()
.chain(model -> (model == null) ? acceptNew(form, req) : acceptOld(form, req, model)) .chain(model -> (model == null) ? acceptNew(form, req) : acceptOld(form, req, model))
@ -319,11 +319,13 @@ public class AffiliationService {
.recoverWithNull() .recoverWithNull()
.call(___ -> setMembre(form.new Member(3), club, req.getSaison())))) .call(___ -> setMembre(form.new Member(3), club, req.getSaison()))))
.onItem() .onItem()
.invoke(model -> Utils.uploadFile(scanner, form.getLogo(), form.getId(), media, .invoke(model -> Uni.createFrom()
"aff_request/logo")) .future(Utils.replacePhoto(form.getId(), form.getLogo(), media,
.invoke(model -> Utils.uploadFile(scanner, form.getStatus(), form.getId(), media, "aff_request/logo")))
"aff_request/status"))
.onItem() .onItem()
.invoke(model -> Uni.createFrom()
.future(Utils.replacePhoto(form.getId(), form.getStatus(), media,
"aff_request/status")))
.call(model -> Utils.moveMedia(form.getId(), model.getId(), media, "aff_request/logo", .call(model -> Utils.moveMedia(form.getId(), model.getId(), media, "aff_request/logo",
"ppClub")) "ppClub"))
.call(model -> Utils.moveMedia(form.getId(), model.getId(), media, "aff_request/status", .call(model -> Utils.moveMedia(form.getId(), model.getId(), media, "aff_request/status",
@ -353,16 +355,10 @@ public class AffiliationService {
.map(c -> club)); .map(c -> club));
}) })
.call(club -> reactiveMailer.send( .call(club -> reactiveMailer.send(
Mail.withHtml(form.getM1_email(), "FFSAF - Creation de votre compte sur l'intranet", Mail.withText(form.getM1_email(),
String.format(Utils.HTML_HEADER, "FFSAF - Creation de votre compte sur l'intranet") + "FFSAF - Acceptation de votre demande d'affiliation",
String.format(""" String.format(
<p>Votre demande d'affiliation pour le club <span class="highlight">%s</span> a été acceptée.</p> """
<p>LLe numéro d'affiliation de votre club est le <span class="highlight">%d</span>.</p>
""",
club.getName(), club.getNo_affiliation()) +
Utils.HTML_FOOTER
)
.setText(String.format("""
Bonjour, Bonjour,
Votre demande d'affiliation pour le club %s a été acceptée. Votre demande d'affiliation pour le club %s a été acceptée.
@ -370,8 +366,8 @@ public class AffiliationService {
Cordialement, Cordialement,
L'équipe de la FFSAF L'équipe de la FFSAF
""", club.getName(), club.getNo_affiliation())) """, club.getName(), club.getNo_affiliation())
.setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("contact@ffsaf.fr") ).setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("contact@ffsaf.fr")
.addTo(form.getM2_email(), form.getM3_email()) .addTo(form.getM2_email(), form.getM3_email())
)); ));
} }
@ -401,7 +397,7 @@ public class AffiliationService {
public Uni<SimpleReqAffiliation> getRequest(long id) { public Uni<SimpleReqAffiliation> getRequest(long id) {
return repositoryRequest.findById(id).map(SimpleReqAffiliation::fromModel) return repositoryRequest.findById(id).map(SimpleReqAffiliation::fromModel)
.onItem().ifNull().failWith(new DNotFoundException(trad.t("demande.d.affiliation.non.trouve"))) .onItem().ifNull().failWith(new DNotFoundException("Demande d'affiliation non trouvé"))
.call(out -> clubRepository.find("StateId = ?1", out.getStateId()).firstResult().invoke(c -> { .call(out -> clubRepository.find("StateId = ?1", out.getStateId()).firstResult().invoke(c -> {
if (c != null) { if (c != null) {
out.setClub(c.getId()); out.setClub(c.getId());
@ -425,7 +421,7 @@ public class AffiliationService {
public Uni<List<SimpleAffiliation>> getAffiliation(long id) { public Uni<List<SimpleAffiliation>> getAffiliation(long id) {
return clubRepository.findById(id) return clubRepository.findById(id)
.onItem().ifNull().failWith(new DNotFoundException(trad.t("club.non.trouve"))) .onItem().ifNull().failWith(new DNotFoundException("Club non trouvé"))
.call(model -> Mutiny.fetch(model.getAffiliations())) .call(model -> Mutiny.fetch(model.getAffiliations()))
.chain(model -> repositoryRequest.list("state_id = ?1", model.getStateId()) .chain(model -> repositoryRequest.list("state_id = ?1", model.getStateId())
.map(reqs -> reqs.stream().map(req -> .map(reqs -> reqs.stream().map(req ->
@ -437,11 +433,11 @@ public class AffiliationService {
public Uni<SimpleAffiliation> setAffiliation(long id, int saison) { public Uni<SimpleAffiliation> setAffiliation(long id, int saison) {
return clubRepository.findById(id) return clubRepository.findById(id)
.onItem().ifNull().failWith(new DNotFoundException(trad.t("club.non.trouve"))) .onItem().ifNull().failWith(new DNotFoundException("Club non trouvé"))
.call(model -> Mutiny.fetch(model.getAffiliations())) .call(model -> Mutiny.fetch(model.getAffiliations()))
.invoke(Unchecked.consumer(club -> { .invoke(Unchecked.consumer(club -> {
if (club.getAffiliations().stream().anyMatch(affiliation -> affiliation.getSaison() == saison)) { if (club.getAffiliations().stream().anyMatch(affiliation -> affiliation.getSaison() == saison)) {
throw new DBadRequestException(trad.t("affiliation.deja.existante")); throw new DBadRequestException("Affiliation déjà existante");
} }
})) }))
.chain(club -> .chain(club ->
@ -462,16 +458,10 @@ public class AffiliationService {
public Uni<?> deleteReqAffiliation(long id, String reason, boolean federationAdmin) { public Uni<?> deleteReqAffiliation(long id, String reason, boolean federationAdmin) {
return repositoryRequest.findById(id) return repositoryRequest.findById(id)
.call(aff -> federationAdmin ? reactiveMailer.send( .call(aff -> federationAdmin ? reactiveMailer.send(
Mail.withHtml(aff.getM1_email(), "FFSAF - Votre demande d'affiliation a été rejetée.", Mail.withText(aff.getM1_email(),
String.format(Utils.HTML_HEADER, "FFSAF - Votre demande d'affiliation a été rejetée.") + "FFSAF - Votre demande d'affiliation a été rejetée.",
String.format(""" String.format(
<p>Votre demande d'affiliation pour le club %s a été rejetée pour la/les raison(s) suivante(s):<br/>%s</p> """
<p>Si vous rencontrez un problème ou si vous avez des questions, n'hésitez pas à nous contacter à l'adresse <a href="mailto:contact@ffsaf.fr">contact@ffsaf.fr</a>.</p>
""",
aff.getName(), reason) +
Utils.HTML_FOOTER
)
.setText(String.format("""
Bonjour, Bonjour,
Votre demande d'affiliation pour le club %s a été rejetée pour la/les raison(s) suivante(s): Votre demande d'affiliation pour le club %s a été rejetée pour la/les raison(s) suivante(s):
@ -481,8 +471,8 @@ public class AffiliationService {
Cordialement, Cordialement,
L'équipe de la FFSAF L'équipe de la FFSAF
""", aff.getName(), reason)) """, aff.getName(), reason)
.setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("contact@ffsaf.fr") ).setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("contact@ffsaf.fr")
.addTo(aff.getM2_email(), aff.getM3_email()) .addTo(aff.getM2_email(), aff.getM3_email())
) : Uni.createFrom().nullItem()) ) : Uni.createFrom().nullItem())
.chain(aff -> Panache.withTransaction(() -> repositoryRequest.delete(aff))) .chain(aff -> Panache.withTransaction(() -> repositoryRequest.delete(aff)))

View File

@ -1,195 +0,0 @@
package fr.titionfire.ffsaf.domain.service;
import fr.titionfire.ffsaf.data.model.CardModel;
import fr.titionfire.ffsaf.data.model.ClubCardModel;
import fr.titionfire.ffsaf.data.model.CompetitionModel;
import fr.titionfire.ffsaf.data.model.MatchModel;
import fr.titionfire.ffsaf.data.repository.*;
import fr.titionfire.ffsaf.rest.exception.DBadRequestException;
import fr.titionfire.ffsaf.ws.recv.RCard;
import io.quarkus.hibernate.reactive.panache.Panache;
import io.quarkus.hibernate.reactive.panache.common.WithSession;
import io.quarkus.panache.common.Sort;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@WithSession
@ApplicationScoped
public class CardService {
@Inject
CardRepository cardRepository;
@Inject
ClubCardRepository clubCardRepository;
@Inject
RegisterRepository registerRepository;
@Inject
CompetitionGuestRepository competitionGuestRepository;
@Inject
MatchRepository matchRepository;
@Inject
TradService trad;
private static final List<CardModel.CardType> COMPETITION_LEVEL_CARDS = List.of(
CardModel.CardType.YELLOW,
CardModel.CardType.RED,
CardModel.CardType.BLACK
);
private List<Long> extractCombIds(MatchModel match) {
List<Long> ids = new ArrayList<>();
if (match.getC1_id() != null)
ids.add(match.getC1_id().getId());
if (match.getC2_id() != null)
ids.add(match.getC2_id().getId());
if (match.getC1_guest() != null)
ids.add(match.getC1_guest().getId() * -1);
if (match.getC2_guest() != null)
ids.add(match.getC2_guest().getId() * -1);
return ids;
}
public Uni<List<CardModel>> getForMatch(MatchModel match) {
return cardRepository.list(
"competition = ?1 AND (type IN ?2 OR (type = CardType.BLUE AND category = ?4)) AND comb IN ?3",
match.getCategory().getCompet(), COMPETITION_LEVEL_CARDS,
extractCombIds(match), match.getCategory().getId());
}
public Uni<List<CardModel>> getAll(CompetitionModel competition) {
return cardRepository.list("competition = ?1", competition);
}
public Uni<RCard.SendCardAdd> checkCanBeAdded(RCard.SendCardAdd card, MatchModel matchModel) {
return cardRepository.find("competition = ?1 AND comb = ?2",
Sort.descending("type"),
matchModel.getCategory().getCompet(), card.combId())
.firstResult()
.map(card_ -> {
if (card.type() == CardModel.CardType.BLUE) {
return card_ == null || (card_.getType() == CardModel.CardType.BLUE
&& !Objects.equals(card_.getCategory(), matchModel.getCategory().getId()));
}
if (card.type() == CardModel.CardType.BLACK) {
return card_ != null && card_.getType() == CardModel.CardType.RED;
}
return card_ == null || card_.getType().ordinal() < card.type().ordinal();
})
.chain(b -> {
if (b)
return Uni.createFrom().item(card);
else
return Uni.createFrom().failure(new DBadRequestException(trad.t("card.cannot.be.added")));
});
}
public Uni<List<CardModel>> addTeamCard(CompetitionModel competition, String teamUuid, String teamName,
CardModel.CardType type, String reason) {
return clubCardRepository.find("competition = ?1 AND (teamUuid = ?2 OR teamName = ?3)",
Sort.descending("type"), competition.getId(), teamUuid, teamName)
.firstResult()
.map(card_ -> {
if (type == CardModel.CardType.BLACK) {
return card_ != null && card_.getType() == CardModel.CardType.RED;
}
return card_ == null || card_.getType().ordinal() < type.ordinal();
})
.chain(b -> {
if (!b)
return Uni.createFrom().failure(new DBadRequestException(trad.t("card.cannot.be.added")));
if (teamUuid != null) {
return registerRepository.list("competition = ?1 AND club.clubId = ?2", competition, teamUuid)
.map(l -> l.stream().map(r -> r.getMembre().getId()).toList());
} else {
return competitionGuestRepository.list("competition = ?1 AND club = ?2", competition,
teamName)
.map(l -> l.stream().map(r -> r.getId() * -1).toList());
}
})
.chain(combIds -> cardRepository.list("competition = ?1 AND comb IN ?2", competition, combIds)
.map(cards -> {
List<CardModel> newCards = new ArrayList<>();
for (Long id : combIds) {
Optional<CardModel> optional = cards.stream()
.filter(c -> id.equals(c.getComb()) && c.getType() == type).findAny();
CardModel model = new CardModel();
model.setCompetition(competition);
model.setCompetitionId(competition.getId());
model.setComb(id);
model.setTeamCard(true);
if (optional.isEmpty()) {
model.setType(type);
} else {
model.setType(
CardModel.CardType.values()[Math.min(optional.get().getType().ordinal() + 1,
CardModel.CardType.BLACK.ordinal())]);
}
newCards.add(model);
}
return newCards;
})
)
.call(newCards -> Panache.withTransaction(() -> cardRepository.persist(newCards)))
.call(newCards -> {
ClubCardModel model = new ClubCardModel();
model.setCompetition(competition.getId());
model.setTeamUuid(teamUuid);
model.setTeamName(teamName);
model.setType(type);
model.setReason(reason);
model.setCardIds(newCards.stream().map(CardModel::getId).toList());
return Panache.withTransaction(() -> clubCardRepository.persist(model));
});
}
public Uni<List<CardModel>> recvReturnState(CompetitionModel competition, RCard.SendTeamCardReturnState state) {
return clubCardRepository.find("competition = ?1 AND (teamUuid = ?2 OR teamName = ?3) AND type = ?4",
competition.getId(), state.teamUuid(), state.teamName(), state.type())
.firstResult()
.chain(o -> cardRepository.list("id IN ?1", o.getCardIds()))
.call(cards -> matchRepository.list("category.compet = ?1 AND category.id IN ?2", competition,
state.selectedCategory())
.invoke(matches -> {
for (CardModel card : cards) {
for (MatchModel m : matches.stream()
.filter(m -> extractCombIds(m).contains(card.getComb())).toList()) {
if (state.state() == 1) {
card.setCategory(m.getCategory().getId());
} else if (state.state() == 2) {
card.setCategory(m.getCategory().getId());
if (Objects.equals(m.getId(), state.selectedMatch()))
card.setMatch(m.getId());
}
}
}
})
.chain(() -> Panache.withTransaction(() -> cardRepository.persist(cards))));
}
public Uni<List<Long>> rmTeamCard(CompetitionModel competition, String teamUuid, String teamName,
CardModel.CardType type) {
return clubCardRepository.find("competition = ?1 AND (teamUuid = ?2 OR teamName = ?3) AND type = ?4",
competition.getId(), teamUuid, teamName, type)
.firstResult()
.chain(card -> Uni.createFrom().item(card.getCardIds())
.call(() -> Panache.withTransaction(() -> cardRepository.delete("id IN ?1", card.getCardIds())))
.call(() -> Panache.withTransaction(() -> clubCardRepository.delete(card))));
}
}

View File

@ -45,13 +45,10 @@ public class CategoryService {
@Inject @Inject
CompetitionGuestRepository competitionGuestRepository; CompetitionGuestRepository competitionGuestRepository;
@Inject
TradService trad;
public Uni<CategoryData> getByIdAdmin(SecurityCtx securityCtx, CompetitionSystem system, Long id) { public Uni<CategoryData> getByIdAdmin(SecurityCtx securityCtx, CompetitionSystem system, Long id) {
return repository.find("systemId = ?1 AND system = ?2", id, system) return repository.find("systemId = ?1 AND system = ?2", id, system)
.firstResult() .firstResult()
.onItem().ifNull().failWith(() -> new RuntimeException(trad.t("categorie.non.trouver"))) .onItem().ifNull().failWith(() -> new RuntimeException("Category not found"))
.call(data -> permService.hasAdminViewPerm(securityCtx, data.getCompet())) .call(data -> permService.hasAdminViewPerm(securityCtx, data.getCompet()))
.map(CategoryData::fromModel); .map(CategoryData::fromModel);
} }
@ -67,7 +64,7 @@ public class CategoryService {
.chain(o -> { .chain(o -> {
if (o == null) { if (o == null) {
return competRepository.findById(data.getCompet()) return competRepository.findById(data.getCompet())
.onItem().ifNull().failWith(() -> new RuntimeException(trad.t("competition.not.found"))) .onItem().ifNull().failWith(() -> new RuntimeException("Competition not found"))
.call(o2 -> permService.hasEditPerm(securityCtx, o2)) .call(o2 -> permService.hasEditPerm(securityCtx, o2))
.chain(competitionModel -> { .chain(competitionModel -> {
CategoryModel model = new CategoryModel(); CategoryModel model = new CategoryModel();
@ -142,7 +139,7 @@ public class CategoryService {
.onItem().ifNotNull().call(o2 -> permService.hasEditPerm(securityCtx, o2.getCompet())) .onItem().ifNotNull().call(o2 -> permService.hasEditPerm(securityCtx, o2.getCompet()))
.onItem().ifNull().switchTo( .onItem().ifNull().switchTo(
() -> competRepository.findById(data.getCompet()) () -> competRepository.findById(data.getCompet())
.onItem().ifNull().failWith(() -> new RuntimeException(trad.t("competition.not.found"))) .onItem().ifNull().failWith(() -> new RuntimeException("Compet not found"))
.call(o -> permService.hasEditPerm(securityCtx, o)) .call(o -> permService.hasEditPerm(securityCtx, o))
.map(o -> { .map(o -> {
CategoryModel model = new CategoryModel(); CategoryModel model = new CategoryModel();
@ -259,7 +256,7 @@ public class CategoryService {
public Uni<?> delete(SecurityCtx securityCtx, CompetitionSystem system, Long id) { public Uni<?> delete(SecurityCtx securityCtx, CompetitionSystem system, Long id) {
return repository.find("systemId = ?1 AND system = ?2", id, system).firstResult() return repository.find("systemId = ?1 AND system = ?2", id, system).firstResult()
.onItem().ifNull().failWith(() -> new RuntimeException(trad.t("categorie.non.trouver"))) .onItem().ifNull().failWith(() -> new RuntimeException("Category not found"))
.call(o -> permService.hasEditPerm(securityCtx, o.getCompet())) .call(o -> permService.hasEditPerm(securityCtx, o.getCompet()))
.call(o -> Mutiny.fetch(o.getTree()) .call(o -> Mutiny.fetch(o.getTree())
.call(o2 -> o2.isEmpty() ? Uni.createFrom().nullItem() : .call(o2 -> o2.isEmpty() ? Uni.createFrom().nullItem() :

View File

@ -58,7 +58,7 @@ public class CheckoutService {
String organizationSlug; String organizationSlug;
public Uni<Boolean> canDeleteLicence(long id) { public Uni<Boolean> canDeleteLicence(long id) {
return repository.countByLicenseId(id).invoke(c -> System.out.println(c)).map(count -> count == 0); return repository.find("?1 IN licenseIds", id).count().map(count -> count == 0);
} }
public Uni<String> create(List<Long> ids, SecurityCtx securityCtx) { public Uni<String> create(List<Long> ids, SecurityCtx securityCtx) {

View File

@ -5,7 +5,6 @@ import com.fasterxml.jackson.core.type.TypeReference;
import fr.titionfire.ffsaf.data.model.AffiliationModel; import fr.titionfire.ffsaf.data.model.AffiliationModel;
import fr.titionfire.ffsaf.data.model.ClubModel; import fr.titionfire.ffsaf.data.model.ClubModel;
import fr.titionfire.ffsaf.data.model.MembreModel; import fr.titionfire.ffsaf.data.model.MembreModel;
import fr.titionfire.ffsaf.data.repository.AffiliationRepository;
import fr.titionfire.ffsaf.data.repository.ClubRepository; import fr.titionfire.ffsaf.data.repository.ClubRepository;
import fr.titionfire.ffsaf.data.repository.CombRepository; import fr.titionfire.ffsaf.data.repository.CombRepository;
import fr.titionfire.ffsaf.net2.ServerCustom; import fr.titionfire.ffsaf.net2.ServerCustom;
@ -45,9 +44,6 @@ public class ClubService {
@Inject @Inject
ClubRepository repository; ClubRepository repository;
@Inject
AffiliationRepository affiliationRepository;
@Inject @Inject
ServerCustom serverCustom; ServerCustom serverCustom;
@ -63,9 +59,6 @@ public class ClubService {
@Inject @Inject
LoggerService ls; LoggerService ls;
@Inject
TradService trad;
public SimpleClubModel findByIdOptionalClub(long id) throws Throwable { public SimpleClubModel findByIdOptionalClub(long id) throws Throwable {
return VertxContextSupport.subscribeAndAwait( return VertxContextSupport.subscribeAndAwait(
() -> Panache.withTransaction(() -> repository.findById(id).map(SimpleClubModel::fromModel))); () -> Panache.withTransaction(() -> repository.findById(id).map(SimpleClubModel::fromModel)));
@ -133,7 +126,7 @@ public class ClubService {
return combRepository.find("userId = ?1", securityCtx.getSubject()).firstResult() return combRepository.find("userId = ?1", securityCtx.getSubject()).firstResult()
.invoke(Unchecked.consumer(m -> { .invoke(Unchecked.consumer(m -> {
if (m == null || m.getClub() == null) if (m == null || m.getClub() == null)
throw new DNotFoundException(trad.t("club.non.trouve")); throw new DNotFoundException("Club non trouvé");
})) }))
.map(MembreModel::getClub) .map(MembreModel::getClub)
.call(club -> Mutiny.fetch(club.getContact())); .call(club -> Mutiny.fetch(club.getContact()));
@ -153,7 +146,7 @@ public class ClubService {
return combRepository.find("userId = ?1", securityCtx.getSubject()).firstResult() return combRepository.find("userId = ?1", securityCtx.getSubject()).firstResult()
.invoke(Unchecked.consumer(m -> { .invoke(Unchecked.consumer(m -> {
if (m == null || m.getClub() == null) if (m == null || m.getClub() == null)
throw new DNotFoundException(trad.t("club.non.trouve")); throw new DNotFoundException("Club non trouvé");
if (!securityCtx.isInClubGroup(m.getClub().getId())) if (!securityCtx.isInClubGroup(m.getClub().getId()))
throw new DForbiddenException(); throw new DForbiddenException();
})) }))
@ -169,7 +162,7 @@ public class ClubService {
return combRepository.find("userId = ?1", securityCtx.getSubject()).firstResult() return combRepository.find("userId = ?1", securityCtx.getSubject()).firstResult()
.invoke(Unchecked.consumer(m -> { .invoke(Unchecked.consumer(m -> {
if (m == null || m.getClub() == null) if (m == null || m.getClub() == null)
throw new DNotFoundException(trad.t("club.non.trouve")); throw new DNotFoundException("Club non trouvé");
if (!securityCtx.isInClubGroup(m.getClub().getId())) if (!securityCtx.isInClubGroup(m.getClub().getId()))
throw new DForbiddenException(); throw new DForbiddenException();
})) }))
@ -186,7 +179,7 @@ public class ClubService {
ls.logUpdate("Contact(s)...", club); ls.logUpdate("Contact(s)...", club);
club.setContact(MAPPER.readValue(form.getContact(), typeRef)); club.setContact(MAPPER.readValue(form.getContact(), typeRef));
} catch (JsonProcessingException e) { } catch (JsonProcessingException e) {
throw new DBadRequestException(trad.t("erreur.de.format.des.contacts")); throw new DBadRequestException("Erreur de format des contacts");
} }
ls.logChange("Lieux d'entrainements", club.getTraining_location(), form.getTraining_location(), ls.logChange("Lieux d'entrainements", club.getTraining_location(), form.getTraining_location(),
@ -236,13 +229,12 @@ public class ClubService {
ls.logUpdate("Contact(s)...", m); ls.logUpdate("Contact(s)...", m);
m.setContact(MAPPER.readValue(input.getContact(), typeRef)); m.setContact(MAPPER.readValue(input.getContact(), typeRef));
} catch (JsonProcessingException e) { } catch (JsonProcessingException e) {
throw new DBadRequestException(trad.t("erreur.de.format.des.contacts")); throw new DBadRequestException("Erreur de format des contacts");
} }
} }
return Panache.withTransaction(() -> repository.persist(m)).call(() -> ls.append()); return Panache.withTransaction(() -> repository.persist(m)).call(() -> ls.append());
})) }))
.call(clubModel -> nameChange.get() ? keycloakService.updateGroupFromClub( .call(clubModel -> nameChange.get() ? keycloakService.updateGroupFromClub(clubModel) // update group in keycloak
clubModel) // update group in keycloak
: Uni.createFrom().nullItem()) : Uni.createFrom().nullItem())
.invoke(membreModel -> SReqClub.sendIfNeed(serverCustom.clients, .invoke(membreModel -> SReqClub.sendIfNeed(serverCustom.clients,
SimpleClubModel.fromModel(membreModel))) SimpleClubModel.fromModel(membreModel)))
@ -290,13 +282,11 @@ public class ClubService {
combModel.setClub(null); combModel.setClub(null);
combModel.setRole(RoleAsso.MEMBRE); combModel.setRole(RoleAsso.MEMBRE);
}).toList()) }).toList())
.call(list -> list.stream().noneMatch(m -> m.getUserId() != null) ? .call(list -> (list.isEmpty()) ? Uni.createFrom().voidItem() :
Uni.createFrom().voidItem() :
Uni.join().all(list.stream().filter(m -> m.getUserId() != null) Uni.join().all(list.stream().filter(m -> m.getUserId() != null)
.map(m -> keycloakService.clearUser(m.getUserId())).toList()) .map(m -> keycloakService.clearUser(m.getUserId())).toList())
.andCollectFailures()) .andCollectFailures())
.chain(list -> list.isEmpty() ? Uni.createFrom().voidItem() : .chain(list -> Panache.withTransaction(() -> combRepository.persist(list)))
Panache.withTransaction(() -> combRepository.persist(list)))
.map(o -> club) .map(o -> club)
) )
.call(clubModel -> (clubModel.getClubId() == null) ? Uni.createFrom() .call(clubModel -> (clubModel.getClubId() == null) ? Uni.createFrom()
@ -333,11 +323,9 @@ public class ClubService {
} }
public Uni<List<ClubMapData>> getMapData() { public Uni<List<ClubMapData>> getMapData() {
return affiliationRepository.list("saison >= ?1 AND club.international = ?2", Utils.getSaison() - 1, false) return repository.list("international", false).toMulti().flatMap(list -> Multi.createFrom().iterable(list))
.toMulti().flatMap(list -> Multi.createFrom().iterable(list)) .call(clubModel -> Mutiny.fetch(clubModel.getContact()))
.call(affiliationModel -> Mutiny.fetch(affiliationModel.getClub().getContact())) .map(clubModel -> {
.map(affiliationModel -> {
ClubModel clubModel = affiliationModel.getClub();
ClubMapData data = new ClubMapData(); ClubMapData data = new ClubMapData();
data.setName(clubModel.getName()); data.setName(clubModel.getName());

View File

@ -98,14 +98,12 @@ public class CompetPermService {
map.putIfAbsent(model.getId(), "owner"); map.putIfAbsent(model.getId(), "owner");
else if (securityCtx.roleHas("federation_admin")) else if (securityCtx.roleHas("federation_admin"))
map.putIfAbsent(model.getId(), "admin"); map.putIfAbsent(model.getId(), "admin");
else if (securityCtx.isInClubGroup( else if (securityCtx.isInClubGroup(model.getClub().getId()) && (securityCtx.roleHas(
model.getClub().getId()) && (securityCtx.isClubAdmin())) "club_president")
|| securityCtx.roleHas("club_respo_intra") || securityCtx.roleHas(
"club_secretaire")
|| securityCtx.roleHas("club_tresorier")))
map.putIfAbsent(model.getId(), "admin"); map.putIfAbsent(model.getId(), "admin");
else if (model.getAdmin().contains(securityCtx.getSubject()))
map.putIfAbsent(model.getId(), "admin");
else if (model.getTable().contains(securityCtx.getSubject()))
map.putIfAbsent(model.getId(), "table");
} }
return map; return map;
})); }));
@ -184,14 +182,12 @@ public class CompetPermService {
if (o.getSystem() == CompetitionSystem.SAFCA) if (o.getSystem() == CompetitionSystem.SAFCA)
return hasSafcaViewPerm(securityCtx, o.getId()); return hasSafcaViewPerm(securityCtx, o.getId());
if (o.getAdmin().contains(securityCtx.getSubject()))
return Uni.createFrom().nullItem();
if (!securityCtx.isInClubGroup(o.getClub().getId())) // Only membre club pass here if (!securityCtx.isInClubGroup(o.getClub().getId())) // Only membre club pass here
throw new DForbiddenException(); throw new DForbiddenException();
if (o.getSystem() == CompetitionSystem.INTERNAL) if (o.getSystem() == CompetitionSystem.INTERNAL)
if (securityCtx.isClubAdmin()) if (securityCtx.roleHas("club_president") || securityCtx.roleHas("club_respo_intra")
|| securityCtx.roleHas("club_secretaire") || securityCtx.roleHas("club_tresorier"))
return Uni.createFrom().nullItem(); return Uni.createFrom().nullItem();
throw new DForbiddenException(); throw new DForbiddenException();

View File

@ -7,7 +7,10 @@ import fr.titionfire.ffsaf.net2.data.SimpleCompet;
import fr.titionfire.ffsaf.net2.request.SReqCompet; import fr.titionfire.ffsaf.net2.request.SReqCompet;
import fr.titionfire.ffsaf.net2.request.SReqRegister; import fr.titionfire.ffsaf.net2.request.SReqRegister;
import fr.titionfire.ffsaf.rest.client.dto.NotificationData; import fr.titionfire.ffsaf.rest.client.dto.NotificationData;
import fr.titionfire.ffsaf.rest.data.*; import fr.titionfire.ffsaf.rest.data.CompetitionData;
import fr.titionfire.ffsaf.rest.data.RegisterRequestData;
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.DBadRequestException;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException; import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.rest.exception.DNotFoundException; import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
@ -60,9 +63,6 @@ public class CompetitionService {
@Inject @Inject
CompetitionGuestRepository competitionGuestRepository; CompetitionGuestRepository competitionGuestRepository;
@Inject
CatPresetRepository catPresetRepository;
@Inject @Inject
ServerCustom serverCustom; ServerCustom serverCustom;
@ -97,29 +97,21 @@ public class CompetitionService {
@CacheName("have-access") @CacheName("have-access")
Cache cacheNoneAccess; Cache cacheNoneAccess;
@Inject
TradService trad;
public Uni<CompetitionData> getById(SecurityCtx securityCtx, Long id) { public Uni<CompetitionData> getById(SecurityCtx securityCtx, Long id) {
return permService.hasViewPerm(securityCtx, id).map(cm -> { return permService.hasViewPerm(securityCtx, id).map(CompetitionData::fromModelLight);
CompetitionData out = CompetitionData.fromModelLight(cm);
if (cm.getAdmin() != null) {
out.setCanEditRegisters(cm.getAdmin().stream().anyMatch(u -> u.equals(securityCtx.getSubject())));
}
return out;
});
} }
public Uni<CompetitionData> getByIdAdmin(SecurityCtx securityCtx, Long id) { public Uni<CompetitionData> getByIdAdmin(SecurityCtx securityCtx, Long id) {
if (id == 0) { if (id == 0) {
return Uni.createFrom().item(new CompetitionData()); return Uni.createFrom()
.item(new CompetitionData(null, "", "", "", "", new Date(), new Date(),
CompetitionSystem.INTERNAL, RegisterMode.FREE, new Date(), new Date(), true,
null, "", "", null, true, "", "", "", ""));
} }
return permService.hasAdminViewPerm(securityCtx, id) return permService.hasAdminViewPerm(securityCtx, id)
.call(competitionModel -> Mutiny.fetch(competitionModel.getCatPreset()))
.chain(competitionModel -> Mutiny.fetch(competitionModel.getInsc()) .chain(competitionModel -> Mutiny.fetch(competitionModel.getInsc())
.chain(insc -> Mutiny.fetch(competitionModel.getGuests()) .chain(insc -> Mutiny.fetch(competitionModel.getGuests())
.map(guest -> CompetitionData.fromModel(competitionModel).addInsc(insc, guest) .map(guest -> CompetitionData.fromModel(competitionModel).addInsc(insc, guest))))
.addPresets(competitionModel.getCatPreset()))))
.chain(data -> .chain(data ->
vertx.getOrCreateContext().executeBlocking(() -> { vertx.getOrCreateContext().executeBlocking(() -> {
keycloakService.getUser(UUID.fromString(data.getOwner())) keycloakService.getUser(UUID.fromString(data.getOwner()))
@ -137,14 +129,6 @@ public class CompetitionService {
out.addAll(cm.stream().map(CompetitionData::fromModelLight).toList()); out.addAll(cm.stream().map(CompetitionData::fromModelLight).toList());
out.forEach(competition -> competition.setCanEdit(true)); out.forEach(competition -> competition.setCanEdit(true));
})) }))
.chain(ids -> repository.list("id NOT IN ?1 AND ?2 IN admin", ids, securityCtx.getSubject())
.map(cm -> {
out.addAll(cm.stream().map(CompetitionData::fromModelLight).toList());
out.forEach(competition -> competition.setCanEditRegisters(true));
List<Long> ids2 = new ArrayList<>(ids);
ids2.addAll(cm.stream().map(CompetitionModel::getId).toList());
return ids2;
}))
.call(ids -> .call(ids ->
repository.list("id NOT IN ?1 AND (publicVisible = TRUE OR registerMode IN ?2)", ids, repository.list("id NOT IN ?1 AND (publicVisible = TRUE OR registerMode IN ?2)", ids,
securityCtx.isClubAdmin() ? List.of(RegisterMode.FREE, RegisterMode.HELLOASSO, securityCtx.isClubAdmin() ? List.of(RegisterMode.FREE, RegisterMode.HELLOASSO,
@ -181,9 +165,8 @@ public class CompetitionService {
public Uni<List<CompetitionData>> getAllSystemTable(SecurityCtx securityCtx, public Uni<List<CompetitionData>> getAllSystemTable(SecurityCtx securityCtx,
CompetitionSystem system) { CompetitionSystem system) {
return repository.list("system = ?1", system) return repository.list("system = ?1", system)
.chain(l -> Uni.join().all(l.stream().map(cm -> .chain(l -> Uni.join().all(l.stream().map(cm -> permService.hasTablePerm(securityCtx, cm)).toList())
permService.hasTablePerm(securityCtx, cm).onFailure().recoverWithNull() .andCollectFailures())
).toList()).andCollectFailures())
.map(l -> l.stream().filter(Objects::nonNull).map(CompetitionData::fromModel).toList()); .map(l -> l.stream().filter(Objects::nonNull).map(CompetitionData::fromModel).toList());
} }
@ -193,7 +176,7 @@ public class CompetitionService {
.invoke(Unchecked.consumer(combModel -> { .invoke(Unchecked.consumer(combModel -> {
if (!securityCtx.getRoles().contains("create_compet") && !securityCtx.getRoles() if (!securityCtx.getRoles().contains("create_compet") && !securityCtx.getRoles()
.contains("federation_admin")) .contains("federation_admin"))
throw new DForbiddenException(trad.t("vous.ne.pouvez.pas.creer.de.competition")); throw new DForbiddenException("Vous ne pouvez pas créer de compétition");
})) }))
.map(MembreModel::getClub) .map(MembreModel::getClub)
.chain(clubModel -> { .chain(clubModel -> {
@ -206,21 +189,17 @@ public class CompetitionService {
model.setGuests(new ArrayList<>()); model.setGuests(new ArrayList<>());
model.setUuid(UUID.randomUUID().toString()); model.setUuid(UUID.randomUUID().toString());
model.setOwner(securityCtx.getSubject()); model.setOwner(securityCtx.getSubject());
model.setCatPreset(new ArrayList<>());
copyData(data, model); copyData(data, model);
return Panache.withTransaction(() -> repository.persist(model)); return Panache.withTransaction(() -> repository.persist(model));
}) }).map(CompetitionData::fromModel)
.call(model -> syncPreset(data, model))
.map(CompetitionData::fromModel)
.call(c -> (c.getSystem() == CompetitionSystem.SAFCA) ? cacheAccess.invalidate( .call(c -> (c.getSystem() == CompetitionSystem.SAFCA) ? cacheAccess.invalidate(
securityCtx.getSubject()) : Uni.createFrom().nullItem()) securityCtx.getSubject()) : Uni.createFrom().nullItem())
.call(c -> (c.getSystem() == CompetitionSystem.INTERNAL) ? cacheNoneAccess.invalidate( .call(c -> (c.getSystem() == CompetitionSystem.INTERNAL) ? cacheNoneAccess.invalidate(
securityCtx.getSubject()) : Uni.createFrom().nullItem()); securityCtx.getSubject()) : Uni.createFrom().nullItem());
} else { } else {
return permService.hasEditPerm(securityCtx, data.getId()) return permService.hasEditPerm(securityCtx, data.getId())
.call(model -> Mutiny.fetch(model.getCatPreset()))
.chain(model -> { .chain(model -> {
copyData(data, model); copyData(data, model);
@ -228,8 +207,7 @@ public class CompetitionService {
keycloakService.getUser(data.getOwner()).map(UserRepresentation::getId).orElse(null)) keycloakService.getUser(data.getOwner()).map(UserRepresentation::getId).orElse(null))
.invoke(Unchecked.consumer(newOwner -> { .invoke(Unchecked.consumer(newOwner -> {
if (newOwner == null) if (newOwner == null)
throw new DBadRequestException( throw new DBadRequestException("User " + data.getOwner() + " not found");
String.format(trad.t("user.not.found"), data.getOwner()));
if (!newOwner.equals(model.getOwner())) { if (!newOwner.equals(model.getOwner())) {
if (!securityCtx.roleHas("federation_admin") if (!securityCtx.roleHas("federation_admin")
&& !securityCtx.roleHas("safca_super_admin") && !securityCtx.roleHas("safca_super_admin")
@ -239,9 +217,7 @@ public class CompetitionService {
} }
})) }))
.chain(__ -> Panache.withTransaction(() -> repository.persist(model))); .chain(__ -> Panache.withTransaction(() -> repository.persist(model)));
}) }).map(CompetitionData::fromModel)
.call(model -> syncPreset(data, model))
.map(model -> CompetitionData.fromModel(model).addPresets(model.getCatPreset()))
.call(c -> (c.getSystem() == CompetitionSystem.SAFCA) ? cacheAccess.invalidate( .call(c -> (c.getSystem() == CompetitionSystem.SAFCA) ? cacheAccess.invalidate(
securityCtx.getSubject()) : Uni.createFrom().nullItem()) securityCtx.getSubject()) : Uni.createFrom().nullItem())
.call(c -> (c.getSystem() == CompetitionSystem.INTERNAL) ? cacheNoneAccess.invalidate( .call(c -> (c.getSystem() == CompetitionSystem.INTERNAL) ? cacheNoneAccess.invalidate(
@ -249,45 +225,6 @@ public class CompetitionService {
} }
} }
private Uni<?> syncPreset(CompetitionData data, CompetitionModel model) {
List<Long> toRemoveId = model.getCatPreset().stream()
.map(CatPresetModel::getId)
.filter(id -> data.getPresets().stream().noneMatch(preset -> Objects.equals(preset.getId(), id)))
.toList();
for (PresetData preset : data.getPresets()) {
CatPresetModel presetModel;
if (preset.getId() != null && preset.getId() > 0) {
presetModel = model.getCatPreset().stream()
.filter(p -> p.getId().equals(preset.getId()))
.findFirst()
.orElse(new CatPresetModel());
} else {
presetModel = new CatPresetModel();
model.getCatPreset().add(presetModel);
}
presetModel.setCompetition(model);
presetModel.setName(preset.getName());
presetModel.setSwordType(preset.getSword());
presetModel.setShieldType(preset.getShield());
presetModel.setCategories(preset.getCategories());
presetModel.setMandatoryProtection1(preset.getMandatoryProtection1());
presetModel.setMandatoryProtection2(preset.getMandatoryProtection2());
}
// Remove deleted presets
model.getCatPreset().removeIf(presetModel -> toRemoveId.contains(presetModel.getId()));
return Panache.withTransaction(() -> repository.persist(model)
.call(__ -> {
if (!toRemoveId.isEmpty()) {
return catPresetRepository.delete("id IN ?1", toRemoveId);
}
return Uni.createFrom().nullItem();
}));
}
private void copyData(CompetitionData data, CompetitionModel model) { private void copyData(CompetitionData data, CompetitionModel model) {
if (model.getBanMembre() == null) if (model.getBanMembre() == null)
model.setBanMembre(new ArrayList<>()); model.setBanMembre(new ArrayList<>());
@ -301,7 +238,6 @@ public class CompetitionService {
model.setStartRegister(data.getStartRegister()); model.setStartRegister(data.getStartRegister());
model.setEndRegister(data.getEndRegister()); model.setEndRegister(data.getEndRegister());
model.setRegisterMode(data.getRegisterMode()); model.setRegisterMode(data.getRegisterMode());
model.setRequiredWeight(data.getRequiredWeight());
model.setData1(data.getData1()); model.setData1(data.getData1());
model.setData2(data.getData2()); model.setData2(data.getData2());
model.setData3(data.getData3()); model.setData3(data.getData3());
@ -315,18 +251,11 @@ public class CompetitionService {
Uni<List<SimpleRegisterComb>> uni = Mutiny.fetch(c.getInsc()) Uni<List<SimpleRegisterComb>> uni = Mutiny.fetch(c.getInsc())
.onItem().transformToMulti(Multi.createFrom()::iterable) .onItem().transformToMulti(Multi.createFrom()::iterable)
.onItem().call(combModel -> Mutiny.fetch(combModel.getMembre().getLicences())) .onItem().call(combModel -> Mutiny.fetch(combModel.getMembre().getLicences()))
.onItem().call(combModel -> Mutiny.fetch(combModel.getCategoriesInscrites())) .map(cm -> SimpleRegisterComb.fromModel(cm, cm.getMembre().getLicences()))
.map(cm -> SimpleRegisterComb.fromModel(cm, cm.getMembre().getLicences())
.setCategorieInscrite(cm.getCategoriesInscrites()))
.collect().asList(); .collect().asList();
return uni return uni
.call(l -> Mutiny.fetch(c.getGuests()) .call(l -> Mutiny.fetch(c.getGuests())
.onItem().transformToMulti(Multi.createFrom()::iterable) .map(guest -> guest.stream().map(SimpleRegisterComb::fromModel).toList())
.filter(g -> !g.isTeam())
.onItem().call(guest -> Mutiny.fetch(guest.getCategoriesInscrites()))
.map(guest -> SimpleRegisterComb.fromModel(guest)
.setCategorieInscrite(guest.getCategoriesInscrites()))
.collect().asList()
.invoke(l::addAll)); .invoke(l::addAll));
}); });
@ -341,23 +270,18 @@ public class CompetitionService {
model.getClub())) model.getClub()))
.onItem().transformToMulti(Multi.createFrom()::iterable) .onItem().transformToMulti(Multi.createFrom()::iterable)
.onItem().call(combModel -> Mutiny.fetch(combModel.getMembre().getLicences())) .onItem().call(combModel -> Mutiny.fetch(combModel.getMembre().getLicences()))
.onItem().call(combModel -> Mutiny.fetch(combModel.getCategoriesInscrites())) .map(combModel -> SimpleRegisterComb.fromModel(combModel, combModel.getMembre().getLicences()))
.map(combModel -> SimpleRegisterComb.fromModel(combModel, combModel.getMembre().getLicences())
.setCategorieInscrite(combModel.getCategoriesInscrites()))
.collect().asList(); .collect().asList();
return membreService.getByAccountId(securityCtx.getSubject()) return membreService.getByAccountId(securityCtx.getSubject())
.chain(model -> registerRepository.find("competition.id = ?1 AND membre = ?2", id, model).firstResult() .chain(model -> registerRepository.find("competition.id = ?1 AND membre = ?2", id, model).firstResult()
.call(rm -> rm == null ? Uni.createFrom().voidItem() : .map(rm -> rm == null ? List.of() : List.of(SimpleRegisterComb.fromModel(rm, List.of()))));
Mutiny.fetch(rm.getCategoriesInscrites()))
.map(rm -> rm == null ? List.of() : List.of(SimpleRegisterComb.fromModel(rm, List.of())
.setCategorieInscrite(rm.getCategoriesInscrites()))));
} }
public Uni<SimpleRegisterComb> addRegisterComb(SecurityCtx securityCtx, Long id, RegisterRequestData data, public Uni<SimpleRegisterComb> addRegisterComb(SecurityCtx securityCtx, Long id, RegisterRequestData data,
String source) { String source) {
if ("admin".equals(source)) if ("admin".equals(source))
if (data.getLicence() == null || data.getLicence() != -1) { // not a guest if (data.getLicence() != -1) { // not a guest
return permService.hasEditPerm(securityCtx, id) return permService.hasEditPerm(securityCtx, id)
.chain(c -> findComb(data.getLicence(), data.getFname(), data.getLname()) .chain(c -> findComb(data.getLicence(), data.getFname(), data.getLname())
.call(combModel -> Mutiny.fetch(combModel.getLicences())) .call(combModel -> Mutiny.fetch(combModel.getLicences()))
@ -367,9 +291,8 @@ public class CompetitionService {
c.getBanMembre().remove(combModel.getId()); c.getBanMembre().remove(combModel.getId());
return Panache.withTransaction(() -> repository.persist(c)); return Panache.withTransaction(() -> repository.persist(c));
}) })
.chain(combModel -> updateRegister(data, c, combModel, true, false))) .chain(combModel -> updateRegister(data, c, combModel, true)))
.map(r -> SimpleRegisterComb.fromModel(r, r.getMembre().getLicences()) .map(r -> SimpleRegisterComb.fromModel(r, r.getMembre().getLicences()));
.setCategorieInscrite(r.getCategoriesInscrites()));
} else { } else {
return permService.hasEditPerm(securityCtx, id) return permService.hasEditPerm(securityCtx, id)
.chain(c -> competitionGuestRepository.findById(data.getId() * -1) .chain(c -> competitionGuestRepository.findById(data.getId() * -1)
@ -380,35 +303,21 @@ public class CompetitionService {
model.setCompetition(c); model.setCompetition(c);
return model; return model;
})) }))
.invoke(model -> { .chain(model -> {
model.setFname(data.getFname()); model.setFname(data.getFname());
if (data.getLname().equals("__team"))
model.setLname("_team");
else
model.setLname(data.getLname()); model.setLname(data.getLname());
model.setGenre(data.getGenre()); model.setGenre(data.getGenre());
model.setClub(data.getClub()); model.setClub(data.getClub());
model.setCountry(data.getCountry()); model.setCountry(data.getCountry());
model.setWeightReal(data.getWeightReal());
model.setCategorie(data.getCategorie());
if (model.getCompetition().getRequiredWeight().contains(model.getCategorie()))
model.setWeight(data.getWeight()); model.setWeight(data.getWeight());
}) model.setCategorie(data.getCategorie());
.call(g -> Mutiny.fetch(g.getCategoriesInscrites()))
.call(g -> catPresetRepository.list("competition = ?1 AND id IN ?2", g.getCompetition(), return Panache.withTransaction(() -> competitionGuestRepository.persist(model))
data.getCategoriesInscrites())
.invoke(cats -> {
g.getCategoriesInscrites().clear();
g.getCategoriesInscrites().addAll(cats);
g.getCategoriesInscrites()
.removeIf(cat -> cat.getCategories().stream()
.noneMatch(e -> e.getCategorie().equals(g.getCategorie())));
}))
.chain(model -> Panache.withTransaction(() -> competitionGuestRepository.persist(model))
.call(r -> model.getCompetition().getSystem() == CompetitionSystem.INTERNAL ? .call(r -> model.getCompetition().getSystem() == CompetitionSystem.INTERNAL ?
sRegister.sendRegister(model.getCompetition().getUuid(), sRegister.sendRegister(model.getCompetition().getUuid(),
r) : Uni.createFrom().voidItem())) r) : Uni.createFrom().voidItem());
.map(g -> SimpleRegisterComb.fromModel(g).setCategorieInscrite(g.getCategoriesInscrites())); })
.map(SimpleRegisterComb::fromModel);
} }
if ("club".equals(source)) if ("club".equals(source))
return repository.findById(id) return repository.findById(id)
@ -417,7 +326,7 @@ public class CompetitionService {
|| !securityCtx.isClubAdmin()) || !securityCtx.isClubAdmin())
throw new DForbiddenException(); throw new DForbiddenException();
if (new Date().before(cm.getStartRegister()) || new Date().after(cm.getEndRegister())) if (new Date().before(cm.getStartRegister()) || new Date().after(cm.getEndRegister()))
throw new DBadRequestException(trad.t("inscription.fermee")); throw new DBadRequestException("Inscription fermée");
})) }))
.chain(c -> findComb(data.getLicence(), data.getFname(), data.getLname()) .chain(c -> findComb(data.getLicence(), data.getFname(), data.getLname())
.call(combModel -> Mutiny.fetch(combModel.getLicences())) .call(combModel -> Mutiny.fetch(combModel.getLicences()))
@ -425,118 +334,39 @@ public class CompetitionService {
if (!securityCtx.isInClubGroup(model.getClub().getId())) if (!securityCtx.isInClubGroup(model.getClub().getId()))
throw new DForbiddenException(); throw new DForbiddenException();
if (c.getBanMembre().contains(model.getId())) if (c.getBanMembre().contains(model.getId()))
throw new DForbiddenException(trad.t("insc.err1")); throw new DForbiddenException(
"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, false))) .chain(combModel -> updateRegister(data, c, combModel, false)))
.map(r -> SimpleRegisterComb.fromModel(r, r.getMembre().getLicences()) .map(r -> SimpleRegisterComb.fromModel(r, r.getMembre().getLicences()));
.setCategorieInscrite(r.getCategoriesInscrites()));
return repository.findById(id) return repository.findById(id)
.invoke(Unchecked.consumer(cm -> { .invoke(Unchecked.consumer(cm -> {
if (cm.getRegisterMode() != RegisterMode.FREE) if (cm.getRegisterMode() != RegisterMode.FREE)
throw new DForbiddenException(); throw new DForbiddenException();
if (new Date().before(cm.getStartRegister()) || new Date().after(cm.getEndRegister())) if (new Date().before(cm.getStartRegister()) || new Date().after(cm.getEndRegister()))
throw new DBadRequestException(trad.t("inscription.fermee")); throw new DBadRequestException("Inscription fermée");
})) }))
.chain(c -> membreService.getByAccountId(securityCtx.getSubject()) .chain(c -> membreService.getByAccountId(securityCtx.getSubject())
.invoke(Unchecked.consumer(model -> { .invoke(Unchecked.consumer(model -> {
if (c.getBanMembre().contains(model.getId())) if (c.getBanMembre().contains(model.getId()))
throw new DForbiddenException(trad.t("insc.err2")); throw new DForbiddenException(
"Vous n'avez pas le droit de vous inscrire (par décision de l'administrateur de la compétition)");
})) }))
.chain(combModel -> updateRegister(data, c, combModel, false, false))) .chain(combModel -> updateRegister(data, c, combModel, false)))
.map(r -> SimpleRegisterComb.fromModel(r, List.of()).setCategorieInscrite(r.getCategoriesInscrites())); .map(r -> SimpleRegisterComb.fromModel(r, List.of()));
}
public Uni<List<SimpleRegisterComb>> addRegistersComb(SecurityCtx securityCtx, Long id,
List<RegisterRequestData> datas,
String source) {
if (!"admin".equals(source))
return Uni.createFrom().failure(new DForbiddenException());
return Multi.createFrom().iterable(datas).onItem().transformToUni(data ->
makeImportUpdate(securityCtx, id, data).onFailure().recoverWithItem(t -> {
SimpleRegisterComb errorComb = new SimpleRegisterComb();
errorComb.setLicence(-42);
errorComb.setFname("ERROR");
errorComb.setLname(t.getMessage());
return errorComb;
})).concatenate().collect().asList();
}
private Uni<SimpleRegisterComb> makeImportUpdate(SecurityCtx securityCtx, Long id, RegisterRequestData data) {
if (data.getLicence() == null || 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, true)))
.map(r -> SimpleRegisterComb.fromModel(r, r.getMembre().getLicences())
.setCategorieInscrite(r.getCategoriesInscrites()));
} else {
return permService.hasEditPerm(securityCtx, id)
.chain(c -> findGuestOrInit(data.getFname(), data.getLname(), c))
.invoke(Unchecked.consumer(model -> {
if (data.getCategorie() == null)
throw new DBadRequestException(trad.t("categorie.requise"));
model.setCategorie(data.getCategorie());
if (data.getGenre() == null) {
if (model.getGenre() == null)
data.setGenre(Genre.NA);
} else
model.setGenre(data.getGenre());
if (data.getClub() == null) {
if (model.getClub() == null)
data.setClub("");
} else
model.setClub(data.getClub());
if (data.getCountry() == null) {
if (model.getCountry() == null)
data.setCountry("FR");
} else
model.setCountry(data.getCountry());
if (model.getCompetition().getRequiredWeight().contains(model.getCategorie())) {
if (data.getCountry() != null)
model.setWeight(data.getWeight());
}
}))
.call(g -> Mutiny.fetch(g.getCategoriesInscrites()))
.call(g -> catPresetRepository.list("competition = ?1 AND id IN ?2", g.getCompetition(),
data.getCategoriesInscrites())
.invoke(cats -> {
g.getCategoriesInscrites().clear();
g.getCategoriesInscrites().addAll(cats);
g.getCategoriesInscrites().removeIf(cat -> cat.getCategories().stream()
.noneMatch(e -> e.getCategorie().equals(g.getCategorie())));
}))
.chain(model -> Panache.withTransaction(() -> competitionGuestRepository.persist(model))
.call(r -> model.getCompetition().getSystem() == CompetitionSystem.INTERNAL ?
sRegister.sendRegister(model.getCompetition().getUuid(),
r) : Uni.createFrom().voidItem()))
.map(g -> SimpleRegisterComb.fromModel(g).setCategorieInscrite(g.getCategoriesInscrites()));
}
} }
private Uni<RegisterModel> updateRegister(RegisterRequestData data, CompetitionModel c, private Uni<RegisterModel> updateRegister(RegisterRequestData data, CompetitionModel c,
MembreModel combModel, boolean admin, boolean append) { MembreModel combModel, boolean admin) {
return registerRepository.find("competition = ?1 AND membre = ?2", c, combModel).firstResult() return registerRepository.find("competition = ?1 AND membre = ?2", c, combModel).firstResult()
.onFailure().recoverWithNull() .onFailure().recoverWithNull()
.map(Unchecked.function(r -> { .map(Unchecked.function(r -> {
if (r != null) { if (r != null) {
if (!admin && r.isLockEdit()) if (!admin && r.isLockEdit())
throw new DForbiddenException(trad.t("insc.err3")); throw new DForbiddenException(
if (data.getOverCategory() != null || !append) "Modification bloquée par l'administrateur de la compétition");
if (data.getOverCategory() == null) r.setWeight(data.getWeight());
r.setOverCategory(0);
else
r.setOverCategory(data.getOverCategory()); r.setOverCategory(data.getOverCategory());
r.setCategorie( r.setCategorie(
(combModel.getBirth_date() == null) ? combModel.getCategorie() : (combModel.getBirth_date() == null) ? combModel.getCategorie() :
@ -545,91 +375,50 @@ public class CompetitionService {
int days = Utils.getDaysBeforeCompetition(c.getDate()); int days = Utils.getDaysBeforeCompetition(c.getDate());
if (days > -7) if (days > -7)
r.setClub(combModel.getClub()); r.setClub(combModel.getClub());
if (c.getRequiredWeight().contains(r.getCategorie2())) if (admin)
if (data.getCountry() != null || !append)
r.setWeight(data.getWeight());
if (admin) {
r.setWeightReal(data.getWeightReal());
r.setLockEdit(data.isLockEdit()); r.setLockEdit(data.isLockEdit());
}
} else { } else {
r = new RegisterModel(c, combModel, data.getWeight(), data.getOverCategory(), r = new RegisterModel(c, combModel, data.getWeight(), data.getOverCategory(),
(combModel.getBirth_date() == null) ? combModel.getCategorie() : (combModel.getBirth_date() == null) ? combModel.getCategorie() :
Utils.getCategoryFormBirthDate(combModel.getBirth_date(), Utils.getCategoryFormBirthDate(combModel.getBirth_date(),
c.getDate()), c.getDate()),
(combModel.getClub() == null) ? null : combModel.getClub()); (combModel.getClub() == null) ? null : combModel.getClub());
if (admin) { if (admin)
r.setWeightReal(data.getWeightReal());
r.setLockEdit(data.isLockEdit()); r.setLockEdit(data.isLockEdit());
} else else
r.setLockEdit(false); r.setLockEdit(false);
} }
if (c.getSystem() == CompetitionSystem.SAFCA) { if (c.getSystem() == CompetitionSystem.SAFCA) {
SReqRegister.sendIfNeed(serverCustom.clients, SReqRegister.sendIfNeed(serverCustom.clients,
new CompetitionData.SimpleRegister(r.getMembre().getId(), new CompetitionData.SimpleRegister(r.getMembre().getId(),
r.getOverCategory(), r.getWeight2(), r.getCategorie(), r.getOverCategory(), r.getWeight(), r.getCategorie(),
(r.getClub() == null) ? null : r.getClub().getId(), (r.getClub() == null) ? null : r.getClub().getId(),
(r.getClub() == null) ? null : r.getClub().getName()), c.getId()); (r.getClub() == null) ? null : r.getClub().getName()), c.getId());
} }
return r; return r;
})) }))
.call(r -> Mutiny.fetch(r.getCategoriesInscrites()).chain(__ ->
catPresetRepository.list("competition = ?1 AND id IN ?2", c, data.getCategoriesInscrites())
.invoke(cats -> {
if (data.isQuick()) {
cats.removeIf(cat -> r.getCategoriesInscrites().stream()
.anyMatch(cp -> cp.equals(cat)));
} else {
r.getCategoriesInscrites().clear();
}
r.getCategoriesInscrites().addAll(cats);
r.getCategoriesInscrites()
.removeIf(cat -> cat.getCategories().stream()
.noneMatch(e -> e.getCategorie().equals(r.getCategorie2())));
})))
.chain(r -> Panache.withTransaction(() -> registerRepository.persist(r))) .chain(r -> Panache.withTransaction(() -> registerRepository.persist(r)))
.call(r -> c.getSystem() == CompetitionSystem.INTERNAL ? .call(r -> c.getSystem() == CompetitionSystem.INTERNAL ?
sRegister.sendRegister(c.getUuid(), r) : Uni.createFrom().voidItem()); sRegister.sendRegister(c.getUuid(), r) : Uni.createFrom().voidItem());
} }
private Uni<CompetitionGuestModel> findGuestOrInit(String fname, String lname, CompetitionModel competition) {
if (fname == null || lname == null)
return Uni.createFrom().failure(new DBadRequestException(trad.t("nom.et.prenom.requis")));
return competitionGuestRepository.find(
"unaccent(lname) ILIKE unaccent(?1) AND unaccent(fname) ILIKE unaccent(?2) AND competition = ?3",
lname, fname, competition).firstResult()
.map(guestModel -> {
if (guestModel == null) {
CompetitionGuestModel model = new CompetitionGuestModel();
model.setFname(fname);
if (lname.equals("__team"))
model.setLname("_team");
else
model.setLname(lname);
model.setCompetition(competition);
return model;
}
return guestModel;
});
}
private Uni<MembreModel> findComb(Long licence, String fname, String lname) { 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() return combRepository.find("licence = ?1", licence).firstResult()
.invoke(Unchecked.consumer(combModel -> { .invoke(Unchecked.consumer(combModel -> {
if (combModel == null) if (combModel == null)
throw new DForbiddenException(String.format(trad.t("licence.non.trouve"), licence)); throw new DForbiddenException("Licence " + licence + " non trouvé");
})); }));
} else { } else {
if (fname == null || lname == null) if (fname == null || lname == null)
return Uni.createFrom().failure(new DBadRequestException(trad.t("nom.et.prenom.requis"))); return Uni.createFrom().failure(new DBadRequestException("Nom et prénom requis"));
return combRepository.find("unaccent(lname) ILIKE unaccent(?1) AND unaccent(fname) ILIKE unaccent(?2)", return combRepository.find("unaccent(lname) ILIKE unaccent(?1) AND unaccent(fname) ILIKE unaccent(?2)",
lname, lname,
fname).firstResult() fname).firstResult()
.invoke(Unchecked.consumer(combModel -> { .invoke(Unchecked.consumer(combModel -> {
if (combModel == null) if (combModel == null)
throw new DForbiddenException(String.format(trad.t("combattant.non.trouve"), fname, lname)); throw new DForbiddenException("Combattant " + fname + " " + lname + " non trouvé");
})); }));
} }
} }
@ -656,13 +445,12 @@ public class CompetitionService {
|| !securityCtx.isClubAdmin()) || !securityCtx.isClubAdmin())
throw new DForbiddenException(); throw new DForbiddenException();
if (new Date().before(cm.getStartRegister()) || new Date().after(cm.getEndRegister())) if (new Date().before(cm.getStartRegister()) || new Date().after(cm.getEndRegister()))
throw new DBadRequestException(trad.t("inscription.fermee")); throw new DBadRequestException("Inscription fermée");
})) }))
.call(cm -> membreService.getById(combId) .call(cm -> membreService.getById(combId)
.invoke(Unchecked.consumer(model -> { .invoke(Unchecked.consumer(model -> {
if (model == null) if (model == null)
throw new DNotFoundException( throw new DNotFoundException("Membre " + combId + " n'existe pas");
String.format(trad.t("le.membre.n.existe.pas"), combId));
if (!securityCtx.isInClubGroup(model.getClub().getId())) if (!securityCtx.isInClubGroup(model.getClub().getId()))
throw new DForbiddenException(); throw new DForbiddenException();
}))) })))
@ -674,7 +462,7 @@ public class CompetitionService {
if (cm.getRegisterMode() != RegisterMode.FREE || !Objects.equals(model.getId(), combId)) if (cm.getRegisterMode() != RegisterMode.FREE || !Objects.equals(model.getId(), combId))
throw new DForbiddenException(); throw new DForbiddenException();
if (new Date().before(cm.getStartRegister()) || new Date().after(cm.getEndRegister())) if (new Date().before(cm.getStartRegister()) || new Date().after(cm.getEndRegister()))
throw new DBadRequestException(trad.t("inscription.fermee")); throw new DBadRequestException("Inscription fermée");
}))) })))
.chain(c -> deleteRegister(combId, c, false)); .chain(c -> deleteRegister(combId, c, false));
} }
@ -682,7 +470,7 @@ public class CompetitionService {
private Uni<Void> deleteRegister(Long combId, CompetitionModel c, boolean admin) { private Uni<Void> deleteRegister(Long combId, CompetitionModel c, boolean admin) {
if (admin && combId < 0) { if (admin && combId < 0) {
return competitionGuestRepository.find("competition = ?1 AND id = ?2", c, combId * -1).firstResult() return competitionGuestRepository.find("competition = ?1 AND id = ?2", c, combId * -1).firstResult()
.onFailure().transform(t -> new DBadRequestException(trad.t("combattant.non.inscrit"))) .onFailure().transform(t -> new DBadRequestException("Combattant non inscrit"))
.call(Unchecked.function( .call(Unchecked.function(
model -> Panache.withTransaction(() -> competitionGuestRepository.delete(model)) model -> Panache.withTransaction(() -> competitionGuestRepository.delete(model))
.call(r -> c.getSystem() == CompetitionSystem.INTERNAL ? .call(r -> c.getSystem() == CompetitionSystem.INTERNAL ?
@ -691,10 +479,10 @@ public class CompetitionService {
.replaceWithVoid(); .replaceWithVoid();
} }
return registerRepository.find("competition = ?1 AND membre.id = ?2", c, combId).firstResult() return registerRepository.find("competition = ?1 AND membre.id = ?2", c, combId).firstResult()
.onFailure().transform(t -> new DBadRequestException(trad.t("combattant.non.inscrit"))) .onFailure().transform(t -> new DBadRequestException("Combattant non inscrit"))
.call(Unchecked.function(registerModel -> { .call(Unchecked.function(registerModel -> {
if (!admin && registerModel.isLockEdit()) if (!admin && registerModel.isLockEdit())
throw new DForbiddenException(trad.t("insc.err3")); 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 ? .call(r -> c.getSystem() == CompetitionSystem.INTERNAL ?
sRegister.sendRegisterRemove(c.getUuid(), combId) : Uni.createFrom().voidItem()); sRegister.sendRegisterRemove(c.getUuid(), combId) : Uni.createFrom().voidItem());
@ -725,64 +513,6 @@ public class CompetitionService {
.call(__ -> cache.invalidate(id)); .call(__ -> cache.invalidate(id));
} }
public Uni<SimpleCompetData> getInternalData(SecurityCtx securityCtx, Long id) {
return permService.hasEditPerm(securityCtx, id)
.invoke(Unchecked.consumer(cm -> {
if (cm.getSystem() != CompetitionSystem.INTERNAL)
throw new DBadRequestException(trad.t("competition.is.not.internal"));
}))
.chain(competitionModel -> {
SimpleCompetData data = SimpleCompetData.fromModel(competitionModel);
return vertx.getOrCreateContext().executeBlocking(() -> {
if (competitionModel.getAdmin() != null)
data.setAdmin(
competitionModel.getAdmin().stream().map(uuid -> keycloakService.getUserById(uuid))
.filter(Optional::isPresent)
.map(user -> user.get().getUsername())
.toList());
if (competitionModel.getTable() != null)
data.setTable(
competitionModel.getTable().stream().map(uuid -> keycloakService.getUserById(uuid))
.filter(Optional::isPresent)
.map(user -> user.get().getUsername())
.toList());
return data;
});
});
}
public Uni<Void> setInternalData(SecurityCtx securityCtx, SimpleCompetData data) {
return permService.hasEditPerm(securityCtx, data.getId())
.invoke(Unchecked.consumer(cm -> {
if (cm.getSystem() != CompetitionSystem.INTERNAL)
throw new DBadRequestException(trad.t("competition.is.not.internal"));
}))
.chain(cm -> vertx.getOrCreateContext().executeBlocking(() -> {
ArrayList<String> admin = new ArrayList<>();
ArrayList<String> table = new ArrayList<>();
for (String username : data.getAdmin()) {
Optional<UserRepresentation> opt = keycloakService.getUser(username);
if (opt.isEmpty())
throw new DBadRequestException(String.format(trad.t("user.not.found"), username));
admin.add(opt.get().getId());
}
for (String username : data.getTable()) {
Optional<UserRepresentation> opt = keycloakService.getUser(username);
if (opt.isEmpty())
throw new DBadRequestException(String.format(trad.t("user.not.found"), username));
table.add(opt.get().getId());
}
cm.setAdmin(admin);
cm.setTable(table);
cm.setConfig(data.getConfigForInternal());
return cm;
}))
.chain(cm -> Panache.withTransaction(() -> repository.persist(cm)))
.replaceWithVoid();
}
public Uni<SimpleCompetData> getSafcaData(SecurityCtx securityCtx, Long id) { public Uni<SimpleCompetData> getSafcaData(SecurityCtx securityCtx, Long id) {
return permService.getSafcaConfig(id) return permService.getSafcaConfig(id)
.call(Unchecked.function(o -> { .call(Unchecked.function(o -> {
@ -819,13 +549,13 @@ public class CompetitionService {
for (String username : data.getAdmin()) { for (String username : data.getAdmin()) {
Optional<UserRepresentation> opt = keycloakService.getUser(username); Optional<UserRepresentation> opt = keycloakService.getUser(username);
if (opt.isEmpty()) if (opt.isEmpty())
throw new DBadRequestException(String.format(trad.t("user.not.found"), username)); throw new DBadRequestException("User " + username + " not found");
admin.add(UUID.fromString(opt.get().getId())); admin.add(UUID.fromString(opt.get().getId()));
} }
for (String username : data.getTable()) { for (String username : data.getTable()) {
Optional<UserRepresentation> opt = keycloakService.getUser(username); Optional<UserRepresentation> opt = keycloakService.getUser(username);
if (opt.isEmpty()) if (opt.isEmpty())
throw new DBadRequestException(String.format(trad.t("user.not.found"), username)); throw new DBadRequestException("User " + username + " not found");
table.add(UUID.fromString(opt.get().getId())); table.add(UUID.fromString(opt.get().getId()));
} }
@ -851,12 +581,6 @@ public class CompetitionService {
.call(__ -> cache.invalidate(data.getId())); .call(__ -> cache.invalidate(data.getId()));
} }
public Uni<List<PresetData>> getPresetsForCompetition(SecurityCtx securityCtx, Long id) {
return permService.hasViewPerm(securityCtx, id)
.chain(cm -> Mutiny.fetch(cm.getCatPreset()))
.map(p -> p.stream().map(PresetData::fromModel).toList());
}
public Uni<Response> unregisterHelloAsso(NotificationData data) { public Uni<Response> unregisterHelloAsso(NotificationData data) {
if (!data.getState().equals("Refunded")) if (!data.getState().equals("Refunded"))
return Uni.createFrom().item(Response.ok().build()); return Uni.createFrom().item(Response.ok().build());
@ -890,8 +614,8 @@ public class CompetitionService {
public Uni<Response> registerHelloAsso(NotificationData data) { public Uni<Response> registerHelloAsso(NotificationData data) {
String organizationSlug = data.getOrganizationSlug(); String organizationSlug = data.getOrganizationSlug();
String formSlug = data.getFormSlug(); String formSlug = data.getFormSlug();
RegisterRequestData req = new RegisterRequestData(null, "", "", null, null, 0, false, new ArrayList<>(), null, RegisterRequestData req = new RegisterRequestData(null, "", "", null, 0, false, null, Categorie.CADET, Genre.NA,
Categorie.CADET, Genre.NA, null, "fr", false); null, "fr");
return repository.find("data1 = ?1 AND data2 = ?2", organizationSlug, formSlug).firstResult() return repository.find("data1 = ?1 AND data2 = ?2", organizationSlug, formSlug).firstResult()
.onFailure().recoverWithNull() .onFailure().recoverWithNull()
@ -925,7 +649,7 @@ public class CompetitionService {
.call(m -> Panache.withTransaction(() -> .call(m -> Panache.withTransaction(() ->
helloAssoRepository.persist( helloAssoRepository.persist(
new HelloAssoRegisterModel(cm, m, data.getId())))) new HelloAssoRegisterModel(cm, m, data.getId()))))
.chain(m -> updateRegister(req, cm, m, true, true))) .chain(m -> updateRegister(req, cm, m, true)))
.onFailure().recoverWithItem(throwable -> { .onFailure().recoverWithItem(throwable -> {
fail.add("%s %s - licence n°%d".formatted(item.getUser().getLastName(), fail.add("%s %s - licence n°%d".formatted(item.getUser().getLastName(),
item.getUser().getFirstName(), optional.get())); item.getUser().getFirstName(), optional.get()));

View File

@ -4,6 +4,7 @@ import fr.titionfire.ffsaf.rest.client.HelloAssoAuthClient;
import fr.titionfire.ffsaf.rest.client.dto.TokenResponse; import fr.titionfire.ffsaf.rest.client.dto.TokenResponse;
import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.eclipse.microprofile.config.inject.ConfigProperty; import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.eclipse.microprofile.rest.client.inject.RestClient; import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
@ -12,6 +13,7 @@ import org.jboss.logging.Logger;
public class HelloAssoTokenService { public class HelloAssoTokenService {
private static final Logger LOG = Logger.getLogger(HelloAssoTokenService.class); private static final Logger LOG = Logger.getLogger(HelloAssoTokenService.class);
@Inject
@RestClient @RestClient
HelloAssoAuthClient authClient; HelloAssoAuthClient authClient;
@ -25,11 +27,6 @@ public class HelloAssoTokenService {
// Récupère un token valide (en le rafraîchissant si nécessaire) // Récupère un token valide (en le rafraîchissant si nécessaire)
public Uni<String> getValidAccessToken() { public Uni<String> getValidAccessToken() {
if (clientId == null || clientSecret == null || clientId.isEmpty() || clientSecret.isEmpty() || clientId.equalsIgnoreCase(
"null") || clientSecret.equalsIgnoreCase("null")) {
LOG.error("Client ID ou Client Secret non configuré pour HelloAsso");
return Uni.createFrom().failure(new IllegalStateException("HelloAsso client credentials not configured"));
}
if (currentToken == null || currentToken.isExpired()) { if (currentToken == null || currentToken.isExpired()) {
return fetchNewToken(clientId, clientSecret); return fetchNewToken(clientId, clientSecret);
} }

View File

@ -156,18 +156,10 @@ public class KeycloakService {
return oldEmail; return oldEmail;
}).call(oldEmail -> oldEmail == null || !enabled_email ? Uni.createFrom().item("") : }).call(oldEmail -> oldEmail == null || !enabled_email ? Uni.createFrom().item("") :
reactiveMailer.send( reactiveMailer.send(
Mail.withHtml(oldEmail, "FFSAF - Changement de votre adresse email", Mail.withText(oldEmail,
String.format(Utils.HTML_HEADER, "FFSAF - Changement de votre adresse email") + "FFSAF - Changement de votre adresse email",
String.format(""" String.format(
<p>Suite à la modification de votre adresse email fournie lors de votre ()inscription à la FFSAF,<br/> """
vous allez recevoir dans les prochaines minutes un email de vérification de votre nouvelle adresse sur celle-ci.</p>
<p>Ancienne adresse email : <span class="highlight">%s</span><br/>Nouvelle adresse email : <span class="highlight">%s</span></p>
<p>Si vous n'avez pas demandé cette modification, veuillez contacter le support à l'adresse <a href="mailto:support@ffsaf.fr">support@ffsaf.fr</a>.</p>
""",
oldEmail, email) +
Utils.HTML_FOOTER
)
.setText(String.format("""
Bonjour, Bonjour,
Suite à la modification de votre adresse email fournie lors de votre ()inscription à la FFSAF, Suite à la modification de votre adresse email fournie lors de votre ()inscription à la FFSAF,
@ -180,8 +172,8 @@ public class KeycloakService {
Cordialement, Cordialement,
L'équipe de la FFSAF L'équipe de la FFSAF
""", oldEmail, email)) """, oldEmail, email)
.setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("support@ffsaf.fr") ).setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("support@ffsaf.fr")
).onFailure().invoke(e -> LOGGER.error("Fail to send email", e))); ).onFailure().invoke(e -> LOGGER.error("Fail to send email", e)));
} }
@ -278,33 +270,13 @@ public class KeycloakService {
.invoke(user -> membreModel.setUserId(user.getId())) .invoke(user -> membreModel.setUserId(user.getId()))
.call(user -> updateRole(user.getId(), List.of("safca_user"), List.of())) .call(user -> updateRole(user.getId(), List.of("safca_user"), List.of()))
.call(user -> enabled_email ? reactiveMailer.send( .call(user -> enabled_email ? reactiveMailer.send(
Mail.withHtml(user.getEmail(), "FFSAF - Creation de votre compte sur l'intranet", Mail.withText(user.getEmail(),
String.format(Utils.HTML_HEADER, "Création de votre compte intranet FFSAF") + "FFSAF - Creation de votre compte sur l'intranet",
String.format( String.format(
"""
<p>Suite &agrave; votre premi&egrave;re inscription <span class="highlight">%s</span> &agrave; la <strong>F&eacute;d&eacute;ration France Soft Armored Fighting (FFSAF)</strong>, votre compte intranet a &eacute;t&eacute; cr&eacute;&eacute;.</p>
<p>Ce compte vous permettra de :</p>
<ul>
<li>Consulter vos informations personnelles,</li>
<li>Vous inscrire aux comp&eacute;titions (bient&ocirc;t disponible),</li>
<li>Consulter les r&eacute;sultats des comp&eacute;titions.</li>
</ul>
<p>L&rsquo;intranet est accessible &agrave; l&rsquo;adresse suivante :</p>
<p style="text-align: center;"><a href="https://intra.ffsaf.fr" class="button">Acc&eacute;der &agrave; l&apos;intranet</a></p>
<p>Votre nom d&rsquo;utilisateur est : <span class="highlight">%s</span></p>
<p>Pour d&eacute;finir votre mot de passe, rendez-vous sur l&rsquo;intranet : <strong>Connexion &gt; Mot de passe oubli&eacute; ?</strong></p>
<p>Si vous n&rsquo;avez pas demand&eacute; cette inscription, veuillez contacter le support &agrave; l&rsquo;adresse : <a href="mailto:support@ffsaf.fr">support@ffsaf.fr</a>.</p>
<p class="footer">(Pas de panique, nous ne vous enverrons pas de message autre que ceux concernant votre compte.)</p>
""",
membreModel.getRole() == RoleAsso.MEMBRE ? "par votre club (" + membreModel.getClub()
.getName() + ") " : "", user.getUsername()) +
Utils.HTML_FOOTER
)
.setText(String.format(
""" """
Bonjour, Bonjour,
Suite à votre première inscription % la Fédération France Soft Armored Fighting (FFSAF), votre compte intranet a été créé. Suite à votre première inscription % 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. 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 L'intranet est accessible à l'adresse suivante : https://intra.ffsaf.fr
@ -319,8 +291,8 @@ public class KeycloakService {
L'équipe de la FFSAF L'équipe de la FFSAF
""", """,
membreModel.getRole() == RoleAsso.MEMBRE ? "par votre club (" + membreModel.getClub() membreModel.getRole() == RoleAsso.MEMBRE ? "par votre club (" + membreModel.getClub()
.getName() + ") " : "", user.getUsername())) .getName() + ") " : "", user.getUsername())
.setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("support@ffsaf.fr") ).setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("support@ffsaf.fr")
) : Uni.createFrom().nullItem()) ) : Uni.createFrom().nullItem())
.call(user -> membreService.setUserId(membreModel.getId(), user.getId())) .call(user -> membreService.setUserId(membreModel.getId(), user.getId()))
.call(user -> setClubGroupMembre(membreModel, membreModel.getClub())); .call(user -> setClubGroupMembre(membreModel, membreModel.getClub()));
@ -377,19 +349,11 @@ public class KeycloakService {
public Optional<UserRepresentation> getUser(UUID userId) { public Optional<UserRepresentation> getUser(UUID userId) {
return getUserById(userId.toString()); UserResource user = keycloak.realm(realm).users().get(userId.toString());
}
public Optional<UserRepresentation> getUserById(String userId) {
try {
UserResource user = keycloak.realm(realm).users().get(userId);
if (user == null) if (user == null)
return Optional.empty(); return Optional.empty();
else else
return Optional.of(user.toRepresentation()); return Optional.of(user.toRepresentation());
} catch (Exception e) {
return Optional.empty();
}
} }
private String makeLogin(MembreModel model) { private String makeLogin(MembreModel model) {

View File

@ -47,9 +47,6 @@ public class LicenceService {
@Inject @Inject
CheckoutService checkoutService; CheckoutService checkoutService;
@Inject
TradService trad;
public Uni<List<LicenceModel>> getLicence(long id, Consumer<MembreModel> checkPerm) { public Uni<List<LicenceModel>> getLicence(long id, Consumer<MembreModel> checkPerm) {
return combRepository.findById(id).invoke(checkPerm) return combRepository.findById(id).invoke(checkPerm)
.chain(combRepository -> Mutiny.fetch(combRepository.getLicences())); .chain(combRepository -> Mutiny.fetch(combRepository.getLicences()));
@ -87,26 +84,6 @@ public class LicenceService {
)); ));
} }
public Uni<?> validePaymentLicences(List<Long> ids) {
Uni<String> uni = Uni.createFrom().nullItem();
for (Long id : ids) {
uni = uni.chain(__ -> repository.find("membre.id = ?1 AND saison = ?2", id, Utils.getSaison()).firstResult()
.chain(model -> {
if (!model.isPay())
ls.logUpdate("payment (admin) de la licence", model);
return validatePayLicences(model);
}))
.map(__ -> "OK");
}
return uni.call(__ -> ls.append());
}
protected Uni<LicenceModel> validatePayLicences(LicenceModel model) {
model.setPay(true);
return Panache.withTransaction(() -> repository.persist(model));
}
public Uni<LicenceModel> setLicence(long id, LicenceForm form) { public Uni<LicenceModel> setLicence(long id, LicenceForm form) {
if (form.getId() == -1) { if (form.getId() == -1) {
return combRepository.findById(id).chain(membreModel -> { return combRepository.findById(id).chain(membreModel -> {
@ -144,7 +121,7 @@ public class LicenceService {
} }
private Function<MembreModel, Uni<?>> genLicenceNumberAndAccountIfNeed() { private Function<MembreModel, Uni<?>> genLicenceNumberAndAccountIfNeed() {
return membreModel -> ((membreModel.getLicence() == null || membreModel.getLicence() <= 0) ? return membreModel -> ((membreModel.getLicence() <= 0) ?
sequenceRepository.getNextValueInTransaction(SequenceType.Licence) sequenceRepository.getNextValueInTransaction(SequenceType.Licence)
.invoke(i -> membreModel.setLicence(Math.toIntExact(i))) .invoke(i -> membreModel.setLicence(Math.toIntExact(i)))
.chain(() -> combRepository.persist(membreModel)) .chain(() -> combRepository.persist(membreModel))
@ -160,7 +137,7 @@ public class LicenceService {
return repository.list("membre.id IN ?1 AND saison = ?2 AND pay = FALSE", ids, Utils.getSaison()) return repository.list("membre.id IN ?1 AND saison = ?2 AND pay = FALSE", ids, Utils.getSaison())
.invoke(Unchecked.consumer(models -> { .invoke(Unchecked.consumer(models -> {
if (models.size() != ids.size()) if (models.size() != ids.size())
throw new DBadRequestException(trad.t("erreur.lors.de.la.selection.des.membres")); throw new DBadRequestException("Erreur lors de la sélection des membres");
})) }))
.call(models -> { .call(models -> {
Uni<?> uni = Uni.createFrom().nullItem(); Uni<?> uni = Uni.createFrom().nullItem();
@ -177,10 +154,10 @@ public class LicenceService {
.call(__ -> checkoutService.canDeleteLicence(id) .call(__ -> checkoutService.canDeleteLicence(id)
.invoke(Unchecked.consumer(b -> { .invoke(Unchecked.consumer(b -> {
if (!b) throw new DBadRequestException( if (!b) throw new DBadRequestException(
trad.t("licence.rm.err1")); "Impossible de supprimer une licence pour laquelle un paiement est en cours");
}))) })))
.call(model -> ls.logADelete(model)) .call(model -> ls.logADelete(model))
.chain(model -> Panache.withTransaction(() -> repository.delete(model))); .chain(model -> repository.delete(model));
} }
public Uni<LicenceModel> askLicence(long id, LicenceForm form, Consumer<MembreModel> checkPerm) { public Uni<LicenceModel> askLicence(long id, LicenceForm form, Consumer<MembreModel> checkPerm) {
@ -189,7 +166,7 @@ public class LicenceService {
return repository.find("saison = ?1 AND membre = ?2", Utils.getSaison(), membreModel).count() return repository.find("saison = ?1 AND membre = ?2", Utils.getSaison(), membreModel).count()
.invoke(Unchecked.consumer(count -> { .invoke(Unchecked.consumer(count -> {
if (count > 0) if (count > 0)
throw new DBadRequestException(trad.t("licence.deja.demandee")); throw new DBadRequestException("Licence déjà demandée");
})).chain(__ -> combRepository.findById(id).chain(membreModel2 -> { })).chain(__ -> combRepository.findById(id).chain(membreModel2 -> {
LicenceModel model = new LicenceModel(); LicenceModel model = new LicenceModel();
model.setClub_id((membreModel2.getClub() == null) ? null : membreModel2.getClub().getId()); model.setClub_id((membreModel2.getClub() == null) ? null : membreModel2.getClub().getId());
@ -218,13 +195,13 @@ public class LicenceService {
.call(__ -> checkoutService.canDeleteLicence(id) .call(__ -> checkoutService.canDeleteLicence(id)
.invoke(Unchecked.consumer(b -> { .invoke(Unchecked.consumer(b -> {
if (!b) throw new DBadRequestException( if (!b) throw new DBadRequestException(
trad.t("licence.rm.err1")); "Impossible de supprimer une licence pour laquelle un paiement est en cours");
}))) })))
.invoke(Unchecked.consumer(licenceModel -> { .invoke(Unchecked.consumer(licenceModel -> {
if (licenceModel.isValidate()) if (licenceModel.isValidate())
throw new DBadRequestException(trad.t("impossible.de.supprimer.une.licence.deja.validee")); throw new DBadRequestException("Impossible de supprimer une licence déjà validée");
if (licenceModel.isPay()) if (licenceModel.isPay())
throw new DBadRequestException(trad.t("impossible.de.supprimer.une.licence.deja.payee")); throw new DBadRequestException("Impossible de supprimer une licence déjà payée");
})) }))
.call(model -> ls.logADelete(model)) .call(model -> ls.logADelete(model))
.chain(__ -> Panache.withTransaction(() -> repository.deleteById(id))); .chain(__ -> Panache.withTransaction(() -> repository.deleteById(id)));

View File

@ -58,8 +58,6 @@ public class LoggerService {
} }
public Uni<?> append() { public Uni<?> append() {
if (buffer.isEmpty())
return Uni.createFrom().voidItem();
return Panache.withTransaction(() -> repository.persist(buffer)) return Panache.withTransaction(() -> repository.persist(buffer))
.invoke(__ -> buffer.clear()); .invoke(__ -> buffer.clear());
} }

View File

@ -7,12 +7,14 @@ import fr.titionfire.ffsaf.data.repository.*;
import fr.titionfire.ffsaf.net2.ServerCustom; import fr.titionfire.ffsaf.net2.ServerCustom;
import fr.titionfire.ffsaf.net2.data.SimpleCombModel; import fr.titionfire.ffsaf.net2.data.SimpleCombModel;
import fr.titionfire.ffsaf.net2.request.SReqComb; import fr.titionfire.ffsaf.net2.request.SReqComb;
import fr.titionfire.ffsaf.rest.data.*; import fr.titionfire.ffsaf.rest.data.MeData;
import fr.titionfire.ffsaf.rest.data.SimpleLicence;
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.DBadRequestException;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException; import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.rest.exception.DInternalError; import fr.titionfire.ffsaf.rest.exception.DInternalError;
import fr.titionfire.ffsaf.rest.from.FullMemberForm; import fr.titionfire.ffsaf.rest.from.FullMemberForm;
import fr.titionfire.ffsaf.rest.from.UserSettingForm;
import fr.titionfire.ffsaf.utils.*; import fr.titionfire.ffsaf.utils.*;
import io.quarkus.hibernate.reactive.panache.Panache; import io.quarkus.hibernate.reactive.panache.Panache;
import io.quarkus.hibernate.reactive.panache.PanacheQuery; import io.quarkus.hibernate.reactive.panache.PanacheQuery;
@ -62,9 +64,6 @@ public class MembreService {
@Inject @Inject
LoggerService ls; LoggerService ls;
@Inject
TradService trad;
public SimpleCombModel find(int licence, String np) throws Throwable { public SimpleCombModel find(int licence, String np) throws Throwable {
return VertxContextSupport.subscribeAndAwait(() -> Panache.withTransaction(() -> return VertxContextSupport.subscribeAndAwait(() -> Panache.withTransaction(() ->
repository.find( repository.find(
@ -126,21 +125,8 @@ public class MembreService {
return sort; return sort;
} }
public Uni<PageResult<SimpleMembre>> search(int limit, int page, String search, int licenceRequest, int payState, public Uni<PageResult<SimpleMembre>> searchAdmin(int limit, int page, String search, String club,
String order, String categorie, Boolean archive, String subject) { int licenceRequest, int payState, String order, String categorie) {
return repository.find("userId = ?1", subject).firstResult()
.invoke(Unchecked.consumer(membreModel -> {
if (membreModel == null || membreModel.getClub() == null)
throw new DForbiddenException();
}))
.chain(membreModel ->
searchAdmin(limit, page, search, membreModel.getClub(), licenceRequest, payState, order,
categorie, archive));
}
public Uni<PageResult<SimpleMembre>> searchAdmin(int limit, int page, String search, Object club,
int licenceRequest, int payState, String order, String categorie,
Boolean archive) {
if (search == null) if (search == null)
search = ""; search = "";
search = "%" + search.replaceAll(" ", "% %") + "%"; search = "%" + search.replaceAll(" ", "% %") + "%";
@ -151,47 +137,77 @@ public class MembreService {
else else
categorieFilter = "categorie = " + Categorie.valueOf(categorie).ordinal(); categorieFilter = "categorie = " + Categorie.valueOf(categorie).ordinal();
String archiveFilter; String finalSearch = search;
if (archive == null || archive) Uni<List<LicenceModel>> baseUni = getLicenceListe(licenceRequest, payState);
archiveFilter = "True";
else
archiveFilter = String.format(
"EXISTS (SELECT 1 FROM LicenceModel l WHERE l.membre.id = m.id AND l.saison >= %s)",
Utils.getSaison() - 1);
String clubFilter = "(TRUE OR ?3 = ?3)";
if (club != null) {
if (club instanceof String club_) {
if (!club_.isBlank()) {
if (club_.equals("null"))
clubFilter = "club IS NULL AND ?3 = ?3";
else
clubFilter = "LOWER(club.name) LIKE LOWER(?3)";
}
} else if (club instanceof ClubModel)
clubFilter = "club = ?3";
}
String queryStr = String.format(
"SELECT m FROM MembreModel m WHERE id %s ?2 AND %s AND (%s) AND %s AND %s",
(licenceRequest == 0 || licenceRequest == 4) ? "NOT IN" : "IN", clubFilter, FIND_NAME_REQUEST,
categorieFilter,
archiveFilter);
Sort sort = getSort(order); Sort sort = getSort(order);
if (sort == null) if (sort == null)
return Uni.createFrom().failure(new DInternalError(trad.t("erreur.lors.calcul.du.trie"))); return Uni.createFrom().failure(new DInternalError("Erreur lors calcul du trie"));
String finalSearch = search; return baseUni
return getLicenceListe(licenceRequest, payState)
.map(l -> l.stream().map(l2 -> l2.getMembre().getId()).toList()) .map(l -> l.stream().map(l2 -> l2.getMembre().getId()).toList())
.chain(ids -> { .chain(ids -> {
PanacheQuery<MembreModel> query; PanacheQuery<MembreModel> query;
query = repository.find(queryStr, sort, finalSearch, ids, club).page(Page.ofSize(limit));
String idf = ((licenceRequest == 0 || licenceRequest == 4) ? "NOT IN" : "IN");
if (club == null || club.isBlank()) {
query = repository.find(
"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 + ") 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 + ") AND " + categorieFilter,
sort, finalSearch, club, ids)
.page(Page.ofSize(limit));
}
}
return getPageResult(query, limit, page); return getPageResult(query, limit, page);
}); });
} }
public Uni<PageResult<SimpleMembre>> search(int limit, int page, String search, int licenceRequest, int payState,
String order, String categorie, String subject) {
if (search == null)
search = "";
search = "%" + search.replaceAll(" ", "% %") + "%";
String finalSearch = search;
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 -> {
String idf = ((licenceRequest == 0 || licenceRequest == 4) ? "NOT IN" : "IN");
return repository.find("userId = ?1", subject).firstResult()
.chain(membreModel -> {
PanacheQuery<MembreModel> query = repository.find(
"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);
});
});
}
private Uni<PageResult<SimpleMembre>> getPageResult(PanacheQuery<MembreModel> query, int limit, int page) { private Uni<PageResult<SimpleMembre>> getPageResult(PanacheQuery<MembreModel> query, int limit, int page) {
return Uni.createFrom().item(new PageResult<SimpleMembre>()) return Uni.createFrom().item(new PageResult<SimpleMembre>())
.invoke(result -> result.setPage(page)) .invoke(result -> result.setPage(page))
@ -199,7 +215,7 @@ public class MembreService {
.call(result -> query.count().invoke(result::setResult_count)) .call(result -> query.count().invoke(result::setResult_count))
.call(result -> query.pageCount() .call(result -> query.pageCount()
.invoke(Unchecked.consumer(pages -> { .invoke(Unchecked.consumer(pages -> {
if (page > pages) throw new DBadRequestException(trad.t("page.out.of.range")); if (page > pages) throw new DBadRequestException("Page out of range");
})) }))
.invoke(result::setPage_count)) .invoke(result::setPage_count))
.call(result -> query.page(Page.of(page, limit)).list() .call(result -> query.page(Page.of(page, limit)).list()
@ -244,8 +260,8 @@ public class MembreService {
for (MembreModel membreModel : 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); LOGGER.info("Similar membres found: " + membreModel);
throw new DForbiddenException(String.format(trad.t("le.membre.appartient.pas.a.votre.club"), throw new DForbiddenException(
membreModel.getLicence())); "Le membre n°" + membreModel.getLicence() + " n'appartient pas à votre club");
} }
} }
Uni<Void> uniResult = Uni.createFrom().voidItem(); Uni<Void> uniResult = Uni.createFrom().voidItem();
@ -271,18 +287,14 @@ public class MembreService {
if (model.getEmail() != null && !model.getEmail().isBlank()) { if (model.getEmail() != null && !model.getEmail().isBlank()) {
if (model.getLicence() != null && !model.getLicence().equals(dataIn.getLicence())) { if (model.getLicence() != null && !model.getLicence().equals(dataIn.getLicence())) {
LOGGER.info("Similar membres found: " + model); LOGGER.info("Similar membres found: " + model);
throw new DBadRequestException( throw new DBadRequestException("Email '" + model.getEmail() + "' déja utiliser");
String.format(trad.t("email.deja.utilise.par"), model.getEmail(),
model.getFname(), model.getLname()));
} }
if (StringSimilarity.similarity(model.getLname().toUpperCase(), if (StringSimilarity.similarity(model.getLname().toUpperCase(),
dataIn.getNom().toUpperCase()) > 3 || StringSimilarity.similarity( dataIn.getNom().toUpperCase()) > 3 || StringSimilarity.similarity(
model.getFname().toUpperCase(), dataIn.getPrenom().toUpperCase()) > 3) { model.getFname().toUpperCase(), dataIn.getPrenom().toUpperCase()) > 3) {
LOGGER.info("Similar membres found: " + model); LOGGER.info("Similar membres found: " + model);
throw new DBadRequestException( throw new DBadRequestException("Email '" + model.getEmail() + "' déja utiliser");
String.format(trad.t("email.deja.utilise.par"), model.getEmail(),
model.getFname(), model.getLname()));
} }
} }
@ -293,8 +305,7 @@ public class MembreService {
model.getFname().toUpperCase(), dataIn.getPrenom().toUpperCase()) > 3)) { model.getFname().toUpperCase(), dataIn.getPrenom().toUpperCase()) > 3)) {
LOGGER.info("Similar membres found: " + model); LOGGER.info("Similar membres found: " + model);
throw new DBadRequestException( throw new DBadRequestException(
String.format(trad.t("try.edit.licence"), model.getLicence(), model.getFname(), "Pour enregistrer un nouveau membre, veuillez laisser le champ licence vide.");
model.getFname()));
} }
ls.logChange("Nom", model.getLname(), dataIn.getNom().toUpperCase(), model); ls.logChange("Nom", model.getLname(), dataIn.getNom().toUpperCase(), model);
@ -302,7 +313,8 @@ public class MembreService {
dataIn.getPrenom().toUpperCase().charAt(0) + dataIn.getPrenom().substring(1), model); dataIn.getPrenom().toUpperCase().charAt(0) + dataIn.getPrenom().substring(1), model);
model.setLname(dataIn.getNom().toUpperCase()); model.setLname(dataIn.getNom().toUpperCase());
model.setFname(Utils.formatPrenom(dataIn.getPrenom())); model.setFname(dataIn.getPrenom().toUpperCase().charAt(0) + dataIn.getPrenom().substring(1));
if (dataIn.getEmail() != null && !dataIn.getEmail().isBlank()) { if (dataIn.getEmail() != null && !dataIn.getEmail().isBlank()) {
ls.logChange("Email", model.getEmail(), dataIn.getEmail(), model); ls.logChange("Email", model.getEmail(), dataIn.getEmail(), model);
@ -368,7 +380,7 @@ public class MembreService {
.call(__ -> repository.count("email LIKE ?1 AND id != ?2", membre.getEmail(), id) .call(__ -> repository.count("email LIKE ?1 AND id != ?2", membre.getEmail(), id)
.invoke(Unchecked.consumer(c -> { .invoke(Unchecked.consumer(c -> {
if (c > 0 && !membre.getEmail().isBlank()) if (c > 0 && !membre.getEmail().isBlank())
throw new DBadRequestException(trad.t("email.deja.utilise")); throw new DBadRequestException("Email déjà utiliser");
}))) })))
.chain(membreModel -> clubRepository.findById(membre.getClub()) .chain(membreModel -> clubRepository.findById(membre.getClub())
.map(club -> new Pair<>(membreModel, club))) .map(club -> new Pair<>(membreModel, club)))
@ -390,7 +402,7 @@ public class MembreService {
.call(__ -> repository.count("email LIKE ?1 AND id != ?2", membre.getEmail(), id) .call(__ -> repository.count("email LIKE ?1 AND id != ?2", membre.getEmail(), id)
.invoke(Unchecked.consumer(c -> { .invoke(Unchecked.consumer(c -> {
if (c > 0 && !membre.getEmail().isBlank()) if (c > 0 && !membre.getEmail().isBlank())
throw new DBadRequestException(trad.t("email.deja.utilise")); throw new DBadRequestException("Email déjà utiliser");
}))) })))
.invoke(Unchecked.consumer(membreModel -> { .invoke(Unchecked.consumer(membreModel -> {
if (!securityCtx.isInClubGroup(membreModel.getClub().getId())) if (!securityCtx.isInClubGroup(membreModel.getClub().getId()))
@ -399,7 +411,7 @@ public class MembreService {
membre.getLname().toUpperCase()) > 3 || StringSimilarity.similarity( membre.getLname().toUpperCase()) > 3 || StringSimilarity.similarity(
membreModel.getFname().toUpperCase(), membre.getFname().toUpperCase()) > 3) { membreModel.getFname().toUpperCase(), membre.getFname().toUpperCase()) > 3) {
throw new DBadRequestException( throw new DBadRequestException(
trad.t("regiter.new.membre")); "Pour enregistrer un nouveau membre, veuillez utilisez le bouton prévue a cette effet.");
} }
})) }))
.invoke(Unchecked.consumer(membreModel -> { .invoke(Unchecked.consumer(membreModel -> {
@ -408,7 +420,7 @@ public class MembreService {
else if (securityCtx.roleHas("club_secretaire")) source = RoleAsso.SECRETAIRE; else if (securityCtx.roleHas("club_secretaire")) source = RoleAsso.SECRETAIRE;
else if (securityCtx.roleHas("club_respo_intra")) source = RoleAsso.MEMBREBUREAU; else if (securityCtx.roleHas("club_respo_intra")) source = RoleAsso.MEMBREBUREAU;
if (!membre.getRole().equals(membreModel.getRole()) && membre.getRole().level >= source.level) if (!membre.getRole().equals(membreModel.getRole()) && membre.getRole().level >= source.level)
throw new DForbiddenException(trad.t("permission.insuffisante")); throw new DForbiddenException("Permission insuffisante");
})) }))
.onItem().transform(target -> { .onItem().transform(target -> {
if (!securityCtx.getSubject().equals(target.getUserId())) { if (!securityCtx.getSubject().equals(target.getUserId())) {
@ -422,7 +434,7 @@ public class MembreService {
private Uni<String> update(Uni<MembreModel> uni, FullMemberForm membre, boolean admin) { private Uni<String> update(Uni<MembreModel> uni, FullMemberForm membre, boolean admin) {
return uni.chain(target -> { return uni.chain(target -> {
ls.logChange("Prénom", target.getFname(), membre.getFname(), target); ls.logChange("Prénom", target.getFname(), membre.getFname(), target);
target.setFname(Utils.formatPrenom(membre.getFname())); target.setFname(membre.getFname());
ls.logChange("Nom", target.getLname(), membre.getLname(), target); ls.logChange("Nom", target.getLname(), membre.getLname(), target);
target.setLname(membre.getLname().toUpperCase()); target.setLname(membre.getLname().toUpperCase());
ls.logChange("Pays", target.getCountry(), membre.getCountry(), target); ls.logChange("Pays", target.getCountry(), membre.getCountry(), target);
@ -470,8 +482,7 @@ public class MembreService {
.call(membreModel -> licenceRepository.update("club_id = ?1 where membre = ?2 AND saison = ?3", .call(membreModel -> licenceRepository.update("club_id = ?1 where membre = ?2 AND saison = ?3",
(membreModel.getClub() == null) ? null : membreModel.getClub().getId(), membreModel, (membreModel.getClub() == null) ? null : membreModel.getClub().getId(), membreModel,
Utils.getSaison())) Utils.getSaison()))
.call(membreModel -> (membre.getPhoto_data() != null && membre.getPhoto_data() .call(membreModel -> membre.getPhoto_data().length > 0 ? ls.logAUpdate("Photo",
.size() > 0) ? ls.logAUpdate("Photo",
membreModel) : Uni.createFrom().nullItem()) membreModel) : Uni.createFrom().nullItem())
.map(__ -> "OK"); .map(__ -> "OK");
} }
@ -481,8 +492,7 @@ public class MembreService {
return clubRepository.findById(input.getClub()) return clubRepository.findById(input.getClub())
.call(__ -> repository.count("email LIKE ?1", input.getEmail()) .call(__ -> repository.count("email LIKE ?1", input.getEmail())
.invoke(Unchecked.consumer(c -> { .invoke(Unchecked.consumer(c -> {
if (c > 0 && input.getEmail() != null && !input.getEmail().isBlank()) if (c > 0) throw new DBadRequestException("Email déjà utiliser");
throw new DBadRequestException(trad.t("email.deja.utilise"));
}))) })))
.chain(clubModel -> { .chain(clubModel -> {
MembreModel model = getMembreModel(input, clubModel); MembreModel model = getMembreModel(input, clubModel);
@ -498,7 +508,7 @@ public class MembreService {
return repository.find("userId = ?1", subject).firstResult() return repository.find("userId = ?1", subject).firstResult()
.call(__ -> repository.count("email LIKE ?1", input.getEmail()) .call(__ -> repository.count("email LIKE ?1", input.getEmail())
.invoke(Unchecked.consumer(c -> { .invoke(Unchecked.consumer(c -> {
if (c > 0) throw new DBadRequestException(trad.t("email.deja.utilise")); if (c > 0) throw new DBadRequestException("Email déjà utiliser");
}))) })))
.call(membreModel -> .call(membreModel ->
repository.count( repository.count(
@ -506,7 +516,7 @@ public class MembreService {
input.getLname(), input.getFname(), membreModel.getClub()) input.getLname(), input.getFname(), membreModel.getClub())
.invoke(Unchecked.consumer(c -> { .invoke(Unchecked.consumer(c -> {
if (c > 0) if (c > 0)
throw new DBadRequestException(trad.t("membre.deja.existent")); throw new DBadRequestException("Membre déjà existent");
}))) })))
.chain(membreModel -> { .chain(membreModel -> {
MembreModel model = getMembreModel(input, membreModel.getClub()); MembreModel model = getMembreModel(input, membreModel.getClub());
@ -539,13 +549,13 @@ public class MembreService {
.invoke(Unchecked.consumer(membreModel -> { .invoke(Unchecked.consumer(membreModel -> {
if (membreModel.getLicence() != null) { if (membreModel.getLicence() != null) {
throw new DBadRequestException( throw new DBadRequestException(
trad.t("membre.rm.err1")); "Impossible de supprimer un membre qui a déjà un numéro de licence");
} }
})) }))
.call(membreModel -> licenceRepository.find("membre = ?1", membreModel).count() .call(membreModel -> licenceRepository.find("membre = ?1", membreModel).count()
.invoke(Unchecked.consumer(l -> { .invoke(Unchecked.consumer(l -> {
if (l > 0) if (l > 0)
throw new DBadRequestException(trad.t("membre.rm.err2")); throw new DBadRequestException("Impossible de supprimer un membre avec des licences");
}))) })))
.call(membreModel -> (membreModel.getUserId() != null) ? .call(membreModel -> (membreModel.getUserId() != null) ?
keycloakService.removeAccount(membreModel.getUserId()) : Uni.createFrom().nullItem()) keycloakService.removeAccount(membreModel.getUserId()) : Uni.createFrom().nullItem())
@ -567,8 +577,8 @@ public class MembreService {
private static MembreModel getMembreModel(FullMemberForm input, ClubModel clubModel) { private static MembreModel getMembreModel(FullMemberForm input, ClubModel clubModel) {
MembreModel model = new MembreModel(); MembreModel model = new MembreModel();
model.setFname(Utils.formatPrenom(input.getFname())); model.setFname(input.getFname());
model.setLname(input.getLname().toUpperCase()); model.setLname(input.getLname());
model.setEmail(input.getEmail()); model.setEmail(input.getEmail());
model.setLicence(null); model.setLicence(null);
model.setGenre(input.getGenre()); model.setGenre(input.getGenre());
@ -591,30 +601,13 @@ public class MembreService {
public Uni<MeData> getMembre(String subject) { public Uni<MeData> getMembre(String subject) {
MeData meData = new MeData(); MeData meData = new MeData();
return repository.find("userId = ?1", subject).firstResult() return repository.find("userId = ?1", subject).firstResult()
.invoke(m -> meData.setMembre(m, trad)) .invoke(meData::setMembre)
.call(membreModel -> Mutiny.fetch(membreModel.getLicences()) .chain(membreModel -> Mutiny.fetch(membreModel.getLicences()))
.map(licences -> licences.stream().map(SimpleLicence::fromModel).toList()) .map(licences -> licences.stream().map(SimpleLicence::fromModel).toList())
.invoke(meData::setLicences)) .invoke(meData::setLicences)
.call(membreModel -> Mutiny.fetch(membreModel.getSelections())
.map(licences -> licences.stream().map(SimpleSelection::fromModel).toList())
.invoke(meData::setSelections))
.map(__ -> meData); .map(__ -> meData);
} }
public Uni<Void> updateSettings(String subject, UserSettingForm settingForm) {
return repository.find("userId = ?1", subject).firstResult()
.invoke(Unchecked.consumer(membreModel -> {
if (settingForm.getResultPrivacy() != null) {
ls.logChange("Confidentialité des résultats", membreModel.getResultPrivacy(),
settingForm.getResultPrivacy(), membreModel);
membreModel.setResultPrivacy(settingForm.getResultPrivacy());
}
}))
.call(membreModel -> Panache.withTransaction(() -> repository.persist(membreModel)))
.call(membreModel -> ls.append())
.replaceWithVoid();
}
@Scheduled(cron = "0 0 1 1 9 ?") @Scheduled(cron = "0 0 1 1 9 ?")
Uni<Void> everySeason() { Uni<Void> everySeason() {
return repository.list("birth_date IS NOT NULL") return repository.list("birth_date IS NOT NULL")
@ -624,4 +617,5 @@ public class MembreService {
}).toList()).andCollectFailures()) }).toList()).andCollectFailures())
.map(__ -> null); .map(__ -> null);
} }
} }

View File

@ -46,9 +46,6 @@ public class PDFService {
@ConfigProperty(name = "pdf-maker.sign-file") @ConfigProperty(name = "pdf-maker.sign-file")
String sign_file; String sign_file;
@Inject
TradService trad;
public Uni<Response> getLicencePdf(String subject) { public Uni<Response> getLicencePdf(String subject) {
return getLicencePdf(combRepository.find("userId = ?1", subject).firstResult() return getLicencePdf(combRepository.find("userId = ?1", subject).firstResult()
@ -61,7 +58,7 @@ public class PDFService {
LicenceModel licence = m.getLicences().stream() LicenceModel licence = m.getLicences().stream()
.filter(licenceModel -> licenceModel.getSaison() == Utils.getSaison() && licenceModel.isValidate()) .filter(licenceModel -> licenceModel.getSaison() == Utils.getSaison() && licenceModel.isValidate())
.findFirst() .findFirst()
.orElseThrow(() -> new DNotFoundException(trad.t("pas.de.licence.pour.la.saison.en.cours"))); .orElseThrow(() -> new DNotFoundException("Pas de licence pour la saison en cours"));
try { try {
byte[] buff = make_pdf(m, licence); byte[] buff = make_pdf(m, licence);
@ -122,7 +119,7 @@ public class PDFService {
combRepository.find("userId = ?1", subject).firstResult() combRepository.find("userId = ?1", subject).firstResult()
.invoke(Unchecked.consumer(m -> { .invoke(Unchecked.consumer(m -> {
if (m == null || m.getClub() == null) if (m == null || m.getClub() == null)
throw new DNotFoundException(trad.t("club.non.trouve")); throw new DNotFoundException("Club non trouvé");
})) }))
.map(MembreModel::getClub) .map(MembreModel::getClub)
.call(m -> Mutiny.fetch(m.getAffiliations()))); .call(m -> Mutiny.fetch(m.getAffiliations())));
@ -133,7 +130,7 @@ public class PDFService {
clubRepository.findById(id) clubRepository.findById(id)
.invoke(Unchecked.consumer(m -> { .invoke(Unchecked.consumer(m -> {
if (m == null) if (m == null)
throw new DNotFoundException(trad.t("club.non.trouve")); throw new DNotFoundException("Club non trouvé");
})) }))
.call(m -> Mutiny.fetch(m.getAffiliations()))); .call(m -> Mutiny.fetch(m.getAffiliations())));
} }
@ -144,7 +141,7 @@ public class PDFService {
.map(Unchecked.function(m -> { .map(Unchecked.function(m -> {
if (m.getAffiliations().stream() if (m.getAffiliations().stream()
.noneMatch(licenceModel -> licenceModel.getSaison() == Utils.getSaison())) .noneMatch(licenceModel -> licenceModel.getSaison() == Utils.getSaison()))
throw new DNotFoundException(trad.t("pas.d.affiliation.pour.la.saison.en.cours")); throw new DNotFoundException("Pas d'affiliation pour la saison en cours");
try { try {
byte[] buff = make_pdf(m); byte[] buff = make_pdf(m);

View File

@ -1,10 +1,11 @@
package fr.titionfire.ffsaf.domain.service; package fr.titionfire.ffsaf.domain.service;
import fr.titionfire.ffsaf.data.model.*; import fr.titionfire.ffsaf.data.model.*;
import fr.titionfire.ffsaf.data.repository.*; import fr.titionfire.ffsaf.data.repository.CategoryRepository;
import fr.titionfire.ffsaf.domain.entity.MatchModelExtend; 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.data.ResultCategoryData;
import fr.titionfire.ffsaf.rest.exception.DBadRequestException;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException; import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.utils.*; import fr.titionfire.ffsaf.utils.*;
import io.quarkus.hibernate.reactive.panache.common.WithSession; import io.quarkus.hibernate.reactive.panache.common.WithSession;
@ -34,135 +35,64 @@ public class ResultService {
@Inject @Inject
MembreService membreService; MembreService membreService;
@Inject
ClubRepository clubRepository;
@Inject
CompetitionGuestRepository competitionGuestRepository;
@Inject @Inject
CategoryRepository categoryRepository; CategoryRepository categoryRepository;
@Inject @Inject
MatchRepository matchRepository; MatchRepository matchRepository;
@Inject private static final ResourceBundle BUNDLE = ResourceBundle.getBundle("lang.String");
CardRepository cardRepository;
@Inject
TradService trad;
private static final HashMap<Long, String> combTempIds = new HashMap<>();
private static String getCombTempId(Long key) {
synchronized (combTempIds) {
if (!combTempIds.containsKey(key)) {
combTempIds.put(key, UUID.randomUUID().toString());
}
return combTempIds.get(key);
}
}
private static Long getCombTempId(String value) {
synchronized (combTempIds) {
for (Map.Entry<Long, String> entry : combTempIds.entrySet()) {
if (entry.getValue().equals(value)) {
return entry.getKey();
}
}
return null;
}
}
private static final HashMap<String, Long> clubTempIds = new HashMap<>();
private static Long getClubTempId(String key) {
synchronized (clubTempIds) {
if (!clubTempIds.containsKey(key)) {
clubTempIds.put(key, (System.currentTimeMillis() + clubTempIds.size()) * -1);
}
return clubTempIds.get(key);
}
}
private static String getClubTempId(Long value) {
synchronized (clubTempIds) {
for (Map.Entry<String, Long> entry : clubTempIds.entrySet()) {
if (entry.getValue().equals(value)) {
return entry.getKey();
}
}
return null;
}
}
public Uni<List<Object[]>> getList(SecurityCtx securityCtx) { public Uni<List<Object[]>> getList(SecurityCtx securityCtx) {
return membreService.getByAccountId(securityCtx.getSubject()) return membreService.getByAccountId(securityCtx.getSubject())
.chain(m -> registerRepository.list( .chain(m -> registerRepository.list("membre = ?1", m))
"membre = ?1 OR (TRUE = ?2 AND membre.club = ?3)",
m, securityCtx.isClubAdmin(), m.getClub()))
.onItem().transformToMulti(Multi.createFrom()::iterable) .onItem().transformToMulti(Multi.createFrom()::iterable)
.onItem().call(r -> Mutiny.fetch(r.getCompetition())) .onItem().call(r -> Mutiny.fetch(r.getCompetition()))
.onItem().transform(RegisterModel::getCompetition) .onItem().transform(r -> new Object[]{r.getCompetition().getUuid(), r.getCompetition().getName(),
.collect().asList() r.getCompetition().getDate()})
.chain(l -> compRepository.list("owner = ?1 OR ?1 IN admin", securityCtx.getSubject()) .collect().asList();
.map(l2 -> Stream.concat(l.stream(), l2.stream()).distinct()
.map(c -> new Object[]{c.getUuid(), c.getName(), c.getDate()}).toList())
);
} }
public Uni<HashMap<String, Long>> getCategoryList(String uuid, SecurityCtx securityCtx) { public Uni<List<ResultCategoryData>> getCategory(String uuid, SecurityCtx securityCtx) {
return hasAccess(uuid, securityCtx).chain(__ -> getCategoryList(uuid)); 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
public Uni<HashMap<String, Long>> getCategoryList(String uuid) { m.getMembre(), cats)))
return categoryRepository.list("compet.uuid = ?1", uuid)
.map(categoryModels -> {
HashMap<String, Long> map = new HashMap<>();
categoryModels.stream()
.sorted(Comparator.comparing(CategoryModel::getName))
.forEachOrdered(categoryModel -> map.put(categoryModel.getName(), categoryModel.getId()));
return map;
});
}
public Uni<ResultCategoryData> getCategory(String uuid, long poule, SecurityCtx securityCtx) {
return hasAccess(uuid, securityCtx).chain(membreModel -> getData(uuid, poule, membreModel));
}
public Uni<ResultCategoryData> getCategory(String uuid, long poule) {
return getData(uuid, poule, null);
}
private Uni<ResultCategoryData> getData(String uuid, long poule, MembreModel membreModel) {
List<CardModel> cards = new ArrayList<>();
return matchRepository.list("category.compet.uuid = ?1 AND category.id = ?2", uuid, poule)
.call(list -> list.isEmpty() ? Uni.createFrom().voidItem() :
Mutiny.fetch(list.get(0).getCategory().getTree()))
.chain(list -> cardRepository.list("competition.uuid = ?1", uuid).invoke(cards::addAll)
.map(c -> list.stream().map(m -> new MatchModelExtend(m, c)).toList()))
.map(matchModels -> { .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(); ResultCategoryData out = new ResultCategoryData();
CategoryModel categoryModel = matchModels.get(0).getCategory(); CategoryModel categoryModel = matchModels.get(0).getCategory();
out.setName(categoryModel.getName()); out.setName(categoryModel.getName());
out.setType(categoryModel.getType()); out.setType(categoryModel.getType());
out.setLiceName(categoryModel.getLiceName() == null ? new String[]{} : categoryModel.getLiceName()
.split(";"));
out.setGenTime(System.currentTimeMillis());
getArray2(matchModels, membreModel, out); getArray2(matchModels, out);
getTree(categoryModel.getTree(), membreModel, cards, out); getTree(categoryModel.getTree(), out);
return out; return out;
});
} }
private void getArray2(List<MatchModelExtend> matchModels_, MembreModel membreModel, ResultCategoryData out) { private void getArray2(List<MatchModel> matchModels_, ResultCategoryData out) {
List<MatchModelExtend> matchModels = matchModels_.stream().filter(o -> o.getCategory_ord() >= 0).toList(); List<MatchModel> matchModels = matchModels_.stream().filter(o -> o.getCategory_ord() >= 0).toList();
HashMap<Character, List<MatchModelExtend>> matchMap = new HashMap<>(); HashMap<Character, List<MatchModel>> matchMap = new HashMap<>();
for (MatchModelExtend model : matchModels) { for (MatchModel model : matchModels) {
char g = model.getPoule(); char g = model.getPoule();
if (!matchMap.containsKey(g)) if (!matchMap.containsKey(g))
matchMap.put(g, new ArrayList<>()); matchMap.put(g, new ArrayList<>());
@ -171,35 +101,56 @@ public class ResultService {
matchMap.forEach((c, matchEntities) -> { matchMap.forEach((c, matchEntities) -> {
List<ResultCategoryData.PouleArrayData> matchs = matchEntities.stream() List<ResultCategoryData.PouleArrayData> matchs = matchEntities.stream()
.sorted(Comparator.comparing(MatchModelExtend::getCategory_ord)) .sorted(Comparator.comparing(MatchModel::getCategory_ord))
.map(o -> ResultCategoryData.PouleArrayData.fromModel(o, membreModel, .map(ResultCategoryData.PouleArrayData::fromModel)
ResultPrivacy.REGISTERED_ONLY_NO_DETAILS))
.toList(); .toList();
List<ResultCategoryData.RankArray> rankArray = matchEntities.stream() List<ResultCategoryData.RankArray> rankArray = matchEntities.stream()
.flatMap(m -> Stream.of(m.getC1_id(), m.getC2_id(), m.getC1_guest(), m.getC2_guest())) .flatMap(m -> Stream.of(m.getC1Name(), m.getC2Name()))
.distinct() .distinct()
.filter(Objects::nonNull) .map(combName -> {
.map(comb -> { AtomicInteger w = new AtomicInteger(0);
CombStat stat = makeStat(matchEntities, comb); AtomicInteger pointMake = new AtomicInteger(0);
return new ResultCategoryData.RankArray(0, AtomicInteger pointTake = new AtomicInteger(0);
comb.getName(membreModel, ResultPrivacy.REGISTERED_ONLY_NO_DETAILS), stat.score, stat.w,
stat.pointMake, stat.pointTake, stat.getPointRate()); 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 .sorted(Comparator
.comparing(ResultCategoryData.RankArray::getScore) .comparing(ResultCategoryData.RankArray::getWin)
.thenComparing(ResultCategoryData.RankArray::getWin)
.thenComparing(ResultCategoryData.RankArray::getPointRate).reversed()) .thenComparing(ResultCategoryData.RankArray::getPointRate).reversed())
.toList(); .toList();
out.getMatchs().put(c, matchs); out.getMatchs().put(c, matchs);
int lastScore = -1;
int lastWin = -1; int lastWin = -1;
float pointRate = 0; float pointRate = 0;
int rank = 0; int rank = 0;
for (ResultCategoryData.RankArray rankArray1 : rankArray) { for (ResultCategoryData.RankArray rankArray1 : rankArray) {
if (rankArray1.getScore() != lastScore || rankArray1.getWin() != lastWin || pointRate != rankArray1.getPointRate()) { if (rankArray1.getWin() != lastWin || pointRate != rankArray1.getPointRate()) {
lastScore = rankArray1.getScore();
lastWin = rankArray1.getWin(); lastWin = rankArray1.getWin();
pointRate = rankArray1.getPointRate(); pointRate = rankArray1.getPointRate();
rank++; rank++;
@ -210,29 +161,23 @@ public class ResultService {
}); });
} }
private static void convertTree(TreeModel src, TreeNode<ResultCategoryData.TreeData> dst, MembreModel membreModel, private static void convertTree(TreeModel src, TreeNode<ResultCategoryData.TreeData> dst) {
ResultPrivacy privacy, List<CardModel> cards) { dst.setData(ResultCategoryData.TreeData.from(src.getMatch()));
dst.setData(
ResultCategoryData.TreeData.from(new MatchModelExtend(src.getMatch(), cards), membreModel, privacy));
if (src.getLeft() != null) { if (src.getLeft() != null) {
dst.setLeft(new TreeNode<>()); dst.setLeft(new TreeNode<>());
convertTree(src.getLeft(), dst.getLeft(), membreModel, privacy, cards); convertTree(src.getLeft(), dst.getLeft());
} }
if (src.getRight() != null) { if (src.getRight() != null) {
dst.setRight(new TreeNode<>()); dst.setRight(new TreeNode<>());
convertTree(src.getRight(), dst.getRight(), membreModel, privacy, cards); convertTree(src.getRight(), dst.getRight());
} }
} }
private void getTree(List<TreeModel> treeModels, MembreModel membreModel, List<CardModel> cards, private void getTree(List<TreeModel> treeModels, ResultCategoryData out) {
ResultCategoryData out) {
ArrayList<TreeNode<ResultCategoryData.TreeData>> trees = new ArrayList<>(); ArrayList<TreeNode<ResultCategoryData.TreeData>> trees = new ArrayList<>();
treeModels.stream() treeModels.stream().filter(t -> t.getLevel() != 0).forEach(treeModel -> {
.filter(t -> t.getLevel() != 0)
.sorted(Comparator.comparing(TreeModel::getLevel))
.forEach(treeModel -> {
TreeNode<ResultCategoryData.TreeData> root = new TreeNode<>(); TreeNode<ResultCategoryData.TreeData> root = new TreeNode<>();
convertTree(treeModel, root, membreModel, ResultPrivacy.REGISTERED_ONLY_NO_DETAILS, cards); convertTree(treeModel, root);
trees.add(root); trees.add(root);
}); });
out.setTrees(trees); out.setTrees(trees);
@ -240,61 +185,71 @@ public class ResultService {
public Uni<CombsArrayData> getAllCombArray(String uuid, SecurityCtx securityCtx) { public Uni<CombsArrayData> getAllCombArray(String uuid, SecurityCtx securityCtx) {
return hasAccess(uuid, securityCtx) return hasAccess(uuid, securityCtx)
.chain(membreModel -> getAllCombArray_(uuid, membreModel)); .chain(cm_register -> registerRepository.list("competition.uuid = ?1", uuid)
}
public Uni<CombsArrayData> getAllCombArrayPublic(String uuid) {
return getAllCombArray_(uuid, null);
}
private Uni<CombsArrayData> getAllCombArray_(String uuid, MembreModel membreModel) {
return registerRepository.list("competition.uuid = ?1", uuid)
.chain(registers -> matchRepository.list("category.compet.uuid = ?1", uuid) .chain(registers -> matchRepository.list("category.compet.uuid = ?1", uuid)
.chain(matchModels -> cardRepository.list("competition.uuid = ?1", uuid) .map(matchModels -> new Pair<>(registers, matchModels)))
.map(cards -> new Pair<>(registers,
matchModels.stream().map(m -> new MatchModelExtend(m, cards)).toList()))))
.map(pair -> { .map(pair -> {
List<RegisterModel> registers = pair.getKey(); List<RegisterModel> registers = pair.getKey();
List<MatchModelExtend> matchModels = pair.getValue(); List<MatchModel> matchModels = pair.getValue();
CombsArrayData.CombsArrayDataBuilder builder = CombsArrayData.builder(); CombsArrayData.CombsArrayDataBuilder builder = CombsArrayData.builder();
List<CombsArrayData.CombsData> combs = matchModels.stream() List<CombsArrayData.CombsData> combs = matchModels.stream()
.flatMap(m -> Stream.of(m.getC1_id(), m.getC2_id(), m.getC1_guest(), m.getC2_guest())) .flatMap(m -> Stream.of(m.getC1Name(), m.getC2Name()))
.filter(Objects::nonNull) .filter(Objects::nonNull)
.distinct() .distinct()
.map(comb -> { .map(combName -> {
var builder2 = CombsArrayData.CombsData.builder(); var builder2 = CombsArrayData.CombsData.builder();
CombStat stat = makeStat(matchModels, comb); AtomicInteger w = new AtomicInteger(0);
AtomicInteger l = new AtomicInteger(0);
AtomicInteger pointMake = new AtomicInteger();
AtomicInteger pointTake = new AtomicInteger();
Categorie categorie = null; matchModels.stream()
String clubName = null; .filter(m -> m.isEnd() && (m.getC1Name().equals(combName)
|| m.getC2Name().equals(combName)))
Optional<RegisterModel> register = registers.stream() .forEach(matchModel -> {
.filter(r -> Objects.equals(r.getMembre(), comb)).findFirst(); int win = matchModel.win();
if (register.isPresent()) { if ((combName.equals(matchModel.getC1Name()) && win > 0) ||
categorie = register.get().getCategorie2(); combName.equals(matchModel.getC2Name()) && win < 0) {
ClubModel club = register.get().getClub2(); w.getAndIncrement();
clubName = (club == null) ? trad.t("no.licence") : club.getName(); } else {
} else if (comb instanceof CompetitionGuestModel guestModel) { l.getAndIncrement();
categorie = guestModel.getCategorie();
clubName = guestModel.getClub();
} else if (comb instanceof MembreModel model) {
categorie = model.getCategorie();
clubName = (model.getClub() == null) ? trad.t("no.licence")
: model.getClub().getName();
} }
builder2.cat((categorie == null) ? "---" : categorie.getName(trad)); matchModel.getScores().stream()
builder2.name(comb.getName(membreModel, ResultPrivacy.REGISTERED_ONLY)); .filter(s -> s.getS1() > -900 && s.getS2() > -900)
builder2.w(stat.w); .forEach(score -> {
builder2.l(stat.l); if (combName.equals(matchModel.getC1Name())) {
builder2.ratioVictoire((stat.l == 0) ? stat.w : (float) stat.w / stat.l); pointMake.addAndGet(score.getS1());
builder2.club(clubName); pointTake.addAndGet(score.getS2());
builder2.pointMake(stat.pointMake); } else {
builder2.pointTake(stat.pointTake); pointMake.addAndGet(score.getS2());
builder2.ratioPoint(stat.getPointRate()); 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(); return builder2.build();
}) })
@ -302,178 +257,15 @@ public class ResultService {
.toList(); .toList();
builder.nb_insc(combs.size()); builder.nb_insc(combs.size());
builder.tt_match((int) matchModels.stream().filter(MatchModelExtend::isEnd).count()); builder.tt_match((int) matchModels.stream().filter(MatchModel::isEnd).count());
builder.point(matchModels.stream() builder.point(combs.stream().mapToInt(CombsArrayData.CombsData::pointMake).sum());
.filter(MatchModelExtend::isEnd)
.flatMap(m -> m.getScoresToCompute().stream())
.mapToInt(s -> s.getS1() + s.getS2()).sum());
builder.combs(combs); builder.combs(combs);
return builder.build(); return builder.build();
});
}
public Uni<HashMap<String, String>> getCombList(String uuid, SecurityCtx securityCtx) {
return hasAccess(uuid, securityCtx)
.chain(membreModel -> getCombList(uuid, ResultPrivacy.REGISTERED_ONLY));
}
public Uni<HashMap<String, String>> getCombList(String uuid) {
return getCombList(uuid, ResultPrivacy.PUBLIC);
}
private Uni<HashMap<String, String>> getCombList(String uuid, ResultPrivacy privacy) {
return registerRepository.list("competition.uuid = ?1 AND membre.resultPrivacy <= ?2", uuid, privacy)
.map(models -> {
HashMap<String, String> map = new HashMap<>();
models.forEach(
r -> map.put(r.getMembre().getName(), getCombTempId(r.getMembre().getId())));
return map;
})
.chain(map -> competitionGuestRepository.list("competition.uuid = ?1 AND lname != \"__team\"", uuid)
.map(models -> {
models.forEach(guestModel -> map.put(guestModel.getName(),
getCombTempId(guestModel.getId() * -1)));
return map;
}) })
); );
} }
public Uni<?> getCombArrayPublic(String uuid, String combTempId, SecurityCtx securityCtx) {
return hasAccess(uuid, securityCtx)
.chain(membreModel -> getCombArrayPublic(uuid, combTempId, ResultPrivacy.REGISTERED_ONLY));
}
public Uni<?> getCombArrayPublic(String uuid, String combTempId) {
return getCombArrayPublic(uuid, combTempId, ResultPrivacy.PUBLIC);
}
private Uni<?> getCombArrayPublic(String uuid, String combTempId, ResultPrivacy privacy) {
CombArrayData.CombArrayDataBuilder builder = CombArrayData.builder();
Long id = getCombTempId(combTempId);
if (id == null) {
return Uni.createFrom().failure(new DForbiddenException(trad.t("comb.not.found")));
}
Uni<List<MatchModelExtend>> uni;
if (id >= 0) {
uni = registerRepository.find("membre.id = ?1 AND competition.uuid = ?2 AND membre.resultPrivacy <= ?3", id,
uuid, privacy).firstResult()
.chain(Unchecked.function(registerModel -> {
if (registerModel == null)
throw new DBadRequestException(trad.t("combattant.non.inscrit"));
builder.name(Utils.getFullName(registerModel.getMembre()));
builder.club((registerModel.getClub2() == null) ? trad.t("no.licence") :
registerModel.getClub2().getName());
builder.cat((registerModel.getCategorie2() == null) ? "---" :
registerModel.getCategorie2().getName(trad));
return matchRepository.list(
"SELECT DISTINCT m FROM MatchModel m LEFT JOIN m.c1_guest.comb c1g LEFT JOIN m.c2_guest.comb c2g " +
"WHERE m.category.compet.uuid = ?1 AND (m.c1_id = ?2 OR m.c2_id = ?2 OR c1g = ?2 OR c2g = ?2)",
uuid, registerModel.getMembre())
.chain(matchModels -> cardRepository.list("competition.uuid = ?1", uuid)
.map(cards -> matchModels.stream().map(m -> new MatchModelExtend(m, cards))
.toList()));
}));
} else {
uni = competitionGuestRepository.find("id = ?1 AND competition.uuid = ?2", -id, uuid).firstResult()
.chain(guestModel -> {
builder.name(Utils.getFullName(guestModel));
builder.club(guestModel.getClub());
builder.cat(
(guestModel.getCategorie() == null) ? "---" : guestModel.getCategorie().getName(trad));
return matchRepository.list(
"SELECT DISTINCT m FROM MatchModel m LEFT JOIN m.c1_guest.guest c1g LEFT JOIN m.c2_guest.guest c2g " +
"WHERE m.category.compet.uuid = ?1 AND (m.c1_guest = ?2 OR m.c2_guest = ?2 OR c1g = ?2 OR c2g = ?2)",
uuid, guestModel)
.chain(matchModels -> cardRepository.list("competition.uuid = ?1", uuid)
.map(cards -> matchModels.stream().map(m -> new MatchModelExtend(m, cards))
.toList()));
});
}
return uni.invoke(matchModels -> {
List<CategoryModel> pouleModels = matchModels.stream().map(MatchModelExtend::getCategory).distinct()
.toList();
List<CombArrayData.MatchsData> matchs = new ArrayList<>();
AtomicInteger sumW = new AtomicInteger();
AtomicInteger sumPointMake = new AtomicInteger(0);
AtomicInteger sumPointTake = new AtomicInteger(0);
for (MatchModelExtend matchModel : matchModels) {
if ((matchModel.getC1_id() == null && matchModel.getC1_guest() == null) ||
(matchModel.getC2_id() == null && matchModel.getC2_guest() == null))
continue;
var builder2 = CombArrayData.MatchsData.builder();
builder2.date(matchModel.getDate());
builder2.poule(pouleModels.stream().filter(p -> p.equals(matchModel.getCategory()))
.map(CategoryModel::getName).findFirst().orElse(""));
builder2.end(matchModel.isEnd());
AtomicInteger pointMake = new AtomicInteger();
AtomicInteger pointTake = new AtomicInteger();
if (matchModel.isC1(id)) {
builder2.adv(matchModel.getC2Name());
if (matchModel.isEnd()) {
matchModel.getScoresToCompute()
.forEach(scoreEntity -> {
pointMake.addAndGet(scoreEntity.getS1());
pointTake.addAndGet(scoreEntity.getS2());
});
builder2.score(matchModel.getScoresToPrint().stream()
.map(s -> new Integer[]{s.getS1(), s.getS2()}).toList());
} else {
builder2.score(new ArrayList<>());
}
builder2.win(matchModel.isEnd() && matchModel.getWin() > 0);
} else {
builder2.adv(matchModel.getC1Name());
if (matchModel.isEnd()) {
matchModel.getScoresToCompute()
.forEach(scoreEntity -> {
pointMake.addAndGet(scoreEntity.getS2());
pointTake.addAndGet(scoreEntity.getS1());
});
builder2.score(matchModel.getScoresToPrint().stream()
.map(s -> new Integer[]{s.getS2(), s.getS1()}).toList());
} else {
builder2.score(new ArrayList<>());
}
builder2.win(matchModel.isEnd() && matchModel.getWin() < 0);
}
builder2.eq(matchModel.isEnd() && matchModel.getWin() == 0);
builder2.ratio(
(pointTake.get() == 0) ? pointMake.get() : (float) pointMake.get() / pointTake.get());
sumPointMake.addAndGet(pointMake.get());
sumPointTake.addAndGet(pointTake.get());
matchs.add(builder2.build());
if (builder2.win)
sumW.getAndIncrement();
}
builder.totalWin(sumW.get());
builder.pointRatio(
(sumPointTake.get() == 0) ? sumPointMake.get() : (float) sumPointMake.get() / sumPointTake.get());
builder.pointMake(sumPointMake.get());
builder.pointTake(sumPointTake.get());
matchs.sort(Comparator.comparing(CombArrayData.MatchsData::poule)
.thenComparing(CombArrayData.MatchsData::adv));
builder.matchs(matchs);
})
.map(__ -> builder.build());
}
@Builder @Builder
@RegisterForReflection @RegisterForReflection
@ -485,132 +277,85 @@ public class ResultService {
} }
} }
@Builder public Uni<ClubArrayData> getClubArray(String uuid, SecurityCtx securityCtx) {
@RegisterForReflection
public static record CombArrayData(String name, String club, String cat, int totalWin,
float pointRatio, int pointMake, int pointTake, List<MatchsData> matchs) {
@Builder
@RegisterForReflection
public static record MatchsData(Date date, String poule, String adv, List<Integer[]> score, float ratio,
boolean win, boolean eq, boolean end) {
}
}
public Uni<HashMap<String, Long>> getClubList(String uuid, SecurityCtx securityCtx) {
return hasAccess(uuid, securityCtx).chain(__ -> getClubList(uuid));
}
public Uni<HashMap<String, Long>> getClubList(String uuid) {
return registerRepository.list("competition.uuid = ?1", uuid)
.map(registers -> {
HashMap<String, Long> registerMap = new HashMap<>();
registers.stream().map(RegisterModel::getClub2).distinct().filter(Objects::nonNull)
.forEach(registerClub -> registerMap.put(registerClub.getName(), registerClub.getId()));
return registerMap;
})
.chain(map -> competitionGuestRepository.list("competition.uuid = ?1", uuid)
.map(guests -> {
guests.stream().map(CompetitionGuestModel::getClub).distinct()
.filter(Objects::nonNull)
.forEach(guestClub -> map.putIfAbsent(guestClub,
getClubTempId(guestClub)));
return map;
})
);
}
public Uni<ClubArrayData> getClubArray(String uuid, Long id, SecurityCtx securityCtx) {
return hasAccess(uuid, securityCtx).chain(membreModel -> getClubArray2(uuid, id, membreModel));
}
public Uni<ClubArrayData> getClubArray2(String uuid, Long id, MembreModel membreModel) {
if (id < 0) {
String clubName = getClubTempId(id);
if (clubName == null) {
return Uni.createFrom().failure(new DForbiddenException(trad.t("club.not.found")));
}
return competitionGuestRepository.list("competition.uuid = ?1 AND club = ?2", uuid, clubName)
.call(list -> {
if (list.isEmpty())
return Uni.createFrom().failure(new DBadRequestException(trad.t("club.not.found")));
return Uni.createFrom().voidItem();
})
.chain(guests -> matchRepository.list(
"SELECT DISTINCT m FROM MatchModel m LEFT JOIN m.c1_guest.guest c1g LEFT JOIN m.c2_guest.guest c2g " +
"WHERE m.category.compet.uuid = ?1 AND (m.c1_guest IN ?2 OR m.c2_guest IN ?2 OR c1g IN ?2 OR c2g IN ?2)",
uuid, guests)
.chain(mm -> cardRepository.list("competition.uuid = ?1", uuid)
.map(cards ->
getClubArray2(clubName, guests.stream().map(o -> (CombModel) o).toList(),
mm.stream().map(m -> new MatchModelExtend(m, cards)).toList(),
new ArrayList<>(), membreModel)
)));
} else {
return clubRepository.findById(id).chain(clubModel ->
registerRepository.list("competition.uuid = ?1 AND membre.club = ?2", uuid, clubModel)
.chain(registers -> matchRepository.list(
"SELECT DISTINCT m FROM MatchModel m LEFT JOIN m.c1_guest.comb c1g LEFT JOIN m.c2_guest.comb c2g " +
"WHERE m.category.compet.uuid = ?1 AND (m.c1_id IN ?2 OR m.c2_id IN ?2 OR c1g IN ?2 OR c2g IN ?2)",
uuid, registers.stream().map(RegisterModel::getMembre).toList())
.chain(matchModels -> cardRepository.list("competition.uuid = ?1", uuid)
.map(cards ->
getClubArray2(clubModel.getName(),
registers.stream().map(o -> (CombModel) o.getMembre())
.toList(),
matchModels.stream()
.map(m -> new MatchModelExtend(m, cards)).toList(),
registers, membreModel)
))));
}
}
private ClubArrayData getClubArray2(String name, List<CombModel> combs, List<MatchModelExtend> matchModels,
List<RegisterModel> registers, MembreModel membreModel) {
ClubArrayData.ClubArrayDataBuilder builder = ClubArrayData.builder(); ClubArrayData.ClubArrayDataBuilder builder = ClubArrayData.builder();
builder.name(name);
builder.nb_insc(combs.size());
ArrayList<Long> win_ids = new ArrayList<>(); return hasAccess(uuid, securityCtx)
ArrayList<Long> match_ids = new ArrayList<>(); .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 -> {
List<ClubArrayData.CombData> combData = combs.stream().map(comb -> {
var builder2 = ClubArrayData.CombData.builder(); var builder2 = ClubArrayData.CombData.builder();
CombStat stat = makeStat(matchModels, comb); AtomicInteger w = new AtomicInteger(0);
AtomicInteger l = new AtomicInteger(0);
AtomicInteger pointMake = new AtomicInteger();
AtomicInteger pointTake = new AtomicInteger();
Categorie categorie = null; matchModels.stream()
.filter(m -> m.isEnd() && (register.getMembre().equals(m.getC1_id())
Optional<RegisterModel> register = registers.stream() || register.getMembre().equals(m.getC2_id())))
.filter(r -> Objects.equals(r.getMembre(), comb)).findFirst(); .forEach(matchModel -> {
if (register.isPresent()) { int win = matchModel.win();
categorie = register.get().getCategorie2(); if ((register.getMembre()
} else if (comb instanceof CompetitionGuestModel guestModel) { .equals(matchModel.getC1_id()) && win > 0) ||
categorie = guestModel.getCategorie(); register.getMembre()
} else if (comb instanceof MembreModel model) { .equals(matchModel.getC2_id()) && win < 0) {
categorie = model.getCategorie(); w.getAndIncrement();
} else {
l.getAndIncrement();
} }
builder2.cat((categorie == null) ? "---" : categorie.getName(trad)); matchModel.getScores().stream()
builder2.name(comb.getName(membreModel, ResultPrivacy.REGISTERED_ONLY)); .filter(s -> s.getS1() > -900 && s.getS2() > -900)
builder2.w(stat.w); .forEach(score -> {
builder2.l(stat.l); if (register.getMembre()
builder2.ratioVictoire((stat.l == 0) ? stat.w : (float) stat.w / stat.l); .equals(matchModel.getC1_id())) {
builder2.pointMake(stat.pointMake); pointMake.addAndGet(score.getS1());
builder2.pointTake(stat.pointTake); pointTake.addAndGet(score.getS2());
builder2.ratioPoint(stat.getPointRate()); } else {
pointMake.addAndGet(score.getS2());
pointTake.addAndGet(score.getS1());
}
});
});
win_ids.addAll(stat.win_ids); Categorie categorie = register.getCategorie();
match_ids.addAll(stat.match_ids); 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(); return builder2.build();
}) })
.sorted(Comparator.comparing(ClubArrayData.CombData::name)) .sorted(Comparator.comparing(ClubArrayData.CombData::name))
.toList(); .toList();
builder.nb_match((int) match_ids.stream().distinct().count()); builder.nb_match(tt_match.get());
builder.match_w((int) win_ids.stream().distinct().count()); builder.match_w(tt_win.get());
builder.ratioVictoire((float) combData.stream().filter(c -> c.l + c.w != 0) builder.ratioVictoire((float) combData.stream().filter(c -> c.l + c.w != 0)
.mapToDouble(ClubArrayData.CombData::ratioVictoire).average().orElse(0L)); .mapToDouble(ClubArrayData.CombData::ratioVictoire).average().orElse(0L));
builder.pointMake(combData.stream().mapToInt(ClubArrayData.CombData::pointMake).sum()); builder.pointMake(combData.stream().mapToInt(ClubArrayData.CombData::pointMake).sum());
@ -620,38 +365,8 @@ public class ResultService {
builder.combs(combData); builder.combs(combData);
return builder.build(); return builder.build();
} })
);
private static CombStat makeStat(List<MatchModelExtend> matchModels, CombModel comb) {
CombStat stat = new CombStat();
matchModels.stream()
.filter(m -> m.isEnd() && (m.isC1(comb) || m.isC2(comb)))
.forEach(matchModel -> {
stat.match_ids.add(matchModel.getId());
int win = matchModel.getWin();
if (win == 0) {
stat.score += 1;
} else if ((matchModel.isC1(comb) && win > 0) || matchModel.isC2(comb) && win < 0) {
stat.w++;
stat.win_ids.add(matchModel.getId());
stat.score += 2;
} else {
stat.l++;
}
matchModel.getScoresToCompute()
.forEach(score -> {
if (matchModel.isC1(comb)) {
stat.pointMake += score.getS1();
stat.pointTake += score.getS2();
} else {
stat.pointMake += score.getS2();
stat.pointTake += score.getS1();
}
});
});
return stat;
} }
@Builder @Builder
@ -665,60 +380,21 @@ public class ResultService {
} }
} }
@RegisterForReflection private Uni<RegisterModel> hasAccess(String uuid, SecurityCtx securityCtx) {
public static class CombStat {
public int w;
public int l;
public int score;
public int pointMake;
public int pointTake;
public ArrayList<Long> win_ids = new ArrayList<>();
public ArrayList<Long> match_ids = new ArrayList<>();
public CombStat() {
this.w = 0;
this.l = 0;
this.score = 0;
this.pointMake = 0;
this.pointTake = 0;
}
public float getPointRate() {
return (pointTake == 0) ? pointMake : (float) pointMake / pointTake;
}
}
private Uni<MembreModel> hasAccess(String uuid, SecurityCtx securityCtx) {
return registerRepository.find("membre.userId = ?1 AND competition.uuid = ?2", securityCtx.getSubject(), uuid) return registerRepository.find("membre.userId = ?1 AND competition.uuid = ?2", securityCtx.getSubject(), uuid)
.firstResult() .firstResult()
.chain(Unchecked.function(o -> { .invoke(Unchecked.consumer(o -> {
if (o != null) if (o == null)
return Uni.createFrom().item(o.getMembre()); throw new DForbiddenException("Access denied");
}));
return membreService.getByAccountId(securityCtx.getSubject()).chain(m -> {
if (securityCtx.isClubAdmin()) {
return registerRepository.count("membre.club = ?2 AND competition.uuid = ?1",
uuid, m.getClub()).chain(c -> {
if (c > 0) return Uni.createFrom().item(m);
return compRepository.count("uuid = ?1 AND (owner = ?2 OR ?2 IN admin)",
uuid, securityCtx.getSubject())
.chain(c2 -> {
if (c2 > 0) return Uni.createFrom().item(m);
return Uni.createFrom().failure(new DForbiddenException(
trad.t("access.denied")));
});
});
} else {
return compRepository.count("uuid = ?1 AND (owner = ?2 OR ?2 IN admin)", uuid,
securityCtx.getSubject())
.chain(c2 -> {
if (c2 > 0) return Uni.createFrom().item(m);
return Uni.createFrom()
.failure(new DForbiddenException(trad.t("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");
})); }));
} }
} }

View File

@ -1,64 +0,0 @@
package fr.titionfire.ffsaf.domain.service;
import fr.titionfire.ffsaf.data.model.LogModel;
import fr.titionfire.ffsaf.data.model.MembreModel;
import fr.titionfire.ffsaf.data.model.SelectionModel;
import fr.titionfire.ffsaf.data.repository.CombRepository;
import fr.titionfire.ffsaf.data.repository.SelectionRepository;
import fr.titionfire.ffsaf.rest.data.SimpleSelection;
import io.quarkus.hibernate.reactive.panache.Panache;
import io.quarkus.hibernate.reactive.panache.common.WithSession;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.hibernate.reactive.mutiny.Mutiny;
import java.util.List;
import java.util.function.Consumer;
@WithSession
@ApplicationScoped
public class SelectionService {
@Inject
CombRepository combRepository;
@Inject
SelectionRepository repository;
@Inject
LoggerService ls;
public Uni<List<SelectionModel>> getSelection(long id, Consumer<MembreModel> checkPerm) {
return combRepository.findById(id).invoke(checkPerm)
.chain(combRepository -> Mutiny.fetch(combRepository.getSelections()));
}
public Uni<SelectionModel> setSelection(long id, SimpleSelection data) {
if (data.getId() == -1) {
return combRepository.findById(id).chain(membreModel -> {
SelectionModel model = new SelectionModel();
model.setMembre(membreModel);
model.setSaison(data.getSaison());
model.setCategorie(data.getCategorie());
return Panache.withTransaction(() -> repository.persist(model))
.call(licenceModel -> ls.logA(LogModel.ActionType.ADD, membreModel.getObjectName(),
licenceModel));
});
} else {
return repository.findById(data.getId()).chain(model -> {
ls.logChange("Catégorie", model.getCategorie(), data.getCategorie(), model);
model.setCategorie(data.getCategorie());
return Panache.withTransaction(() -> repository.persist(model))
.call(__ -> ls.append());
});
}
}
public Uni<Void> deleteSelection(long id) {
return repository.findById(id)
.call(model -> ls.logADelete(model))
.chain(model -> Panache.withTransaction(() -> repository.delete(model)));
}
}

View File

@ -36,7 +36,7 @@ public class StatsService {
LicenceStats.YearStats yearStats = stats.getLicences().get(licence.getSaison()); LicenceStats.YearStats yearStats = stats.getLicences().get(licence.getSaison());
// System.out.println("stats: " + licence.getMembre().getFname()); System.out.println("stats: " + licence.getMembre().getFname());
if (licence.isValidate()) { if (licence.isValidate()) {
if (licence.getMembre().getGenre() == Genre.H) if (licence.getMembre().getGenre() == Genre.H)
yearStats.addH(); yearStats.addH();

View File

@ -1,41 +0,0 @@
package fr.titionfire.ffsaf.domain.service;
import jakarta.enterprise.context.RequestScoped;
import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;
import jakarta.ws.rs.container.ContainerRequestContext;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
@RequestScoped
public class TradService {
@Inject
Instance<ContainerRequestContext> requestContextInstance;
public static final Locale fallbackLocale = Locale.FRANCE;
public String t(String key) {
return translate(key);
}
public String translate(String key) {
ContainerRequestContext requestContext = requestContextInstance.get();
Locale userLocale = (Locale) requestContext.getProperty("userLocale");
try {
ResourceBundle messages = ResourceBundle.getBundle("lang.messages", userLocale);
return messages.getString(key);
} catch (MissingResourceException e) {
try {
ResourceBundle fallbackMessages = ResourceBundle.getBundle("lang.messages", fallbackLocale);
return fallbackMessages.getString(key);
} catch (MissingResourceException ex) {
return key;
}
}
}
}

View File

@ -1,23 +0,0 @@
package fr.titionfire.ffsaf.domain.service;
import jakarta.enterprise.context.ApplicationScoped;
import java.util.HashMap;
@ApplicationScoped
public class UpdateService { // For public result page
static HashMap<Long, Long> lastUpdate = new HashMap<>();
public void setNewData(long id) {
lastUpdate.put(id, System.currentTimeMillis());
}
public boolean needUpdate(long id, long last_update) {
if (!lastUpdate.containsKey(id)) {
lastUpdate.put(id, System.currentTimeMillis() - 5000);
return true;
}
return lastUpdate.getOrDefault(id, 0L) > last_update;
}
}

View File

@ -1,28 +0,0 @@
package fr.titionfire.ffsaf.domain.service;
import io.quarkiverse.antivirus.runtime.Antivirus;
import io.quarkiverse.antivirus.runtime.AntivirusScanResult;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import java.io.InputStream;
import java.util.List;
@ApplicationScoped
public class VirusScannerService {
@Inject
Antivirus antivirus;
public Uni<List<AntivirusScanResult>> scanFileReactive(String fileName, InputStream inputStream) {
System.out.println("Starting reactive virus scan for file: " + fileName);
// Wrap the blocking antivirus scan in a reactive context
// This moves the blocking operation to a worker thread
return Uni.createFrom().item(() -> {
System.out.println("Scanning file on worker thread: " + fileName);
return antivirus.scan(fileName, inputStream);
}).runSubscriptionOn(io.smallrye.mutiny.infrastructure.Infrastructure.getDefaultWorkerPool());
}
}

View File

@ -49,7 +49,7 @@ public class AffiliationEndpoints {
@GET @GET
@Path("{id}") @Path("{id}")
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Renvoie les affiliations pour un club", description = "Cette méthode renvoie les affiliations pour un club donné. Seuls les administrateurs de la fédération et les présidents, secrétaires et responsables intranet du club peuvent accéder à cette méthode.") @Operation(summary = "Renvoie les affiliations pour un club", description = "Cette méthode renvoie les affiliations pour un club donné. Seuls les administrateurs de la fédération et les présidents, secrétaires et responsables intranet du club peuvent accéder à cette méthode.")
@APIResponses(value = { @APIResponses(value = {

View File

@ -73,7 +73,7 @@ public class AffiliationRequestEndpoints {
@GET @GET
@Path("/{id}") @Path("/{id}")
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Renvoie une demande d'affiliation", description = "Cette méthode renvoie une demande d'affiliation " + @Operation(summary = "Renvoie une demande d'affiliation", description = "Cette méthode renvoie une demande d'affiliation " +
"pour l'identifiant spécifié.") "pour l'identifiant spécifié.")
@ -92,7 +92,7 @@ public class AffiliationRequestEndpoints {
@DELETE @DELETE
@Path("/{id}") @Path("/{id}")
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Supprime une demande d'affiliation", description = "Cette méthode supprime une demande " + @Operation(summary = "Supprime une demande d'affiliation", description = "Cette méthode supprime une demande " +
"d'affiliation pour l'identifiant spécifié.") "d'affiliation pour l'identifiant spécifié.")
@ -128,7 +128,7 @@ public class AffiliationRequestEndpoints {
@PUT @PUT
@Path("/edit") @Path("/edit")
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
@Produces(MediaType.TEXT_PLAIN) @Produces(MediaType.TEXT_PLAIN)
@Consumes(MediaType.MULTIPART_FORM_DATA) @Consumes(MediaType.MULTIPART_FORM_DATA)
@Operation(summary = "Modifie une demande d'affiliation", description = "Cette méthode modifie une demande " + @Operation(summary = "Modifie une demande d'affiliation", description = "Cette méthode modifie une demande " +

View File

@ -1,12 +1,10 @@
package fr.titionfire.ffsaf.rest; package fr.titionfire.ffsaf.rest;
import fr.titionfire.ffsaf.domain.service.TradService;
import fr.titionfire.ffsaf.rest.client.SirenService; import fr.titionfire.ffsaf.rest.client.SirenService;
import fr.titionfire.ffsaf.rest.client.StateIdService; import fr.titionfire.ffsaf.rest.client.StateIdService;
import fr.titionfire.ffsaf.rest.data.AssoData; import fr.titionfire.ffsaf.rest.data.AssoData;
import fr.titionfire.ffsaf.rest.exception.DNotFoundException; import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.Uni;
import jakarta.inject.Inject;
import jakarta.ws.rs.*; import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MediaType;
import org.eclipse.microprofile.openapi.annotations.Operation; import org.eclipse.microprofile.openapi.annotations.Operation;
@ -21,9 +19,6 @@ public class AssoEndpoints {
@RestClient @RestClient
SirenService sirenService; SirenService sirenService;
@Inject
TradService trad;
@GET @GET
@Path("state_id/{stateId}") @Path("state_id/{stateId}")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@ -33,9 +28,9 @@ public class AssoEndpoints {
stateId).chain(stateIdService::getAssoDataFromUnit)).onFailure().transform(throwable -> { stateId).chain(stateIdService::getAssoDataFromUnit)).onFailure().transform(throwable -> {
if (throwable instanceof WebApplicationException exception) { if (throwable instanceof WebApplicationException exception) {
if (exception.getResponse().getStatus() == 404) if (exception.getResponse().getStatus() == 404)
return new DNotFoundException(trad.t("service.momentanement.indisponible")); return new DNotFoundException("Service momentanément indisponible");
if (exception.getResponse().getStatus() == 400) if (exception.getResponse().getStatus() == 400)
return new DNotFoundException(trad.t("asso.introuvable")); return new DNotFoundException("Asso introuvable");
} }
return throwable; return throwable;
}); });

View File

@ -3,11 +3,10 @@ package fr.titionfire.ffsaf.rest;
import fr.titionfire.ffsaf.data.model.ClubModel; import fr.titionfire.ffsaf.data.model.ClubModel;
import fr.titionfire.ffsaf.domain.service.ClubService; import fr.titionfire.ffsaf.domain.service.ClubService;
import fr.titionfire.ffsaf.domain.service.PDFService; import fr.titionfire.ffsaf.domain.service.PDFService;
import fr.titionfire.ffsaf.domain.service.TradService;
import fr.titionfire.ffsaf.domain.service.VirusScannerService;
import fr.titionfire.ffsaf.net2.data.SimpleClubModel; import fr.titionfire.ffsaf.net2.data.SimpleClubModel;
import fr.titionfire.ffsaf.rest.data.*; import fr.titionfire.ffsaf.rest.data.*;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException; import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.rest.exception.DInternalError;
import fr.titionfire.ffsaf.rest.from.FullClubForm; import fr.titionfire.ffsaf.rest.from.FullClubForm;
import fr.titionfire.ffsaf.rest.from.PartClubForm; import fr.titionfire.ffsaf.rest.from.PartClubForm;
import fr.titionfire.ffsaf.utils.Contact; import fr.titionfire.ffsaf.utils.Contact;
@ -48,15 +47,9 @@ public class ClubEndpoints {
@Inject @Inject
SecurityCtx securityCtx; SecurityCtx securityCtx;
@Inject
VirusScannerService scannerService;
@ConfigProperty(name = "upload_dir") @ConfigProperty(name = "upload_dir")
String media; String media;
@Inject
TradService trad;
Consumer<ClubModel> checkPerm = Unchecked.consumer(clubModel -> { Consumer<ClubModel> checkPerm = Unchecked.consumer(clubModel -> {
if (!securityCtx.roleHas("federation_admin") && !securityCtx.isInClubGroup(clubModel.getId())) if (!securityCtx.roleHas("federation_admin") && !securityCtx.isInClubGroup(clubModel.getId()))
throw new DForbiddenException(); throw new DForbiddenException();
@ -88,7 +81,7 @@ public class ClubEndpoints {
@Operation(summary = "Renvoie les types de contacts pour les clubs", description = "Renvoie la liste des types de " + @Operation(summary = "Renvoie les types de contacts pour les clubs", description = "Renvoie la liste des types de " +
"contacts possibles pour les clubs") "contacts possibles pour les clubs")
public Uni<HashMap<String, String>> getConcatType() { public Uni<HashMap<String, String>> getConcatType() {
return Uni.createFrom().item(Contact.toSite(trad)); return Uni.createFrom().item(Contact.toSite());
} }
@GET @GET
@ -116,7 +109,7 @@ public class ClubEndpoints {
@GET @GET
@Path("{id}") @Path("{id}")
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Renvoie les détails d'un club en fonction de son identifiant", description = "Renvoie les " + @Operation(summary = "Renvoie les détails d'un club en fonction de son identifiant", description = "Renvoie les " +
"détails d'un club en fonction de son identifiant, y compris les informations sur les membres et les affiliations") "détails d'un club en fonction de son identifiant, y compris les informations sur les membres et les affiliations")
@ -128,8 +121,9 @@ public class ClubEndpoints {
}) })
public Uni<SimpleClub> getById( public Uni<SimpleClub> getById(
@Parameter(description = "Identifiant de club") @PathParam("id") long id) { @Parameter(description = "Identifiant de club") @PathParam("id") long id) {
return clubService.getById(id).onItem().invoke(checkPerm).map(SimpleClub::fromModel) return clubService.getById(id).onItem().invoke(checkPerm).map(SimpleClub::fromModel).invoke(m -> {
.invoke(m -> m.setContactMap(Contact.toSite(trad))); m.setContactMap(Contact.toSite());
});
} }
@PUT @PUT
@ -151,9 +145,25 @@ public class ClubEndpoints {
return clubService.update(id, input) return clubService.update(id, input)
.invoke(Unchecked.consumer(out -> { .invoke(Unchecked.consumer(out -> {
if (!out.equals("OK")) throw new InternalError("Fail to update data: " + out); if (!out.equals("OK")) throw new InternalError("Fail to update data: " + out);
})) })).chain(() -> {
.chain(() -> Utils.uploadFile(scannerService, input.getLogo(), id, media, "ppClub")) if (input.getLogo().length > 0)
.chain(() -> Utils.uploadFile(scannerService, input.getStatus(), id, media, "clubStatus")); return Uni.createFrom().future(Utils.replacePhoto(id, input.getLogo(), media, "ppClub"
)).invoke(Unchecked.consumer(out -> {
if (!out.equals("OK"))
throw new DInternalError("Impossible de reconnaitre le fichier: " + out);
})); // TODO log
else
return Uni.createFrom().nullItem();
}).chain(() -> {
if (input.getStatus().length > 0)
return Uni.createFrom().future(Utils.replacePhoto(id, input.getStatus(), media, "clubStatus"
)).invoke(Unchecked.consumer(out -> {
if (!out.equals("OK"))
throw new DInternalError("Impossible de reconnaitre le fichier: " + out);
})); // TODO log
else
return Uni.createFrom().nullItem();
});
} }
@PUT @PUT
@ -171,9 +181,19 @@ public class ClubEndpoints {
return clubService.add(input) return clubService.add(input)
.invoke(Unchecked.consumer(id -> { .invoke(Unchecked.consumer(id -> {
if (id == null) throw new InternalError("Fail to create club data"); if (id == null) throw new InternalError("Fail to create club data");
})) })).call(id -> {
.call(id -> Utils.uploadFile(scannerService, input.getLogo(), id, media, "ppClub")) if (input.getLogo().length > 0)
.call(id -> Utils.uploadFile(scannerService, input.getStatus(), id, media, "clubStatus")); return Uni.createFrom().future(Utils.replacePhoto(id, input.getLogo(), media, "ppClub"
)); // TODO log
else
return Uni.createFrom().nullItem();
}).call(id -> {
if (input.getStatus().length > 0)
return Uni.createFrom().future(Utils.replacePhoto(id, input.getStatus(), media, "clubStatus"
)); // TODO log
else
return Uni.createFrom().nullItem();
});
} }
@DELETE @DELETE
@ -210,7 +230,7 @@ public class ClubEndpoints {
@GET @GET
@Path("/me") @Path("/me")
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Renvoie les informations du club de l'utilisateur connecté", description = "Renvoie les " + @Operation(summary = "Renvoie les informations du club de l'utilisateur connecté", description = "Renvoie les " +
"informations du club de l'utilisateur connecté") "informations du club de l'utilisateur connecté")
@ -222,12 +242,12 @@ public class ClubEndpoints {
}) })
public Uni<SimpleClub> getOfUser() { public Uni<SimpleClub> getOfUser() {
return clubService.getOfUser(securityCtx).map(SimpleClub::fromModel) return clubService.getOfUser(securityCtx).map(SimpleClub::fromModel)
.invoke(m -> m.setContactMap(Contact.toSite(trad))); .invoke(m -> m.setContactMap(Contact.toSite()));
} }
@PUT @PUT
@Path("/me") @Path("/me")
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.MULTIPART_FORM_DATA) @Consumes(MediaType.MULTIPART_FORM_DATA)
@Operation(summary = "Met à jour les informations du club de l'utilisateur connecté", description = "Met à jour les" + @Operation(summary = "Met à jour les informations du club de l'utilisateur connecté", description = "Met à jour les" +
@ -244,7 +264,7 @@ public class ClubEndpoints {
@GET @GET
@Path("/me/affiliation") @Path("/me/affiliation")
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
@Operation(summary = "Renvoie l'attestation d'affiliation du club de l'utilisateur connecté", description = @Operation(summary = "Renvoie l'attestation d'affiliation du club de l'utilisateur connecté", description =
"Renvoie l'attestation d'affiliation du club de l'utilisateur connecté") "Renvoie l'attestation d'affiliation du club de l'utilisateur connecté")
@APIResponses(value = { @APIResponses(value = {
@ -276,7 +296,7 @@ public class ClubEndpoints {
@GET @GET
@Path("/renew/{id}") @Path("/renew/{id}")
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Operation(hidden = true) @Operation(hidden = true)
public Uni<RenewAffData> getRenew(@PathParam("id") long id, @QueryParam("m1") long m1_id, public Uni<RenewAffData> getRenew(@PathParam("id") long id, @QueryParam("m1") long m1_id,
@ -287,7 +307,7 @@ public class ClubEndpoints {
@GET @GET
@Path("/desk/{id}") @Path("/desk/{id}")
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Renvoie la liste des membres du bureau du club", description = "Renvoie la liste des membres " + @Operation(summary = "Renvoie la liste des membres du bureau du club", description = "Renvoie la liste des membres " +
"du bureau du club spécifié") "du bureau du club spécifié")
@ -325,7 +345,7 @@ public class ClubEndpoints {
@GET @GET
@Path("{id}/status") @Path("{id}/status")
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
@Operation(summary = "Renvoie le statut du club", description = "Renvoie le statut du club spécifié") @Operation(summary = "Renvoie le statut du club", description = "Renvoie le statut du club spécifié")
@APIResponses(value = { @APIResponses(value = {
@APIResponse(responseCode = "200", description = "Le statut du club"), @APIResponse(responseCode = "200", description = "Le statut du club"),

View File

@ -1,7 +1,10 @@
package fr.titionfire.ffsaf.rest; package fr.titionfire.ffsaf.rest;
import fr.titionfire.ffsaf.domain.service.CompetitionService; import fr.titionfire.ffsaf.domain.service.CompetitionService;
import fr.titionfire.ffsaf.rest.data.*; import fr.titionfire.ffsaf.rest.data.CompetitionData;
import fr.titionfire.ffsaf.rest.data.RegisterRequestData;
import fr.titionfire.ffsaf.rest.data.SimpleCompetData;
import fr.titionfire.ffsaf.rest.data.SimpleRegisterComb;
import fr.titionfire.ffsaf.utils.SecurityCtx; import fr.titionfire.ffsaf.utils.SecurityCtx;
import io.quarkus.security.Authenticated; import io.quarkus.security.Authenticated;
import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.Uni;
@ -50,16 +53,6 @@ public class CompetitionEndpoints {
return service.addRegisterComb(securityCtx, id, data, source); return service.addRegisterComb(securityCtx, id, data, source);
} }
@POST
@Path("{id}/registers/{source}")
@Authenticated
@Produces(MediaType.APPLICATION_JSON)
@Operation(hidden = true)
public Uni<List<SimpleRegisterComb>> addRegistersComb(@PathParam("id") Long id, @PathParam("source") String source,
List<RegisterRequestData> data) {
return service.addRegistersComb(securityCtx, id, data, source);
}
@DELETE @DELETE
@Path("{id}/register/{comb_id}/{source}") @Path("{id}/register/{comb_id}/{source}")
@Authenticated @Authenticated
@ -78,21 +71,6 @@ public class CompetitionEndpoints {
return service.getSafcaData(securityCtx, id); return service.getSafcaData(securityCtx, id);
} }
@GET
@Path("{id}/internalData")
@Authenticated
@Produces(MediaType.APPLICATION_JSON)
public Uni<SimpleCompetData> getInternalData(@PathParam("id") Long id) {
return service.getInternalData(securityCtx, id);
}
@GET
@Path("{id}/categories")
@Authenticated
@Produces(MediaType.APPLICATION_JSON)
public Uni<List<PresetData>> getPresetsForCompetition(@PathParam("id") Long id) {
return service.getPresetsForCompetition(securityCtx, id);
}
@GET @GET
@Path("all") @Path("all")
@ -117,14 +95,6 @@ public class CompetitionEndpoints {
return service.setSafcaData(securityCtx, data); return service.setSafcaData(securityCtx, data);
} }
@POST
@Path("/internalData")
@Authenticated
@Produces(MediaType.APPLICATION_JSON)
public Uni<?> setInternalData(SimpleCompetData data) {
return service.setInternalData(securityCtx, data);
}
@DELETE @DELETE
@Path("{id}") @Path("{id}")
@Authenticated @Authenticated

View File

@ -37,7 +37,7 @@ public class CompteEndpoints {
@GET @GET
@Path("{id}") @Path("{id}")
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
@Operation(summary = "Renvoie les informations d'un compte utilisateur", description = "Renvoie les informations d'un" + @Operation(summary = "Renvoie les informations d'un compte utilisateur", description = "Renvoie les informations d'un" +
" compte utilisateur en fonction de son identifiant long (UUID)") " compte utilisateur en fonction de son identifiant long (UUID)")
@APIResponses(value = { @APIResponses(value = {

View File

@ -1,84 +0,0 @@
package fr.titionfire.ffsaf.rest;
import fr.titionfire.ffsaf.domain.service.ResultService;
import fr.titionfire.ffsaf.domain.service.UpdateService;
import io.smallrye.mutiny.Uni;
import jakarta.inject.Inject;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import java.util.HashMap;
@Path("api/public/result/{id}")
public class ExternalResultEndpoints {
@Inject
ResultService resultService;
@Inject
UpdateService updateService;
@PathParam("id")
private String id;
@GET
@Path("/poule/list")
@Produces(MediaType.APPLICATION_JSON)
public Uni<HashMap<String, Long>> list() {
return resultService.getCategoryList(id);
}
@GET
@Path("/poule/data")
@Produces(MediaType.APPLICATION_JSON)
public Uni<?> getArray(@QueryParam("poule") long poule, @DefaultValue("-1") @QueryParam("rf") long rf) {
if (poule == 0)
return Uni.createFrom().voidItem();
if (updateService.needUpdate(poule, rf)) {
return resultService.getCategory(id, poule);
} else {
return Uni.createFrom().voidItem();
}
}
@GET
@Path("/comb/list")
@Produces(MediaType.APPLICATION_JSON)
public Uni<HashMap<String, String>> combList() {
return resultService.getCombList(id);
}
@GET
@Path("/comb/data")
@Produces(MediaType.APPLICATION_JSON)
public Uni<?> getArray(@QueryParam("comb") String comb) {
if (comb.equals("0"))
return Uni.createFrom().item("");
return resultService.getCombArrayPublic(id, comb);
}
@GET
@Path("/comb/get_all")
@Produces(MediaType.APPLICATION_JSON)
public Uni<?> getAll() {
return resultService.getAllCombArrayPublic(id);
}
@GET
@Path("/club/list")
@Produces(MediaType.APPLICATION_JSON)
public Uni<HashMap<String, Long>> clubList() {
return resultService.getClubList(id);
}
@GET
@Path("/club/data")
@Produces(MediaType.APPLICATION_JSON)
public Uni<?> getClubArray(@QueryParam("club") long club) {
if (club == 0)
return Uni.createFrom().item("");
return resultService.getClubArray2(id, club, null);
}
}

View File

@ -36,7 +36,7 @@ public class LicenceEndpoints {
@GET @GET
@Path("{id}") @Path("{id}")
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Renvoie les licences d'un membre", description = "Renvoie les licences d'un membre en fonction " + @Operation(summary = "Renvoie les licences d'un membre", description = "Renvoie les licences d'un membre en fonction " +
"de son identifiant") "de son identifiant")
@ -68,7 +68,7 @@ public class LicenceEndpoints {
@GET @GET
@Path("current/club") @Path("current/club")
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Renvoie les licences de la saison en cours (pour les clubs)", description = "Renvoie les " + @Operation(summary = "Renvoie les licences de la saison en cours (pour les clubs)", description = "Renvoie les " +
"licences de la saison en cours (pour les clubs)") "licences de la saison en cours (pour les clubs)")
@ -83,7 +83,7 @@ public class LicenceEndpoints {
@POST @POST
@Path("pay") @Path("pay")
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Operation(summary = "Paiement des licence", description = "Retourne le lien de paiement pour les licence des membre fournie") @Operation(summary = "Paiement des licence", description = "Retourne le lien de paiement pour les licence des membre fournie")
@ -101,7 +101,7 @@ public class LicenceEndpoints {
@RolesAllowed("federation_admin") @RolesAllowed("federation_admin")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.MULTIPART_FORM_DATA) @Consumes(MediaType.MULTIPART_FORM_DATA)
@Operation(summary = "Créer une licence", description = "Créer une licence en fonction de son identifiant et des " + @Operation(summary = "Créer une licence", description = "Créer unr licence en fonction de son identifiant et des " +
"informations fournies dans le formulaire (pour les administrateurs)") "informations fournies dans le formulaire (pour les administrateurs)")
@APIResponses(value = { @APIResponses(value = {
@APIResponse(responseCode = "200", description = "La licence a été mise à jour avec succès"), @APIResponse(responseCode = "200", description = "La licence a été mise à jour avec succès"),
@ -118,7 +118,7 @@ public class LicenceEndpoints {
@RolesAllowed("federation_admin") @RolesAllowed("federation_admin")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Operation(summary = "Validation licence", description = "Valide en masse les licences de l'année en cours (pour les administrateurs)") @Operation(summary = "Validation licence", description = "Valide en masse les licence de l'année en cours (pour les administrateurs)")
@APIResponses(value = { @APIResponses(value = {
@APIResponse(responseCode = "200", description = "Les licences ont été mise à jour avec succès"), @APIResponse(responseCode = "200", description = "Les licences ont été mise à jour avec succès"),
@APIResponse(responseCode = "403", description = "Accès refusé"), @APIResponse(responseCode = "403", description = "Accès refusé"),
@ -128,21 +128,6 @@ public class LicenceEndpoints {
return licenceService.valideLicences(ids); return licenceService.valideLicences(ids);
} }
@POST
@Path("validate-pay")
@RolesAllowed("federation_admin")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Operation(summary = "Validation du payment des licences", description = "Valide en masse le payment des licences de l'année en cours (pour les administrateurs)")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "Les licences ont été mise à jour avec succès"),
@APIResponse(responseCode = "403", description = "Accès refusé"),
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
})
public Uni<?> validePaymentLicences(@Parameter(description = "Id des membres a valider") List<Long> ids) {
return licenceService.validePaymentLicences(ids);
}
@DELETE @DELETE
@Path("{id}") @Path("{id}")
@RolesAllowed("federation_admin") @RolesAllowed("federation_admin")
@ -161,7 +146,7 @@ public class LicenceEndpoints {
@POST @POST
@Path("club/{id}") @Path("club/{id}")
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.MULTIPART_FORM_DATA) @Consumes(MediaType.MULTIPART_FORM_DATA)
@Operation(summary = "Demande une nouvelle licence", description = "Demande une nouvelle licence en fonction de" + @Operation(summary = "Demande une nouvelle licence", description = "Demande une nouvelle licence en fonction de" +
@ -178,7 +163,7 @@ public class LicenceEndpoints {
@DELETE @DELETE
@Path("club/{id}") @Path("club/{id}")
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
@Produces(MediaType.TEXT_PLAIN) @Produces(MediaType.TEXT_PLAIN)
@Operation(summary = "Supprime une demande de licence", description = "Supprime une demande de licence en fonction " + @Operation(summary = "Supprime une demande de licence", description = "Supprime une demande de licence en fonction " +
"de son identifiant (pour les clubs)") "de son identifiant (pour les clubs)")

View File

@ -2,7 +2,6 @@ package fr.titionfire.ffsaf.rest;
import fr.titionfire.ffsaf.data.model.MembreModel; import fr.titionfire.ffsaf.data.model.MembreModel;
import fr.titionfire.ffsaf.domain.service.MembreService; import fr.titionfire.ffsaf.domain.service.MembreService;
import fr.titionfire.ffsaf.domain.service.VirusScannerService;
import fr.titionfire.ffsaf.rest.data.SimpleMembre; import fr.titionfire.ffsaf.rest.data.SimpleMembre;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException; import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.rest.exception.DInternalError; import fr.titionfire.ffsaf.rest.exception.DInternalError;
@ -22,7 +21,6 @@ import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses; import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
import org.eclipse.microprofile.openapi.annotations.tags.Tag; import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.jboss.logging.Logger;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -31,14 +29,10 @@ import java.util.function.Consumer;
@Path("api/member") @Path("api/member")
@RolesAllowed({"federation_admin"}) @RolesAllowed({"federation_admin"})
public class MembreAdminEndpoints { public class MembreAdminEndpoints {
private static final Logger LOGGER = Logger.getLogger(MembreAdminEndpoints.class);
@Inject @Inject
MembreService membreService; MembreService membreService;
@Inject
VirusScannerService scannerService;
@ConfigProperty(name = "upload_dir") @ConfigProperty(name = "upload_dir")
String media; String media;
@ -65,7 +59,6 @@ public class MembreAdminEndpoints {
@Parameter(description = "Text à rechercher") @QueryParam("search") String search, @Parameter(description = "Text à rechercher") @QueryParam("search") String search,
@Parameter(description = "Club à filter") @QueryParam("club") String club, @Parameter(description = "Club à filter") @QueryParam("club") String club,
@Parameter(description = "Catégorie à filter") @QueryParam("categorie") String categorie, @Parameter(description = "Catégorie à filter") @QueryParam("categorie") String categorie,
@Parameter(description = "Inclure les archive") @QueryParam("archive") Boolean archive,
@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 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 = "État du payment: 0 -> non payer, 1 -> payer, 2 -> tout") @QueryParam("payment") int payment,
@Parameter(description = "Ordre") @QueryParam("order") String order) { @Parameter(description = "Ordre") @QueryParam("order") String order) {
@ -73,8 +66,7 @@ public class MembreAdminEndpoints {
limit = 50; limit = 50;
if (page == null || page < 1) if (page == null || page < 1)
page = 1; page = 1;
return membreService.searchAdmin(limit, page - 1, search, club, licenceRequest, payment, order, return membreService.searchAdmin(limit, page - 1, search, club, licenceRequest, payment, order, categorie);
categorie, archive);
} }
@GET @GET
@ -103,8 +95,16 @@ public class MembreAdminEndpoints {
.invoke(Unchecked.consumer(out -> { .invoke(Unchecked.consumer(out -> {
if (!out.equals("OK")) if (!out.equals("OK"))
throw new DInternalError("Impossible de reconnaitre le fichier: " + out); throw new DInternalError("Impossible de reconnaitre le fichier: " + out);
})) })).chain(() -> {
.call(__ -> Utils.uploadFile(scannerService, input.getPhoto_data(), id, media, "ppMembre")); if (input.getPhoto_data().length > 0)
return Uni.createFrom().future(Utils.replacePhoto(id, input.getPhoto_data(), media, "ppMembre"
)).invoke(Unchecked.consumer(out -> {
if (!out.equals("OK"))
throw new DInternalError("Impossible de reconnaitre le fichier: " + out);
}));
else
return Uni.createFrom().nullItem();
});
} }
@POST @POST
@ -121,8 +121,13 @@ public class MembreAdminEndpoints {
return membreService.add(input) return membreService.add(input)
.invoke(Unchecked.consumer(id -> { .invoke(Unchecked.consumer(id -> {
if (id == null) throw new InternalError("Fail to creat member data"); if (id == null) throw new InternalError("Fail to creat member data");
})) })).call(id -> {
.call(id -> Utils.uploadFile(scannerService, input.getPhoto_data(), id, media, "ppMembre")); if (input.getPhoto_data().length > 0)
return Uni.createFrom().future(Utils.replacePhoto(id, input.getPhoto_data(), media, "ppMembre"
));
else
return Uni.createFrom().nullItem();
});
} }
@DELETE @DELETE

View File

@ -1,9 +1,9 @@
package fr.titionfire.ffsaf.rest; package fr.titionfire.ffsaf.rest;
import fr.titionfire.ffsaf.domain.service.MembreService; import fr.titionfire.ffsaf.domain.service.MembreService;
import fr.titionfire.ffsaf.domain.service.VirusScannerService;
import fr.titionfire.ffsaf.rest.data.SimpleMembre; import fr.titionfire.ffsaf.rest.data.SimpleMembre;
import fr.titionfire.ffsaf.rest.data.SimpleMembreInOutData; import fr.titionfire.ffsaf.rest.data.SimpleMembreInOutData;
import fr.titionfire.ffsaf.rest.exception.DInternalError;
import fr.titionfire.ffsaf.rest.from.FullMemberForm; import fr.titionfire.ffsaf.rest.from.FullMemberForm;
import fr.titionfire.ffsaf.utils.PageResult; import fr.titionfire.ffsaf.utils.PageResult;
import fr.titionfire.ffsaf.utils.SecurityCtx; import fr.titionfire.ffsaf.utils.SecurityCtx;
@ -24,7 +24,7 @@ import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import java.util.List; import java.util.List;
@Tag(name = "Membre club", description = "Gestion des membres (pour les clubs)") @Tag(name = "Membre club", description = "Gestion des membres (pour les clubs)")
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
@Path("api/member") @Path("api/member")
public class MembreClubEndpoints { public class MembreClubEndpoints {
@ -37,9 +37,6 @@ public class MembreClubEndpoints {
@Inject @Inject
SecurityCtx securityCtx; SecurityCtx securityCtx;
@Inject
VirusScannerService scannerService;
@GET @GET
@Path("/find/club") @Path("/find/club")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@ -54,7 +51,6 @@ public class MembreClubEndpoints {
@Parameter(description = "Page à consulter") @QueryParam("page") Integer page, @Parameter(description = "Page à consulter") @QueryParam("page") Integer page,
@Parameter(description = "Text à rechercher") @QueryParam("search") String search, @Parameter(description = "Text à rechercher") @QueryParam("search") String search,
@Parameter(description = "Catégorie à filter") @QueryParam("categorie") String categorie, @Parameter(description = "Catégorie à filter") @QueryParam("categorie") String categorie,
@Parameter(description = "Inclure les archive") @QueryParam("archive") Boolean archive,
@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 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) { @Parameter(description = "Ordre") @QueryParam("order") String order) {
@ -62,8 +58,7 @@ public class MembreClubEndpoints {
limit = 50; limit = 50;
if (page == null || page < 1) if (page == null || page < 1)
page = 1; page = 1;
return membreService.search(limit, page - 1, search, licenceRequest, payment, order, categorie, archive, return membreService.search(limit, page - 1, search, licenceRequest, payment, order, categorie, securityCtx.getSubject());
securityCtx.getSubject());
} }
@GET @GET
@ -111,7 +106,16 @@ public class MembreClubEndpoints {
return membreService.update(id, input, securityCtx) return membreService.update(id, input, securityCtx)
.invoke(Unchecked.consumer(out -> { .invoke(Unchecked.consumer(out -> {
if (!out.equals("OK")) throw new InternalError("Fail to update data: " + out); if (!out.equals("OK")) throw new InternalError("Fail to update data: " + out);
})).chain(() -> Utils.uploadFile(scannerService, input.getPhoto_data(), id, media, "ppMembre")); })).chain(() -> {
if (input.getPhoto_data().length > 0)
return Uni.createFrom().future(Utils.replacePhoto(id, input.getPhoto_data(), media, "ppMembre"
)).invoke(Unchecked.consumer(out -> {
if (!out.equals("OK"))
throw new DInternalError("Impossible de reconnaitre le fichier: " + out);
}));
else
return Uni.createFrom().nullItem();
});
} }
@POST @POST
@ -129,7 +133,13 @@ public class MembreClubEndpoints {
return membreService.add(input, securityCtx.getSubject()) return membreService.add(input, securityCtx.getSubject())
.invoke(Unchecked.consumer(id -> { .invoke(Unchecked.consumer(id -> {
if (id == null) throw new InternalError("Fail to creat member data"); if (id == null) throw new InternalError("Fail to creat member data");
})).call(id -> Utils.uploadFile(scannerService, input.getPhoto_data(), id, media, "ppMembre")); })).call(id -> {
if (input.getPhoto_data().length > 0)
return Uni.createFrom().future(Utils.replacePhoto(id, input.getPhoto_data(), media, "ppMembre"
));
else
return Uni.createFrom().nullItem();
});
} }
@DELETE @DELETE

View File

@ -6,7 +6,6 @@ import fr.titionfire.ffsaf.domain.service.PDFService;
import fr.titionfire.ffsaf.rest.data.MeData; import fr.titionfire.ffsaf.rest.data.MeData;
import fr.titionfire.ffsaf.rest.data.SimpleMembre; import fr.titionfire.ffsaf.rest.data.SimpleMembre;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException; import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.rest.from.UserSettingForm;
import fr.titionfire.ffsaf.utils.SecurityCtx; import fr.titionfire.ffsaf.utils.SecurityCtx;
import fr.titionfire.ffsaf.utils.Utils; import fr.titionfire.ffsaf.utils.Utils;
import io.quarkus.security.Authenticated; import io.quarkus.security.Authenticated;
@ -52,7 +51,7 @@ public class MembreEndpoints {
@GET @GET
@Path("{id}") @Path("{id}")
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Renvoie les détails d'un membre en fonction de son identifiant", description = "Renvoie les " + @Operation(summary = "Renvoie les détails d'un membre en fonction de son identifiant", description = "Renvoie les " +
"détails d'un membre en fonction de son identifiant") "détails d'un membre en fonction de son identifiant")
@ -69,7 +68,7 @@ public class MembreEndpoints {
@GET @GET
@Path("/find/licence") @Path("/find/licence")
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
@Operation(summary = "Renvoie les détails d'un membre en fonction de son numéro de licence", description = "Renvoie " + @Operation(summary = "Renvoie les détails d'un membre en fonction de son numéro de licence", description = "Renvoie " +
"les détails d'un membre en fonction de son numéro de licence") "les détails d'un membre en fonction de son numéro de licence")
@APIResponses(value = { @APIResponses(value = {
@ -114,21 +113,6 @@ public class MembreEndpoints {
return pdfService.getLicencePdf(securityCtx.getSubject()); return pdfService.getLicencePdf(securityCtx.getSubject());
} }
@PUT
@Path("me/setting")
@Authenticated
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_PLAIN)
@Operation(summary = "Met à jour les paramètres du membre connecté", description = "Met à jour les paramètres du membre connecté")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "Les paramètres ont été mis à jour"),
@APIResponse(responseCode = "403", description = "Accès refusé"),
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
})
public Uni<Void> updateMeSettings(UserSettingForm settingForm) {
return membreService.updateSettings(securityCtx.getSubject(), settingForm);
}
@GET @GET
@Path("me/photo") @Path("me/photo")
@Authenticated @Authenticated
@ -146,7 +130,7 @@ public class MembreEndpoints {
@GET @GET
@Path("{id}/photo") @Path("{id}/photo")
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
@Operation(summary = "Renvoie la photo d'un membre", description = "Renvoie la photo d'un membre en fonction de son identifiant") @Operation(summary = "Renvoie la photo d'un membre", description = "Renvoie la photo d'un membre en fonction de son identifiant")
@APIResponses(value = { @APIResponses(value = {
@APIResponse(responseCode = "200", description = "La photo du membre"), @APIResponse(responseCode = "200", description = "La photo du membre"),
@ -162,7 +146,7 @@ public class MembreEndpoints {
@GET @GET
@Path("{id}/licence") @Path("{id}/licence")
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"}) @RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
@Operation(summary = "Renvoie le pdf de la licence d'un membre", description = "Renvoie le pdf de la licence d'un membre en fonction de son identifiant") @Operation(summary = "Renvoie le pdf de la licence d'un membre", description = "Renvoie le pdf de la licence d'un membre en fonction de son identifiant")
@APIResponses(value = { @APIResponses(value = {
@APIResponse(responseCode = "200", description = "Le pdf de la licence"), @APIResponse(responseCode = "200", description = "Le pdf de la licence"),

View File

@ -10,7 +10,6 @@ import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path; import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam; import jakarta.ws.rs.PathParam;
import java.util.HashMap;
import java.util.List; import java.util.List;
@Authenticated @Authenticated
@ -30,39 +29,15 @@ public class ResultEndpoints {
} }
@GET @GET
@Path("{uuid}/category/list") @Path("{uuid}")
public Uni<HashMap<String, Long>> getCategoryList(@PathParam("uuid") String uuid) { public Uni<List<ResultCategoryData>> getCategory(@PathParam("uuid") String uuid) {
return resultService.getCategoryList(uuid, securityCtx); return resultService.getCategory(uuid, securityCtx);
} }
@GET @GET
@Path("{uuid}/category/{id}") @Path("{uuid}/club")
public Uni<ResultCategoryData> getCategory(@PathParam("uuid") String uuid, @PathParam("id") long id) { public Uni<ResultService.ClubArrayData> getClub(@PathParam("uuid") String uuid) {
return resultService.getCategory(uuid, id, securityCtx); return resultService.getClubArray(uuid, securityCtx);
}
@GET
@Path("{uuid}/club/list")
public Uni<HashMap<String, Long>> getClubList(@PathParam("uuid") String uuid) {
return resultService.getClubList(uuid, securityCtx);
}
@GET
@Path("{uuid}/club/{id}")
public Uni<ResultService.ClubArrayData> getClub(@PathParam("uuid") String uuid, @PathParam("id") long id) {
return resultService.getClubArray(uuid, id, securityCtx);
}
@GET
@Path("{uuid}/comb/list")
public Uni<HashMap<String, String>> getCombList(@PathParam("uuid") String uuid) {
return resultService.getCombList(uuid, securityCtx);
}
@GET
@Path("{uuid}/comb/{id}")
public Uni<?> getCombList(@PathParam("uuid") String uuid, @PathParam("id") String id) {
return resultService.getCombArrayPublic(uuid, id, securityCtx);
} }
@GET @GET

View File

@ -1,85 +0,0 @@
package fr.titionfire.ffsaf.rest;
import fr.titionfire.ffsaf.data.model.MembreModel;
import fr.titionfire.ffsaf.domain.service.SelectionService;
import fr.titionfire.ffsaf.rest.data.SimpleSelection;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.utils.SecurityCtx;
import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.unchecked.Unchecked;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Inject;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
import java.util.List;
import java.util.function.Consumer;
@Path("api/selection")
public class SelectionEndpoints {
@Inject
SelectionService selectionService;
@Inject
SecurityCtx securityCtx;
Consumer<MembreModel> checkPerm = Unchecked.consumer(membreModel -> {
if (!securityCtx.roleHas("federation_admin") && !securityCtx.isInClubGroup(membreModel.getClub().getId()))
throw new DForbiddenException();
});
@GET
@Path("{id}")
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra",
"ffsaf_selectionneur"})
@Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Renvoie les séléctions d'un membre", description = "Renvoie les séléctions d'un membre en fonction " +
"de son identifiant")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "La liste des séléctions du membre"),
@APIResponse(responseCode = "403", description = "Accès refusé"),
@APIResponse(responseCode = "404", description = "Le membre n'existe pas"),
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
})
public Uni<List<SimpleSelection>> getSelection(@PathParam("id") long id) {
return selectionService.getSelection(id, checkPerm)
.map(selectionModels -> selectionModels.stream().map(SimpleSelection::fromModel).toList());
}
@POST
@Path("{id}")
@RolesAllowed({"federation_admin", "ffsaf_selectionneur"})
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Operation(summary = "Créer une séléction", description = "Créer une séléction en fonction de son identifiant et des " +
"informations fournies dans le formulaire (pour les administrateurs)")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "La séléction a été mise à jour avec succès"),
@APIResponse(responseCode = "403", description = "Accès refusé"),
@APIResponse(responseCode = "404", description = "La séléction n'existe pas"),
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
})
public Uni<SimpleSelection> setSelection(@PathParam("id") long id, SimpleSelection data) {
return selectionService.setSelection(id, data).map(SimpleSelection::fromModel);
}
@DELETE
@Path("{id}")
@RolesAllowed({"federation_admin", "ffsaf_selectionneur"})
@Produces(MediaType.TEXT_PLAIN)
@Operation(summary = "Supprime une séléction", description = "Supprime une séléction en fonction de son identifiant " +
"(pour les administrateurs)")
@APIResponses(value = {
@APIResponse(responseCode = "204", description = "La séléction a été supprimée avec succès"),
@APIResponse(responseCode = "403", description = "Accès refusé"),
@APIResponse(responseCode = "404", description = "La séléction n'existe pas"),
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
})
public Uni<?> deleteSelection(@PathParam("id") long id) {
return selectionService.deleteSelection(id);
}
}

View File

@ -1,6 +1,5 @@
package fr.titionfire.ffsaf.rest.data; package fr.titionfire.ffsaf.rest.data;
import fr.titionfire.ffsaf.data.model.CatPresetModel;
import fr.titionfire.ffsaf.data.model.CompetitionGuestModel; import fr.titionfire.ffsaf.data.model.CompetitionGuestModel;
import fr.titionfire.ffsaf.data.model.CompetitionModel; import fr.titionfire.ffsaf.data.model.CompetitionModel;
import fr.titionfire.ffsaf.data.model.RegisterModel; import fr.titionfire.ffsaf.data.model.RegisterModel;
@ -11,7 +10,6 @@ import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -35,23 +33,12 @@ public class CompetitionData {
private Long club; private Long club;
private String clubName; private String clubName;
private String owner; private String owner;
private List<SimpleRegister> registers; // for SAFCA private List<SimpleRegister> registers;
private boolean canEdit; private boolean canEdit;
private boolean canEditRegisters;
private String data1; private String data1;
private String data2; private String data2;
private String data3; private String data3;
private String data4; private String data4;
private String config;
private List<PresetData> presets;
private List<Categorie> requiredWeight;
public CompetitionData() {
this(null, "", "", "", "", new Date(), new Date(),
CompetitionSystem.INTERNAL, RegisterMode.FREE, new Date(), new Date(), true,
null, "", "", null, true, true,
"", "", "", "", "{}", new ArrayList<>(), new ArrayList<>());
}
public static CompetitionData fromModel(CompetitionModel model) { public static CompetitionData fromModel(CompetitionModel model) {
if (model == null) if (model == null)
@ -60,9 +47,8 @@ public class CompetitionData {
return new CompetitionData(model.getId(), model.getName(), model.getDescription(), model.getAdresse(), return new CompetitionData(model.getId(), model.getName(), model.getDescription(), model.getAdresse(),
model.getUuid(), model.getDate(), model.getTodate(), model.getSystem(), model.getUuid(), model.getDate(), model.getTodate(), model.getSystem(),
model.getRegisterMode(), model.getStartRegister(), model.getEndRegister(), model.isPublicVisible(), model.getRegisterMode(), model.getStartRegister(), model.getEndRegister(), model.isPublicVisible(),
model.getClub().getId(), model.getClub().getName(), model.getOwner(), null, false, false, model.getClub().getId(), model.getClub().getName(), model.getOwner(), null, false,
model.getData1(), model.getData2(), model.getData3(), model.getData4(), model.getConfig(), model.getData1(), model.getData2(), model.getData3(), model.getData4());
new ArrayList<>(), model.getRequiredWeight());
} }
public static CompetitionData fromModelLight(CompetitionModel model) { public static CompetitionData fromModelLight(CompetitionModel model) {
@ -72,35 +58,29 @@ public class CompetitionData {
CompetitionData out = new CompetitionData(model.getId(), model.getName(), model.getDescription(), CompetitionData out = new CompetitionData(model.getId(), model.getName(), model.getDescription(),
model.getAdresse(), "", model.getDate(), model.getTodate(), null, model.getAdresse(), "", model.getDate(), model.getTodate(), null,
model.getRegisterMode(), model.getStartRegister(), model.getEndRegister(), model.isPublicVisible(), model.getRegisterMode(), model.getStartRegister(), model.getEndRegister(), model.isPublicVisible(),
null, model.getClub().getName(), "", null, false, false, null, model.getClub().getName(), "", null, false,
"", "", "", "", "{}", new ArrayList<>(), model.getRequiredWeight()); "", "", "", "");
if (model.getRegisterMode() == RegisterMode.HELLOASSO) { if (model.getRegisterMode() == RegisterMode.HELLOASSO) {
out.setData1(model.getData1()); out.setData1(model.getData1());
out.setData2(model.getData2()); out.setData2(model.getData2());
} }
return out; return out;
} }
public CompetitionData addInsc(List<RegisterModel> insc, List<CompetitionGuestModel> guests) { public CompetitionData addInsc(List<RegisterModel> insc, List<CompetitionGuestModel> guests) {
this.registers = Stream.concat( this.registers = Stream.concat(
insc.stream() insc.stream()
.map(i -> new SimpleRegister(i.getMembre().getId(), i.getOverCategory(), i.getWeight2(), .map(i -> new SimpleRegister(i.getMembre().getId(), i.getOverCategory(), i.getWeight(),
i.getCategorie(), (i.getClub() == null) ? null : i.getClub().getId(), i.getCategorie(), (i.getClub() == null) ? null : i.getClub().getId(),
(i.getClub() == null) ? null : i.getClub().getName())), (i.getClub() == null) ? null : i.getClub().getName())),
guests.stream() guests.stream()
.map(i -> new SimpleRegister(i.getId() * -1, 0, i.getWeight2(), .map(i -> new SimpleRegister(i.getId() * -1, 0, i.getWeight(),
i.getCategorie(), null, i.getClub()))).toList(); i.getCategorie(), null, i.getClub()))).toList();
return this; return this;
} }
public CompetitionData addPresets(List<CatPresetModel> presets) {
this.presets = presets.stream().map(PresetData::fromModel).toList();
return this;
}
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@RegisterForReflection @RegisterForReflection

View File

@ -1,8 +1,6 @@
package fr.titionfire.ffsaf.rest.data; package fr.titionfire.ffsaf.rest.data;
import fr.titionfire.ffsaf.data.model.MembreModel; import fr.titionfire.ffsaf.data.model.MembreModel;
import fr.titionfire.ffsaf.domain.service.TradService;
import fr.titionfire.ffsaf.utils.ResultPrivacy;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@ -17,50 +15,45 @@ import java.util.List;
@NoArgsConstructor @NoArgsConstructor
@RegisterForReflection @RegisterForReflection
public class MeData { public class MeData {
@Schema(description = "L'identifiant du membre.", examples = "1") @Schema(description = "L'identifiant du membre.", example = "1")
private long id; private long id;
@Schema(description = "Le nom du membre.", examples = "Dupont") @Schema(description = "Le nom du membre.", example = "Dupont")
private String lname = ""; private String lname = "";
@Schema(description = "Le prénom du membre.", examples = "Jean") @Schema(description = "Le prénom du membre.", example = "Jean")
private String fname = ""; private String fname = "";
@Schema(description = "La catégorie du membre.", examples = "SENIOR") @Schema(description = "La catégorie du membre.", example = "SENIOR")
private String categorie; private String categorie;
@Schema(description = "Le nom du club du membre.", examples = "Association sportive") @Schema(description = "Le nom du club du membre.", example = "Association sportive")
private String club; private String club;
@Schema(description = "Le genre du membre.", examples = "Homme") @Schema(description = "Le genre du membre.", example = "Homme")
private String genre; private String genre;
@Schema(description = "Le numéro de licence du membre.", examples = "12345") @Schema(description = "Le numéro de licence du membre.", example = "12345")
private int licence; private int licence;
@Schema(description = "Le pays du membre.", examples = "FR") @Schema(description = "Le pays du membre.", example = "FR")
private String country; private String country;
@Schema(description = "La date de naissance du membre.") @Schema(description = "La date de naissance du membre.")
private Date birth_date; private Date birth_date;
@Schema(description = "L'adresse e-mail du membre.", examples = "jean.dupont@examples.com") @Schema(description = "L'adresse e-mail du membre.", example = "jean.dupont@example.com")
private String email; private String email;
@Schema(description = "Le rôle du membre dans l'association.", examples = "MEMBRE") @Schema(description = "Le rôle du membre dans l'association.", example = "MEMBRE")
private String role; private String role;
@Schema(description = "Le grade d'arbitrage du membre.", examples = "N/A") @Schema(description = "Le grade d'arbitrage du membre.", example = "N/A")
private String grade_arbitrage; private String grade_arbitrage;
@Schema(description = "La confidentialité des résultats", examples = "PUBLIC")
private ResultPrivacy resultPrivacy;
@Schema(description = "La liste des licences du membre.") @Schema(description = "La liste des licences du membre.")
private List<SimpleLicence> licences; private List<SimpleLicence> licences;
@Schema(description = "La liste des séléctions du membre.")
private List<SimpleSelection> selections;
public void setMembre(MembreModel membreModel, TradService trad) { public void setMembre(MembreModel membreModel) {
this.id = membreModel.getId(); this.id = membreModel.getId();
this.lname = membreModel.getLname(); this.lname = membreModel.getLname();
this.fname = membreModel.getFname(); this.fname = membreModel.getFname();
this.categorie = membreModel.getCategorie() == null ? trad.t("categorie.inconnue") : membreModel.getCategorie().getName(trad); this.categorie = membreModel.getCategorie().getName();
this.club = membreModel.getClub() == null ? trad.t("sans.club") : membreModel.getClub().getName(); this.club = membreModel.getClub() == null ? "Sans club" : membreModel.getClub().getName();
this.genre = membreModel.getGenre().getString(trad); this.genre = membreModel.getGenre().str;
this.licence = membreModel.getLicence(); this.licence = membreModel.getLicence();
this.country = membreModel.getCountry(); this.country = membreModel.getCountry();
this.birth_date = membreModel.getBirth_date(); this.birth_date = membreModel.getBirth_date();
this.email = membreModel.getEmail(); this.email = membreModel.getEmail();
this.role = membreModel.getRole().getString(trad); this.role = membreModel.getRole().str;
this.grade_arbitrage = membreModel.getGrade_arbitrage().getString(trad); this.grade_arbitrage = membreModel.getGrade_arbitrage().str;
this.resultPrivacy = membreModel.getResultPrivacy();
} }
} }

View File

@ -1,29 +0,0 @@
package fr.titionfire.ffsaf.rest.data;
import fr.titionfire.ffsaf.data.model.CatPresetModel;
import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;
@Data
@AllArgsConstructor
@RegisterForReflection
public class PresetData {
private Long id;
private String name;
private CatPresetModel.SwordType sword;
private CatPresetModel.ShieldType shield;
private List<CatPresetModel.CategorieEmbeddable> categories;
private int mandatoryProtection1;
private int mandatoryProtection2;
public static PresetData fromModel(CatPresetModel model) {
if (model == null)
return null;
return new PresetData(model.getId(), model.getName(), model.getSwordType(), model.getShieldType(),
model.getCategories(), model.getMandatoryProtection1(), model.getMandatoryProtection2());
}
}

View File

@ -7,8 +7,6 @@ import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.util.List;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
@ -19,10 +17,8 @@ public class RegisterRequestData {
private String lname; private String lname;
private Integer weight; private Integer weight;
private Integer weightReal; private int overCategory;
private Integer overCategory;
private boolean lockEdit = false; private boolean lockEdit = false;
private List<Long> categoriesInscrites;
// for guest registration only // for guest registration only
private Long id = null; private Long id = null;
@ -30,6 +26,4 @@ public class RegisterRequestData {
private Genre genre = Genre.NA; private Genre genre = Genre.NA;
private String club = null; private String club = null;
private String country = null; private String country = null;
private boolean quick = false;
} }

View File

@ -1,8 +1,6 @@
package fr.titionfire.ffsaf.rest.data; package fr.titionfire.ffsaf.rest.data;
import fr.titionfire.ffsaf.data.model.MembreModel; import fr.titionfire.ffsaf.data.model.MatchModel;
import fr.titionfire.ffsaf.domain.entity.MatchModelExtend;
import fr.titionfire.ffsaf.utils.ResultPrivacy;
import fr.titionfire.ffsaf.utils.ScoreEmbeddable; import fr.titionfire.ffsaf.utils.ScoreEmbeddable;
import fr.titionfire.ffsaf.utils.TreeNode; import fr.titionfire.ffsaf.utils.TreeNode;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
@ -11,7 +9,6 @@ import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -24,8 +21,6 @@ public class ResultCategoryData {
HashMap<Character, List<PouleArrayData>> matchs = new HashMap<>(); HashMap<Character, List<PouleArrayData>> matchs = new HashMap<>();
HashMap<Character, List<RankArray>> rankArray = new HashMap<>(); HashMap<Character, List<RankArray>> rankArray = new HashMap<>();
ArrayList<TreeNode<TreeData>> trees; ArrayList<TreeNode<TreeData>> trees;
String[] liceName;
long genTime;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@ -33,7 +28,6 @@ public class ResultCategoryData {
public static class RankArray { public static class RankArray {
int rank; int rank;
String name; String name;
int score;
int win; int win;
int pointMake; int pointMake;
int pointTake; int pointTake;
@ -41,29 +35,25 @@ public class ResultCategoryData {
} }
@RegisterForReflection @RegisterForReflection
public record PouleArrayData(String red, boolean red_w, List<Integer[]> score, boolean blue_w, String blue, public record PouleArrayData(String red, boolean red_w, List<Integer[]> score, boolean blue_w, String blue, boolean end) {
boolean eq, boolean end, Date date) { public static PouleArrayData fromModel(MatchModel matchModel) {
public static PouleArrayData fromModel(MatchModelExtend matchModel, MembreModel membreModel, ResultPrivacy privacy) {
return new PouleArrayData( return new PouleArrayData(
matchModel.getC1Name(membreModel, privacy), matchModel.getC1Name(),
matchModel.isEnd() && matchModel.getWin() > 0, matchModel.isEnd() && matchModel.win() > 0,
matchModel.isEnd() ? matchModel.isEnd() ?
matchModel.getScoresToPrint().stream().map(s -> new Integer[]{s.getS1(), s.getS2()}).toList() matchModel.getScores().stream().map(s -> new Integer[]{s.getS1(), s.getS2()}).toList()
: new ArrayList<>(), : new ArrayList<>(),
matchModel.isEnd() && matchModel.getWin() < 0, matchModel.isEnd() && matchModel.win() < 0,
matchModel.getC2Name(membreModel, privacy), matchModel.getC2Name(),
matchModel.isEnd() && matchModel.getWin() == 0, matchModel.isEnd());
matchModel.isEnd(),
matchModel.getDate());
} }
} }
@RegisterForReflection @RegisterForReflection
public static record TreeData(long id, String c1FullName, String c2FullName, List<ScoreEmbeddable> scores, public static record TreeData(long id, String c1FullName, String c2FullName, List<ScoreEmbeddable> scores,
boolean end, int win) { boolean end) {
public static TreeData from(MatchModelExtend match, MembreModel membreModel, ResultPrivacy privacy) { public static TreeData from(MatchModel match) {
return new TreeData(match.getId(), match.getC1Name(membreModel, privacy), return new TreeData(match.getId(), match.getC1Name(), match.getC2Name(), match.getScores(), match.isEnd());
match.getC2Name(membreModel, privacy), match.getScoresToPrint(), match.isEnd(), match.getWin());
} }
} }
} }

View File

@ -1,9 +1,5 @@
package fr.titionfire.ffsaf.rest.data; package fr.titionfire.ffsaf.rest.data;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import fr.titionfire.ffsaf.data.model.CompetitionModel;
import fr.titionfire.ffsaf.net2.data.SimpleCompet; import fr.titionfire.ffsaf.net2.data.SimpleCompet;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@ -29,41 +25,4 @@ public class SimpleCompetData {
return new SimpleCompetData(compet.id(), compet.show_blason(), compet.show_flag(), return new SimpleCompetData(compet.id(), compet.show_blason(), compet.show_flag(),
new ArrayList<>(), new ArrayList<>()); new ArrayList<>(), new ArrayList<>());
} }
public static SimpleCompetData fromModel(CompetitionModel competitionModel) {
if (competitionModel == null)
return null;
boolean show_blason = true;
boolean show_flag = false;
if (competitionModel.getConfig() != null) {
try {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode = objectMapper.readTree(competitionModel.getConfig());
if (rootNode.has("show_blason"))
show_blason = rootNode.get("show_blason").asBoolean();
if (rootNode.has("show_flag"))
show_flag = rootNode.get("show_flag").asBoolean();
} catch (JsonProcessingException ignored) {
}
}
return new SimpleCompetData(competitionModel.getId(), show_blason, show_flag,
new ArrayList<>(), new ArrayList<>());
}
public String getConfigForInternal(){
ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode = objectMapper.createObjectNode()
.put("show_blason", this.show_blason)
.put("show_flag", this.show_flag);
try {
return objectMapper.writeValueAsString(rootNode);
} catch (JsonProcessingException e) {
return "{}";
}
}
} }

View File

@ -19,32 +19,34 @@ import java.util.Date;
@AllArgsConstructor @AllArgsConstructor
@RegisterForReflection @RegisterForReflection
public class SimpleMembre { public class SimpleMembre {
@Schema(description = "L'identifiant du membre.", examples = "1") @Schema(description = "L'identifiant du membre.", example = "1")
private long id; private long id;
@Schema(description = "L'identifiant long du membre (userID).", examples = "e81d1d35-d897-421e-8086-6c5e74d13c6e") @Schema(description = "L'identifiant long du membre (userID).", example = "e81d1d35-d897-421e-8086-6c5e74d13c6e")
private String userId; private String userId;
@Schema(description = "Le nom du membre.", examples = "Dupont") @Schema(description = "Le nom du membre.", example = "Dupont")
private String lname = ""; private String lname = "";
@Schema(description = "Le prénom du membre.", examples = "Jean") @Schema(description = "Le prénom du membre.", example = "Jean")
private String fname = ""; private String fname = "";
@Schema(description = "La catégorie du membre.", examples = "SENIOR") @Schema(description = "La catégorie du membre.", example = "SENIOR")
private Categorie categorie; private Categorie categorie;
@Schema(description = "Le club du membre.") @Schema(description = "Le club du membre.")
private SimpleClubModel club; private SimpleClubModel club;
@Schema(description = "Le genre du membre.", examples = "H") @Schema(description = "Le genre du membre.", example = "H")
private Genre genre; private Genre genre;
@Schema(description = "Le numéro de licence du membre.", examples = "12345") @Schema(description = "Le numéro de licence du membre.", example = "12345")
private Integer licence; private Integer licence;
@Schema(description = "Le pays du membre.", examples = "FR") @Schema(description = "Le pays du membre.", example = "FR")
private String country; private String country;
@Schema(description = "La date de naissance du membre.") @Schema(description = "La date de naissance du membre.")
private Date birth_date; private Date birth_date;
@Schema(description = "L'adresse e-mail du membre.", examples = "jean.dupont@examples.com") @Schema(description = "L'adresse e-mail du membre.", example = "jean.dupont@example.com")
private String email; private String email;
@Schema(description = "Le rôle du membre dans l'association.", examples = "MEMBRE") @Schema(description = "Le rôle du membre dans l'association.", example = "MEMBRE")
private RoleAsso role; private RoleAsso role;
@Schema(description = "Le grade d'arbitrage du membre.", examples = "N/A") @Schema(description = "Le grade d'arbitrage du membre.", example = "N/A")
private GradeArbitrage grade_arbitrage; private GradeArbitrage grade_arbitrage;
@Schema(hidden = true)
private String url_photo;
public static SimpleMembre fromModel(MembreModel model) { public static SimpleMembre fromModel(MembreModel model) {
if (model == null) if (model == null)
@ -64,6 +66,7 @@ public class SimpleMembre {
.email(model.getEmail()) .email(model.getEmail())
.role(model.getRole()) .role(model.getRole())
.grade_arbitrage(model.getGrade_arbitrage()) .grade_arbitrage(model.getGrade_arbitrage())
.url_photo(model.getUrl_photo())
.build(); .build();
} }
} }

View File

@ -1,6 +1,9 @@
package fr.titionfire.ffsaf.rest.data; package fr.titionfire.ffsaf.rest.data;
import fr.titionfire.ffsaf.data.model.*; 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.net2.data.SimpleClubModel;
import fr.titionfire.ffsaf.utils.Categorie; import fr.titionfire.ffsaf.utils.Categorie;
import fr.titionfire.ffsaf.utils.Genre; import fr.titionfire.ffsaf.utils.Genre;
@ -8,14 +11,11 @@ import fr.titionfire.ffsaf.utils.Utils;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List; import java.util.List;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor
@RegisterForReflection @RegisterForReflection
public class SimpleRegisterComb { public class SimpleRegisterComb {
private long id; private long id;
@ -27,11 +27,9 @@ public class SimpleRegisterComb {
private SimpleClubModel club; private SimpleClubModel club;
private Integer licence; private Integer licence;
private Integer weight; private Integer weight;
private Integer weightReal;
private int overCategory; private int overCategory;
private boolean hasLicenceActive; private boolean hasLicenceActive;
private boolean lockEdit; private boolean lockEdit;
private List<Long> categoriesInscrites;
public static SimpleRegisterComb fromModel(RegisterModel register, List<LicenceModel> licences) { public static SimpleRegisterComb fromModel(RegisterModel register, List<LicenceModel> licences) {
MembreModel membreModel = register.getMembre(); MembreModel membreModel = register.getMembre();
@ -39,21 +37,15 @@ public class SimpleRegisterComb {
membreModel.getGenre(), membreModel.getCountry(), membreModel.getGenre(), membreModel.getCountry(),
(register.getCategorie() == null) ? null : register.getCategorie(), (register.getCategorie() == null) ? null : register.getCategorie(),
SimpleClubModel.fromModel(register.getClub()), membreModel.getLicence(), register.getWeight(), SimpleClubModel.fromModel(register.getClub()), membreModel.getLicence(), register.getWeight(),
register.getWeightReal(), register.getOverCategory(), register.getOverCategory(),
licences.stream().anyMatch(l -> l.isValidate() && l.getSaison() == Utils.getSaison()), licences.stream().anyMatch(l -> l.isValidate() && l.getSaison() == Utils.getSaison()),
register.isLockEdit(), new ArrayList<>()); register.isLockEdit());
} }
public static SimpleRegisterComb fromModel(CompetitionGuestModel guest) { public static SimpleRegisterComb fromModel(CompetitionGuestModel guest) {
return new SimpleRegisterComb(guest.getId() * -1, guest.getFname(), guest.getLname(), return new SimpleRegisterComb(guest.getId() * -1, guest.getFname(), guest.getLname(),
guest.getGenre(), guest.getCountry(), guest.getCategorie(), guest.getGenre(), guest.getCountry(), guest.getCategorie(),
new SimpleClubModel(null, guest.getClub(), "fr", null), new SimpleClubModel(null, guest.getClub(), "fr", null),
null, guest.getWeight(), guest.getWeightReal(), 0, false, false, null, guest.getWeight(), 0, false, false);
new ArrayList<>());
}
public SimpleRegisterComb setCategorieInscrite(List<CatPresetModel> presets) {
this.categoriesInscrites = presets.stream().map(CatPresetModel::getId).toList();
return this;
} }
} }

View File

@ -1,36 +0,0 @@
package fr.titionfire.ffsaf.rest.data;
import fr.titionfire.ffsaf.data.model.SelectionModel;
import fr.titionfire.ffsaf.utils.Categorie;
import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
@Data
@Builder
@AllArgsConstructor
@RegisterForReflection
public class SimpleSelection {
@Schema(description = "ID de la séléction", examples = "1")
Long id;
@Schema(description = "ID du membre", examples = "1")
Long membre;
@Schema(description = "Saison de la séléction", examples = "2024")
int saison;
@Schema(description = "Catégorie de la séléction", examples = "JUNIOR")
Categorie categorie;
public static SimpleSelection fromModel(SelectionModel model) {
if (model == null)
return null;
return new SimpleSelection.SimpleSelectionBuilder()
.id(model.getId())
.membre(model.getMembre().getId())
.saison(model.getSaison())
.categorie(model.getCategorie())
.build();
}
}

View File

@ -9,7 +9,6 @@ import lombok.ToString;
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.jboss.resteasy.reactive.PartType; import org.jboss.resteasy.reactive.PartType;
import org.jboss.resteasy.reactive.multipart.FileUpload;
@Getter @Getter
@ToString(exclude = {"status", "logo"}) @ToString(exclude = {"status", "logo"})
@ -18,85 +17,85 @@ public class AffiliationRequestForm {
@FormParam("id") @FormParam("id")
private Long id = null; private Long id = null;
@Schema(description = "Le nom de l'association.", examples = "Association sportive", required = true) @Schema(description = "Le nom de l'association.", example = "Association sportive", required = true)
@FormParam("name") @FormParam("name")
private String name = null; private String name = null;
@Schema(description = "Le numéro SIRET/RNA de l'association.", examples = "12345678901234", required = true) @Schema(description = "Le numéro SIRET/RNA de l'association.", example = "12345678901234", required = true)
@FormParam("state_id") @FormParam("state_id")
private String state_id = null; private String state_id = null;
@Schema(description = "L'adresse de l'association.", examples = "1 rue de l'exemple, 75000 Paris", required = true) @Schema(description = "L'adresse de l'association.", example = "1 rue de l'exemple, 75000 Paris", required = true)
@FormParam("adresse") @FormParam("adresse")
private String adresse = null; private String adresse = null;
@Schema(description = "Email de contact de l'association", examples = "test@test.fr") @Schema(description = "Email de contact de l'association", example = "test@test.fr")
@FormParam("contact") @FormParam("contact")
private String contact = null; private String contact = null;
@Schema(description = "La saison de l'affiliation.", examples = "2025", required = true) @Schema(description = "La saison de l'affiliation.", example = "2025", required = true)
@FormParam("saison") @FormParam("saison")
private int saison = -1; private int saison = -1;
@Schema(description = "Le statut de l'association.", type = SchemaType.ARRAY) @Schema(description = "Le statut de l'association.", type = SchemaType.ARRAY, implementation = byte.class)
@FormParam("status") @FormParam("status")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @PartType(MediaType.APPLICATION_OCTET_STREAM)
private FileUpload status = null; private byte[] status = new byte[0];
@Schema(description = "Le logo de l'association.", type = SchemaType.ARRAY) @Schema(description = "Le logo de l'association.", type = SchemaType.ARRAY, implementation = byte.class)
@FormParam("logo") @FormParam("logo")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @PartType(MediaType.APPLICATION_OCTET_STREAM)
private FileUpload logo = null; private byte[] logo = new byte[0];
@Schema(description = "Le nom du premier membre de l'association.", examples = "Doe", required = true) @Schema(description = "Le nom du premier membre de l'association.", example = "Doe", required = true)
@FormParam("m1_nom") @FormParam("m1_nom")
private String m1_lname = null; private String m1_lname = null;
@Schema(description = "Le prénom du premier membre de l'association.", examples = "John", required = true) @Schema(description = "Le prénom du premier membre de l'association.", example = "John", required = true)
@FormParam("m1_prenom") @FormParam("m1_prenom")
private String m1_fname = null; private String m1_fname = null;
@Schema(description = "L'adresse e-mail du premier membre de l'association.", examples = "john.doe@test.com", required = true) @Schema(description = "L'adresse e-mail du premier membre de l'association.", example = "john.doe@test.com", required = true)
@FormParam("m1_mail") @FormParam("m1_mail")
private String m1_email = null; private String m1_email = null;
@Schema(description = "Le numéro de licence du premier membre de l'association. (null si non licencié)", examples = "12345") @Schema(description = "Le numéro de licence du premier membre de l'association. (null si non licencié)", example = "12345")
@FormParam("m1_licence") @FormParam("m1_licence")
private String m1_lincence = null; private String m1_lincence = null;
@Schema(description = "Le rôle du premier membre de l'association. (doit être PRESIDENT)", examples = "PRESIDENT", required = true) @Schema(description = "Le rôle du premier membre de l'association. (doit être PRESIDENT)", example = "PRESIDENT", required = true)
@FormParam("m1_role") @FormParam("m1_role")
private RoleAsso m1_role = null; private RoleAsso m1_role = null;
@Schema(description = "Le nom du deuxième membre de l'association.", examples = "Xavier", required = true) @Schema(description = "Le nom du deuxième membre de l'association.", example = "Xavier", required = true)
@FormParam("m2_nom") @FormParam("m2_nom")
private String m2_lname = null; private String m2_lname = null;
@Schema(description = "Le prénom du deuxième membre de l'association.", examples = "Login", required = true) @Schema(description = "Le prénom du deuxième membre de l'association.", example = "Login", required = true)
@FormParam("m2_prenom") @FormParam("m2_prenom")
private String m2_fname = null; private String m2_fname = null;
@Schema(description = "L'adresse e-mail du deuxième membre de l'association.", examples = "xavier.login@test.com", required = true) @Schema(description = "L'adresse e-mail du deuxième membre de l'association.", example = "xavier.login@test.com", required = true)
@FormParam("m2_mail") @FormParam("m2_mail")
private String m2_email = null; private String m2_email = null;
@Schema(description = "Le numéro de licence du deuxième membre de l'association. (null si non licencié)", examples = "04242") @Schema(description = "Le numéro de licence du deuxième membre de l'association. (null si non licencié)", example = "04242")
@FormParam("m2_licence") @FormParam("m2_licence")
private String m2_lincence = null; private String m2_lincence = null;
@Schema(description = "Le rôle du deuxième membre de l'association.", examples = "SECRETAIRE", required = true) @Schema(description = "Le rôle du deuxième membre de l'association.", example = "SECRETAIRE", required = true)
@FormParam("m2_role") @FormParam("m2_role")
private RoleAsso m2_role = null; private RoleAsso m2_role = null;
@Schema(description = "Le nom du troisième membre de l'association.", examples = "Doe2", required = true) @Schema(description = "Le nom du troisième membre de l'association.", example = "Doe2", required = true)
@FormParam("m3_nom") @FormParam("m3_nom")
private String m3_lname = null; private String m3_lname = null;
@Schema(description = "Le prénom du troisième membre de l'association.", examples = "John2", required = true) @Schema(description = "Le prénom du troisième membre de l'association.", example = "John2", required = true)
@FormParam("m3_prenom") @FormParam("m3_prenom")
private String m3_fname = null; private String m3_fname = null;
@Schema(description = "L'adresse e-mail du troisième membre de l'association.", examples = "john.doe22@test.com", required = true) @Schema(description = "L'adresse e-mail du troisième membre de l'association.", example = "john.doe22@test.com", required = true)
@FormParam("m3_mail") @FormParam("m3_mail")
private String m3_email = null; private String m3_email = null;
@ -104,7 +103,7 @@ public class AffiliationRequestForm {
@FormParam("m3_licence") @FormParam("m3_licence")
private String m3_lincence = null; private String m3_lincence = null;
@Schema(description = "Le rôle du troisième membre de l'association.", examples = "MEMBREBUREAU", required = true) @Schema(description = "Le rôle du troisième membre de l'association.", example = "MEMBREBUREAU", required = true)
@FormParam("m3_role") @FormParam("m3_role")
private RoleAsso m3_role = null; private RoleAsso m3_role = null;

View File

@ -6,124 +6,123 @@ import jakarta.ws.rs.core.MediaType;
import lombok.Getter; import lombok.Getter;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.jboss.resteasy.reactive.PartType; import org.jboss.resteasy.reactive.PartType;
import org.jboss.resteasy.reactive.multipart.FileUpload;
@Getter @Getter
public class AffiliationRequestSaveForm { public class AffiliationRequestSaveForm {
@Schema(description = "L'identifiant de l'affiliation.", examples = "1", required = true) @Schema(description = "L'identifiant de l'affiliation.", example = "1", required = true)
@FormParam("id") @FormParam("id")
private Long id = null; private Long id = null;
@Schema(description = "Le nom de l'association.", examples = "Association sportive", required = true) @Schema(description = "Le nom de l'association.", example = "Association sportive", required = true)
@FormParam("name") @FormParam("name")
private String name = null; private String name = null;
@Schema(description = "Le numéro SIRET ou RNA de l'association.", examples = "12345678901234", required = true) @Schema(description = "Le numéro SIRET ou RNA de l'association.", example = "12345678901234", required = true)
@FormParam("state_id") @FormParam("state_id")
private String state_id = null; private String state_id = null;
@Schema(description = "L'adresse de l'association.", examples = "1 rue de l'exemple, 75000 Paris", required = true) @Schema(description = "L'adresse de l'association.", example = "1 rue de l'exemple, 75000 Paris", required = true)
@FormParam("address") @FormParam("address")
private String address = null; private String address = null;
@Schema(description = "Email de contact de l'association", examples = "test@test.fr") @Schema(description = "Email de contact de l'association", example = "test@test.fr")
@FormParam("contact") @FormParam("contact")
private String contact = null; private String contact = null;
@Schema(description = "Le statut de l'association.") @Schema(description = "Le statut de l'association.")
@FormParam("status") @FormParam("status")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @PartType(MediaType.APPLICATION_OCTET_STREAM)
private FileUpload status = null; private byte[] status = new byte[0];
@Schema(description = "Le logo de l'association.") @Schema(description = "Le logo de l'association.")
@FormParam("logo") @FormParam("logo")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @PartType(MediaType.APPLICATION_OCTET_STREAM)
private FileUpload logo = null; private byte[] logo = new byte[0];
@Schema(description = "Mode utiliser pour la sauvegarde du membre 1 (0 = licence mode, 2 = nom, prénom)", examples = "0", required = true) @Schema(description = "Mode utiliser pour la sauvegarde du membre 1 (0 = licence mode, 2 = nom, prénom)", example = "0", required = true)
@FormParam("m1_mode") @FormParam("m1_mode")
private Integer m1_mode = null; private Integer m1_mode = null;
@Schema(description = "Le rôle du premier membre de l'association.", examples = "PRÉSIDENT", required = true) @Schema(description = "Le rôle du premier membre de l'association.", example = "PRÉSIDENT", required = true)
@FormParam("m1_role") @FormParam("m1_role")
private RoleAsso m1_role = null; private RoleAsso m1_role = null;
@Schema(description = "Le numéro de licence du premier membre de l'association. (null si non licencié)", examples = "1234567", required = true) @Schema(description = "Le numéro de licence du premier membre de l'association. (null si non licencié)", example = "1234567", required = true)
@FormParam("m1_licence") @FormParam("m1_licence")
private String m1_lincence = null; private String m1_lincence = null;
@Schema(description = "Le nom du premier membre de l'association.", examples = "Dupont", required = true) @Schema(description = "Le nom du premier membre de l'association.", example = "Dupont", required = true)
@FormParam("m1_lname") @FormParam("m1_lname")
private String m1_lname = null; private String m1_lname = null;
@Schema(description = "Le prénom du premier membre de l'association.", examples = "Jean", required = true) @Schema(description = "Le prénom du premier membre de l'association.", example = "Jean", required = true)
@FormParam("m1_fname") @FormParam("m1_fname")
private String m1_fname = null; private String m1_fname = null;
@Schema(description = "L'adresse e-mail du premier membre de l'association.", examples = "jean.dupont@examples.com", required = true) @Schema(description = "L'adresse e-mail du premier membre de l'association.", example = "jean.dupont@example.com", required = true)
@FormParam("m1_email") @FormParam("m1_email")
private String m1_email = null; private String m1_email = null;
@Schema(name = "keep_email", @Schema(name = "keep_email",
description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm1_email')", examples = "1", required = true) description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm1_email')", example = "1", required = true)
@FormParam("m1_email_mode") @FormParam("m1_email_mode")
private Integer m1_email_mode = null; private Integer m1_email_mode = null;
@Schema(description = "Mode utiliser pour la sauvegarde du membre 2 (0 = licence mode, 2 = nom, prénom)", examples = "0", required = true) @Schema(description = "Mode utiliser pour la sauvegarde du membre 2 (0 = licence mode, 2 = nom, prénom)", example = "0", required = true)
@FormParam("m2_mode") @FormParam("m2_mode")
private Integer m2_mode = null; private Integer m2_mode = null;
@Schema(description = "Le rôle du deuxième membre de l'association.", examples = "TRÉSORIER", required = true) @Schema(description = "Le rôle du deuxième membre de l'association.", example = "TRÉSORIER", required = true)
@FormParam("m2_role") @FormParam("m2_role")
private RoleAsso m2_role = null; private RoleAsso m2_role = null;
@Schema(description = "Le numéro de licence du deuxième membre de l'association. (null si non licencié)", examples = "2345678", required = true) @Schema(description = "Le numéro de licence du deuxième membre de l'association. (null si non licencié)", example = "2345678", required = true)
@FormParam("m2_licence") @FormParam("m2_licence")
private String m2_lincence = null; private String m2_lincence = null;
@Schema(description = "Le nom du deuxième membre de l'association.", examples = "Durand", required = true) @Schema(description = "Le nom du deuxième membre de l'association.", example = "Durand", required = true)
@FormParam("m2_lname") @FormParam("m2_lname")
private String m2_lname = null; private String m2_lname = null;
@Schema(description = "Le prénom du deuxième membre de l'association.", examples = "Paul", required = true) @Schema(description = "Le prénom du deuxième membre de l'association.", example = "Paul", required = true)
@FormParam("m2_fname") @FormParam("m2_fname")
private String m2_fname = null; private String m2_fname = null;
@Schema(description = "L'adresse e-mail du deuxième membre de l'association.", examples = "paul.durand@examples.com", required = true) @Schema(description = "L'adresse e-mail du deuxième membre de l'association.", example = "paul.durand@example.com", required = true)
@FormParam("m2_email") @FormParam("m2_email")
private String m2_email = null; private String m2_email = null;
@Schema(name = "keep_email", @Schema(name = "keep_email",
description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm2_email')", examples = "1", required = true) description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm2_email')", example = "1", required = true)
@FormParam("m2_email_mode") @FormParam("m2_email_mode")
private Integer m2_email_mode = null; private Integer m2_email_mode = null;
@Schema(description = "Mode utiliser pour la sauvegarde du membre 3 (0 = licence mode, 2 = nom, prénom)", examples = "0", required = true) @Schema(description = "Mode utiliser pour la sauvegarde du membre 3 (0 = licence mode, 2 = nom, prénom)", example = "0", required = true)
@FormParam("m3_mode") @FormParam("m3_mode")
private Integer m3_mode = null; private Integer m3_mode = null;
@Schema(description = "Le rôle du troisième membre de l'association.", examples = "SECRÉTAIRE", required = true) @Schema(description = "Le rôle du troisième membre de l'association.", example = "SECRÉTAIRE", required = true)
@FormParam("m3_role") @FormParam("m3_role")
private RoleAsso m3_role = null; private RoleAsso m3_role = null;
@Schema(description = "Le numéro de licence du troisième membre de l'association. (null si non licencié)", examples = "3456789", required = true) @Schema(description = "Le numéro de licence du troisième membre de l'association. (null si non licencié)", example = "3456789", required = true)
@FormParam("m3_licence") @FormParam("m3_licence")
private String m3_lincence = null; private String m3_lincence = null;
@Schema(description = "Le nom du troisième membre de l'association.", examples = "Martin", required = true) @Schema(description = "Le nom du troisième membre de l'association.", example = "Martin", required = true)
@FormParam("m3_lname") @FormParam("m3_lname")
private String m3_lname = null; private String m3_lname = null;
@Schema(description = "Le prénom du troisième membre de l'association.", examples = "Pierre", required = true) @Schema(description = "Le prénom du troisième membre de l'association.", example = "Pierre", required = true)
@FormParam("m3_fname") @FormParam("m3_fname")
private String m3_fname = null; private String m3_fname = null;
@Schema(description = "L'adresse e-mail du troisième membre de l'association.", examples = "pierre.martin@examples.com", required = true) @Schema(description = "L'adresse e-mail du troisième membre de l'association.", example = "pierre.martin@example.com", required = true)
@FormParam("m3_email") @FormParam("m3_email")
private String m3_email = null; private String m3_email = null;
@Schema(name = "keep_email", @Schema(name = "keep_email",
description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm3_email')", examples = "1", required = true) description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm3_email')", example = "1", required = true)
@FormParam("m3_email_mode") @FormParam("m3_email_mode")
private Integer m3_email_mode = null; private Integer m3_email_mode = null;
@ -175,6 +174,8 @@ public class AffiliationRequestSaveForm {
", state_id=" + state_id + ", state_id=" + state_id +
", address='" + address + '\'' + ", address='" + address + '\'' +
", contact='" + contact + '\'' + ", contact='" + contact + '\'' +
", status_len=" + status.length +
", logo_len=" + logo.length +
", m1_mode=" + m1_mode + ", m1_mode=" + m1_mode +
", m1_role=" + m1_role + ", m1_role=" + m1_role +
", m1_lincence='" + m1_lincence + '\'' + ", m1_lincence='" + m1_lincence + '\'' +

View File

@ -7,58 +7,57 @@ import lombok.ToString;
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.jboss.resteasy.reactive.PartType; import org.jboss.resteasy.reactive.PartType;
import org.jboss.resteasy.reactive.multipart.FileUpload;
@ToString @ToString
@Getter @Getter
public class FullClubForm { public class FullClubForm {
@FormParam("id") @FormParam("id")
@Schema(description = "Identifiant du club", examples = "1", required = true) @Schema(description = "Identifiant du club", example = "1", required = true)
private String id = null; private String id = null;
@FormParam("name") @FormParam("name")
@Schema(description = "Nom du club", examples = "Association sportive", required = true) @Schema(description = "Nom du club", example = "Association sportive", required = true)
private String name = null; private String name = null;
@FormParam("country") @FormParam("country")
@Schema(description = "Pays du club", examples = "FR", required = true) @Schema(description = "Pays du club", example = "FR", required = true)
private String country = null; private String country = null;
@FormParam("contact") @FormParam("contact")
@Schema(description = "Les contacts du club", examples = "{\"SITE\": \"www.test.com\", \"COURRIEL\": \"test@test.com\"}", required = true) @Schema(description = "Les contacts du club", example = "{\"SITE\": \"www.test.com\", \"COURRIEL\": \"test@test.com\"}", required = true)
private String contact = null; private String contact = null;
@FormParam("training_location") @FormParam("training_location")
@Schema(description = "Liste des lieux d'entraînement", examples = "[{\"text\":\"addr 1\",\"lng\":2.24654,\"lat\":52.4868658},{\"text\":\"addr 2\",\"lng\":2.88654,\"lat\":52.7865456}]", required = true) @Schema(description = "Liste des lieux d'entraînement", example = "[{\"text\":\"addr 1\",\"lng\":2.24654,\"lat\":52.4868658},{\"text\":\"addr 2\",\"lng\":2.88654,\"lat\":52.7865456}]", required = true)
private String training_location = null; private String training_location = null;
@FormParam("training_day_time") @FormParam("training_day_time")
@Schema(description = "Liste des jours et horaires d'entraînement (jours 0-6, 0=>lundi) (temps en minute depuis 00:00, 122=>2h02)", examples = "[{\"day\":0,\"time_start\":164,\"time_end\":240},{\"day\":3,\"time_start\":124,\"time_end\":250}]", required = true) @Schema(description = "Liste des jours et horaires d'entraînement (jours 0-6, 0=>lundi) (temps en minute depuis 00:00, 122=>2h02)", example = "[{\"day\":0,\"time_start\":164,\"time_end\":240},{\"day\":3,\"time_start\":124,\"time_end\":250}]", required = true)
private String training_day_time = null; private String training_day_time = null;
@FormParam("contact_intern") @FormParam("contact_intern")
@Schema(description = "Contact interne du club", examples = "john.doe@test.com") @Schema(description = "Contact interne du club", example = "john.doe@test.com")
private String contact_intern = null; private String contact_intern = null;
@FormParam("address") @FormParam("address")
@Schema(description = "Adresse postale du club", examples = "1 rue de l'exemple, 75000 Paris", required = true) @Schema(description = "Adresse postale du club", example = "1 rue de l'exemple, 75000 Paris", required = true)
private String address = null; private String address = null;
@FormParam("state_id") @FormParam("state_id")
@Schema(description = "Numéro SIRET ou RNA du club", examples = "12345678901234", required = true) @Schema(description = "Numéro SIRET ou RNA du club", example = "12345678901234", required = true)
private String state_id = null; private String state_id = null;
@FormParam("international") @FormParam("international")
@Schema(description = "Club international", examples = "false", required = true) @Schema(description = "Club international", example = "false", required = true)
private boolean international = false; private boolean international = false;
@FormParam("status") @FormParam("status")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @PartType(MediaType.APPLICATION_OCTET_STREAM)
@Schema(description = "Le statut de l'association.", type = SchemaType.ARRAY) @Schema(description = "Le statut de l'association.", type = SchemaType.ARRAY, implementation = byte.class)
private FileUpload status = null; private byte[] status = new byte[0];
@FormParam("logo") @FormParam("logo")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @PartType(MediaType.APPLICATION_OCTET_STREAM)
@Schema(description = "Le logo de l'association.", type = SchemaType.ARRAY) @Schema(description = "Le logo de l'association.", type = SchemaType.ARRAY, implementation = byte.class)
private FileUpload logo = null; private byte[] logo = new byte[0];
} }

View File

@ -8,33 +8,32 @@ import jakarta.ws.rs.core.MediaType;
import lombok.Getter; import lombok.Getter;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.jboss.resteasy.reactive.PartType; import org.jboss.resteasy.reactive.PartType;
import org.jboss.resteasy.reactive.multipart.FileUpload;
import java.util.Date; import java.util.Date;
@Getter @Getter
public class FullMemberForm { public class FullMemberForm {
@Schema(description = "L'identifiant du membre.", examples = "1") @Schema(description = "L'identifiant du membre.", example = "1")
@FormParam("id") @FormParam("id")
private String id = null; private String id = null;
@Schema(description = "Le nom du membre.", examples = "Dupont") @Schema(description = "Le nom du membre.", example = "Dupont")
@FormParam("lname") @FormParam("lname")
private String lname = null; private String lname = null;
@Schema(description = "Le prénom du membre.", examples = "Jean") @Schema(description = "Le prénom du membre.", example = "Jean")
@FormParam("fname") @FormParam("fname")
private String fname = null; private String fname = null;
@Schema(description = "L'identifiant du club du membre.", examples = "1") @Schema(description = "L'identifiant du club du membre.", example = "1")
@FormParam("club") @FormParam("club")
private Long club = null; private Long club = null;
@Schema(description = "Le genre du membre.", examples = "H") @Schema(description = "Le genre du membre.", example = "H")
@FormParam("genre") @FormParam("genre")
private Genre genre; private Genre genre;
@Schema(description = "Le pays du membre.", examples = "FR") @Schema(description = "Le pays du membre.", example = "FR")
@FormParam("country") @FormParam("country")
private String country; private String country;
@ -42,22 +41,22 @@ public class FullMemberForm {
@FormParam("birth_date") @FormParam("birth_date")
private Date birth_date = null; private Date birth_date = null;
@Schema(description = "L'adresse e-mail du membre.", examples = "jean.dupont@example.com") @Schema(description = "L'adresse e-mail du membre.", example = "jean.dupont@example.com")
@FormParam("email") @FormParam("email")
private String email; private String email;
@Schema(description = "Le rôle du membre dans l'association.", examples = "MEMBRE") @Schema(description = "Le rôle du membre dans l'association.", example = "MEMBRE")
@FormParam("role") @FormParam("role")
private RoleAsso role; private RoleAsso role;
@Schema(description = "Le grade d'arbitrage du membre.", examples = "ASSESSEUR") @Schema(description = "Le grade d'arbitrage du membre.", example = "ASSESSEUR")
@FormParam("grade_arbitrage") @FormParam("grade_arbitrage")
private GradeArbitrage grade_arbitrage = GradeArbitrage.NA; private GradeArbitrage grade_arbitrage = GradeArbitrage.NA;
@Schema(description = "La photo du membre.") @Schema(description = "La photo du membre.")
@FormParam("photo_data") @FormParam("photo_data")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @PartType(MediaType.APPLICATION_OCTET_STREAM)
private FileUpload photo_data = null; private byte[] photo_data = new byte[0];
@Override @Override
public String toString() { public String toString() {
@ -71,6 +70,7 @@ public class FullMemberForm {
", email='" + email + '\'' + ", email='" + email + '\'' +
", role=" + role + ", role=" + role +
", grade_arbitrage=" + grade_arbitrage + ", grade_arbitrage=" + grade_arbitrage +
", url_photo=" + photo_data.length +
'}'; '}';
} }
} }

View File

@ -1,15 +0,0 @@
package fr.titionfire.ffsaf.rest.from;
import fr.titionfire.ffsaf.utils.ResultPrivacy;
import jakarta.ws.rs.FormParam;
import lombok.Getter;
import lombok.ToString;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
@ToString
@Getter
public class UserSettingForm {
@FormParam("resultPrivacy")
@Schema(description = "La confidentialité des résultats", examples = "PUBLIC", defaultValue = "PUBLIC", required = true)
private ResultPrivacy resultPrivacy;
}

View File

@ -1,6 +1,5 @@
package fr.titionfire.ffsaf.utils; package fr.titionfire.ffsaf.utils;
import fr.titionfire.ffsaf.domain.service.TradService;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@ -20,7 +19,7 @@ public enum Categorie {
VETERAN2; VETERAN2;
public String getName(ResourceBundle BUNDLE) { public String getName(ResourceBundle BUNDLE) {
return switch (this) { return switch (this){
case SUPER_MINI -> BUNDLE.getString("Cat.SUPER_MINI"); case SUPER_MINI -> BUNDLE.getString("Cat.SUPER_MINI");
case MINI_POUSSIN -> BUNDLE.getString("Cat.MINI_POUSSIN"); case MINI_POUSSIN -> BUNDLE.getString("Cat.MINI_POUSSIN");
case POUSSIN -> BUNDLE.getString("Cat.POUSSIN"); case POUSSIN -> BUNDLE.getString("Cat.POUSSIN");
@ -35,24 +34,8 @@ public enum Categorie {
}; };
} }
public String getName(TradService tradService) {
return switch (this) {
case SUPER_MINI -> tradService.translate("Cat.SUPER_MINI");
case MINI_POUSSIN -> tradService.translate("Cat.MINI_POUSSIN");
case POUSSIN -> tradService.translate("Cat.POUSSIN");
case BENJAMIN -> tradService.translate("Cat.BENJAMIN");
case MINIME -> tradService.translate("Cat.MINIME");
case CADET -> tradService.translate("Cat.CADET");
case JUNIOR -> tradService.translate("Cat.JUNIOR");
case SENIOR1 -> tradService.translate("Cat.SENIOR1");
case SENIOR2 -> tradService.translate("Cat.SENIOR2");
case VETERAN1 -> tradService.translate("Cat.VETERAN1");
case VETERAN2 -> tradService.translate("Cat.VETERAN2");
};
}
public String getName() { public String getName() {
return switch (this) { return switch (this){
case SUPER_MINI -> "Super Mini"; case SUPER_MINI -> "Super Mini";
case MINI_POUSSIN -> "Mini Poussin"; case MINI_POUSSIN -> "Mini Poussin";
case POUSSIN -> "Poussin"; case POUSSIN -> "Poussin";

View File

@ -1,34 +1,32 @@
package fr.titionfire.ffsaf.utils; package fr.titionfire.ffsaf.utils;
import fr.titionfire.ffsaf.domain.service.TradService;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
import java.util.HashMap; import java.util.HashMap;
@RegisterForReflection @RegisterForReflection
public enum Contact { public enum Contact {
COURRIEL, COURRIEL("Courriel"),
TELEPHONE, TELEPHONE("Téléphone"),
SITE, SITE("Site web"),
FACEBOOK, FACEBOOK("Facebook"),
INSTAGRAM, INSTAGRAM("Instagram"),
AUTRE; AUTRE("Autre");
public String getName(TradService trad) { public String name;
return switch (this) {
case COURRIEL -> trad.translate("Contact.COURRIEL"); Contact(String name) {
case TELEPHONE -> trad.translate("Contact.TELEPHONE"); this.name = name;
case SITE -> trad.translate("Contact.SITE");
case FACEBOOK -> trad.translate("Contact.FACEBOOK");
case INSTAGRAM -> trad.translate("Contact.INSTAGRAM");
case AUTRE -> trad.translate("Contact.AUTRE");
};
} }
public static HashMap<String, String> toSite(TradService trad) { public void setName(String name) {
this.name = name;
}
public static HashMap<String, String> toSite() {
HashMap<String, String> map = new HashMap<>(); HashMap<String, String> map = new HashMap<>();
for (Contact contact : Contact.values()) { for (Contact contact : Contact.values()) {
map.put(contact.toString(), contact.getName(trad)); map.put(contact.toString(), contact.name);
} }
return map; return map;
} }

View File

@ -1,6 +1,5 @@
package fr.titionfire.ffsaf.utils; package fr.titionfire.ffsaf.utils;
import fr.titionfire.ffsaf.domain.service.TradService;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
@RegisterForReflection @RegisterForReflection
@ -28,17 +27,8 @@ public enum Genre {
} }
} }
public String getString(TradService trad) {
return switch (this) {
case H -> trad.translate("Genre.Homme");
case F -> trad.translate("Genre.Femme");
case NA -> trad.translate("Genre.NA");
};
}
@Override @Override
public String toString() { public String toString() {
return str; return str;
} }
} }

View File

@ -1,6 +1,5 @@
package fr.titionfire.ffsaf.utils; package fr.titionfire.ffsaf.utils;
import fr.titionfire.ffsaf.domain.service.TradService;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
@RegisterForReflection @RegisterForReflection
@ -15,14 +14,6 @@ public enum GradeArbitrage {
this.str = name; this.str = name;
} }
public String getString(TradService trad) {
return switch (this) {
case NA -> trad.translate("GradeArbitrage.NA");
case ASSESSEUR -> trad.translate("GradeArbitrage.ASSESSEUR");
case ARBITRE -> trad.translate("GradeArbitrage.ARBITRE");
};
}
@Override @Override
public String toString() { public String toString() {
return str; return str;

View File

@ -1,8 +0,0 @@
package fr.titionfire.ffsaf.utils;
public enum ResultPrivacy {
PUBLIC,
REGISTERED_ONLY,
REGISTERED_ONLY_NO_DETAILS,
PRIVATE;
}

View File

@ -1,6 +1,5 @@
package fr.titionfire.ffsaf.utils; package fr.titionfire.ffsaf.utils;
import fr.titionfire.ffsaf.domain.service.TradService;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
@RegisterForReflection @RegisterForReflection
@ -22,19 +21,6 @@ public enum RoleAsso {
this.level = level; this.level = level;
} }
public String getString(TradService trad) {
return switch (this){
case MEMBRE -> trad.translate("RoleAsso.MEMBRE");
case PRESIDENT -> trad.translate("RoleAsso.PRESIDENT");
case VPRESIDENT -> trad.translate("RoleAsso.VPRESIDENT");
case SECRETAIRE -> trad.translate("RoleAsso.SECRETAIRE");
case VSECRETAIRE -> trad.translate("RoleAsso.VSECRETAIRE");
case TRESORIER -> trad.translate("RoleAsso.TRESORIER");
case VTRESORIER -> trad.translate("RoleAsso.VTRESORIER");
case MEMBREBUREAU -> trad.translate("RoleAsso.MEMBREBUREAU");
};
}
@Override @Override
public String toString() { public String toString() {
return str; return str;

View File

@ -1,20 +1,12 @@
package fr.titionfire.ffsaf.utils; package fr.titionfire.ffsaf.utils;
import fr.titionfire.ffsaf.data.model.CompetitionGuestModel;
import fr.titionfire.ffsaf.data.model.MembreModel;
import fr.titionfire.ffsaf.domain.service.VirusScannerService;
import fr.titionfire.ffsaf.rest.exception.DBadRequestException;
import fr.titionfire.ffsaf.rest.exception.DInternalError;
import fr.titionfire.ffsaf.rest.exception.DetailException;
import io.quarkiverse.antivirus.runtime.AntivirusScanResult;
import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.unchecked.Unchecked;
import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import jodd.net.MimeTypes; import jodd.net.MimeTypes;
import org.apache.tika.Tika;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.reactive.multipart.FileUpload;
import java.io.*; import java.io.*;
import java.net.URISyntaxException; import java.net.URISyntaxException;
@ -29,79 +21,6 @@ import java.util.concurrent.Future;
public class Utils { public class Utils {
private static final Logger LOGGER = Logger.getLogger(Utils.class); private static final Logger LOGGER = Logger.getLogger(Utils.class);
public static String HTML_HEADER = """
<!DOCTYPE html>
<html data-lt-installed="true">
<head>
<meta charset="UTF-8">
<title>%s</title>
<style>
body {
font-family: Arial, sans-serif;
line-height: 1.6;
color: #333;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.header {
background-color: #003366;
color: white;
padding: 20px;
text-align: center;
border-radius: 5px 5px 0 0;
}
.content {
padding: 20px;
background-color: #f9f9f9;
border-radius: 0 0 5px 5px;
border: 1px solid #ddd;
border-top: none;
}
.button {
display: inline-block;
padding: 10px 20px;
background-color: #003366;
color: white !important;
text-decoration: none;
border-radius: 5px;
margin: 15px 0;
}
.footer {
margin-top: 20px;
font-size: 0.9em;
color: #666;
text-align: center;
}
.highlight {
font-weight: bold;
color: #003366;
}
</style>
</head>
<body data-gramm="false" data-lt-tmp-id="lt-957854">
<div class="header">
<div><img src="https://intra.ffsaf.fr/Logo-FFSAF-2023.png" alt="ffsaf" height="128">
<h1>F&eacute;d&eacute;ration France Soft Armored Fighting</h1>
</div>
</div>
<div class="content">
<p>Bonjour,</p>
""";
public static String HTML_FOOTER = """
<p>Cordialement,<br>L&rsquo;&eacute;quipe de la FFSAF</p>
</div>
</body>
</html>
""";
public static int getSaison() { public static int getSaison() {
return getSaison(new Date()); return getSaison(new Date());
} }
@ -189,72 +108,44 @@ public class Utils {
}); });
} }
public static Uni<String> uploadFile(VirusScannerService ss, FileUpload file, long id, String media, String dir) { public static Future<String> replacePhoto(long id, byte[] input, String media, String dir) {
if (file == null || file.size() == 0) return CompletableFuture.supplyAsync(() -> {
return Uni.createFrom().item("Ok"); if (input == null || input.length == 0)
return "OK";
LOGGER.infof("Received file upload request for: %s (size: %d bytes)", file.fileName(), file.size()); try (InputStream is = new BufferedInputStream(new ByteArrayInputStream(input))) {
return Uni.createFrom().<InputStream>item(() -> { String mimeType;
try { try {
// Read the entire file into memory for virus scanning Tika tika = new Tika();
// ByteArrayInputStream fully supports mark/reset operations required by ClamAV mimeType = tika.detect(is);// Magic.getMagicMatch(input, false).getMimeType();
// This ensures we can scan the file content before any filesystem storage
InputStream fileStream = java.nio.file.Files.newInputStream(file.uploadedFile());
byte[] fileBytes = fileStream.readAllBytes();
fileStream.close(); // Close the file stream immediately
return new ByteArrayInputStream(fileBytes);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("Failed to read uploaded file: " + e.getMessage(), e); mimeType = URLConnection.guessContentTypeFromStream(is);
} }
}).runSubscriptionOn(io.smallrye.mutiny.infrastructure.Infrastructure.getDefaultWorkerPool()).onItem() String[] detectedExtensions = MimeTypes.findExtensionsByMimeTypes(mimeType, false);
.transformToUni(inputStream -> {
// Perform virus scanning reactively using the input stream
return ss.scanFileReactive(file.fileName(), inputStream).onItem().invoke(() -> {
try {
inputStream.close();
} catch (IOException e) {
LOGGER.warn("Warning: Failed to close input stream: " + e.getMessage());
}
});
})
.onItem().transformToUni(scanResults -> Uni.createFrom().item(Unchecked.supplier(() -> {
// Check if any scanner found a threat
for (AntivirusScanResult result : scanResults) {
if (result.getStatus() != Response.Status.OK.getStatusCode()) {
LOGGER.warnf("THREAT DETECTED in %s: %s", file.fileName(), result.getMessage());
throw new DetailException(Response.Status.fromStatusCode(result.getStatus()),
"THREAT_DETECTED on File " + file.fileName() + " is infected: " + result.getMessage());
}
}
// File is clean - now we can safely process it
LOGGER.infof("File is clean: %s (size=%d) (contentType=%s)", file.fileName(), file.size(),
file.contentType());
String[] detectedExtensions = MimeTypes.findExtensionsByMimeTypes(file.contentType(), false);
if (detectedExtensions.length == 0) if (detectedExtensions.length == 0)
throw new DBadRequestException( throw new IOException("Fail to detect file extension for MIME type " + mimeType);
"Fail to detect file extension for MIME type " + file.contentType());
File dirFile = new File(media, dir); File dirFile = new File(media, dir);
if (!dirFile.exists()) if (!dirFile.exists())
if (!dirFile.mkdirs()) if (!dirFile.mkdirs())
throw new DInternalError("Fail to create directory " + dir); throw new IOException("Fail to create directory " + dir);
FilenameFilter filter = (directory, filename) -> filename.startsWith(id + "."); FilenameFilter filter = (directory, filename) -> filename.startsWith(id + ".");
File[] files = dirFile.listFiles(filter); File[] files = dirFile.listFiles(filter);
if (files != null) { if (files != null) {
for (File f : files) { for (File file : files) {
//noinspection ResultOfMethodCallIgnored //noinspection ResultOfMethodCallIgnored
f.delete(); file.delete();
} }
} }
File f = file.filePath().toFile(); String extension = "." + detectedExtensions[0];
//noinspection ResultOfMethodCallIgnored Files.write(new File(dirFile, id + extension).toPath(), input);
f.renameTo(new File(dirFile, id + "." + detectedExtensions[0])); return "OK";
return "ok"; } catch (IOException e) {
}))); return e.getMessage();
}
});
} }
public static Uni<Response> getMediaFile(long id, String media, String dirname, public static Uni<Response> getMediaFile(long id, String media, String dirname,
@ -371,46 +262,4 @@ public class Utils {
return (int) ((calendar.getTimeInMillis() - now.getTimeInMillis()) / (1000 * 60 * 60 * 24)); return (int) ((calendar.getTimeInMillis() - now.getTimeInMillis()) / (1000 * 60 * 60 * 24));
} }
public static String formatPrenom(String input) {
if (input == null || input.isEmpty()) {
return input;
}
StringBuilder result = new StringBuilder();
String[] mots = input.split(" ");
for (String mot : mots) {
if (!mot.isEmpty()) {
String[] parties = mot.split("[-']");
StringBuilder motFormate = new StringBuilder();
for (int i = 0; i < parties.length; i++) {
if (!parties[i].isEmpty()) {
String premiereLettre = parties[i].substring(0, 1).toUpperCase();
String reste = parties[i].substring(1).toLowerCase();
motFormate.append(premiereLettre).append(reste);
}
if (i < parties.length - 1) {
motFormate.append(mot.charAt(mot.indexOf(parties[i]) + parties[i].length()));
}
}
result.append(motFormate).append(" ");
}
}
return result.toString().trim();
}
public static String getFullName(Object... models) {
for (Object model : models) {
if (model == null)
continue;
if (model instanceof MembreModel membreModel)
return membreModel.getFname() + " " + membreModel.getLname();
if (model instanceof CompetitionGuestModel guestModel)
return guestModel.getFname() + " " + guestModel.getLname();
}
return "";
}
} }

View File

@ -4,7 +4,6 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import fr.titionfire.ffsaf.data.repository.CompetitionRepository; import fr.titionfire.ffsaf.data.repository.CompetitionRepository;
import fr.titionfire.ffsaf.domain.service.CompetPermService; import fr.titionfire.ffsaf.domain.service.CompetPermService;
import fr.titionfire.ffsaf.net2.MessageType; import fr.titionfire.ffsaf.net2.MessageType;
import fr.titionfire.ffsaf.rest.data.SimpleCompetData;
import fr.titionfire.ffsaf.utils.SecurityCtx; import fr.titionfire.ffsaf.utils.SecurityCtx;
import fr.titionfire.ffsaf.ws.data.WelcomeInfo; import fr.titionfire.ffsaf.ws.data.WelcomeInfo;
import fr.titionfire.ffsaf.ws.recv.*; import fr.titionfire.ffsaf.ws.recv.*;
@ -17,15 +16,12 @@ import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.unchecked.Unchecked; import io.smallrye.mutiny.unchecked.Unchecked;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.ws.rs.ForbiddenException; import jakarta.ws.rs.ForbiddenException;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.time.Duration;
import java.util.*; import java.util.*;
import java.util.concurrent.Executor;
import static fr.titionfire.ffsaf.net2.Client_Thread.MAPPER; import static fr.titionfire.ffsaf.net2.Client_Thread.MAPPER;
@ -46,13 +42,7 @@ public class CompetitionWS {
RRegister rRegister; RRegister rRegister;
@Inject @Inject
RCard rCard; RCardboard rCardboard;
@Inject
RTeam rTeam;
@Inject
RState rState;
@Inject @Inject
SecurityCtx securityCtx; SecurityCtx securityCtx;
@ -60,15 +50,6 @@ public class CompetitionWS {
@Inject @Inject
CompetPermService competPermService; CompetPermService competPermService;
@SuppressWarnings("CdiInjectionPointsInspection")
@Inject
OpenConnections connections;
@Inject
@Named("notify-executor")
Executor notifyExecutor;
private static Executor executor;
@Inject @Inject
CompetitionRepository competitionRepository; CompetitionRepository competitionRepository;
@ -96,11 +77,7 @@ public class CompetitionWS {
getWSReceiverMethods(RMatch.class, rMatch); getWSReceiverMethods(RMatch.class, rMatch);
getWSReceiverMethods(RCategorie.class, rCategorie); getWSReceiverMethods(RCategorie.class, rCategorie);
getWSReceiverMethods(RRegister.class, rRegister); getWSReceiverMethods(RRegister.class, rRegister);
getWSReceiverMethods(RCard.class, rCard); getWSReceiverMethods(RCardboard.class, rCardboard);
getWSReceiverMethods(RTeam.class, rTeam);
getWSReceiverMethods(RState.class, rState);
executor = notifyExecutor;
} }
@OnOpen @OnOpen
@ -117,8 +94,8 @@ public class CompetitionWS {
.call(cm -> competPermService.hasEditPerm(securityCtx, cm).map(__ -> PermLevel.ADMIN) .call(cm -> competPermService.hasEditPerm(securityCtx, cm).map(__ -> PermLevel.ADMIN)
.onFailure() .onFailure()
.recoverWithUni(competPermService.hasTablePerm(securityCtx, cm).map(__ -> PermLevel.TABLE)) .recoverWithUni(competPermService.hasTablePerm(securityCtx, cm).map(__ -> PermLevel.TABLE))
//.onFailure() .onFailure()
//.recoverWithUni(competPermService.hasViewPerm(securityCtx, cm).map(__ -> PermLevel.VIEW)) .recoverWithUni(competPermService.hasViewPerm(securityCtx, cm).map(__ -> PermLevel.VIEW))
.invoke(prem -> connection.userData().put(UserData.TypedKey.forString("prem"), prem.toString())) .invoke(prem -> connection.userData().put(UserData.TypedKey.forString("prem"), prem.toString()))
.invoke(prem -> LOGGER.infof("Connection permission: %s", prem)) .invoke(prem -> LOGGER.infof("Connection permission: %s", prem))
.onFailure().transform(t -> new ForbiddenException())) .onFailure().transform(t -> new ForbiddenException()))
@ -127,13 +104,10 @@ public class CompetitionWS {
waitingResponse.put(connection, new HashMap<>()); waitingResponse.put(connection, new HashMap<>());
}) })
.map(cm -> { .map(cm -> {
SimpleCompetData data = SimpleCompetData.fromModel(cm);
WelcomeInfo welcomeInfo = new WelcomeInfo(); WelcomeInfo welcomeInfo = new WelcomeInfo();
welcomeInfo.setName(cm.getName()); welcomeInfo.setName(cm.getName());
welcomeInfo.setPerm(connection.userData().get(UserData.TypedKey.forString("prem"))); welcomeInfo.setPerm(connection.userData().get(UserData.TypedKey.forString("prem")));
welcomeInfo.setShow_blason(data.isShow_blason());
welcomeInfo.setShow_flag(data.isShow_flag());
return new MessageOut(UUID.randomUUID(), "welcomeInfo", MessageType.NOTIFY, welcomeInfo); return new MessageOut(UUID.randomUUID(), "welcomeInfo", MessageType.NOTIFY, welcomeInfo);
}); });
@ -145,7 +119,6 @@ public class CompetitionWS {
LOGGER.debugf("Active connections: %d", connection.getOpenConnections().size()); LOGGER.debugf("Active connections: %d", connection.getOpenConnections().size());
waitingResponse.remove(connection); waitingResponse.remove(connection);
rState.removeConnection(connection);
} }
private MessageOut makeReply(MessageIn message, Object data) { private MessageOut makeReply(MessageIn message, Object data) {
@ -193,7 +166,6 @@ public class CompetitionWS {
return Uni.createFrom().item(makeError(message, "Permission denied")).toMulti(); return Uni.createFrom().item(makeError(message, "Permission denied")).toMulti();
return ((Uni<?>) method.invoke(entry.getValue(), connection, return ((Uni<?>) method.invoke(entry.getValue(), connection,
MAPPER.treeToValue(message.data(), method.getParameterTypes()[1]))) MAPPER.treeToValue(message.data(), method.getParameterTypes()[1])))
.ifNoItem().after(Duration.ofSeconds(5)).fail()
.map(o -> makeReply(message, o)) .map(o -> makeReply(message, o))
.onFailure() .onFailure()
.recoverWithItem(t -> { .recoverWithItem(t -> {
@ -212,7 +184,7 @@ public class CompetitionWS {
// return Uni.createFrom().item(new Message<>(message.uuid(), message.code(), MessageType.REPLY, "ko")); // return Uni.createFrom().item(new Message<>(message.uuid(), message.code(), MessageType.REPLY, "ko"));
} }
public static void sendNotifyToOtherEditor(WebSocketConnection connection, String code, Object data) { public static Uni<Void> sendNotifyToOtherEditor(WebSocketConnection connection, String code, Object data) {
String uuid = connection.pathParam("uuid"); String uuid = connection.pathParam("uuid");
List<Uni<Void>> queue = new ArrayList<>(); List<Uni<Void>> queue = new ArrayList<>();
@ -224,39 +196,7 @@ public class CompetitionWS {
} }
}); });
Uni.join().all(queue) return Uni.join().all(queue).andCollectFailures().onFailure().recoverWithNull().replaceWithVoid();
.andCollectFailures()
.runSubscriptionOn(executor)
.subscribeAsCompletionStage()
.whenComplete((v, t) -> {
if (t != null) {
LOGGER.error("Error sending ws_out message", t);
}
});
}
public static void sendNotifyState(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 -> {
Boolean s = c.userData().get(UserData.TypedKey.forBoolean("needState"));
if (uuid.equals(c.pathParam("uuid")) && s != null && s) {
queue.add(c.sendText(new MessageOut(UUID.randomUUID(), code, MessageType.NOTIFY, data)));
}
});
Uni.join().all(queue)
.andCollectFailures()
.runSubscriptionOn(executor)
.subscribeAsCompletionStage()
.whenComplete((v, t) -> {
if (t != null) {
LOGGER.error("Error sending ws_out message", t);
}
});
} }
@OnError @OnError

View File

@ -1,19 +0,0 @@
package fr.titionfire.ffsaf.ws;
import jakarta.enterprise.inject.Produces;
import jakarta.inject.Named;
import jakarta.inject.Singleton;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@Singleton
public class ExecutorProducer {
@Produces
@Named("notify-executor")
public Executor produceNotifyExecutor() {
// Créez un pool de threads avec une taille fixe (par exemple, 10 threads)
return Executors.newFixedThreadPool(10);
}
}

View File

@ -8,6 +8,4 @@ import lombok.Data;
public class WelcomeInfo { public class WelcomeInfo {
private String name; private String name;
private String perm; private String perm;
private boolean show_blason;
private boolean show_flag;
} }

View File

@ -1,158 +0,0 @@
package fr.titionfire.ffsaf.ws.recv;
import fr.titionfire.ffsaf.data.model.CardModel;
import fr.titionfire.ffsaf.data.model.MatchModel;
import fr.titionfire.ffsaf.data.repository.CardRepository;
import fr.titionfire.ffsaf.data.repository.ClubCardRepository;
import fr.titionfire.ffsaf.data.repository.CompetitionRepository;
import fr.titionfire.ffsaf.data.repository.MatchRepository;
import fr.titionfire.ffsaf.domain.service.CardService;
import fr.titionfire.ffsaf.domain.service.TradService;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
import fr.titionfire.ffsaf.ws.PermLevel;
import fr.titionfire.ffsaf.ws.send.SSCard;
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 java.util.Date;
import java.util.List;
@WithSession
@ApplicationScoped
@RegisterForReflection
public class RCard {
@Inject
MatchRepository matchRepository;
@Inject
ClubCardRepository clubCardRepository;
@Inject
CardRepository cardRepository;
@Inject
CardService cardService;
@Inject
CompetitionRepository competitionRepository;
@Inject
TradService trad;
private Uni<MatchModel> getById(long id, WebSocketConnection connection) {
return matchRepository.findById(id)
.invoke(Unchecked.consumer(o -> {
if (o == null)
throw new DNotFoundException(trad.t("matche.non.trouver"));
if (!o.getCategory().getCompet().getUuid().equals(connection.pathParam("uuid")))
throw new DForbiddenException(trad.t("permission.denied"));
}));
}
@WSReceiver(code = "getCardForMatch", permission = PermLevel.VIEW)
public Uni<List<CardModel>> getCardForMatch(WebSocketConnection connection, Long matchId) {
if (matchId == null)
return Uni.createFrom().nullItem();
return getById(matchId, connection).chain(matchModel -> cardService.getForMatch(matchModel));
}
@WSReceiver(code = "getAllForTeamNoDetail", permission = PermLevel.VIEW)
public Uni<List<SendTeamCards>> getAllForTeamNoDetail(WebSocketConnection connection, Object o) {
return competitionRepository.find("uuid", connection.pathParam("uuid")).firstResult()
.chain(c -> clubCardRepository.list("competition = ?1", c.getId()))
.map(cards -> cards.stream()
.map(card -> new SendTeamCards(card.getTeamUuid(), card.getTeamName(), List.of(),
card.getType(), card.getReason(), card.getDate()))
.toList());
}
@WSReceiver(code = "sendCardAdd", permission = PermLevel.TABLE)
public Uni<Void> sendCardAdd(WebSocketConnection connection, SendCardAdd card) {
return getById(card.matchId(), connection)
.chain(matchModel -> cardService.checkCanBeAdded(card, matchModel)
.chain(c -> {
CardModel model = new CardModel();
model.setComb(card.combId());
model.setMatch(card.matchId());
model.setCategory(matchModel.getCategory().getId());
model.setCompetition(matchModel.getCategory().getCompet());
model.setCompetitionId(matchModel.getCategory().getCompet().getId());
model.setType(card.type());
model.setReason(card.reason());
return Panache.withTransaction(() -> cardRepository.persist(model));
})
)
.invoke(cardModel -> SSCard.sendCards(connection, List.of(cardModel)))
.replaceWithVoid();
}
@WSReceiver(code = "sendCardRm", permission = PermLevel.ADMIN)
public Uni<Void> sendCardRm(WebSocketConnection connection, SendCardAdd card) {
return getById(card.matchId(), connection)
.chain(matchModel -> cardRepository.find("match = ?1 AND comb = ?2 AND type = ?3",
matchModel.getId(), card.combId(), card.type())
.firstResult()
.invoke(Unchecked.consumer(o -> {
if (o == null)
throw new DNotFoundException(trad.t("carton.non.trouver"));
SSCard.sendRmCards(connection, List.of(o.getId()));
}))
.chain(cardModel -> Panache.withTransaction(() -> cardRepository.delete(cardModel)))
)
.replaceWithVoid();
}
@WSReceiver(code = "applyTeamCards", permission = PermLevel.TABLE)
public Uni<Void> applyTeamCards(WebSocketConnection connection, SendTeamCards teamCards) {
return competitionRepository.find("uuid", connection.pathParam("uuid")).firstResult()
.chain(c -> cardService.addTeamCard(c, teamCards.teamUuid(), teamCards.teamName(), teamCards.type,
teamCards.reason()))
.invoke(cards -> SSCard.sendTeamCard(connection,
new SendTeamCards(teamCards.teamUuid(), teamCards.teamName(), cards, teamCards.type(),
teamCards.reason(), new Date())))
.replaceWithVoid();
}
@WSReceiver(code = "sendTeamCardReturnState", permission = PermLevel.TABLE)
public Uni<Void> sendTeamCardReturnState(WebSocketConnection connection, SendTeamCardReturnState state) {
if (state.state <= 0 || state.state > 2)
return Uni.createFrom().voidItem();
return competitionRepository.find("uuid", connection.pathParam("uuid")).firstResult()
.chain(c -> cardService.recvReturnState(c, state))
.invoke(cards -> SSCard.sendCards(connection, cards))
.replaceWithVoid();
}
@WSReceiver(code = "removeTeamCards", permission = PermLevel.TABLE)
public Uni<Void> removeTeamCards(WebSocketConnection connection, SendTeamCards teamCards) {
return competitionRepository.find("uuid", connection.pathParam("uuid")).firstResult()
.chain(c -> cardService.rmTeamCard(c, teamCards.teamUuid(), teamCards.teamName(), teamCards.type))
.invoke(cards -> SSCard.sendRmCards(connection, cards))
.invoke(__ -> SSCard.rmTeamCard(connection, teamCards))
.replaceWithVoid();
}
@RegisterForReflection
public record SendCardAdd(long matchId, long combId, CardModel.CardType type, String reason) {
}
@RegisterForReflection
public record SendTeamCards(String teamUuid, String teamName, List<CardModel> cards, CardModel.CardType type,
String reason, Date date) {
}
@RegisterForReflection
public record SendTeamCardReturnState(String teamUuid, String teamName, CardModel.CardType type,
int state, Long selectedCategory, Long selectedMatch) {
}
}

View File

@ -0,0 +1,128 @@
package fr.titionfire.ffsaf.ws.recv;
import fr.titionfire.ffsaf.data.model.CardboardModel;
import fr.titionfire.ffsaf.data.model.MatchModel;
import fr.titionfire.ffsaf.data.repository.CardboardRepository;
import fr.titionfire.ffsaf.data.repository.MatchRepository;
import fr.titionfire.ffsaf.domain.entity.CardboardEntity;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
import fr.titionfire.ffsaf.ws.PermLevel;
import fr.titionfire.ffsaf.ws.send.SSCardboard;
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 java.util.Objects;
@WithSession
@ApplicationScoped
@RegisterForReflection
public class RCardboard {
@Inject
MatchRepository matchRepository;
@Inject
CardboardRepository cardboardRepository;
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");
}));
}
@WSReceiver(code = "sendCardboardChange", permission = PermLevel.TABLE)
public Uni<Void> sendCardboardChange(WebSocketConnection connection, SendCardboard card) {
return getById(card.matchId, connection)
.chain(matchModel -> cardboardRepository.find("(comb.id = ?1 OR guestComb.id = ?2) AND match.id = ?3",
card.combId, card.combId * -1, card.matchId).firstResult()
.chain(model -> {
if (model != null) {
model.setRed(model.getRed() + card.red);
model.setYellow(model.getYellow() + card.yellow);
return Panache.withTransaction(() -> cardboardRepository.persist(model));
}
CardboardModel cardboardModel = new CardboardModel();
cardboardModel.setCompet(matchModel.getCategory().getCompet());
cardboardModel.setMatch(matchModel);
cardboardModel.setRed(card.red);
cardboardModel.setYellow(card.yellow);
cardboardModel.setComb(null);
cardboardModel.setGuestComb(null);
if (card.combId >= 0) {
if (matchModel.getC1_id() != null && matchModel.getC1_id().getId() == card.combId)
cardboardModel.setComb(matchModel.getC1_id());
if (matchModel.getC2_id() != null && matchModel.getC2_id().getId() == card.combId)
cardboardModel.setComb(matchModel.getC2_id());
} else {
if (matchModel.getC1_guest() != null && matchModel.getC1_guest()
.getId() == card.combId * -1)
cardboardModel.setGuestComb(matchModel.getC1_guest());
if (matchModel.getC2_guest() != null && matchModel.getC2_guest()
.getId() == card.combId * -1)
cardboardModel.setGuestComb(matchModel.getC2_guest());
}
if (cardboardModel.getComb() == null && cardboardModel.getGuestComb() == null)
return Uni.createFrom().nullItem();
return Panache.withTransaction(() -> cardboardRepository.persist(cardboardModel));
}))
.call(model -> SSCardboard.sendCardboard(connection, CardboardEntity.fromModel(model)))
.replaceWithVoid();
}
@WSReceiver(code = "getCardboardWithoutThis", permission = PermLevel.VIEW)
public Uni<CardboardAllMatch> getCardboardWithoutThis(WebSocketConnection connection, Long matchId) {
return getById(matchId, connection)
.chain(matchModel -> cardboardRepository.list("compet = ?1 AND match != ?2", matchModel.getCategory().getCompet(), matchModel)
.map(models -> {
CardboardAllMatch out = new CardboardAllMatch();
models.stream().filter(c -> (matchModel.getC1_id() != null
&& Objects.equals(c.getComb(), matchModel.getC1_id()))
|| (matchModel.getC1_guest() != null
&& Objects.equals(c.getGuestComb(), matchModel.getC1_guest())))
.forEach(c -> {
out.c1_yellow += c.getYellow();
out.c1_red += c.getRed();
});
models.stream().filter(c -> (matchModel.getC2_id() != null
&& Objects.equals(c.getComb(), matchModel.getC2_id()))
|| (matchModel.getC2_guest() != null
&& Objects.equals(c.getGuestComb(), matchModel.getC2_guest())))
.forEach(c -> {
out.c2_yellow += c.getYellow();
out.c2_red += c.getRed();
});
return out;
}));
}
@RegisterForReflection
public record SendCardboard(long matchId, long combId, int yellow, int red) {
}
@Data
@RegisterForReflection
public static class CardboardAllMatch {
int c1_yellow = 0;
int c1_red = 0;
int c2_yellow = 0;
int c2_red = 0;
}
}

View File

@ -1,14 +1,14 @@
package fr.titionfire.ffsaf.ws.recv; package fr.titionfire.ffsaf.ws.recv;
import fr.titionfire.ffsaf.data.model.CardModel;
import fr.titionfire.ffsaf.data.model.CategoryModel; import fr.titionfire.ffsaf.data.model.CategoryModel;
import fr.titionfire.ffsaf.data.model.MatchModel; import fr.titionfire.ffsaf.data.model.MatchModel;
import fr.titionfire.ffsaf.data.model.TreeModel; import fr.titionfire.ffsaf.data.model.TreeModel;
import fr.titionfire.ffsaf.data.repository.*; 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.MatchEntity;
import fr.titionfire.ffsaf.domain.entity.TreeEntity; import fr.titionfire.ffsaf.domain.entity.TreeEntity;
import fr.titionfire.ffsaf.domain.service.CardService;
import fr.titionfire.ffsaf.domain.service.TradService;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException; import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.rest.exception.DNotFoundException; import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
import fr.titionfire.ffsaf.utils.TreeNode; import fr.titionfire.ffsaf.utils.TreeNode;
@ -46,19 +46,13 @@ public class RCategorie {
@Inject @Inject
TreeRepository treeRepository; TreeRepository treeRepository;
@Inject
CardService cardService;
@Inject
TradService trad;
private Uni<CategoryModel> getById(long id, WebSocketConnection connection) { private Uni<CategoryModel> getById(long id, WebSocketConnection connection) {
return categoryRepository.findById(id) return categoryRepository.findById(id)
.invoke(Unchecked.consumer(o -> { .invoke(Unchecked.consumer(o -> {
if (o == null) if (o == null)
throw new DNotFoundException(trad.t("categorie.non.trouver")); throw new DNotFoundException("Catégorie non trouver");
if (!o.getCompet().getUuid().equals(connection.pathParam("uuid"))) if (!o.getCompet().getUuid().equals(connection.pathParam("uuid")))
throw new DForbiddenException(trad.t("permission.denied")); throw new DForbiddenException("Permission denied");
})); }));
} }
@ -86,8 +80,6 @@ public class RCategorie {
.call(cat -> treeRepository.list("category = ?1 AND level != 0", cat.getId()) .call(cat -> treeRepository.list("category = ?1 AND level != 0", cat.getId())
.map(treeModels -> treeModels.stream().map(TreeEntity::fromModel).toList()) .map(treeModels -> treeModels.stream().map(TreeEntity::fromModel).toList())
.invoke(fullCategory::setTrees)) .invoke(fullCategory::setTrees))
.call(cat -> cardService.getAll(cat.getCompet())
.invoke(fullCategory::setCards))
.map(__ -> fullCategory); .map(__ -> fullCategory);
} }
@ -105,7 +97,7 @@ public class RCategorie {
return categoryRepository.create(categoryModel); return categoryRepository.create(categoryModel);
}) })
.invoke(cat -> SSCategorie.sendAddCategory(connection, cat)) .call(cat -> SSCategorie.sendAddCategory(connection, cat))
.map(CategoryModel::getId); .map(CategoryModel::getId);
} }
@ -126,10 +118,9 @@ public class RCategorie {
uni = uni.chain(__ -> treeRepository.delete("category = ?1", cat.getId())) uni = uni.chain(__ -> treeRepository.delete("category = ?1", cat.getId()))
.chain(__ -> matchRepository.delete("category = ?1 AND category_ord = -42", cat)); .chain(__ -> matchRepository.delete("category = ?1 AND category_ord = -42", cat));
} }
Uni<Long> finalUni = uni; return uni;
return Panache.withTransaction(() -> finalUni);
}) })
.invoke(cat -> SSCategorie.sendCategory(connection, cat)) .call(cat -> SSCategorie.sendCategory(connection, cat))
.replaceWithVoid(); .replaceWithVoid();
} }
@ -210,17 +201,7 @@ public class RCategorie {
.call(__ -> treeRepository.flush()) .call(__ -> treeRepository.flush())
.call(cat -> treeRepository.list("category = ?1 AND level != 0", cat.getId()) .call(cat -> treeRepository.list("category = ?1 AND level != 0", cat.getId())
.map(treeModels -> treeModels.stream().map(TreeEntity::fromModel).toList()) .map(treeModels -> treeModels.stream().map(TreeEntity::fromModel).toList())
.invoke(trees -> SSCategorie.sendTreeCategory(connection, trees))) .chain(trees -> SSCategorie.sendTreeCategory(connection, trees)))
.replaceWithVoid();
}
@WSReceiver(code = "deleteCategory", permission = PermLevel.ADMIN)
public Uni<Void> deleteCategory(WebSocketConnection connection, Long id) {
return getById(id, connection)
.call(cat -> Panache.withTransaction(() -> treeRepository.delete("category = ?1", cat.getId())
.call(__ -> matchRepository.delete("category = ?1", cat))))
.chain(cat -> Panache.withTransaction(() -> categoryRepository.delete(cat)))
.invoke(__ -> SSCategorie.sendDelCategory(connection, id))
.replaceWithVoid(); .replaceWithVoid();
} }
@ -244,6 +225,5 @@ public class RCategorie {
String liceName; String liceName;
List<TreeEntity> trees = null; List<TreeEntity> trees = null;
List<MatchEntity> matches; List<MatchEntity> matches;
List<CardModel> cards;
} }
} }

View File

@ -4,7 +4,6 @@ import fr.titionfire.ffsaf.data.model.*;
import fr.titionfire.ffsaf.data.repository.*; import fr.titionfire.ffsaf.data.repository.*;
import fr.titionfire.ffsaf.domain.entity.MatchEntity; import fr.titionfire.ffsaf.domain.entity.MatchEntity;
import fr.titionfire.ffsaf.domain.entity.TreeEntity; import fr.titionfire.ffsaf.domain.entity.TreeEntity;
import fr.titionfire.ffsaf.domain.service.TradService;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException; import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.rest.exception.DNotFoundException; import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
import fr.titionfire.ffsaf.utils.ScoreEmbeddable; import fr.titionfire.ffsaf.utils.ScoreEmbeddable;
@ -45,19 +44,13 @@ public class RMatch {
@Inject @Inject
CompetitionGuestRepository competitionGuestRepository; CompetitionGuestRepository competitionGuestRepository;
@Inject
TradService trad;
@Inject
RState rState;
private Uni<MatchModel> getById(long id, WebSocketConnection connection) { private Uni<MatchModel> getById(long id, WebSocketConnection connection) {
return matchRepository.findById(id) return matchRepository.findById(id)
.invoke(Unchecked.consumer(o -> { .invoke(Unchecked.consumer(o -> {
if (o == null) if (o == null)
throw new DNotFoundException(trad.t("matche.non.trouver")); throw new DNotFoundException("Matche non trouver");
if (!o.getCategory().getCompet().getUuid().equals(connection.pathParam("uuid"))) if (!o.getCategory().getCompet().getUuid().equals(connection.pathParam("uuid")))
throw new DForbiddenException(trad.t("permission.denied")); throw new DForbiddenException("Permission denied");
})); }));
} }
@ -85,13 +78,13 @@ public class RMatch {
return categoryRepository.findById(m.categorie) return categoryRepository.findById(m.categorie)
.invoke(Unchecked.consumer(o -> { .invoke(Unchecked.consumer(o -> {
if (o == null) if (o == null)
throw new DNotFoundException(trad.t("categorie.non.trouver")); throw new DNotFoundException("Catégorie non trouver");
if (!o.getCompet().getUuid().equals(connection.pathParam("uuid"))) if (!o.getCompet().getUuid().equals(connection.pathParam("uuid")))
throw new DForbiddenException(trad.t("permission.denied")); throw new DForbiddenException("Permission denied");
})) }))
.chain(categoryModel -> creatMatch(categoryModel, m)) .chain(categoryModel -> creatMatch(categoryModel, m))
.chain(mm -> Panache.withTransaction(() -> matchRepository.create(mm))) .chain(mm -> Panache.withTransaction(() -> matchRepository.create(mm)))
.invoke(mm -> SSMatch.sendMatch(connection, MatchEntity.fromModel(mm))) .call(mm -> SSMatch.sendMatch(connection, MatchEntity.fromModel(mm)))
.replaceWithVoid(); .replaceWithVoid();
} }
@ -128,7 +121,7 @@ public class RMatch {
mm.setC2_guest(null); mm.setC2_guest(null);
})) }))
.chain(mm -> Panache.withTransaction(() -> matchRepository.persist(mm))) .chain(mm -> Panache.withTransaction(() -> matchRepository.persist(mm)))
.invoke(mm -> SSMatch.sendMatch(connection, MatchEntity.fromModel(mm))) .call(mm -> SSMatch.sendMatch(connection, MatchEntity.fromModel(mm)))
.replaceWithVoid(); .replaceWithVoid();
} }
@ -143,7 +136,7 @@ public class RMatch {
m.getCategory_ord())) m.getCategory_ord()))
.invoke(m -> m.setCategory_ord(order.pos)) .invoke(m -> m.setCategory_ord(order.pos))
.call(m -> Panache.withTransaction(() -> matchRepository.persist(m))) .call(m -> Panache.withTransaction(() -> matchRepository.persist(m)))
.invoke(mm -> SSMatch.sendMatchOrder(connection, order)) .call(mm -> SSMatch.sendMatchOrder(connection, order))
.replaceWithVoid(); .replaceWithVoid();
} }
@ -170,12 +163,12 @@ public class RMatch {
.call(mm -> { .call(mm -> {
if (mm.isEnd() && mm.win() != old_win && mm.getCategory_ord() == -42) { if (mm.isEnd() && mm.win() != old_win && mm.getCategory_ord() == -42) {
return updateEndAndTree(mm, new ArrayList<>()) return updateEndAndTree(mm, new ArrayList<>())
.invoke(l -> SSMatch.sendMatch(connection, l)); .call(l -> SSMatch.sendMatch(connection, l));
} }
return Uni.createFrom().nullItem(); return Uni.createFrom().nullItem();
}); });
}) })
.invoke(mm -> SSMatch.sendMatch(connection, MatchEntity.fromModel(mm))) .call(mm -> SSMatch.sendMatch(connection, MatchEntity.fromModel(mm)))
.replaceWithVoid(); .replaceWithVoid();
} }
@ -195,9 +188,8 @@ public class RMatch {
return Panache.withTransaction(() -> matchRepository.persist(mm)); return Panache.withTransaction(() -> matchRepository.persist(mm));
}) })
.invoke(mm -> toSend.add(MatchEntity.fromModel(mm))) .invoke(mm -> toSend.add(MatchEntity.fromModel(mm)))
.invoke(mm -> rState.setMatchEnd(connection, matchEnd))
.chain(mm -> updateEndAndTree(mm, toSend)) .chain(mm -> updateEndAndTree(mm, toSend))
.invoke(__ -> SSMatch.sendMatch(connection, toSend)) .call(__ -> SSMatch.sendMatch(connection, toSend))
.replaceWithVoid(); .replaceWithVoid();
} }
@ -285,9 +277,8 @@ public class RMatch {
@WSReceiver(code = "deleteMatch", permission = PermLevel.ADMIN) @WSReceiver(code = "deleteMatch", permission = PermLevel.ADMIN)
public Uni<Void> deleteMatch(WebSocketConnection connection, Long idMatch) { public Uni<Void> deleteMatch(WebSocketConnection connection, Long idMatch) {
return getById(idMatch, connection) return getById(idMatch, connection)
.map(__ -> idMatch) .chain(matchModel -> Panache.withTransaction(() -> matchRepository.delete(matchModel)))
.chain(l -> Panache.withTransaction(() -> matchRepository.delete("id = ?1", l))) .call(__ -> SSMatch.sendDeleteMatch(connection, idMatch))
.invoke(__ -> SSMatch.sendDeleteMatch(connection, idMatch))
.replaceWithVoid(); .replaceWithVoid();
} }
@ -297,15 +288,13 @@ public class RMatch {
return categoryRepository.findById(data.categorie) return categoryRepository.findById(data.categorie)
.invoke(Unchecked.consumer(o -> { .invoke(Unchecked.consumer(o -> {
if (o == null) if (o == null)
throw new DNotFoundException(trad.t("categorie.non.trouver")); throw new DNotFoundException("Catégorie non trouver");
if (!o.getCompet().getUuid().equals(connection.pathParam("uuid"))) if (!o.getCompet().getUuid().equals(connection.pathParam("uuid")))
throw new DForbiddenException(trad.t("permission.denied")); throw new DForbiddenException("Permission denied");
})) }))
.call(cm -> data.matchesToRemove.isEmpty() ? Uni.createFrom().voidItem() : .call(cm -> matchRepository.delete("id IN ?1 AND category = ?2", data.matchesToRemove, cm)
(Panache.withTransaction( .call(__ -> SSMatch.sendDeleteMatch(connection, data.matchesToRemove)))
() -> matchRepository.delete("id IN ?1 AND category = ?2", data.matchesToRemove, cm)) .call(cm -> matchRepository.list("id IN ?1 AND category = ?2",
.invoke(__ -> SSMatch.sendDeleteMatch(connection, data.matchesToRemove))))
.call(cm -> Panache.withSession(() -> matchRepository.list("id IN ?1 AND category = ?2",
Stream.concat(data.matchOrderToUpdate.keySet().stream(), Stream.concat(data.matchOrderToUpdate.keySet().stream(),
data.matchPouleToUpdate.keySet().stream()) data.matchPouleToUpdate.keySet().stream())
.distinct().toList(), cm) .distinct().toList(), cm)
@ -315,22 +304,19 @@ public class RMatch {
if (data.matchOrderToUpdate.containsKey(model.getId())) if (data.matchOrderToUpdate.containsKey(model.getId()))
model.setCategory_ord(data.matchOrderToUpdate.get(model.getId())); model.setCategory_ord(data.matchOrderToUpdate.get(model.getId()));
})) }))
.call(mm -> mm.isEmpty() ? Uni.createFrom().voidItem() : .call(mm -> Panache.withTransaction(() -> matchRepository.persist(mm)))
Panache.withTransaction(() -> matchRepository.persist(mm))) .invoke(mm -> matches.addAll(mm.stream().map(MatchEntity::fromModel).toList()))
.invoke(mm -> matches.addAll(mm.stream().map(MatchEntity::fromModel).toList())))
) )
.chain(categoryModel -> { .chain(categoryModel -> {
Uni<List<MatchModel>> uni = Uni.createFrom().item(new ArrayList<>()); Uni<List<MatchModel>> uni = Uni.createFrom().item(new ArrayList<>());
for (AddMatch match : data.newMatch) for (AddMatch match : data.newMatch)
uni = uni.call(l -> creatMatch(categoryModel, match).invoke(l::add)); uni = uni.call(l -> creatMatch(categoryModel, match).invoke(l::add));
Uni<List<MatchModel>> finalUni = uni; return uni;
return Panache.withSession(() -> finalUni);
} }
) )
.chain(mm -> mm.isEmpty() ? Uni.createFrom().voidItem() : .chain(mm -> Panache.withTransaction(() -> matchRepository.create(mm))
Panache.withTransaction(() -> matchRepository.create(mm))
.invoke(__ -> matches.addAll(mm.stream().map(MatchEntity::fromModel).toList()))) .invoke(__ -> matches.addAll(mm.stream().map(MatchEntity::fromModel).toList())))
.invoke(__ -> SSMatch.sendMatch(connection, matches)) .call(__ -> SSMatch.sendMatch(connection, matches))
.replaceWithVoid(); .replaceWithVoid();
} }

View File

@ -1,149 +0,0 @@
package fr.titionfire.ffsaf.ws.recv;
import fr.titionfire.ffsaf.ws.PermLevel;
import fr.titionfire.ffsaf.ws.send.SSState;
import io.quarkus.runtime.annotations.RegisterForReflection;
import io.quarkus.websockets.next.UserData;
import io.quarkus.websockets.next.WebSocketConnection;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import lombok.Data;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
@ApplicationScoped
@RegisterForReflection
public class RState {
private static final HashMap<WebSocketConnection, TableState> tableStates = new HashMap<>();
@WSReceiver(code = "subscribeToState", permission = PermLevel.VIEW)
public Uni<List<TableState>> sendCurrentScore(WebSocketConnection connection, Boolean subscribe) {
connection.userData().put(UserData.TypedKey.forBoolean("needState"), subscribe);
if (subscribe) {
String uuid = connection.pathParam("uuid");
return Uni.createFrom().item(() ->
tableStates.values().stream().filter(s -> s.getCompetitionUuid().equals(uuid)).toList()
);
}
return Uni.createFrom().nullItem();
}
@WSReceiver(code = "sendState", permission = PermLevel.TABLE)
public Uni<Void> sendState(WebSocketConnection connection, TableState tableState) {
tableState.setCompetitionUuid(connection.pathParam("uuid"));
if (tableStates.containsKey(connection))
tableState.setId(tableStates.get(connection).getId());
if (tableState.getChronoState().isRunning() && tableState.getChronoState().state == 0)
tableState.setState(MatchState.IN_PROGRESS);
tableStates.put(connection, tableState);
SSState.sendStateFull(connection, tableState);
return Uni.createFrom().voidItem();
}
@WSReceiver(code = "sendSelectCategory", permission = PermLevel.TABLE)
public Uni<Void> sendSelectCategory(WebSocketConnection connection, Long catId) {
TableState tableState = tableStates.get(connection);
if (tableState != null) {
tableState.setSelectedCategory(catId);
tableState.setState(MatchState.NOT_STARTED);
SSState.sendStateFull(connection, tableState);
}
return Uni.createFrom().voidItem();
}
@WSReceiver(code = "sendSelectMatch", permission = PermLevel.TABLE)
public Uni<Void> sendSelectMatch(WebSocketConnection connection, Long matchId) {
TableState tableState = tableStates.get(connection);
if (tableState != null) {
tableState.setSelectedMatch(matchId);
tableState.setState(MatchState.NOT_STARTED);
SSState.sendStateFull(connection, tableState);
}
return Uni.createFrom().voidItem();
}
@WSReceiver(code = "sendCurentChrono", permission = PermLevel.TABLE)
public Uni<Void> sendCurentChrono(WebSocketConnection connection, ChronoState chronoState) {
TableState tableState = tableStates.get(connection);
if (tableState != null) {
tableState.setChronoState(chronoState);
if (chronoState.isRunning())
tableState.setState(MatchState.IN_PROGRESS);
SSState.sendStateFull(connection, tableState);
}
return Uni.createFrom().voidItem();
}
@WSReceiver(code = "sendLicenceName", permission = PermLevel.TABLE)
public Uni<Void> sendCurrentScore(WebSocketConnection connection, String name) {
TableState tableState = tableStates.get(connection);
if (tableState != null) {
tableState.setLiceName(name);
SSState.sendStateFull(connection, tableState);
}
return Uni.createFrom().voidItem();
}
@WSReceiver(code = "sendCurrentScore", permission = PermLevel.TABLE)
public Uni<Void> sendCurrentScore(WebSocketConnection connection, ScoreState scoreState) {
TableState tableState = tableStates.get(connection);
if (tableState != null) {
tableState.setScoreState(scoreState);
SSState.sendStateFull(connection, tableState);
}
return Uni.createFrom().voidItem();
}
public void removeConnection(WebSocketConnection connection) {
if (tableStates.containsKey(connection)) {
SSState.sendRmStateFull(connection, tableStates.get(connection).getId());
tableStates.remove(connection);
}
}
public void setMatchEnd(WebSocketConnection connection, RMatch.MatchEnd matchEnd) {
if (tableStates.containsKey(connection)) {
TableState tableState = tableStates.get(connection);
if (matchEnd.end())
tableState.setState(MatchState.ENDED);
else
tableState.setState(MatchState.IN_PROGRESS);
SSState.sendStateFull(connection, tableState);
}
}
@RegisterForReflection
public record ChronoState(long time, long startTime, long configTime, long configPause, int state) {
public boolean isRunning() {
return startTime != 0 || state != 0;
}
}
@RegisterForReflection
public record ScoreState(int scoreRouge, int scoreBleu) {
}
@Data
@RegisterForReflection
public static class TableState {
UUID id = UUID.randomUUID();
String competitionUuid;
Long selectedCategory;
Long selectedMatch;
ChronoState chronoState;
ScoreState scoreState;
String liceName = "???";
MatchState state = MatchState.NOT_STARTED;
}
public enum MatchState {
NOT_STARTED,
IN_PROGRESS,
ENDED
}
}

View File

@ -1,137 +0,0 @@
package fr.titionfire.ffsaf.ws.recv;
import fr.titionfire.ffsaf.data.model.CompetitionGuestModel;
import fr.titionfire.ffsaf.data.model.RegisterModel;
import fr.titionfire.ffsaf.data.repository.CompetitionGuestRepository;
import fr.titionfire.ffsaf.data.repository.CompetitionRepository;
import fr.titionfire.ffsaf.data.repository.RegisterRepository;
import fr.titionfire.ffsaf.domain.entity.CombEntity;
import fr.titionfire.ffsaf.domain.service.TradService;
import fr.titionfire.ffsaf.utils.Categorie;
import fr.titionfire.ffsaf.utils.Genre;
import fr.titionfire.ffsaf.utils.Pair;
import fr.titionfire.ffsaf.ws.PermLevel;
import fr.titionfire.ffsaf.ws.send.SSRegister;
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 jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@WithSession
@ApplicationScoped
@RegisterForReflection
public class RTeam {
@Inject
TradService trad;
@Inject
CompetitionRepository competitionRepository;
@Inject
RegisterRepository registerRepository;
@Inject
CompetitionGuestRepository competitionGuestRepository;
@WSReceiver(code = "setTeam", permission = PermLevel.ADMIN)
public Uni<CombEntity> setTeam(WebSocketConnection connection, TeamData data) {
return competitionRepository.find("uuid", connection.pathParam("uuid")).firstResult()
.chain(cm -> registerRepository.list("membre.id IN ?1 AND competition = ?2",
data.members.stream().filter(id -> id >= 0).toList(), cm)
.chain(l -> competitionGuestRepository.list("id IN ?1",
data.members.stream().filter(id -> id < 0).map(i -> i * -1).toList())
.map(l2 -> new Pair<>(l, l2)))
.chain(pair ->
competitionGuestRepository.find("fname = ?1 AND lname = ?2 AND competition = ?3",
data.name, "__team", cm).firstResult()
.chain(team -> {
if (pair.getKey().isEmpty() && pair.getValue().isEmpty()) {
if (team != null) {
CompetitionGuestModel finalTeam1 = team;
SSRegister.sendRegisterRemove(connection, finalTeam1.getId() * -1);
return Panache.withTransaction(
() -> competitionGuestRepository.delete(finalTeam1))
.replaceWith((CombEntity) null);
} else
return Uni.createFrom().item((CombEntity) null);
}
if (team == null) {
// Create new team
team = new CompetitionGuestModel();
team.setFname(data.name);
team.setLname("__team");
team.setCompetition(cm);
team.setClub("Team");
team.setGenre(Genre.NA);
} else {
team.getComb().clear();
team.getGuest().clear();
}
team.setCategorie(Stream.concat(
pair.getKey().stream().map(RegisterModel::getCategorie2),
pair.getValue().stream().map(CompetitionGuestModel::getCategorie))
.map(Enum::ordinal)
.max(Integer::compareTo)
.map(i -> Categorie.values()[i]).orElse(Categorie.SENIOR1));
List<Integer> s = Stream.concat(
pair.getKey().stream().map(RegisterModel::getWeight),
pair.getValue().stream().map(CompetitionGuestModel::getWeight))
.filter(Objects::nonNull).toList();
if (s.isEmpty()) {
team.setWeight(null);
} else if (s.size() == 1) {
team.setWeight(s.get(0));
} else {
team.setWeight((int) s.stream().mapToInt(Integer::intValue)
.average()
.orElse(0));
}
team.setCountry(Stream.concat(
pair.getKey().stream().map(m -> m.getMembre().getCountry()),
pair.getValue().stream().map(CompetitionGuestModel::getCountry))
.filter(Objects::nonNull)
.map(String::toUpperCase)
.collect(Collectors.groupingBy(
e -> e, // Classer par élément
Collectors.counting() // Compter les occurrences
))
.entrySet()
.stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.orElse("FR"));
team.getComb().addAll(
pair.getKey().stream().map(RegisterModel::getMembre).toList());
team.getGuest().addAll(pair.getValue());
CompetitionGuestModel finalTeam = team;
return Panache.withTransaction(
() -> competitionGuestRepository.persistAndFlush(finalTeam))
.map(CombEntity::fromModel);
}))
)
.invoke(combEntity -> {
if (combEntity != null)
SSRegister.sendRegister(connection, combEntity);
});
}
@RegisterForReflection
public record TeamData(List<Long> members, String name) {
}
}

View File

@ -1,27 +0,0 @@
package fr.titionfire.ffsaf.ws.send;
import fr.titionfire.ffsaf.data.model.CardModel;
import fr.titionfire.ffsaf.ws.CompetitionWS;
import fr.titionfire.ffsaf.ws.recv.RCard;
import io.quarkus.websockets.next.WebSocketConnection;
import java.util.List;
public class SSCard {
public static void sendCards(WebSocketConnection connection, List<CardModel> cardModel) {
CompetitionWS.sendNotifyToOtherEditor(connection, "sendCards", cardModel);
}
public static void sendRmCards(WebSocketConnection connection, List<Long> ids) {
CompetitionWS.sendNotifyToOtherEditor(connection, "rmCards", ids);
}
public static void sendTeamCard(WebSocketConnection connection, RCard.SendTeamCards teamCards) {
CompetitionWS.sendNotifyToOtherEditor(connection, "sendTeamCard", teamCards);
}
public static void rmTeamCard(WebSocketConnection connection, RCard.SendTeamCards teamCards) {
CompetitionWS.sendNotifyToOtherEditor(connection, "rmTeamCard", teamCards);
}
}

View File

@ -0,0 +1,13 @@
package fr.titionfire.ffsaf.ws.send;
import fr.titionfire.ffsaf.domain.entity.CardboardEntity;
import fr.titionfire.ffsaf.ws.CompetitionWS;
import io.quarkus.websockets.next.WebSocketConnection;
import io.smallrye.mutiny.Uni;
public class SSCardboard {
public static Uni<Void> sendCardboard(WebSocketConnection connection, CardboardEntity cardboardEntity) {
return CompetitionWS.sendNotifyToOtherEditor(connection, "sendCardboard", cardboardEntity);
}
}

View File

@ -5,32 +5,29 @@ import fr.titionfire.ffsaf.domain.entity.TreeEntity;
import fr.titionfire.ffsaf.ws.CompetitionWS; import fr.titionfire.ffsaf.ws.CompetitionWS;
import fr.titionfire.ffsaf.ws.recv.RCategorie; import fr.titionfire.ffsaf.ws.recv.RCategorie;
import io.quarkus.websockets.next.WebSocketConnection; import io.quarkus.websockets.next.WebSocketConnection;
import io.smallrye.mutiny.Uni;
import java.util.List; import java.util.List;
public class SSCategorie { public class SSCategorie {
public static void sendAddCategory(WebSocketConnection connection, CategoryModel category) { public static Uni<Void> sendAddCategory(WebSocketConnection connection, CategoryModel category) {
SSCategorie.sendAddCategory(connection, RCategorie.JustCategorie.from(category)); return SSCategorie.sendAddCategory(connection, RCategorie.JustCategorie.from(category));
} }
public static void sendAddCategory(WebSocketConnection connection, RCategorie.JustCategorie justCategorie) { public static Uni<Void> sendAddCategory(WebSocketConnection connection, RCategorie.JustCategorie justCategorie) {
CompetitionWS.sendNotifyToOtherEditor(connection, "sendAddCategory", justCategorie); return CompetitionWS.sendNotifyToOtherEditor(connection, "sendAddCategory", justCategorie);
} }
public static void sendCategory(WebSocketConnection connection, CategoryModel category) { public static Uni<Void> sendCategory(WebSocketConnection connection, CategoryModel category) {
SSCategorie.sendCategory(connection, RCategorie.JustCategorie.from(category)); return SSCategorie.sendCategory(connection, RCategorie.JustCategorie.from(category));
} }
public static void sendCategory(WebSocketConnection connection, RCategorie.JustCategorie justCategorie) { public static Uni<Void> sendCategory(WebSocketConnection connection, RCategorie.JustCategorie justCategorie) {
CompetitionWS.sendNotifyToOtherEditor(connection, "sendCategory", justCategorie); return CompetitionWS.sendNotifyToOtherEditor(connection, "sendCategory", justCategorie);
} }
public static void sendTreeCategory(WebSocketConnection connection, List<TreeEntity> treeEntities) { public static Uni<Void> sendTreeCategory(WebSocketConnection connection, List<TreeEntity> treeEntities) {
CompetitionWS.sendNotifyToOtherEditor(connection, "sendTreeCategory", treeEntities); return CompetitionWS.sendNotifyToOtherEditor(connection, "sendTreeCategory", treeEntities);
}
public static void sendDelCategory(WebSocketConnection connection, Long id) {
CompetitionWS.sendNotifyToOtherEditor(connection, "sendDelCategory", id);
} }
} }

View File

@ -4,28 +4,29 @@ import fr.titionfire.ffsaf.domain.entity.MatchEntity;
import fr.titionfire.ffsaf.ws.CompetitionWS; import fr.titionfire.ffsaf.ws.CompetitionWS;
import fr.titionfire.ffsaf.ws.recv.RMatch; import fr.titionfire.ffsaf.ws.recv.RMatch;
import io.quarkus.websockets.next.WebSocketConnection; import io.quarkus.websockets.next.WebSocketConnection;
import io.smallrye.mutiny.Uni;
import java.util.List; import java.util.List;
public class SSMatch { public class SSMatch {
public static void sendMatch(WebSocketConnection connection, MatchEntity matchEntity) { public static Uni<Void> sendMatch(WebSocketConnection connection, MatchEntity matchEntity) {
SSMatch.sendMatch(connection, List.of(matchEntity)); return SSMatch.sendMatch(connection, List.of(matchEntity));
} }
public static void sendMatch(WebSocketConnection connection, List<MatchEntity> matchEntities) { public static Uni<Void> sendMatch(WebSocketConnection connection, List<MatchEntity> matchEntities) {
CompetitionWS.sendNotifyToOtherEditor(connection, "sendMatch", matchEntities); return CompetitionWS.sendNotifyToOtherEditor(connection, "sendMatch", matchEntities);
} }
public static void sendMatchOrder(WebSocketConnection connection, RMatch.MatchOrder matchOrder) { public static Uni<Void> sendMatchOrder(WebSocketConnection connection, RMatch.MatchOrder matchOrder) {
CompetitionWS.sendNotifyToOtherEditor(connection, "sendMatchOrder", matchOrder); return CompetitionWS.sendNotifyToOtherEditor(connection, "sendMatchOrder", matchOrder);
} }
public static void sendDeleteMatch(WebSocketConnection connection, Long l) { public static Uni<Void> sendDeleteMatch(WebSocketConnection connection, Long l) {
SSMatch.sendDeleteMatch(connection, List.of(l)); return SSMatch.sendDeleteMatch(connection, List.of(l));
} }
public static void sendDeleteMatch(WebSocketConnection connection, List<Long> longs) { public static Uni<Void> sendDeleteMatch(WebSocketConnection connection, List<Long> longs) {
CompetitionWS.sendNotifyToOtherEditor(connection, "sendDeleteMatch", longs); return CompetitionWS.sendNotifyToOtherEditor(connection, "sendDeleteMatch", longs);
} }
} }

View File

@ -1,16 +0,0 @@
package fr.titionfire.ffsaf.ws.send;
import fr.titionfire.ffsaf.domain.entity.CombEntity;
import fr.titionfire.ffsaf.ws.CompetitionWS;
import io.quarkus.websockets.next.WebSocketConnection;
public class SSRegister {
public static void sendRegister(WebSocketConnection connection, CombEntity combEntity) {
CompetitionWS.sendNotifyToOtherEditor(connection, "sendRegister", combEntity);
}
public static void sendRegisterRemove(WebSocketConnection connection, Long combId) {
CompetitionWS.sendNotifyToOtherEditor(connection, "sendRegisterRemove", combId);
}
}

View File

@ -1,19 +0,0 @@
package fr.titionfire.ffsaf.ws.send;
import fr.titionfire.ffsaf.ws.CompetitionWS;
import fr.titionfire.ffsaf.ws.recv.RState;
import io.quarkus.websockets.next.WebSocketConnection;
import java.util.UUID;
public class SSState {
public static void sendStateFull(WebSocketConnection connection, RState.TableState state) {
CompetitionWS.sendNotifyState(connection, "sendStateFull", state);
}
public static void sendRmStateFull(WebSocketConnection connection, UUID id) {
CompetitionWS.sendNotifyState(connection, "rmStateFull", id);
}
}

View File

@ -8,9 +8,8 @@ quarkus.hibernate-orm.database.generation=update
quarkus.hibernate-orm.physical-naming-strategy=fr.titionfire.ffsaf.data.SafcaNamingStrategy quarkus.hibernate-orm.physical-naming-strategy=fr.titionfire.ffsaf.data.SafcaNamingStrategy
quarkus.hibernate-orm.dialect=fr.titionfire.ffsaf.data.CustomPostgreSQLDialect quarkus.hibernate-orm.dialect=fr.titionfire.ffsaf.data.CustomPostgreSQLDialect
quarkus.datasource.jdbc.reactive.max-size=40
quarkus.http.cors.enabled=true quarkus.http.cors=true
quarkus.quartz.start-mode=forced quarkus.quartz.start-mode=forced
%dev.pdf-maker.jar-path=src\\main\\pdf_gen\\target\\pdf_gen-1.0-SNAPSHOT-jar-with-dependencies.jar %dev.pdf-maker.jar-path=src\\main\\pdf_gen\\target\\pdf_gen-1.0-SNAPSHOT-jar-with-dependencies.jar
@ -68,7 +67,7 @@ quarkus.http.auth.permission.public.policy=permit
quarkus.keycloak.admin-client.server-url=https://auth.safca.fr quarkus.keycloak.admin-client.server-url=https://auth.safca.fr
quarkus.native.resources.includes=asset/**,lang/** quarkus.native.resources.includes=asset/**
# HelloAsso Connector # HelloAsso Connector
helloasso.api=https://api.helloasso.com helloasso.api=https://api.helloasso.com
@ -76,4 +75,6 @@ helloasso.client-id=changeme
helloasso.client-secret=changeme helloasso.client-secret=changeme
quarkus.rest-client.helloasso-auth.url=${helloasso.api}/oauth2 quarkus.rest-client.helloasso-auth.url=${helloasso.api}/oauth2
quarkus.rest-client.helloasso-auth.scope=javax.inject.Singleton
quarkus.rest-client.helloasso-api.url=${helloasso.api}/v5 quarkus.rest-client.helloasso-api.url=${helloasso.api}/v5

View 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

View File

@ -1,89 +0,0 @@
filtre.all=--all--
no.licence=Not licensed
Cat.SUPER_MINI=Super Mini
Cat.MINI_POUSSIN=Mini Chick
Cat.POUSSIN=Chick
Cat.BENJAMIN=Benjamin
Cat.MINIME=Minime
Cat.CADET=Cadet
Cat.JUNIOR=Junior
Cat.SENIOR1=Senior 1
Cat.SENIOR2=Senior 2
Cat.VETERAN1=Veteran 1
Cat.VETERAN2=Veteran 2
access.denied=Access denied
club.not.found=Club not found
combattant.non.inscrit=Fighter not registered
comb.not.found=Fighter not found
matche.non.trouver=Match not found
permission.denied=Permission denied
categorie.non.trouver=Category not found
RoleAsso.MEMBRE=Member
RoleAsso.PRESIDENT=President
RoleAsso.VPRESIDENT=Vice-President
RoleAsso.SECRETAIRE=Secretary
RoleAsso.VSECRETAIRE=Vice-Secretary
RoleAsso.TRESORIER=Treasurer
RoleAsso.VTRESORIER=Vice-Treasurer
RoleAsso.MEMBREBUREAU=Board Member
sans.club=No club
categorie.inconnue=Unknown category
GradeArbitrage.NA=N/A
GradeArbitrage.ASSESSEUR=Assessor
GradeArbitrage.ARBITRE=Referee
Genre.Homme=Male
Genre.Femme=Female
Genre.NA=Not defined
Contact.COURRIEL=Email
Contact.TELEPHONE=Phone
Contact.SITE=Website
Contact.FACEBOOK=Facebook
Contact.INSTAGRAM=Instagram
Contact.AUTRE=Other
service.momentanement.indisponible=Service temporarily unavailable
asso.introuvable=Association not found
erreur.lors.calcul.du.trie=Error during sorting calculation
page.out.of.range=Page out of range
le.membre.appartient.pas.a.votre.club=Member no. %d does not belong to your club
email.deja.utilise.par=Email '%s' already used by %s %s
try.edit.licence=To register a new member, please leave the license field blank. (Unauthorized attempt to change the name on license %d for %s %s)
email.deja.utilise=Email already in use
regiter.new.membre=To register a new member, please use the dedicated button.
permission.insuffisante=Insufficient permission
membre.deja.existent=Member already exists
membre.rm.err1=Cannot delete a member who already has a license number
membre.rm.err2=Cannot delete a member with licenses
pas.de.licence.pour.la.saison.en.cours=No license for the current season
club.non.trouve=Club not found
pas.d.affiliation.pour.la.saison.en.cours=No affiliation for the current season
erreur.lors.de.la.selection.des.membres=Error during member selection
licence.rm.err1=Cannot delete a license for which payment is in progress
licence.deja.demandee=License already requested
impossible.de.supprimer.une.licence.deja.validee=Cannot delete an already validated license
impossible.de.supprimer.une.licence.deja.payee=Cannot delete an already paid license
vous.ne.pouvez.pas.creer.de.competition=You cannot create a competition
user.not.found=User %s not found
inscription.fermee=Registration closed
insc.err1=You do not have the right to register this member (by decision of the competition administrator)
insc.err2=You do not have the right to register (by decision of the competition administrator)
insc.err3=Modification blocked by the competition administrator
licence.non.trouve=License %s not found
nom.et.prenom.requis=Last name and first name required
combattant.non.trouve=Fighter %s %s not found
le.membre.n.existe.pas=Member %d does not exist
competition.is.not.internal=Competition is not INTERNAL
erreur.de.format.des.contacts=Contact format error
competition.not.found=Competition not found
saison.non.valid=Invalid season
demande.d.affiliation.deja.existante=Affiliation request already exists
affiliation.deja.existante=Affiliation already exists
licence.membre.n.1.inconnue=License member no. 1 unknown
licence.membre.n.2.inconnue=License member no. 2 unknown
licence.membre.n.3.inconnue=License member no. 3 unknown
demande.d.affiliation.non.trouve=Affiliation request not found
carton.non.trouver=Card not found
card.cannot.be.added=Unable to add the card

Some files were not shown because too many files have changed in this diff Show More