Compare commits
166 Commits
dev-comp
...
4a07eb4ed9
| Author | SHA1 | Date | |
|---|---|---|---|
| 4a07eb4ed9 | |||
| d2a7e6cbac | |||
| 78d22b466d | |||
| b419e2f58d | |||
| a5d3973394 | |||
| 4dff0940c1 | |||
| eed7a10cfb | |||
| 1cbbde6506 | |||
| e8d5d0fa0c | |||
| a5bbc41dfd | |||
| 01436ac220 | |||
| 0150c4fac2 | |||
| c456fdae8b | |||
| 4bf07cc8f8 | |||
| a8356c8663 | |||
| c7a2215103 | |||
| 46f543abde | |||
| d8b6f1ad25 | |||
| 9170157dbb | |||
| babbc5d585 | |||
| 51c774a21e | |||
| 9d85b9ae45 | |||
| 0ab0731ebd | |||
| ec48f73d9f | |||
| f98f1bd1ac | |||
| b9d752ac55 | |||
| 13650b27c1 | |||
| 0757ae7198 | |||
| a871b52006 | |||
| 78959fc485 | |||
| 0a91e72c29 | |||
| e3a1d1c50b | |||
| 3933954e09 | |||
| 959e356fb9 | |||
| 3b5955ff31 | |||
| e8ee5811a0 | |||
| 12326fe122 | |||
| 9624ff93f0 | |||
| 5444235512 | |||
| b54eaa2549 | |||
| 6a7af8aea9 | |||
| bc4dbb532f | |||
| 0e269e0bf7 | |||
| 6d6324e1b4 | |||
| 309f2a2268 | |||
| 13bae3e817 | |||
| c6751b0428 | |||
| 237952f95a | |||
| 075f01a205 | |||
| 82231744af | |||
| 71a4d98434 | |||
| 29a1184994 | |||
| 3d07a5bc8e | |||
| a730384d37 | |||
| 412e661319 | |||
| bc72b7912c | |||
| 6359e7e027 | |||
| c7a9cc221f | |||
| 17c61be171 | |||
| 76f69c2154 | |||
| 639f07ccdc | |||
| c02e37862c | |||
| 2b6dc48880 | |||
| 6879d9195d | |||
| 1595fb57c3 | |||
| 8067d496f8 | |||
| aba8d8a202 | |||
| 38663d97c2 | |||
| 377ce70125 | |||
| 61cee85335 | |||
| 19949d1e35 | |||
| 03cdcf78c8 | |||
| 0b4f843084 | |||
| fa00273c87 | |||
| b2438e52fc | |||
| 31bbe5719f | |||
| bf377c9c5e | |||
| 145d5e7ca8 | |||
| 448e49b9fd | |||
| b7a1e58436 | |||
| a73a3562c3 | |||
| 0dace76fc3 | |||
| f76ca43ed6 | |||
| c6b24a1b20 | |||
| c47c04c29e | |||
| e06df24002 | |||
| 352c34064f | |||
| 2ccd2a9178 | |||
| 0ff3ffd66b | |||
| 847674d62c | |||
| 8896e2a28a | |||
| 68b4f8e476 | |||
| d3fb884ab4 | |||
| 81faafe2de | |||
| ee730be570 | |||
| 4856326b29 | |||
| b94f4b43ce | |||
| 795d044c0b | |||
| dc5ab9c3c4 | |||
| 870891a77c | |||
| 7e1356b621 | |||
| b689521e56 | |||
| e81f475402 | |||
| 095a5fcede | |||
| 3decc6d0e0 | |||
| 254fd7d73f | |||
| 12a75d003c | |||
| 7f957b98f2 | |||
| 8b2c9613fd | |||
| 50b49c40e3 | |||
| 47d3921e05 | |||
| ecc9753237 | |||
| 7c4addd525 | |||
| a8565534e6 | |||
| 43fcbb5ef6 | |||
| fefc5d651b | |||
| 163d9b23e9 | |||
| 53509820c6 | |||
| a8ad3a7558 | |||
| f46e268d39 | |||
| abad3194a4 | |||
| 6e7eec0587 | |||
| 8c83668364 | |||
| 771c06ccd8 | |||
| b479b992cf | |||
| f018e52afa | |||
| be2f01c070 | |||
| 9ab50238b9 | |||
| cf5d93630f | |||
| e5e17d3862 | |||
| 7410569ced | |||
| b107f443aa | |||
| 8e2d68ebd5 | |||
| f050127fd7 | |||
| d02fd63834 | |||
| b143cc759f | |||
| cc5534ef00 | |||
| 26f56006f6 | |||
| f8dacee3e7 | |||
| ed1f30f2b6 | |||
| 8517e9824c | |||
| 6cec8ff31d | |||
| e7deba52e9 | |||
| d95c173fa8 | |||
| 8a0e4423f2 | |||
| b956236934 | |||
| 7767c98304 | |||
| 7e380ccb69 | |||
| 94d1148eb1 | |||
| 8a14f58ce5 | |||
| 79dbbdaaec | |||
| bf5704db54 | |||
| dec98f9508 | |||
| d3a62e980d | |||
| b89ed62795 | |||
| 5ffc9fb495 | |||
| 5e48bc4623 | |||
| 81b953fb05 | |||
| c6659f8d85 | |||
| e86fe42b3d | |||
| ef528aa524 | |||
| e6cc4cbc96 | |||
| c58dedf80a | |||
| 1908de681e | |||
| 76381c75bd | |||
| 7d281196c1 |
@@ -17,17 +17,38 @@ jobs:
|
||||
steps:
|
||||
- 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
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17.0.12'
|
||||
java-version: '21'
|
||||
distribution: 'graalvm'
|
||||
cache: 'maven'
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '18'
|
||||
node-version: '22'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: src/main/webapp/package-lock.json
|
||||
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -50,3 +50,4 @@ nb-configuration.xml
|
||||
/media/
|
||||
/media-ext/
|
||||
/sign.jpg
|
||||
/.gitea/workflows/test.yml
|
||||
|
||||
53
README.md
53
README.md
@@ -1,8 +1,22 @@
|
||||
# ffsaf-site
|
||||
# FFSAF - Intranet
|
||||
|
||||
This project uses Quarkus, the Supersonic Subatomic Java Framework.
|
||||
## Introduction et context
|
||||
|
||||
If you want to learn more about Quarkus, please visit its website: https://quarkus.io/ .
|
||||
L’intranet de la Fédération française de Soft Armored Fighting a pour but centralise la prise de licences des adhérents
|
||||
et l’affiliation des clubs. Il permet aussi de recueillir les résultats des compétitions organisées par les clubs et,
|
||||
plus récemment, d’en faciliter l’organisation 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 d’affiliation ;
|
||||
* 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 d’affiliation.
|
||||
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 d’une poule. Il supporte plusieurs lices, assure la synchronisation en temps réel des modifications
|
||||
entre toutes les instances de l’application web et publie automatiquement les résultats sur le site de l’organisateur.
|
||||
|
||||
## Running the application in dev mode
|
||||
|
||||
@@ -51,35 +65,4 @@ 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`
|
||||
|
||||
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)
|
||||
If you want to learn more about building native executables, please consult https://quarkus.io/guides/maven-tooling.
|
||||
@@ -20,6 +20,11 @@ services:
|
||||
- default
|
||||
- intra
|
||||
- nginx
|
||||
healthcheck:
|
||||
test: [ "CMD", "curl", "-f", "https://intra.ffsaf.fr/api" ]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
ffsaf-db:
|
||||
image: public.ecr.aws/docker/library/postgres:17.2
|
||||
|
||||
18
pom.xml
18
pom.xml
@@ -11,7 +11,7 @@
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
|
||||
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
|
||||
<quarkus.platform.version>3.16.4</quarkus.platform.version>
|
||||
<quarkus.platform.version>3.30.5</quarkus.platform.version>
|
||||
<skipITs>true</skipITs>
|
||||
<surefire-plugin.version>3.2.3</surefire-plugin.version>
|
||||
</properties>
|
||||
@@ -56,19 +56,15 @@
|
||||
<artifactId>quarkus-rest-client-jackson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.vertx</groupId>
|
||||
<artifactId>vertx-mssql-client</artifactId>
|
||||
<version>4.4.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-arc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.quarkiverse.tika</groupId>
|
||||
<artifactId>quarkus-tika</artifactId>
|
||||
<version>2.0.4</version>
|
||||
<groupId>io.quarkiverse.antivirus</groupId>
|
||||
<artifactId>quarkus-antivirus</artifactId>
|
||||
<version>1.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -96,7 +92,7 @@
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.22</version>
|
||||
<version>1.18.42</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -127,7 +123,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.xmlgraphics</groupId>
|
||||
<artifactId>fop</artifactId>
|
||||
<version>2.6</version>
|
||||
<version>2.11</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
|
||||
48
src/main/java/fr/titionfire/ffsaf/UserInfoProvider.java
Normal file
48
src/main/java/fr/titionfire/ffsaf/UserInfoProvider.java
Normal file
@@ -0,0 +1,48 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -44,4 +44,8 @@ public class CategoryModel {
|
||||
Integer type;
|
||||
|
||||
String liceName = "1";
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "id_preset", referencedColumnName = "id")
|
||||
CatPresetModel preset;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package fr.titionfire.ffsaf.data.model;
|
||||
|
||||
import fr.titionfire.ffsaf.utils.ResultPrivacy;
|
||||
|
||||
public interface CombModel {
|
||||
Long getCombId();
|
||||
String getName();
|
||||
String getName(MembreModel model, ResultPrivacy privacy);
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package fr.titionfire.ffsaf.data.model;
|
||||
|
||||
import fr.titionfire.ffsaf.utils.Categorie;
|
||||
import fr.titionfire.ffsaf.utils.Genre;
|
||||
import fr.titionfire.ffsaf.utils.ResultPrivacy;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -9,6 +10,11 @@ import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@@ -17,7 +23,7 @@ import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Table(name = "competition_guest")
|
||||
public class CompetitionGuestModel {
|
||||
public class CompetitionGuestModel implements CombModel {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
Long id;
|
||||
@@ -38,13 +44,72 @@ public class CompetitionGuestModel {
|
||||
String country = "fr";
|
||||
|
||||
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) {
|
||||
this.fname = s.substring(0, s.indexOf(" "));
|
||||
this.lname = s.substring(s.indexOf(" ") + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getCombId() {
|
||||
return this.id * -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return fname + " " + lname;
|
||||
if (this.isTeam())
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package fr.titionfire.ffsaf.data.model;
|
||||
|
||||
import fr.titionfire.ffsaf.utils.Categorie;
|
||||
import fr.titionfire.ffsaf.utils.CompetitionSystem;
|
||||
import fr.titionfire.ffsaf.utils.RegisterMode;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
@@ -58,6 +59,10 @@ public class CompetitionModel {
|
||||
@OneToMany(mappedBy = "competition", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
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<>();
|
||||
|
||||
@@ -67,8 +72,15 @@ public class CompetitionModel {
|
||||
@Column(name = "table_")
|
||||
List<String> table = new ArrayList<>();
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
String data1;
|
||||
@Column(columnDefinition = "TEXT")
|
||||
String data2;
|
||||
@Column(columnDefinition = "TEXT")
|
||||
String data3;
|
||||
@Column(columnDefinition = "TEXT")
|
||||
String data4;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
String config;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public class LogModel {
|
||||
}
|
||||
|
||||
public enum ObjectType {
|
||||
Membre, Affiliation, Licence, Club, Competition, Register
|
||||
Membre, Affiliation, Licence, Club, Competition, Register, Selection
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package fr.titionfire.ffsaf.data.model;
|
||||
|
||||
import fr.titionfire.ffsaf.utils.CompetitionSystem;
|
||||
import fr.titionfire.ffsaf.utils.ResultPrivacy;
|
||||
import fr.titionfire.ffsaf.utils.ScoreEmbeddable;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import jakarta.persistence.*;
|
||||
@@ -9,6 +10,7 @@ import lombok.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@@ -65,19 +67,35 @@ public class MatchModel {
|
||||
@JoinColumn(name = "match", referencedColumnName = "id")
|
||||
List<CardboardModel> cardboard = new ArrayList<>();
|
||||
|
||||
public String getC1Name(MembreModel model, ResultPrivacy privacy) {
|
||||
if (c1_id != null)
|
||||
return c1_id.getName(model, privacy);
|
||||
if (c1_guest != null)
|
||||
return c1_guest.getName(model, privacy);
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getC2Name(MembreModel model, ResultPrivacy privacy) {
|
||||
if (c2_id != null)
|
||||
return c2_id.getName(model, privacy);
|
||||
if (c2_guest != null)
|
||||
return c2_guest.getName(model, privacy);
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getC1Name() {
|
||||
if (c1_id != null)
|
||||
return c1_id.fname + " " + c1_id.lname;
|
||||
return c1_id.getName();
|
||||
if (c1_guest != null)
|
||||
return c1_guest.fname + " " + c1_guest.lname;
|
||||
return c1_guest.getName();
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getC2Name() {
|
||||
if (c2_id != null)
|
||||
return c2_id.fname + " " + c2_id.lname;
|
||||
return c2_id.getName();
|
||||
if (c2_guest != null)
|
||||
return c2_guest.fname + " " + c2_guest.lname;
|
||||
return c2_guest.getName();
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -94,4 +112,30 @@ public class MatchModel {
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package fr.titionfire.ffsaf.data.model;
|
||||
|
||||
import fr.titionfire.ffsaf.utils.Categorie;
|
||||
import fr.titionfire.ffsaf.utils.Genre;
|
||||
import fr.titionfire.ffsaf.utils.GradeArbitrage;
|
||||
import fr.titionfire.ffsaf.utils.RoleAsso;
|
||||
import fr.titionfire.ffsaf.utils.*;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.*;
|
||||
@@ -11,6 +8,7 @@ import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@@ -21,23 +19,23 @@ import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Table(name = "membre")
|
||||
public class MembreModel implements LoggableModel {
|
||||
public class MembreModel implements LoggableModel, CombModel {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Access(AccessType.PROPERTY)
|
||||
@Schema(description = "L'identifiant du membre.", example = "1")
|
||||
@Schema(description = "L'identifiant du membre.", examples = "1")
|
||||
Long id;
|
||||
|
||||
@Schema(description = "L'identifiant long du membre (userID).", example = "e81d1d35-d897-421e-8086-6c5e74d13c6e")
|
||||
@Schema(description = "L'identifiant long du membre (userID).", examples = "e81d1d35-d897-421e-8086-6c5e74d13c6e")
|
||||
String userId;
|
||||
|
||||
@Schema(description = "Le nom du membre.", example = "Dupont")
|
||||
@Schema(description = "Le nom du membre.", examples = "Dupont")
|
||||
String lname;
|
||||
@Schema(description = "Le prénom du membre.", example = "Jean")
|
||||
@Schema(description = "Le prénom du membre.", examples = "Jean")
|
||||
String fname;
|
||||
|
||||
@Schema(description = "La catégorie du membre.", example = "SENIOR")
|
||||
@Schema(description = "La catégorie du membre.", examples = "SENIOR")
|
||||
Categorie categorie;
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@@ -45,34 +43,39 @@ public class MembreModel implements LoggableModel {
|
||||
@Schema(description = "Le club du membre.")
|
||||
ClubModel club;
|
||||
|
||||
@Schema(description = "Le genre du membre.", example = "H")
|
||||
@Schema(description = "Le genre du membre.", examples = "H")
|
||||
Genre genre;
|
||||
|
||||
@Schema(description = "Le numéro de licence du membre.", example = "12345")
|
||||
@Schema(description = "Le numéro de licence du membre.", examples = "12345")
|
||||
Integer licence;
|
||||
|
||||
@Schema(description = "Le pays du membre.", example = "FR")
|
||||
@Schema(description = "Le pays du membre.", examples = "FR")
|
||||
String country;
|
||||
|
||||
@Schema(description = "La date de naissance du membre.")
|
||||
Date birth_date;
|
||||
|
||||
@Schema(description = "L'adresse e-mail du membre.", example = "jean.dupont@example.com")
|
||||
@Schema(description = "L'adresse e-mail du membre.", examples = "jean.dupont@examples.com")
|
||||
String email;
|
||||
|
||||
@Schema(description = "Le rôle du membre dans l'association.", example = "MEMBRE")
|
||||
@Schema(description = "Le rôle du membre dans l'association.", examples = "MEMBRE")
|
||||
RoleAsso role;
|
||||
|
||||
@Schema(description = "Le grade d'arbitrage du membre.", example = "NA")
|
||||
@Schema(description = "Le grade d'arbitrage du membre.", examples = "NA")
|
||||
GradeArbitrage grade_arbitrage;
|
||||
|
||||
@Schema(hidden = true)
|
||||
String url_photo;
|
||||
@Schema(description = "La confidentialité de ces résultats", examples = "PUBLIC")
|
||||
@Column(nullable = false, columnDefinition = "smallint default 0")
|
||||
ResultPrivacy resultPrivacy = ResultPrivacy.PUBLIC;
|
||||
|
||||
@OneToMany(mappedBy = "membre", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
@Schema(description = "Les licences du membre. (optionnel)")
|
||||
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
|
||||
public String getObjectName() {
|
||||
return fname + " " + lname;
|
||||
@@ -100,4 +103,25 @@ public class MembreModel implements LoggableModel {
|
||||
", grade_arbitrage=" + grade_arbitrage +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getCombId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.fname + " " + this.lname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(MembreModel model, ResultPrivacy privacy) {
|
||||
if (model == null || !Objects.equals(this.getId(), model.getId())) {
|
||||
if (model == null && this.getResultPrivacy() != ResultPrivacy.PUBLIC)
|
||||
return "Anonyme";
|
||||
if (this.getResultPrivacy().ordinal() > privacy.ordinal())
|
||||
return "Anonyme";
|
||||
}
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@ import lombok.Setter;
|
||||
import org.hibernate.annotations.OnDelete;
|
||||
import org.hibernate.annotations.OnDeleteAction;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@@ -35,6 +38,7 @@ public class RegisterModel {
|
||||
MembreModel membre;
|
||||
|
||||
Integer weight;
|
||||
Integer weightReal;
|
||||
int overCategory = 0;
|
||||
Categorie categorie;
|
||||
|
||||
@@ -46,6 +50,17 @@ public class RegisterModel {
|
||||
@Column(nullable = false, columnDefinition = "boolean default 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,
|
||||
Categorie categorie, ClubModel club) {
|
||||
this.id = new RegisterId(competition.getId(), membre.getId());
|
||||
@@ -66,4 +81,19 @@ public class RegisterModel {
|
||||
return membre.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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
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> {
|
||||
}
|
||||
@@ -2,8 +2,17 @@ package fr.titionfire.ffsaf.data.repository;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.CheckoutModel;
|
||||
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
@ApplicationScoped
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package fr.titionfire.ffsaf.data.repository;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.SelectionModel;
|
||||
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
|
||||
@ApplicationScoped
|
||||
public class SelectionRepository implements PanacheRepositoryBase<SelectionModel, Long> {
|
||||
}
|
||||
@@ -9,6 +9,10 @@ import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@RegisterForReflection
|
||||
@@ -23,6 +27,7 @@ public class CombEntity {
|
||||
String country;
|
||||
int overCategory;
|
||||
Integer weight;
|
||||
List<CombEntity> teamMembers;
|
||||
|
||||
public static CombEntity fromModel(MembreModel model) {
|
||||
if (model == null)
|
||||
@@ -31,7 +36,7 @@ public class CombEntity {
|
||||
return new CombEntity(model.getId(), model.getLname(), model.getFname(), model.getCategorie(),
|
||||
model.getClub() == null ? null : model.getClub().getClubId(),
|
||||
model.getClub() == null ? "Sans club" : model.getClub().getName(), model.getGenre(), model.getCountry(),
|
||||
0, null);
|
||||
0, null, new ArrayList<>());
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +45,9 @@ public class CombEntity {
|
||||
return 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) {
|
||||
@@ -51,6 +58,6 @@ public class CombEntity {
|
||||
return new CombEntity(model.getId(), model.getLname(), model.getFname(), registerModel.getCategorie(),
|
||||
registerModel.getClub2() == null ? null : registerModel.getClub2().getClubId(),
|
||||
registerModel.getClub2() == null ? "Sans club" : registerModel.getClub2().getName(), model.getGenre(),
|
||||
model.getCountry(), registerModel.getOverCategory(), registerModel.getWeight());
|
||||
model.getCountry(), registerModel.getOverCategory(), registerModel.getWeight(), new ArrayList<>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
package fr.titionfire.ffsaf.domain.entity;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.MembreModel;
|
||||
import fr.titionfire.ffsaf.utils.Categorie;
|
||||
import fr.titionfire.ffsaf.utils.Genre;
|
||||
import fr.titionfire.ffsaf.utils.GradeArbitrage;
|
||||
import fr.titionfire.ffsaf.utils.RoleAsso;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@RegisterForReflection
|
||||
public class MembreEntity {
|
||||
private long id;
|
||||
private String lname = "";
|
||||
private String fname = "";
|
||||
private Categorie categorie;
|
||||
private ClubEntity club;
|
||||
private Genre genre;
|
||||
private Integer licence;
|
||||
private String country;
|
||||
private Date birth_date;
|
||||
private String email;
|
||||
private RoleAsso role;
|
||||
private GradeArbitrage grade_arbitrage;
|
||||
private String url_photo;
|
||||
|
||||
|
||||
public static MembreEntity fromModel(MembreModel model) {
|
||||
if (model == null)
|
||||
return null;
|
||||
|
||||
return new MembreEntityBuilder()
|
||||
.id(model.getId())
|
||||
.lname(model.getLname())
|
||||
.fname(model.getFname())
|
||||
.categorie(model.getCategorie())
|
||||
.club(ClubEntity.fromModel(model.getClub()))
|
||||
.genre(model.getGenre())
|
||||
.licence(model.getLicence())
|
||||
.country(model.getCountry())
|
||||
.birth_date(model.getBirth_date())
|
||||
.email(model.getEmail())
|
||||
.role(model.getRole())
|
||||
.grade_arbitrage(model.getGrade_arbitrage())
|
||||
.url_photo(model.getUrl_photo())
|
||||
.build();
|
||||
}
|
||||
|
||||
public static String getFullName(MembreModel model) {
|
||||
return model.getFname() + " " + model.getLname();
|
||||
}
|
||||
public String getFullName() {
|
||||
return this.fname + " " + this.lname;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -64,6 +64,9 @@ public class AffiliationService {
|
||||
@Inject
|
||||
LoggerService ls;
|
||||
|
||||
@Inject
|
||||
VirusScannerService scanner;
|
||||
|
||||
@RestClient
|
||||
StateIdService stateIdService;
|
||||
|
||||
@@ -76,6 +79,9 @@ public class AffiliationService {
|
||||
@ConfigProperty(name = "notif.affRequest.mail")
|
||||
List<String> mails;
|
||||
|
||||
@Inject
|
||||
TradService trad;
|
||||
|
||||
public Uni<List<AffiliationRequestModel>> getAllReq() {
|
||||
return repositoryRequest.listAll();
|
||||
}
|
||||
@@ -89,7 +95,7 @@ public class AffiliationService {
|
||||
return Uni.createFrom().item(affModel)
|
||||
.invoke(Unchecked.consumer(model -> {
|
||||
if (model.getSaison() != currentSaison && model.getSaison() != currentSaison + 1) {
|
||||
throw new DBadRequestException("Saison non valid");
|
||||
throw new DBadRequestException(trad.t("saison.non.valid"));
|
||||
}
|
||||
}))
|
||||
.chain(() -> ((affModel.getState_id().charAt(0) == 'W') ? stateIdService.get_rna(
|
||||
@@ -107,7 +113,7 @@ public class AffiliationService {
|
||||
out, affModel.getSaison()))
|
||||
.onItem().invoke(Unchecked.consumer(count -> {
|
||||
if (count != 0 && unique) {
|
||||
throw new DBadRequestException("Demande d'affiliation déjà existante");
|
||||
throw new DBadRequestException(trad.t("demande.d.affiliation.deja.existante"));
|
||||
}
|
||||
}))
|
||||
)
|
||||
@@ -115,28 +121,28 @@ public class AffiliationService {
|
||||
repository.count("club = ?1 and saison = ?2", club, affModel.getSaison())))
|
||||
.onItem().invoke(Unchecked.consumer(count -> {
|
||||
if (count != 0) {
|
||||
throw new DBadRequestException("Affiliation déjà existante");
|
||||
throw new DBadRequestException(trad.t("affiliation.deja.existante"));
|
||||
}
|
||||
}))
|
||||
.map(o -> affModel)
|
||||
.call(model -> ((model.getM1_lincence() != -1) ? combRepository.find("licence",
|
||||
model.getM1_lincence()).count().invoke(Unchecked.consumer(count -> {
|
||||
if (count == 0) {
|
||||
throw new DBadRequestException("Licence membre n°1 inconnue");
|
||||
throw new DBadRequestException(trad.t("licence.membre.n.1.inconnue"));
|
||||
}
|
||||
})) : Uni.createFrom().nullItem())
|
||||
)
|
||||
.call(model -> ((model.getM2_lincence() != -1) ? combRepository.find("licence",
|
||||
model.getM2_lincence()).count().invoke(Unchecked.consumer(count -> {
|
||||
if (count == 0) {
|
||||
throw new DBadRequestException("Licence membre n°2 inconnue");
|
||||
throw new DBadRequestException(trad.t("licence.membre.n.2.inconnue"));
|
||||
}
|
||||
})) : Uni.createFrom().nullItem())
|
||||
)
|
||||
.call(model -> ((model.getM3_lincence() != -1) ? combRepository.find("licence",
|
||||
model.getM3_lincence()).count().invoke(Unchecked.consumer(count -> {
|
||||
if (count == 0) {
|
||||
throw new DBadRequestException("Licence membre n°3 inconnue");
|
||||
throw new DBadRequestException(trad.t("licence.membre.n.3.inconnue"));
|
||||
}
|
||||
})) : Uni.createFrom().nullItem())
|
||||
);
|
||||
@@ -145,7 +151,7 @@ public class AffiliationService {
|
||||
public Uni<?> saveEdit(AffiliationRequestForm form) {
|
||||
return pre_save(form, false)
|
||||
.chain(model -> repositoryRequest.findById(form.getId())
|
||||
.onItem().ifNull().failWith(new DNotFoundException("Demande d'affiliation non trouvé"))
|
||||
.onItem().ifNull().failWith(new DNotFoundException(trad.t("demande.d.affiliation.non.trouve")))
|
||||
.chain(origine -> {
|
||||
origine.setName(model.getName());
|
||||
origine.setAddress(model.getAddress());
|
||||
@@ -174,15 +180,12 @@ public class AffiliationService {
|
||||
LOGGER.debug("Affiliation Request Created");
|
||||
LOGGER.debug(form.toString());
|
||||
|
||||
// noinspection ResultOfMethodCallIgnored,ReactiveStreamsUnusedPublisher
|
||||
// noinspection ReactiveStreamsUnusedPublisher
|
||||
return pre_save(form, true)
|
||||
.chain(model -> Panache.withTransaction(() -> repositoryRequest.persist(model)))
|
||||
.onItem()
|
||||
.invoke(model -> Uni.createFrom().future(Utils.replacePhoto(model.getId(), form.getLogo(), media,
|
||||
"aff_request/logo")))
|
||||
.onItem()
|
||||
.invoke(model -> Uni.createFrom().future(Utils.replacePhoto(model.getId(), form.getStatus(), media,
|
||||
"aff_request/status")))
|
||||
.invoke(m -> Utils.uploadFile(scanner, form.getLogo(), m.getId(), media, "aff_request/logo"))
|
||||
.invoke(m -> Utils.uploadFile(scanner, form.getStatus(), m.getId(), media, "aff_request/status"))
|
||||
.call(model -> reactiveMailer.send(
|
||||
Mail.withText("no-reply@ffsaf.fr",
|
||||
"[NOTIF] FFSAF - Nouvelle demande d'affiliation",
|
||||
@@ -201,7 +204,7 @@ public class AffiliationService {
|
||||
LOGGER.debug(form.toString());
|
||||
|
||||
return repositoryRequest.findById(form.getId())
|
||||
.onItem().ifNull().failWith(new DNotFoundException("Demande d'affiliation non trouvé"))
|
||||
.onItem().ifNull().failWith(new DNotFoundException(trad.t("demande.d.affiliation.non.trouve")))
|
||||
.map(model -> {
|
||||
model.setName(form.getName());
|
||||
model.setState_id(form.getState_id());
|
||||
@@ -245,11 +248,8 @@ public class AffiliationService {
|
||||
})
|
||||
.chain(model -> Panache.withTransaction(() -> repositoryRequest.persist(model)))
|
||||
.onItem()
|
||||
.invoke(model -> Uni.createFrom().future(Utils.replacePhoto(model.getId(), form.getLogo(), media,
|
||||
"aff_request/logo")))
|
||||
.onItem()
|
||||
.invoke(model -> Uni.createFrom().future(Utils.replacePhoto(model.getId(), form.getStatus(), media,
|
||||
"aff_request/status")))
|
||||
.invoke(m -> Utils.uploadFile(scanner, form.getLogo(), m.getId(), media, "aff_request/logo"))
|
||||
.invoke(m -> Utils.uploadFile(scanner, form.getStatus(), m.getId(), media, "aff_request/status"))
|
||||
.map(__ -> "Ok");
|
||||
}
|
||||
|
||||
@@ -309,7 +309,7 @@ public class AffiliationService {
|
||||
LOGGER.debug(form.toString());
|
||||
|
||||
return repositoryRequest.findById(form.getId())
|
||||
.onItem().ifNull().failWith(new DNotFoundException("Demande d'affiliation non trouvé"))
|
||||
.onItem().ifNull().failWith(new DNotFoundException(trad.t("demande.d.affiliation.non.trouve")))
|
||||
.chain(req ->
|
||||
clubRepository.find("StateId = ?1", form.getState_id()).firstResult()
|
||||
.chain(model -> (model == null) ? acceptNew(form, req) : acceptOld(form, req, model))
|
||||
@@ -319,13 +319,11 @@ public class AffiliationService {
|
||||
.recoverWithNull()
|
||||
.call(___ -> setMembre(form.new Member(3), club, req.getSaison()))))
|
||||
.onItem()
|
||||
.invoke(model -> Uni.createFrom()
|
||||
.future(Utils.replacePhoto(form.getId(), form.getLogo(), media,
|
||||
"aff_request/logo")))
|
||||
.invoke(model -> Utils.uploadFile(scanner, form.getLogo(), form.getId(), media,
|
||||
"aff_request/logo"))
|
||||
.invoke(model -> Utils.uploadFile(scanner, form.getStatus(), form.getId(), media,
|
||||
"aff_request/status"))
|
||||
.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",
|
||||
"ppClub"))
|
||||
.call(model -> Utils.moveMedia(form.getId(), model.getId(), media, "aff_request/status",
|
||||
@@ -355,19 +353,25 @@ public class AffiliationService {
|
||||
.map(c -> club));
|
||||
})
|
||||
.call(club -> reactiveMailer.send(
|
||||
Mail.withText(form.getM1_email(),
|
||||
"FFSAF - Acceptation de votre demande d'affiliation",
|
||||
String.format(
|
||||
"""
|
||||
Bonjour,
|
||||
|
||||
Votre demande d'affiliation pour le club %s a été acceptée.
|
||||
Le numéro d'affiliation de votre club est le %d.
|
||||
|
||||
Cordialement,
|
||||
L'équipe de la FFSAF
|
||||
""", club.getName(), club.getNo_affiliation())
|
||||
).setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("contact@ffsaf.fr")
|
||||
Mail.withHtml(form.getM1_email(), "FFSAF - Creation de votre compte sur l'intranet",
|
||||
String.format(Utils.HTML_HEADER, "FFSAF - Creation de votre compte sur l'intranet") +
|
||||
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,
|
||||
|
||||
Votre demande d'affiliation pour le club %s a été acceptée.
|
||||
Le numéro d'affiliation de votre club est le %d.
|
||||
|
||||
Cordialement,
|
||||
L'équipe de la FFSAF
|
||||
""", club.getName(), club.getNo_affiliation()))
|
||||
.setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("contact@ffsaf.fr")
|
||||
.addTo(form.getM2_email(), form.getM3_email())
|
||||
));
|
||||
}
|
||||
@@ -397,7 +401,7 @@ public class AffiliationService {
|
||||
|
||||
public Uni<SimpleReqAffiliation> getRequest(long id) {
|
||||
return repositoryRequest.findById(id).map(SimpleReqAffiliation::fromModel)
|
||||
.onItem().ifNull().failWith(new DNotFoundException("Demande d'affiliation non trouvé"))
|
||||
.onItem().ifNull().failWith(new DNotFoundException(trad.t("demande.d.affiliation.non.trouve")))
|
||||
.call(out -> clubRepository.find("StateId = ?1", out.getStateId()).firstResult().invoke(c -> {
|
||||
if (c != null) {
|
||||
out.setClub(c.getId());
|
||||
@@ -421,7 +425,7 @@ public class AffiliationService {
|
||||
|
||||
public Uni<List<SimpleAffiliation>> getAffiliation(long id) {
|
||||
return clubRepository.findById(id)
|
||||
.onItem().ifNull().failWith(new DNotFoundException("Club non trouvé"))
|
||||
.onItem().ifNull().failWith(new DNotFoundException(trad.t("club.non.trouve")))
|
||||
.call(model -> Mutiny.fetch(model.getAffiliations()))
|
||||
.chain(model -> repositoryRequest.list("state_id = ?1", model.getStateId())
|
||||
.map(reqs -> reqs.stream().map(req ->
|
||||
@@ -433,11 +437,11 @@ public class AffiliationService {
|
||||
|
||||
public Uni<SimpleAffiliation> setAffiliation(long id, int saison) {
|
||||
return clubRepository.findById(id)
|
||||
.onItem().ifNull().failWith(new DNotFoundException("Club non trouvé"))
|
||||
.onItem().ifNull().failWith(new DNotFoundException(trad.t("club.non.trouve")))
|
||||
.call(model -> Mutiny.fetch(model.getAffiliations()))
|
||||
.invoke(Unchecked.consumer(club -> {
|
||||
if (club.getAffiliations().stream().anyMatch(affiliation -> affiliation.getSaison() == saison)) {
|
||||
throw new DBadRequestException("Affiliation déjà existante");
|
||||
throw new DBadRequestException(trad.t("affiliation.deja.existante"));
|
||||
}
|
||||
}))
|
||||
.chain(club ->
|
||||
@@ -458,21 +462,27 @@ public class AffiliationService {
|
||||
public Uni<?> deleteReqAffiliation(long id, String reason, boolean federationAdmin) {
|
||||
return repositoryRequest.findById(id)
|
||||
.call(aff -> federationAdmin ? reactiveMailer.send(
|
||||
Mail.withText(aff.getM1_email(),
|
||||
"FFSAF - Votre demande d'affiliation a été rejetée.",
|
||||
String.format(
|
||||
"""
|
||||
Bonjour,
|
||||
|
||||
Votre demande d'affiliation pour le club %s a été rejetée pour la/les raison(s) suivante(s):
|
||||
%s
|
||||
|
||||
Si vous rencontrez un problème ou si vous avez des questions, n'hésitez pas à nous contacter à l'adresse contact@ffsaf.fr.
|
||||
|
||||
Cordialement,
|
||||
L'équipe de la FFSAF
|
||||
""", aff.getName(), reason)
|
||||
).setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("contact@ffsaf.fr")
|
||||
Mail.withHtml(aff.getM1_email(), "FFSAF - Votre demande d'affiliation a été rejetée.",
|
||||
String.format(Utils.HTML_HEADER, "FFSAF - Votre demande d'affiliation a été rejetée.") +
|
||||
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,
|
||||
|
||||
Votre demande d'affiliation pour le club %s a été rejetée pour la/les raison(s) suivante(s):
|
||||
%s
|
||||
|
||||
Si vous rencontrez un problème ou si vous avez des questions, n'hésitez pas à nous contacter à l'adresse contact@ffsaf.fr.
|
||||
|
||||
Cordialement,
|
||||
L'équipe de la FFSAF
|
||||
""", aff.getName(), reason))
|
||||
.setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("contact@ffsaf.fr")
|
||||
.addTo(aff.getM2_email(), aff.getM3_email())
|
||||
) : Uni.createFrom().nullItem())
|
||||
.chain(aff -> Panache.withTransaction(() -> repositoryRequest.delete(aff)))
|
||||
|
||||
@@ -45,10 +45,13 @@ public class CategoryService {
|
||||
@Inject
|
||||
CompetitionGuestRepository competitionGuestRepository;
|
||||
|
||||
@Inject
|
||||
TradService trad;
|
||||
|
||||
public Uni<CategoryData> getByIdAdmin(SecurityCtx securityCtx, CompetitionSystem system, Long id) {
|
||||
return repository.find("systemId = ?1 AND system = ?2", id, system)
|
||||
.firstResult()
|
||||
.onItem().ifNull().failWith(() -> new RuntimeException("Category not found"))
|
||||
.onItem().ifNull().failWith(() -> new RuntimeException(trad.t("categorie.non.trouver")))
|
||||
.call(data -> permService.hasAdminViewPerm(securityCtx, data.getCompet()))
|
||||
.map(CategoryData::fromModel);
|
||||
}
|
||||
@@ -64,7 +67,7 @@ public class CategoryService {
|
||||
.chain(o -> {
|
||||
if (o == null) {
|
||||
return competRepository.findById(data.getCompet())
|
||||
.onItem().ifNull().failWith(() -> new RuntimeException("Competition not found"))
|
||||
.onItem().ifNull().failWith(() -> new RuntimeException(trad.t("competition.not.found")))
|
||||
.call(o2 -> permService.hasEditPerm(securityCtx, o2))
|
||||
.chain(competitionModel -> {
|
||||
CategoryModel model = new CategoryModel();
|
||||
@@ -139,7 +142,7 @@ public class CategoryService {
|
||||
.onItem().ifNotNull().call(o2 -> permService.hasEditPerm(securityCtx, o2.getCompet()))
|
||||
.onItem().ifNull().switchTo(
|
||||
() -> competRepository.findById(data.getCompet())
|
||||
.onItem().ifNull().failWith(() -> new RuntimeException("Compet not found"))
|
||||
.onItem().ifNull().failWith(() -> new RuntimeException(trad.t("competition.not.found")))
|
||||
.call(o -> permService.hasEditPerm(securityCtx, o))
|
||||
.map(o -> {
|
||||
CategoryModel model = new CategoryModel();
|
||||
@@ -256,7 +259,7 @@ public class CategoryService {
|
||||
|
||||
public Uni<?> delete(SecurityCtx securityCtx, CompetitionSystem system, Long id) {
|
||||
return repository.find("systemId = ?1 AND system = ?2", id, system).firstResult()
|
||||
.onItem().ifNull().failWith(() -> new RuntimeException("Category not found"))
|
||||
.onItem().ifNull().failWith(() -> new RuntimeException(trad.t("categorie.non.trouver")))
|
||||
.call(o -> permService.hasEditPerm(securityCtx, o.getCompet()))
|
||||
.call(o -> Mutiny.fetch(o.getTree())
|
||||
.call(o2 -> o2.isEmpty() ? Uni.createFrom().nullItem() :
|
||||
|
||||
@@ -58,7 +58,7 @@ public class CheckoutService {
|
||||
String organizationSlug;
|
||||
|
||||
public Uni<Boolean> canDeleteLicence(long id) {
|
||||
return repository.find("?1 IN licenseIds", id).count().map(count -> count == 0);
|
||||
return repository.countByLicenseId(id).invoke(c -> System.out.println(c)).map(count -> count == 0);
|
||||
}
|
||||
|
||||
public Uni<String> create(List<Long> ids, SecurityCtx securityCtx) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import fr.titionfire.ffsaf.data.model.AffiliationModel;
|
||||
import fr.titionfire.ffsaf.data.model.ClubModel;
|
||||
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.CombRepository;
|
||||
import fr.titionfire.ffsaf.net2.ServerCustom;
|
||||
@@ -44,6 +45,9 @@ public class ClubService {
|
||||
@Inject
|
||||
ClubRepository repository;
|
||||
|
||||
@Inject
|
||||
AffiliationRepository affiliationRepository;
|
||||
|
||||
@Inject
|
||||
ServerCustom serverCustom;
|
||||
|
||||
@@ -59,6 +63,9 @@ public class ClubService {
|
||||
@Inject
|
||||
LoggerService ls;
|
||||
|
||||
@Inject
|
||||
TradService trad;
|
||||
|
||||
public SimpleClubModel findByIdOptionalClub(long id) throws Throwable {
|
||||
return VertxContextSupport.subscribeAndAwait(
|
||||
() -> Panache.withTransaction(() -> repository.findById(id).map(SimpleClubModel::fromModel)));
|
||||
@@ -126,7 +133,7 @@ public class ClubService {
|
||||
return combRepository.find("userId = ?1", securityCtx.getSubject()).firstResult()
|
||||
.invoke(Unchecked.consumer(m -> {
|
||||
if (m == null || m.getClub() == null)
|
||||
throw new DNotFoundException("Club non trouvé");
|
||||
throw new DNotFoundException(trad.t("club.non.trouve"));
|
||||
}))
|
||||
.map(MembreModel::getClub)
|
||||
.call(club -> Mutiny.fetch(club.getContact()));
|
||||
@@ -146,7 +153,7 @@ public class ClubService {
|
||||
return combRepository.find("userId = ?1", securityCtx.getSubject()).firstResult()
|
||||
.invoke(Unchecked.consumer(m -> {
|
||||
if (m == null || m.getClub() == null)
|
||||
throw new DNotFoundException("Club non trouvé");
|
||||
throw new DNotFoundException(trad.t("club.non.trouve"));
|
||||
if (!securityCtx.isInClubGroup(m.getClub().getId()))
|
||||
throw new DForbiddenException();
|
||||
}))
|
||||
@@ -162,7 +169,7 @@ public class ClubService {
|
||||
return combRepository.find("userId = ?1", securityCtx.getSubject()).firstResult()
|
||||
.invoke(Unchecked.consumer(m -> {
|
||||
if (m == null || m.getClub() == null)
|
||||
throw new DNotFoundException("Club non trouvé");
|
||||
throw new DNotFoundException(trad.t("club.non.trouve"));
|
||||
if (!securityCtx.isInClubGroup(m.getClub().getId()))
|
||||
throw new DForbiddenException();
|
||||
}))
|
||||
@@ -179,7 +186,7 @@ public class ClubService {
|
||||
ls.logUpdate("Contact(s)...", club);
|
||||
club.setContact(MAPPER.readValue(form.getContact(), typeRef));
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new DBadRequestException("Erreur de format des contacts");
|
||||
throw new DBadRequestException(trad.t("erreur.de.format.des.contacts"));
|
||||
}
|
||||
|
||||
ls.logChange("Lieux d'entrainements", club.getTraining_location(), form.getTraining_location(),
|
||||
@@ -229,12 +236,13 @@ public class ClubService {
|
||||
ls.logUpdate("Contact(s)...", m);
|
||||
m.setContact(MAPPER.readValue(input.getContact(), typeRef));
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new DBadRequestException("Erreur de format des contacts");
|
||||
throw new DBadRequestException(trad.t("erreur.de.format.des.contacts"));
|
||||
}
|
||||
}
|
||||
return Panache.withTransaction(() -> repository.persist(m)).call(() -> ls.append());
|
||||
}))
|
||||
.call(clubModel -> nameChange.get() ? keycloakService.updateGroupFromClub(clubModel) // update group in keycloak
|
||||
.call(clubModel -> nameChange.get() ? keycloakService.updateGroupFromClub(
|
||||
clubModel) // update group in keycloak
|
||||
: Uni.createFrom().nullItem())
|
||||
.invoke(membreModel -> SReqClub.sendIfNeed(serverCustom.clients,
|
||||
SimpleClubModel.fromModel(membreModel)))
|
||||
@@ -282,11 +290,13 @@ public class ClubService {
|
||||
combModel.setClub(null);
|
||||
combModel.setRole(RoleAsso.MEMBRE);
|
||||
}).toList())
|
||||
.call(list -> (list.isEmpty()) ? Uni.createFrom().voidItem() :
|
||||
.call(list -> list.stream().noneMatch(m -> m.getUserId() != null) ?
|
||||
Uni.createFrom().voidItem() :
|
||||
Uni.join().all(list.stream().filter(m -> m.getUserId() != null)
|
||||
.map(m -> keycloakService.clearUser(m.getUserId())).toList())
|
||||
.andCollectFailures())
|
||||
.chain(list -> Panache.withTransaction(() -> combRepository.persist(list)))
|
||||
.chain(list -> list.isEmpty() ? Uni.createFrom().voidItem() :
|
||||
Panache.withTransaction(() -> combRepository.persist(list)))
|
||||
.map(o -> club)
|
||||
)
|
||||
.call(clubModel -> (clubModel.getClubId() == null) ? Uni.createFrom()
|
||||
@@ -323,9 +333,11 @@ public class ClubService {
|
||||
}
|
||||
|
||||
public Uni<List<ClubMapData>> getMapData() {
|
||||
return repository.list("international", false).toMulti().flatMap(list -> Multi.createFrom().iterable(list))
|
||||
.call(clubModel -> Mutiny.fetch(clubModel.getContact()))
|
||||
.map(clubModel -> {
|
||||
return affiliationRepository.list("saison >= ?1 AND club.international = ?2", Utils.getSaison() - 1, false)
|
||||
.toMulti().flatMap(list -> Multi.createFrom().iterable(list))
|
||||
.call(affiliationModel -> Mutiny.fetch(affiliationModel.getClub().getContact()))
|
||||
.map(affiliationModel -> {
|
||||
ClubModel clubModel = affiliationModel.getClub();
|
||||
ClubMapData data = new ClubMapData();
|
||||
|
||||
data.setName(clubModel.getName());
|
||||
|
||||
@@ -98,12 +98,14 @@ public class CompetPermService {
|
||||
map.putIfAbsent(model.getId(), "owner");
|
||||
else if (securityCtx.roleHas("federation_admin"))
|
||||
map.putIfAbsent(model.getId(), "admin");
|
||||
else if (securityCtx.isInClubGroup(model.getClub().getId()) && (securityCtx.roleHas(
|
||||
"club_president")
|
||||
|| securityCtx.roleHas("club_respo_intra") || securityCtx.roleHas(
|
||||
"club_secretaire")
|
||||
|| securityCtx.roleHas("club_tresorier")))
|
||||
else if (securityCtx.isInClubGroup(
|
||||
model.getClub().getId()) && (securityCtx.isClubAdmin()))
|
||||
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;
|
||||
}));
|
||||
@@ -182,12 +184,14 @@ public class CompetPermService {
|
||||
if (o.getSystem() == CompetitionSystem.SAFCA)
|
||||
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
|
||||
throw new DForbiddenException();
|
||||
|
||||
if (o.getSystem() == CompetitionSystem.INTERNAL)
|
||||
if (securityCtx.roleHas("club_president") || securityCtx.roleHas("club_respo_intra")
|
||||
|| securityCtx.roleHas("club_secretaire") || securityCtx.roleHas("club_tresorier"))
|
||||
if (securityCtx.isClubAdmin())
|
||||
return Uni.createFrom().nullItem();
|
||||
|
||||
throw new DForbiddenException();
|
||||
|
||||
@@ -7,10 +7,7 @@ import fr.titionfire.ffsaf.net2.data.SimpleCompet;
|
||||
import fr.titionfire.ffsaf.net2.request.SReqCompet;
|
||||
import fr.titionfire.ffsaf.net2.request.SReqRegister;
|
||||
import fr.titionfire.ffsaf.rest.client.dto.NotificationData;
|
||||
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.data.*;
|
||||
import fr.titionfire.ffsaf.rest.exception.DBadRequestException;
|
||||
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
|
||||
import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
|
||||
@@ -63,6 +60,9 @@ public class CompetitionService {
|
||||
@Inject
|
||||
CompetitionGuestRepository competitionGuestRepository;
|
||||
|
||||
@Inject
|
||||
CatPresetRepository catPresetRepository;
|
||||
|
||||
@Inject
|
||||
ServerCustom serverCustom;
|
||||
|
||||
@@ -97,21 +97,29 @@ public class CompetitionService {
|
||||
@CacheName("have-access")
|
||||
Cache cacheNoneAccess;
|
||||
|
||||
@Inject
|
||||
TradService trad;
|
||||
|
||||
public Uni<CompetitionData> getById(SecurityCtx securityCtx, Long id) {
|
||||
return permService.hasViewPerm(securityCtx, id).map(CompetitionData::fromModelLight);
|
||||
return permService.hasViewPerm(securityCtx, id).map(cm -> {
|
||||
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) {
|
||||
if (id == 0) {
|
||||
return Uni.createFrom()
|
||||
.item(new CompetitionData(null, "", "", "", "", new Date(), new Date(),
|
||||
CompetitionSystem.INTERNAL, RegisterMode.FREE, new Date(), new Date(), true,
|
||||
null, "", "", null, true, "", "", "", ""));
|
||||
return Uni.createFrom().item(new CompetitionData());
|
||||
}
|
||||
return permService.hasAdminViewPerm(securityCtx, id)
|
||||
.call(competitionModel -> Mutiny.fetch(competitionModel.getCatPreset()))
|
||||
.chain(competitionModel -> Mutiny.fetch(competitionModel.getInsc())
|
||||
.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 ->
|
||||
vertx.getOrCreateContext().executeBlocking(() -> {
|
||||
keycloakService.getUser(UUID.fromString(data.getOwner()))
|
||||
@@ -129,6 +137,14 @@ public class CompetitionService {
|
||||
out.addAll(cm.stream().map(CompetitionData::fromModelLight).toList());
|
||||
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 ->
|
||||
repository.list("id NOT IN ?1 AND (publicVisible = TRUE OR registerMode IN ?2)", ids,
|
||||
securityCtx.isClubAdmin() ? List.of(RegisterMode.FREE, RegisterMode.HELLOASSO,
|
||||
@@ -165,8 +181,9 @@ public class CompetitionService {
|
||||
public Uni<List<CompetitionData>> getAllSystemTable(SecurityCtx securityCtx,
|
||||
CompetitionSystem system) {
|
||||
return repository.list("system = ?1", system)
|
||||
.chain(l -> Uni.join().all(l.stream().map(cm -> permService.hasTablePerm(securityCtx, cm)).toList())
|
||||
.andCollectFailures())
|
||||
.chain(l -> Uni.join().all(l.stream().map(cm ->
|
||||
permService.hasTablePerm(securityCtx, cm).onFailure().recoverWithNull()
|
||||
).toList()).andCollectFailures())
|
||||
.map(l -> l.stream().filter(Objects::nonNull).map(CompetitionData::fromModel).toList());
|
||||
}
|
||||
|
||||
@@ -176,7 +193,7 @@ public class CompetitionService {
|
||||
.invoke(Unchecked.consumer(combModel -> {
|
||||
if (!securityCtx.getRoles().contains("create_compet") && !securityCtx.getRoles()
|
||||
.contains("federation_admin"))
|
||||
throw new DForbiddenException("Vous ne pouvez pas créer de compétition");
|
||||
throw new DForbiddenException(trad.t("vous.ne.pouvez.pas.creer.de.competition"));
|
||||
}))
|
||||
.map(MembreModel::getClub)
|
||||
.chain(clubModel -> {
|
||||
@@ -189,17 +206,21 @@ public class CompetitionService {
|
||||
model.setGuests(new ArrayList<>());
|
||||
model.setUuid(UUID.randomUUID().toString());
|
||||
model.setOwner(securityCtx.getSubject());
|
||||
model.setCatPreset(new ArrayList<>());
|
||||
|
||||
copyData(data, 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(
|
||||
securityCtx.getSubject()) : Uni.createFrom().nullItem())
|
||||
.call(c -> (c.getSystem() == CompetitionSystem.INTERNAL) ? cacheNoneAccess.invalidate(
|
||||
securityCtx.getSubject()) : Uni.createFrom().nullItem());
|
||||
} else {
|
||||
return permService.hasEditPerm(securityCtx, data.getId())
|
||||
.call(model -> Mutiny.fetch(model.getCatPreset()))
|
||||
.chain(model -> {
|
||||
copyData(data, model);
|
||||
|
||||
@@ -207,7 +228,8 @@ public class CompetitionService {
|
||||
keycloakService.getUser(data.getOwner()).map(UserRepresentation::getId).orElse(null))
|
||||
.invoke(Unchecked.consumer(newOwner -> {
|
||||
if (newOwner == null)
|
||||
throw new DBadRequestException("User " + data.getOwner() + " not found");
|
||||
throw new DBadRequestException(
|
||||
String.format(trad.t("user.not.found"), data.getOwner()));
|
||||
if (!newOwner.equals(model.getOwner())) {
|
||||
if (!securityCtx.roleHas("federation_admin")
|
||||
&& !securityCtx.roleHas("safca_super_admin")
|
||||
@@ -217,7 +239,9 @@ public class CompetitionService {
|
||||
}
|
||||
}))
|
||||
.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(
|
||||
securityCtx.getSubject()) : Uni.createFrom().nullItem())
|
||||
.call(c -> (c.getSystem() == CompetitionSystem.INTERNAL) ? cacheNoneAccess.invalidate(
|
||||
@@ -225,6 +249,45 @@ 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) {
|
||||
if (model.getBanMembre() == null)
|
||||
model.setBanMembre(new ArrayList<>());
|
||||
@@ -238,6 +301,7 @@ public class CompetitionService {
|
||||
model.setStartRegister(data.getStartRegister());
|
||||
model.setEndRegister(data.getEndRegister());
|
||||
model.setRegisterMode(data.getRegisterMode());
|
||||
model.setRequiredWeight(data.getRequiredWeight());
|
||||
model.setData1(data.getData1());
|
||||
model.setData2(data.getData2());
|
||||
model.setData3(data.getData3());
|
||||
@@ -251,11 +315,18 @@ public class CompetitionService {
|
||||
Uni<List<SimpleRegisterComb>> uni = Mutiny.fetch(c.getInsc())
|
||||
.onItem().transformToMulti(Multi.createFrom()::iterable)
|
||||
.onItem().call(combModel -> Mutiny.fetch(combModel.getMembre().getLicences()))
|
||||
.map(cm -> SimpleRegisterComb.fromModel(cm, cm.getMembre().getLicences()))
|
||||
.onItem().call(combModel -> Mutiny.fetch(combModel.getCategoriesInscrites()))
|
||||
.map(cm -> SimpleRegisterComb.fromModel(cm, cm.getMembre().getLicences())
|
||||
.setCategorieInscrite(cm.getCategoriesInscrites()))
|
||||
.collect().asList();
|
||||
return uni
|
||||
.call(l -> Mutiny.fetch(c.getGuests())
|
||||
.map(guest -> guest.stream().map(SimpleRegisterComb::fromModel).toList())
|
||||
.onItem().transformToMulti(Multi.createFrom()::iterable)
|
||||
.filter(g -> !g.isTeam())
|
||||
.onItem().call(guest -> Mutiny.fetch(guest.getCategoriesInscrites()))
|
||||
.map(guest -> SimpleRegisterComb.fromModel(guest)
|
||||
.setCategorieInscrite(guest.getCategoriesInscrites()))
|
||||
.collect().asList()
|
||||
.invoke(l::addAll));
|
||||
});
|
||||
|
||||
@@ -270,18 +341,23 @@ public class CompetitionService {
|
||||
model.getClub()))
|
||||
.onItem().transformToMulti(Multi.createFrom()::iterable)
|
||||
.onItem().call(combModel -> Mutiny.fetch(combModel.getMembre().getLicences()))
|
||||
.map(combModel -> SimpleRegisterComb.fromModel(combModel, combModel.getMembre().getLicences()))
|
||||
.onItem().call(combModel -> Mutiny.fetch(combModel.getCategoriesInscrites()))
|
||||
.map(combModel -> SimpleRegisterComb.fromModel(combModel, combModel.getMembre().getLicences())
|
||||
.setCategorieInscrite(combModel.getCategoriesInscrites()))
|
||||
.collect().asList();
|
||||
|
||||
return membreService.getByAccountId(securityCtx.getSubject())
|
||||
.chain(model -> registerRepository.find("competition.id = ?1 AND membre = ?2", id, model).firstResult()
|
||||
.map(rm -> rm == null ? List.of() : List.of(SimpleRegisterComb.fromModel(rm, List.of()))));
|
||||
.call(rm -> rm == null ? Uni.createFrom().voidItem() :
|
||||
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,
|
||||
String source) {
|
||||
if ("admin".equals(source))
|
||||
if (data.getLicence() != -1) { // not a guest
|
||||
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()))
|
||||
@@ -292,7 +368,8 @@ public class CompetitionService {
|
||||
return Panache.withTransaction(() -> repository.persist(c));
|
||||
})
|
||||
.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 {
|
||||
return permService.hasEditPerm(securityCtx, id)
|
||||
.chain(c -> competitionGuestRepository.findById(data.getId() * -1)
|
||||
@@ -303,21 +380,35 @@ public class CompetitionService {
|
||||
model.setCompetition(c);
|
||||
return model;
|
||||
}))
|
||||
.chain(model -> {
|
||||
.invoke(model -> {
|
||||
model.setFname(data.getFname());
|
||||
model.setLname(data.getLname());
|
||||
if (data.getLname().equals("__team"))
|
||||
model.setLname("_team");
|
||||
else
|
||||
model.setLname(data.getLname());
|
||||
model.setGenre(data.getGenre());
|
||||
model.setClub(data.getClub());
|
||||
model.setCountry(data.getCountry());
|
||||
model.setWeight(data.getWeight());
|
||||
model.setWeightReal(data.getWeightReal());
|
||||
if (model.getCompetition().getRequiredWeight().contains(model.getCategorie()))
|
||||
model.setWeight(data.getWeight());
|
||||
model.setCategorie(data.getCategorie());
|
||||
|
||||
return Panache.withTransaction(() -> competitionGuestRepository.persist(model))
|
||||
.call(r -> model.getCompetition().getSystem() == CompetitionSystem.INTERNAL ?
|
||||
sRegister.sendRegister(model.getCompetition().getUuid(),
|
||||
r) : Uni.createFrom().voidItem());
|
||||
})
|
||||
.map(SimpleRegisterComb::fromModel);
|
||||
.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()));
|
||||
}
|
||||
if ("club".equals(source))
|
||||
return repository.findById(id)
|
||||
@@ -326,7 +417,7 @@ public class CompetitionService {
|
||||
|| !securityCtx.isClubAdmin())
|
||||
throw new DForbiddenException();
|
||||
if (new Date().before(cm.getStartRegister()) || new Date().after(cm.getEndRegister()))
|
||||
throw new DBadRequestException("Inscription fermée");
|
||||
throw new DBadRequestException(trad.t("inscription.fermee"));
|
||||
}))
|
||||
.chain(c -> findComb(data.getLicence(), data.getFname(), data.getLname())
|
||||
.call(combModel -> Mutiny.fetch(combModel.getLicences()))
|
||||
@@ -334,27 +425,26 @@ public class CompetitionService {
|
||||
if (!securityCtx.isInClubGroup(model.getClub().getId()))
|
||||
throw new DForbiddenException();
|
||||
if (c.getBanMembre().contains(model.getId()))
|
||||
throw new DForbiddenException(
|
||||
"Vous n'avez pas le droit d'inscrire ce membre (par décision de l'administrateur de la compétition)");
|
||||
throw new DForbiddenException(trad.t("insc.err1"));
|
||||
}))
|
||||
.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)
|
||||
.invoke(Unchecked.consumer(cm -> {
|
||||
if (cm.getRegisterMode() != RegisterMode.FREE)
|
||||
throw new DForbiddenException();
|
||||
if (new Date().before(cm.getStartRegister()) || new Date().after(cm.getEndRegister()))
|
||||
throw new DBadRequestException("Inscription fermée");
|
||||
throw new DBadRequestException(trad.t("inscription.fermee"));
|
||||
}))
|
||||
.chain(c -> membreService.getByAccountId(securityCtx.getSubject())
|
||||
.invoke(Unchecked.consumer(model -> {
|
||||
if (c.getBanMembre().contains(model.getId()))
|
||||
throw new DForbiddenException(
|
||||
"Vous n'avez pas le droit de vous inscrire (par décision de l'administrateur de la compétition)");
|
||||
throw new DForbiddenException(trad.t("insc.err2"));
|
||||
}))
|
||||
.chain(combModel -> updateRegister(data, c, combModel, false)))
|
||||
.map(r -> SimpleRegisterComb.fromModel(r, List.of()));
|
||||
.map(r -> SimpleRegisterComb.fromModel(r, List.of()).setCategorieInscrite(r.getCategoriesInscrites()));
|
||||
}
|
||||
|
||||
private Uni<RegisterModel> updateRegister(RegisterRequestData data, CompetitionModel c,
|
||||
@@ -364,9 +454,7 @@ public class CompetitionService {
|
||||
.map(Unchecked.function(r -> {
|
||||
if (r != null) {
|
||||
if (!admin && r.isLockEdit())
|
||||
throw new DForbiddenException(
|
||||
"Modification bloquée par l'administrateur de la compétition");
|
||||
r.setWeight(data.getWeight());
|
||||
throw new DForbiddenException(trad.t("insc.err3"));
|
||||
r.setOverCategory(data.getOverCategory());
|
||||
r.setCategorie(
|
||||
(combModel.getBirth_date() == null) ? combModel.getCategorie() :
|
||||
@@ -375,29 +463,48 @@ public class CompetitionService {
|
||||
int days = Utils.getDaysBeforeCompetition(c.getDate());
|
||||
if (days > -7)
|
||||
r.setClub(combModel.getClub());
|
||||
if (admin)
|
||||
if (c.getRequiredWeight().contains(r.getCategorie2()))
|
||||
r.setWeight(data.getWeight());
|
||||
if (admin) {
|
||||
r.setWeightReal(data.getWeightReal());
|
||||
r.setLockEdit(data.isLockEdit());
|
||||
}
|
||||
} else {
|
||||
r = new RegisterModel(c, combModel, data.getWeight(), data.getOverCategory(),
|
||||
(combModel.getBirth_date() == null) ? combModel.getCategorie() :
|
||||
Utils.getCategoryFormBirthDate(combModel.getBirth_date(),
|
||||
c.getDate()),
|
||||
(combModel.getClub() == null) ? null : combModel.getClub());
|
||||
if (admin)
|
||||
if (admin) {
|
||||
r.setWeightReal(data.getWeightReal());
|
||||
r.setLockEdit(data.isLockEdit());
|
||||
else
|
||||
} else
|
||||
r.setLockEdit(false);
|
||||
}
|
||||
|
||||
if (c.getSystem() == CompetitionSystem.SAFCA) {
|
||||
SReqRegister.sendIfNeed(serverCustom.clients,
|
||||
new CompetitionData.SimpleRegister(r.getMembre().getId(),
|
||||
r.getOverCategory(), r.getWeight(), r.getCategorie(),
|
||||
r.getOverCategory(), r.getWeight2(), r.getCategorie(),
|
||||
(r.getClub() == null) ? null : r.getClub().getId(),
|
||||
(r.getClub() == null) ? null : r.getClub().getName()), c.getId());
|
||||
}
|
||||
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)))
|
||||
.call(r -> c.getSystem() == CompetitionSystem.INTERNAL ?
|
||||
sRegister.sendRegister(c.getUuid(), r) : Uni.createFrom().voidItem());
|
||||
@@ -408,17 +515,17 @@ public class CompetitionService {
|
||||
return combRepository.find("licence = ?1", licence).firstResult()
|
||||
.invoke(Unchecked.consumer(combModel -> {
|
||||
if (combModel == null)
|
||||
throw new DForbiddenException("Licence " + licence + " non trouvé");
|
||||
throw new DForbiddenException(String.format(trad.t("licence.non.trouve"), licence));
|
||||
}));
|
||||
} else {
|
||||
if (fname == null || lname == null)
|
||||
return Uni.createFrom().failure(new DBadRequestException("Nom et prénom requis"));
|
||||
return Uni.createFrom().failure(new DBadRequestException(trad.t("nom.et.prenom.requis")));
|
||||
return combRepository.find("unaccent(lname) ILIKE unaccent(?1) AND unaccent(fname) ILIKE unaccent(?2)",
|
||||
lname,
|
||||
fname).firstResult()
|
||||
.invoke(Unchecked.consumer(combModel -> {
|
||||
if (combModel == null)
|
||||
throw new DForbiddenException("Combattant " + fname + " " + lname + " non trouvé");
|
||||
throw new DForbiddenException(String.format(trad.t("combattant.non.trouve"), fname, lname));
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -445,12 +552,13 @@ public class CompetitionService {
|
||||
|| !securityCtx.isClubAdmin())
|
||||
throw new DForbiddenException();
|
||||
if (new Date().before(cm.getStartRegister()) || new Date().after(cm.getEndRegister()))
|
||||
throw new DBadRequestException("Inscription fermée");
|
||||
throw new DBadRequestException(trad.t("inscription.fermee"));
|
||||
}))
|
||||
.call(cm -> membreService.getById(combId)
|
||||
.invoke(Unchecked.consumer(model -> {
|
||||
if (model == null)
|
||||
throw new DNotFoundException("Membre " + combId + " n'existe pas");
|
||||
throw new DNotFoundException(
|
||||
String.format(trad.t("le.membre.n.existe.pas"), combId));
|
||||
if (!securityCtx.isInClubGroup(model.getClub().getId()))
|
||||
throw new DForbiddenException();
|
||||
})))
|
||||
@@ -462,7 +570,7 @@ public class CompetitionService {
|
||||
if (cm.getRegisterMode() != RegisterMode.FREE || !Objects.equals(model.getId(), combId))
|
||||
throw new DForbiddenException();
|
||||
if (new Date().before(cm.getStartRegister()) || new Date().after(cm.getEndRegister()))
|
||||
throw new DBadRequestException("Inscription fermée");
|
||||
throw new DBadRequestException(trad.t("inscription.fermee"));
|
||||
})))
|
||||
.chain(c -> deleteRegister(combId, c, false));
|
||||
}
|
||||
@@ -470,7 +578,7 @@ public class CompetitionService {
|
||||
private Uni<Void> deleteRegister(Long combId, CompetitionModel c, boolean admin) {
|
||||
if (admin && combId < 0) {
|
||||
return competitionGuestRepository.find("competition = ?1 AND id = ?2", c, combId * -1).firstResult()
|
||||
.onFailure().transform(t -> new DBadRequestException("Combattant non inscrit"))
|
||||
.onFailure().transform(t -> new DBadRequestException(trad.t("combattant.non.inscrit")))
|
||||
.call(Unchecked.function(
|
||||
model -> Panache.withTransaction(() -> competitionGuestRepository.delete(model))
|
||||
.call(r -> c.getSystem() == CompetitionSystem.INTERNAL ?
|
||||
@@ -479,10 +587,10 @@ public class CompetitionService {
|
||||
.replaceWithVoid();
|
||||
}
|
||||
return registerRepository.find("competition = ?1 AND membre.id = ?2", c, combId).firstResult()
|
||||
.onFailure().transform(t -> new DBadRequestException("Combattant non inscrit"))
|
||||
.onFailure().transform(t -> new DBadRequestException(trad.t("combattant.non.inscrit")))
|
||||
.call(Unchecked.function(registerModel -> {
|
||||
if (!admin && registerModel.isLockEdit())
|
||||
throw new DForbiddenException("Modification bloquée par l'administrateur de la compétition");
|
||||
throw new DForbiddenException(trad.t("insc.err3"));
|
||||
return Panache.withTransaction(() -> registerRepository.delete(registerModel))
|
||||
.call(r -> c.getSystem() == CompetitionSystem.INTERNAL ?
|
||||
sRegister.sendRegisterRemove(c.getUuid(), combId) : Uni.createFrom().voidItem());
|
||||
@@ -513,6 +621,64 @@ public class CompetitionService {
|
||||
.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) {
|
||||
return permService.getSafcaConfig(id)
|
||||
.call(Unchecked.function(o -> {
|
||||
@@ -549,13 +715,13 @@ public class CompetitionService {
|
||||
for (String username : data.getAdmin()) {
|
||||
Optional<UserRepresentation> opt = keycloakService.getUser(username);
|
||||
if (opt.isEmpty())
|
||||
throw new DBadRequestException("User " + username + " not found");
|
||||
throw new DBadRequestException(String.format(trad.t("user.not.found"), username));
|
||||
admin.add(UUID.fromString(opt.get().getId()));
|
||||
}
|
||||
for (String username : data.getTable()) {
|
||||
Optional<UserRepresentation> opt = keycloakService.getUser(username);
|
||||
if (opt.isEmpty())
|
||||
throw new DBadRequestException("User " + username + " not found");
|
||||
throw new DBadRequestException(String.format(trad.t("user.not.found"), username));
|
||||
table.add(UUID.fromString(opt.get().getId()));
|
||||
}
|
||||
|
||||
@@ -581,6 +747,12 @@ public class CompetitionService {
|
||||
.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) {
|
||||
if (!data.getState().equals("Refunded"))
|
||||
return Uni.createFrom().item(Response.ok().build());
|
||||
@@ -614,8 +786,8 @@ public class CompetitionService {
|
||||
public Uni<Response> registerHelloAsso(NotificationData data) {
|
||||
String organizationSlug = data.getOrganizationSlug();
|
||||
String formSlug = data.getFormSlug();
|
||||
RegisterRequestData req = new RegisterRequestData(null, "", "", null, 0, false, null, Categorie.CADET, Genre.NA,
|
||||
null, "fr");
|
||||
RegisterRequestData req = new RegisterRequestData(null, "", "", null, null, 0, false, new ArrayList<>(), null,
|
||||
Categorie.CADET, Genre.NA, null, "fr", false);
|
||||
|
||||
return repository.find("data1 = ?1 AND data2 = ?2", organizationSlug, formSlug).firstResult()
|
||||
.onFailure().recoverWithNull()
|
||||
|
||||
@@ -4,7 +4,6 @@ import fr.titionfire.ffsaf.rest.client.HelloAssoAuthClient;
|
||||
import fr.titionfire.ffsaf.rest.client.dto.TokenResponse;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
import org.jboss.logging.Logger;
|
||||
@@ -13,7 +12,6 @@ import org.jboss.logging.Logger;
|
||||
public class HelloAssoTokenService {
|
||||
private static final Logger LOG = Logger.getLogger(HelloAssoTokenService.class);
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
HelloAssoAuthClient authClient;
|
||||
|
||||
@@ -27,6 +25,11 @@ public class HelloAssoTokenService {
|
||||
|
||||
// Récupère un token valide (en le rafraîchissant si nécessaire)
|
||||
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()) {
|
||||
return fetchNewToken(clientId, clientSecret);
|
||||
}
|
||||
|
||||
@@ -156,24 +156,32 @@ public class KeycloakService {
|
||||
return oldEmail;
|
||||
}).call(oldEmail -> oldEmail == null || !enabled_email ? Uni.createFrom().item("") :
|
||||
reactiveMailer.send(
|
||||
Mail.withText(oldEmail,
|
||||
"FFSAF - Changement de votre adresse email",
|
||||
String.format(
|
||||
"""
|
||||
Bonjour,
|
||||
|
||||
Suite à la modification de votre adresse email fournie lors de votre (ré)inscription à la FFSAF,
|
||||
vous allez recevoir dans les prochaines minutes un email de vérification de votre nouvelle adresse sur celle-ci.
|
||||
|
||||
Ancienne adresse email : %s
|
||||
Nouvelle adresse email : %s
|
||||
|
||||
Si vous n'avez pas demandé cette modification, veuillez contacter le support à l'adresse support@ffsaf.fr.
|
||||
|
||||
Cordialement,
|
||||
L'équipe de la FFSAF
|
||||
""", oldEmail, email)
|
||||
).setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("support@ffsaf.fr")
|
||||
Mail.withHtml(oldEmail, "FFSAF - Changement de votre adresse email",
|
||||
String.format(Utils.HTML_HEADER, "FFSAF - Changement de votre adresse email") +
|
||||
String.format("""
|
||||
<p>Suite à la modification de votre adresse email fournie lors de votre (ré)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,
|
||||
|
||||
Suite à la modification de votre adresse email fournie lors de votre (ré)inscription à la FFSAF,
|
||||
vous allez recevoir dans les prochaines minutes un email de vérification de votre nouvelle adresse sur celle-ci.
|
||||
|
||||
Ancienne adresse email : %s
|
||||
Nouvelle adresse email : %s
|
||||
|
||||
Si vous n'avez pas demandé cette modification, veuillez contacter le support à l'adresse support@ffsaf.fr.
|
||||
|
||||
Cordialement,
|
||||
L'équipe de la FFSAF
|
||||
""", oldEmail, email))
|
||||
.setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("support@ffsaf.fr")
|
||||
).onFailure().invoke(e -> LOGGER.error("Fail to send email", e)));
|
||||
}
|
||||
|
||||
@@ -270,13 +278,33 @@ public class KeycloakService {
|
||||
.invoke(user -> membreModel.setUserId(user.getId()))
|
||||
.call(user -> updateRole(user.getId(), List.of("safca_user"), List.of()))
|
||||
.call(user -> enabled_email ? reactiveMailer.send(
|
||||
Mail.withText(user.getEmail(),
|
||||
"FFSAF - Creation de votre compte sur l'intranet",
|
||||
String.format(
|
||||
Mail.withHtml(user.getEmail(), "FFSAF - Creation de votre compte sur l'intranet",
|
||||
String.format(Utils.HTML_HEADER, "Création de votre compte intranet FFSAF") +
|
||||
String.format(
|
||||
"""
|
||||
<p>Suite à votre première inscription <span class="highlight">%s</span> à la <strong>Fédération France Soft Armored Fighting (FFSAF)</strong>, votre compte intranet a été créé.</p>
|
||||
<p>Ce compte vous permettra de :</p>
|
||||
<ul>
|
||||
<li>Consulter vos informations personnelles,</li>
|
||||
<li>Vous inscrire aux compétitions (bientôt disponible),</li>
|
||||
<li>Consulter les résultats des compétitions.</li>
|
||||
</ul>
|
||||
<p>L’intranet est accessible à l’adresse suivante :</p>
|
||||
<p style="text-align: center;"><a href="https://intra.ffsaf.fr" class="button">Accéder à l'intranet</a></p>
|
||||
<p>Votre nom d’utilisateur est : <span class="highlight">%s</span></p>
|
||||
<p>Pour définir votre mot de passe, rendez-vous sur l’intranet : <strong>Connexion > Mot de passe oublié ?</strong></p>
|
||||
<p>Si vous n’avez pas demandé cette inscription, veuillez contacter le support à l’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,
|
||||
|
||||
Suite à votre première inscription %sà la Fédération Française de Soft Armored Fighting (FFSAF), votre compte intranet a été créé.
|
||||
Suite à votre première inscription %sà la Fédération France Soft Armored Fighting (FFSAF), votre compte intranet a été créé.
|
||||
Ce compte vous permettra de consulter vos informations et, dans un futur proche, de vous inscrire aux compétitions ainsi que d'en consulter les résultats.
|
||||
|
||||
L'intranet est accessible à l'adresse suivante : https://intra.ffsaf.fr
|
||||
@@ -291,8 +319,8 @@ public class KeycloakService {
|
||||
L'équipe de la FFSAF
|
||||
""",
|
||||
membreModel.getRole() == RoleAsso.MEMBRE ? "par votre club (" + membreModel.getClub()
|
||||
.getName() + ") " : "", user.getUsername())
|
||||
).setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("support@ffsaf.fr")
|
||||
.getName() + ") " : "", user.getUsername()))
|
||||
.setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("support@ffsaf.fr")
|
||||
) : Uni.createFrom().nullItem())
|
||||
.call(user -> membreService.setUserId(membreModel.getId(), user.getId()))
|
||||
.call(user -> setClubGroupMembre(membreModel, membreModel.getClub()));
|
||||
@@ -349,11 +377,19 @@ public class KeycloakService {
|
||||
|
||||
|
||||
public Optional<UserRepresentation> getUser(UUID userId) {
|
||||
UserResource user = keycloak.realm(realm).users().get(userId.toString());
|
||||
if (user == null)
|
||||
return getUserById(userId.toString());
|
||||
}
|
||||
|
||||
public Optional<UserRepresentation> getUserById(String userId) {
|
||||
try {
|
||||
UserResource user = keycloak.realm(realm).users().get(userId);
|
||||
if (user == null)
|
||||
return Optional.empty();
|
||||
else
|
||||
return Optional.of(user.toRepresentation());
|
||||
} catch (Exception e) {
|
||||
return Optional.empty();
|
||||
else
|
||||
return Optional.of(user.toRepresentation());
|
||||
}
|
||||
}
|
||||
|
||||
private String makeLogin(MembreModel model) {
|
||||
|
||||
@@ -47,6 +47,9 @@ public class LicenceService {
|
||||
@Inject
|
||||
CheckoutService checkoutService;
|
||||
|
||||
@Inject
|
||||
TradService trad;
|
||||
|
||||
public Uni<List<LicenceModel>> getLicence(long id, Consumer<MembreModel> checkPerm) {
|
||||
return combRepository.findById(id).invoke(checkPerm)
|
||||
.chain(combRepository -> Mutiny.fetch(combRepository.getLicences()));
|
||||
@@ -84,6 +87,26 @@ 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) {
|
||||
if (form.getId() == -1) {
|
||||
return combRepository.findById(id).chain(membreModel -> {
|
||||
@@ -121,7 +144,7 @@ public class LicenceService {
|
||||
}
|
||||
|
||||
private Function<MembreModel, Uni<?>> genLicenceNumberAndAccountIfNeed() {
|
||||
return membreModel -> ((membreModel.getLicence() <= 0) ?
|
||||
return membreModel -> ((membreModel.getLicence() == null || membreModel.getLicence() <= 0) ?
|
||||
sequenceRepository.getNextValueInTransaction(SequenceType.Licence)
|
||||
.invoke(i -> membreModel.setLicence(Math.toIntExact(i)))
|
||||
.chain(() -> combRepository.persist(membreModel))
|
||||
@@ -137,7 +160,7 @@ public class LicenceService {
|
||||
return repository.list("membre.id IN ?1 AND saison = ?2 AND pay = FALSE", ids, Utils.getSaison())
|
||||
.invoke(Unchecked.consumer(models -> {
|
||||
if (models.size() != ids.size())
|
||||
throw new DBadRequestException("Erreur lors de la sélection des membres");
|
||||
throw new DBadRequestException(trad.t("erreur.lors.de.la.selection.des.membres"));
|
||||
}))
|
||||
.call(models -> {
|
||||
Uni<?> uni = Uni.createFrom().nullItem();
|
||||
@@ -154,10 +177,10 @@ public class LicenceService {
|
||||
.call(__ -> checkoutService.canDeleteLicence(id)
|
||||
.invoke(Unchecked.consumer(b -> {
|
||||
if (!b) throw new DBadRequestException(
|
||||
"Impossible de supprimer une licence pour laquelle un paiement est en cours");
|
||||
trad.t("licence.rm.err1"));
|
||||
})))
|
||||
.call(model -> ls.logADelete(model))
|
||||
.chain(model -> repository.delete(model));
|
||||
.chain(model -> Panache.withTransaction(() -> repository.delete(model)));
|
||||
}
|
||||
|
||||
public Uni<LicenceModel> askLicence(long id, LicenceForm form, Consumer<MembreModel> checkPerm) {
|
||||
@@ -166,7 +189,7 @@ public class LicenceService {
|
||||
return repository.find("saison = ?1 AND membre = ?2", Utils.getSaison(), membreModel).count()
|
||||
.invoke(Unchecked.consumer(count -> {
|
||||
if (count > 0)
|
||||
throw new DBadRequestException("Licence déjà demandée");
|
||||
throw new DBadRequestException(trad.t("licence.deja.demandee"));
|
||||
})).chain(__ -> combRepository.findById(id).chain(membreModel2 -> {
|
||||
LicenceModel model = new LicenceModel();
|
||||
model.setClub_id((membreModel2.getClub() == null) ? null : membreModel2.getClub().getId());
|
||||
@@ -195,13 +218,13 @@ public class LicenceService {
|
||||
.call(__ -> checkoutService.canDeleteLicence(id)
|
||||
.invoke(Unchecked.consumer(b -> {
|
||||
if (!b) throw new DBadRequestException(
|
||||
"Impossible de supprimer une licence pour laquelle un paiement est en cours");
|
||||
trad.t("licence.rm.err1"));
|
||||
})))
|
||||
.invoke(Unchecked.consumer(licenceModel -> {
|
||||
if (licenceModel.isValidate())
|
||||
throw new DBadRequestException("Impossible de supprimer une licence déjà validée");
|
||||
throw new DBadRequestException(trad.t("impossible.de.supprimer.une.licence.deja.validee"));
|
||||
if (licenceModel.isPay())
|
||||
throw new DBadRequestException("Impossible de supprimer une licence déjà payée");
|
||||
throw new DBadRequestException(trad.t("impossible.de.supprimer.une.licence.deja.payee"));
|
||||
}))
|
||||
.call(model -> ls.logADelete(model))
|
||||
.chain(__ -> Panache.withTransaction(() -> repository.deleteById(id)));
|
||||
|
||||
@@ -58,6 +58,8 @@ public class LoggerService {
|
||||
}
|
||||
|
||||
public Uni<?> append() {
|
||||
if (buffer.isEmpty())
|
||||
return Uni.createFrom().voidItem();
|
||||
return Panache.withTransaction(() -> repository.persist(buffer))
|
||||
.invoke(__ -> buffer.clear());
|
||||
}
|
||||
|
||||
@@ -7,14 +7,12 @@ import fr.titionfire.ffsaf.data.repository.*;
|
||||
import fr.titionfire.ffsaf.net2.ServerCustom;
|
||||
import fr.titionfire.ffsaf.net2.data.SimpleCombModel;
|
||||
import fr.titionfire.ffsaf.net2.request.SReqComb;
|
||||
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.data.*;
|
||||
import fr.titionfire.ffsaf.rest.exception.DBadRequestException;
|
||||
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
|
||||
import fr.titionfire.ffsaf.rest.exception.DInternalError;
|
||||
import fr.titionfire.ffsaf.rest.from.FullMemberForm;
|
||||
import fr.titionfire.ffsaf.rest.from.UserSettingForm;
|
||||
import fr.titionfire.ffsaf.utils.*;
|
||||
import io.quarkus.hibernate.reactive.panache.Panache;
|
||||
import io.quarkus.hibernate.reactive.panache.PanacheQuery;
|
||||
@@ -64,6 +62,9 @@ public class MembreService {
|
||||
@Inject
|
||||
LoggerService ls;
|
||||
|
||||
@Inject
|
||||
TradService trad;
|
||||
|
||||
public SimpleCombModel find(int licence, String np) throws Throwable {
|
||||
return VertxContextSupport.subscribeAndAwait(() -> Panache.withTransaction(() ->
|
||||
repository.find(
|
||||
@@ -125,8 +126,21 @@ public class MembreService {
|
||||
return sort;
|
||||
}
|
||||
|
||||
public Uni<PageResult<SimpleMembre>> searchAdmin(int limit, int page, String search, String club,
|
||||
int licenceRequest, int payState, String order, String categorie) {
|
||||
public Uni<PageResult<SimpleMembre>> search(int limit, int page, String search, int licenceRequest, int payState,
|
||||
String order, String categorie, Boolean archive, String subject) {
|
||||
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)
|
||||
search = "";
|
||||
search = "%" + search.replaceAll(" ", "% %") + "%";
|
||||
@@ -137,77 +151,47 @@ public class MembreService {
|
||||
else
|
||||
categorieFilter = "categorie = " + Categorie.valueOf(categorie).ordinal();
|
||||
|
||||
String finalSearch = search;
|
||||
Uni<List<LicenceModel>> baseUni = getLicenceListe(licenceRequest, payState);
|
||||
String archiveFilter;
|
||||
if (archive == null || archive)
|
||||
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);
|
||||
if (sort == null)
|
||||
return Uni.createFrom().failure(new DInternalError("Erreur lors calcul du trie"));
|
||||
return Uni.createFrom().failure(new DInternalError(trad.t("erreur.lors.calcul.du.trie")));
|
||||
|
||||
return baseUni
|
||||
String finalSearch = search;
|
||||
return getLicenceListe(licenceRequest, payState)
|
||||
.map(l -> l.stream().map(l2 -> l2.getMembre().getId()).toList())
|
||||
.chain(ids -> {
|
||||
PanacheQuery<MembreModel> query;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
query = repository.find(queryStr, sort, finalSearch, ids, club).page(Page.ofSize(limit));
|
||||
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) {
|
||||
return Uni.createFrom().item(new PageResult<SimpleMembre>())
|
||||
.invoke(result -> result.setPage(page))
|
||||
@@ -215,7 +199,7 @@ public class MembreService {
|
||||
.call(result -> query.count().invoke(result::setResult_count))
|
||||
.call(result -> query.pageCount()
|
||||
.invoke(Unchecked.consumer(pages -> {
|
||||
if (page > pages) throw new DBadRequestException("Page out of range");
|
||||
if (page > pages) throw new DBadRequestException(trad.t("page.out.of.range"));
|
||||
}))
|
||||
.invoke(result::setPage_count))
|
||||
.call(result -> query.page(Page.of(page, limit)).list()
|
||||
@@ -260,8 +244,8 @@ public class MembreService {
|
||||
for (MembreModel membreModel : membres) {
|
||||
if (!Objects.equals(membreModel.getClub(), clubModel.get())) {
|
||||
LOGGER.info("Similar membres found: " + membreModel);
|
||||
throw new DForbiddenException(
|
||||
"Le membre n°" + membreModel.getLicence() + " n'appartient pas à votre club");
|
||||
throw new DForbiddenException(String.format(trad.t("le.membre.appartient.pas.a.votre.club"),
|
||||
membreModel.getLicence()));
|
||||
}
|
||||
}
|
||||
Uni<Void> uniResult = Uni.createFrom().voidItem();
|
||||
@@ -287,14 +271,18 @@ public class MembreService {
|
||||
if (model.getEmail() != null && !model.getEmail().isBlank()) {
|
||||
if (model.getLicence() != null && !model.getLicence().equals(dataIn.getLicence())) {
|
||||
LOGGER.info("Similar membres found: " + model);
|
||||
throw new DBadRequestException("Email '" + model.getEmail() + "' déja utiliser");
|
||||
throw new DBadRequestException(
|
||||
String.format(trad.t("email.deja.utilise.par"), model.getEmail(),
|
||||
model.getFname(), model.getLname()));
|
||||
}
|
||||
|
||||
if (StringSimilarity.similarity(model.getLname().toUpperCase(),
|
||||
dataIn.getNom().toUpperCase()) > 3 || StringSimilarity.similarity(
|
||||
model.getFname().toUpperCase(), dataIn.getPrenom().toUpperCase()) > 3) {
|
||||
LOGGER.info("Similar membres found: " + model);
|
||||
throw new DBadRequestException("Email '" + model.getEmail() + "' déja utiliser");
|
||||
throw new DBadRequestException(
|
||||
String.format(trad.t("email.deja.utilise.par"), model.getEmail(),
|
||||
model.getFname(), model.getLname()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,7 +293,8 @@ public class MembreService {
|
||||
model.getFname().toUpperCase(), dataIn.getPrenom().toUpperCase()) > 3)) {
|
||||
LOGGER.info("Similar membres found: " + model);
|
||||
throw new DBadRequestException(
|
||||
"Pour enregistrer un nouveau membre, veuillez laisser le champ licence vide.");
|
||||
String.format(trad.t("try.edit.licence"), model.getLicence(), model.getFname(),
|
||||
model.getFname()));
|
||||
}
|
||||
|
||||
ls.logChange("Nom", model.getLname(), dataIn.getNom().toUpperCase(), model);
|
||||
@@ -313,8 +302,7 @@ public class MembreService {
|
||||
dataIn.getPrenom().toUpperCase().charAt(0) + dataIn.getPrenom().substring(1), model);
|
||||
|
||||
model.setLname(dataIn.getNom().toUpperCase());
|
||||
model.setFname(dataIn.getPrenom().toUpperCase().charAt(0) + dataIn.getPrenom().substring(1));
|
||||
|
||||
model.setFname(Utils.formatPrenom(dataIn.getPrenom()));
|
||||
|
||||
if (dataIn.getEmail() != null && !dataIn.getEmail().isBlank()) {
|
||||
ls.logChange("Email", model.getEmail(), dataIn.getEmail(), model);
|
||||
@@ -380,7 +368,7 @@ public class MembreService {
|
||||
.call(__ -> repository.count("email LIKE ?1 AND id != ?2", membre.getEmail(), id)
|
||||
.invoke(Unchecked.consumer(c -> {
|
||||
if (c > 0 && !membre.getEmail().isBlank())
|
||||
throw new DBadRequestException("Email déjà utiliser");
|
||||
throw new DBadRequestException(trad.t("email.deja.utilise"));
|
||||
})))
|
||||
.chain(membreModel -> clubRepository.findById(membre.getClub())
|
||||
.map(club -> new Pair<>(membreModel, club)))
|
||||
@@ -402,7 +390,7 @@ public class MembreService {
|
||||
.call(__ -> repository.count("email LIKE ?1 AND id != ?2", membre.getEmail(), id)
|
||||
.invoke(Unchecked.consumer(c -> {
|
||||
if (c > 0 && !membre.getEmail().isBlank())
|
||||
throw new DBadRequestException("Email déjà utiliser");
|
||||
throw new DBadRequestException(trad.t("email.deja.utilise"));
|
||||
})))
|
||||
.invoke(Unchecked.consumer(membreModel -> {
|
||||
if (!securityCtx.isInClubGroup(membreModel.getClub().getId()))
|
||||
@@ -411,7 +399,7 @@ public class MembreService {
|
||||
membre.getLname().toUpperCase()) > 3 || StringSimilarity.similarity(
|
||||
membreModel.getFname().toUpperCase(), membre.getFname().toUpperCase()) > 3) {
|
||||
throw new DBadRequestException(
|
||||
"Pour enregistrer un nouveau membre, veuillez utilisez le bouton prévue a cette effet.");
|
||||
trad.t("regiter.new.membre"));
|
||||
}
|
||||
}))
|
||||
.invoke(Unchecked.consumer(membreModel -> {
|
||||
@@ -420,7 +408,7 @@ public class MembreService {
|
||||
else if (securityCtx.roleHas("club_secretaire")) source = RoleAsso.SECRETAIRE;
|
||||
else if (securityCtx.roleHas("club_respo_intra")) source = RoleAsso.MEMBREBUREAU;
|
||||
if (!membre.getRole().equals(membreModel.getRole()) && membre.getRole().level >= source.level)
|
||||
throw new DForbiddenException("Permission insuffisante");
|
||||
throw new DForbiddenException(trad.t("permission.insuffisante"));
|
||||
}))
|
||||
.onItem().transform(target -> {
|
||||
if (!securityCtx.getSubject().equals(target.getUserId())) {
|
||||
@@ -434,7 +422,7 @@ public class MembreService {
|
||||
private Uni<String> update(Uni<MembreModel> uni, FullMemberForm membre, boolean admin) {
|
||||
return uni.chain(target -> {
|
||||
ls.logChange("Prénom", target.getFname(), membre.getFname(), target);
|
||||
target.setFname(membre.getFname());
|
||||
target.setFname(Utils.formatPrenom(membre.getFname()));
|
||||
ls.logChange("Nom", target.getLname(), membre.getLname(), target);
|
||||
target.setLname(membre.getLname().toUpperCase());
|
||||
ls.logChange("Pays", target.getCountry(), membre.getCountry(), target);
|
||||
@@ -482,7 +470,8 @@ public class MembreService {
|
||||
.call(membreModel -> licenceRepository.update("club_id = ?1 where membre = ?2 AND saison = ?3",
|
||||
(membreModel.getClub() == null) ? null : membreModel.getClub().getId(), membreModel,
|
||||
Utils.getSaison()))
|
||||
.call(membreModel -> membre.getPhoto_data().length > 0 ? ls.logAUpdate("Photo",
|
||||
.call(membreModel -> (membre.getPhoto_data() != null && membre.getPhoto_data()
|
||||
.size() > 0) ? ls.logAUpdate("Photo",
|
||||
membreModel) : Uni.createFrom().nullItem())
|
||||
.map(__ -> "OK");
|
||||
}
|
||||
@@ -492,7 +481,8 @@ public class MembreService {
|
||||
return clubRepository.findById(input.getClub())
|
||||
.call(__ -> repository.count("email LIKE ?1", input.getEmail())
|
||||
.invoke(Unchecked.consumer(c -> {
|
||||
if (c > 0) throw new DBadRequestException("Email déjà utiliser");
|
||||
if (c > 0 && input.getEmail() != null && !input.getEmail().isBlank())
|
||||
throw new DBadRequestException(trad.t("email.deja.utilise"));
|
||||
})))
|
||||
.chain(clubModel -> {
|
||||
MembreModel model = getMembreModel(input, clubModel);
|
||||
@@ -508,7 +498,7 @@ public class MembreService {
|
||||
return repository.find("userId = ?1", subject).firstResult()
|
||||
.call(__ -> repository.count("email LIKE ?1", input.getEmail())
|
||||
.invoke(Unchecked.consumer(c -> {
|
||||
if (c > 0) throw new DBadRequestException("Email déjà utiliser");
|
||||
if (c > 0) throw new DBadRequestException(trad.t("email.deja.utilise"));
|
||||
})))
|
||||
.call(membreModel ->
|
||||
repository.count(
|
||||
@@ -516,7 +506,7 @@ public class MembreService {
|
||||
input.getLname(), input.getFname(), membreModel.getClub())
|
||||
.invoke(Unchecked.consumer(c -> {
|
||||
if (c > 0)
|
||||
throw new DBadRequestException("Membre déjà existent");
|
||||
throw new DBadRequestException(trad.t("membre.deja.existent"));
|
||||
})))
|
||||
.chain(membreModel -> {
|
||||
MembreModel model = getMembreModel(input, membreModel.getClub());
|
||||
@@ -549,13 +539,13 @@ public class MembreService {
|
||||
.invoke(Unchecked.consumer(membreModel -> {
|
||||
if (membreModel.getLicence() != null) {
|
||||
throw new DBadRequestException(
|
||||
"Impossible de supprimer un membre qui a déjà un numéro de licence");
|
||||
trad.t("membre.rm.err1"));
|
||||
}
|
||||
}))
|
||||
.call(membreModel -> licenceRepository.find("membre = ?1", membreModel).count()
|
||||
.invoke(Unchecked.consumer(l -> {
|
||||
if (l > 0)
|
||||
throw new DBadRequestException("Impossible de supprimer un membre avec des licences");
|
||||
throw new DBadRequestException(trad.t("membre.rm.err2"));
|
||||
})))
|
||||
.call(membreModel -> (membreModel.getUserId() != null) ?
|
||||
keycloakService.removeAccount(membreModel.getUserId()) : Uni.createFrom().nullItem())
|
||||
@@ -577,8 +567,8 @@ public class MembreService {
|
||||
|
||||
private static MembreModel getMembreModel(FullMemberForm input, ClubModel clubModel) {
|
||||
MembreModel model = new MembreModel();
|
||||
model.setFname(input.getFname());
|
||||
model.setLname(input.getLname());
|
||||
model.setFname(Utils.formatPrenom(input.getFname()));
|
||||
model.setLname(input.getLname().toUpperCase());
|
||||
model.setEmail(input.getEmail());
|
||||
model.setLicence(null);
|
||||
model.setGenre(input.getGenre());
|
||||
@@ -601,13 +591,30 @@ public class MembreService {
|
||||
public Uni<MeData> getMembre(String subject) {
|
||||
MeData meData = new MeData();
|
||||
return repository.find("userId = ?1", subject).firstResult()
|
||||
.invoke(meData::setMembre)
|
||||
.chain(membreModel -> Mutiny.fetch(membreModel.getLicences()))
|
||||
.map(licences -> licences.stream().map(SimpleLicence::fromModel).toList())
|
||||
.invoke(meData::setLicences)
|
||||
.invoke(m -> meData.setMembre(m, trad))
|
||||
.call(membreModel -> Mutiny.fetch(membreModel.getLicences())
|
||||
.map(licences -> licences.stream().map(SimpleLicence::fromModel).toList())
|
||||
.invoke(meData::setLicences))
|
||||
.call(membreModel -> Mutiny.fetch(membreModel.getSelections())
|
||||
.map(licences -> licences.stream().map(SimpleSelection::fromModel).toList())
|
||||
.invoke(meData::setSelections))
|
||||
.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 ?")
|
||||
Uni<Void> everySeason() {
|
||||
return repository.list("birth_date IS NOT NULL")
|
||||
@@ -617,5 +624,4 @@ public class MembreService {
|
||||
}).toList()).andCollectFailures())
|
||||
.map(__ -> null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -46,6 +46,9 @@ public class PDFService {
|
||||
@ConfigProperty(name = "pdf-maker.sign-file")
|
||||
String sign_file;
|
||||
|
||||
@Inject
|
||||
TradService trad;
|
||||
|
||||
|
||||
public Uni<Response> getLicencePdf(String subject) {
|
||||
return getLicencePdf(combRepository.find("userId = ?1", subject).firstResult()
|
||||
@@ -58,7 +61,7 @@ public class PDFService {
|
||||
LicenceModel licence = m.getLicences().stream()
|
||||
.filter(licenceModel -> licenceModel.getSaison() == Utils.getSaison() && licenceModel.isValidate())
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new DNotFoundException("Pas de licence pour la saison en cours"));
|
||||
.orElseThrow(() -> new DNotFoundException(trad.t("pas.de.licence.pour.la.saison.en.cours")));
|
||||
|
||||
try {
|
||||
byte[] buff = make_pdf(m, licence);
|
||||
@@ -119,7 +122,7 @@ public class PDFService {
|
||||
combRepository.find("userId = ?1", subject).firstResult()
|
||||
.invoke(Unchecked.consumer(m -> {
|
||||
if (m == null || m.getClub() == null)
|
||||
throw new DNotFoundException("Club non trouvé");
|
||||
throw new DNotFoundException(trad.t("club.non.trouve"));
|
||||
}))
|
||||
.map(MembreModel::getClub)
|
||||
.call(m -> Mutiny.fetch(m.getAffiliations())));
|
||||
@@ -130,7 +133,7 @@ public class PDFService {
|
||||
clubRepository.findById(id)
|
||||
.invoke(Unchecked.consumer(m -> {
|
||||
if (m == null)
|
||||
throw new DNotFoundException("Club non trouvé");
|
||||
throw new DNotFoundException(trad.t("club.non.trouve"));
|
||||
}))
|
||||
.call(m -> Mutiny.fetch(m.getAffiliations())));
|
||||
}
|
||||
@@ -141,7 +144,7 @@ public class PDFService {
|
||||
.map(Unchecked.function(m -> {
|
||||
if (m.getAffiliations().stream()
|
||||
.noneMatch(licenceModel -> licenceModel.getSaison() == Utils.getSaison()))
|
||||
throw new DNotFoundException("Pas d'affiliation pour la saison en cours");
|
||||
throw new DNotFoundException(trad.t("pas.d.affiliation.pour.la.saison.en.cours"));
|
||||
|
||||
try {
|
||||
byte[] buff = make_pdf(m);
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package fr.titionfire.ffsaf.domain.service;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.*;
|
||||
import fr.titionfire.ffsaf.data.repository.CategoryRepository;
|
||||
import fr.titionfire.ffsaf.data.repository.CompetitionRepository;
|
||||
import fr.titionfire.ffsaf.data.repository.MatchRepository;
|
||||
import fr.titionfire.ffsaf.data.repository.RegisterRepository;
|
||||
import fr.titionfire.ffsaf.data.repository.*;
|
||||
import fr.titionfire.ffsaf.rest.data.ResultCategoryData;
|
||||
import fr.titionfire.ffsaf.rest.exception.DBadRequestException;
|
||||
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
|
||||
import fr.titionfire.ffsaf.utils.*;
|
||||
import io.quarkus.hibernate.reactive.panache.common.WithSession;
|
||||
@@ -35,60 +33,125 @@ public class ResultService {
|
||||
@Inject
|
||||
MembreService membreService;
|
||||
|
||||
@Inject
|
||||
ClubRepository clubRepository;
|
||||
|
||||
@Inject
|
||||
CompetitionGuestRepository competitionGuestRepository;
|
||||
|
||||
@Inject
|
||||
CategoryRepository categoryRepository;
|
||||
|
||||
@Inject
|
||||
MatchRepository matchRepository;
|
||||
|
||||
private static final ResourceBundle BUNDLE = ResourceBundle.getBundle("lang.String");
|
||||
@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) {
|
||||
return membreService.getByAccountId(securityCtx.getSubject())
|
||||
.chain(m -> registerRepository.list("membre = ?1", m))
|
||||
.chain(m -> registerRepository.list(
|
||||
"membre = ?1 OR (TRUE = ?2 AND membre.club = ?3)",
|
||||
m, securityCtx.isClubAdmin(), m.getClub()))
|
||||
.onItem().transformToMulti(Multi.createFrom()::iterable)
|
||||
.onItem().call(r -> Mutiny.fetch(r.getCompetition()))
|
||||
.onItem().transform(r -> new Object[]{r.getCompetition().getUuid(), r.getCompetition().getName(),
|
||||
r.getCompetition().getDate()})
|
||||
.collect().asList();
|
||||
.onItem().transform(RegisterModel::getCompetition)
|
||||
.collect().asList()
|
||||
.chain(l -> compRepository.list("owner = ?1 OR ?1 IN admin", securityCtx.getSubject())
|
||||
.map(l2 -> Stream.concat(l.stream(), l2.stream()).distinct()
|
||||
.map(c -> new Object[]{c.getUuid(), c.getName(), c.getDate()}).toList())
|
||||
);
|
||||
}
|
||||
|
||||
public Uni<List<ResultCategoryData>> getCategory(String uuid, SecurityCtx securityCtx) {
|
||||
return hasAccess(uuid, securityCtx)
|
||||
.chain(m -> categoryRepository.list("compet.uuid = ?1", uuid)
|
||||
.chain(cats -> matchRepository.list("(c1_id = ?1 OR c2_id = ?1 OR True) AND category IN ?2", //TODO rm OR True
|
||||
m.getMembre(), cats)))
|
||||
.map(matchModels -> {
|
||||
HashMap<Long, List<MatchModel>> map = new HashMap<>();
|
||||
for (MatchModel matchModel : matchModels) {
|
||||
if (!map.containsKey(matchModel.getCategory().getId()))
|
||||
map.put(matchModel.getCategory().getId(), new ArrayList<>());
|
||||
map.get(matchModel.getCategory().getId()).add(matchModel);
|
||||
}
|
||||
|
||||
return map.values();
|
||||
})
|
||||
.onItem()
|
||||
.transformToMulti(Multi.createFrom()::iterable)
|
||||
.onItem().call(list -> Mutiny.fetch(list.get(0).getCategory().getTree()))
|
||||
.onItem().transform(this::getData)
|
||||
.collect().asList();
|
||||
|
||||
public Uni<HashMap<String, Long>> getCategoryList(String uuid, SecurityCtx securityCtx) {
|
||||
return hasAccess(uuid, securityCtx).chain(__ -> getCategoryList(uuid));
|
||||
}
|
||||
|
||||
private ResultCategoryData getData(List<MatchModel> matchModels) {
|
||||
public Uni<HashMap<String, Long>> getCategoryList(String uuid) {
|
||||
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 ->
|
||||
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()))
|
||||
.map(list -> getData(list, membreModel)));
|
||||
}
|
||||
|
||||
public Uni<ResultCategoryData> getCategory(String uuid, long poule) {
|
||||
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()))
|
||||
.map(list -> getData(list, null));
|
||||
}
|
||||
|
||||
private ResultCategoryData getData(List<MatchModel> matchModels, MembreModel membreModel) {
|
||||
ResultCategoryData out = new ResultCategoryData();
|
||||
|
||||
CategoryModel categoryModel = matchModels.get(0).getCategory();
|
||||
out.setName(categoryModel.getName());
|
||||
out.setType(categoryModel.getType());
|
||||
out.setLiceName(categoryModel.getLiceName() == null ? new String[]{} : categoryModel.getLiceName().split(";"));
|
||||
out.setGenTime(System.currentTimeMillis());
|
||||
|
||||
getArray2(matchModels, out);
|
||||
getTree(categoryModel.getTree(), out);
|
||||
getArray2(matchModels, membreModel, out);
|
||||
getTree(categoryModel.getTree(), membreModel, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
private void getArray2(List<MatchModel> matchModels_, ResultCategoryData out) {
|
||||
private void getArray2(List<MatchModel> matchModels_, MembreModel membreModel, ResultCategoryData out) {
|
||||
List<MatchModel> matchModels = matchModels_.stream().filter(o -> o.getCategory_ord() >= 0).toList();
|
||||
|
||||
HashMap<Character, List<MatchModel>> matchMap = new HashMap<>();
|
||||
@@ -102,55 +165,34 @@ public class ResultService {
|
||||
matchMap.forEach((c, matchEntities) -> {
|
||||
List<ResultCategoryData.PouleArrayData> matchs = matchEntities.stream()
|
||||
.sorted(Comparator.comparing(MatchModel::getCategory_ord))
|
||||
.map(ResultCategoryData.PouleArrayData::fromModel)
|
||||
.map(o -> ResultCategoryData.PouleArrayData.fromModel(o, membreModel,
|
||||
ResultPrivacy.REGISTERED_ONLY_NO_DETAILS))
|
||||
.toList();
|
||||
|
||||
List<ResultCategoryData.RankArray> rankArray = matchEntities.stream()
|
||||
.flatMap(m -> Stream.of(m.getC1Name(), m.getC2Name()))
|
||||
.flatMap(m -> Stream.of(m.getC1_id(), m.getC2_id(), m.getC1_guest(), m.getC2_guest()))
|
||||
.distinct()
|
||||
.map(combName -> {
|
||||
AtomicInteger w = new AtomicInteger(0);
|
||||
AtomicInteger pointMake = new AtomicInteger(0);
|
||||
AtomicInteger pointTake = new AtomicInteger(0);
|
||||
|
||||
matchEntities.stream()
|
||||
.filter(m -> m.isEnd() && (m.getC1Name().equals(combName) || m.getC2Name()
|
||||
.equals(combName)))
|
||||
.forEach(matchModel -> {
|
||||
int win = matchModel.win();
|
||||
if ((matchModel.getC1Name()
|
||||
.equals(combName) && win > 0) || matchModel.getC2Name()
|
||||
.equals(combName) && win < 0)
|
||||
w.getAndIncrement();
|
||||
|
||||
for (ScoreEmbeddable score : matchModel.getScores()) {
|
||||
if (score.getS1() <= -900 || score.getS2() <= -900)
|
||||
continue;
|
||||
if (matchModel.getC1Name().equals(combName)) {
|
||||
pointMake.addAndGet(score.getS1());
|
||||
pointTake.addAndGet(score.getS2());
|
||||
} else {
|
||||
pointMake.addAndGet(score.getS2());
|
||||
pointTake.addAndGet(score.getS1());
|
||||
}
|
||||
}
|
||||
});
|
||||
float pointRate = (pointTake.get() == 0) ? pointMake.get() : (float) pointMake.get() / pointTake.get();
|
||||
|
||||
return new ResultCategoryData.RankArray(0, combName, w.get(),
|
||||
pointMake.get(), pointTake.get(), pointRate);
|
||||
.filter(Objects::nonNull)
|
||||
.map(comb -> {
|
||||
CombStat stat = makeStat(matchEntities, comb);
|
||||
return new ResultCategoryData.RankArray(0,
|
||||
comb.getName(membreModel, ResultPrivacy.REGISTERED_ONLY_NO_DETAILS), stat.score, stat.w,
|
||||
stat.pointMake, stat.pointTake, stat.getPointRate());
|
||||
})
|
||||
.sorted(Comparator
|
||||
.comparing(ResultCategoryData.RankArray::getWin)
|
||||
.comparing(ResultCategoryData.RankArray::getScore)
|
||||
.thenComparing(ResultCategoryData.RankArray::getWin)
|
||||
.thenComparing(ResultCategoryData.RankArray::getPointRate).reversed())
|
||||
.toList();
|
||||
out.getMatchs().put(c, matchs);
|
||||
|
||||
int lastScore = -1;
|
||||
int lastWin = -1;
|
||||
float pointRate = 0;
|
||||
int rank = 0;
|
||||
for (ResultCategoryData.RankArray rankArray1 : rankArray) {
|
||||
if (rankArray1.getWin() != lastWin || pointRate != rankArray1.getPointRate()) {
|
||||
if (rankArray1.getScore() != lastScore || rankArray1.getWin() != lastWin || pointRate != rankArray1.getPointRate()) {
|
||||
lastScore = rankArray1.getScore();
|
||||
lastWin = rankArray1.getWin();
|
||||
pointRate = rankArray1.getPointRate();
|
||||
rank++;
|
||||
@@ -161,111 +203,262 @@ public class ResultService {
|
||||
});
|
||||
}
|
||||
|
||||
private static void convertTree(TreeModel src, TreeNode<ResultCategoryData.TreeData> dst) {
|
||||
dst.setData(ResultCategoryData.TreeData.from(src.getMatch()));
|
||||
private static void convertTree(TreeModel src, TreeNode<ResultCategoryData.TreeData> dst, MembreModel membreModel,
|
||||
ResultPrivacy privacy) {
|
||||
dst.setData(ResultCategoryData.TreeData.from(src.getMatch(), membreModel, privacy));
|
||||
if (src.getLeft() != null) {
|
||||
dst.setLeft(new TreeNode<>());
|
||||
convertTree(src.getLeft(), dst.getLeft());
|
||||
convertTree(src.getLeft(), dst.getLeft(), membreModel, privacy);
|
||||
}
|
||||
if (src.getRight() != null) {
|
||||
dst.setRight(new TreeNode<>());
|
||||
convertTree(src.getRight(), dst.getRight());
|
||||
convertTree(src.getRight(), dst.getRight(), membreModel, privacy);
|
||||
}
|
||||
}
|
||||
|
||||
private void getTree(List<TreeModel> treeModels, ResultCategoryData out) {
|
||||
private void getTree(List<TreeModel> treeModels, MembreModel membreModel, ResultCategoryData out) {
|
||||
ArrayList<TreeNode<ResultCategoryData.TreeData>> trees = new ArrayList<>();
|
||||
treeModels.stream().filter(t -> t.getLevel() != 0).forEach(treeModel -> {
|
||||
TreeNode<ResultCategoryData.TreeData> root = new TreeNode<>();
|
||||
convertTree(treeModel, root);
|
||||
trees.add(root);
|
||||
});
|
||||
treeModels.stream()
|
||||
.filter(t -> t.getLevel() != 0)
|
||||
.sorted(Comparator.comparing(TreeModel::getLevel))
|
||||
.forEach(treeModel -> {
|
||||
TreeNode<ResultCategoryData.TreeData> root = new TreeNode<>();
|
||||
convertTree(treeModel, root, membreModel, ResultPrivacy.REGISTERED_ONLY_NO_DETAILS);
|
||||
trees.add(root);
|
||||
});
|
||||
out.setTrees(trees);
|
||||
}
|
||||
|
||||
public Uni<CombsArrayData> getAllCombArray(String uuid, SecurityCtx securityCtx) {
|
||||
return hasAccess(uuid, securityCtx)
|
||||
.chain(cm_register -> registerRepository.list("competition.uuid = ?1", uuid)
|
||||
.chain(registers -> matchRepository.list("category.compet.uuid = ?1", uuid)
|
||||
.map(matchModels -> new Pair<>(registers, matchModels)))
|
||||
.map(pair -> {
|
||||
List<RegisterModel> registers = pair.getKey();
|
||||
List<MatchModel> matchModels = pair.getValue();
|
||||
.chain(membreModel -> getAllCombArray_(uuid, membreModel));
|
||||
}
|
||||
|
||||
CombsArrayData.CombsArrayDataBuilder builder = CombsArrayData.builder();
|
||||
public Uni<CombsArrayData> getAllCombArrayPublic(String uuid) {
|
||||
return getAllCombArray_(uuid, null);
|
||||
}
|
||||
|
||||
List<CombsArrayData.CombsData> combs = matchModels.stream()
|
||||
.flatMap(m -> Stream.of(m.getC1Name(), m.getC2Name()))
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.map(combName -> {
|
||||
var builder2 = CombsArrayData.CombsData.builder();
|
||||
AtomicInteger w = new AtomicInteger(0);
|
||||
AtomicInteger l = new AtomicInteger(0);
|
||||
AtomicInteger pointMake = new AtomicInteger();
|
||||
AtomicInteger pointTake = new AtomicInteger();
|
||||
private Uni<CombsArrayData> getAllCombArray_(String uuid, MembreModel membreModel) {
|
||||
return registerRepository.list("competition.uuid = ?1", uuid)
|
||||
.chain(registers -> matchRepository.list("category.compet.uuid = ?1", uuid)
|
||||
.map(matchModels -> new Pair<>(registers, matchModels)))
|
||||
.map(pair -> {
|
||||
List<RegisterModel> registers = pair.getKey();
|
||||
List<MatchModel> matchModels = pair.getValue();
|
||||
|
||||
matchModels.stream()
|
||||
.filter(m -> m.isEnd() && (m.getC1Name().equals(combName)
|
||||
|| m.getC2Name().equals(combName)))
|
||||
.forEach(matchModel -> {
|
||||
int win = matchModel.win();
|
||||
if ((combName.equals(matchModel.getC1Name()) && win > 0) ||
|
||||
combName.equals(matchModel.getC2Name()) && win < 0) {
|
||||
w.getAndIncrement();
|
||||
} else {
|
||||
l.getAndIncrement();
|
||||
}
|
||||
CombsArrayData.CombsArrayDataBuilder builder = CombsArrayData.builder();
|
||||
|
||||
matchModel.getScores().stream()
|
||||
.filter(s -> s.getS1() > -900 && s.getS2() > -900)
|
||||
.forEach(score -> {
|
||||
if (combName.equals(matchModel.getC1Name())) {
|
||||
pointMake.addAndGet(score.getS1());
|
||||
pointTake.addAndGet(score.getS2());
|
||||
} else {
|
||||
pointMake.addAndGet(score.getS2());
|
||||
pointTake.addAndGet(score.getS1());
|
||||
}
|
||||
});
|
||||
});
|
||||
List<CombsArrayData.CombsData> combs = matchModels.stream()
|
||||
.flatMap(m -> Stream.of(m.getC1_id(), m.getC2_id(), m.getC1_guest(), m.getC2_guest()))
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.map(comb -> {
|
||||
var builder2 = CombsArrayData.CombsData.builder();
|
||||
CombStat stat = makeStat(matchModels, comb);
|
||||
|
||||
Categorie categorie = null;
|
||||
ClubModel club = null;
|
||||
Categorie categorie = null;
|
||||
String clubName = null;
|
||||
|
||||
Optional<RegisterModel> register = registers.stream()
|
||||
.filter(r -> r.getName().equals(combName)).findFirst();
|
||||
if (register.isPresent()) {
|
||||
categorie = register.get().getCategorie();
|
||||
club = register.get().getClub2();
|
||||
}
|
||||
Optional<RegisterModel> register = registers.stream()
|
||||
.filter(r -> Objects.equals(r.getMembre(), comb)).findFirst();
|
||||
if (register.isPresent()) {
|
||||
categorie = register.get().getCategorie2();
|
||||
ClubModel club = register.get().getClub2();
|
||||
clubName = (club == null) ? trad.t("no.licence") : club.getName();
|
||||
} else if (comb instanceof CompetitionGuestModel guestModel) {
|
||||
categorie = guestModel.getCategorie();
|
||||
clubName = guestModel.getClub();
|
||||
} else if (comb instanceof MembreModel model) {
|
||||
categorie = model.getCategorie();
|
||||
clubName = (model.getClub() == null) ? trad.t("no.licence")
|
||||
: model.getClub().getName();
|
||||
}
|
||||
|
||||
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());
|
||||
builder2.cat((categorie == null) ? "---" : categorie.getName(trad));
|
||||
builder2.name(comb.getName(membreModel, ResultPrivacy.REGISTERED_ONLY));
|
||||
builder2.w(stat.w);
|
||||
builder2.l(stat.l);
|
||||
builder2.ratioVictoire((stat.l == 0) ? stat.w : (float) stat.w / stat.l);
|
||||
builder2.club(clubName);
|
||||
builder2.pointMake(stat.pointMake);
|
||||
builder2.pointTake(stat.pointTake);
|
||||
builder2.ratioPoint(stat.getPointRate());
|
||||
|
||||
return builder2.build();
|
||||
})
|
||||
.sorted(Comparator.comparing(CombsArrayData.CombsData::name))
|
||||
.toList();
|
||||
return builder2.build();
|
||||
})
|
||||
.sorted(Comparator.comparing(CombsArrayData.CombsData::name))
|
||||
.toList();
|
||||
|
||||
builder.nb_insc(combs.size());
|
||||
builder.tt_match((int) matchModels.stream().filter(MatchModel::isEnd).count());
|
||||
builder.point(combs.stream().mapToInt(CombsArrayData.CombsData::pointMake).sum());
|
||||
builder.combs(combs);
|
||||
builder.nb_insc(combs.size());
|
||||
builder.tt_match((int) matchModels.stream().filter(MatchModel::isEnd).count());
|
||||
builder.point(matchModels.stream()
|
||||
.filter(MatchModel::isEnd)
|
||||
.flatMap(m -> m.getScores().stream())
|
||||
.filter(s -> s.getS1() > -900 && s.getS2() > -900)
|
||||
.mapToInt(s -> s.getS1() + s.getS2()).sum());
|
||||
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<MatchModel>> 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());
|
||||
}));
|
||||
} 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);
|
||||
});
|
||||
}
|
||||
|
||||
return uni.invoke(matchModels -> {
|
||||
List<CategoryModel> pouleModels = matchModels.stream().map(MatchModel::getCategory).distinct()
|
||||
.toList();
|
||||
List<CombArrayData.MatchsData> matchs = new ArrayList<>();
|
||||
|
||||
AtomicInteger sumW = new AtomicInteger();
|
||||
AtomicInteger sumPointMake = new AtomicInteger(0);
|
||||
AtomicInteger sumPointTake = new AtomicInteger(0);
|
||||
|
||||
for (MatchModel 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.getScores().stream()
|
||||
.filter(s -> s.getS1() > -900 && s.getS2() > -900)
|
||||
.forEach(scoreEntity -> {
|
||||
pointMake.addAndGet(scoreEntity.getS1());
|
||||
pointTake.addAndGet(scoreEntity.getS2());
|
||||
});
|
||||
builder2.score(matchModel.getScores().stream()
|
||||
.map(s -> new Integer[]{s.getS1(), s.getS2()}).toList());
|
||||
} else {
|
||||
builder2.score(new ArrayList<>());
|
||||
}
|
||||
builder2.win(matchModel.isEnd() && matchModel.win() > 0);
|
||||
} else {
|
||||
builder2.adv(matchModel.getC1Name());
|
||||
if (matchModel.isEnd()) {
|
||||
matchModel.getScores().stream()
|
||||
.filter(s -> s.getS1() > -900 && s.getS2() > -900)
|
||||
.forEach(scoreEntity -> {
|
||||
pointMake.addAndGet(scoreEntity.getS2());
|
||||
pointTake.addAndGet(scoreEntity.getS1());
|
||||
});
|
||||
builder2.score(matchModel.getScores().stream()
|
||||
.map(s -> new Integer[]{s.getS2(), s.getS1()}).toList());
|
||||
} else {
|
||||
builder2.score(new ArrayList<>());
|
||||
}
|
||||
builder2.win(matchModel.isEnd() && matchModel.win() < 0);
|
||||
}
|
||||
builder2.eq(matchModel.isEnd() && matchModel.win() == 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
|
||||
@RegisterForReflection
|
||||
@@ -277,98 +470,166 @@ public class ResultService {
|
||||
}
|
||||
}
|
||||
|
||||
public Uni<ClubArrayData> getClubArray(String uuid, SecurityCtx securityCtx) {
|
||||
ClubArrayData.ClubArrayDataBuilder builder = ClubArrayData.builder();
|
||||
@Builder
|
||||
@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) {
|
||||
}
|
||||
}
|
||||
|
||||
return hasAccess(uuid, securityCtx)
|
||||
.invoke(cm_register -> builder.name(cm_register.getClub2().getName()))
|
||||
.chain(cm_register -> registerRepository.list("competition.uuid = ?1 AND membre.club = ?2", uuid,
|
||||
cm_register.getClub2())
|
||||
.chain(registers -> matchRepository.list("category.compet.uuid = ?1", uuid)
|
||||
.map(matchModels -> new Pair<>(registers, matchModels)))
|
||||
.map(pair -> {
|
||||
List<RegisterModel> registers = pair.getKey();
|
||||
List<MatchModel> matchModels = pair.getValue();
|
||||
public Uni<HashMap<String, Long>> getClubList(String uuid, SecurityCtx securityCtx) {
|
||||
return hasAccess(uuid, securityCtx).chain(__ -> getClubList(uuid));
|
||||
}
|
||||
|
||||
builder.nb_insc(registers.size());
|
||||
|
||||
AtomicInteger tt_win = new AtomicInteger(0);
|
||||
AtomicInteger tt_match = new AtomicInteger(0);
|
||||
|
||||
List<ClubArrayData.CombData> combData = registers.stream()
|
||||
.map(register -> {
|
||||
|
||||
var builder2 = ClubArrayData.CombData.builder();
|
||||
AtomicInteger w = new AtomicInteger(0);
|
||||
AtomicInteger l = new AtomicInteger(0);
|
||||
AtomicInteger pointMake = new AtomicInteger();
|
||||
AtomicInteger pointTake = new AtomicInteger();
|
||||
|
||||
matchModels.stream()
|
||||
.filter(m -> m.isEnd() && (register.getMembre().equals(m.getC1_id())
|
||||
|| register.getMembre().equals(m.getC2_id())))
|
||||
.forEach(matchModel -> {
|
||||
int win = matchModel.win();
|
||||
if ((register.getMembre()
|
||||
.equals(matchModel.getC1_id()) && win > 0) ||
|
||||
register.getMembre()
|
||||
.equals(matchModel.getC2_id()) && win < 0) {
|
||||
w.getAndIncrement();
|
||||
} else {
|
||||
l.getAndIncrement();
|
||||
}
|
||||
|
||||
matchModel.getScores().stream()
|
||||
.filter(s -> s.getS1() > -900 && s.getS2() > -900)
|
||||
.forEach(score -> {
|
||||
if (register.getMembre()
|
||||
.equals(matchModel.getC1_id())) {
|
||||
pointMake.addAndGet(score.getS1());
|
||||
pointTake.addAndGet(score.getS2());
|
||||
} else {
|
||||
pointMake.addAndGet(score.getS2());
|
||||
pointTake.addAndGet(score.getS1());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Categorie categorie = register.getCategorie();
|
||||
if (categorie == null)
|
||||
categorie = register.getMembre().getCategorie();
|
||||
|
||||
builder2.cat((categorie == null) ? "---" : categorie.getName(BUNDLE));
|
||||
builder2.name(register.getName());
|
||||
builder2.w(w.get());
|
||||
builder2.l(l.get());
|
||||
builder2.ratioVictoire((l.get() == 0) ? w.get() : (float) w.get() / l.get());
|
||||
builder2.pointMake(pointMake.get());
|
||||
builder2.pointTake(pointTake.get());
|
||||
builder2.ratioPoint(
|
||||
(pointTake.get() == 0) ? pointMake.get() : (float) pointMake.get() / pointTake.get());
|
||||
|
||||
tt_win.addAndGet(w.get());
|
||||
tt_match.addAndGet(w.get() + l.get());
|
||||
|
||||
return builder2.build();
|
||||
})
|
||||
.sorted(Comparator.comparing(ClubArrayData.CombData::name))
|
||||
.toList();
|
||||
|
||||
builder.nb_match(tt_match.get());
|
||||
builder.match_w(tt_win.get());
|
||||
builder.ratioVictoire((float) combData.stream().filter(c -> c.l + c.w != 0)
|
||||
.mapToDouble(ClubArrayData.CombData::ratioVictoire).average().orElse(0L));
|
||||
builder.pointMake(combData.stream().mapToInt(ClubArrayData.CombData::pointMake).sum());
|
||||
builder.pointTake(combData.stream().mapToInt(ClubArrayData.CombData::pointTake).sum());
|
||||
builder.ratioPoint((float) combData.stream().filter(c -> c.l + c.w != 0)
|
||||
.mapToDouble(ClubArrayData.CombData::ratioPoint).average().orElse(0L));
|
||||
builder.combs(combData);
|
||||
|
||||
return builder.build();
|
||||
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)
|
||||
.map(matchModels ->
|
||||
getClubArray2(clubName, guests.stream().map(o -> (CombModel) o).toList(),
|
||||
matchModels, 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())
|
||||
.map(matchModels ->
|
||||
getClubArray2(clubModel.getName(),
|
||||
registers.stream().map(o -> (CombModel) o.getMembre()).toList(),
|
||||
matchModels, registers, membreModel))));
|
||||
}
|
||||
}
|
||||
|
||||
private ClubArrayData getClubArray2(String name, List<CombModel> combs, List<MatchModel> matchModels,
|
||||
List<RegisterModel> registers, MembreModel membreModel) {
|
||||
ClubArrayData.ClubArrayDataBuilder builder = ClubArrayData.builder();
|
||||
builder.name(name);
|
||||
builder.nb_insc(combs.size());
|
||||
|
||||
ArrayList<Long> win_ids = new ArrayList<>();
|
||||
ArrayList<Long> match_ids = new ArrayList<>();
|
||||
|
||||
List<ClubArrayData.CombData> combData = combs.stream().map(comb -> {
|
||||
var builder2 = ClubArrayData.CombData.builder();
|
||||
CombStat stat = makeStat(matchModels, comb);
|
||||
|
||||
Categorie categorie = null;
|
||||
|
||||
Optional<RegisterModel> register = registers.stream()
|
||||
.filter(r -> Objects.equals(r.getMembre(), comb)).findFirst();
|
||||
if (register.isPresent()) {
|
||||
categorie = register.get().getCategorie2();
|
||||
} else if (comb instanceof CompetitionGuestModel guestModel) {
|
||||
categorie = guestModel.getCategorie();
|
||||
} else if (comb instanceof MembreModel model) {
|
||||
categorie = model.getCategorie();
|
||||
}
|
||||
|
||||
builder2.cat((categorie == null) ? "---" : categorie.getName(trad));
|
||||
builder2.name(comb.getName(membreModel, ResultPrivacy.REGISTERED_ONLY));
|
||||
builder2.w(stat.w);
|
||||
builder2.l(stat.l);
|
||||
builder2.ratioVictoire((stat.l == 0) ? stat.w : (float) stat.w / stat.l);
|
||||
builder2.pointMake(stat.pointMake);
|
||||
builder2.pointTake(stat.pointTake);
|
||||
builder2.ratioPoint(stat.getPointRate());
|
||||
|
||||
win_ids.addAll(stat.win_ids);
|
||||
match_ids.addAll(stat.match_ids);
|
||||
|
||||
return builder2.build();
|
||||
})
|
||||
.sorted(Comparator.comparing(ClubArrayData.CombData::name))
|
||||
.toList();
|
||||
|
||||
builder.nb_match((int) match_ids.stream().distinct().count());
|
||||
builder.match_w((int) win_ids.stream().distinct().count());
|
||||
builder.ratioVictoire((float) combData.stream().filter(c -> c.l + c.w != 0)
|
||||
.mapToDouble(ClubArrayData.CombData::ratioVictoire).average().orElse(0L));
|
||||
builder.pointMake(combData.stream().mapToInt(ClubArrayData.CombData::pointMake).sum());
|
||||
builder.pointTake(combData.stream().mapToInt(ClubArrayData.CombData::pointTake).sum());
|
||||
builder.ratioPoint((float) combData.stream().filter(c -> c.l + c.w != 0)
|
||||
.mapToDouble(ClubArrayData.CombData::ratioPoint).average().orElse(0L));
|
||||
builder.combs(combData);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static CombStat makeStat(List<MatchModel> 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.win();
|
||||
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.getScores().stream()
|
||||
.filter(s -> s.getS1() > -900 && s.getS2() > -900)
|
||||
.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
|
||||
@RegisterForReflection
|
||||
public static record ClubArrayData(String name, int nb_insc, int nb_match, int match_w, float ratioVictoire,
|
||||
@@ -380,21 +641,60 @@ public class ResultService {
|
||||
}
|
||||
}
|
||||
|
||||
private Uni<RegisterModel> hasAccess(String uuid, SecurityCtx securityCtx) {
|
||||
return registerRepository.find("membre.userId = ?1 AND competition.uuid = ?2", securityCtx.getSubject(), uuid)
|
||||
.firstResult()
|
||||
.invoke(Unchecked.consumer(o -> {
|
||||
if (o == null)
|
||||
throw new DForbiddenException("Access denied");
|
||||
}));
|
||||
@RegisterForReflection
|
||||
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<RegisterModel> hasAccess(Long compId, SecurityCtx securityCtx) {
|
||||
return registerRepository.find("membre.userId = ?1 AND competition.id = ?2", securityCtx.getSubject(), compId)
|
||||
private Uni<MembreModel> hasAccess(String uuid, SecurityCtx securityCtx) {
|
||||
return registerRepository.find("membre.userId = ?1 AND competition.uuid = ?2", securityCtx.getSubject(), uuid)
|
||||
.firstResult()
|
||||
.invoke(Unchecked.consumer(o -> {
|
||||
if (o == null)
|
||||
throw new DForbiddenException("Access denied");
|
||||
.chain(Unchecked.function(o -> {
|
||||
if (o != null)
|
||||
return Uni.createFrom().item(o.getMembre());
|
||||
|
||||
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")));
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
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)));
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ public class StatsService {
|
||||
|
||||
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.getMembre().getGenre() == Genre.H)
|
||||
yearStats.addH();
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
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());
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,7 @@ public class AffiliationEndpoints {
|
||||
|
||||
@GET
|
||||
@Path("{id}")
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@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.")
|
||||
@APIResponses(value = {
|
||||
|
||||
@@ -73,7 +73,7 @@ public class AffiliationRequestEndpoints {
|
||||
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Operation(summary = "Renvoie une demande d'affiliation", description = "Cette méthode renvoie une demande d'affiliation " +
|
||||
"pour l'identifiant spécifié.")
|
||||
@@ -92,7 +92,7 @@ public class AffiliationRequestEndpoints {
|
||||
|
||||
@DELETE
|
||||
@Path("/{id}")
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Operation(summary = "Supprime une demande d'affiliation", description = "Cette méthode supprime une demande " +
|
||||
"d'affiliation pour l'identifiant spécifié.")
|
||||
@@ -128,7 +128,7 @@ public class AffiliationRequestEndpoints {
|
||||
|
||||
@PUT
|
||||
@Path("/edit")
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||
@Operation(summary = "Modifie une demande d'affiliation", description = "Cette méthode modifie une demande " +
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
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.StateIdService;
|
||||
import fr.titionfire.ffsaf.rest.data.AssoData;
|
||||
import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.*;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import org.eclipse.microprofile.openapi.annotations.Operation;
|
||||
@@ -19,6 +21,9 @@ public class AssoEndpoints {
|
||||
@RestClient
|
||||
SirenService sirenService;
|
||||
|
||||
@Inject
|
||||
TradService trad;
|
||||
|
||||
@GET
|
||||
@Path("state_id/{stateId}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@@ -28,9 +33,9 @@ public class AssoEndpoints {
|
||||
stateId).chain(stateIdService::getAssoDataFromUnit)).onFailure().transform(throwable -> {
|
||||
if (throwable instanceof WebApplicationException exception) {
|
||||
if (exception.getResponse().getStatus() == 404)
|
||||
return new DNotFoundException("Service momentanément indisponible");
|
||||
return new DNotFoundException(trad.t("service.momentanement.indisponible"));
|
||||
if (exception.getResponse().getStatus() == 400)
|
||||
return new DNotFoundException("Asso introuvable");
|
||||
return new DNotFoundException(trad.t("asso.introuvable"));
|
||||
}
|
||||
return throwable;
|
||||
});
|
||||
|
||||
@@ -3,10 +3,11 @@ package fr.titionfire.ffsaf.rest;
|
||||
import fr.titionfire.ffsaf.data.model.ClubModel;
|
||||
import fr.titionfire.ffsaf.domain.service.ClubService;
|
||||
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.rest.data.*;
|
||||
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.PartClubForm;
|
||||
import fr.titionfire.ffsaf.utils.Contact;
|
||||
@@ -47,9 +48,15 @@ public class ClubEndpoints {
|
||||
@Inject
|
||||
SecurityCtx securityCtx;
|
||||
|
||||
@Inject
|
||||
VirusScannerService scannerService;
|
||||
|
||||
@ConfigProperty(name = "upload_dir")
|
||||
String media;
|
||||
|
||||
@Inject
|
||||
TradService trad;
|
||||
|
||||
Consumer<ClubModel> checkPerm = Unchecked.consumer(clubModel -> {
|
||||
if (!securityCtx.roleHas("federation_admin") && !securityCtx.isInClubGroup(clubModel.getId()))
|
||||
throw new DForbiddenException();
|
||||
@@ -81,7 +88,7 @@ public class ClubEndpoints {
|
||||
@Operation(summary = "Renvoie les types de contacts pour les clubs", description = "Renvoie la liste des types de " +
|
||||
"contacts possibles pour les clubs")
|
||||
public Uni<HashMap<String, String>> getConcatType() {
|
||||
return Uni.createFrom().item(Contact.toSite());
|
||||
return Uni.createFrom().item(Contact.toSite(trad));
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -109,7 +116,7 @@ public class ClubEndpoints {
|
||||
|
||||
@GET
|
||||
@Path("{id}")
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@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")
|
||||
@@ -121,9 +128,8 @@ public class ClubEndpoints {
|
||||
})
|
||||
public Uni<SimpleClub> getById(
|
||||
@Parameter(description = "Identifiant de club") @PathParam("id") long id) {
|
||||
return clubService.getById(id).onItem().invoke(checkPerm).map(SimpleClub::fromModel).invoke(m -> {
|
||||
m.setContactMap(Contact.toSite());
|
||||
});
|
||||
return clubService.getById(id).onItem().invoke(checkPerm).map(SimpleClub::fromModel)
|
||||
.invoke(m -> m.setContactMap(Contact.toSite(trad)));
|
||||
}
|
||||
|
||||
@PUT
|
||||
@@ -145,25 +151,9 @@ public class ClubEndpoints {
|
||||
return clubService.update(id, input)
|
||||
.invoke(Unchecked.consumer(out -> {
|
||||
if (!out.equals("OK")) throw new InternalError("Fail to update data: " + out);
|
||||
})).chain(() -> {
|
||||
if (input.getLogo().length > 0)
|
||||
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();
|
||||
});
|
||||
}))
|
||||
.chain(() -> Utils.uploadFile(scannerService, input.getLogo(), id, media, "ppClub"))
|
||||
.chain(() -> Utils.uploadFile(scannerService, input.getStatus(), id, media, "clubStatus"));
|
||||
}
|
||||
|
||||
@PUT
|
||||
@@ -181,19 +171,9 @@ public class ClubEndpoints {
|
||||
return clubService.add(input)
|
||||
.invoke(Unchecked.consumer(id -> {
|
||||
if (id == null) throw new InternalError("Fail to create club data");
|
||||
})).call(id -> {
|
||||
if (input.getLogo().length > 0)
|
||||
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();
|
||||
});
|
||||
}))
|
||||
.call(id -> Utils.uploadFile(scannerService, input.getLogo(), id, media, "ppClub"))
|
||||
.call(id -> Utils.uploadFile(scannerService, input.getStatus(), id, media, "clubStatus"));
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@@ -230,7 +210,7 @@ public class ClubEndpoints {
|
||||
|
||||
@GET
|
||||
@Path("/me")
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Operation(summary = "Renvoie les informations du club de l'utilisateur connecté", description = "Renvoie les " +
|
||||
"informations du club de l'utilisateur connecté")
|
||||
@@ -242,12 +222,12 @@ public class ClubEndpoints {
|
||||
})
|
||||
public Uni<SimpleClub> getOfUser() {
|
||||
return clubService.getOfUser(securityCtx).map(SimpleClub::fromModel)
|
||||
.invoke(m -> m.setContactMap(Contact.toSite()));
|
||||
.invoke(m -> m.setContactMap(Contact.toSite(trad)));
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("/me")
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||
@Operation(summary = "Met à jour les informations du club de l'utilisateur connecté", description = "Met à jour les" +
|
||||
@@ -264,7 +244,7 @@ public class ClubEndpoints {
|
||||
|
||||
@GET
|
||||
@Path("/me/affiliation")
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@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é")
|
||||
@APIResponses(value = {
|
||||
@@ -296,7 +276,7 @@ public class ClubEndpoints {
|
||||
|
||||
@GET
|
||||
@Path("/renew/{id}")
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Operation(hidden = true)
|
||||
public Uni<RenewAffData> getRenew(@PathParam("id") long id, @QueryParam("m1") long m1_id,
|
||||
@@ -307,7 +287,7 @@ public class ClubEndpoints {
|
||||
|
||||
@GET
|
||||
@Path("/desk/{id}")
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Operation(summary = "Renvoie la liste des membres du bureau du club", description = "Renvoie la liste des membres " +
|
||||
"du bureau du club spécifié")
|
||||
@@ -345,7 +325,7 @@ public class ClubEndpoints {
|
||||
|
||||
@GET
|
||||
@Path("{id}/status")
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@Operation(summary = "Renvoie le statut du club", description = "Renvoie le statut du club spécifié")
|
||||
@APIResponses(value = {
|
||||
@APIResponse(responseCode = "200", description = "Le statut du club"),
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
package fr.titionfire.ffsaf.rest;
|
||||
|
||||
import fr.titionfire.ffsaf.domain.service.CompetitionService;
|
||||
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.data.*;
|
||||
import fr.titionfire.ffsaf.utils.SecurityCtx;
|
||||
import io.quarkus.security.Authenticated;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
@@ -71,6 +68,21 @@ public class CompetitionEndpoints {
|
||||
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
|
||||
@Path("all")
|
||||
@@ -95,6 +107,14 @@ public class CompetitionEndpoints {
|
||||
return service.setSafcaData(securityCtx, data);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("/internalData")
|
||||
@Authenticated
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Uni<?> setInternalData(SimpleCompetData data) {
|
||||
return service.setInternalData(securityCtx, data);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{id}")
|
||||
@Authenticated
|
||||
|
||||
@@ -37,7 +37,7 @@ public class CompteEndpoints {
|
||||
|
||||
@GET
|
||||
@Path("{id}")
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@Operation(summary = "Renvoie les informations d'un compte utilisateur", description = "Renvoie les informations d'un" +
|
||||
" compte utilisateur en fonction de son identifiant long (UUID)")
|
||||
@APIResponses(value = {
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ public class LicenceEndpoints {
|
||||
|
||||
@GET
|
||||
@Path("{id}")
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Operation(summary = "Renvoie les licences d'un membre", description = "Renvoie les licences d'un membre en fonction " +
|
||||
"de son identifiant")
|
||||
@@ -68,7 +68,7 @@ public class LicenceEndpoints {
|
||||
|
||||
@GET
|
||||
@Path("current/club")
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@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)")
|
||||
@@ -83,7 +83,7 @@ public class LicenceEndpoints {
|
||||
|
||||
@POST
|
||||
@Path("pay")
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@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")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||
@Operation(summary = "Créer une licence", description = "Créer unr licence en fonction de son identifiant et des " +
|
||||
@Operation(summary = "Créer une licence", description = "Créer une licence en fonction de son identifiant et des " +
|
||||
"informations fournies dans le formulaire (pour les administrateurs)")
|
||||
@APIResponses(value = {
|
||||
@APIResponse(responseCode = "200", description = "La licence a été mise à jour avec succès"),
|
||||
@@ -118,7 +118,7 @@ public class LicenceEndpoints {
|
||||
@RolesAllowed("federation_admin")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Operation(summary = "Validation licence", description = "Valide en masse les licence de l'année en cours (pour les administrateurs)")
|
||||
@Operation(summary = "Validation licence", description = "Valide en masse les 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é"),
|
||||
@@ -128,6 +128,21 @@ public class LicenceEndpoints {
|
||||
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
|
||||
@Path("{id}")
|
||||
@RolesAllowed("federation_admin")
|
||||
@@ -146,7 +161,7 @@ public class LicenceEndpoints {
|
||||
|
||||
@POST
|
||||
@Path("club/{id}")
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||
@Operation(summary = "Demande une nouvelle licence", description = "Demande une nouvelle licence en fonction de" +
|
||||
@@ -163,7 +178,7 @@ public class LicenceEndpoints {
|
||||
|
||||
@DELETE
|
||||
@Path("club/{id}")
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
@Operation(summary = "Supprime une demande de licence", description = "Supprime une demande de licence en fonction " +
|
||||
"de son identifiant (pour les clubs)")
|
||||
|
||||
@@ -2,6 +2,7 @@ package fr.titionfire.ffsaf.rest;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.MembreModel;
|
||||
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.exception.DForbiddenException;
|
||||
import fr.titionfire.ffsaf.rest.exception.DInternalError;
|
||||
@@ -21,6 +22,7 @@ import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
|
||||
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
|
||||
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
|
||||
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
@@ -29,10 +31,14 @@ import java.util.function.Consumer;
|
||||
@Path("api/member")
|
||||
@RolesAllowed({"federation_admin"})
|
||||
public class MembreAdminEndpoints {
|
||||
private static final Logger LOGGER = Logger.getLogger(MembreAdminEndpoints.class);
|
||||
|
||||
@Inject
|
||||
MembreService membreService;
|
||||
|
||||
@Inject
|
||||
VirusScannerService scannerService;
|
||||
|
||||
@ConfigProperty(name = "upload_dir")
|
||||
String media;
|
||||
|
||||
@@ -59,6 +65,7 @@ public class MembreAdminEndpoints {
|
||||
@Parameter(description = "Text à rechercher") @QueryParam("search") String search,
|
||||
@Parameter(description = "Club à filter") @QueryParam("club") String club,
|
||||
@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 du payment: 0 -> non payer, 1 -> payer, 2 -> tout") @QueryParam("payment") int payment,
|
||||
@Parameter(description = "Ordre") @QueryParam("order") String order) {
|
||||
@@ -66,7 +73,8 @@ public class MembreAdminEndpoints {
|
||||
limit = 50;
|
||||
if (page == null || page < 1)
|
||||
page = 1;
|
||||
return membreService.searchAdmin(limit, page - 1, search, club, licenceRequest, payment, order, categorie);
|
||||
return membreService.searchAdmin(limit, page - 1, search, club, licenceRequest, payment, order,
|
||||
categorie, archive);
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -95,16 +103,8 @@ public class MembreAdminEndpoints {
|
||||
.invoke(Unchecked.consumer(out -> {
|
||||
if (!out.equals("OK"))
|
||||
throw new DInternalError("Impossible de reconnaitre le fichier: " + out);
|
||||
})).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();
|
||||
});
|
||||
}))
|
||||
.call(__ -> Utils.uploadFile(scannerService, input.getPhoto_data(), id, media, "ppMembre"));
|
||||
}
|
||||
|
||||
@POST
|
||||
@@ -121,13 +121,8 @@ public class MembreAdminEndpoints {
|
||||
return membreService.add(input)
|
||||
.invoke(Unchecked.consumer(id -> {
|
||||
if (id == null) throw new InternalError("Fail to creat member data");
|
||||
})).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();
|
||||
});
|
||||
}))
|
||||
.call(id -> Utils.uploadFile(scannerService, input.getPhoto_data(), id, media, "ppMembre"));
|
||||
}
|
||||
|
||||
@DELETE
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package fr.titionfire.ffsaf.rest;
|
||||
|
||||
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.SimpleMembreInOutData;
|
||||
import fr.titionfire.ffsaf.rest.exception.DInternalError;
|
||||
import fr.titionfire.ffsaf.rest.from.FullMemberForm;
|
||||
import fr.titionfire.ffsaf.utils.PageResult;
|
||||
import fr.titionfire.ffsaf.utils.SecurityCtx;
|
||||
@@ -24,7 +24,7 @@ import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
||||
import java.util.List;
|
||||
|
||||
@Tag(name = "Membre club", description = "Gestion des membres (pour les clubs)")
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@Path("api/member")
|
||||
public class MembreClubEndpoints {
|
||||
|
||||
@@ -37,6 +37,9 @@ public class MembreClubEndpoints {
|
||||
@Inject
|
||||
SecurityCtx securityCtx;
|
||||
|
||||
@Inject
|
||||
VirusScannerService scannerService;
|
||||
|
||||
@GET
|
||||
@Path("/find/club")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@@ -51,6 +54,7 @@ public class MembreClubEndpoints {
|
||||
@Parameter(description = "Page à consulter") @QueryParam("page") Integer page,
|
||||
@Parameter(description = "Text à rechercher") @QueryParam("search") String search,
|
||||
@Parameter(description = "Catégorie à filter") @QueryParam("categorie") String categorie,
|
||||
@Parameter(description = "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 du payment: 0 -> non payer, 1 -> payer, 2 -> tout") @QueryParam("payment") int payment,
|
||||
@Parameter(description = "Ordre") @QueryParam("order") String order) {
|
||||
@@ -58,7 +62,8 @@ public class MembreClubEndpoints {
|
||||
limit = 50;
|
||||
if (page == null || page < 1)
|
||||
page = 1;
|
||||
return membreService.search(limit, page - 1, search, licenceRequest, payment, order, categorie, securityCtx.getSubject());
|
||||
return membreService.search(limit, page - 1, search, licenceRequest, payment, order, categorie, archive,
|
||||
securityCtx.getSubject());
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -106,16 +111,7 @@ public class MembreClubEndpoints {
|
||||
return membreService.update(id, input, securityCtx)
|
||||
.invoke(Unchecked.consumer(out -> {
|
||||
if (!out.equals("OK")) throw new InternalError("Fail to update data: " + out);
|
||||
})).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();
|
||||
});
|
||||
})).chain(() -> Utils.uploadFile(scannerService, input.getPhoto_data(), id, media, "ppMembre"));
|
||||
}
|
||||
|
||||
@POST
|
||||
@@ -133,13 +129,7 @@ public class MembreClubEndpoints {
|
||||
return membreService.add(input, securityCtx.getSubject())
|
||||
.invoke(Unchecked.consumer(id -> {
|
||||
if (id == null) throw new InternalError("Fail to creat member data");
|
||||
})).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();
|
||||
});
|
||||
})).call(id -> Utils.uploadFile(scannerService, input.getPhoto_data(), id, media, "ppMembre"));
|
||||
}
|
||||
|
||||
@DELETE
|
||||
|
||||
@@ -6,6 +6,7 @@ import fr.titionfire.ffsaf.domain.service.PDFService;
|
||||
import fr.titionfire.ffsaf.rest.data.MeData;
|
||||
import fr.titionfire.ffsaf.rest.data.SimpleMembre;
|
||||
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.Utils;
|
||||
import io.quarkus.security.Authenticated;
|
||||
@@ -51,7 +52,7 @@ public class MembreEndpoints {
|
||||
|
||||
@GET
|
||||
@Path("{id}")
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@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")
|
||||
@@ -68,7 +69,7 @@ public class MembreEndpoints {
|
||||
|
||||
@GET
|
||||
@Path("/find/licence")
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@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")
|
||||
@APIResponses(value = {
|
||||
@@ -113,6 +114,21 @@ public class MembreEndpoints {
|
||||
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
|
||||
@Path("me/photo")
|
||||
@Authenticated
|
||||
@@ -130,7 +146,7 @@ public class MembreEndpoints {
|
||||
|
||||
@GET
|
||||
@Path("{id}/photo")
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
|
||||
@Operation(summary = "Renvoie la photo d'un membre", description = "Renvoie la photo d'un membre en fonction de son identifiant")
|
||||
@APIResponses(value = {
|
||||
@APIResponse(responseCode = "200", description = "La photo du membre"),
|
||||
@@ -146,7 +162,7 @@ public class MembreEndpoints {
|
||||
|
||||
@GET
|
||||
@Path("{id}/licence")
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
|
||||
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "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")
|
||||
@APIResponses(value = {
|
||||
@APIResponse(responseCode = "200", description = "Le pdf de la licence"),
|
||||
|
||||
@@ -10,6 +10,7 @@ import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
@Authenticated
|
||||
@@ -29,17 +30,41 @@ public class ResultEndpoints {
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{uuid}")
|
||||
public Uni<List<ResultCategoryData>> getCategory(@PathParam("uuid") String uuid) {
|
||||
return resultService.getCategory(uuid, securityCtx);
|
||||
@Path("{uuid}/category/list")
|
||||
public Uni<HashMap<String, Long>> getCategoryList(@PathParam("uuid") String uuid) {
|
||||
return resultService.getCategoryList(uuid, securityCtx);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{uuid}/club")
|
||||
public Uni<ResultService.ClubArrayData> getClub(@PathParam("uuid") String uuid) {
|
||||
return resultService.getClubArray(uuid, securityCtx);
|
||||
@Path("{uuid}/category/{id}")
|
||||
public Uni<ResultCategoryData> getCategory(@PathParam("uuid") String uuid, @PathParam("id") long id) {
|
||||
return resultService.getCategory(uuid, id, 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
|
||||
@Path("{uuid}/comb")
|
||||
public Uni<ResultService.CombsArrayData> getComb(@PathParam("uuid") String uuid) {
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
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.CompetitionModel;
|
||||
import fr.titionfire.ffsaf.data.model.RegisterModel;
|
||||
@@ -10,6 +11,7 @@ import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
@@ -33,12 +35,23 @@ public class CompetitionData {
|
||||
private Long club;
|
||||
private String clubName;
|
||||
private String owner;
|
||||
private List<SimpleRegister> registers;
|
||||
private List<SimpleRegister> registers; // for SAFCA
|
||||
private boolean canEdit;
|
||||
private boolean canEditRegisters;
|
||||
private String data1;
|
||||
private String data2;
|
||||
private String data3;
|
||||
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) {
|
||||
if (model == null)
|
||||
@@ -47,8 +60,9 @@ public class CompetitionData {
|
||||
return new CompetitionData(model.getId(), model.getName(), model.getDescription(), model.getAdresse(),
|
||||
model.getUuid(), model.getDate(), model.getTodate(), model.getSystem(),
|
||||
model.getRegisterMode(), model.getStartRegister(), model.getEndRegister(), model.isPublicVisible(),
|
||||
model.getClub().getId(), model.getClub().getName(), model.getOwner(), null, false,
|
||||
model.getData1(), model.getData2(), model.getData3(), model.getData4());
|
||||
model.getClub().getId(), model.getClub().getName(), model.getOwner(), null, false, false,
|
||||
model.getData1(), model.getData2(), model.getData3(), model.getData4(), model.getConfig(),
|
||||
new ArrayList<>(), model.getRequiredWeight());
|
||||
}
|
||||
|
||||
public static CompetitionData fromModelLight(CompetitionModel model) {
|
||||
@@ -58,29 +72,35 @@ public class CompetitionData {
|
||||
CompetitionData out = new CompetitionData(model.getId(), model.getName(), model.getDescription(),
|
||||
model.getAdresse(), "", model.getDate(), model.getTodate(), null,
|
||||
model.getRegisterMode(), model.getStartRegister(), model.getEndRegister(), model.isPublicVisible(),
|
||||
null, model.getClub().getName(), "", null, false,
|
||||
"", "", "", "");
|
||||
null, model.getClub().getName(), "", null, false, false,
|
||||
"", "", "", "", "{}", new ArrayList<>(), model.getRequiredWeight());
|
||||
|
||||
if (model.getRegisterMode() == RegisterMode.HELLOASSO) {
|
||||
out.setData1(model.getData1());
|
||||
out.setData2(model.getData2());
|
||||
}
|
||||
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
public CompetitionData addInsc(List<RegisterModel> insc, List<CompetitionGuestModel> guests) {
|
||||
this.registers = Stream.concat(
|
||||
insc.stream()
|
||||
.map(i -> new SimpleRegister(i.getMembre().getId(), i.getOverCategory(), i.getWeight(),
|
||||
.map(i -> new SimpleRegister(i.getMembre().getId(), i.getOverCategory(), i.getWeight2(),
|
||||
i.getCategorie(), (i.getClub() == null) ? null : i.getClub().getId(),
|
||||
(i.getClub() == null) ? null : i.getClub().getName())),
|
||||
guests.stream()
|
||||
.map(i -> new SimpleRegister(i.getId() * -1, 0, i.getWeight(),
|
||||
.map(i -> new SimpleRegister(i.getId() * -1, 0, i.getWeight2(),
|
||||
i.getCategorie(), null, i.getClub()))).toList();
|
||||
return this;
|
||||
}
|
||||
|
||||
public CompetitionData addPresets(List<CatPresetModel> presets) {
|
||||
this.presets = presets.stream().map(PresetData::fromModel).toList();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@RegisterForReflection
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package fr.titionfire.ffsaf.rest.data;
|
||||
|
||||
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 lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
@@ -15,45 +17,50 @@ import java.util.List;
|
||||
@NoArgsConstructor
|
||||
@RegisterForReflection
|
||||
public class MeData {
|
||||
@Schema(description = "L'identifiant du membre.", example = "1")
|
||||
@Schema(description = "L'identifiant du membre.", examples = "1")
|
||||
private long id;
|
||||
@Schema(description = "Le nom du membre.", example = "Dupont")
|
||||
@Schema(description = "Le nom du membre.", examples = "Dupont")
|
||||
private String lname = "";
|
||||
@Schema(description = "Le prénom du membre.", example = "Jean")
|
||||
@Schema(description = "Le prénom du membre.", examples = "Jean")
|
||||
private String fname = "";
|
||||
@Schema(description = "La catégorie du membre.", example = "SENIOR")
|
||||
@Schema(description = "La catégorie du membre.", examples = "SENIOR")
|
||||
private String categorie;
|
||||
@Schema(description = "Le nom du club du membre.", example = "Association sportive")
|
||||
@Schema(description = "Le nom du club du membre.", examples = "Association sportive")
|
||||
private String club;
|
||||
@Schema(description = "Le genre du membre.", example = "Homme")
|
||||
@Schema(description = "Le genre du membre.", examples = "Homme")
|
||||
private String genre;
|
||||
@Schema(description = "Le numéro de licence du membre.", example = "12345")
|
||||
@Schema(description = "Le numéro de licence du membre.", examples = "12345")
|
||||
private int licence;
|
||||
@Schema(description = "Le pays du membre.", example = "FR")
|
||||
@Schema(description = "Le pays du membre.", examples = "FR")
|
||||
private String country;
|
||||
@Schema(description = "La date de naissance du membre.")
|
||||
private Date birth_date;
|
||||
@Schema(description = "L'adresse e-mail du membre.", example = "jean.dupont@example.com")
|
||||
@Schema(description = "L'adresse e-mail du membre.", examples = "jean.dupont@examples.com")
|
||||
private String email;
|
||||
@Schema(description = "Le rôle du membre dans l'association.", example = "MEMBRE")
|
||||
@Schema(description = "Le rôle du membre dans l'association.", examples = "MEMBRE")
|
||||
private String role;
|
||||
@Schema(description = "Le grade d'arbitrage du membre.", example = "N/A")
|
||||
@Schema(description = "Le grade d'arbitrage du membre.", examples = "N/A")
|
||||
private String grade_arbitrage;
|
||||
@Schema(description = "La confidentialité des résultats", examples = "PUBLIC")
|
||||
private ResultPrivacy resultPrivacy;
|
||||
@Schema(description = "La liste des licences du membre.")
|
||||
private List<SimpleLicence> licences;
|
||||
@Schema(description = "La liste des séléctions du membre.")
|
||||
private List<SimpleSelection> selections;
|
||||
|
||||
public void setMembre(MembreModel membreModel) {
|
||||
public void setMembre(MembreModel membreModel, TradService trad) {
|
||||
this.id = membreModel.getId();
|
||||
this.lname = membreModel.getLname();
|
||||
this.fname = membreModel.getFname();
|
||||
this.categorie = membreModel.getCategorie().getName();
|
||||
this.club = membreModel.getClub() == null ? "Sans club" : membreModel.getClub().getName();
|
||||
this.genre = membreModel.getGenre().str;
|
||||
this.categorie = membreModel.getCategorie() == null ? trad.t("categorie.inconnue") : membreModel.getCategorie().getName(trad);
|
||||
this.club = membreModel.getClub() == null ? trad.t("sans.club") : membreModel.getClub().getName();
|
||||
this.genre = membreModel.getGenre().getString(trad);
|
||||
this.licence = membreModel.getLicence();
|
||||
this.country = membreModel.getCountry();
|
||||
this.birth_date = membreModel.getBirth_date();
|
||||
this.email = membreModel.getEmail();
|
||||
this.role = membreModel.getRole().str;
|
||||
this.grade_arbitrage = membreModel.getGrade_arbitrage().str;
|
||||
this.role = membreModel.getRole().getString(trad);
|
||||
this.grade_arbitrage = membreModel.getGrade_arbitrage().getString(trad);
|
||||
this.resultPrivacy = membreModel.getResultPrivacy();
|
||||
}
|
||||
}
|
||||
|
||||
29
src/main/java/fr/titionfire/ffsaf/rest/data/PresetData.java
Normal file
29
src/main/java/fr/titionfire/ffsaf/rest/data/PresetData.java
Normal file
@@ -0,0 +1,29 @@
|
||||
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());
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@@ -17,8 +19,10 @@ public class RegisterRequestData {
|
||||
private String lname;
|
||||
|
||||
private Integer weight;
|
||||
private Integer weightReal;
|
||||
private int overCategory;
|
||||
private boolean lockEdit = false;
|
||||
private List<Long> categoriesInscrites;
|
||||
|
||||
// for guest registration only
|
||||
private Long id = null;
|
||||
@@ -26,4 +30,6 @@ public class RegisterRequestData {
|
||||
private Genre genre = Genre.NA;
|
||||
private String club = null;
|
||||
private String country = null;
|
||||
|
||||
private boolean quick = false;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package fr.titionfire.ffsaf.rest.data;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.MatchModel;
|
||||
import fr.titionfire.ffsaf.data.model.MembreModel;
|
||||
import fr.titionfire.ffsaf.utils.ResultPrivacy;
|
||||
import fr.titionfire.ffsaf.utils.ScoreEmbeddable;
|
||||
import fr.titionfire.ffsaf.utils.TreeNode;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
@@ -9,6 +11,7 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
@@ -21,6 +24,8 @@ public class ResultCategoryData {
|
||||
HashMap<Character, List<PouleArrayData>> matchs = new HashMap<>();
|
||||
HashMap<Character, List<RankArray>> rankArray = new HashMap<>();
|
||||
ArrayList<TreeNode<TreeData>> trees;
|
||||
String[] liceName;
|
||||
long genTime;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@@ -28,6 +33,7 @@ public class ResultCategoryData {
|
||||
public static class RankArray {
|
||||
int rank;
|
||||
String name;
|
||||
int score;
|
||||
int win;
|
||||
int pointMake;
|
||||
int pointTake;
|
||||
@@ -35,25 +41,29 @@ public class ResultCategoryData {
|
||||
}
|
||||
|
||||
@RegisterForReflection
|
||||
public record PouleArrayData(String red, boolean red_w, List<Integer[]> score, boolean blue_w, String blue, boolean end) {
|
||||
public static PouleArrayData fromModel(MatchModel matchModel) {
|
||||
public record PouleArrayData(String red, boolean red_w, List<Integer[]> score, boolean blue_w, String blue,
|
||||
boolean eq, boolean end, Date date) {
|
||||
public static PouleArrayData fromModel(MatchModel matchModel, MembreModel membreModel, ResultPrivacy privacy) {
|
||||
return new PouleArrayData(
|
||||
matchModel.getC1Name(),
|
||||
matchModel.getC1Name(membreModel, privacy),
|
||||
matchModel.isEnd() && matchModel.win() > 0,
|
||||
matchModel.isEnd() ?
|
||||
matchModel.getScores().stream().map(s -> new Integer[]{s.getS1(), s.getS2()}).toList()
|
||||
: new ArrayList<>(),
|
||||
matchModel.isEnd() && matchModel.win() < 0,
|
||||
matchModel.getC2Name(),
|
||||
matchModel.isEnd());
|
||||
matchModel.getC2Name(membreModel, privacy),
|
||||
matchModel.isEnd() && matchModel.win() == 0,
|
||||
matchModel.isEnd(),
|
||||
matchModel.getDate());
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterForReflection
|
||||
public static record TreeData(long id, String c1FullName, String c2FullName, List<ScoreEmbeddable> scores,
|
||||
boolean end) {
|
||||
public static TreeData from(MatchModel match) {
|
||||
return new TreeData(match.getId(), match.getC1Name(), match.getC2Name(), match.getScores(), match.isEnd());
|
||||
public static TreeData from(MatchModel match, MembreModel membreModel, ResultPrivacy privacy) {
|
||||
return new TreeData(match.getId(), match.getC1Name(membreModel, privacy),
|
||||
match.getC2Name(membreModel, privacy), match.getScores(), match.isEnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
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 io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -25,4 +29,41 @@ public class SimpleCompetData {
|
||||
return new SimpleCompetData(compet.id(), compet.show_blason(), compet.show_flag(),
|
||||
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 "{}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,34 +19,32 @@ import java.util.Date;
|
||||
@AllArgsConstructor
|
||||
@RegisterForReflection
|
||||
public class SimpleMembre {
|
||||
@Schema(description = "L'identifiant du membre.", example = "1")
|
||||
@Schema(description = "L'identifiant du membre.", examples = "1")
|
||||
private long id;
|
||||
@Schema(description = "L'identifiant long du membre (userID).", example = "e81d1d35-d897-421e-8086-6c5e74d13c6e")
|
||||
@Schema(description = "L'identifiant long du membre (userID).", examples = "e81d1d35-d897-421e-8086-6c5e74d13c6e")
|
||||
private String userId;
|
||||
@Schema(description = "Le nom du membre.", example = "Dupont")
|
||||
@Schema(description = "Le nom du membre.", examples = "Dupont")
|
||||
private String lname = "";
|
||||
@Schema(description = "Le prénom du membre.", example = "Jean")
|
||||
@Schema(description = "Le prénom du membre.", examples = "Jean")
|
||||
private String fname = "";
|
||||
@Schema(description = "La catégorie du membre.", example = "SENIOR")
|
||||
@Schema(description = "La catégorie du membre.", examples = "SENIOR")
|
||||
private Categorie categorie;
|
||||
@Schema(description = "Le club du membre.")
|
||||
private SimpleClubModel club;
|
||||
@Schema(description = "Le genre du membre.", example = "H")
|
||||
@Schema(description = "Le genre du membre.", examples = "H")
|
||||
private Genre genre;
|
||||
@Schema(description = "Le numéro de licence du membre.", example = "12345")
|
||||
@Schema(description = "Le numéro de licence du membre.", examples = "12345")
|
||||
private Integer licence;
|
||||
@Schema(description = "Le pays du membre.", example = "FR")
|
||||
@Schema(description = "Le pays du membre.", examples = "FR")
|
||||
private String country;
|
||||
@Schema(description = "La date de naissance du membre.")
|
||||
private Date birth_date;
|
||||
@Schema(description = "L'adresse e-mail du membre.", example = "jean.dupont@example.com")
|
||||
@Schema(description = "L'adresse e-mail du membre.", examples = "jean.dupont@examples.com")
|
||||
private String email;
|
||||
@Schema(description = "Le rôle du membre dans l'association.", example = "MEMBRE")
|
||||
@Schema(description = "Le rôle du membre dans l'association.", examples = "MEMBRE")
|
||||
private RoleAsso role;
|
||||
@Schema(description = "Le grade d'arbitrage du membre.", example = "N/A")
|
||||
@Schema(description = "Le grade d'arbitrage du membre.", examples = "N/A")
|
||||
private GradeArbitrage grade_arbitrage;
|
||||
@Schema(hidden = true)
|
||||
private String url_photo;
|
||||
|
||||
public static SimpleMembre fromModel(MembreModel model) {
|
||||
if (model == null)
|
||||
@@ -66,7 +64,6 @@ public class SimpleMembre {
|
||||
.email(model.getEmail())
|
||||
.role(model.getRole())
|
||||
.grade_arbitrage(model.getGrade_arbitrage())
|
||||
.url_photo(model.getUrl_photo())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package fr.titionfire.ffsaf.rest.data;
|
||||
|
||||
import fr.titionfire.ffsaf.data.model.CompetitionGuestModel;
|
||||
import fr.titionfire.ffsaf.data.model.LicenceModel;
|
||||
import fr.titionfire.ffsaf.data.model.MembreModel;
|
||||
import fr.titionfire.ffsaf.data.model.RegisterModel;
|
||||
import fr.titionfire.ffsaf.data.model.*;
|
||||
import fr.titionfire.ffsaf.net2.data.SimpleClubModel;
|
||||
import fr.titionfire.ffsaf.utils.Categorie;
|
||||
import fr.titionfire.ffsaf.utils.Genre;
|
||||
@@ -12,6 +9,7 @@ import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@@ -27,9 +25,11 @@ public class SimpleRegisterComb {
|
||||
private SimpleClubModel club;
|
||||
private Integer licence;
|
||||
private Integer weight;
|
||||
private Integer weightReal;
|
||||
private int overCategory;
|
||||
private boolean hasLicenceActive;
|
||||
private boolean lockEdit;
|
||||
private List<Long> categoriesInscrites;
|
||||
|
||||
public static SimpleRegisterComb fromModel(RegisterModel register, List<LicenceModel> licences) {
|
||||
MembreModel membreModel = register.getMembre();
|
||||
@@ -37,15 +37,21 @@ public class SimpleRegisterComb {
|
||||
membreModel.getGenre(), membreModel.getCountry(),
|
||||
(register.getCategorie() == null) ? null : register.getCategorie(),
|
||||
SimpleClubModel.fromModel(register.getClub()), membreModel.getLicence(), register.getWeight(),
|
||||
register.getOverCategory(),
|
||||
register.getWeightReal(), register.getOverCategory(),
|
||||
licences.stream().anyMatch(l -> l.isValidate() && l.getSaison() == Utils.getSaison()),
|
||||
register.isLockEdit());
|
||||
register.isLockEdit(), new ArrayList<>());
|
||||
}
|
||||
|
||||
public static SimpleRegisterComb fromModel(CompetitionGuestModel guest) {
|
||||
return new SimpleRegisterComb(guest.getId() * -1, guest.getFname(), guest.getLname(),
|
||||
guest.getGenre(), guest.getCountry(), guest.getCategorie(),
|
||||
new SimpleClubModel(null, guest.getClub(), "fr", null),
|
||||
null, guest.getWeight(), 0, false, false);
|
||||
null, guest.getWeight(), guest.getWeightReal(), 0, false, false,
|
||||
new ArrayList<>());
|
||||
}
|
||||
|
||||
public SimpleRegisterComb setCategorieInscrite(List<CatPresetModel> presets) {
|
||||
this.categoriesInscrites = presets.stream().map(CatPresetModel::getId).toList();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import lombok.ToString;
|
||||
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
import org.jboss.resteasy.reactive.PartType;
|
||||
import org.jboss.resteasy.reactive.multipart.FileUpload;
|
||||
|
||||
@Getter
|
||||
@ToString(exclude = {"status", "logo"})
|
||||
@@ -17,85 +18,85 @@ public class AffiliationRequestForm {
|
||||
@FormParam("id")
|
||||
private Long id = null;
|
||||
|
||||
@Schema(description = "Le nom de l'association.", example = "Association sportive", required = true)
|
||||
@Schema(description = "Le nom de l'association.", examples = "Association sportive", required = true)
|
||||
@FormParam("name")
|
||||
private String name = null;
|
||||
|
||||
@Schema(description = "Le numéro SIRET/RNA de l'association.", example = "12345678901234", required = true)
|
||||
@Schema(description = "Le numéro SIRET/RNA de l'association.", examples = "12345678901234", required = true)
|
||||
@FormParam("state_id")
|
||||
private String state_id = null;
|
||||
|
||||
@Schema(description = "L'adresse de l'association.", example = "1 rue de l'exemple, 75000 Paris", required = true)
|
||||
@Schema(description = "L'adresse de l'association.", examples = "1 rue de l'exemple, 75000 Paris", required = true)
|
||||
@FormParam("adresse")
|
||||
private String adresse = null;
|
||||
|
||||
@Schema(description = "Email de contact de l'association", example = "test@test.fr")
|
||||
@Schema(description = "Email de contact de l'association", examples = "test@test.fr")
|
||||
@FormParam("contact")
|
||||
private String contact = null;
|
||||
|
||||
@Schema(description = "La saison de l'affiliation.", example = "2025", required = true)
|
||||
@Schema(description = "La saison de l'affiliation.", examples = "2025", required = true)
|
||||
@FormParam("saison")
|
||||
private int saison = -1;
|
||||
|
||||
@Schema(description = "Le statut de l'association.", type = SchemaType.ARRAY, implementation = byte.class)
|
||||
@Schema(description = "Le statut de l'association.", type = SchemaType.ARRAY)
|
||||
@FormParam("status")
|
||||
@PartType(MediaType.APPLICATION_OCTET_STREAM)
|
||||
private byte[] status = new byte[0];
|
||||
private FileUpload status = null;
|
||||
|
||||
@Schema(description = "Le logo de l'association.", type = SchemaType.ARRAY, implementation = byte.class)
|
||||
@Schema(description = "Le logo de l'association.", type = SchemaType.ARRAY)
|
||||
@FormParam("logo")
|
||||
@PartType(MediaType.APPLICATION_OCTET_STREAM)
|
||||
private byte[] logo = new byte[0];
|
||||
private FileUpload logo = null;
|
||||
|
||||
@Schema(description = "Le nom du premier membre de l'association.", example = "Doe", required = true)
|
||||
@Schema(description = "Le nom du premier membre de l'association.", examples = "Doe", required = true)
|
||||
@FormParam("m1_nom")
|
||||
private String m1_lname = null;
|
||||
|
||||
@Schema(description = "Le prénom du premier membre de l'association.", example = "John", required = true)
|
||||
@Schema(description = "Le prénom du premier membre de l'association.", examples = "John", required = true)
|
||||
@FormParam("m1_prenom")
|
||||
private String m1_fname = null;
|
||||
|
||||
@Schema(description = "L'adresse e-mail du premier membre de l'association.", example = "john.doe@test.com", required = true)
|
||||
@Schema(description = "L'adresse e-mail du premier membre de l'association.", examples = "john.doe@test.com", required = true)
|
||||
@FormParam("m1_mail")
|
||||
private String m1_email = null;
|
||||
|
||||
@Schema(description = "Le numéro de licence du premier membre de l'association. (null si non licencié)", example = "12345")
|
||||
@Schema(description = "Le numéro de licence du premier membre de l'association. (null si non licencié)", examples = "12345")
|
||||
@FormParam("m1_licence")
|
||||
private String m1_lincence = null;
|
||||
|
||||
@Schema(description = "Le rôle du premier membre de l'association. (doit être PRESIDENT)", example = "PRESIDENT", required = true)
|
||||
@Schema(description = "Le rôle du premier membre de l'association. (doit être PRESIDENT)", examples = "PRESIDENT", required = true)
|
||||
@FormParam("m1_role")
|
||||
private RoleAsso m1_role = null;
|
||||
|
||||
@Schema(description = "Le nom du deuxième membre de l'association.", example = "Xavier", required = true)
|
||||
@Schema(description = "Le nom du deuxième membre de l'association.", examples = "Xavier", required = true)
|
||||
@FormParam("m2_nom")
|
||||
private String m2_lname = null;
|
||||
|
||||
@Schema(description = "Le prénom du deuxième membre de l'association.", example = "Login", required = true)
|
||||
@Schema(description = "Le prénom du deuxième membre de l'association.", examples = "Login", required = true)
|
||||
@FormParam("m2_prenom")
|
||||
private String m2_fname = null;
|
||||
|
||||
@Schema(description = "L'adresse e-mail du deuxième membre de l'association.", example = "xavier.login@test.com", required = true)
|
||||
@Schema(description = "L'adresse e-mail du deuxième membre de l'association.", examples = "xavier.login@test.com", required = true)
|
||||
@FormParam("m2_mail")
|
||||
private String m2_email = null;
|
||||
|
||||
@Schema(description = "Le numéro de licence du deuxième membre de l'association. (null si non licencié)", example = "04242")
|
||||
@Schema(description = "Le numéro de licence du deuxième membre de l'association. (null si non licencié)", examples = "04242")
|
||||
@FormParam("m2_licence")
|
||||
private String m2_lincence = null;
|
||||
|
||||
@Schema(description = "Le rôle du deuxième membre de l'association.", example = "SECRETAIRE", required = true)
|
||||
@Schema(description = "Le rôle du deuxième membre de l'association.", examples = "SECRETAIRE", required = true)
|
||||
@FormParam("m2_role")
|
||||
private RoleAsso m2_role = null;
|
||||
|
||||
@Schema(description = "Le nom du troisième membre de l'association.", example = "Doe2", required = true)
|
||||
@Schema(description = "Le nom du troisième membre de l'association.", examples = "Doe2", required = true)
|
||||
@FormParam("m3_nom")
|
||||
private String m3_lname = null;
|
||||
|
||||
@Schema(description = "Le prénom du troisième membre de l'association.", example = "John2", required = true)
|
||||
@Schema(description = "Le prénom du troisième membre de l'association.", examples = "John2", required = true)
|
||||
@FormParam("m3_prenom")
|
||||
private String m3_fname = null;
|
||||
|
||||
@Schema(description = "L'adresse e-mail du troisième membre de l'association.", example = "john.doe22@test.com", required = true)
|
||||
@Schema(description = "L'adresse e-mail du troisième membre de l'association.", examples = "john.doe22@test.com", required = true)
|
||||
@FormParam("m3_mail")
|
||||
private String m3_email = null;
|
||||
|
||||
@@ -103,7 +104,7 @@ public class AffiliationRequestForm {
|
||||
@FormParam("m3_licence")
|
||||
private String m3_lincence = null;
|
||||
|
||||
@Schema(description = "Le rôle du troisième membre de l'association.", example = "MEMBREBUREAU", required = true)
|
||||
@Schema(description = "Le rôle du troisième membre de l'association.", examples = "MEMBREBUREAU", required = true)
|
||||
@FormParam("m3_role")
|
||||
private RoleAsso m3_role = null;
|
||||
|
||||
|
||||
@@ -6,123 +6,124 @@ import jakarta.ws.rs.core.MediaType;
|
||||
import lombok.Getter;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
import org.jboss.resteasy.reactive.PartType;
|
||||
import org.jboss.resteasy.reactive.multipart.FileUpload;
|
||||
|
||||
@Getter
|
||||
public class AffiliationRequestSaveForm {
|
||||
@Schema(description = "L'identifiant de l'affiliation.", example = "1", required = true)
|
||||
@Schema(description = "L'identifiant de l'affiliation.", examples = "1", required = true)
|
||||
@FormParam("id")
|
||||
private Long id = null;
|
||||
|
||||
@Schema(description = "Le nom de l'association.", example = "Association sportive", required = true)
|
||||
@Schema(description = "Le nom de l'association.", examples = "Association sportive", required = true)
|
||||
@FormParam("name")
|
||||
private String name = null;
|
||||
|
||||
@Schema(description = "Le numéro SIRET ou RNA de l'association.", example = "12345678901234", required = true)
|
||||
@Schema(description = "Le numéro SIRET ou RNA de l'association.", examples = "12345678901234", required = true)
|
||||
@FormParam("state_id")
|
||||
private String state_id = null;
|
||||
|
||||
@Schema(description = "L'adresse de l'association.", example = "1 rue de l'exemple, 75000 Paris", required = true)
|
||||
@Schema(description = "L'adresse de l'association.", examples = "1 rue de l'exemple, 75000 Paris", required = true)
|
||||
@FormParam("address")
|
||||
private String address = null;
|
||||
|
||||
@Schema(description = "Email de contact de l'association", example = "test@test.fr")
|
||||
@Schema(description = "Email de contact de l'association", examples = "test@test.fr")
|
||||
@FormParam("contact")
|
||||
private String contact = null;
|
||||
|
||||
@Schema(description = "Le statut de l'association.")
|
||||
@FormParam("status")
|
||||
@PartType(MediaType.APPLICATION_OCTET_STREAM)
|
||||
private byte[] status = new byte[0];
|
||||
private FileUpload status = null;
|
||||
|
||||
@Schema(description = "Le logo de l'association.")
|
||||
@FormParam("logo")
|
||||
@PartType(MediaType.APPLICATION_OCTET_STREAM)
|
||||
private byte[] logo = new byte[0];
|
||||
private FileUpload logo = null;
|
||||
|
||||
@Schema(description = "Mode utiliser pour la sauvegarde du membre 1 (0 = licence mode, 2 = nom, prénom)", example = "0", required = true)
|
||||
@Schema(description = "Mode utiliser pour la sauvegarde du membre 1 (0 = licence mode, 2 = nom, prénom)", examples = "0", required = true)
|
||||
@FormParam("m1_mode")
|
||||
private Integer m1_mode = null;
|
||||
|
||||
@Schema(description = "Le rôle du premier membre de l'association.", example = "PRÉSIDENT", required = true)
|
||||
@Schema(description = "Le rôle du premier membre de l'association.", examples = "PRÉSIDENT", required = true)
|
||||
@FormParam("m1_role")
|
||||
private RoleAsso m1_role = null;
|
||||
|
||||
@Schema(description = "Le numéro de licence du premier membre de l'association. (null si non licencié)", example = "1234567", required = true)
|
||||
@Schema(description = "Le numéro de licence du premier membre de l'association. (null si non licencié)", examples = "1234567", required = true)
|
||||
@FormParam("m1_licence")
|
||||
private String m1_lincence = null;
|
||||
|
||||
@Schema(description = "Le nom du premier membre de l'association.", example = "Dupont", required = true)
|
||||
@Schema(description = "Le nom du premier membre de l'association.", examples = "Dupont", required = true)
|
||||
@FormParam("m1_lname")
|
||||
private String m1_lname = null;
|
||||
|
||||
@Schema(description = "Le prénom du premier membre de l'association.", example = "Jean", required = true)
|
||||
@Schema(description = "Le prénom du premier membre de l'association.", examples = "Jean", required = true)
|
||||
@FormParam("m1_fname")
|
||||
private String m1_fname = null;
|
||||
|
||||
@Schema(description = "L'adresse e-mail du premier membre de l'association.", example = "jean.dupont@example.com", required = true)
|
||||
@Schema(description = "L'adresse e-mail du premier membre de l'association.", examples = "jean.dupont@examples.com", required = true)
|
||||
@FormParam("m1_email")
|
||||
private String m1_email = null;
|
||||
|
||||
@Schema(name = "keep_email",
|
||||
description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm1_email')", example = "1", required = true)
|
||||
description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm1_email')", examples = "1", required = true)
|
||||
@FormParam("m1_email_mode")
|
||||
private Integer m1_email_mode = null;
|
||||
|
||||
@Schema(description = "Mode utiliser pour la sauvegarde du membre 2 (0 = licence mode, 2 = nom, prénom)", example = "0", required = true)
|
||||
@Schema(description = "Mode utiliser pour la sauvegarde du membre 2 (0 = licence mode, 2 = nom, prénom)", examples = "0", required = true)
|
||||
@FormParam("m2_mode")
|
||||
private Integer m2_mode = null;
|
||||
|
||||
@Schema(description = "Le rôle du deuxième membre de l'association.", example = "TRÉSORIER", required = true)
|
||||
@Schema(description = "Le rôle du deuxième membre de l'association.", examples = "TRÉSORIER", required = true)
|
||||
@FormParam("m2_role")
|
||||
private RoleAsso m2_role = null;
|
||||
|
||||
@Schema(description = "Le numéro de licence du deuxième membre de l'association. (null si non licencié)", example = "2345678", required = true)
|
||||
@Schema(description = "Le numéro de licence du deuxième membre de l'association. (null si non licencié)", examples = "2345678", required = true)
|
||||
@FormParam("m2_licence")
|
||||
private String m2_lincence = null;
|
||||
|
||||
@Schema(description = "Le nom du deuxième membre de l'association.", example = "Durand", required = true)
|
||||
@Schema(description = "Le nom du deuxième membre de l'association.", examples = "Durand", required = true)
|
||||
@FormParam("m2_lname")
|
||||
private String m2_lname = null;
|
||||
|
||||
@Schema(description = "Le prénom du deuxième membre de l'association.", example = "Paul", required = true)
|
||||
@Schema(description = "Le prénom du deuxième membre de l'association.", examples = "Paul", required = true)
|
||||
@FormParam("m2_fname")
|
||||
private String m2_fname = null;
|
||||
|
||||
@Schema(description = "L'adresse e-mail du deuxième membre de l'association.", example = "paul.durand@example.com", required = true)
|
||||
@Schema(description = "L'adresse e-mail du deuxième membre de l'association.", examples = "paul.durand@examples.com", required = true)
|
||||
@FormParam("m2_email")
|
||||
private String m2_email = null;
|
||||
|
||||
@Schema(name = "keep_email",
|
||||
description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm2_email')", example = "1", required = true)
|
||||
description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm2_email')", examples = "1", required = true)
|
||||
@FormParam("m2_email_mode")
|
||||
private Integer m2_email_mode = null;
|
||||
|
||||
@Schema(description = "Mode utiliser pour la sauvegarde du membre 3 (0 = licence mode, 2 = nom, prénom)", example = "0", required = true)
|
||||
@Schema(description = "Mode utiliser pour la sauvegarde du membre 3 (0 = licence mode, 2 = nom, prénom)", examples = "0", required = true)
|
||||
@FormParam("m3_mode")
|
||||
private Integer m3_mode = null;
|
||||
|
||||
@Schema(description = "Le rôle du troisième membre de l'association.", example = "SECRÉTAIRE", required = true)
|
||||
@Schema(description = "Le rôle du troisième membre de l'association.", examples = "SECRÉTAIRE", required = true)
|
||||
@FormParam("m3_role")
|
||||
private RoleAsso m3_role = null;
|
||||
|
||||
@Schema(description = "Le numéro de licence du troisième membre de l'association. (null si non licencié)", example = "3456789", required = true)
|
||||
@Schema(description = "Le numéro de licence du troisième membre de l'association. (null si non licencié)", examples = "3456789", required = true)
|
||||
@FormParam("m3_licence")
|
||||
private String m3_lincence = null;
|
||||
|
||||
@Schema(description = "Le nom du troisième membre de l'association.", example = "Martin", required = true)
|
||||
@Schema(description = "Le nom du troisième membre de l'association.", examples = "Martin", required = true)
|
||||
@FormParam("m3_lname")
|
||||
private String m3_lname = null;
|
||||
|
||||
@Schema(description = "Le prénom du troisième membre de l'association.", example = "Pierre", required = true)
|
||||
@Schema(description = "Le prénom du troisième membre de l'association.", examples = "Pierre", required = true)
|
||||
@FormParam("m3_fname")
|
||||
private String m3_fname = null;
|
||||
|
||||
@Schema(description = "L'adresse e-mail du troisième membre de l'association.", example = "pierre.martin@example.com", required = true)
|
||||
@Schema(description = "L'adresse e-mail du troisième membre de l'association.", examples = "pierre.martin@examples.com", required = true)
|
||||
@FormParam("m3_email")
|
||||
private String m3_email = null;
|
||||
|
||||
@Schema(name = "keep_email",
|
||||
description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm3_email')", example = "1", required = true)
|
||||
description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm3_email')", examples = "1", required = true)
|
||||
@FormParam("m3_email_mode")
|
||||
private Integer m3_email_mode = null;
|
||||
|
||||
@@ -174,8 +175,6 @@ public class AffiliationRequestSaveForm {
|
||||
", state_id=" + state_id +
|
||||
", address='" + address + '\'' +
|
||||
", contact='" + contact + '\'' +
|
||||
", status_len=" + status.length +
|
||||
", logo_len=" + logo.length +
|
||||
", m1_mode=" + m1_mode +
|
||||
", m1_role=" + m1_role +
|
||||
", m1_lincence='" + m1_lincence + '\'' +
|
||||
|
||||
@@ -7,57 +7,58 @@ import lombok.ToString;
|
||||
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
import org.jboss.resteasy.reactive.PartType;
|
||||
import org.jboss.resteasy.reactive.multipart.FileUpload;
|
||||
|
||||
@ToString
|
||||
@Getter
|
||||
public class FullClubForm {
|
||||
@FormParam("id")
|
||||
@Schema(description = "Identifiant du club", example = "1", required = true)
|
||||
@Schema(description = "Identifiant du club", examples = "1", required = true)
|
||||
private String id = null;
|
||||
|
||||
@FormParam("name")
|
||||
@Schema(description = "Nom du club", example = "Association sportive", required = true)
|
||||
@Schema(description = "Nom du club", examples = "Association sportive", required = true)
|
||||
private String name = null;
|
||||
|
||||
@FormParam("country")
|
||||
@Schema(description = "Pays du club", example = "FR", required = true)
|
||||
@Schema(description = "Pays du club", examples = "FR", required = true)
|
||||
private String country = null;
|
||||
|
||||
@FormParam("contact")
|
||||
@Schema(description = "Les contacts du club", example = "{\"SITE\": \"www.test.com\", \"COURRIEL\": \"test@test.com\"}", required = true)
|
||||
@Schema(description = "Les contacts du club", examples = "{\"SITE\": \"www.test.com\", \"COURRIEL\": \"test@test.com\"}", required = true)
|
||||
private String contact = null;
|
||||
|
||||
@FormParam("training_location")
|
||||
@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)
|
||||
@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)
|
||||
private String training_location = null;
|
||||
|
||||
@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)", example = "[{\"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)", examples = "[{\"day\":0,\"time_start\":164,\"time_end\":240},{\"day\":3,\"time_start\":124,\"time_end\":250}]", required = true)
|
||||
private String training_day_time = null;
|
||||
|
||||
@FormParam("contact_intern")
|
||||
@Schema(description = "Contact interne du club", example = "john.doe@test.com")
|
||||
@Schema(description = "Contact interne du club", examples = "john.doe@test.com")
|
||||
private String contact_intern = null;
|
||||
|
||||
@FormParam("address")
|
||||
@Schema(description = "Adresse postale du club", example = "1 rue de l'exemple, 75000 Paris", required = true)
|
||||
@Schema(description = "Adresse postale du club", examples = "1 rue de l'exemple, 75000 Paris", required = true)
|
||||
private String address = null;
|
||||
|
||||
@FormParam("state_id")
|
||||
@Schema(description = "Numéro SIRET ou RNA du club", example = "12345678901234", required = true)
|
||||
@Schema(description = "Numéro SIRET ou RNA du club", examples = "12345678901234", required = true)
|
||||
private String state_id = null;
|
||||
|
||||
@FormParam("international")
|
||||
@Schema(description = "Club international", example = "false", required = true)
|
||||
@Schema(description = "Club international", examples = "false", required = true)
|
||||
private boolean international = false;
|
||||
|
||||
@FormParam("status")
|
||||
@PartType(MediaType.APPLICATION_OCTET_STREAM)
|
||||
@Schema(description = "Le statut de l'association.", type = SchemaType.ARRAY, implementation = byte.class)
|
||||
private byte[] status = new byte[0];
|
||||
@Schema(description = "Le statut de l'association.", type = SchemaType.ARRAY)
|
||||
private FileUpload status = null;
|
||||
|
||||
@FormParam("logo")
|
||||
@PartType(MediaType.APPLICATION_OCTET_STREAM)
|
||||
@Schema(description = "Le logo de l'association.", type = SchemaType.ARRAY, implementation = byte.class)
|
||||
private byte[] logo = new byte[0];
|
||||
@Schema(description = "Le logo de l'association.", type = SchemaType.ARRAY)
|
||||
private FileUpload logo = null;
|
||||
}
|
||||
|
||||
@@ -8,32 +8,33 @@ import jakarta.ws.rs.core.MediaType;
|
||||
import lombok.Getter;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
import org.jboss.resteasy.reactive.PartType;
|
||||
import org.jboss.resteasy.reactive.multipart.FileUpload;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Getter
|
||||
public class FullMemberForm {
|
||||
@Schema(description = "L'identifiant du membre.", example = "1")
|
||||
@Schema(description = "L'identifiant du membre.", examples = "1")
|
||||
@FormParam("id")
|
||||
private String id = null;
|
||||
|
||||
@Schema(description = "Le nom du membre.", example = "Dupont")
|
||||
@Schema(description = "Le nom du membre.", examples = "Dupont")
|
||||
@FormParam("lname")
|
||||
private String lname = null;
|
||||
|
||||
@Schema(description = "Le prénom du membre.", example = "Jean")
|
||||
@Schema(description = "Le prénom du membre.", examples = "Jean")
|
||||
@FormParam("fname")
|
||||
private String fname = null;
|
||||
|
||||
@Schema(description = "L'identifiant du club du membre.", example = "1")
|
||||
@Schema(description = "L'identifiant du club du membre.", examples = "1")
|
||||
@FormParam("club")
|
||||
private Long club = null;
|
||||
|
||||
@Schema(description = "Le genre du membre.", example = "H")
|
||||
@Schema(description = "Le genre du membre.", examples = "H")
|
||||
@FormParam("genre")
|
||||
private Genre genre;
|
||||
|
||||
@Schema(description = "Le pays du membre.", example = "FR")
|
||||
@Schema(description = "Le pays du membre.", examples = "FR")
|
||||
@FormParam("country")
|
||||
private String country;
|
||||
|
||||
@@ -41,22 +42,22 @@ public class FullMemberForm {
|
||||
@FormParam("birth_date")
|
||||
private Date birth_date = null;
|
||||
|
||||
@Schema(description = "L'adresse e-mail du membre.", example = "jean.dupont@example.com")
|
||||
@Schema(description = "L'adresse e-mail du membre.", examples = "jean.dupont@example.com")
|
||||
@FormParam("email")
|
||||
private String email;
|
||||
|
||||
@Schema(description = "Le rôle du membre dans l'association.", example = "MEMBRE")
|
||||
@Schema(description = "Le rôle du membre dans l'association.", examples = "MEMBRE")
|
||||
@FormParam("role")
|
||||
private RoleAsso role;
|
||||
|
||||
@Schema(description = "Le grade d'arbitrage du membre.", example = "ASSESSEUR")
|
||||
@Schema(description = "Le grade d'arbitrage du membre.", examples = "ASSESSEUR")
|
||||
@FormParam("grade_arbitrage")
|
||||
private GradeArbitrage grade_arbitrage = GradeArbitrage.NA;
|
||||
|
||||
@Schema(description = "La photo du membre.")
|
||||
@FormParam("photo_data")
|
||||
@PartType(MediaType.APPLICATION_OCTET_STREAM)
|
||||
private byte[] photo_data = new byte[0];
|
||||
private FileUpload photo_data = null;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
@@ -70,7 +71,6 @@ public class FullMemberForm {
|
||||
", email='" + email + '\'' +
|
||||
", role=" + role +
|
||||
", grade_arbitrage=" + grade_arbitrage +
|
||||
", url_photo=" + photo_data.length +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
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;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package fr.titionfire.ffsaf.utils;
|
||||
|
||||
import fr.titionfire.ffsaf.domain.service.TradService;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
|
||||
import java.util.ResourceBundle;
|
||||
@@ -19,7 +20,7 @@ public enum Categorie {
|
||||
VETERAN2;
|
||||
|
||||
public String getName(ResourceBundle BUNDLE) {
|
||||
return switch (this){
|
||||
return switch (this) {
|
||||
case SUPER_MINI -> BUNDLE.getString("Cat.SUPER_MINI");
|
||||
case MINI_POUSSIN -> BUNDLE.getString("Cat.MINI_POUSSIN");
|
||||
case POUSSIN -> BUNDLE.getString("Cat.POUSSIN");
|
||||
@@ -34,8 +35,24 @@ 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() {
|
||||
return switch (this){
|
||||
return switch (this) {
|
||||
case SUPER_MINI -> "Super Mini";
|
||||
case MINI_POUSSIN -> "Mini Poussin";
|
||||
case POUSSIN -> "Poussin";
|
||||
|
||||
@@ -1,32 +1,34 @@
|
||||
package fr.titionfire.ffsaf.utils;
|
||||
|
||||
import fr.titionfire.ffsaf.domain.service.TradService;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@RegisterForReflection
|
||||
public enum Contact {
|
||||
COURRIEL("Courriel"),
|
||||
TELEPHONE("Téléphone"),
|
||||
SITE("Site web"),
|
||||
FACEBOOK("Facebook"),
|
||||
INSTAGRAM("Instagram"),
|
||||
AUTRE("Autre");
|
||||
COURRIEL,
|
||||
TELEPHONE,
|
||||
SITE,
|
||||
FACEBOOK,
|
||||
INSTAGRAM,
|
||||
AUTRE;
|
||||
|
||||
public String name;
|
||||
|
||||
Contact(String name) {
|
||||
this.name = name;
|
||||
public String getName(TradService trad) {
|
||||
return switch (this) {
|
||||
case COURRIEL -> trad.translate("Contact.COURRIEL");
|
||||
case TELEPHONE -> trad.translate("Contact.TELEPHONE");
|
||||
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 void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static HashMap<String, String> toSite() {
|
||||
public static HashMap<String, String> toSite(TradService trad) {
|
||||
HashMap<String, String> map = new HashMap<>();
|
||||
for (Contact contact : Contact.values()) {
|
||||
map.put(contact.toString(), contact.name);
|
||||
map.put(contact.toString(), contact.getName(trad));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package fr.titionfire.ffsaf.utils;
|
||||
|
||||
import fr.titionfire.ffsaf.domain.service.TradService;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
|
||||
@RegisterForReflection
|
||||
@@ -27,8 +28,17 @@ 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
|
||||
public String toString() {
|
||||
return str;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package fr.titionfire.ffsaf.utils;
|
||||
|
||||
import fr.titionfire.ffsaf.domain.service.TradService;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
|
||||
@RegisterForReflection
|
||||
@@ -14,6 +15,14 @@ public enum GradeArbitrage {
|
||||
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
|
||||
public String toString() {
|
||||
return str;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package fr.titionfire.ffsaf.utils;
|
||||
|
||||
public enum ResultPrivacy {
|
||||
PUBLIC,
|
||||
REGISTERED_ONLY,
|
||||
REGISTERED_ONLY_NO_DETAILS,
|
||||
PRIVATE;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package fr.titionfire.ffsaf.utils;
|
||||
|
||||
import fr.titionfire.ffsaf.domain.service.TradService;
|
||||
import io.quarkus.runtime.annotations.RegisterForReflection;
|
||||
|
||||
@RegisterForReflection
|
||||
@@ -21,6 +22,19 @@ public enum RoleAsso {
|
||||
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
|
||||
public String toString() {
|
||||
return str;
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
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.unchecked.Unchecked;
|
||||
import jakarta.ws.rs.core.HttpHeaders;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jodd.net.MimeTypes;
|
||||
import org.apache.tika.Tika;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.jboss.resteasy.reactive.multipart.FileUpload;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URISyntaxException;
|
||||
@@ -21,6 +29,79 @@ import java.util.concurrent.Future;
|
||||
public class Utils {
|
||||
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édération France Soft Armored Fighting</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>Bonjour,</p>
|
||||
""";
|
||||
public static String HTML_FOOTER = """
|
||||
<p>Cordialement,<br>L’équipe de la FFSAF</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
""";
|
||||
|
||||
public static int getSaison() {
|
||||
return getSaison(new Date());
|
||||
}
|
||||
@@ -108,44 +189,72 @@ public class Utils {
|
||||
});
|
||||
}
|
||||
|
||||
public static Future<String> replacePhoto(long id, byte[] input, String media, String dir) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
if (input == null || input.length == 0)
|
||||
return "OK";
|
||||
public static Uni<String> uploadFile(VirusScannerService ss, FileUpload file, long id, String media, String dir) {
|
||||
if (file == null || file.size() == 0)
|
||||
return Uni.createFrom().item("Ok");
|
||||
|
||||
try (InputStream is = new BufferedInputStream(new ByteArrayInputStream(input))) {
|
||||
String mimeType;
|
||||
try {
|
||||
Tika tika = new Tika();
|
||||
mimeType = tika.detect(is);// Magic.getMagicMatch(input, false).getMimeType();
|
||||
} catch (IOException e) {
|
||||
mimeType = URLConnection.guessContentTypeFromStream(is);
|
||||
}
|
||||
String[] detectedExtensions = MimeTypes.findExtensionsByMimeTypes(mimeType, false);
|
||||
if (detectedExtensions.length == 0)
|
||||
throw new IOException("Fail to detect file extension for MIME type " + mimeType);
|
||||
|
||||
File dirFile = new File(media, dir);
|
||||
if (!dirFile.exists())
|
||||
if (!dirFile.mkdirs())
|
||||
throw new IOException("Fail to create directory " + dir);
|
||||
|
||||
FilenameFilter filter = (directory, filename) -> filename.startsWith(id + ".");
|
||||
File[] files = dirFile.listFiles(filter);
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
file.delete();
|
||||
LOGGER.infof("Received file upload request for: %s (size: %d bytes)", file.fileName(), file.size());
|
||||
return Uni.createFrom().<InputStream>item(() -> {
|
||||
try {
|
||||
// Read the entire file into memory for virus scanning
|
||||
// ByteArrayInputStream fully supports mark/reset operations required by ClamAV
|
||||
// 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) {
|
||||
throw new RuntimeException("Failed to read uploaded file: " + e.getMessage(), e);
|
||||
}
|
||||
}).runSubscriptionOn(io.smallrye.mutiny.infrastructure.Infrastructure.getDefaultWorkerPool()).onItem()
|
||||
.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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String extension = "." + detectedExtensions[0];
|
||||
Files.write(new File(dirFile, id + extension).toPath(), input);
|
||||
return "OK";
|
||||
} catch (IOException e) {
|
||||
return e.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)
|
||||
throw new DBadRequestException(
|
||||
"Fail to detect file extension for MIME type " + file.contentType());
|
||||
|
||||
File dirFile = new File(media, dir);
|
||||
if (!dirFile.exists())
|
||||
if (!dirFile.mkdirs())
|
||||
throw new DInternalError("Fail to create directory " + dir);
|
||||
|
||||
FilenameFilter filter = (directory, filename) -> filename.startsWith(id + ".");
|
||||
File[] files = dirFile.listFiles(filter);
|
||||
if (files != null) {
|
||||
for (File f : files) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
|
||||
File f = file.filePath().toFile();
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
f.renameTo(new File(dirFile, id + "." + detectedExtensions[0]));
|
||||
return "ok";
|
||||
})));
|
||||
}
|
||||
|
||||
public static Uni<Response> getMediaFile(long id, String media, String dirname,
|
||||
@@ -262,4 +371,46 @@ public class Utils {
|
||||
|
||||
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 "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import fr.titionfire.ffsaf.data.repository.CompetitionRepository;
|
||||
import fr.titionfire.ffsaf.domain.service.CompetPermService;
|
||||
import fr.titionfire.ffsaf.net2.MessageType;
|
||||
import fr.titionfire.ffsaf.rest.data.SimpleCompetData;
|
||||
import fr.titionfire.ffsaf.utils.SecurityCtx;
|
||||
import fr.titionfire.ffsaf.ws.data.WelcomeInfo;
|
||||
import fr.titionfire.ffsaf.ws.recv.*;
|
||||
@@ -16,12 +17,15 @@ import io.smallrye.mutiny.Uni;
|
||||
import io.smallrye.mutiny.unchecked.Unchecked;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import jakarta.ws.rs.ForbiddenException;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import static fr.titionfire.ffsaf.net2.Client_Thread.MAPPER;
|
||||
|
||||
@@ -39,17 +43,29 @@ public class CompetitionWS {
|
||||
RCategorie rCategorie;
|
||||
|
||||
@Inject
|
||||
RRegister rRegister;
|
||||
RRegister rRegister;
|
||||
|
||||
@Inject
|
||||
RCardboard rCardboard;
|
||||
|
||||
@Inject
|
||||
RTeam rTeam;
|
||||
|
||||
@Inject
|
||||
SecurityCtx securityCtx;
|
||||
|
||||
@Inject
|
||||
CompetPermService competPermService;
|
||||
|
||||
@SuppressWarnings("CdiInjectionPointsInspection")
|
||||
@Inject
|
||||
OpenConnections connections;
|
||||
|
||||
@Inject
|
||||
@Named("notify-executor")
|
||||
Executor notifyExecutor;
|
||||
private static Executor executor;
|
||||
|
||||
@Inject
|
||||
CompetitionRepository competitionRepository;
|
||||
|
||||
@@ -78,6 +94,9 @@ public class CompetitionWS {
|
||||
getWSReceiverMethods(RCategorie.class, rCategorie);
|
||||
getWSReceiverMethods(RRegister.class, rRegister);
|
||||
getWSReceiverMethods(RCardboard.class, rCardboard);
|
||||
getWSReceiverMethods(RTeam.class, rTeam);
|
||||
|
||||
executor = notifyExecutor;
|
||||
}
|
||||
|
||||
@OnOpen
|
||||
@@ -94,8 +113,8 @@ public class CompetitionWS {
|
||||
.call(cm -> competPermService.hasEditPerm(securityCtx, cm).map(__ -> PermLevel.ADMIN)
|
||||
.onFailure()
|
||||
.recoverWithUni(competPermService.hasTablePerm(securityCtx, cm).map(__ -> PermLevel.TABLE))
|
||||
.onFailure()
|
||||
.recoverWithUni(competPermService.hasViewPerm(securityCtx, cm).map(__ -> PermLevel.VIEW))
|
||||
//.onFailure()
|
||||
//.recoverWithUni(competPermService.hasViewPerm(securityCtx, cm).map(__ -> PermLevel.VIEW))
|
||||
.invoke(prem -> connection.userData().put(UserData.TypedKey.forString("prem"), prem.toString()))
|
||||
.invoke(prem -> LOGGER.infof("Connection permission: %s", prem))
|
||||
.onFailure().transform(t -> new ForbiddenException()))
|
||||
@@ -104,10 +123,13 @@ public class CompetitionWS {
|
||||
waitingResponse.put(connection, new HashMap<>());
|
||||
})
|
||||
.map(cm -> {
|
||||
SimpleCompetData data = SimpleCompetData.fromModel(cm);
|
||||
WelcomeInfo welcomeInfo = new WelcomeInfo();
|
||||
|
||||
welcomeInfo.setName(cm.getName());
|
||||
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);
|
||||
});
|
||||
@@ -166,6 +188,7 @@ public class CompetitionWS {
|
||||
return Uni.createFrom().item(makeError(message, "Permission denied")).toMulti();
|
||||
return ((Uni<?>) method.invoke(entry.getValue(), connection,
|
||||
MAPPER.treeToValue(message.data(), method.getParameterTypes()[1])))
|
||||
.ifNoItem().after(Duration.ofSeconds(5)).fail()
|
||||
.map(o -> makeReply(message, o))
|
||||
.onFailure()
|
||||
.recoverWithItem(t -> {
|
||||
@@ -184,7 +207,7 @@ public class CompetitionWS {
|
||||
// return Uni.createFrom().item(new Message<>(message.uuid(), message.code(), MessageType.REPLY, "ko"));
|
||||
}
|
||||
|
||||
public static Uni<Void> sendNotifyToOtherEditor(WebSocketConnection connection, String code, Object data) {
|
||||
public static void sendNotifyToOtherEditor(WebSocketConnection connection, String code, Object data) {
|
||||
String uuid = connection.pathParam("uuid");
|
||||
|
||||
List<Uni<Void>> queue = new ArrayList<>();
|
||||
@@ -196,7 +219,15 @@ public class CompetitionWS {
|
||||
}
|
||||
});
|
||||
|
||||
return Uni.join().all(queue).andCollectFailures().onFailure().recoverWithNull().replaceWithVoid();
|
||||
Uni.join().all(queue)
|
||||
.andCollectFailures()
|
||||
.runSubscriptionOn(executor)
|
||||
.subscribeAsCompletionStage()
|
||||
.whenComplete((v, t) -> {
|
||||
if (t != null) {
|
||||
LOGGER.error("Error sending ws_out message", t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@OnError
|
||||
|
||||
19
src/main/java/fr/titionfire/ffsaf/ws/ExecutorProducer.java
Normal file
19
src/main/java/fr/titionfire/ffsaf/ws/ExecutorProducer.java
Normal file
@@ -0,0 +1,19 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -8,4 +8,6 @@ import lombok.Data;
|
||||
public class WelcomeInfo {
|
||||
private String name;
|
||||
private String perm;
|
||||
private boolean show_blason;
|
||||
private boolean show_flag;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ 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.domain.service.TradService;
|
||||
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
|
||||
import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
|
||||
import fr.titionfire.ffsaf.ws.PermLevel;
|
||||
@@ -32,13 +33,16 @@ public class RCardboard {
|
||||
@Inject
|
||||
CardboardRepository cardboardRepository;
|
||||
|
||||
@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("Matche non trouver");
|
||||
throw new DNotFoundException(trad.t("matche.non.trouver"));
|
||||
if (!o.getCategory().getCompet().getUuid().equals(connection.pathParam("uuid")))
|
||||
throw new DForbiddenException("Permission denied");
|
||||
throw new DForbiddenException(trad.t("permission.denied"));
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -80,35 +84,32 @@ public class RCardboard {
|
||||
return Uni.createFrom().nullItem();
|
||||
return Panache.withTransaction(() -> cardboardRepository.persist(cardboardModel));
|
||||
}))
|
||||
.call(model -> SSCardboard.sendCardboard(connection, CardboardEntity.fromModel(model)))
|
||||
.invoke(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)
|
||||
.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();
|
||||
});
|
||||
|
||||
for (CardboardModel c : models) {
|
||||
if ((matchModel.getC1_id() != null && Objects.equals(c.getComb(),
|
||||
matchModel.getC1_id())) || (matchModel.getC1_guest() != null && Objects.equals(
|
||||
c.getGuestComb(), matchModel.getC1_guest()))) {
|
||||
out.c1_yellow += c.getYellow();
|
||||
out.c1_red += c.getRed();
|
||||
}
|
||||
if ((matchModel.getC2_id() != null && Objects.equals(c.getComb(),
|
||||
matchModel.getC2_id())) || (matchModel.getC2_guest() != null && Objects.equals(
|
||||
c.getGuestComb(), matchModel.getC2_guest()))) {
|
||||
out.c2_yellow += c.getYellow();
|
||||
out.c2_red += c.getRed();
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -3,12 +3,10 @@ package fr.titionfire.ffsaf.ws.recv;
|
||||
import fr.titionfire.ffsaf.data.model.CategoryModel;
|
||||
import fr.titionfire.ffsaf.data.model.MatchModel;
|
||||
import fr.titionfire.ffsaf.data.model.TreeModel;
|
||||
import fr.titionfire.ffsaf.data.repository.CategoryRepository;
|
||||
import fr.titionfire.ffsaf.data.repository.CompetitionRepository;
|
||||
import fr.titionfire.ffsaf.data.repository.MatchRepository;
|
||||
import fr.titionfire.ffsaf.data.repository.TreeRepository;
|
||||
import fr.titionfire.ffsaf.data.repository.*;
|
||||
import fr.titionfire.ffsaf.domain.entity.MatchEntity;
|
||||
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.DNotFoundException;
|
||||
import fr.titionfire.ffsaf.utils.TreeNode;
|
||||
@@ -46,13 +44,19 @@ public class RCategorie {
|
||||
@Inject
|
||||
TreeRepository treeRepository;
|
||||
|
||||
@Inject
|
||||
CardboardRepository cardboardRepository;
|
||||
|
||||
@Inject
|
||||
TradService trad;
|
||||
|
||||
private Uni<CategoryModel> getById(long id, WebSocketConnection connection) {
|
||||
return categoryRepository.findById(id)
|
||||
.invoke(Unchecked.consumer(o -> {
|
||||
if (o == null)
|
||||
throw new DNotFoundException("Catégorie non trouver");
|
||||
throw new DNotFoundException(trad.t("categorie.non.trouver"));
|
||||
if (!o.getCompet().getUuid().equals(connection.pathParam("uuid")))
|
||||
throw new DForbiddenException("Permission denied");
|
||||
throw new DForbiddenException(trad.t("permission.denied"));
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -97,7 +101,7 @@ public class RCategorie {
|
||||
|
||||
return categoryRepository.create(categoryModel);
|
||||
})
|
||||
.call(cat -> SSCategorie.sendAddCategory(connection, cat))
|
||||
.invoke(cat -> SSCategorie.sendAddCategory(connection, cat))
|
||||
.map(CategoryModel::getId);
|
||||
}
|
||||
|
||||
@@ -118,9 +122,10 @@ public class RCategorie {
|
||||
uni = uni.chain(__ -> treeRepository.delete("category = ?1", cat.getId()))
|
||||
.chain(__ -> matchRepository.delete("category = ?1 AND category_ord = -42", cat));
|
||||
}
|
||||
return uni;
|
||||
Uni<Long> finalUni = uni;
|
||||
return Panache.withTransaction(() -> finalUni);
|
||||
})
|
||||
.call(cat -> SSCategorie.sendCategory(connection, cat))
|
||||
.invoke(cat -> SSCategorie.sendCategory(connection, cat))
|
||||
.replaceWithVoid();
|
||||
}
|
||||
|
||||
@@ -201,7 +206,18 @@ public class RCategorie {
|
||||
.call(__ -> treeRepository.flush())
|
||||
.call(cat -> treeRepository.list("category = ?1 AND level != 0", cat.getId())
|
||||
.map(treeModels -> treeModels.stream().map(TreeEntity::fromModel).toList())
|
||||
.chain(trees -> SSCategorie.sendTreeCategory(connection, trees)))
|
||||
.invoke(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(__ -> cardboardRepository.delete("match.category = ?1", cat))
|
||||
.call(__ -> matchRepository.delete("category = ?1", cat))))
|
||||
.chain(cat -> Panache.withTransaction(() -> categoryRepository.delete(cat)))
|
||||
.invoke(__ -> SSCategorie.sendDelCategory(connection, id))
|
||||
.replaceWithVoid();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import fr.titionfire.ffsaf.data.model.*;
|
||||
import fr.titionfire.ffsaf.data.repository.*;
|
||||
import fr.titionfire.ffsaf.domain.entity.MatchEntity;
|
||||
import fr.titionfire.ffsaf.domain.entity.TreeEntity;
|
||||
import fr.titionfire.ffsaf.domain.service.TradService;
|
||||
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
|
||||
import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
|
||||
import fr.titionfire.ffsaf.utils.ScoreEmbeddable;
|
||||
@@ -44,13 +45,19 @@ public class RMatch {
|
||||
@Inject
|
||||
CompetitionGuestRepository competitionGuestRepository;
|
||||
|
||||
@Inject
|
||||
CardboardRepository cardboardRepository;
|
||||
|
||||
@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("Matche non trouver");
|
||||
throw new DNotFoundException(trad.t("matche.non.trouver"));
|
||||
if (!o.getCategory().getCompet().getUuid().equals(connection.pathParam("uuid")))
|
||||
throw new DForbiddenException("Permission denied");
|
||||
throw new DForbiddenException(trad.t("permission.denied"));
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -78,13 +85,13 @@ public class RMatch {
|
||||
return categoryRepository.findById(m.categorie)
|
||||
.invoke(Unchecked.consumer(o -> {
|
||||
if (o == null)
|
||||
throw new DNotFoundException("Catégorie non trouver");
|
||||
throw new DNotFoundException(trad.t("categorie.non.trouver"));
|
||||
if (!o.getCompet().getUuid().equals(connection.pathParam("uuid")))
|
||||
throw new DForbiddenException("Permission denied");
|
||||
throw new DForbiddenException(trad.t("permission.denied"));
|
||||
}))
|
||||
.chain(categoryModel -> creatMatch(categoryModel, m))
|
||||
.chain(mm -> Panache.withTransaction(() -> matchRepository.create(mm)))
|
||||
.call(mm -> SSMatch.sendMatch(connection, MatchEntity.fromModel(mm)))
|
||||
.invoke(mm -> SSMatch.sendMatch(connection, MatchEntity.fromModel(mm)))
|
||||
.replaceWithVoid();
|
||||
}
|
||||
|
||||
@@ -121,7 +128,7 @@ public class RMatch {
|
||||
mm.setC2_guest(null);
|
||||
}))
|
||||
.chain(mm -> Panache.withTransaction(() -> matchRepository.persist(mm)))
|
||||
.call(mm -> SSMatch.sendMatch(connection, MatchEntity.fromModel(mm)))
|
||||
.invoke(mm -> SSMatch.sendMatch(connection, MatchEntity.fromModel(mm)))
|
||||
.replaceWithVoid();
|
||||
}
|
||||
|
||||
@@ -136,7 +143,7 @@ public class RMatch {
|
||||
m.getCategory_ord()))
|
||||
.invoke(m -> m.setCategory_ord(order.pos))
|
||||
.call(m -> Panache.withTransaction(() -> matchRepository.persist(m)))
|
||||
.call(mm -> SSMatch.sendMatchOrder(connection, order))
|
||||
.invoke(mm -> SSMatch.sendMatchOrder(connection, order))
|
||||
.replaceWithVoid();
|
||||
}
|
||||
|
||||
@@ -163,12 +170,12 @@ public class RMatch {
|
||||
.call(mm -> {
|
||||
if (mm.isEnd() && mm.win() != old_win && mm.getCategory_ord() == -42) {
|
||||
return updateEndAndTree(mm, new ArrayList<>())
|
||||
.call(l -> SSMatch.sendMatch(connection, l));
|
||||
.invoke(l -> SSMatch.sendMatch(connection, l));
|
||||
}
|
||||
return Uni.createFrom().nullItem();
|
||||
});
|
||||
})
|
||||
.call(mm -> SSMatch.sendMatch(connection, MatchEntity.fromModel(mm)))
|
||||
.invoke(mm -> SSMatch.sendMatch(connection, MatchEntity.fromModel(mm)))
|
||||
.replaceWithVoid();
|
||||
}
|
||||
|
||||
@@ -189,7 +196,7 @@ public class RMatch {
|
||||
})
|
||||
.invoke(mm -> toSend.add(MatchEntity.fromModel(mm)))
|
||||
.chain(mm -> updateEndAndTree(mm, toSend))
|
||||
.call(__ -> SSMatch.sendMatch(connection, toSend))
|
||||
.invoke(__ -> SSMatch.sendMatch(connection, toSend))
|
||||
.replaceWithVoid();
|
||||
}
|
||||
|
||||
@@ -277,8 +284,11 @@ public class RMatch {
|
||||
@WSReceiver(code = "deleteMatch", permission = PermLevel.ADMIN)
|
||||
public Uni<Void> deleteMatch(WebSocketConnection connection, Long idMatch) {
|
||||
return getById(idMatch, connection)
|
||||
.chain(matchModel -> Panache.withTransaction(() -> matchRepository.delete(matchModel)))
|
||||
.call(__ -> SSMatch.sendDeleteMatch(connection, idMatch))
|
||||
.map(__ -> idMatch)
|
||||
.chain(l -> Panache.withTransaction(() ->
|
||||
cardboardRepository.delete("match.id = ?1", l)
|
||||
.chain(__ -> matchRepository.delete("id = ?1", l))))
|
||||
.invoke(__ -> SSMatch.sendDeleteMatch(connection, idMatch))
|
||||
.replaceWithVoid();
|
||||
}
|
||||
|
||||
@@ -288,13 +298,15 @@ public class RMatch {
|
||||
return categoryRepository.findById(data.categorie)
|
||||
.invoke(Unchecked.consumer(o -> {
|
||||
if (o == null)
|
||||
throw new DNotFoundException("Catégorie non trouver");
|
||||
throw new DNotFoundException(trad.t("categorie.non.trouver"));
|
||||
if (!o.getCompet().getUuid().equals(connection.pathParam("uuid")))
|
||||
throw new DForbiddenException("Permission denied");
|
||||
throw new DForbiddenException(trad.t("permission.denied"));
|
||||
}))
|
||||
.call(cm -> matchRepository.delete("id IN ?1 AND category = ?2", data.matchesToRemove, cm)
|
||||
.call(__ -> SSMatch.sendDeleteMatch(connection, data.matchesToRemove)))
|
||||
.call(cm -> matchRepository.list("id IN ?1 AND category = ?2",
|
||||
.call(cm -> data.matchesToRemove.isEmpty() ? Uni.createFrom().voidItem() :
|
||||
(Panache.withTransaction(
|
||||
() -> matchRepository.delete("id IN ?1 AND category = ?2", data.matchesToRemove, cm))
|
||||
.invoke(__ -> SSMatch.sendDeleteMatch(connection, data.matchesToRemove))))
|
||||
.call(cm -> Panache.withSession(() -> matchRepository.list("id IN ?1 AND category = ?2",
|
||||
Stream.concat(data.matchOrderToUpdate.keySet().stream(),
|
||||
data.matchPouleToUpdate.keySet().stream())
|
||||
.distinct().toList(), cm)
|
||||
@@ -304,19 +316,22 @@ public class RMatch {
|
||||
if (data.matchOrderToUpdate.containsKey(model.getId()))
|
||||
model.setCategory_ord(data.matchOrderToUpdate.get(model.getId()));
|
||||
}))
|
||||
.call(mm -> Panache.withTransaction(() -> matchRepository.persist(mm)))
|
||||
.invoke(mm -> matches.addAll(mm.stream().map(MatchEntity::fromModel).toList()))
|
||||
.call(mm -> mm.isEmpty() ? Uni.createFrom().voidItem() :
|
||||
Panache.withTransaction(() -> matchRepository.persist(mm)))
|
||||
.invoke(mm -> matches.addAll(mm.stream().map(MatchEntity::fromModel).toList())))
|
||||
)
|
||||
.chain(categoryModel -> {
|
||||
Uni<List<MatchModel>> uni = Uni.createFrom().item(new ArrayList<>());
|
||||
for (AddMatch match : data.newMatch)
|
||||
uni = uni.call(l -> creatMatch(categoryModel, match).invoke(l::add));
|
||||
return uni;
|
||||
Uni<List<MatchModel>> finalUni = uni;
|
||||
return Panache.withSession(() -> finalUni);
|
||||
}
|
||||
)
|
||||
.chain(mm -> Panache.withTransaction(() -> matchRepository.create(mm))
|
||||
.invoke(__ -> matches.addAll(mm.stream().map(MatchEntity::fromModel).toList())))
|
||||
.call(__ -> SSMatch.sendMatch(connection, matches))
|
||||
.chain(mm -> mm.isEmpty() ? Uni.createFrom().voidItem() :
|
||||
Panache.withTransaction(() -> matchRepository.create(mm))
|
||||
.invoke(__ -> matches.addAll(mm.stream().map(MatchEntity::fromModel).toList())))
|
||||
.invoke(__ -> SSMatch.sendMatch(connection, matches))
|
||||
.replaceWithVoid();
|
||||
}
|
||||
|
||||
|
||||
137
src/main/java/fr/titionfire/ffsaf/ws/recv/RTeam.java
Normal file
137
src/main/java/fr/titionfire/ffsaf/ws/recv/RTeam.java
Normal file
@@ -0,0 +1,137 @@
|
||||
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) {
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,10 @@ 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);
|
||||
public static void sendCardboard(WebSocketConnection connection, CardboardEntity cardboardEntity) {
|
||||
CompetitionWS.sendNotifyToOtherEditor(connection, "sendCardboard", cardboardEntity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,29 +5,32 @@ import fr.titionfire.ffsaf.domain.entity.TreeEntity;
|
||||
import fr.titionfire.ffsaf.ws.CompetitionWS;
|
||||
import fr.titionfire.ffsaf.ws.recv.RCategorie;
|
||||
import io.quarkus.websockets.next.WebSocketConnection;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SSCategorie {
|
||||
|
||||
public static Uni<Void> sendAddCategory(WebSocketConnection connection, CategoryModel category) {
|
||||
return SSCategorie.sendAddCategory(connection, RCategorie.JustCategorie.from(category));
|
||||
public static void sendAddCategory(WebSocketConnection connection, CategoryModel category) {
|
||||
SSCategorie.sendAddCategory(connection, RCategorie.JustCategorie.from(category));
|
||||
}
|
||||
|
||||
public static Uni<Void> sendAddCategory(WebSocketConnection connection, RCategorie.JustCategorie justCategorie) {
|
||||
return CompetitionWS.sendNotifyToOtherEditor(connection, "sendAddCategory", justCategorie);
|
||||
public static void sendAddCategory(WebSocketConnection connection, RCategorie.JustCategorie justCategorie) {
|
||||
CompetitionWS.sendNotifyToOtherEditor(connection, "sendAddCategory", justCategorie);
|
||||
}
|
||||
|
||||
public static Uni<Void> sendCategory(WebSocketConnection connection, CategoryModel category) {
|
||||
return SSCategorie.sendCategory(connection, RCategorie.JustCategorie.from(category));
|
||||
public static void sendCategory(WebSocketConnection connection, CategoryModel category) {
|
||||
SSCategorie.sendCategory(connection, RCategorie.JustCategorie.from(category));
|
||||
}
|
||||
|
||||
public static Uni<Void> sendCategory(WebSocketConnection connection, RCategorie.JustCategorie justCategorie) {
|
||||
return CompetitionWS.sendNotifyToOtherEditor(connection, "sendCategory", justCategorie);
|
||||
public static void sendCategory(WebSocketConnection connection, RCategorie.JustCategorie justCategorie) {
|
||||
CompetitionWS.sendNotifyToOtherEditor(connection, "sendCategory", justCategorie);
|
||||
}
|
||||
|
||||
public static Uni<Void> sendTreeCategory(WebSocketConnection connection, List<TreeEntity> treeEntities) {
|
||||
return CompetitionWS.sendNotifyToOtherEditor(connection, "sendTreeCategory", treeEntities);
|
||||
public static void sendTreeCategory(WebSocketConnection connection, List<TreeEntity> treeEntities) {
|
||||
CompetitionWS.sendNotifyToOtherEditor(connection, "sendTreeCategory", treeEntities);
|
||||
}
|
||||
|
||||
public static void sendDelCategory(WebSocketConnection connection, Long id) {
|
||||
CompetitionWS.sendNotifyToOtherEditor(connection, "sendDelCategory", id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,29 +4,28 @@ import fr.titionfire.ffsaf.domain.entity.MatchEntity;
|
||||
import fr.titionfire.ffsaf.ws.CompetitionWS;
|
||||
import fr.titionfire.ffsaf.ws.recv.RMatch;
|
||||
import io.quarkus.websockets.next.WebSocketConnection;
|
||||
import io.smallrye.mutiny.Uni;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SSMatch {
|
||||
|
||||
public static Uni<Void> sendMatch(WebSocketConnection connection, MatchEntity matchEntity) {
|
||||
return SSMatch.sendMatch(connection, List.of(matchEntity));
|
||||
public static void sendMatch(WebSocketConnection connection, MatchEntity matchEntity) {
|
||||
SSMatch.sendMatch(connection, List.of(matchEntity));
|
||||
}
|
||||
|
||||
public static Uni<Void> sendMatch(WebSocketConnection connection, List<MatchEntity> matchEntities) {
|
||||
return CompetitionWS.sendNotifyToOtherEditor(connection, "sendMatch", matchEntities);
|
||||
public static void sendMatch(WebSocketConnection connection, List<MatchEntity> matchEntities) {
|
||||
CompetitionWS.sendNotifyToOtherEditor(connection, "sendMatch", matchEntities);
|
||||
}
|
||||
|
||||
public static Uni<Void> sendMatchOrder(WebSocketConnection connection, RMatch.MatchOrder matchOrder) {
|
||||
return CompetitionWS.sendNotifyToOtherEditor(connection, "sendMatchOrder", matchOrder);
|
||||
public static void sendMatchOrder(WebSocketConnection connection, RMatch.MatchOrder matchOrder) {
|
||||
CompetitionWS.sendNotifyToOtherEditor(connection, "sendMatchOrder", matchOrder);
|
||||
}
|
||||
|
||||
public static Uni<Void> sendDeleteMatch(WebSocketConnection connection, Long l) {
|
||||
return SSMatch.sendDeleteMatch(connection, List.of(l));
|
||||
public static void sendDeleteMatch(WebSocketConnection connection, Long l) {
|
||||
SSMatch.sendDeleteMatch(connection, List.of(l));
|
||||
}
|
||||
|
||||
public static Uni<Void> sendDeleteMatch(WebSocketConnection connection, List<Long> longs) {
|
||||
return CompetitionWS.sendNotifyToOtherEditor(connection, "sendDeleteMatch", longs);
|
||||
public static void sendDeleteMatch(WebSocketConnection connection, List<Long> longs) {
|
||||
CompetitionWS.sendNotifyToOtherEditor(connection, "sendDeleteMatch", longs);
|
||||
}
|
||||
}
|
||||
|
||||
16
src/main/java/fr/titionfire/ffsaf/ws/send/SSRegister.java
Normal file
16
src/main/java/fr/titionfire/ffsaf/ws/send/SSRegister.java
Normal file
@@ -0,0 +1,16 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,9 @@ quarkus.hibernate-orm.database.generation=update
|
||||
quarkus.hibernate-orm.physical-naming-strategy=fr.titionfire.ffsaf.data.SafcaNamingStrategy
|
||||
|
||||
quarkus.hibernate-orm.dialect=fr.titionfire.ffsaf.data.CustomPostgreSQLDialect
|
||||
quarkus.datasource.jdbc.reactive.max-size=40
|
||||
|
||||
quarkus.http.cors=true
|
||||
quarkus.http.cors.enabled=true
|
||||
quarkus.quartz.start-mode=forced
|
||||
|
||||
%dev.pdf-maker.jar-path=src\\main\\pdf_gen\\target\\pdf_gen-1.0-SNAPSHOT-jar-with-dependencies.jar
|
||||
@@ -67,7 +68,7 @@ quarkus.http.auth.permission.public.policy=permit
|
||||
quarkus.keycloak.admin-client.server-url=https://auth.safca.fr
|
||||
|
||||
|
||||
quarkus.native.resources.includes=asset/**
|
||||
quarkus.native.resources.includes=asset/**,lang/**
|
||||
|
||||
# HelloAsso Connector
|
||||
helloasso.api=https://api.helloasso.com
|
||||
@@ -75,6 +76,4 @@ helloasso.client-id=changeme
|
||||
helloasso.client-secret=changeme
|
||||
|
||||
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
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
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
|
||||
87
src/main/resources/lang/messages_en.properties
Normal file
87
src/main/resources/lang/messages_en.properties
Normal file
@@ -0,0 +1,87 @@
|
||||
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
|
||||
83
src/main/resources/lang/messages_fr.properties
Normal file
83
src/main/resources/lang/messages_fr.properties
Normal file
@@ -0,0 +1,83 @@
|
||||
filtre.all=--Tous--
|
||||
no.licence=Non licencié
|
||||
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étéran 1
|
||||
Cat.VETERAN2=Vétéran 2
|
||||
access.denied=Accès refusé
|
||||
club.not.found=Club introuvable
|
||||
combattant.non.inscrit=Combattant non inscrit
|
||||
comb.not.found=Combat introuvable
|
||||
matche.non.trouver=Match introuvable
|
||||
permission.denied=Permission refusée
|
||||
categorie.non.trouver=Catégorie introuvable
|
||||
RoleAsso.MEMBRE=Membre
|
||||
RoleAsso.PRESIDENT=Président
|
||||
RoleAsso.VPRESIDENT=Vice-Président
|
||||
RoleAsso.SECRETAIRE=Secrétaire
|
||||
RoleAsso.VSECRETAIRE=Vice-Secrétaire
|
||||
RoleAsso.TRESORIER=Trésorier
|
||||
RoleAsso.VTRESORIER=Vice-Trésorier
|
||||
RoleAsso.MEMBREBUREAU=Membre bureau
|
||||
sans.club=Sans club
|
||||
categorie.inconnue=catégorie inconnue
|
||||
GradeArbitrage.NA=N/A
|
||||
GradeArbitrage.ASSESSEUR=Assesseur
|
||||
GradeArbitrage.ARBITRE=Arbitre
|
||||
Genre.Homme=Homme
|
||||
Genre.Femme=Femme
|
||||
Genre.NA=Non défini
|
||||
Contact.COURRIEL=Courriel
|
||||
Contact.TELEPHONE=Téléphone
|
||||
Contact.SITE=Site web
|
||||
Contact.FACEBOOK=Facebook
|
||||
Contact.INSTAGRAM=Instagram
|
||||
Contact.AUTRE=Autre
|
||||
service.momentanement.indisponible=Service momentanément indisponible
|
||||
asso.introuvable=Association introuvable
|
||||
erreur.lors.calcul.du.trie=Erreur lors du calcul du tri
|
||||
page.out.of.range=Page out of range
|
||||
le.membre.appartient.pas.a.votre.club=Le membre n°%d n'appartient pas à votre club
|
||||
email.deja.utilise.par=L'adresse e-mail '%s' est déjà utilisée par %s %s
|
||||
try.edit.licence=Pour enregistrer un nouveau membre, veuillez laisser le champ licence vide. (Tentative de modification non autorisée du nom sur la licence %d pour %s %s)
|
||||
email.deja.utilise=Adresse e-mail déjà utilisée
|
||||
regiter.new.membre=Pour enregistrer un nouveau membre, veuillez utiliser le bouton prévu à cet effet.
|
||||
permission.insuffisante=Permissions insuffisantes
|
||||
membre.deja.existent=Membre déjà existant
|
||||
membre.rm.err1=Impossible de supprimer un membre qui possède déjà un numéro de licence
|
||||
membre.rm.err2=Impossible de supprimer un membre ayant des licences actives
|
||||
pas.de.licence.pour.la.saison.en.cours=Aucune licence pour la saison en cours
|
||||
club.non.trouve=Club introuvable
|
||||
pas.d.affiliation.pour.la.saison.en.cours=Aucune affiliation pour la saison en cours
|
||||
erreur.lors.de.la.selection.des.membres=Erreur lors de la sélection des membres
|
||||
licence.rm.err1=Impossible de supprimer une licence pour laquelle un paiement est en cours
|
||||
licence.deja.demandee=Licence déjà demandée
|
||||
impossible.de.supprimer.une.licence.deja.validee=Impossible de supprimer une licence déjà validée
|
||||
impossible.de.supprimer.une.licence.deja.payee=Impossible de supprimer une licence déjà payée
|
||||
vous.ne.pouvez.pas.creer.de.competition=Vous n'êtes pas autorisé à créer une compétition
|
||||
user.not.found=Utilisateur %s introuvable
|
||||
inscription.fermee=Inscription fermée
|
||||
insc.err1=Vous n'êtes pas autorisé à inscrire ce membre (décision de l'administrateur de la compétition)
|
||||
insc.err2=Vous n'êtes pas autorisé à vous inscrire (décision de l'administrateur de la compétition)
|
||||
insc.err3=Modification bloquée par l'administrateur de la compétition
|
||||
licence.non.trouve=Licence %s introuvable
|
||||
nom.et.prenom.requis=Nom et prénom obligatoires
|
||||
combattant.non.trouve=Combattant %s %s introuvable
|
||||
le.membre.n.existe.pas=Le membre n°%d n'existe pas
|
||||
competition.is.not.internal=Competition is not INTERNAL
|
||||
erreur.de.format.des.contacts=Format des contacts invalide
|
||||
competition.not.found=Compétition introuvable
|
||||
saison.non.valid=Saison invalide
|
||||
demande.d.affiliation.deja.existante=Une demande d'affiliation existe déjà
|
||||
affiliation.deja.existante=Affiliation déjà existante
|
||||
licence.membre.n.1.inconnue=Licence du membre n°1 inconnue
|
||||
licence.membre.n.2.inconnue=Licence du membre n°2 inconnue
|
||||
licence.membre.n.3.inconnue=Licence du membre n°3 inconnue
|
||||
demande.d.affiliation.non.trouve=Demande d'affiliation introuvable
|
||||
1
src/main/webapp/.gitignore
vendored
1
src/main/webapp/.gitignore
vendored
@@ -22,3 +22,4 @@ dist-ssr
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
/public/result_test.html
|
||||
|
||||
4264
src/main/webapp/package-lock.json
generated
4264
src/main/webapp/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -13,34 +13,40 @@
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.5.1",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.5.1",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.5.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.5.1",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"axios": "^1.6.5",
|
||||
"@fortawesome/fontawesome-svg-core": "^7.1.0",
|
||||
"@fortawesome/free-brands-svg-icons": "^7.1.0",
|
||||
"@fortawesome/free-regular-svg-icons": "^7.1.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^7.1.0",
|
||||
"@fortawesome/react-fontawesome": "^3.1.1",
|
||||
"axios": "^1.13.2",
|
||||
"browser-image-compression": "^2.0.2",
|
||||
"i18next": "^25.7.4",
|
||||
"i18next-browser-languagedetector": "^8.2.0",
|
||||
"i18next-http-backend": "^3.0.2",
|
||||
"jszip": "^3.10.1",
|
||||
"leaflet": "^1.9.4",
|
||||
"proj4": "^2.11.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-is": "^19.0.0",
|
||||
"react-leaflet": "^4.2.1",
|
||||
"react-loader-spinner": "^6.1.6",
|
||||
"react-router-dom": "^6.21.2",
|
||||
"react-toastify": "^10.0.4",
|
||||
"recharts": "^2.15.1",
|
||||
"obs-websocket-js": "^5.0.7",
|
||||
"proj4": "^2.20.2",
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
"react-i18next": "^16.5.3",
|
||||
"react-is": "^19.2.3",
|
||||
"react-leaflet": "^5.0.0",
|
||||
"react-loader-spinner": "^8.0.2",
|
||||
"react-router-dom": "^7.12.0",
|
||||
"react-toastify": "^11.0.5",
|
||||
"recharts": "^3.6.0",
|
||||
"xlsx": "^0.18.5",
|
||||
"xlsx-js-style": "^1.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.43",
|
||||
"@types/react-dom": "^18.2.17",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"eslint": "^8.55.0",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.5",
|
||||
"vite": "^5.0.8"
|
||||
"@types/react": "^19.2.8",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^5.1.2",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-react-refresh": "^0.4.26",
|
||||
"vite": "^7.3.1"
|
||||
}
|
||||
}
|
||||
|
||||
BIN
src/main/webapp/public/Logo-FFSAF-2023.png
Normal file
BIN
src/main/webapp/public/Logo-FFSAF-2023.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 155 KiB |
995
src/main/webapp/public/competition.js
Normal file
995
src/main/webapp/public/competition.js
Normal file
@@ -0,0 +1,995 @@
|
||||
import i18next from 'https://cdn.jsdelivr.net/npm/i18next@25.7.4/+esm';
|
||||
import i18nextHttpBackend from 'https://cdn.jsdelivr.net/npm/i18next-http-backend@3.0.2/+esm'
|
||||
import i18nextBrowserLanguagedetector from 'https://cdn.jsdelivr.net/npm/i18next-browser-languagedetector@8.2.0/+esm'
|
||||
|
||||
let apiUrlRoot = "";
|
||||
const rootDiv = document.getElementById("safca_api_data");
|
||||
const cupImg = `<img decoding="async" loading="lazy" width="16" height="16" class="wp-image-1635"
|
||||
style="width: 16px;" src="https://intra.ffsaf.fr/img/171891.png"
|
||||
alt="">`
|
||||
const cupImg2 = `<img decoding="async" loading="lazy" width="16" height="16" class="wp-image-1635"
|
||||
style="width: 16px;" src="https://intra.ffsaf.fr/img/171892.png"
|
||||
alt="">`
|
||||
|
||||
|
||||
const voidFunction = () => {
|
||||
}
|
||||
let lastRf = 0;
|
||||
let rfFonction = voidFunction;
|
||||
|
||||
setInterval(() => {
|
||||
// rfFonction();
|
||||
}, 15000);
|
||||
|
||||
function setSubPage(name) {
|
||||
window.location.hash = name;
|
||||
const location = name.split('/');
|
||||
console.log(location);
|
||||
|
||||
switch (location[0]) {
|
||||
case 'home':
|
||||
homePage();
|
||||
break;
|
||||
case 'poule':
|
||||
poulePage(location);
|
||||
break;
|
||||
case 'comb':
|
||||
combPage(location);
|
||||
break;
|
||||
case 'club':
|
||||
clubPage(location);
|
||||
break;
|
||||
case 'all':
|
||||
combsPage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function homePage() {
|
||||
rootDiv.innerHTML = `<h4>${i18next.t('résultatDeLaCompétition')} :</h4>`;
|
||||
|
||||
let content = document.createElement('div');
|
||||
content.innerHTML = `
|
||||
<ul>
|
||||
<li><a id="pouleLink" href="javascript:void(0);">${i18next.t('parCatégorie')}</a></li>
|
||||
<li><a id="combLink" href="javascript:void(0);">${i18next.t('parCombattant')}</a></li>
|
||||
<li><a id="clubLink" href="javascript:void(0);">${i18next.t('parClub')}</a></li>
|
||||
<li><a id="allLink" href="javascript:void(0);">${i18next.t('tousLesCombattants')}</a></li>
|
||||
</ul>
|
||||
`
|
||||
rootDiv.append(content)
|
||||
|
||||
document.getElementById('pouleLink').addEventListener('click', () => setSubPage('poule'));
|
||||
document.getElementById('combLink').addEventListener('click', () => setSubPage('comb'));
|
||||
document.getElementById('clubLink').addEventListener('click', () => setSubPage('club'));
|
||||
document.getElementById('allLink').addEventListener('click', () => setSubPage('all'));
|
||||
}
|
||||
|
||||
let loadingAnimationStep = 0;
|
||||
|
||||
function startLoading(root) {
|
||||
const id = "loading" + Math.random().toString(36);
|
||||
let element = document.createElement('h2');
|
||||
element.id = id;
|
||||
|
||||
const anim = setInterval(() => {
|
||||
let str = i18next.t('chargement');
|
||||
for (let i = 0; i < loadingAnimationStep; i++) {
|
||||
str += ".";
|
||||
}
|
||||
loadingAnimationStep = (loadingAnimationStep + 1) % 4;
|
||||
element.innerText = str;
|
||||
}, 500);
|
||||
|
||||
root.append(element)
|
||||
return {interval: anim, root: root, element: element};
|
||||
}
|
||||
|
||||
function stopLoading(loading) {
|
||||
clearInterval(loading['interval']);
|
||||
loading['root'].removeChild(loading['element']);
|
||||
}
|
||||
|
||||
function scoreToString(score) {
|
||||
const scorePrint = (s1) => {
|
||||
switch (s1) {
|
||||
case -997:
|
||||
return i18next.t('disc.');
|
||||
case -998:
|
||||
return i18next.t('abs.');
|
||||
case -999:
|
||||
return i18next.t('for.');
|
||||
case -1000:
|
||||
return "";
|
||||
default:
|
||||
return String(s1);
|
||||
}
|
||||
}
|
||||
|
||||
return score.map(o => scorePrint(o.at(0)) + "-" + scorePrint(o.at(1))).join(" | ");
|
||||
}
|
||||
|
||||
function dateToString(date) {
|
||||
if (date === null || date === undefined)
|
||||
return "";
|
||||
|
||||
const date_ = new Date(date);
|
||||
const date_2 = new Date(date);
|
||||
const current = new Date();
|
||||
current.setHours(0, 0, 0, 0);
|
||||
date_2.setHours(0, 0, 0, 0);
|
||||
|
||||
let d = Math.floor((current - date_2) / (1000 * 60 * 60 * 24));
|
||||
if (d === 0)
|
||||
return i18next.t('aujourdhuià', {time: date_.toLocaleTimeString([], {hour: "2-digit", minute: "2-digit"})});
|
||||
else if (d === 1)
|
||||
return i18next.t('hierà', {time: date_.toLocaleTimeString([], {hour: "2-digit", minute: "2-digit"})});
|
||||
else if (d === 2)
|
||||
return i18next.t('avanthierà', {time: date_.toLocaleTimeString([], {hour: "2-digit", minute: "2-digit"})});
|
||||
else
|
||||
return date_.toLocaleDateString();
|
||||
}
|
||||
|
||||
function buildPouleMenu(isPoule, change_view) {
|
||||
const menuDiv = document.createElement('div');
|
||||
menuDiv.id = 'menu';
|
||||
menuDiv.style.borderBottom = '1px solid #9EA0A1';
|
||||
menuDiv.style.paddingBottom = '25px';
|
||||
|
||||
const ul = document.createElement('ul');
|
||||
ul.id = 'onglets';
|
||||
ul.style.position = 'absolute';
|
||||
ul.style.border = '1px solid transparent';
|
||||
ul.style.padding = '0';
|
||||
ul.style.font = 'bold 11px Batang, arial, serif';
|
||||
ul.style.listStyleType = 'none';
|
||||
ul.style.left = '50%';
|
||||
ul.style.marginTop = '0';
|
||||
ul.style.width = '430px';
|
||||
ul.style.marginLeft = '-215px';
|
||||
|
||||
function createTab(text, isActive, onClickHandler) {
|
||||
const li = document.createElement('li');
|
||||
if (isActive) {
|
||||
li.className = 'active';
|
||||
li.style.borderBottom = '1px solid #fff';
|
||||
li.style.backgroundColor = '#fff';
|
||||
} else {
|
||||
li.style.backgroundColor = '#F4F9FD';
|
||||
}
|
||||
li.style.float = 'left';
|
||||
li.style.height = '21px';
|
||||
li.style.margin = '2px 2px 0 2px !important';
|
||||
li.style.margin = '1px 2px 0 2px';
|
||||
li.style.border = '1px solid #9EA0A1';
|
||||
|
||||
const a = document.createElement('a');
|
||||
a.href = 'javascript:void(0);';
|
||||
a.onclick = onClickHandler;
|
||||
a.textContent = text;
|
||||
a.style.display = 'block';
|
||||
a.style.color = '#666';
|
||||
a.style.textDecoration = 'none';
|
||||
a.style.padding = '4px';
|
||||
|
||||
a.addEventListener('mouseover', function () {
|
||||
a.style.background = '#fff';
|
||||
});
|
||||
|
||||
a.addEventListener('mouseout', function () {
|
||||
if (!isActive)
|
||||
a.style.background = '#F4F9FD';
|
||||
});
|
||||
|
||||
li.appendChild(a);
|
||||
return li;
|
||||
}
|
||||
|
||||
const li1 = createTab(i18next.t('poule'), isPoule, function () {
|
||||
change_view(true);
|
||||
});
|
||||
ul.appendChild(li1);
|
||||
const li2 = createTab(i18next.t('tournois'), !isPoule, function () {
|
||||
change_view(false);
|
||||
});
|
||||
ul.appendChild(li2);
|
||||
|
||||
menuDiv.appendChild(ul);
|
||||
|
||||
return menuDiv;
|
||||
}
|
||||
|
||||
function buildMatchArray(matchs) {
|
||||
const pouleDiv = document.createElement('div');
|
||||
let arrayContent = `
|
||||
<figure class="wp-block-table is-style-stripes" style="font-size: 16px">
|
||||
<table style="width: 800px;overflow: auto"><thead>
|
||||
<tr>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('rouge')}</th>
|
||||
<th class="has-text-align-center" data-align="center"></th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('scores')}</th>
|
||||
<th class="has-text-align-center" data-align="center"></th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('bleu')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('date')}</th>
|
||||
</tr>
|
||||
</thead><tbody>`
|
||||
for (const match of matchs) {
|
||||
arrayContent += `
|
||||
<tr>
|
||||
<td class="has-text-align-right" data-align="right">${match.red}</td>
|
||||
<td class="has-text-align-center" data-align="center">${match.red_w ? cupImg : (match.eq ? cupImg2 : "")}</td>
|
||||
<td class="has-text-align-center" data-align="center">${scoreToString(match.score)}</td>
|
||||
<td class="has-text-align-center" data-align="center">${match.blue_w ? cupImg : (match.eq ? cupImg2 : "")}</td>
|
||||
<td class="has-text-align-left" data-align="left">${match.blue}</td>
|
||||
<td class="has-text-align-center" data-align="center">${dateToString((match.end) ? match.date : null)}</td>
|
||||
</tr>`
|
||||
}
|
||||
arrayContent += `</tbody></table></figure>`
|
||||
pouleDiv.innerHTML = arrayContent;
|
||||
return pouleDiv;
|
||||
}
|
||||
|
||||
function buildRankArray(rankArray) {
|
||||
const arrayDiv = document.createElement('div');
|
||||
let arrayContent = `<figure class="wp-block-table is-style-stripes" style="font-size: 16px; margin-top: 2em">
|
||||
<table style="width: 600px;overflow: auto">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('place')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('nom')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('score')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('victoire')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('ratio')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('pointsMarqués')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('pointsReçus')}</th>
|
||||
</tr>
|
||||
</thead><tbody>`
|
||||
for (const row of rankArray) {
|
||||
arrayContent += `
|
||||
<tr>
|
||||
<td class="has-text-align-center" data-align="center">${row.rank}</td>
|
||||
<td class="has-text-align-left" data-align="left">${row.name}</td>
|
||||
<td class="has-text-align-center" data-align="center">${row.score}</td>
|
||||
<td class="has-text-align-center" data-align="center">${row.win}</td>
|
||||
<td class="has-text-align-center" data-align="center">${row.pointRate.toFixed(3)}</td>
|
||||
<td class="has-text-align-center" data-align="center">${row.pointMake}</td>
|
||||
<td class="has-text-align-center" data-align="center">${row.pointTake}</td>
|
||||
</tr>`
|
||||
|
||||
}
|
||||
arrayContent += `</tbody></table></figure>`
|
||||
arrayDiv.innerHTML = arrayContent;
|
||||
return arrayDiv;
|
||||
}
|
||||
|
||||
function buildTree(treeData) {
|
||||
return drawGraph(initTree(treeData))
|
||||
}
|
||||
|
||||
function poulePage(location) {
|
||||
rootDiv.innerHTML = `<h4>${i18next.t('résultatDeLaCompétition')} :</h4><a id="homeLink" href="javascript:void(0);">${i18next.t('back')}</a>`;
|
||||
document.getElementById('homeLink').addEventListener('click', () => setSubPage('home'));
|
||||
|
||||
const content = document.createElement('div');
|
||||
content.style.marginTop = '1em';
|
||||
content.innerHTML = `<h4>${i18next.t('rechercheParCatégorie')}</h4>`;
|
||||
|
||||
const dataContainer = document.createElement('div');
|
||||
dataContainer.id = 'data-container';
|
||||
|
||||
let currentPoule = 0;
|
||||
const loadPoule = () => {
|
||||
const loading = startLoading(content);
|
||||
fetch(`${apiUrlRoot}/poule/data?poule=${currentPoule}&rf=${lastRf}`)
|
||||
.then(response => {
|
||||
if (response.status === 204) // No content => no update
|
||||
return;
|
||||
|
||||
response.json().then(poule => {
|
||||
lastRf = (poule.genTime !== undefined) ? poule.genTime : 0;
|
||||
// console.log(poule);
|
||||
|
||||
if (location.length === 3 && poule.type < 3) {
|
||||
location.pop();
|
||||
window.location.hash = location.join('/');
|
||||
}
|
||||
|
||||
dataContainer.replaceChildren();
|
||||
|
||||
if (poule.type === 1) {
|
||||
for (const g in poule.matchs) {
|
||||
if (Object.keys(poule.matchs).length > 1) {
|
||||
const text = document.createElement('h4');
|
||||
text.textContent = `${i18next.t('poule')} ${g}`;
|
||||
text.style.marginTop = '2em';
|
||||
dataContainer.append(text);
|
||||
}
|
||||
dataContainer.append(buildMatchArray(poule.matchs[g]));
|
||||
dataContainer.append(buildRankArray(poule.rankArray[g]));
|
||||
}
|
||||
} else if (poule.type === 2) {
|
||||
dataContainer.append(buildTree(poule['trees']));
|
||||
} else {
|
||||
const change_view = (isPoule) => {
|
||||
dataContainer.replaceChildren(buildPouleMenu(isPoule, change_view));
|
||||
|
||||
if (isPoule) {
|
||||
for (const g in poule.matchs) {
|
||||
if (Object.keys(poule.matchs).length > 1) {
|
||||
const text = document.createElement('h4');
|
||||
text.textContent = `${i18next.t('poule')} ${g}`;
|
||||
text.style.marginTop = '2em';
|
||||
dataContainer.append(text);
|
||||
}
|
||||
dataContainer.append(buildMatchArray(poule.matchs[g]));
|
||||
dataContainer.append(buildRankArray(poule.rankArray[g]));
|
||||
}
|
||||
} else {
|
||||
dataContainer.append(buildTree(poule['trees']));
|
||||
}
|
||||
|
||||
location[2] = isPoule ? 1 : 2;
|
||||
window.location.hash = location.join('/');
|
||||
}
|
||||
change_view((location.length === 3) ? location[2] === '1' : true);
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
dataContainer.replaceChildren(new Text(i18next.t('erreurDeChargementDeLaPoule')));
|
||||
})
|
||||
.finally(() => stopLoading(loading));
|
||||
}
|
||||
|
||||
const loading = startLoading(content);
|
||||
fetch(`${apiUrlRoot}/poule/list`)
|
||||
.then(response => response.json())
|
||||
.then(poule => {
|
||||
const select = document.createElement('select');
|
||||
select.setAttribute('id', poule.id);
|
||||
select.innerHTML = `<option value="0">${i18next.t('--sélectionnerUneCatégorie--')}</option>`;
|
||||
for (const pouleKey of Object.keys(poule).sort((a, b) => a.toLocaleLowerCase().localeCompare(b.toLocaleLowerCase()))) {
|
||||
select.innerHTML += `<option value="${poule[pouleKey]}">${pouleKey}</option>`;
|
||||
}
|
||||
select.addEventListener('change', e => {
|
||||
location[1] = Object.keys(poule).find(key => poule[key] === Number(e.target.value));
|
||||
location[1] = encodeURI(location[1]);
|
||||
window.location.hash = location.join('/');
|
||||
lastRf = 0;
|
||||
currentPoule = e.target.value;
|
||||
loadPoule();
|
||||
})
|
||||
content.append(select);
|
||||
content.appendChild(dataContainer);
|
||||
|
||||
if (location.length > 1 && location[1] !== undefined && location[1] !== '') {
|
||||
const tmp = poule[decodeURI(location[1])];
|
||||
select.value = tmp;
|
||||
currentPoule = tmp
|
||||
loadPoule();
|
||||
}
|
||||
})
|
||||
.catch(() => rootDiv.append(new Text(i18next.t('erreurDeChargementDesCatégories'))))
|
||||
.finally(() => stopLoading(loading));
|
||||
|
||||
rfFonction = () => {
|
||||
if (currentPoule !== 0)
|
||||
loadPoule();
|
||||
}
|
||||
|
||||
rootDiv.append(content)
|
||||
}
|
||||
|
||||
function buildCombView(comb) {
|
||||
const pouleDiv = document.createElement('div');
|
||||
let arrayContent = `
|
||||
<h3>Info :</h3>
|
||||
<ul>
|
||||
<li>${i18next.t('nomPrénom')} : ${comb.name}</li>
|
||||
<li>${i18next.t('club')} : ${comb.club}</li>
|
||||
<li>${i18next.t('catégorie')} : ${comb.cat}</li>
|
||||
</ul>
|
||||
<h3>${i18next.t('statistique')} :</h3>
|
||||
<ul>
|
||||
<li>${i18next.t('tauxDeVictoire2', {
|
||||
nb: comb.matchs.length === 0 ? "---" : (comb.totalWin / comb.matchs.filter(m => m.end).length * 100).toFixed(0),
|
||||
victoires: comb.totalWin,
|
||||
matchs: comb.matchs.filter(m => m.end).length
|
||||
})}
|
||||
</li>
|
||||
<li>${i18next.t('pointsMarqués2', {nb: comb.pointMake})}</li>
|
||||
<li>${i18next.t('pointsReçus2', {nb: comb.pointTake})}</li>
|
||||
<li>${i18next.t('ratioDuScore2', {nb: comb.pointRatio.toFixed(3)})}</li>
|
||||
</ul>
|
||||
|
||||
<h3>${i18next.t('listeDesMatchs')}:</h3>
|
||||
|
||||
<figure class="wp-block-table is-style-stripes" style="font-size: 16px">
|
||||
<table style="width: 700px;overflow: auto"><thead>
|
||||
<tr>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('date')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('poule')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('adversaire')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('scores')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('ratio')}</th>
|
||||
<th class="has-text-align-center" data-align="center"></th>
|
||||
</tr>
|
||||
</thead><tbody>`
|
||||
for (const match of comb.matchs) {
|
||||
arrayContent += `
|
||||
<tr>
|
||||
<td class="has-text-align-center" data-align="center">${dateToString(match.date)}</td>
|
||||
<td class="has-text-align-center" data-align="center">${match.poule}</td>
|
||||
<td class="has-text-align-center" data-align="center">${match.adv}</td>
|
||||
<td class="has-text-align-center" data-align="center">${scoreToString(match.score)}</td>
|
||||
<td class="has-text-align-center" data-align="center">${match.end ? match.ratio.toFixed(3) : ""}</td>
|
||||
<td class="has-text-align-center" data-align="center">${match.win ? cupImg : (match.eq ? cupImg2 : "")}</td>
|
||||
</tr>`
|
||||
}
|
||||
arrayContent += `</tbody></table></figure>`
|
||||
pouleDiv.innerHTML = arrayContent;
|
||||
return pouleDiv;
|
||||
}
|
||||
|
||||
function combPage(location) {
|
||||
rootDiv.innerHTML = `<h4>${i18next.t('résultatDeLaCompétition')} :</h4><a id="homeLink" href="javascript:void(0);">${i18next.t('back')}</a>`;
|
||||
document.getElementById('homeLink').addEventListener('click', () => setSubPage('home'));
|
||||
|
||||
const content = document.createElement('div');
|
||||
content.style.marginTop = '1em';
|
||||
content.innerHTML = `<h4>${i18next.t('rechercheParCombattant')}</h4>`;
|
||||
|
||||
const dataContainer = document.createElement('div');
|
||||
dataContainer.id = 'data-container';
|
||||
|
||||
const loadComb = (id) => {
|
||||
const loading = startLoading(content);
|
||||
fetch(`${apiUrlRoot}/comb/data?comb=${id}`)
|
||||
.then(response => response.json())
|
||||
.then(comb => {
|
||||
console.log(comb);
|
||||
dataContainer.replaceChildren(buildCombView(comb));
|
||||
})
|
||||
.catch(() => dataContainer.replaceChildren(new Text(i18next.t('erreurDeChargementDuCombattant'))))
|
||||
.finally(() => stopLoading(loading));
|
||||
}
|
||||
|
||||
const loading = startLoading(content);
|
||||
fetch(`${apiUrlRoot}/comb/list`)
|
||||
.then(response => response.json())
|
||||
.then(combs => {
|
||||
const select = document.createElement('select');
|
||||
select.innerHTML = `<option value="0">${i18next.t('--sélectionnerUnCombattant--')}</option>`;
|
||||
for (const comb of Object.keys(combs).sort()) {
|
||||
select.innerHTML += `<option value="${combs[comb]}">${comb}</option>`;
|
||||
}
|
||||
select.addEventListener('change', e => {
|
||||
location[1] = Object.keys(combs).find(key => combs[key] === e.target.value);
|
||||
location[1] = encodeURI(location[1]);
|
||||
window.location.hash = location.join('/');
|
||||
loadComb(e.target.value);
|
||||
})
|
||||
content.append(select);
|
||||
content.appendChild(dataContainer);
|
||||
|
||||
if (location.length > 1 && location[1] !== undefined && location[1] !== '') {
|
||||
const tmp = combs[decodeURI(location[1])];
|
||||
select.value = tmp;
|
||||
loadComb(tmp);
|
||||
}
|
||||
})
|
||||
.catch(() => rootDiv.append(new Text(i18next.t('erreurDeChargementDesCombattants'))))
|
||||
.finally(() => stopLoading(loading));
|
||||
|
||||
rootDiv.append(content)
|
||||
}
|
||||
|
||||
function buildClubView(club) {
|
||||
const pouleDiv = document.createElement('div');
|
||||
let arrayContent = `
|
||||
<h3>${i18next.t('info')} :</h3>
|
||||
<ul>
|
||||
<li>${i18next.t('nom')} : ${club.name}</li>
|
||||
<li>${i18next.t('nombreDinscris')} : ${club.nb_insc}</li>
|
||||
</ul>
|
||||
<h3>${i18next.t('statistique')} :</h3>
|
||||
<ul>
|
||||
<li>${i18next.t('nombreDeMatchDisputé2', {nb: club.nb_match})}</li>
|
||||
<li>${i18next.t('nombreDeVictoires2', {nb: club.match_w})}</li>
|
||||
<li>${i18next.t('ratioDeVictoiresMoyen2', {nb: club.ratioVictoire.toFixed(3)})}</li>
|
||||
<li>${i18next.t('pointsMarqués2', {nb: club.pointMake})}</li>
|
||||
<li>${i18next.t('pointsReçus2', {nb: club.pointTake})}</li>
|
||||
<li>${i18next.t('ratioDePointsMoyen2', {nb: club.ratioPoint.toFixed(3)})}</li>
|
||||
</ul>
|
||||
|
||||
<h3>${i18next.t('listeDesMenbres')} :</h3>
|
||||
|
||||
<figure class="wp-block-table is-style-stripes" style="font-size: 16px">
|
||||
<table style="width: 800px;overflow: auto"><thead>
|
||||
<tr>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('catégorie')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('nom')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('victoires')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('défaites')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('ratioVictoires')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('pointsMarqués')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('pointsReçus')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('ratioPoints')}</th>
|
||||
</tr>
|
||||
</thead><tbody>`
|
||||
for (const comb of club.combs) {
|
||||
arrayContent += `
|
||||
<tr>
|
||||
<td class="has-text-align-center" data-align="center">${comb.cat}</td>
|
||||
<td class="has-text-align-center" data-align="center">${comb.name}</td>
|
||||
<td class="has-text-align-center" data-align="center">${comb.w}</td>
|
||||
<td class="has-text-align-center" data-align="center">${comb.l}</td>
|
||||
<td class="has-text-align-center" data-align="center">${comb.ratioVictoire.toFixed(3)}</td>
|
||||
<td class="has-text-align-center" data-align="center">${comb.pointMake}</td>
|
||||
<td class="has-text-align-center" data-align="center">${comb.pointTake}</td>
|
||||
<td class="has-text-align-center" data-align="center">${comb.ratioPoint.toFixed(3)}</td>
|
||||
</tr>`
|
||||
}
|
||||
arrayContent += `</tbody></table></figure>`
|
||||
pouleDiv.innerHTML = arrayContent;
|
||||
return pouleDiv;
|
||||
}
|
||||
|
||||
function clubPage(location) {
|
||||
rootDiv.innerHTML = `<h4>${i18next.t('résultatDeLaCompétition')} :</h4><a id="homeLink" href="javascript:void(0);">${i18next.t('back')}</a>`;
|
||||
document.getElementById('homeLink').addEventListener('click', () => setSubPage('home'));
|
||||
|
||||
const content = document.createElement('div');
|
||||
content.style.marginTop = '1em';
|
||||
content.innerHTML = `<h4>${i18next.t('rechercheParClub')}</h4>`;
|
||||
|
||||
const dataContainer = document.createElement('div');
|
||||
dataContainer.id = 'data-container';
|
||||
|
||||
const loadComb = (id) => {
|
||||
const loading = startLoading(content);
|
||||
fetch(`${apiUrlRoot}/club/data?club=${id}`)
|
||||
.then(response => response.json())
|
||||
.then(club => {
|
||||
console.log(club);
|
||||
dataContainer.replaceChildren(buildClubView(club));
|
||||
})
|
||||
.catch(() => dataContainer.replaceChildren(new Text(i18next.t('erreurDeChargementDuClub'))))
|
||||
.finally(() => stopLoading(loading));
|
||||
}
|
||||
|
||||
const loading = startLoading(content);
|
||||
fetch(`${apiUrlRoot}/club/list`)
|
||||
.then(response => response.json())
|
||||
.then(clubs => {
|
||||
const select = document.createElement('select');
|
||||
select.innerHTML = `<option value="0">${i18next.t('--sélectionnerUnClub--')}</option>`;
|
||||
for (const club of Object.keys(clubs).sort()) {
|
||||
select.innerHTML += `<option value="${clubs[club]}">${club}</option>`;
|
||||
}
|
||||
select.addEventListener('change', e => {
|
||||
if (e.target.value === '0')
|
||||
return;
|
||||
location[1] = Object.keys(clubs).find(key => clubs[key] === Number(e.target.value));
|
||||
location[1] = encodeURI(location[1]);
|
||||
window.location.hash = location.join('/');
|
||||
loadComb(e.target.value);
|
||||
})
|
||||
content.append(select);
|
||||
content.appendChild(dataContainer);
|
||||
|
||||
if (location.length > 1 && location[1] !== undefined && location[1] !== '') {
|
||||
const tmp = clubs[decodeURI(location[1])];
|
||||
select.value = tmp;
|
||||
loadComb(tmp);
|
||||
}
|
||||
})
|
||||
.catch(() => rootDiv.append(new Text(i18next.t('erreurDeChargementDesClubs'))))
|
||||
.finally(() => stopLoading(loading));
|
||||
|
||||
rootDiv.append(content)
|
||||
}
|
||||
|
||||
function buildCombsView(combs) {
|
||||
const pouleDiv = document.createElement('div');
|
||||
let arrayContent = `
|
||||
<h3>${i18next.t('statistique')} :</h3>
|
||||
<ul>
|
||||
<li>${i18next.t('nombreDinscris2', {nb: combs.nb_insc})}</li>
|
||||
<li>${i18next.t('nombreDeMatchDisputé2', {nb: combs.tt_match})}</li>
|
||||
<li>${i18next.t('pointsMarqués2', {nb: combs.point})}</li>
|
||||
</ul>
|
||||
|
||||
<h3>${i18next.t('listeDesCombattants')} :</h3>
|
||||
|
||||
<figure class="wp-block-table is-style-stripes" style="font-size: 16px">
|
||||
<table style="width: 1200px;overflow: auto"><thead>
|
||||
<tr>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('catégorie')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('club')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('nom')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('victoires')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('défaites')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('ratioVictoires')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('pointsMarqués')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('pointsReçus')}</th>
|
||||
<th class="has-text-align-center" data-align="center">${i18next.t('ratiosPoints')}</th>
|
||||
</tr>
|
||||
</thead><tbody>`
|
||||
for (const comb of combs.combs) {
|
||||
arrayContent += `
|
||||
<tr>
|
||||
<td class="has-text-align-center" data-align="center">${comb.cat}</td>
|
||||
<td class="has-text-align-center" data-align="center">${comb.club}</td>
|
||||
<td class="has-text-align-center" data-align="center">${comb.name}</td>
|
||||
<td class="has-text-align-center" data-align="center">${comb.w}</td>
|
||||
<td class="has-text-align-center" data-align="center">${comb.l}</td>
|
||||
<td class="has-text-align-center" data-align="center">${comb.ratioVictoire.toFixed(3)}</td>
|
||||
<td class="has-text-align-center" data-align="center">${comb.pointMake}</td>
|
||||
<td class="has-text-align-center" data-align="center">${comb.pointTake}</td>
|
||||
<td class="has-text-align-center" data-align="center">${comb.ratioPoint.toFixed(3)}</td>
|
||||
</tr>`
|
||||
}
|
||||
arrayContent += `</tbody></table></figure>`
|
||||
pouleDiv.innerHTML = arrayContent;
|
||||
return pouleDiv;
|
||||
}
|
||||
|
||||
function combsPage() {
|
||||
rootDiv.innerHTML = `<h4>${i18next.t('résultatDeLaCompétition')} :</h4><a id="homeLink" href="javascript:void(0);">${i18next.t('back')}</a>`;
|
||||
document.getElementById('homeLink').addEventListener('click', () => setSubPage('home'));
|
||||
|
||||
const content = document.createElement('div');
|
||||
content.style.marginTop = '1em';
|
||||
|
||||
const dataContainer = document.createElement('div');
|
||||
dataContainer.id = 'data-container';
|
||||
|
||||
const loading = startLoading(content);
|
||||
fetch(`${apiUrlRoot}/comb/get_all`)
|
||||
.then(response => response.json())
|
||||
.then(combs => {
|
||||
console.log(combs);
|
||||
dataContainer.replaceChildren(buildCombsView(combs));
|
||||
})
|
||||
.catch(() => dataContainer.replaceChildren(new Text(i18next.t('erreurDeChargementDeLaListe'))))
|
||||
.finally(() => stopLoading(loading));
|
||||
|
||||
content.append(dataContainer);
|
||||
rootDiv.append(content)
|
||||
}
|
||||
|
||||
export async function initCompetitionApi(apiUrlRoot_, host) {
|
||||
apiUrlRoot = apiUrlRoot_;
|
||||
|
||||
const options = {
|
||||
order: ['querystring', 'cookie', 'localStorage', 'sessionStorage', 'navigator', 'htmlTag'],
|
||||
caches: [],
|
||||
}
|
||||
|
||||
const backend = {
|
||||
loadPath: `${host}/locales/{{lng}}/{{ns}}.json`,
|
||||
}
|
||||
|
||||
await i18next
|
||||
.use(i18nextHttpBackend)
|
||||
.use(i18nextBrowserLanguagedetector)
|
||||
.init({
|
||||
supportedLngs: ['fr', 'en'],
|
||||
fallbackLng: 'fr',
|
||||
debug: host.startsWith('http://localhost'),
|
||||
interpolation: {
|
||||
escapeValue: true,
|
||||
},
|
||||
detection: options,
|
||||
backend: backend,
|
||||
ns: ['result'],
|
||||
defaultNS: 'result',
|
||||
})
|
||||
|
||||
console.log("apiUrlRoot:", apiUrlRoot)
|
||||
console.log("FFSAF Competition API initialized.")
|
||||
|
||||
let hash = window.location.hash.substring(1);
|
||||
if (hash.length === 0)
|
||||
setSubPage('home');
|
||||
else
|
||||
setSubPage(hash);
|
||||
}
|
||||
|
||||
class TreeNode {
|
||||
constructor(data) {
|
||||
this.data = data;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
|
||||
death() {
|
||||
let dg = 0;
|
||||
let dd = 0;
|
||||
|
||||
if (this.right != null)
|
||||
dg = this.right.death();
|
||||
|
||||
if (this.left != null)
|
||||
dg = this.left.death();
|
||||
|
||||
return 1 + Math.max(dg, dd);
|
||||
}
|
||||
}
|
||||
|
||||
function initTree(data_in) {
|
||||
let out = [];
|
||||
for (const din of data_in) {
|
||||
out.push(parseTree(din));
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
function parseTree(data_in) {
|
||||
if (data_in?.data == null)
|
||||
return null;
|
||||
|
||||
let node = new TreeNode(data_in.data);
|
||||
node.left = parseTree(data_in?.left);
|
||||
node.right = parseTree(data_in?.right);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
const max_x = 500;
|
||||
const size = 24;
|
||||
|
||||
function getBounds(root) {
|
||||
let px = max_x;
|
||||
let py;
|
||||
let maxx, minx, miny, maxy
|
||||
|
||||
function drawNode(tree, px, py) {
|
||||
let death = tree.death() - 1
|
||||
|
||||
if (death === 0) {
|
||||
if (miny > py - size - ((size * 1.5 / 2) | 0)) miny = py - size - (size * 1.5 / 2) | 0;
|
||||
if (maxy < py + size + ((size * 1.5 / 2) | 0)) maxy = py + size + (size * 1.5 / 2) | 0;
|
||||
} else {
|
||||
if (miny > py - size * 2 * death - ((size * 1.5 / 2) | 0))
|
||||
miny = py - size * 2 * death - ((size * 1.5 / 2) | 0);
|
||||
if (maxy < py + size * 2 * death + ((size * 1.5 / 2) | 0))
|
||||
maxy = py + size * 2 * death + ((size * 1.5 / 2) | 0);
|
||||
}
|
||||
if (minx > px - size * 2 - size * 8) minx = px - size * 2 - size * 8;
|
||||
|
||||
if (tree.left != null) drawNode(tree.left, px - size * 2 - size * 8, py - size * 2 * death);
|
||||
if (tree.right != null) drawNode(tree.right, px - size * 2 - size * 8, py + size * 2 * death);
|
||||
}
|
||||
|
||||
if (root != null) {
|
||||
py = (size * 2 * root.at(0).death() + (((size * 1.5 / 2) | 0) + size) * root.at(0).death()) * 2;
|
||||
|
||||
maxx = px;
|
||||
minx = px;
|
||||
miny = py - (size * 1.5 / 2) | 0;
|
||||
maxy = py + (size * 1.5 / 2) | 0;
|
||||
|
||||
for (const node of root) {
|
||||
px = px - size * 2 - size * 8;
|
||||
if (minx > px) minx = px;
|
||||
|
||||
drawNode(node, px, py);
|
||||
//graphics2D.drawRect(minx, miny, maxx - minx, maxy - miny);
|
||||
py = maxy + ((size * 2 * node.death() + ((size * 1.5 / 2) | 0)));
|
||||
px = maxx;
|
||||
}
|
||||
} else {
|
||||
minx = 0;
|
||||
maxx = 0;
|
||||
miny = 0;
|
||||
maxy = 0;
|
||||
}
|
||||
|
||||
return [minx, maxx, miny, maxy];
|
||||
}
|
||||
|
||||
function drawGraph(root = []) {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.id = "myCanvas";
|
||||
canvas.style.border = "1px solid grey";
|
||||
canvas.style.marginTop = "10px";
|
||||
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
const [minx, maxx, miny, maxy] = getBounds(root);
|
||||
canvas.width = maxx - minx;
|
||||
canvas.height = maxy - miny;
|
||||
ctx.translate(-minx, -miny);
|
||||
|
||||
|
||||
ctx.fillStyle = "#000000"
|
||||
ctx.lineWidth = 2
|
||||
ctx.strokeStyle = "#000000"
|
||||
|
||||
function printText(s, x, y, width, height, lineG, lineD) {
|
||||
ctx.save();
|
||||
ctx.translate(x, y);
|
||||
|
||||
let tSize = 17;
|
||||
let ratioX = height * 1. / 20.;
|
||||
|
||||
ctx.font = "100 " + tSize + "px Arial";
|
||||
|
||||
let mw = width - (ratioX * 2) | 0;
|
||||
if (ctx.measureText(s).width > mw) {
|
||||
let dTextSize = true;
|
||||
do {
|
||||
tSize--;
|
||||
ctx.font = tSize + "px Arial";
|
||||
} while (ctx.measureText(s).width > mw && tSize > 10)
|
||||
|
||||
if (!dTextSize || ctx.measureText(s).width > mw) {
|
||||
let s = "";
|
||||
for (const string2 in s.split(" ")) {
|
||||
if (ctx.measureText(s + string2).width >= mw) {
|
||||
s += "...";
|
||||
break;
|
||||
} else {
|
||||
s += string2 + " "
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const text = ctx.measureText(s)
|
||||
let dx = (width - text.width) / 2;
|
||||
let dy = ((height - text.actualBoundingBoxDescent) / 2) + (text.actualBoundingBoxAscent / 2);
|
||||
|
||||
ctx.fillText(s, dx, dy, width - dy);
|
||||
ctx.restore();
|
||||
|
||||
ctx.beginPath();
|
||||
if (lineD) {
|
||||
ctx.moveTo((ratioX * 2.5 + x + dx + text.width) | 0, y + height / 2);
|
||||
ctx.lineTo(x + width, y + height / 2)
|
||||
}
|
||||
if (lineG) {
|
||||
ctx.moveTo(x, y + height / 2);
|
||||
ctx.lineTo((dx + x - ratioX * 2.5) | 0, y + height / 2)
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
function printScores(scores, px, py, scale) {
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(px - size * 2, py - size * scale);
|
||||
ctx.font = "100 " + 14 + "px Arial";
|
||||
ctx.textBaseline = 'top';
|
||||
|
||||
for (let i = 0; i < scores.length; i++) {
|
||||
const score = scores[i].s1 + "-" + scores[i].s2;
|
||||
const div = (scores.length <= 2) ? 2 : (scores.length >= 4) ? 4 : 3;
|
||||
const text = ctx.measureText(score);
|
||||
let dx = (size * 2 - text.width) / 2;
|
||||
let dy = ((size * 2 / div - text.actualBoundingBoxDescent) / 2) + (text.actualBoundingBoxAscent / 2);
|
||||
|
||||
ctx.fillStyle = '#ffffffdd';
|
||||
ctx.fillRect(dx, size * 2 * scale / div * (i) + dy, text.width, 14);
|
||||
ctx.fillStyle = "#000000";
|
||||
ctx.fillText(score, dx, size * 2 * scale / div * (i) + dy, size * 2);
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
function drawNode(tree, px, py) {
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(px, py)
|
||||
ctx.lineTo(px - size, py)
|
||||
ctx.stroke();
|
||||
|
||||
let death = tree.death() - 1
|
||||
let match = tree.data
|
||||
|
||||
if (death === 0) {
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(px - size, py + size)
|
||||
ctx.lineTo(px - size, py - size)
|
||||
|
||||
ctx.moveTo(px - size, py + size)
|
||||
ctx.lineTo(px - size * 2, py + size)
|
||||
ctx.moveTo(px - size, py - size)
|
||||
ctx.lineTo(px - size * 2, py - size)
|
||||
ctx.stroke();
|
||||
|
||||
printScores(match.scores, px, py, 1);
|
||||
|
||||
ctx.fillStyle = "#FF0000";
|
||||
printText((match.c1FullName == null) ? "" : match.c1FullName, px - size * 2 - size * 8, py - size - (size * 1.5 / 2) | 0,
|
||||
size * 8, (size * 1.5) | 0, false, true)
|
||||
|
||||
ctx.fillStyle = "#0000FF";
|
||||
printText((match.c2FullName == null) ? "" : match.c2FullName, px - size * 2 - size * 8, py + size - (size * 1.5 / 2) | 0,
|
||||
size * 8, (size * 1.5) | 0, false, true)
|
||||
|
||||
if (max_y < py + size + ((size * 1.5 / 2) | 0)) max_y = py + size + (size * 1.5 / 2) | 0;
|
||||
} else {
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(px - size, py)
|
||||
ctx.lineTo(px - size, py + size * 2 * death)
|
||||
ctx.moveTo(px - size, py)
|
||||
ctx.lineTo(px - size, py - size * 2 * death)
|
||||
|
||||
ctx.moveTo(px - size, py + size * 2 * death)
|
||||
ctx.lineTo(px - size * 2, py + size * 2 * death)
|
||||
ctx.moveTo(px - size, py - size * 2 * death)
|
||||
ctx.lineTo(px - size * 2, py - size * 2 * death)
|
||||
ctx.stroke();
|
||||
|
||||
printScores(match.scores, px, py, 1.5);
|
||||
|
||||
ctx.fillStyle = "#FF0000";
|
||||
printText((match.c1FullName == null) ? "" : match.c1FullName, px - size * 2 - size * 8, py - size * 2 * death - (size * 1.5 / 2) | 0,
|
||||
size * 8, (size * 1.5) | 0, true, true)
|
||||
|
||||
ctx.fillStyle = "#0000FF";
|
||||
printText((match.c2FullName == null) ? "" : match.c2FullName, px - size * 2 - size * 8, py + size * 2 * death - (size * 1.5 / 2) | 0,
|
||||
size * 8, (size * 1.5) | 0, true, true)
|
||||
|
||||
if (max_y < py + size * 2 * death + ((size * 1.5 / 2) | 0))
|
||||
max_y = py + size * 2 * death + ((size * 1.5 / 2) | 0);
|
||||
}
|
||||
|
||||
ctx.stroke();
|
||||
|
||||
if (tree.left != null) drawNode(tree.left, px - size * 2 - size * 8, py - size * 2 * death);
|
||||
if (tree.right != null) drawNode(tree.right, px - size * 2 - size * 8, py + size * 2 * death);
|
||||
}
|
||||
|
||||
function win(scores) {
|
||||
let sum = 0;
|
||||
for (const score of scores) {
|
||||
if (score.s1 === -1000 || score.s2 === -1000)
|
||||
continue;
|
||||
|
||||
if (score.s1 > score.s2)
|
||||
sum++;
|
||||
else if (score.s1 < score.s2)
|
||||
sum--;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
let px = max_x;
|
||||
let py;
|
||||
let max_y
|
||||
|
||||
if (root != null) {
|
||||
py = (size * 2 * root.at(0).death() + (((size * 1.5 / 2) | 0) + size) * root.at(0).death()) * 2;
|
||||
|
||||
max_y = py + (size * 1.5 / 2) | 0;
|
||||
|
||||
for (const node of root) {
|
||||
let win_name = "";
|
||||
if (node.data.end) {
|
||||
if (win(node.data.scores) > 0)
|
||||
win_name = (node.data.c1FullName === null) ? "???" : node.data.c1FullName;
|
||||
else
|
||||
win_name = (node.data.c2FullName === null) ? "???" : node.data.c2FullName;
|
||||
}
|
||||
|
||||
|
||||
ctx.fillStyle = "#18A918";
|
||||
printText(win_name, px - size * 2 - size * 8, py - ((size * 1.5 / 2) | 0),
|
||||
size * 8, (size * 1.5) | 0, true, false);
|
||||
|
||||
px = px - size * 2 - size * 8;
|
||||
|
||||
drawNode(node, px, py);
|
||||
|
||||
py = max_y + ((size * 2 * node.death() + ((size * 1.5 / 2) | 0)));
|
||||
px = max_x;
|
||||
}
|
||||
}
|
||||
|
||||
return canvas;
|
||||
}
|
||||
BIN
src/main/webapp/public/img/171892.png
Normal file
BIN
src/main/webapp/public/img/171892.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
150
src/main/webapp/public/locales/en/cm.json
Normal file
150
src/main/webapp/public/locales/en/cm.json
Normal file
@@ -0,0 +1,150 @@
|
||||
{
|
||||
"--SélectionnerUnCombattant--": "-- Select a fighter --",
|
||||
"--Tous--": "-- All --",
|
||||
"PourLéquipe": "for the team",
|
||||
"actuel": "Current",
|
||||
"administration": "Administration",
|
||||
"adresseDuServeur": "Server address",
|
||||
"ajouter": "Add",
|
||||
"ajouterDesCombattants": "Add fighters",
|
||||
"ajouterUneTeam": "Add team",
|
||||
"attention": "Warning",
|
||||
"aucuneConfigurationObs": "No OBS configuration found, please import one",
|
||||
"bleu": "Blue",
|
||||
"blue": "Blue",
|
||||
"catégorie": "Category",
|
||||
"chrono.+/-...S": "+/- ... s",
|
||||
"chrono.+10S": "+10 s",
|
||||
"chrono.+1S": "+1 s",
|
||||
"chrono.-10S": "-10 s",
|
||||
"chrono.-1S": "-1 s",
|
||||
"chrono.arrêter": "Stop",
|
||||
"chrono.définirLeTemps": "Set time",
|
||||
"chrono.démarrer": "Start",
|
||||
"chrono.editionTemps": "Time editing",
|
||||
"chrono.entrezLeTempsEnS": "Enter time in seconds",
|
||||
"chrono.recapTemps": "Time: {{temps}}, pause: {{pause}}",
|
||||
"chronomètre": "Stopwatch",
|
||||
"club": "Club",
|
||||
"compétition": "Competition",
|
||||
"compétitionManager": "Competition manager",
|
||||
"config.obs.dossierDesResources": "Resources folder",
|
||||
"config.obs.motDePasseDuServeur": "Server password",
|
||||
"config.obs.warn1": "/! The password will be stored in plain text; it is recommended to use it only on OBS WebSocket and to change it between each competition",
|
||||
"config.obs.ws": "ws://",
|
||||
"configurationObs": "OBS Configuration",
|
||||
"confirm1": "This match already has results; are you sure you want to delete it?",
|
||||
"confirm2.msg": "Do you really want to change the tournament tree size or the loser matches? This will modify existing matches (including possible deletions)!",
|
||||
"confirm2.title": "Tournament tree change",
|
||||
"confirm3.msg": "Do you really want to remove the {{typeStr}} part from the category? This will delete the matches contained in this part!",
|
||||
"confirm3.title": "Change category type",
|
||||
"confirm4.msg": "Do you really want to delete the category {{name}}. This will delete all associated matches!",
|
||||
"confirm4.title": "Delete category",
|
||||
"conserverUniquementLesMatchsTerminés": "Keep only finished matches",
|
||||
"contre": "vs",
|
||||
"créerLesMatchs": "Create matches",
|
||||
"demi-finalesEtFinales": "Semi-finals and finals",
|
||||
"duréePause": "Pause duration",
|
||||
"duréeRound": "Round duration",
|
||||
"editionDeLaCatégorie": "Edit category",
|
||||
"enregister": "Save",
|
||||
"enregistrer": "Save",
|
||||
"epéeBouclier": "Sword and shield",
|
||||
"err1": "A fighter cannot fight themselves!",
|
||||
"err2": "The combat zone name format is invalid. Please separate names with ';'.",
|
||||
"err3": "At least one type (pool or tournament) must be selected.",
|
||||
"erreurLorsDeLaCopieDansLePresse": "Error while copying to clipboard: ",
|
||||
"erreurLorsDeLaCréationDesMatchs": "Error while creating matches: ",
|
||||
"exporter": "Export",
|
||||
"fermer": "Close",
|
||||
"finalesUniquement": "Finals only",
|
||||
"genre": "Gender",
|
||||
"genre.f": "F",
|
||||
"genre.h": "M",
|
||||
"genre.na": "NA",
|
||||
"inscrit": "Registered",
|
||||
"manche": "Round",
|
||||
"matchPourLesPerdantsDuTournoi": "Match for tournament losers:",
|
||||
"matches": "Matches",
|
||||
"modifier": "Edit",
|
||||
"msg1": "There are already matches in this pool; what do you want to do with them?",
|
||||
"neRienConserver": "Keep nothing",
|
||||
"no": "No.",
|
||||
"nom": "Name",
|
||||
"nomDeLéquipe": "team name",
|
||||
"nomDesZonesDeCombat": "Combat zone names <1>(separated by ';')</1>",
|
||||
"nouvelle...": "New...",
|
||||
"obs.préfixDesSources": "Source prefix",
|
||||
"pays": "Country",
|
||||
"poids": "Weight",
|
||||
"poule": "Pool",
|
||||
"poulePour": "Pool for: ",
|
||||
"préparation...": "Preparing...",
|
||||
"rouge": "Red",
|
||||
"réinitialiser": "Reset",
|
||||
"résultat": "Result",
|
||||
"sansPoule": "No pool",
|
||||
"sauvegarde": "Backup",
|
||||
"sauvegarder": "Save",
|
||||
"score": "Score",
|
||||
"score.err1": "Cannot end a tournament match in a draw.",
|
||||
"score.spe": "Special scores: <br/>-997: disqualified <br/>-998: absent <br/>-999: forfeit",
|
||||
"scores": "Scores",
|
||||
"secrétariatsDeLice": "Ring secretariats",
|
||||
"select.aucunCombattantDisponible": "No fighters available",
|
||||
"select.aucunCombattantSélectionné": "No fighters selected",
|
||||
"select.msg1": "(0 = disabled)",
|
||||
"select.recherche": "Search",
|
||||
"select.sélectionnerDesCombatants": "Select fighters",
|
||||
"select.à": "to",
|
||||
"serveur": "Server",
|
||||
"suivant": "Next",
|
||||
"supprimer": "Delete",
|
||||
"sélectionneLesModesDaffichage": "Select display modes",
|
||||
"sélectionner": "Select",
|
||||
"team": "Team",
|
||||
"terminé": "Finished",
|
||||
"texteCopiéDansLePresse": "Text copied to clipboard! Paste it into an HTML tag on your WordPress.",
|
||||
"toast.createCategory.error": "Error while creating the category",
|
||||
"toast.createCategory.pending": "Creating category...",
|
||||
"toast.createCategory.success": "Category created!",
|
||||
"toast.deleteCategory.error": "Error while deleting the category",
|
||||
"toast.deleteCategory.pending": "Deleting category...",
|
||||
"toast.deleteCategory.success": "Category deleted!",
|
||||
"toast.matchs.create.error": "Error while creating matches.",
|
||||
"toast.matchs.create.pending": "Creating matches in progress...",
|
||||
"toast.matchs.create.success": "Matches created successfully.",
|
||||
"toast.team.update.error": "Error while updating team",
|
||||
"toast.team.update.pending": "Updating team...",
|
||||
"toast.team.update.success": "Team updated!",
|
||||
"toast.updateCategory.error": "Error while updating the category",
|
||||
"toast.updateCategory.pending": "Updating category...",
|
||||
"toast.updateCategory.success": "Category updated!",
|
||||
"toast.updateMatchScore.error": "Error while updating match score",
|
||||
"toast.updateMatchScore.pending": "Updating match score...",
|
||||
"toast.updateMatchScore.success": "Match score updated!",
|
||||
"toast.updateTrees.error": "Error while updating trees",
|
||||
"toast.updateTrees.init.error": "Error while creating trees",
|
||||
"toast.updateTrees.init.pending": "Creating tournament trees...",
|
||||
"toast.updateTrees.init.success": "Trees created!",
|
||||
"toast.updateTrees.pending": "Updating tournament trees...",
|
||||
"toast.updateTrees.success": "Trees updated!",
|
||||
"tournoi": "Tournament",
|
||||
"tournois": "Tournaments",
|
||||
"tousLesMatchs": "All matches",
|
||||
"toutConserver": "Keep all",
|
||||
"ttm.admin.obs": "Short click: Download resources. Long click: Create OBS configuration",
|
||||
"ttm.admin.scripte": "Copy integration script",
|
||||
"ttm.table.inverserLaPosition": "Reverse fighter positions on this screen",
|
||||
"ttm.table.obs": "Short click: Load configuration and connect. Long click: Ring configuration",
|
||||
"ttm.table.pub_aff": "Open public display",
|
||||
"ttm.table.pub_score": "Show scores on public display",
|
||||
"type": "Type",
|
||||
"téléchargement": "Download",
|
||||
"téléchargementEnCours": "Downloading...",
|
||||
"téléchargementTerminé!": "Download completed!",
|
||||
"uneCatégorie": "a category",
|
||||
"valider": "Validate",
|
||||
"zone": "Zone",
|
||||
"zoneDeCombat": "Combat zone"
|
||||
}
|
||||
585
src/main/webapp/public/locales/en/common.json
Normal file
585
src/main/webapp/public/locales/en/common.json
Normal file
@@ -0,0 +1,585 @@
|
||||
{
|
||||
"(optionnelle)": "(optional)",
|
||||
"---SansClub---": "--- no club ---",
|
||||
"---TousLesAges---": "--- all ages ---",
|
||||
"---ToutLesClubs---": "--- all clubs ---",
|
||||
"---ToutLesPays---": "--- all countries ---",
|
||||
"---TouteLesCatégories---": "--- all categories ---",
|
||||
"--NonLicencier--": "-- Not licensed --",
|
||||
"--SélectionnerCatégorie--": "-- Select category --",
|
||||
"1Catégorie": "+1 category",
|
||||
"2Catégorie": "+2 categories",
|
||||
"LesModificationsNontEnregistrer": "/!\\ The changes have not yet been saved, click save /!\\",
|
||||
"activer": "Activate",
|
||||
"admin": "Administration",
|
||||
"administrateur": "Administrator",
|
||||
"adresse": "Address",
|
||||
"adresseAdministrative": "Administrative address",
|
||||
"aff.ancienNom": "Former name: {{name}}",
|
||||
"aff.byMembreSim": "By similar member",
|
||||
"aff.byNewMenbre": "By new member",
|
||||
"aff.byNoLicence": "By license number",
|
||||
"aff.info1": "This club has already been affiliated (affiliation no. {{no}})",
|
||||
"aff.membreNo": "Member no. {{no}}",
|
||||
"aff.nomDuClub": "Club name",
|
||||
"aff.raisonDuRefus": "Reason for refusal",
|
||||
"aff.raisonDuRefus.msg": "Please indicate the reason for refusal",
|
||||
"aff.refusConfirm": "Are you sure you want to refuse this request?",
|
||||
"aff.refuserLaDemande": "Refuse the request",
|
||||
"aff.refuserLaDemande.detail": "Are you sure you want to refuse this request?",
|
||||
"aff.submit.error1": "Please enter a valid license number for member {{id}}",
|
||||
"aff.submit.error2": "Please enter a valid license number for member {{id}}",
|
||||
"aff.submit.error3": "Please enter a valid email for member {{id}}",
|
||||
"aff.toast.accept.error": "Failed to accept affiliation",
|
||||
"aff.toast.accept.pending": "Accepting affiliation in progress",
|
||||
"aff.toast.accept.success": "Affiliation accepted successfully 🎉",
|
||||
"aff.toast.del.error": "Failed to delete affiliation request",
|
||||
"aff.toast.del.pending": "Deleting affiliation request in progress",
|
||||
"aff.toast.del.success": "Affiliation request deleted successfully 🎉",
|
||||
"aff.toast.del2.error": "Failed to delete affiliation",
|
||||
"aff.toast.del2.pending": "Deleting affiliation in progress",
|
||||
"aff.toast.del2.success": "Affiliation deleted successfully 🎉",
|
||||
"aff.toast.save.error": "Failed to save affiliation request",
|
||||
"aff.toast.save.pending": "Saving affiliation request in progress",
|
||||
"aff.toast.save.success": "Affiliation request saved successfully 🎉",
|
||||
"aff.toast.save2.error": "Failed to save affiliation",
|
||||
"aff.toast.save2.pending": "Saving affiliation in progress",
|
||||
"aff.toast.save2.success": "Affiliation saved successfully 🎉",
|
||||
"aff_req.appuyerSurRechercher": "Press search to complete",
|
||||
"aff_req.association": "The association",
|
||||
"aff_req.button.cancel": "Cancel my request",
|
||||
"aff_req.button.confirm": "Confirm my affiliation request",
|
||||
"aff_req.button.save": "Save changes",
|
||||
"aff_req.denomination": "Denomination",
|
||||
"aff_req.disposeLicence": "Already has a license",
|
||||
"aff_req.error1": "The role of member {{i}} is required",
|
||||
"aff_req.error2": "The SIRET/RNA format is invalid",
|
||||
"aff_req.nomDeLassociation": "Association name",
|
||||
"aff_req.text1": "Affiliation is annual and valid for one sports season: from September 1st to August 31st of the following year.",
|
||||
"aff_req.text2": "To affiliate, a sports association must meet the following conditions:",
|
||||
"aff_req.text2.li": [
|
||||
"Have its headquarters in France or the Principality of Monaco",
|
||||
"Be constituted in accordance with Chapter 1 of Title II of Book 1 of the Sports Code",
|
||||
"Pursue a purpose that falls within the definition of Article 1 of the Federation's statutes",
|
||||
"Have statutes compatible with the principles of organization and operation of the Federation",
|
||||
"Ensure freedom of opinion and respect for the rights of defense within it, and prohibit any discrimination",
|
||||
"Comply with the rules of supervision, hygiene, and safety established by the Federation's regulations"
|
||||
],
|
||||
"aff_req.text3": "After validation of your request, you will receive a temporary identifier and password to access your FFSAF space",
|
||||
"aff_req.text4": "Note that to finalize your affiliation, you will need to:",
|
||||
"aff_req.text4.li1": "Have at least three licensed members, including the president",
|
||||
"aff_req.text4.li2": "Have paid the fees provided for by the federal regulations",
|
||||
"aff_req.text5": "You can later add publicly visible addresses for your training locations",
|
||||
"aff_req.text6": "Leave blank to make no changes. (If a coat of arms has already been sent with this request, it will be used; otherwise, we will use the one from the previous affiliation)",
|
||||
"aff_req.text7": "Affiliation request sent successfully",
|
||||
"aff_req.text8": "Once your request is validated, you will receive a temporary identifier and password to access your FFSAF space",
|
||||
"aff_req.toast.undo.error": "Failed to cancel affiliation request",
|
||||
"aff_req.toast.undo.pending": "Cancelling affiliation request in progress",
|
||||
"aff_req.toast.undo.success": "Affiliation request cancelled successfully 🎉",
|
||||
"afficherLesCombattantsNonPesés": "Show unweighed fighters",
|
||||
"afficherLétatDesAffiliation": "Display affiliation status",
|
||||
"affiliation": "Affiliation",
|
||||
"affiliationNo": "Affiliation no. {{no}}",
|
||||
"ajout": "Addition",
|
||||
"ajouterUnClub": "Add a club",
|
||||
"ajouterUnMembre": "Add a member",
|
||||
"all_season": "--- all seasons ---",
|
||||
"ans": "years",
|
||||
"arme": "Weapon",
|
||||
"au": "to",
|
||||
"aucun": "None",
|
||||
"aucunMembreSélectionné": "No member selected",
|
||||
"aucuneCatégorieDisponible": "No categories available at this time.",
|
||||
"back": "« back",
|
||||
"blason": "Coat of arms",
|
||||
"bouclier": "Shield",
|
||||
"bureau": "Board",
|
||||
"button.accepter": "Accept",
|
||||
"button.ajouter": "Add",
|
||||
"button.annuler": "Cancel",
|
||||
"button.appliquer": "Apply",
|
||||
"button.confirmer": "Confirm",
|
||||
"button.créer": "Create",
|
||||
"button.enregistrer": "Save",
|
||||
"button.fermer": "Close",
|
||||
"button.modifier": "Edit",
|
||||
"button.refuser": "Refuse",
|
||||
"button.seDésinscrire": "Unsubscribe",
|
||||
"button.suivant": "Next",
|
||||
"button.supprimer": "Delete",
|
||||
"casque": "Helmet",
|
||||
"cat.benjamin": "Benjamin",
|
||||
"cat.cadet": "Cadet",
|
||||
"cat.catégorieInconnue": "Unknown category",
|
||||
"cat.junior": "Junior",
|
||||
"cat.miniPoussin": "Mini Chick",
|
||||
"cat.minime": "Minime",
|
||||
"cat.poussin": "Chick",
|
||||
"cat.senior1": "Senior 1",
|
||||
"cat.senior2": "Senior 2",
|
||||
"cat.superMini": "Super Mini",
|
||||
"cat.vétéran1": "Veteran 1",
|
||||
"cat.vétéran2": "Veteran 2",
|
||||
"categorie": "category",
|
||||
"catégorie": "Category",
|
||||
"catégorieàAjouter": "Category to add",
|
||||
"certificatMédical": "Medical certificate",
|
||||
"chargement...": "Loading...",
|
||||
"chargerLexcel": "Load Excel",
|
||||
"chargerLexcel.msg": "Please use the file above as a template; do not rename the columns or modify the license numbers.",
|
||||
"choisir...": "Choose...",
|
||||
"club.aff_renew.msg": "Please select 0 to 3 board members to fill out the pre-request. (If a non-board member will become one next year, you can enter them in the next step)",
|
||||
"club.change.status": "To modify the above information, please contact the FFSAF by email.",
|
||||
"club.contact.tt": {
|
||||
"AUTRE": "Other club contact",
|
||||
"COURRIEL": "Club email address<br>Example: contact@ffsaf.fr",
|
||||
"FACEBOOK": "Club Facebook page starting with 'https://www.facebook.com/'<br>Example: https://www.facebook.com/ffmsf",
|
||||
"INSTAGRAM": "Club Instagram account starting with 'https://www.instagram.com/'<br>Example: https://www.instagram.com/ff_msf",
|
||||
"SITE": "Club website with or without 'https://'<br>Example: ffsaf.fr<br>Or https://ffsaf.fr",
|
||||
"TELEPHONE": "Club phone number<br>Example: 06 12 13 78 55"
|
||||
},
|
||||
"club.toast.aff.error": "Failed to load affiliations",
|
||||
"club.toast.aff.pending": "Loading affiliations in progress",
|
||||
"club.toast.aff.success": "Affiliations loaded successfully 🎉",
|
||||
"club.toast.del.error": "Failed to delete club",
|
||||
"club.toast.del.pending": "Deleting club in progress",
|
||||
"club.toast.del.success": "Club deleted successfully 🎉",
|
||||
"club.toast.new.error": "Failed to create club",
|
||||
"club.toast.new.pending": "Creating club in progress",
|
||||
"club.toast.new.success": "Club created successfully 🎉",
|
||||
"club.toast.save.error": "Failed to save club",
|
||||
"club.toast.save.pending": "Saving club in progress",
|
||||
"club.toast.save.success": "Club saved successfully 🎉",
|
||||
"clubExterne": "External club",
|
||||
"club_one": "Club",
|
||||
"club_other": "Clubs",
|
||||
"club_zero": "No club",
|
||||
"combattant": "fighter",
|
||||
"comp.aff.blason": "Display the club's coat of arms on screens",
|
||||
"comp.aff.flag": "Display the fighter's country on screens",
|
||||
"comp.ajoutRapide": "Quick add",
|
||||
"comp.ajouterUnCombattant": "Add a fighter",
|
||||
"comp.ajouterUnInvité": "Add a guest",
|
||||
"comp.billetterie": "Ticketing",
|
||||
"comp.billetterieHelloasso": "HelloAsso Ticketing",
|
||||
"comp.catégorieNormalisée": "Standardized category",
|
||||
"comp.combattantNonTrouvé": "Fighter not found",
|
||||
"comp.combattantsInscrits": "Registered fighters",
|
||||
"comp.compétitionFuture": "Future competition",
|
||||
"comp.compétitionPassée": "Past competition",
|
||||
"comp.créationCompétition": "Competition creation",
|
||||
"comp.dateDinscription": "Registration date",
|
||||
"comp.editionCompétition": "Competition edition",
|
||||
"comp.error1": "The end date must be after the start date.",
|
||||
"comp.error2": "Please enter the start and end dates of registration.",
|
||||
"comp.error3": "The end date of registration must be after the start date of registration.",
|
||||
"comp.exporterLesInscription": "Export registrations",
|
||||
"comp.ha.emailDeRéceptionDesInscriptionséchoué": "Email for receiving failed registrations",
|
||||
"comp.ha.error1": "Please enter the HelloAsso ticketing URL and associated rates.",
|
||||
"comp.ha.error2": "The HelloAsso ticketing URL is invalid. Please check the URL format.",
|
||||
"comp.ha.error3": "Please enter the email for receiving failed registrations.",
|
||||
"comp.ha.tarifsHelloasso": "HelloAsso rates",
|
||||
"comp.ha.text1": "To ensure good interconnection with HelloAsso, please follow these instructions:",
|
||||
"comp.ha.text2": "<strong>Configure the notification URL:</strong> In order for us to receive a notification for each registration, it is necessary to configure the notification URL of your HelloAsso account to redirect to \"https://intra.ffsaf.fr/api/webhook/ha\". To do this, from the home page of your association on HelloAsso, go to <strong>My account</strong> > <strong>Settings</strong> > <strong>Integrations and API</strong> section Notification and copy-paste <strong>https://intra.ffsaf.fr/api/webhook/ha</strong> in the <strong>My callback URL</strong> field and save.",
|
||||
"comp.ha.text3": "<strong>Copy-paste the exact name of the rates</strong> <em>-separated by semicolons-</em> that will result in automatic registration. All these rates must imperatively require the license number as a mandatory field. To do this, during the configuration of your ticketing at step 3, click on <strong>+ Add information</strong>, enter the exact title <strong>License number</strong>, in <strong>Type of response desired</strong> enter Number, select the rates entered previously and make the information mandatory.",
|
||||
"comp.ha.text4": "<strong>Copy-paste the URL of your ticketing</strong> in the field below. It should look like this: https://www.helloasso.com/associations/__asso-name-on-helloasso__/events/__ticketing-name__",
|
||||
"comp.ha.text5": "HelloAsso ticketing URL",
|
||||
"comp.ha.text6": "If for any reason the automatic registration fails, an email will be sent to this address to inform you",
|
||||
"comp.informationsGénéralesSurLaCompétition": "General information about the competition",
|
||||
"comp.informationsSurLeModeDinscription": "Information on the registration mode",
|
||||
"comp.informationsTechniques": "Technical information",
|
||||
"comp.inscription": "Registration",
|
||||
"comp.inscriptionModeAdministrateur": "Registration - administrator mode",
|
||||
"comp.inscriptionsLibres": "Free registrations",
|
||||
"comp.inscriptionsParLesAdministrateursDeLaCompétition": "Registrations by competition administrators",
|
||||
"comp.inscriptionsParLesResponsablesDeClub": "Registrations by club managers",
|
||||
"comp.inscriptionsSurLaBilletterieHelloasso": "Registrations on the HelloAsso ticketing",
|
||||
"comp.modal.annoncé": "Announced",
|
||||
"comp.modal.information": "Information",
|
||||
"comp.modal.pesé": "Weighed",
|
||||
"comp.modal.poids": "Weight (in kg)",
|
||||
"comp.modal.recherche": "Search*",
|
||||
"comp.modal.surclassement": "Overclassification",
|
||||
"comp.modal.text1": "Guests are reserved for members not licensed by the federation. Fighters registered via this form will not be able to see their results from their profile.",
|
||||
"comp.modal.text2": "Prevent members/clubs from modifying this registration",
|
||||
"comp.modifierLesParticipants": "View/Edit participants",
|
||||
"comp.monInscription": "My registration",
|
||||
"comp.noDeLicence": "License number",
|
||||
"comp.nouvelleCompétition": "New competition",
|
||||
"comp.organisateur": "Organizer",
|
||||
"comp.quiPeutInscrire": "Who can register",
|
||||
"comp.reg.libres": "Free",
|
||||
"comp.reg.parLesAdministrateursDeLaCompétition": "By competition administrators",
|
||||
"comp.reg.parLesResponsablesDeClub": "By club managers",
|
||||
"comp.reg.surLaBilletterieHelloasso": "On the HelloAsso ticketing",
|
||||
"comp.responsablesEtBureauxDesAssociations": "Managers and boards of associations",
|
||||
"comp.sinscrire": "Register",
|
||||
"comp.supprimerLaCompétition": "Delete competition",
|
||||
"comp.supprimerLaCompétition.msg": "Are you sure you want to delete this competition and all associated results?",
|
||||
"comp.surclassement_one": "{{cat}} with 1 overclassification",
|
||||
"comp.surclassement_other": "{{cat}} with {{count}} overclassifications",
|
||||
"comp.surclassement_zero": "{{cat}}",
|
||||
"comp.text2": "Visible to the public (appears in the list of competitions)",
|
||||
"comp.text3": "If not checked, the competition will only be visible to people who can register participants.",
|
||||
"comp.tips": "Tip 1: It is possible to ban a fighter, which will prevent them from being re-registered by any means other than by an administrator of this competition. To do this, click on the small <1/> next to their name.<br/>Tip 2: It is also possible to lock the modifications of their registration from their file, which will prevent it from being modified/deleted by themselves and/or a club manager.",
|
||||
"comp.toast.del.error": "Failed to delete competition",
|
||||
"comp.toast.del.pending": "Deleting competition in progress",
|
||||
"comp.toast.del.success": "Competition deleted successfully 🎉",
|
||||
"comp.toast.params.error": "Failed to update competition parameters",
|
||||
"comp.toast.params.pending": "Updating competition parameters in progress...",
|
||||
"comp.toast.params.success": "Competition parameters updated successfully 🎉",
|
||||
"comp.toast.register.add.error": "Fighter not found",
|
||||
"comp.toast.register.add.pending": "Search in progress",
|
||||
"comp.toast.register.add.success": "Fighter found and added/updated",
|
||||
"comp.toast.register.ban.error": "Error",
|
||||
"comp.toast.register.ban.pending": "Unregistration in progress",
|
||||
"comp.toast.register.ban.success": "Fighter unregistered and banned",
|
||||
"comp.toast.register.del.error": "Error",
|
||||
"comp.toast.register.del.pending": "Unregistration in progress",
|
||||
"comp.toast.register.del.success": "Fighter unregistered",
|
||||
"comp.toast.register.self.add.error": "Error during registration",
|
||||
"comp.toast.register.self.add.pending": "Registration in progress",
|
||||
"comp.toast.register.self.add.success": "Registration completed 🎉",
|
||||
"comp.toast.register.self.del.error": "Error during unregistration",
|
||||
"comp.toast.register.self.del.pending": "Unregistration in progress",
|
||||
"comp.toast.register.self.del.success": "Unregistration completed",
|
||||
"comp.toast.save.error": "Failed to save competition",
|
||||
"comp.toast.save.pending": "Saving competition in progress",
|
||||
"comp.toast.save.success": "Competition saved successfully 🎉",
|
||||
"comp.tousLesMembresDeLaFfsaf": "All FFSAF members",
|
||||
"comp.typeDinscription": "Registration type",
|
||||
"comp.uniquementLesAdministrateursDeLaCompétition": "Only competition administrators",
|
||||
"comp.warn1": "Are you sure you want to unregister and ban this fighter from the competition?\n(You can re-register them later)",
|
||||
"comp.warn2": "Are you sure you want to unregister this fighter?\nThis will not unregister them from the HelloAsso ticketing and will not refund them.",
|
||||
"comp.warn3": "Are you sure you want to unregister this fighter?",
|
||||
"comp.warn4": "Are you sure you want to unregister yourself?",
|
||||
"comp_manage": "Competitions Manager",
|
||||
"competition_one": "Competition",
|
||||
"competition_other": "Competitions",
|
||||
"compte": "Account",
|
||||
"compétition": "Competition",
|
||||
"configuration": "Configuration",
|
||||
"configurationDeLaCatégorie": "Category configuration",
|
||||
"conserverLancienEmail": "Keep the old email",
|
||||
"contactAdministratif": "Administrative contact",
|
||||
"contactInterne": "Internal contact",
|
||||
"contact_one": "Contact",
|
||||
"contact_other": "Contacts",
|
||||
"coquilleProtectionPelvienne": "Shell / Pelvic protection",
|
||||
"date": "Date",
|
||||
"dateDeNaissance": "Date of birth",
|
||||
"days": [
|
||||
"Monday",
|
||||
"Tuesday",
|
||||
"Wednesday",
|
||||
"Thursday",
|
||||
"Friday",
|
||||
"Saturday",
|
||||
"Sunday"
|
||||
],
|
||||
"de": "of",
|
||||
"demandeDaffiliationEnCours": "Affiliation request in progress",
|
||||
"demandeDeLicence": "License request",
|
||||
"demander": "Request",
|
||||
"description": "Description",
|
||||
"dlAff": "Download affiliation certificate",
|
||||
"donnéesAdministratives": "Administrative data",
|
||||
"du": "From",
|
||||
"dun": "of a",
|
||||
"duréePause": "Pause duration",
|
||||
"duréeRound": "Round duration",
|
||||
"définirLidDuCompte": "Define account ID",
|
||||
"editionDeL'affiliation": "Editing affiliation",
|
||||
"editionDeLaDemande": "Editing request",
|
||||
"editionDeLaLicence": "Editing license",
|
||||
"editionDeLaSéléction": "Editing selection",
|
||||
"editionDeLadresse": "Editing address",
|
||||
"email": "Email",
|
||||
"en": "in",
|
||||
"enAttente": "Pending",
|
||||
"erreurDePaiement": "Payment error😕",
|
||||
"erreurDePaiement.detail": "Error message:",
|
||||
"erreurDePaiement.msg": "An error occurred while processing your payment. Please try again later.",
|
||||
"espaceAdministration": "Administration space",
|
||||
"f": "F",
|
||||
"faitPar": "Done by",
|
||||
"femme": "Female",
|
||||
"filtre": "Filter",
|
||||
"gantMainBouclier": "Shield hand glove",
|
||||
"gantMainsArmées": "Armed hand(s) glove(s)",
|
||||
"gants": "Gloves",
|
||||
"genre": "Gender",
|
||||
"gestionGroupée": "Group management",
|
||||
"gorgerin": "Gorgerin",
|
||||
"gradeDarbitrage": "Refereeing grade",
|
||||
"h": "M",
|
||||
"home": {
|
||||
"header1": "For licensed members",
|
||||
"header2": "For clubs",
|
||||
"text1": "Here you will find all your information as well as the status of your registration with the federation. You can also download your registration certificate, register for competitions, and consult your results, provided that the organizing club has entered them.<br/><br/>During your first registration, you will receive an email containing your login information; this email will be sent once your license is validated by the secretariat.",
|
||||
"text2": "This is where you can take out federal licenses for your members, where you can request or renew your affiliation, enter your schedules, training locations, and social networks, which will then be displayed on the ffsaf.fr website.<br/>You will also have the possibility to publish registration forms for your competitions and to record the results.<br/><br/>Not yet affiliated with the federation? Click <1>here</1> to make your first request.",
|
||||
"welcome_message": "Welcome to the intranet of the Fédération France Soft Armored Fighting"
|
||||
},
|
||||
"homme": "Male",
|
||||
"horairesD'entraînements": "Training schedules",
|
||||
"information": "Information",
|
||||
"invité": "guest",
|
||||
"keepEmpty": "Leave blank to make no changes.",
|
||||
"le": "the",
|
||||
"licence": "License",
|
||||
"licenceNo": "License no. {{no}}",
|
||||
"lieu": "Place",
|
||||
"lieuxDentraînements": "Training locations",
|
||||
"loading": "Loading...",
|
||||
"me": {
|
||||
"result": {
|
||||
"PRIVATE": "Private (visible only to me)",
|
||||
"PUBLIC": "Public (visible to all)",
|
||||
"REGISTERED_ONLY": "Logged-in members (visible to federation members)",
|
||||
"REGISTERED_ONLY_NO_DETAILS": "Logged-in members - hide details (visible to federation members)"
|
||||
},
|
||||
"toast.settings.error": "Failed to update settings 😕",
|
||||
"toast.settings.pending": "Updating settings in progress...",
|
||||
"toast.settings.success": "Settings updated successfully 🎉"
|
||||
},
|
||||
"me.changerMonMotDePasse": "Change my password",
|
||||
"me.formationDarbitrage": "Refereeing training",
|
||||
"me.paramètresDuCompte": "Account settings",
|
||||
"me.rôleAuSienDuClub": "Role within the club",
|
||||
"me.visibilitéDesRésultats": "Visibility of results",
|
||||
"member_one": "Member",
|
||||
"member_other": "Members",
|
||||
"membre.emailVideàLaLigne": "Empty email on line {{no}}",
|
||||
"membre.emailVérifié": "Email verified",
|
||||
"membre.filtre.inactif": "Show inactive fighters",
|
||||
"membre.filtre.licence": "Show license status",
|
||||
"membre.filtre.licences": [
|
||||
"No request or valid license",
|
||||
"With request or valid license",
|
||||
"Request in progress",
|
||||
"License validated",
|
||||
"All license statuses",
|
||||
"Complete request",
|
||||
"Incomplete request"
|
||||
],
|
||||
"membre.filtre.payement": [
|
||||
"Without payment",
|
||||
"With payment",
|
||||
"All payment statuses"
|
||||
],
|
||||
"membre.identifiant": "Identifier",
|
||||
"membre.import.err1": "Invalid medical certificate date format on line {{no}}",
|
||||
"membre.import.err2": "Invalid medical certificate date format on line {{no}}",
|
||||
"membre.import.err3": "Empty date of birth on line {{no}}",
|
||||
"membre.import.err4": "Invalid date of birth format on line {{no}}",
|
||||
"membre.import.err5": "Invalid email on line {{no}}",
|
||||
"membre.import.errTT_one": "{{count}} error in the file, operation cancelled",
|
||||
"membre.import.errTT_other": "{{count}} errors in the file, operation cancelled",
|
||||
"membre.import.warn_one": "{{count}} medical certificate not filled",
|
||||
"membre.import.warn_other": "{{count}} medical certificates not filled",
|
||||
"membre.info.emailInfo": "The email is used to create an account to log in to the site and must be unique.<br/>For minors, the parents' email can be used multiple times using the following syntax: {'email.parent+<alphanumeric characters>@example.com'}.<br/>Examples: mail.parent+1@example.com, mail.parent+titouan@example.com, mail.parent+cedrique@example.com",
|
||||
"membre.info.error1": "Please select a valid country 😕",
|
||||
"membre.info.error2": "Please select a valid club 😕",
|
||||
"membre.initaccount": "Initialize account",
|
||||
"membre.initaccount.text1": "Enter the account UUID",
|
||||
"membre.initaccount.text2": "Warning: only change a member's ID if you are sure of what you are doing...",
|
||||
"membre.noAccount": "This member does not have an account...",
|
||||
"membre.noAccount.clubMsg": "An account will be created by the federation when their first license is validated",
|
||||
"membre.nomVideàLaLigne": "Empty last name on line {{no}}",
|
||||
"membre.prénomVideàLaLigne": "Empty first name on line {{no}}",
|
||||
"membre.toast.compte.created": "Account created successfully 🎉",
|
||||
"membre.toast.compte.error": "Failed to create account",
|
||||
"membre.toast.compte.pending": "Creating account in progress",
|
||||
"membre.toast.del.error": "Failed to delete account",
|
||||
"membre.toast.del.pending": "Deleting account in progress",
|
||||
"membre.toast.del.success": "Account deleted successfully 🎉",
|
||||
"membre.toast.id.error": "Failed to define identifier",
|
||||
"membre.toast.id.pending": "Defining identifier in progress",
|
||||
"membre.toast.id.success": "Identifier defined successfully 🎉",
|
||||
"membre.toast.licence.ask.del.error": "Failed to delete license request",
|
||||
"membre.toast.licence.ask.del.pending": "Deleting license request in progress",
|
||||
"membre.toast.licence.ask.del.success": "License request deleted successfully 🎉",
|
||||
"membre.toast.licence.ask.error": "Failed to request license",
|
||||
"membre.toast.licence.ask.pending": "Saving license request in progress",
|
||||
"membre.toast.licence.ask.success": "License request saved successfully 🎉",
|
||||
"membre.toast.licence.del.error": "Failed to delete license",
|
||||
"membre.toast.licence.del.pending": "Deleting license in progress",
|
||||
"membre.toast.licence.del.success": "License deleted successfully 🎉",
|
||||
"membre.toast.licence.save.error": "Failed to save license",
|
||||
"membre.toast.licence.save.pending": "Saving license in progress",
|
||||
"membre.toast.licence.save.success": "License saved successfully 🎉",
|
||||
"membre.toast.licences.export.error": "Failed to export licenses",
|
||||
"membre.toast.licences.export.pending": "Exporting licenses in progress",
|
||||
"membre.toast.licences.export.success": "Licenses exported successfully 🎉",
|
||||
"membre.toast.licences.import.error": "Failed to send changes",
|
||||
"membre.toast.licences.import.pending": "Sending changes in progress",
|
||||
"membre.toast.licences.import.success": "Changes sent successfully 🎉",
|
||||
"membre.toast.licences.load.error": "Failed to load licenses",
|
||||
"membre.toast.licences.load.pending": "Loading licenses in progress",
|
||||
"membre.toast.licences.load.success": "Licenses loaded successfully 🎉",
|
||||
"membre.toast.perm.error": "Failed to update permissions 😕",
|
||||
"membre.toast.perm.pending": "Updating permissions in progress...",
|
||||
"membre.toast.perm.success": "Permissions updated successfully 🎉",
|
||||
"membre.toast.save.error": "Failed to update profile 😕",
|
||||
"membre.toast.save.pending": "Updating profile in progress...",
|
||||
"membre.toast.save.success": "Profile updated successfully 🎉",
|
||||
"membre.toast.select.del.error": "Failed to delete selection",
|
||||
"membre.toast.select.del.pending": "Deleting selection in progress",
|
||||
"membre.toast.select.del.success": "Selection deleted successfully 🎉",
|
||||
"membre.toast.select.save.error": "Failed to save selection",
|
||||
"membre.toast.select.save.pending": "Saving selection in progress",
|
||||
"membre.toast.select.save.success": "Selection saved successfully 🎉",
|
||||
"mettreàJours": "Update",
|
||||
"modification": "Modification",
|
||||
"nationalité": "Nationality",
|
||||
"nav": {
|
||||
"account": "My account",
|
||||
"aff_request": "Affiliation request",
|
||||
"club": {
|
||||
"my": "My club"
|
||||
},
|
||||
"competitions": {
|
||||
"results": "My results"
|
||||
},
|
||||
"home": "Home",
|
||||
"login": "Login",
|
||||
"logout": "Logout",
|
||||
"space": "My space",
|
||||
"title": "FFSAF Intranet"
|
||||
},
|
||||
"noLicence": "License no.",
|
||||
"noSiretOuRna": "SIRET or RNA no.",
|
||||
"nom": "Last name",
|
||||
"nombreDeLicences": "Number of licenses",
|
||||
"nombreDeLicencesParCatégorie": "Number of licenses by category for {{saison}}",
|
||||
"non": "No",
|
||||
"nonDéfinie": "Not defined",
|
||||
"nonValidée": "Not validated",
|
||||
"nouveauClub": "New club",
|
||||
"nouveauMembre": "New member",
|
||||
"nouvelEmail": "New email",
|
||||
"ou": "or",
|
||||
"oui": "Yes",
|
||||
"outdated_session": {
|
||||
"login_button": "Log in again",
|
||||
"message": "Your session has expired, please log in again to continue using the application.",
|
||||
"title": "Session expired"
|
||||
},
|
||||
"pageClub": "Club page",
|
||||
"pageMembre": "Member page",
|
||||
"pageNouveauClub": "New club page",
|
||||
"page_info_full": "Line {{line}} to {{tt_line}} (page {{page}} of {{tt_page}})",
|
||||
"page_info_ligne": "{{show}} line(s) displayed out of {{total}}",
|
||||
"paiementDeLaLicence": "License payment",
|
||||
"paiementDesLicences": "License payments",
|
||||
"par": "by",
|
||||
"pasDeLicence": "No license",
|
||||
"payment.ha.info": "HelloAsso's solidarity model guarantees that 100% of your payment will be transferred to the chosen association. You can support the help they provide to associations by leaving a voluntary contribution to HelloAsso at the time of your payment.",
|
||||
"payment.info": "About HelloAsso",
|
||||
"payment.paiementSécurisé": "Secure payment",
|
||||
"payment.payerAvec": "Pay with",
|
||||
"payment.recap": "{{count}} license(s) selected<br/>Total amount to pay: {{total}} €",
|
||||
"paymentDesLicences": "License payments",
|
||||
"paymentDesLicences.msg_one": "Are you sure you want to mark the license as paid?",
|
||||
"paymentDesLicences.msg_other": "Are you sure you want to mark the {{count}} licenses as paid?",
|
||||
"paymentDesLicences.msg_zero": "$t(paymentDesLicences.msg_other)",
|
||||
"paymentOk": "🎉Your payment has been processed successfully.🎉",
|
||||
"paymentOk.msg": "Thank you for your payment. The licenses should be activated within the next hour, provided that the medical certificate is completed.",
|
||||
"pays": "Country",
|
||||
"perm.administrateurDeLaFédération": "Federation administrator",
|
||||
"perm.créerDesCompétion": "Create competitions",
|
||||
"perm.ffsafIntra": "FFSAF intra",
|
||||
"permission": "Permission",
|
||||
"peutSinscrire": "Can register?",
|
||||
"photos": "Photos",
|
||||
"plastron": "Breastplate",
|
||||
"poidsDemandéPour": "Weight required for",
|
||||
"prenom": "First name",
|
||||
"protectionDeBras": "Arm protection",
|
||||
"protectionDeBrasArmé": "Protection of armed arm(s)",
|
||||
"protectionDeBrasDeBouclier": "Shield arm protection",
|
||||
"protectionDeCoudes": "Elbow protection",
|
||||
"protectionDeGenoux": "Knee protection",
|
||||
"protectionDeJambes": "Leg protection",
|
||||
"protectionDePieds": "Foot protection",
|
||||
"protectionDorsale": "Back protector",
|
||||
"protectionObligatoire": "Mandatory protection",
|
||||
"prénomEtNom": "First and last name",
|
||||
"rechercher": "Search",
|
||||
"rechercher...": "Search...",
|
||||
"registration_one": "Registration",
|
||||
"registration_other": "Registrations",
|
||||
"renouveler": "Renew",
|
||||
"renouvellementDeLaffiliation": "Affiliation renewal",
|
||||
"result_one": "Result",
|
||||
"result_other": "Results",
|
||||
"retouràLaListeDeMembres": "Back to member list",
|
||||
"role": "Role",
|
||||
"role.membre": "Member",
|
||||
"role.membreDuBureau": "Board member",
|
||||
"role.président": "President",
|
||||
"role.secrétaire": "Secretary",
|
||||
"role.trésorier": "Treasurer",
|
||||
"role.vise-président": "Vice-President",
|
||||
"role.vise-secrétaire": "Vice-Secretary",
|
||||
"role.vise-trésorier": "Vice-Treasurer",
|
||||
"saison": "Season",
|
||||
"sans": "Without",
|
||||
"secrétariatsDeLice": "Ring secretariats",
|
||||
"selectionner...": "Select...",
|
||||
"shield.buckler": "Buckler",
|
||||
"shield.none": "$t(sans) / $t(nonDéfinie)",
|
||||
"shield.round": "Round",
|
||||
"shield.standard": "Standard",
|
||||
"shield.teardrop": "Teardrop",
|
||||
"siDisponiblePourLaCatégorieDages": "If available for the age category",
|
||||
"siretOuRna": "SIRET or RNA",
|
||||
"stats": "Statistics",
|
||||
"statue": "Statue",
|
||||
"status": "Status",
|
||||
"statuts": "Statutes",
|
||||
"supprimerLeClub": "Delete club",
|
||||
"supprimerLeClub.msg": "Are you sure you want to delete this club?",
|
||||
"supprimerLeCompte": "Delete account",
|
||||
"supprimerLeCompte.msg": "Are you sure you want to delete this account?",
|
||||
"sword.none": "$t(sans) / $t(nonDéfinie)",
|
||||
"sword.oneHand": "One hand",
|
||||
"sword.saber": "Saber",
|
||||
"sword.twoHand": "Two hands",
|
||||
"sélectionEnéquipeDeFrance": "Selection in the French team",
|
||||
"sélectionner...": "Select...",
|
||||
"toast.edit.error": "Failed to save changes",
|
||||
"toast.edit.pending": "Saving changes in progress",
|
||||
"toast.edit.success": "Changes saved successfully 🎉",
|
||||
"toast.licence.bulk.pay.error": "Failed to mark licenses as paid",
|
||||
"toast.licence.bulk.pay.pending": "Marking licenses as paid in progress",
|
||||
"toast.licence.bulk.pay.success": "Licenses marked as paid successfully 🎉",
|
||||
"toast.licence.bulk.valid.error": "Failed to validate licenses",
|
||||
"toast.licence.bulk.valid.pending": "Validating licenses in progress",
|
||||
"toast.licence.bulk.valid.success": "Licenses validated successfully 🎉",
|
||||
"toast.licence.order.error": "Failed to create order",
|
||||
"toast.licence.order.pending": "Creating order in progress",
|
||||
"toast.licence.order.success": "Order created successfully 🎉",
|
||||
"trie": "Sort",
|
||||
"téléchargerLexcelDesMembres": "Download members' Excel",
|
||||
"téléchargerLexcelDesMembres.info": "To be used as a template to update information",
|
||||
"téléchargéeLaLicence": "Download license",
|
||||
"validationDeLaLicence": "License validation",
|
||||
"validationDesLicences": "License validations",
|
||||
"validerDesLicences": "Validate licenses",
|
||||
"validerLePayement_one": "Validate payment for the selected license",
|
||||
"validerLePayement_other": "Validate payment for the {{count}} selected licenses",
|
||||
"validerLePayement_zero": "$t(validerLePayement_other)",
|
||||
"validerLicence.msg_one": "Are you sure you want to validate the license?",
|
||||
"validerLicence.msg_other": "Are you sure you want to validate the {{count}} licenses?",
|
||||
"validerLicence.msg_zero": "$t(validerLicence.msg_other)",
|
||||
"validerLicence_one": "Validate the selected license",
|
||||
"validerLicence_other": "Validate the {{count}} selected licenses",
|
||||
"validerLicence_zero": "$t(validerLicence_other)",
|
||||
"validée": "Validated",
|
||||
"voir/modifierLesParticipants": "View/Edit participants",
|
||||
"voirLesStatues": "View statues",
|
||||
"vousNêtesPasEncoreInscrit": "You are not yet registered or your registration has not yet been entered on the intranet",
|
||||
"à": "at",
|
||||
"étatDeLaDemande": "Request status"
|
||||
}
|
||||
68
src/main/webapp/public/locales/en/result.json
Normal file
68
src/main/webapp/public/locales/en/result.json
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"--sélectionnerUnClub--": "--Select a club--",
|
||||
"--sélectionnerUnCombattant--": "--Select a fighter--",
|
||||
"--sélectionnerUneCatégorie--": "--Select a category--",
|
||||
"abs.": "abs.",
|
||||
"adversaire": "Opponent",
|
||||
"aujourdhuià": "Today at {{time}}",
|
||||
"avanthierà": "Day before yesterday at {{time}}",
|
||||
"back": "« back",
|
||||
"bleu": "Blue",
|
||||
"catégorie": "Category",
|
||||
"chargement": "Loading",
|
||||
"club": "Club",
|
||||
"combattant": "Fighter",
|
||||
"combattants": "Fighters",
|
||||
"date": "Date",
|
||||
"disc.": "DQ",
|
||||
"défaites": "Losses",
|
||||
"erreurDeChargementDeLaListe": "Error loading the list",
|
||||
"erreurDeChargementDeLaPoule": "Error loading the pool",
|
||||
"erreurDeChargementDesCatégories": "Error loading categories",
|
||||
"erreurDeChargementDesClubs": "Error loading clubs",
|
||||
"erreurDeChargementDesCombattants": "Error loading fighters",
|
||||
"erreurDeChargementDuClub": "Error loading club",
|
||||
"erreurDeChargementDuCombattant": "Error loading fighter",
|
||||
"for.": "forf.",
|
||||
"hierà": "Yesterday at {{time}}",
|
||||
"info": "Info",
|
||||
"listeDesCombattants": "List of fighters",
|
||||
"listeDesMatchs": "List of matches",
|
||||
"listeDesMembres": "List of members",
|
||||
"listeDesMenbres": "List of members",
|
||||
"nom": "Last name",
|
||||
"nomPrénom": "Last name First name",
|
||||
"nombreDeMatchDisputé2": "Number of matches played: {{nb}}",
|
||||
"nombreDeVictoires2": "Number of wins: {{nb}}",
|
||||
"nombreDinscris": "Number of registered",
|
||||
"nombreDinscris2": "Number of registered: {{nb}}",
|
||||
"parCatégorie": "By category",
|
||||
"parClub": "By club",
|
||||
"parCombattant": "By fighter",
|
||||
"place": "Place",
|
||||
"pointsMarqués": "Points scored",
|
||||
"pointsMarqués2": "Points scored: {{nb}}",
|
||||
"pointsReçus": "Points received",
|
||||
"pointsReçus2": "Points received: {{nb}}",
|
||||
"poule": "Pool",
|
||||
"ratio": "Ratio",
|
||||
"ratioDePointsMoyen2": "Average points ratio: {{nb}}",
|
||||
"ratioDeVictoiresMoyen2": "Average win ratio: {{nb}}",
|
||||
"ratioDuScore2": "Score ratio (points scored / points received): {{nb}}",
|
||||
"ratioPoints": "Points ratio",
|
||||
"ratioVictoires": "Win ratio",
|
||||
"ratiosPoints": "Points ratios",
|
||||
"rechercheParCatégorie": "Search by category",
|
||||
"rechercheParClub": "Search by club",
|
||||
"rechercheParCombattant": "Search by fighter",
|
||||
"rouge": "Red",
|
||||
"résultatDeLaCompétition": "Competition result",
|
||||
"score": "Score",
|
||||
"scores": "Scores",
|
||||
"statistique": "Statistics",
|
||||
"tauxDeVictoire2": "Win rate: {{nb}}% ({{victoires}} out of {{matchs}})",
|
||||
"tournois": "Tournaments",
|
||||
"tousLesCombattants": "All fighters",
|
||||
"victoire": "Win",
|
||||
"victoires": "Wins"
|
||||
}
|
||||
150
src/main/webapp/public/locales/fr/cm.json
Normal file
150
src/main/webapp/public/locales/fr/cm.json
Normal file
@@ -0,0 +1,150 @@
|
||||
{
|
||||
"--SélectionnerUnCombattant--": "-- Sélectionner un combattant --",
|
||||
"--Tous--": "-- Tous --",
|
||||
"PourLéquipe": " pour l'équipe",
|
||||
"actuel": "Actuel",
|
||||
"administration": "Administration",
|
||||
"adresseDuServeur": "Adresse du serveur",
|
||||
"ajouter": "Ajouter",
|
||||
"ajouterDesCombattants": "Ajouter des combattants",
|
||||
"ajouterUneTeam": "Ajouter une équipe",
|
||||
"attention": "Attention",
|
||||
"aucuneConfigurationObs": "Aucune configuration OBS trouvée, veuillez en importer une",
|
||||
"bleu": "Bleu",
|
||||
"blue": "Blue",
|
||||
"catégorie": "Catégorie",
|
||||
"chrono.+/-...S": "+/- ... s",
|
||||
"chrono.+10S": "+10 s",
|
||||
"chrono.+1S": "+1 s",
|
||||
"chrono.-10S": "-10 s",
|
||||
"chrono.-1S": "-1 s",
|
||||
"chrono.arrêter": "Arrêter",
|
||||
"chrono.définirLeTemps": "Définir le temps",
|
||||
"chrono.démarrer": "Démarrer",
|
||||
"chrono.editionTemps": "Edition temps",
|
||||
"chrono.entrezLeTempsEnS": "Entrez le temps en s",
|
||||
"chrono.recapTemps": "Temps: {{temps}}, pause: {{pause}}",
|
||||
"chronomètre": "Chronomètre",
|
||||
"club": "Club",
|
||||
"compétition": "Compétition",
|
||||
"compétitionManager": "Compétition manager",
|
||||
"config.obs.dossierDesResources": "Dossier des resources",
|
||||
"config.obs.motDePasseDuServeur": "Mot de passe du serveur",
|
||||
"config.obs.warn1": "/! Le mot de passe va être stoker en claire, il est recommandé de ne l'utiliser que sur obs websocket et d'en changer entre chaque compétition",
|
||||
"config.obs.ws": "ws://",
|
||||
"configurationObs": "Configuration OBS",
|
||||
"confirm1": "Ce match a déjà des résultats, êtes-vous sûr de vouloir le supprimer ?",
|
||||
"confirm2.msg": "Voulez-vous vraiment changer la taille de l'arbre du tournoi ou les matchs pour les perdants ? Cela va modifier les matchs existants (incluant des possibles suppressions)!",
|
||||
"confirm2.title": "Changement de l'arbre du tournoi",
|
||||
"confirm3.msg": "Voulez-vous vraiment enlever la partie {{typeStr}} de la catégorie. Cela va supprimer les matchs contenus dans cette partie !",
|
||||
"confirm3.title": "Changement de type de catégorie",
|
||||
"confirm4.msg": "Voulez-vous vraiment supprimer la catégorie {{name}}. Cela va supprimer tous les matchs associés !",
|
||||
"confirm4.title": "Suppression de la catégorie",
|
||||
"conserverUniquementLesMatchsTerminés": "Conserver uniquement les matchs terminés",
|
||||
"contre": "contre",
|
||||
"créerLesMatchs": "Créer les matchs",
|
||||
"demi-finalesEtFinales": "Demi-finales et finales",
|
||||
"duréePause": "Durée pause",
|
||||
"duréeRound": "Durée round",
|
||||
"editionDeLaCatégorie": "Edition de la catégorie",
|
||||
"enregister": "Enregister",
|
||||
"enregistrer": "Enregistrer",
|
||||
"epéeBouclier": "Epée bouclier",
|
||||
"err1": "Un combattant ne peut pas s'affronter lui-même !",
|
||||
"err2": "Le format du nom des zones de combat est invalide. Veuillez séparer les noms par des ';'.",
|
||||
"err3": "Au moins un type (poule ou tournoi) doit être sélectionné.",
|
||||
"erreurLorsDeLaCopieDansLePresse": "Erreur lors de la copie dans le presse-papier : ",
|
||||
"erreurLorsDeLaCréationDesMatchs": "Erreur lors de la création des matchs: ",
|
||||
"exporter": "Exporter",
|
||||
"fermer": "Fermer",
|
||||
"finalesUniquement": "Finales uniquement",
|
||||
"genre": "Genre",
|
||||
"genre.f": "F",
|
||||
"genre.h": "H",
|
||||
"genre.na": "NA",
|
||||
"inscrit": "Inscrit",
|
||||
"manche": "Manche",
|
||||
"matchPourLesPerdantsDuTournoi": "Match pour les perdants du tournoi:",
|
||||
"matches": "Matches",
|
||||
"modifier": "Modifier",
|
||||
"msg1": "Il y a déjà des matchs dans cette poule, que voulez-vous faire avec ?",
|
||||
"neRienConserver": "Ne rien conserver",
|
||||
"no": "N°",
|
||||
"nom": "Nom",
|
||||
"nomDeLéquipe": "Nom de l'équipe",
|
||||
"nomDesZonesDeCombat": "Nom des zones de combat <1>(séparée par des ';')</1>",
|
||||
"nouvelle...": "Nouvelle...",
|
||||
"obs.préfixDesSources": "Préfix des sources",
|
||||
"pays": "Pays",
|
||||
"poids": "Poids",
|
||||
"poule": "Poule",
|
||||
"poulePour": "Poule pour: ",
|
||||
"préparation...": "Préparation...",
|
||||
"rouge": "Rouge",
|
||||
"réinitialiser": "Réinitialiser",
|
||||
"résultat": "Résultat",
|
||||
"sansPoule": "Sans poule",
|
||||
"sauvegarde": "Sauvegarde",
|
||||
"sauvegarder": "Sauvegarder",
|
||||
"score": "Score",
|
||||
"score.err1": "Impossible de terminer un match nul en tournois.",
|
||||
"score.spe": "Score speciaux : <br/>-997 : disqualifié <br/>-998 : absent <br/>-999 : forfait",
|
||||
"scores": "Scores",
|
||||
"secrétariatsDeLice": "Secrétariats de lice",
|
||||
"select.aucunCombattantDisponible": "Aucun combattant disponible",
|
||||
"select.aucunCombattantSélectionné": "Aucun combattant sélectionné",
|
||||
"select.msg1": "(0 = désactivé)",
|
||||
"select.recherche": "Recherche",
|
||||
"select.sélectionnerDesCombatants": "Sélectionner des combatants",
|
||||
"select.à": "à",
|
||||
"serveur": "Serveur",
|
||||
"suivant": "Suivant",
|
||||
"supprimer": "Supprimer",
|
||||
"sélectionneLesModesDaffichage": "Sélectionne les modes d'affichage",
|
||||
"sélectionner": "Sélectionner",
|
||||
"team": "Équipe",
|
||||
"terminé": "Terminé",
|
||||
"texteCopiéDansLePresse": "Texte copié dans le presse-papier ! Collez-le dans une balise HTML sur votre WordPress.",
|
||||
"toast.createCategory.error": "Erreur lors de la création de la catégorie",
|
||||
"toast.createCategory.pending": "Création de la catégorie...",
|
||||
"toast.createCategory.success": "Catégorie créée !",
|
||||
"toast.deleteCategory.error": "Erreur lors de la suppression de la catégorie",
|
||||
"toast.deleteCategory.pending": "Suppression de la catégorie...",
|
||||
"toast.deleteCategory.success": "Catégorie supprimée !",
|
||||
"toast.matchs.create.error": "Erreur lors de la création des matchs.",
|
||||
"toast.matchs.create.pending": "Création des matchs en cours...",
|
||||
"toast.matchs.create.success": "Matchs créés avec succès.",
|
||||
"toast.team.update.error": "Erreur lors de la mise à jour de l'équipe",
|
||||
"toast.team.update.pending": "Mise à jour de l'équipe...",
|
||||
"toast.team.update.success": "Équipe mise à jour !",
|
||||
"toast.updateCategory.error": "Erreur lors de la mise à jour de la catégorie",
|
||||
"toast.updateCategory.pending": "Mise à jour de la catégorie...",
|
||||
"toast.updateCategory.success": "Catégorie mise à jour !",
|
||||
"toast.updateMatchScore.error": "Erreur lors de la mise à jour du score du match",
|
||||
"toast.updateMatchScore.pending": "Mise à jour du score du match...",
|
||||
"toast.updateMatchScore.success": "Score du match mis à jour !",
|
||||
"toast.updateTrees.error": "Erreur lors de la mise à jour des arbres",
|
||||
"toast.updateTrees.init.error": "Erreur lors de la création des arbres",
|
||||
"toast.updateTrees.init.pending": "Création des arbres du tournoi...",
|
||||
"toast.updateTrees.init.success": "Arbres créés !",
|
||||
"toast.updateTrees.pending": "Mise à jour des arbres du tournoi...",
|
||||
"toast.updateTrees.success": "Arbres mis à jour !",
|
||||
"tournoi": "Tournoi",
|
||||
"tournois": "Tournois",
|
||||
"tousLesMatchs": "Tous les matchs",
|
||||
"toutConserver": "Tout conserver",
|
||||
"ttm.admin.obs": "Clique court : Télécharger les ressources. Clique long : Créer la configuration obs",
|
||||
"ttm.admin.scripte": "Copier le scripte d'intégration",
|
||||
"ttm.table.inverserLaPosition": "Inverser la position des combattants sur cette écran",
|
||||
"ttm.table.obs": "Clique court : Charger la configuration et se connecter. Clique long : Configuration de la lice",
|
||||
"ttm.table.pub_aff": "Ouvrir l'affichage public",
|
||||
"ttm.table.pub_score": "Afficher les scores sur l'affichage public",
|
||||
"type": "Type",
|
||||
"téléchargement": "Téléchargement",
|
||||
"téléchargementEnCours": "Téléchargement en cours...",
|
||||
"téléchargementTerminé!": "Téléchargement terminé !",
|
||||
"uneCatégorie": "une catégorie",
|
||||
"valider": "Valider",
|
||||
"zone": "Zone",
|
||||
"zoneDeCombat": "Zone de combat"
|
||||
}
|
||||
585
src/main/webapp/public/locales/fr/common.json
Normal file
585
src/main/webapp/public/locales/fr/common.json
Normal file
@@ -0,0 +1,585 @@
|
||||
{
|
||||
"(optionnelle)": "(optionnelle)",
|
||||
"---SansClub---": "--- sans club ---",
|
||||
"---TousLesAges---": "--- tous les ages ---",
|
||||
"---ToutLesClubs---": "--- tous les clubs ---",
|
||||
"---ToutLesPays---": "--- tout les pays ---",
|
||||
"---TouteLesCatégories---": "--- toute les catégories ---",
|
||||
"--NonLicencier--": "-- Non licencier --",
|
||||
"--SélectionnerCatégorie--": "-- Sélectionner catégorie --",
|
||||
"1Catégorie": "+1 catégorie",
|
||||
"2Catégorie": "+2 catégorie",
|
||||
"LesModificationsNontEnregistrer": "/!\\ Les modifications n'ont pas encore été enregistré, cliqué sur enregistrer /!\\",
|
||||
"activer": "Activer",
|
||||
"admin": "Administration",
|
||||
"administrateur": "Administrateur",
|
||||
"adresse": "Adresse",
|
||||
"adresseAdministrative": "Adresse administrative",
|
||||
"aff.ancienNom": "Ancien nom: {{name}}",
|
||||
"aff.byMembreSim": "Par Membre similaire",
|
||||
"aff.byNewMenbre": "Par Nouveau membre",
|
||||
"aff.byNoLicence": "Par n° de licence",
|
||||
"aff.info1": "Ce club a déjà été affilié (affiliation n°{{no}})",
|
||||
"aff.membreNo": "Membre n°{{no}}",
|
||||
"aff.nomDuClub": "Nom du club",
|
||||
"aff.raisonDuRefus": "Raison du refus",
|
||||
"aff.raisonDuRefus.msg": "Veuillez indiquer la raison du refus",
|
||||
"aff.refusConfirm": "Êtes-vous sûr de vouloir refuser cette demande ?",
|
||||
"aff.refuserLaDemande": "Refuser la demande",
|
||||
"aff.refuserLaDemande.detail": "Êtes-vous sûr de vouloir refuser cette demande ?",
|
||||
"aff.submit.error1": "Veuillez saisir un numéro de licence valide pour le membre {{id}}",
|
||||
"aff.submit.error2": "Veuillez saisir un numéro de licence valide pour le membre {{id}}",
|
||||
"aff.submit.error3": "Veuillez saisir un email valide pour le membre {{id}}",
|
||||
"aff.toast.accept.error": "Échec de l'acceptation de l'affiliation",
|
||||
"aff.toast.accept.pending": "Acceptation de l'affiliation en cours",
|
||||
"aff.toast.accept.success": "Affiliation acceptée avec succès 🎉",
|
||||
"aff.toast.del.error": "Échec de la suppression de la demande d'affiliation",
|
||||
"aff.toast.del.pending": "Suppression de la demande d'affiliation en cours",
|
||||
"aff.toast.del.success": "Demande d'affiliation supprimée avec succès 🎉",
|
||||
"aff.toast.del2.error": "Échec de la suppression de l'affiliation",
|
||||
"aff.toast.del2.pending": "Suppression de l'affiliation en cours",
|
||||
"aff.toast.del2.success": "Affiliation supprimée avec succès 🎉",
|
||||
"aff.toast.save.error": "Échec de l'enregistrement de la demande d'affiliation",
|
||||
"aff.toast.save.pending": "Enregistrement de la demande d'affiliation en cours",
|
||||
"aff.toast.save.success": "Demande d'affiliation enregistrée avec succès 🎉",
|
||||
"aff.toast.save2.error": "Échec de l'enregistrement de l'affiliation",
|
||||
"aff.toast.save2.pending": "Enregistrement de l'affiliation en cours",
|
||||
"aff.toast.save2.success": "Affiliation enregistrée avec succès 🎉",
|
||||
"aff_req.appuyerSurRechercher": "Appuyer sur rechercher pour compléter",
|
||||
"aff_req.association": "L'association",
|
||||
"aff_req.button.cancel": "Annuler ma demande",
|
||||
"aff_req.button.confirm": "Confirmer ma demande d'affiliation",
|
||||
"aff_req.button.save": "Enregistrer les modifications",
|
||||
"aff_req.denomination": "Dénomination",
|
||||
"aff_req.disposeLicence": "Dispose déjà d'une licence",
|
||||
"aff_req.error1": "Le rôle du membre {{i}} est obligatoire",
|
||||
"aff_req.error2": "Le format du SIRET/RNA est invalide",
|
||||
"aff_req.nomDeLassociation": "Nom de l'association",
|
||||
"aff_req.text1": "L'affiliation est annuelle et valable pour une saison sportive : du 1er septembre au 31 août de l’année suivante.",
|
||||
"aff_req.text2": "Pour s’affilier, une association sportive doit réunir les conditions suivantes :",
|
||||
"aff_req.text2.li": [
|
||||
"Avoir son siège social en France ou Principauté de Monaco",
|
||||
"Être constituée conformément au chapitre 1er du titre II du livre 1er du Code du Sport",
|
||||
"Poursuivre un objet social entrant dans la définition de l’article 1 des statuts de la Fédération",
|
||||
"Disposer de statuts compatibles avec les principes d’organisation et de fonctionnement de la Fédération",
|
||||
"Assurer en son sein la liberté d’opinion et le respect des droits de la défense, et s’interdire toute discrimination",
|
||||
"Respecter les règles d’encadrement, d’hygiène et de sécurité établies par les règlements de la Fédération"
|
||||
],
|
||||
"aff_req.text3": "Après validation de votre demande, vous recevrez un identifiant et mot de passe provisoire pour accéder à votre espace FFSAF",
|
||||
"aff_req.text4": "Notez que pour finaliser votre affiliation, il vous faudra :",
|
||||
"aff_req.text4.li1": "Disposer d’au moins trois membres licenciés, dont le président",
|
||||
"aff_req.text4.li2": "S'être acquitté des cotisations prévues par les règlements fédéraux",
|
||||
"aff_req.text5": "Vous pourrez par la suite, ajouter des adresses visibles publiquement pour vos lieux d'entrainement",
|
||||
"aff_req.text6": "Laissez vide pour ne rien changer. (Si un blason a déjà été envoyé lors de cette demande, il sera utilisé, sinon nous utiliserons celui de la précédant affiliation)",
|
||||
"aff_req.text7": "Demande d'affiliation envoyée avec succès",
|
||||
"aff_req.text8": "Une fois votre demande validée, vous recevrez un identifiant et mot de passe provisoire pour accéder à votre espace FFSAF",
|
||||
"aff_req.toast.undo.error": "Échec de l'annulation de la demande d'affiliation",
|
||||
"aff_req.toast.undo.pending": "Annulation de la demande d'affiliation en cours",
|
||||
"aff_req.toast.undo.success": "Demande d'affiliation annulée avec succès 🎉",
|
||||
"afficherLesCombattantsNonPesés": "Afficher les combattants non pesés",
|
||||
"afficherLétatDesAffiliation": "Afficher l'état des affiliation",
|
||||
"affiliation": "Affiliation",
|
||||
"affiliationNo": "Affiliation n°{{no}}",
|
||||
"ajout": "Ajout",
|
||||
"ajouterUnClub": "Ajouter un club",
|
||||
"ajouterUnMembre": "Ajouter un membre",
|
||||
"all_season": "--- tout les saisons ---",
|
||||
"ans": "ans",
|
||||
"arme": "Arme",
|
||||
"au": "au",
|
||||
"aucun": "Aucun",
|
||||
"aucunMembreSélectionné": "Aucun membre sélectionné",
|
||||
"aucuneCatégorieDisponible": "Aucune catégorie disponible pour le moment.",
|
||||
"back": "« retour",
|
||||
"blason": "Blason",
|
||||
"bouclier": "Bouclier",
|
||||
"bureau": "Bureau",
|
||||
"button.accepter": "Accepter",
|
||||
"button.ajouter": "Ajouter",
|
||||
"button.annuler": "Annuler",
|
||||
"button.appliquer": "Appliquer",
|
||||
"button.confirmer": "Confirmer",
|
||||
"button.créer": "Créer",
|
||||
"button.enregistrer": "Enregistrer",
|
||||
"button.fermer": "Fermer",
|
||||
"button.modifier": "Modifier",
|
||||
"button.refuser": "Refuser",
|
||||
"button.seDésinscrire": "Se désinscrire",
|
||||
"button.suivant": "Suivant",
|
||||
"button.supprimer": "Supprimer",
|
||||
"casque": "Casque",
|
||||
"cat.benjamin": "Benjamin",
|
||||
"cat.cadet": "Cadet",
|
||||
"cat.catégorieInconnue": "Catégorie inconnue",
|
||||
"cat.junior": "Junior",
|
||||
"cat.miniPoussin": "Mini Poussin",
|
||||
"cat.minime": "Minime",
|
||||
"cat.poussin": "Poussin",
|
||||
"cat.senior1": "Senior 1",
|
||||
"cat.senior2": "Senior 2",
|
||||
"cat.superMini": "Super Mini",
|
||||
"cat.vétéran1": "Vétéran 1",
|
||||
"cat.vétéran2": "Vétéran 2",
|
||||
"categorie": "categorie",
|
||||
"catégorie": "Catégorie",
|
||||
"catégorieàAjouter": "Catégorie à ajouter",
|
||||
"certificatMédical": "Certificat médical",
|
||||
"chargement...": "Chargement...",
|
||||
"chargerLexcel": "Charger l'Excel",
|
||||
"chargerLexcel.msg": "Merci d'utiliser le fichier ci-dessus comme base, ne pas renommer les colonnes ni modifier les n° de licences.",
|
||||
"choisir...": "Choisir...",
|
||||
"club.aff_renew.msg": "Veuillez sélectionner 0 à 3 membres du bureau pour remplir la pré-demande. (Si un membre non-bureau va le devenir l'an prochain, vous pourrez les renseigner à la prochaine étape)",
|
||||
"club.change.status": "Pour modifier les informations ci-dessus, merci de contacter la FFSAF par mail.",
|
||||
"club.contact.tt": {
|
||||
"AUTRE": "Autre contact du club",
|
||||
"COURRIEL": "Adresse e-mail du club<br>Exemple: contact@ffsaf.fr",
|
||||
"FACEBOOK": "Page Facebook du club débutant par 'https://www.facebook.com/'</br>Exemple: https://www.facebook.com/ffmsf",
|
||||
"INSTAGRAM": "Compte Instagram du club débutant par 'https://www.instagram.com/'</br>Exemple: https://www.instagram.com/ff_msf",
|
||||
"SITE": "Site web du club avec ou sans le 'https://'</br>Exemple: ffsaf.fr</br>Ou https://ffsaf.fr",
|
||||
"TELEPHONE": "Numéro de téléphone du club<br>Exemple: 06 12 13 78 55"
|
||||
},
|
||||
"club.toast.aff.error": "Impossible de charger les affiliations",
|
||||
"club.toast.aff.pending": "Chargement des affiliations en cours",
|
||||
"club.toast.aff.success": "Affiliations chargées avec succès 🎉",
|
||||
"club.toast.del.error": "Échec de la suppression du club",
|
||||
"club.toast.del.pending": "Suppression du club en cours",
|
||||
"club.toast.del.success": "Club supprimé avec succès 🎉",
|
||||
"club.toast.new.error": "Échec de la création du club",
|
||||
"club.toast.new.pending": "Création du club en cours",
|
||||
"club.toast.new.success": "Club créé avec succès 🎉",
|
||||
"club.toast.save.error": "Échec de l'enregistrement du club",
|
||||
"club.toast.save.pending": "Enregistrement du club en cours",
|
||||
"club.toast.save.success": "Club enregistré avec succès 🎉",
|
||||
"clubExterne": "Club externe",
|
||||
"club_one": "Club",
|
||||
"club_other": "Clubs",
|
||||
"club_zero": "Sans club",
|
||||
"combattant": "combattant",
|
||||
"comp.aff.blason": "Afficher le blason du club sur les écrans",
|
||||
"comp.aff.flag": "Afficher le pays du combattant sur les écrans",
|
||||
"comp.ajoutRapide": "Ajout rapide",
|
||||
"comp.ajouterUnCombattant": "Ajouter un combattant",
|
||||
"comp.ajouterUnInvité": "Ajouter un invité",
|
||||
"comp.billetterie": "Billetterie",
|
||||
"comp.billetterieHelloasso": "Billetterie HelloAsso",
|
||||
"comp.catégorieNormalisée": "Catégorie normalisée",
|
||||
"comp.combattantNonTrouvé": "Combattant non trouvé",
|
||||
"comp.combattantsInscrits": "Combattants inscrits",
|
||||
"comp.compétitionFuture": "Compétition future",
|
||||
"comp.compétitionPassée": "Compétition passée",
|
||||
"comp.créationCompétition": "Création compétition",
|
||||
"comp.dateDinscription": "Date d'inscription",
|
||||
"comp.editionCompétition": "Edition compétition",
|
||||
"comp.error1": "La date de fin doit être postérieure à la date de début.",
|
||||
"comp.error2": "Veuillez renseigner les dates de début et de fin d'inscription.",
|
||||
"comp.error3": "La date de fin d'inscription doit être postérieure à la date de début d'inscription.",
|
||||
"comp.exporterLesInscription": "Exporter les inscription",
|
||||
"comp.ha.emailDeRéceptionDesInscriptionséchoué": "Email de réception des inscriptions échoué",
|
||||
"comp.ha.error1": "Veuillez renseigner l'URL de la billetterie HelloAsso et les tarifs associés.",
|
||||
"comp.ha.error2": "L'URL de la billetterie HelloAsso n'est pas valide. Veuillez vérifier le format de l'URL.",
|
||||
"comp.ha.error3": "Veuillez renseigner l'email de réception des inscriptions échouées.",
|
||||
"comp.ha.tarifsHelloasso": "Tarifs HelloAsso",
|
||||
"comp.ha.text1": "Afin de permettre une bonne interconnexion avec HelloAsso, merci de suivre les instructions suivantes :",
|
||||
"comp.ha.text2": "<strong>Configurer l'url de notification : </strong>afin que nous puissions recevoir une notification à chaque inscription, il est nécessaire de configurer l'url de notification de votre compte HelloAsso pour qu'il redirige vers \"https://intra.ffsaf.fr/api/webhook/ha\". Pour ce faire, depuis la page d'accueil de votre association sur HelloAsso, allez dans <strong>Mon compte</strong> > <strong>Paramètres</strong> > <strong> Intégrations et API</strong> section Notification et copier-coller <strong>https://intra.ffsaf.fr/api/webhook/ha </strong> dans le champ <strong>Mon URL de callback</strong> et enregister.",
|
||||
"comp.ha.text3": "<strong>Copier-coller le nom exacte des tarifs</strong> <em>-sépare par des point-virgules-</em> qui donneront lieux à une inscription automatique. Tous ces tarifs doivent impérativement demander le numéro de licence en champs obligatoire. Pour ce faire, lors de la configuration de votre billetterie à l'étape n°3, cliquer sur <strong>+ Ajouter une information</strong>, saisissez l'intituler exact suivant <strong> Numéro de licence</strong>, dans <strong>Type de réponse souhaitée</strong> rentrer Nombre, sélectionner les tarifs entrés plus précédemment et rendre l'information obligatoire.",
|
||||
"comp.ha.text4": "<strong>Copier-coller l'url de votre billetterie</strong> dans le champs si dessous. Il devrais avoir la forme suivante: https://www.helloasso.com/associations/__nom-asso-sur-helloasso__/evenements/__nom-billetterie__",
|
||||
"comp.ha.text5": "Url de la billetterie HelloAsso",
|
||||
"comp.ha.text6": "Si pour une raison quelconque l'inscription automatique échoue, un email sera envoyé à cette adresse pour vous en informer",
|
||||
"comp.informationsGénéralesSurLaCompétition": "Informations générales sur la compétition",
|
||||
"comp.informationsSurLeModeDinscription": "Informations sur le mode d'inscription",
|
||||
"comp.informationsTechniques": "Informations techniques",
|
||||
"comp.inscription": "Inscription",
|
||||
"comp.inscriptionModeAdministrateur": "Inscription - mode administrateur",
|
||||
"comp.inscriptionsLibres": "Inscriptions libres",
|
||||
"comp.inscriptionsParLesAdministrateursDeLaCompétition": "Inscriptions par les administrateurs de la compétition",
|
||||
"comp.inscriptionsParLesResponsablesDeClub": "Inscriptions par les responsables de club",
|
||||
"comp.inscriptionsSurLaBilletterieHelloasso": "Inscriptions sur la billetterie HelloAsso",
|
||||
"comp.modal.annoncé": "Annoncé",
|
||||
"comp.modal.information": "Information",
|
||||
"comp.modal.pesé": "Pesé",
|
||||
"comp.modal.poids": "Poids (en kg)",
|
||||
"comp.modal.recherche": "Recherche*",
|
||||
"comp.modal.surclassement": "Surclassement",
|
||||
"comp.modal.text1": "Les invités sont réservés aux membres non licenciés par la fédération. Les combattants inscrits via ce formulaire ne pourront pas voir leur résultat depuis leur profil.",
|
||||
"comp.modal.text2": "Empêcher les membres/club de modifier cette inscription",
|
||||
"comp.modifierLesParticipants": "Voir/Modifier les participants",
|
||||
"comp.monInscription": "Mon inscription",
|
||||
"comp.noDeLicence": "N° de licence",
|
||||
"comp.nouvelleCompétition": "Nouvelle compétition",
|
||||
"comp.organisateur": "Organisateur",
|
||||
"comp.quiPeutInscrire": "Qui peut inscrire",
|
||||
"comp.reg.libres": "Libres",
|
||||
"comp.reg.parLesAdministrateursDeLaCompétition": "Par les administrateurs de la compétition",
|
||||
"comp.reg.parLesResponsablesDeClub": "Par les responsables de club",
|
||||
"comp.reg.surLaBilletterieHelloasso": "Sur la billetterie HelloAsso",
|
||||
"comp.responsablesEtBureauxDesAssociations": "Responsables et bureaux des associations",
|
||||
"comp.sinscrire": "S'inscrire",
|
||||
"comp.supprimerLaCompétition": "Supprimer la compétition",
|
||||
"comp.supprimerLaCompétition.msg": "Êtes-vous sûr de vouloir supprimer cette compétition est tout les resultat associer?",
|
||||
"comp.surclassement_one": "{{cat}} avec 1 de surclassement",
|
||||
"comp.surclassement_other": "{{cat}} avec {{count}} de surclassements",
|
||||
"comp.surclassement_zero": "{{cat}}",
|
||||
"comp.text2": "Visible par le public (Apparaît dans la liste des compétitions)",
|
||||
"comp.text3": "Si non coché, la compétition ne sera visible que par les personnes pouvant y inscrire des participants.",
|
||||
"comp.tips": "Tips 1: Il est possible de bannir un combattant, ce qui l'empêchera d'être réinscrit par un autre moyen que par un administrateur de cette compétition. Pour cela, cliquez sur la petite <1/> à côté de son nom.<br/>Tips 2: Il est aussi possible de verrouiller les modifications de son inscription depuis sa fiche, ce qui l'empêchera d'être modifié/supprimé par lui-même et/ou un responsable de club.",
|
||||
"comp.toast.del.error": "Échec de la suppression de la compétition",
|
||||
"comp.toast.del.pending": "Suppression de la compétition en cours",
|
||||
"comp.toast.del.success": "Compétition supprimée avec succès 🎉",
|
||||
"comp.toast.params.error": "Échec de la mise à jours des paramètres de la compétition",
|
||||
"comp.toast.params.pending": "Mise à jours des paramètres de la compétition en cours...",
|
||||
"comp.toast.params.success": "Paramètres de la compétition mis à jours avec succès 🎉",
|
||||
"comp.toast.register.add.error": "Combattant non trouvé",
|
||||
"comp.toast.register.add.pending": "Recherche en cours",
|
||||
"comp.toast.register.add.success": "Combattant trouvé et ajouté/mis à jour",
|
||||
"comp.toast.register.ban.error": "Erreur",
|
||||
"comp.toast.register.ban.pending": "Désinscription en cours",
|
||||
"comp.toast.register.ban.success": "Combattant désinscrit et bannie",
|
||||
"comp.toast.register.del.error": "Erreur",
|
||||
"comp.toast.register.del.pending": "Désinscription en cours",
|
||||
"comp.toast.register.del.success": "Combattant désinscrit",
|
||||
"comp.toast.register.self.add.error": "Erreur lors de l'inscription",
|
||||
"comp.toast.register.self.add.pending": "Inscription en cours",
|
||||
"comp.toast.register.self.add.success": "Inscription réalisée 🎉",
|
||||
"comp.toast.register.self.del.error": "Erreur lors de la désinscription",
|
||||
"comp.toast.register.self.del.pending": "Désinscription en cours",
|
||||
"comp.toast.register.self.del.success": "Désinscription réalisée",
|
||||
"comp.toast.save.error": "Échec de l'enregistrement de la compétition",
|
||||
"comp.toast.save.pending": "Enregistrement de la compétition en cours",
|
||||
"comp.toast.save.success": "Compétition enregistrée avec succès 🎉",
|
||||
"comp.tousLesMembresDeLaFfsaf": "Tous les membres de la FFSAF",
|
||||
"comp.typeDinscription": "Type d'inscription",
|
||||
"comp.uniquementLesAdministrateursDeLaCompétition": "Uniquement les administrateurs de la compétition",
|
||||
"comp.warn1": "Êtes-vous sûr de vouloir désinscrire et bannir ce combattant de la compétition?\n(Vous pouvez le réinscrire plus tard)\"",
|
||||
"comp.warn2": "Êtes-vous sûr de vouloir désinscrire ce combattant ?\nCela ne le désinscrira pas de la billetterie HelloAsso et ne le remboursera pas.",
|
||||
"comp.warn3": "Êtes-vous sûr de vouloir désinscrire ce combattant ?",
|
||||
"comp.warn4": "Êtes-vous sûr de vouloir vous désinscrire ?",
|
||||
"comp_manage": "Compétitions Manager",
|
||||
"competition_one": "Compétition",
|
||||
"competition_other": "Compétitions",
|
||||
"compte": "Compte",
|
||||
"compétition": "Compétition",
|
||||
"configuration": "Configuration",
|
||||
"configurationDeLaCatégorie": "Configuration de la catégorie",
|
||||
"conserverLancienEmail": "Conserver l'ancien email",
|
||||
"contactAdministratif": "Contact administratif",
|
||||
"contactInterne": "Contact interne",
|
||||
"contact_one": "Contact",
|
||||
"contact_other": "Contacts",
|
||||
"coquilleProtectionPelvienne": "Coquille / Protection pelvienne",
|
||||
"date": "Date",
|
||||
"dateDeNaissance": "Date de naissance",
|
||||
"days": [
|
||||
"Lundi",
|
||||
"Mardi",
|
||||
"Mercredi",
|
||||
"Jeudi",
|
||||
"Vendredi",
|
||||
"Samedi",
|
||||
"Dimanche"
|
||||
],
|
||||
"de": "de",
|
||||
"demandeDaffiliationEnCours": "Demande d'affiliation en cours",
|
||||
"demandeDeLicence": "Demande de licence ",
|
||||
"demander": "Demander",
|
||||
"description": "Description",
|
||||
"dlAff": "Téléchargée l'attestation d'affiliation",
|
||||
"donnéesAdministratives": "Données administratives",
|
||||
"du": "Du",
|
||||
"dun": "d'un",
|
||||
"duréePause": "Durée pause",
|
||||
"duréeRound": "Durée round",
|
||||
"définirLidDuCompte": "Définir l'id du compte",
|
||||
"editionDeL'affiliation": "Edition de l'affiliation",
|
||||
"editionDeLaDemande": "Edition de la demande ",
|
||||
"editionDeLaLicence": "Edition de la licence",
|
||||
"editionDeLaSéléction": "Edition de la séléction",
|
||||
"editionDeLadresse": "Edition de l'adresse",
|
||||
"email": "Email",
|
||||
"en": "en",
|
||||
"enAttente": "En attente",
|
||||
"erreurDePaiement": "Erreur de paiement😕",
|
||||
"erreurDePaiement.detail": "Message d'erreur :",
|
||||
"erreurDePaiement.msg": "Une erreur est survenue lors du traitement de votre paiement. Veuillez réessayer plus tard.",
|
||||
"espaceAdministration": "Espace administration",
|
||||
"f": "F",
|
||||
"faitPar": "Fait par",
|
||||
"femme": "Femme",
|
||||
"filtre": "Filtre",
|
||||
"gantMainBouclier": "Gant main de bouclier",
|
||||
"gantMainsArmées": "Gant main(s) armée(s)",
|
||||
"gants": "Gants",
|
||||
"genre": "Genre",
|
||||
"gestionGroupée": "Gestion groupée",
|
||||
"gorgerin": "Gorgerin",
|
||||
"gradeDarbitrage": "Grade d'arbitrage",
|
||||
"h": "H",
|
||||
"home": {
|
||||
"header1": "Pour les licenciés",
|
||||
"header2": "Pour les clubs",
|
||||
"text1": "Vous y retrouverez toutes vos informations ainsi que l'état de votre inscription à la fédération. Vous pouvez également télécharger votre attestation d'inscription, vous inscrire aux compétitions ainsi que consulter vos résultats sous réserve que le club organisateur les ait renseignés.<br/><br/>Lors de votre première inscription, vous recevrez un email contenant vos informations d'identification, ce mail sera envoyé une fois votre licence validée par le secrétariat.",
|
||||
"text2": "C'est ici que vous pouvez prendre les licences fédérales pour vos adhérents, que vous pouvez demander ou renouveler votre affiliation, renseigner vos horaires, lieux d'entraînement et réseaux sociaux qui seront par la suite affichés sur le site ffsaf.fr.<br/>Vous aurez par ailleurs la possibilité de publier des formulaires d'inscriptions pour vos compétitions ainsi que d'enregistrer les résultats.<br/><br/> Vous n'êtes pas encore affilié à la fédération ? Cliquez <1>içi</1> pour faire votre première demande.",
|
||||
"welcome_message": "Bienvenue sur l’intranet de la Fédération France Soft Armored Fighting"
|
||||
},
|
||||
"homme": "Homme",
|
||||
"horairesD'entraînements": "Horaires d'entraînements",
|
||||
"information": "Information",
|
||||
"invité": "invité",
|
||||
"keepEmpty": "Laissez vide pour ne rien changer.",
|
||||
"le": "le",
|
||||
"licence": "Licence",
|
||||
"licenceNo": "Licence n°{{no}}",
|
||||
"lieu": "Lieu",
|
||||
"lieuxDentraînements": "Lieux d'entraînements",
|
||||
"loading": "Chargement...",
|
||||
"me": {
|
||||
"result": {
|
||||
"PRIVATE": "Privé (visible uniquement par moi)",
|
||||
"PUBLIC": "Public (visible par tous)",
|
||||
"REGISTERED_ONLY": "Membres connectés (visibles par les membres de la fédération)",
|
||||
"REGISTERED_ONLY_NO_DETAILS": "Membres connectés - masquer les détails (visibles par les membres de la fédération)"
|
||||
},
|
||||
"toast.settings.error": "Échec de la mise à jours des paramètres 😕",
|
||||
"toast.settings.pending": "Mise à jours des paramètres en cours...",
|
||||
"toast.settings.success": "Paramètres mis à jours avec succès 🎉"
|
||||
},
|
||||
"me.changerMonMotDePasse": "Changer mon mot de passe",
|
||||
"me.formationDarbitrage": "Formation d'arbitrage",
|
||||
"me.paramètresDuCompte": "Paramètres du compte",
|
||||
"me.rôleAuSienDuClub": "Rôle au sien du club",
|
||||
"me.visibilitéDesRésultats": "Visibilité des résultats",
|
||||
"member_one": "Membre",
|
||||
"member_other": "Membres",
|
||||
"membre.emailVideàLaLigne": "Email vide à la ligne {{no}}",
|
||||
"membre.emailVérifié": "Email vérifié",
|
||||
"membre.filtre.inactif": "Afficher les combattants inactifs",
|
||||
"membre.filtre.licence": "Afficher l'état des licences",
|
||||
"membre.filtre.licences": [
|
||||
"Sans demande ni licence validée",
|
||||
"Avec demande ou licence validée",
|
||||
"Demande en cours",
|
||||
"Licence validée",
|
||||
"Tout les états de licences",
|
||||
"Demande complet",
|
||||
"Demande incomplet"
|
||||
],
|
||||
"membre.filtre.payement": [
|
||||
"Sans paiement",
|
||||
"Avec paiement",
|
||||
"Tout les états de paiement"
|
||||
],
|
||||
"membre.identifiant": "Identifiant",
|
||||
"membre.import.err1": "Format de la date de certificat invalide à la ligne {{no}}",
|
||||
"membre.import.err2": "Format de la date de certificat invalide à la ligne {{no}}",
|
||||
"membre.import.err3": "Date de naissance vide à la ligne {{no}}",
|
||||
"membre.import.err4": "Format de la date de naissance invalide à la ligne {{no}}",
|
||||
"membre.import.err5": "Email invalide à la ligne {{no}}",
|
||||
"membre.import.errTT_one": "{{count}} erreur dans le fichier, opération annulée",
|
||||
"membre.import.errTT_other": "{{count}} erreurs dans le fichier, opération annulée",
|
||||
"membre.import.warn_one": "{{count}} certificat médical non rempli",
|
||||
"membre.import.warn_other": "{{count}} certificats médicaux non remplis",
|
||||
"membre.info.emailInfo": "L'email sert à la création de compte pour se connecter au site et doit être unique.<br/>Pour les mineurs, l'email des parents peut être utilisé plusieurs fois grâce à la syntaxe suivante : {'email.parent+<caractères alphanumériques>@exemple.com'}.<br/>Exemples : mail.parent+1@exemple.com, mail.parent+titouan@exemple.com, mail.parent+cedrique@exemple.com",
|
||||
"membre.info.error1": "Veuillez sélectionner un pays valide 😕",
|
||||
"membre.info.error2": "Veuillez sélectionner un club valide 😕",
|
||||
"membre.initaccount": "Initialiser le compte",
|
||||
"membre.initaccount.text1": "Entré l'UUID du compte",
|
||||
"membre.initaccount.text2": "Attention ne changée l'id d'un membre que si vous êtes sûr de ce que vos faites...",
|
||||
"membre.noAccount": "Ce membre ne dispose pas de compte...",
|
||||
"membre.noAccount.clubMsg": "Un compte sera créé par la fédération lors de la validation de sa première licence",
|
||||
"membre.nomVideàLaLigne": "Nom vide à la ligne {{no}}",
|
||||
"membre.prénomVideàLaLigne": "Prénom vide à la ligne {{no}}",
|
||||
"membre.toast.compte.created": "Compte créé avec succès 🎉",
|
||||
"membre.toast.compte.error": "Échec de la création du compte",
|
||||
"membre.toast.compte.pending": "Création du compte en cours",
|
||||
"membre.toast.del.error": "Échec de la suppression du compte",
|
||||
"membre.toast.del.pending": "Suppression du compte en cours",
|
||||
"membre.toast.del.success": "Compte supprimé avec succès 🎉",
|
||||
"membre.toast.id.error": "Échec de la définition de l'identifient",
|
||||
"membre.toast.id.pending": "Définition de l'identifient en cours",
|
||||
"membre.toast.id.success": "Identifient défini avec succès 🎉",
|
||||
"membre.toast.licence.ask.del.error": "Échec de la suppression de la demande de licence",
|
||||
"membre.toast.licence.ask.del.pending": "Suppression de la demande de licence en cours",
|
||||
"membre.toast.licence.ask.del.success": "Demande de licence supprimée avec succès 🎉",
|
||||
"membre.toast.licence.ask.error": "Échec de la demande de licence",
|
||||
"membre.toast.licence.ask.pending": "Enregistrement de la demande de licence en cours",
|
||||
"membre.toast.licence.ask.success": "Demande de licence enregistrée avec succès 🎉",
|
||||
"membre.toast.licence.del.error": "Échec de la suppression de la licence",
|
||||
"membre.toast.licence.del.pending": "Suppression de la licence en cours",
|
||||
"membre.toast.licence.del.success": "Licence supprimée avec succès 🎉",
|
||||
"membre.toast.licence.save.error": "Échec de l'enregistrement de la licence",
|
||||
"membre.toast.licence.save.pending": "Enregistrement de la licence en cours",
|
||||
"membre.toast.licence.save.success": "Licence enregistrée avec succès 🎉",
|
||||
"membre.toast.licences.export.error": "Échec de l'export des licences",
|
||||
"membre.toast.licences.export.pending": "Export des licences en cours",
|
||||
"membre.toast.licences.export.success": "Licences exportées avec succès 🎉",
|
||||
"membre.toast.licences.import.error": "Échec de l'envoie des changements",
|
||||
"membre.toast.licences.import.pending": "Envoie des changements en cours",
|
||||
"membre.toast.licences.import.success": "Changements envoyés avec succès 🎉",
|
||||
"membre.toast.licences.load.error": "Impossible de charger les licences",
|
||||
"membre.toast.licences.load.pending": "Chargement des licences en cours",
|
||||
"membre.toast.licences.load.success": "Licences chargées avec succès 🎉",
|
||||
"membre.toast.perm.error": "Échec de la mise à jours des permissions 😕",
|
||||
"membre.toast.perm.pending": "Mise à jours des permissions en cours...",
|
||||
"membre.toast.perm.success": "Permission mise à jours avec succès 🎉",
|
||||
"membre.toast.save.error": "Échec de la mise à jours du profil 😕",
|
||||
"membre.toast.save.pending": "Mise à jours du profil en cours...",
|
||||
"membre.toast.save.success": "Profil mis à jours avec succès 🎉",
|
||||
"membre.toast.select.del.error": "Échec de la suppression de la séléction",
|
||||
"membre.toast.select.del.pending": "Suppression de la séléction en cours",
|
||||
"membre.toast.select.del.success": "Séléction supprimée avec succès 🎉",
|
||||
"membre.toast.select.save.error": "Échec de l'enregistrement de la séléction",
|
||||
"membre.toast.select.save.pending": "Enregistrement de la séléction en cours",
|
||||
"membre.toast.select.save.success": "Séléction enregistrée avec succès 🎉",
|
||||
"mettreàJours": "Mettre à jours",
|
||||
"modification": "Modification",
|
||||
"nationalité": "Nationalité",
|
||||
"nav": {
|
||||
"account": "Mon compte",
|
||||
"aff_request": "Demande d'affiliation",
|
||||
"club": {
|
||||
"my": "Mon club"
|
||||
},
|
||||
"competitions": {
|
||||
"results": "Mes résultats"
|
||||
},
|
||||
"home": "Accueil",
|
||||
"login": "Connexion",
|
||||
"logout": "Déconnexion",
|
||||
"space": "Mon espace",
|
||||
"title": "FFSAF Intranet"
|
||||
},
|
||||
"noLicence": "N° Licence",
|
||||
"noSiretOuRna": "N° $t(siretOuRna)",
|
||||
"nom": "Nom",
|
||||
"nombreDeLicences": "Nombre de licences",
|
||||
"nombreDeLicencesParCatégorie": "Nombre de licences par catégorie pour {{saison}}",
|
||||
"non": "Non",
|
||||
"nonDéfinie": "Non définie",
|
||||
"nonValidée": "Non validée",
|
||||
"nouveauClub": "Nouveau club",
|
||||
"nouveauMembre": "Nouveau membre",
|
||||
"nouvelEmail": "Nouvel email",
|
||||
"ou": "Ou",
|
||||
"oui": "Oui",
|
||||
"outdated_session": {
|
||||
"login_button": "Se reconnecter",
|
||||
"message": "Votre session a expirée, veuillez vous reconnecter pour continuer à utiliser l'application.",
|
||||
"title": "Session expirée"
|
||||
},
|
||||
"pageClub": "Page club",
|
||||
"pageMembre": "Page membre",
|
||||
"pageNouveauClub": "Page nouveau club",
|
||||
"page_info_full": "Ligne {{line}} à {{tt_line}} (page {{page}} sur {{tt_page}})",
|
||||
"page_info_ligne": "{{show}} ligne(s) affichée(s) sur {{total}}",
|
||||
"paiementDeLaLicence": "Paiement de la licence",
|
||||
"paiementDesLicences": "Paiement des licences",
|
||||
"par": "par",
|
||||
"pasDeLicence": "Pas de licence",
|
||||
"payment.ha.info": "Le modèle solidaire de HelloAsso garantit que 100% de votre paiement sera versé à l’association choisie. Vous pouvez soutenir l’aide qu’ils apportent aux associations en laissant une contribution volontaire à HelloAsso au moment de votre paiement.",
|
||||
"payment.info": "A propos de HelloAsso",
|
||||
"payment.paiementSécurisé": "Paiement sécurisé",
|
||||
"payment.payerAvec": "Payer avec",
|
||||
"payment.recap": "{{count}} licence(s) sélectionnée<br/>Total à régler : {{total}} €",
|
||||
"paymentDesLicences": "Payment des licences",
|
||||
"paymentDesLicences.msg_one": "Êtes-vous sûr de vouloir marquer comme payées la licence ?",
|
||||
"paymentDesLicences.msg_other": "Êtes-vous sûr de vouloir marquer comme payées les {{count}} licences ?",
|
||||
"paymentDesLicences.msg_zero": "$t(paymentDesLicences.msg_other)",
|
||||
"paymentOk": "🎉Votre paiement a été traité avec succès.🎉",
|
||||
"paymentOk.msg": "Merci pour votre paiement. Les licences devraient être activées dans l'heure qui vient, à condition que le certificat médical soit rempli.",
|
||||
"pays": "Pays",
|
||||
"perm.administrateurDeLaFédération": "Administrateur de la fédération",
|
||||
"perm.créerDesCompétion": "Créer des compétion",
|
||||
"perm.ffsafIntra": "FFSAF intra",
|
||||
"permission": "Permission",
|
||||
"peutSinscrire": "Peut s'inscrire?",
|
||||
"photos": "Photos",
|
||||
"plastron": "Plastron",
|
||||
"poidsDemandéPour": "Poids demandé pour",
|
||||
"prenom": "Prénom",
|
||||
"protectionDeBras": "Protection de bras",
|
||||
"protectionDeBrasArmé": "Protection de bras armé(s)",
|
||||
"protectionDeBrasDeBouclier": "Protection de bras de bouclier",
|
||||
"protectionDeCoudes": "Protection de coudes",
|
||||
"protectionDeGenoux": "Protection de genoux",
|
||||
"protectionDeJambes": "Protection de jambes",
|
||||
"protectionDePieds": "Protection de pieds",
|
||||
"protectionDorsale": "Protection dorsale",
|
||||
"protectionObligatoire": "Protection obligatoire",
|
||||
"prénomEtNom": "Prénom et nom",
|
||||
"rechercher": "Rechercher",
|
||||
"rechercher...": "Rechercher...",
|
||||
"registration_one": "Inscription",
|
||||
"registration_other": "Inscriptions",
|
||||
"renouveler": "Renouveler",
|
||||
"renouvellementDeLaffiliation": "Renouvellement de l'affiliation",
|
||||
"result_one": "Résultat",
|
||||
"result_other": "Résultats",
|
||||
"retouràLaListeDeMembres": "Retour à la liste de membres",
|
||||
"role": "Rôle",
|
||||
"role.membre": "Membre",
|
||||
"role.membreDuBureau": "Membre du bureau",
|
||||
"role.président": "Président",
|
||||
"role.secrétaire": "Secrétaire",
|
||||
"role.trésorier": "Trésorier",
|
||||
"role.vise-président": "Vise-Président",
|
||||
"role.vise-secrétaire": "Vise-Secrétaire",
|
||||
"role.vise-trésorier": "Vise-Trésorier",
|
||||
"saison": "Saison",
|
||||
"sans": "Sans",
|
||||
"secrétariatsDeLice": "Secrétariats de lice",
|
||||
"selectionner...": "Sélectionner...",
|
||||
"shield.buckler": "Bocle",
|
||||
"shield.none": "$t(sans) / $t(nonDéfinie)",
|
||||
"shield.round": "Rond",
|
||||
"shield.standard": "Standard",
|
||||
"shield.teardrop": "Larme",
|
||||
"siDisponiblePourLaCatégorieDages": "Si disponible pour la catégorie d'ages",
|
||||
"siretOuRna": "SIRET ou RNA",
|
||||
"stats": "Statistiques",
|
||||
"statue": "Statue",
|
||||
"status": "Status",
|
||||
"statuts": "Statuts",
|
||||
"supprimerLeClub": "Supprimer le club",
|
||||
"supprimerLeClub.msg": "Êtes-vous sûr de vouloir supprimer ce club ?",
|
||||
"supprimerLeCompte": "Supprimer le compte",
|
||||
"supprimerLeCompte.msg": "Êtes-vous sûr de vouloir supprimer ce compte ?",
|
||||
"sword.none": "$t(sans) / $t(nonDéfinie)",
|
||||
"sword.oneHand": "Une main",
|
||||
"sword.saber": "Sabre",
|
||||
"sword.twoHand": "Deux mains",
|
||||
"sélectionEnéquipeDeFrance": "Sélection en équipe de France",
|
||||
"sélectionner...": "Sélectionner...",
|
||||
"toast.edit.error": "Échec de l'enregistrement des modifications",
|
||||
"toast.edit.pending": "Enregistrement des modifications en cours",
|
||||
"toast.edit.success": "Modifications enregistrées avec succès 🎉",
|
||||
"toast.licence.bulk.pay.error": "Échec du marquage des licences comme payées",
|
||||
"toast.licence.bulk.pay.pending": "Marquage des licences comme payées en cours",
|
||||
"toast.licence.bulk.pay.success": "Licences marquées comme payées avec succès 🎉",
|
||||
"toast.licence.bulk.valid.error": "Échec de la validation des licences",
|
||||
"toast.licence.bulk.valid.pending": "Validation des licences en cours",
|
||||
"toast.licence.bulk.valid.success": "Licences validées avec succès 🎉",
|
||||
"toast.licence.order.error": "Échec de le création de la commande",
|
||||
"toast.licence.order.pending": "Création de la commande en cours",
|
||||
"toast.licence.order.success": "Commande créée avec succès 🎉",
|
||||
"trie": "Trie",
|
||||
"téléchargerLexcelDesMembres": "Télécharger l'Excel des membres",
|
||||
"téléchargerLexcelDesMembres.info": "À utiliser comme template pour mettre à jour les informations",
|
||||
"téléchargéeLaLicence": "Téléchargée la licence",
|
||||
"validationDeLaLicence": "Validation de la licence",
|
||||
"validationDesLicences": "Validation des licences",
|
||||
"validerDesLicences": "Valider des licences",
|
||||
"validerLePayement_one": "Valider le payement de la licence sélectionnée",
|
||||
"validerLePayement_other": "Valider le payement des {{count}} licences sélectionnées",
|
||||
"validerLePayement_zero": "$t(validerLePayement_other)",
|
||||
"validerLicence.msg_one": "Êtes-vous sûr de vouloir valider la licence ?",
|
||||
"validerLicence.msg_other": "Êtes-vous sûr de vouloir valider les {{count}} licences ?",
|
||||
"validerLicence.msg_zero": "$t(validerLicence.msg_other)",
|
||||
"validerLicence_one": "Valider la licence sélectionnée",
|
||||
"validerLicence_other": "Valider les {{count}} licences sélectionnées",
|
||||
"validerLicence_zero": "$t(validerLicence_other)",
|
||||
"validée": "Validée",
|
||||
"voir/modifierLesParticipants": "Voir/Modifier les participants",
|
||||
"voirLesStatues": "Voir les statues",
|
||||
"vousNêtesPasEncoreInscrit": "Vous n'êtes pas encore inscrit ou votre inscription n'a pas encore été rentrée sur l'intranet",
|
||||
"à": "à",
|
||||
"étatDeLaDemande": "État de la demande"
|
||||
}
|
||||
68
src/main/webapp/public/locales/fr/result.json
Normal file
68
src/main/webapp/public/locales/fr/result.json
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"--sélectionnerUnClub--": "--Sélectionner un club--",
|
||||
"--sélectionnerUnCombattant--": "--Sélectionner un combattant--",
|
||||
"--sélectionnerUneCatégorie--": "--Sélectionner une catégorie--",
|
||||
"abs.": "abs.",
|
||||
"adversaire": "Adversaire",
|
||||
"aujourdhuià": "Aujourd'hui à {{time}}",
|
||||
"avanthierà": "Avant-hier à {{time}}",
|
||||
"back": "« retour",
|
||||
"bleu": "Bleu",
|
||||
"catégorie": "Catégorie",
|
||||
"chargement": "Chargement",
|
||||
"club": "Club",
|
||||
"combattant": "Combattant",
|
||||
"combattants": "Combattants",
|
||||
"date": "Date",
|
||||
"disc.": "disc.",
|
||||
"défaites": "Défaites",
|
||||
"erreurDeChargementDeLaListe": "Erreur de chargement de la liste",
|
||||
"erreurDeChargementDeLaPoule": "Erreur de chargement de la poule",
|
||||
"erreurDeChargementDesCatégories": "Erreur de chargement des catégories",
|
||||
"erreurDeChargementDesClubs": "Erreur de chargement des clubs",
|
||||
"erreurDeChargementDesCombattants": "Erreur de chargement des combattants",
|
||||
"erreurDeChargementDuClub": "Erreur de chargement du club",
|
||||
"erreurDeChargementDuCombattant": "Erreur de chargement du combattant",
|
||||
"for.": "for.",
|
||||
"hierà": "Hier à {{time}}",
|
||||
"info": "Info",
|
||||
"listeDesCombattants": "Liste des combattants",
|
||||
"listeDesMatchs": "Liste des matchs",
|
||||
"listeDesMembres": "Liste des membres",
|
||||
"listeDesMenbres": "Liste des menbres",
|
||||
"nom": "Nom",
|
||||
"nomPrénom": "Nom Prénom",
|
||||
"nombreDeMatchDisputé2": "Nombre de match disputé : {{nb}}",
|
||||
"nombreDeVictoires2": "Nombre de victoires : {{nb}} ",
|
||||
"nombreDinscris": "Nombre d'inscris",
|
||||
"nombreDinscris2": "Nombre d'inscris : {{nb}}",
|
||||
"parCatégorie": "Par catégorie",
|
||||
"parClub": "Par club",
|
||||
"parCombattant": "Par combattant",
|
||||
"place": "Place",
|
||||
"pointsMarqués": "Points marqués",
|
||||
"pointsMarqués2": "Points marqués : {{nb}}",
|
||||
"pointsReçus": "Points reçus",
|
||||
"pointsReçus2": "Points reçus : {{nb}}",
|
||||
"poule": "Poule",
|
||||
"ratio": "Ratio",
|
||||
"ratioDePointsMoyen2": "Ratio de points moyen : {{nb}}",
|
||||
"ratioDeVictoiresMoyen2": "Ratio de victoires moyen : {{nb}}",
|
||||
"ratioDuScore2": "Ratio du score (point marqué / point reçu): {{nb}}",
|
||||
"ratioPoints": "Ratio points",
|
||||
"ratioVictoires": "Ratio victoires",
|
||||
"ratiosPoints": "Ratios points",
|
||||
"rechercheParCatégorie": "Recherche par catégorie",
|
||||
"rechercheParClub": "Recherche par club",
|
||||
"rechercheParCombattant": "Recherche par combattant",
|
||||
"rouge": "Rouge",
|
||||
"résultatDeLaCompétition": "Résultat de la compétition",
|
||||
"score": "Score",
|
||||
"scores": "Scores",
|
||||
"statistique": "Statistique",
|
||||
"tauxDeVictoire2": "Taux de victoire : {{nb}}% ({{victoires}} sur {{matchs}})",
|
||||
"tournois": "Tournois",
|
||||
"tousLesCombattants": "Tous les combattants",
|
||||
"victoire": "Victoire",
|
||||
"victoires": "Victoires"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user