142 Commits

Author SHA1 Message Date
2772e44456 feat: auto fill certificate fields on add licence
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 11m30s
2026-08-06 16:16:47 +02:00
8f0e3c0738 feat: show old member by default 2026-08-06 15:14:30 +02:00
81f6169d41 feat: add licence detail to add log 2026-08-06 15:03:03 +02:00
931c5076b7 feat: update libs 2026-08-06 15:02:44 +02:00
a328e71035 feat: add licence state to membre find result 2026-08-05 16:45:18 +02:00
d3805ea0e7 fix: cache refresh v2
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 7m13s
2026-03-23 22:11:42 +01:00
2d883ca1da fix: cache refresh
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 7m10s
2026-03-23 16:29:11 +01:00
2501b998fa fix: add log in getAllClubArray
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 7m8s
2026-03-23 16:05:09 +01:00
a7c89dbd73 hot fix: remove save score button 2
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m55s
2026-03-21 12:08:45 +01:00
b2ee06d3b9 hot fix: remove save score button
Some checks failed
Deploy Production Server / if_merged (pull_request) Failing after 44s
2026-03-21 11:59:37 +01:00
3ed44bc044 fix: change obs lice name location
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m57s
2026-03-20 16:40:16 +01:00
d091503f19 fix: clear pub aff when no cat select
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 7m3s
2026-03-20 16:10:59 +01:00
ea17989a82 fix: change methode for move upload file
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m59s
2026-03-18 13:07:39 +01:00
e8555f7992 fix: add more log for file copy
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 7m0s
2026-03-18 11:06:40 +01:00
fdd42c6a63 fix: add log for file copy
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 7m1s
2026-03-18 10:48:09 +01:00
ddf530ce4c fix: obs support wss
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 7m8s
2026-03-17 23:16:06 +01:00
286911cf89 fix: language detection
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 7m2s
2026-03-16 12:19:30 +01:00
4bfa6e845d fix: club guest mixing in result
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 7m3s
2026-03-10 13:59:35 +01:00
806ead5b98 fix: eslint version
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 7m29s
2026-03-09 13:19:12 +01:00
ee0a7d87e9 feat: cm Add audio encodeur generator
Some checks failed
Deploy Production Server / if_merged (pull_request) Failing after 34s
2026-03-09 13:07:51 +01:00
812d873d5d fix: Match reorder refresh 2026-03-08 21:58:57 +01:00
d6d9f86254 feat: PDF for classement club 2026-02-27 11:10:31 +01:00
a22225ee7a feat: classement club 2026-02-23 12:01:36 +01:00
2f390b03e2 feat: add podium PDF
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 7m28s
2026-02-19 15:55:46 +01:00
ed5d73c25f feat: improve generation PDF for categories 2026-02-17 21:35:29 +01:00
0a368454c4 fix: duplicate id liceInput1 2026-02-16 22:49:49 +01:00
752f03cba5 feat: PDF for categories 2026-02-16 22:43:14 +01:00
d857fce71f feat: support decimal on weight 2026-02-13 21:42:48 +01:00
2fd09af0ea feat: auto categories full competition 2026-02-13 21:33:19 +01:00
d43cdc1a4e feat: auto categories 2026-02-11 14:08:13 +01:00
8663aa61cf feat: add silver cup png to cm 2026-02-06 18:02:11 +01:00
758e02dc5b feat: remove ^/api$ path log 2026-02-06 17:26:33 +01:00
31315c951a feat: auto poule
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 7m28s
2026-02-06 17:17:44 +01:00
ab4d57985c fix: add classement array in competition.js 2026-02-06 13:23:09 +01:00
2e846bf801 feat: use preset in cmt 2026-02-06 13:15:18 +01:00
9954dd002c feat: add config for preset in category + filter on select comb 2026-02-05 23:53:49 +01:00
7dab5b8880 fix: tree detection on cat edit 2026-02-05 22:32:31 +01:00
b37902466c feat: add team card when comb is register 2026-02-05 22:07:14 +01:00
89d9e04a6f feat: add classement match system 2026-02-05 21:29:27 +01:00
e2197d0712 fix: score panel fonction update 2026-02-01 15:25:49 +01:00
172dcdaa67 fix: ghost selection in PayAndValidateList
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m59s
2026-01-30 15:00:32 +01:00
cdd7221e86 fix: add weight config for all register source 2026-01-30 14:54:44 +01:00
952300d063 feat: card in result view 2026-01-30 14:50:21 +01:00
541d3824f3 feat: update CardModel 2026-01-30 11:58:31 +01:00
4c260b86b9 feat: remove old card system 2026-01-29 22:43:59 +01:00
9018ecef12 feat: card for team 2026-01-29 22:35:54 +01:00
d749dea6f4 feat: add return of table state 2026-01-27 22:11:49 +01:00
189eb135bb wip: competition card system 2026-01-26 22:36:26 +01:00
197ee0d5b1 feat: register import
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m49s
2026-01-23 16:48:09 +01:00
3d8597869d feat: update register export 2026-01-22 19:04:08 +01:00
4a07eb4ed9 feat: comp register optional weight config 2026-01-22 15:13:48 +01:00
d2a7e6cbac feat: rework CatPreset for add more detail + add preset 2026-01-21 22:05:58 +01:00
78d22b466d feat: add lock picto and hide team on register admin + show registration information on user page 2026-01-20 22:53:47 +01:00
b419e2f58d feat: add category registration system to club and user 2026-01-20 21:49:10 +01:00
a5d3973394 feat: add category registration system to admin 2026-01-20 20:21:34 +01:00
4dff0940c1 feat: add docker healthcheck for api 2026-01-18 21:10:20 +01:00
eed7a10cfb feat: select comb double clic support and add background to already select
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m43s
2026-01-18 15:26:16 +01:00
1cbbde6506 feat: add team support to result 2026-01-18 15:10:38 +01:00
e8d5d0fa0c feat: add team support to cm 2026-01-17 22:37:48 +01:00
a5bbc41dfd feat: update js npm lib
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m49s
2026-01-16 16:20:51 +01:00
01436ac220 feat: add match eq support
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m42s
2026-01-16 15:37:23 +01:00
0150c4fac2 fix: translate backend asset includes in native
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m36s
2026-01-16 14:21:46 +01:00
c456fdae8b fix: translate backend add log
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m48s
2026-01-16 13:59:12 +01:00
4bf07cc8f8 Merge pull request 'i18n' (#99) from i18n into master
Reviewed-on: #99
2026-01-16 12:18:53 +00:00
a8356c8663 feat: translate backend
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 7m23s
2026-01-15 16:32:43 +01:00
c7a2215103 feat: translation competition manager part 2026-01-15 14:08:57 +01:00
46f543abde feat: translation competition part 2026-01-14 18:24:26 +01:00
d8b6f1ad25 feat: translation result 2026-01-14 15:51:15 +01:00
9170157dbb feat: init translation 2026-01-13 21:31:05 +01:00
babbc5d585 Merge pull request 'feat: keep showLicenceState in sessionStorage' (#98) from dev into master
Reviewed-on: #98
2026-01-07 21:10:12 +00:00
51c774a21e feat: keep showLicenceState in sessionStorage
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m52s
2026-01-07 22:09:41 +01:00
9d85b9ae45 Merge pull request 'feat: support ha partial config' (#97) from dev into master
Reviewed-on: #97
2026-01-07 15:35:10 +00:00
0ab0731ebd feat: support ha partial config
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m52s
2026-01-07 16:34:57 +01:00
ec48f73d9f Merge pull request 'feat: support ha partial config' (#96) from dev into master
Reviewed-on: #96
2026-01-07 15:24:44 +00:00
f98f1bd1ac feat: support ha partial config
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m59s
2026-01-07 16:24:19 +01:00
b9d752ac55 Merge pull request 'dev' (#95) from dev into master
Reviewed-on: #95
2026-01-05 16:57:01 +00:00
13650b27c1 feat: add selection
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m50s
2026-01-05 17:56:37 +01:00
0757ae7198 feat: allow admin and club admin to get comp result 2026-01-05 14:20:22 +01:00
a871b52006 feat: use blason setting 2026-01-05 11:09:22 +01:00
78959fc485 feat: cma select comb sort by name 2026-01-04 21:29:42 +01:00
0a91e72c29 feat: autorise null mail for admin add 2026-01-04 21:05:20 +01:00
e3a1d1c50b Merge pull request 'dev' (#94) from dev into master
Reviewed-on: #94
2026-01-03 20:50:18 +00:00
3933954e09 feat: add permission setting to admin page
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m44s
2026-01-03 21:49:36 +01:00
959e356fb9 fix: quick add auto complet 2026-01-03 11:22:04 +01:00
3b5955ff31 fix: rm match with cardboard 2026-01-02 23:44:53 +01:00
e8ee5811a0 feat: avoid ws reconnect when user logged out 2026-01-02 23:12:22 +01:00
12326fe122 Merge pull request 'fix: ws timeout' (#93) from dev into master
Reviewed-on: #93
2026-01-02 21:33:40 +00:00
9624ff93f0 fix: ws timeout
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m42s
2026-01-02 22:33:11 +01:00
5444235512 Merge pull request 'dev' (#92) from dev into master
Reviewed-on: #92
2026-01-02 15:00:08 +00:00
b54eaa2549 fix: remove case sensitive sort result
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m44s
2026-01-02 15:58:59 +01:00
6a7af8aea9 fix: tree order on result api 2026-01-02 15:33:56 +01:00
bc4dbb532f fix: remove extra log on recalculateMatch 2026-01-02 15:13:41 +01:00
0e269e0bf7 Merge pull request 'dev' (#91) from dev into master
Reviewed-on: #91
2026-01-02 14:06:09 +00:00
6d6324e1b4 fix: result on empty category
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m45s
2026-01-02 15:05:30 +01:00
309f2a2268 feat: recalculateMatch add tmp log 2026-01-02 15:03:09 +01:00
13bae3e817 Merge pull request 'dev' (#90) from dev into master
Reviewed-on: #90
2026-01-02 13:42:36 +00:00
c6751b0428 fix: recalculateMatch 2026-01-02 14:42:02 +01:00
237952f95a fix: tree order on cmt 2026-01-02 14:29:11 +01:00
075f01a205 feat: add privacy setting in me page
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m53s
2026-01-02 14:09:55 +01:00
82231744af feat: improve result page design 2026-01-02 13:48:36 +01:00
71a4d98434 fix: club remove 2026-01-02 13:47:54 +01:00
29a1184994 feat: add Result Privacy membre setting 2026-01-01 19:43:25 +01:00
3d07a5bc8e Merge pull request 'fix: rm licence' (#89) from dev into master
Reviewed-on: #89
2025-12-31 15:47:55 +00:00
a730384d37 fix: rm licence
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m42s
2025-12-31 16:47:37 +01:00
412e661319 Merge pull request 'fix: cat graphe color and text alignement' (#88) from dev into master
Reviewed-on: #88
2025-12-31 13:50:57 +00:00
bc72b7912c fix: cat graphe color and text alignement
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 6m46s
2025-12-31 14:50:15 +01:00
6359e7e027 Merge pull request 'fix: ci cache' (#87) from dev into master
Reviewed-on: #87
2025-12-31 13:15:42 +00:00
c7a9cc221f fix: ci cache
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 9m31s
2025-12-31 14:15:25 +01:00
17c61be171 Merge pull request 'fix: ci cache' (#86) from dev into master
Reviewed-on: #86
2025-12-31 13:12:17 +00:00
76f69c2154 fix: ci cache
Some checks failed
Deploy Production Server / if_merged (pull_request) Failing after 1m30s
2025-12-31 14:11:43 +01:00
639f07ccdc Merge pull request 'fix: ci cache' (#85) from dev into master
Reviewed-on: #85
2025-12-31 13:07:57 +00:00
c02e37862c fix: ci cache
Some checks failed
Deploy Production Server / if_merged (pull_request) Failing after 2s
2025-12-31 14:07:37 +01:00
2b6dc48880 Merge pull request 'dev' (#84) from dev into master
Reviewed-on: #84
2025-12-31 12:59:50 +00:00
6879d9195d fix: remove useless log
Some checks failed
Deploy Production Server / if_merged (pull_request) Failing after 7s
2025-12-31 13:59:33 +01:00
1595fb57c3 update: config + add action cache 2025-12-31 13:50:28 +01:00
8067d496f8 Merge pull request 'Re-update to 3.30.5' (#83) from dev into master
Reviewed-on: #83
2025-12-31 12:20:08 +00:00
aba8d8a202 Re-update to 3.30.5
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 8m10s
2025-12-31 13:19:31 +01:00
38663d97c2 Merge pull request 'Restore pom.xml' (#82) from dev into master
Reviewed-on: #82
2025-12-29 22:47:27 +00:00
377ce70125 Restore pom.xml
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m36s
2025-12-29 23:47:06 +01:00
61cee85335 Merge pull request 'Restore Quarkus 3.16.4' (#81) from dev into master
Reviewed-on: #81
2025-12-29 22:36:34 +00:00
19949d1e35 Restore Quarkus 3.16.4
Some checks failed
Deploy Production Server / if_merged (pull_request) Failing after 2m35s
2025-12-29 23:36:02 +01:00
03cdcf78c8 Merge pull request 'Move to Quarkus 3.20.4' (#80) from dev into master
Reviewed-on: #80
2025-12-29 22:30:24 +00:00
0b4f843084 Move to Quarkus 3.20.4
Some checks failed
Deploy Production Server / if_merged (pull_request) Failing after 2m20s
2025-12-29 23:30:01 +01:00
fa00273c87 Merge pull request 'Move to Quarkus 3.27.1' (#79) from dev into master
Reviewed-on: #79
2025-12-29 22:24:03 +00:00
b2438e52fc Move to Quarkus 3.27.1
Some checks failed
Deploy Production Server / if_merged (pull_request) Failing after 5m4s
2025-12-29 23:23:42 +01:00
31bbe5719f Merge pull request 'dev' (#78) from dev into master
Reviewed-on: #78
2025-12-29 20:54:30 +00:00
bf377c9c5e feat: external website result connector
Some checks failed
Deploy Production Server / if_merged (pull_request) Failing after 2m31s
2025-12-29 21:03:05 +01:00
145d5e7ca8 feat: update quarkus 2025-12-29 15:41:13 +01:00
448e49b9fd feat: add obs connector 2025-12-28 21:22:28 +01:00
b7a1e58436 fix: cma comb dupli on poule list 2025-12-27 17:34:58 +01:00
a73a3562c3 feat: add scrolle to match list in cmt 2025-12-27 17:29:28 +01:00
0dace76fc3 feat: cat remove 2025-12-27 17:06:27 +01:00
f76ca43ed6 feat: add import fail log detail 2025-12-27 16:55:23 +01:00
c6b24a1b20 feat: add fname formatter 2025-12-27 16:43:14 +01:00
c47c04c29e fix: cat update/add refresh 2025-12-27 15:00:50 +01:00
e06df24002 ty-fix: ws timeout 2025-12-27 14:20:10 +01:00
352c34064f fix: score save update 2025-12-27 14:18:38 +01:00
2ccd2a9178 fix: disable match filter on 1 zone cat + rename lice to zone 2025-12-27 13:02:45 +01:00
0ff3ffd66b Merge pull request 'feat: add club_tresorier to club admin' (#77) from dev into master
Reviewed-on: #77
2025-12-26 21:19:10 +00:00
847674d62c feat: add club_tresorier to club admin
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m46s
2025-12-26 22:18:03 +01:00
8896e2a28a Merge pull request 'fix: delect club without user' (#76) from dev into master
Reviewed-on: #76
2025-12-26 13:37:05 +00:00
68b4f8e476 fix: delect club without user
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m40s
2025-12-26 14:35:19 +01:00
205 changed files with 20289 additions and 5761 deletions

View File

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

1
.gitignore vendored
View File

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

View File

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

18
pom.xml
View File

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

View File

@@ -44,7 +44,9 @@ public class FrontendForwardingFilter implements ContainerResponseFilter {
final String path = info.getPath(); final String path = info.getPath();
final String address = request.remoteAddress().toString(); final String address = request.remoteAddress().toString();
if (!path.equals("/api")) {
LOG.infof("Request %s %s from IP %s", method, path, address); LOG.infof("Request %s %s from IP %s", method, path, address);
}
int status = responseContext.getStatus(); int status = responseContext.getStatus();
if (status != 404 && !(status == 405 && "GET".equals(requestContext.getMethod()))) { if (status != 404 && !(status == 405 && "GET".equals(requestContext.getMethod()))) {

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

View File

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

View File

@@ -1,42 +0,0 @@
package fr.titionfire.ffsaf.data.model;
import io.quarkus.runtime.annotations.RegisterForReflection;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@RegisterForReflection
@Entity
@Table(name = "cardboard")
public class CardboardModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "comb", referencedColumnName = "id")
MembreModel comb;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "guest_comb", referencedColumnName = "id")
CompetitionGuestModel guestComb;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "match", referencedColumnName = "id")
MatchModel match;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "compet", referencedColumnName = "id")
CompetitionModel compet;
int red;
int yellow;
}

View File

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

View File

@@ -44,4 +44,14 @@ public class CategoryModel {
Integer type; Integer type;
String liceName = "1"; String liceName = "1";
@Column(nullable = false, columnDefinition = "boolean default false")
boolean treeAreClassement = false;
@Column(nullable = false, columnDefinition = "boolean default false")
boolean fullClassement = false;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "id_preset", referencedColumnName = "id")
CatPresetModel preset;
} }

View File

@@ -0,0 +1,38 @@
package fr.titionfire.ffsaf.data.model;
import io.quarkus.runtime.annotations.RegisterForReflection;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import java.util.Date;
import java.util.List;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@RegisterForReflection
@Entity
@Table(name = "card_team")
public class ClubCardModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
Long competition;
String teamUuid;
String teamName;
CardModel.CardType type;
String reason;
@CreationTimestamp
Date date;
List<Long> cardIds;
}

View File

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

View File

@@ -2,6 +2,7 @@ package fr.titionfire.ffsaf.data.model;
import fr.titionfire.ffsaf.utils.Categorie; import fr.titionfire.ffsaf.utils.Categorie;
import fr.titionfire.ffsaf.utils.Genre; import fr.titionfire.ffsaf.utils.Genre;
import fr.titionfire.ffsaf.utils.ResultPrivacy;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
import jakarta.persistence.*; import jakarta.persistence.*;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@@ -9,6 +10,11 @@ import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
@Getter @Getter
@Setter @Setter
@AllArgsConstructor @AllArgsConstructor
@@ -17,7 +23,7 @@ import lombok.Setter;
@Entity @Entity
@Table(name = "competition_guest") @Table(name = "competition_guest")
public class CompetitionGuestModel { public class CompetitionGuestModel implements CombModel {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
Long id; Long id;
@@ -37,14 +43,73 @@ public class CompetitionGuestModel {
String country = "fr"; String country = "fr";
Integer weight = null; Float weight = null;
Float weightReal = null;
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
@JoinTable(
name = "groupe_membre",
joinColumns = @JoinColumn(name = "groupe_id"),
inverseJoinColumns = @JoinColumn(name = "membre_id")
)
List<MembreModel> comb = new ArrayList<>();
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
@JoinTable(
name = "groupe_guest",
joinColumns = @JoinColumn(name = "groupe_id"),
inverseJoinColumns = @JoinColumn(name = "guest_id")
)
List<CompetitionGuestModel> guest = new ArrayList<>();
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@JoinTable(
name = "categories_insc_guest",
joinColumns = @JoinColumn(name = "guest_id"),
inverseJoinColumns = @JoinColumn(name = "category_id")
)
List<CatPresetModel> categoriesInscrites = new ArrayList<>();
public CompetitionGuestModel(String s) { public CompetitionGuestModel(String s) {
this.fname = s.substring(0, s.indexOf(" ")); this.fname = s.substring(0, s.indexOf(" "));
this.lname = s.substring(s.indexOf(" ") + 1); this.lname = s.substring(s.indexOf(" ") + 1);
} }
@Override
public Long getCombId() {
return this.id * -1;
}
@Override
public String getName() { public String getName() {
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 Float getWeight2() {
return (this.weightReal != null) ? this.weightReal : this.weight;
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -11,6 +11,9 @@ import lombok.Setter;
import org.hibernate.annotations.OnDelete; import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction; import org.hibernate.annotations.OnDeleteAction;
import java.util.ArrayList;
import java.util.List;
@Getter @Getter
@Setter @Setter
@AllArgsConstructor @AllArgsConstructor
@@ -34,7 +37,8 @@ public class RegisterModel {
@JoinColumn(name = "id_membre") @JoinColumn(name = "id_membre")
MembreModel membre; MembreModel membre;
Integer weight; Float weight;
Float weightReal;
int overCategory = 0; int overCategory = 0;
Categorie categorie; Categorie categorie;
@@ -46,7 +50,18 @@ public class RegisterModel {
@Column(nullable = false, columnDefinition = "boolean default false") @Column(nullable = false, columnDefinition = "boolean default false")
boolean lockEdit = false; boolean lockEdit = false;
public RegisterModel(CompetitionModel competition, MembreModel membre, Integer weight, int overCategory, @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, Float weight, int overCategory,
Categorie categorie, ClubModel club) { Categorie categorie, ClubModel club) {
this.id = new RegisterId(competition.getId(), membre.getId()); this.id = new RegisterId(competition.getId(), membre.getId());
this.competition = competition; this.competition = competition;
@@ -66,4 +81,19 @@ public class RegisterModel {
return membre.club; return membre.club;
return club; return club;
} }
public Categorie getCategorie2() {
Categorie tmp = this.categorie;
if (tmp == null)
tmp = membre.getCategorie();
if (tmp == null)
return null;
return Categorie.values()[Math.min(tmp.ordinal() + this.overCategory, Categorie.values().length - 1)];
}
public Float getWeight2() {
if (weightReal != null)
return weightReal;
return weight;
}
} }

View File

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

View File

@@ -40,6 +40,14 @@ public class TreeModel {
@JoinColumn(referencedColumnName = "id") @JoinColumn(referencedColumnName = "id")
TreeModel right; TreeModel right;
public TreeModel(Long category, Integer level, MatchModel match) {
this.category = category;
this.level = level;
this.match = match;
this.left = null;
this.right = null;
}
public List<TreeModel> flat() { public List<TreeModel> flat() {
List<TreeModel> out = new ArrayList<>(); List<TreeModel> out = new ArrayList<>();
this.flat(out); this.flat(out);
@@ -55,4 +63,44 @@ public class TreeModel {
if (this.left != null) if (this.left != null)
this.left.flat(out); this.left.flat(out);
} }
public int death() {
int dg = 0;
int dd = 0;
if (this.right != null)
dg = this.right.death();
if (this.left != null)
dg = this.left.death();
return 1 + Math.max(dg, dd);
}
public int getMaxChildrenAtDepth(int death, int current) {
if (current == death)
return 1;
int tmp = 0;
if (this.right != null)
tmp += this.right.getMaxChildrenAtDepth(death, current + 1);
if (this.left != null)
tmp += this.left.getMaxChildrenAtDepth(death, current + 1);
return tmp;
}
public void getChildrenAtDepth (int death, int current, List<TreeModel> out) {
if (current == death) {
out.add(this);
return;
}
if (this.right != null)
this.right.getChildrenAtDepth(death, current + 1, out);
if (this.left != null)
this.left.getChildrenAtDepth(death, current + 1, out);
}
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -20,6 +20,9 @@ public class MatchRepository implements PanacheRepositoryBase<MatchModel, Long>
} }
public Uni<Void> create(List<MatchModel> matchModel) { public Uni<Void> create(List<MatchModel> matchModel) {
if (matchModel.isEmpty())
return Uni.createFrom().voidItem();
matchModel.forEach(model -> model.setSystem(CompetitionSystem.INTERNAL)); matchModel.forEach(model -> model.setSystem(CompetitionSystem.INTERNAL));
return Panache.withTransaction(() -> this.persist(matchModel) return Panache.withTransaction(() -> this.persist(matchModel)
.call(__ -> this.flush()) .call(__ -> this.flush())

View File

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

View File

@@ -1,26 +0,0 @@
package fr.titionfire.ffsaf.domain.entity;
import fr.titionfire.ffsaf.data.model.CardboardModel;
import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
@RegisterForReflection
public class CardboardEntity {
long comb_id;
long match_id;
long compet_id;
int red;
int yellow;
public static CardboardEntity fromModel(CardboardModel model) {
return new CardboardEntity(
model.getComb() != null ? model.getComb().getId() : model.getGuestComb().getId() * -1,
model.getMatch().getId(),
model.getCompet().getId(),
model.getRed(), model.getYellow());
}
}

View File

@@ -1,5 +1,6 @@
package fr.titionfire.ffsaf.domain.entity; package fr.titionfire.ffsaf.domain.entity;
import fr.titionfire.ffsaf.data.model.CatPresetModel;
import fr.titionfire.ffsaf.data.model.CompetitionGuestModel; import fr.titionfire.ffsaf.data.model.CompetitionGuestModel;
import fr.titionfire.ffsaf.data.model.MembreModel; import fr.titionfire.ffsaf.data.model.MembreModel;
import fr.titionfire.ffsaf.data.model.RegisterModel; import fr.titionfire.ffsaf.data.model.RegisterModel;
@@ -9,6 +10,10 @@ import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@RegisterForReflection @RegisterForReflection
@@ -22,7 +27,9 @@ public class CombEntity {
Genre genre; Genre genre;
String country; String country;
int overCategory; int overCategory;
Integer weight; Float weight;
List<CombEntity> teamMembers;
List<Long> categoriesInscrites;
public static CombEntity fromModel(MembreModel model) { public static CombEntity fromModel(MembreModel model) {
if (model == null) if (model == null)
@@ -31,7 +38,7 @@ public class CombEntity {
return new CombEntity(model.getId(), model.getLname(), model.getFname(), model.getCategorie(), return new CombEntity(model.getId(), model.getLname(), model.getFname(), model.getCategorie(),
model.getClub() == null ? null : model.getClub().getClubId(), model.getClub() == null ? null : model.getClub().getClubId(),
model.getClub() == null ? "Sans club" : model.getClub().getName(), model.getGenre(), model.getCountry(), model.getClub() == null ? "Sans club" : model.getClub().getName(), model.getGenre(), model.getCountry(),
0, null); 0, null, new ArrayList<>(), new ArrayList<>());
} }
@@ -40,7 +47,18 @@ public class CombEntity {
return null; return null;
return new CombEntity(model.getId() * -1, model.getLname(), model.getFname(), model.getCategorie(), null, return new CombEntity(model.getId() * -1, model.getLname(), model.getFname(), model.getCategorie(), null,
model.getClub(), model.getGenre(), model.getCountry(), 0, model.getWeight()); model.getClub(), model.getGenre(), model.getCountry(), 0,
model.getWeight2() != null ? model.getWeight2() : model.getWeight(),
Stream.concat(model.getComb().stream().map(CombEntity::fromModel),
model.getGuest().stream().map(CombEntity::fromModel)).toList(),
new ArrayList<>());
}
public CombEntity addCategoriesInscrites(List<CatPresetModel> categoriesInscrites) {
if (categoriesInscrites == null)
return this;
this.categoriesInscrites = categoriesInscrites.stream().map(CatPresetModel::getId).toList();
return this;
} }
public static CombEntity fromModel(RegisterModel registerModel) { public static CombEntity fromModel(RegisterModel registerModel) {
@@ -51,6 +69,8 @@ public class CombEntity {
return new CombEntity(model.getId(), model.getLname(), model.getFname(), registerModel.getCategorie(), return new CombEntity(model.getId(), model.getLname(), model.getFname(), registerModel.getCategorie(),
registerModel.getClub2() == null ? null : registerModel.getClub2().getClubId(), registerModel.getClub2() == null ? null : registerModel.getClub2().getClubId(),
registerModel.getClub2() == null ? "Sans club" : registerModel.getClub2().getName(), model.getGenre(), registerModel.getClub2() == null ? "Sans club" : registerModel.getClub2().getName(), model.getGenre(),
model.getCountry(), registerModel.getOverCategory(), registerModel.getWeight()); model.getCountry(), registerModel.getOverCategory(),
registerModel.getWeight2() != null ? registerModel.getWeight2() : registerModel.getWeight(),
new ArrayList<>(), new ArrayList<>());
} }
} }

View File

@@ -6,7 +6,6 @@ import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@@ -23,7 +22,6 @@ public class MatchEntity {
private Date date; private Date date;
private List<ScoreEmbeddable> scores; private List<ScoreEmbeddable> scores;
private char poule; private char poule;
private List<CardboardEntity> cardboard;
public static MatchEntity fromModel(MatchModel model) { public static MatchEntity fromModel(MatchModel model) {
if (model == null) if (model == null)
@@ -35,22 +33,6 @@ public class MatchEntity {
model.getC2_id()), model.getC2_id()),
model.getCategory_ord(), model.isEnd(), model.getCategory().getId(), model.getDate(), model.getCategory_ord(), model.isEnd(), model.getCategory().getId(), model.getDate(),
model.getScores(), model.getScores(),
model.getPoule(), model.getPoule());
(model.getCardboard() == null) ? new ArrayList<>() : model.getCardboard().stream()
.map(CardboardEntity::fromModel).toList());
}
public int win() {
int sum = 0;
for (ScoreEmbeddable score : scores) {
if (score.getS1() == -1000 || score.getS2() == -1000)
continue;
if (score.getS1() > score.getS2())
sum++;
else if (score.getS1() < score.getS2())
sum--;
}
return sum;
} }
} }

View File

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

View File

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

View File

@@ -64,6 +64,9 @@ public class AffiliationService {
@Inject @Inject
LoggerService ls; LoggerService ls;
@Inject
VirusScannerService scanner;
@RestClient @RestClient
StateIdService stateIdService; StateIdService stateIdService;
@@ -76,6 +79,9 @@ public class AffiliationService {
@ConfigProperty(name = "notif.affRequest.mail") @ConfigProperty(name = "notif.affRequest.mail")
List<String> mails; List<String> mails;
@Inject
TradService trad;
public Uni<List<AffiliationRequestModel>> getAllReq() { public Uni<List<AffiliationRequestModel>> getAllReq() {
return repositoryRequest.listAll(); return repositoryRequest.listAll();
} }
@@ -89,7 +95,7 @@ public class AffiliationService {
return Uni.createFrom().item(affModel) return Uni.createFrom().item(affModel)
.invoke(Unchecked.consumer(model -> { .invoke(Unchecked.consumer(model -> {
if (model.getSaison() != currentSaison && model.getSaison() != currentSaison + 1) { if (model.getSaison() != currentSaison && model.getSaison() != currentSaison + 1) {
throw new DBadRequestException("Saison non valid"); throw new DBadRequestException(trad.t("saison.non.valid"));
} }
})) }))
.chain(() -> ((affModel.getState_id().charAt(0) == 'W') ? stateIdService.get_rna( .chain(() -> ((affModel.getState_id().charAt(0) == 'W') ? stateIdService.get_rna(
@@ -107,7 +113,7 @@ public class AffiliationService {
out, affModel.getSaison())) out, affModel.getSaison()))
.onItem().invoke(Unchecked.consumer(count -> { .onItem().invoke(Unchecked.consumer(count -> {
if (count != 0 && unique) { if (count != 0 && unique) {
throw new DBadRequestException("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()))) repository.count("club = ?1 and saison = ?2", club, affModel.getSaison())))
.onItem().invoke(Unchecked.consumer(count -> { .onItem().invoke(Unchecked.consumer(count -> {
if (count != 0) { if (count != 0) {
throw new DBadRequestException("Affiliation déjà existante"); throw new DBadRequestException(trad.t("affiliation.deja.existante"));
} }
})) }))
.map(o -> affModel) .map(o -> affModel)
.call(model -> ((model.getM1_lincence() != -1) ? combRepository.find("licence", .call(model -> ((model.getM1_lincence() != -1) ? combRepository.find("licence",
model.getM1_lincence()).count().invoke(Unchecked.consumer(count -> { model.getM1_lincence()).count().invoke(Unchecked.consumer(count -> {
if (count == 0) { if (count == 0) {
throw new DBadRequestException("Licence membre n°1 inconnue"); throw new DBadRequestException(trad.t("licence.membre.n.1.inconnue"));
} }
})) : Uni.createFrom().nullItem()) })) : Uni.createFrom().nullItem())
) )
.call(model -> ((model.getM2_lincence() != -1) ? combRepository.find("licence", .call(model -> ((model.getM2_lincence() != -1) ? combRepository.find("licence",
model.getM2_lincence()).count().invoke(Unchecked.consumer(count -> { model.getM2_lincence()).count().invoke(Unchecked.consumer(count -> {
if (count == 0) { if (count == 0) {
throw new DBadRequestException("Licence membre n°2 inconnue"); throw new DBadRequestException(trad.t("licence.membre.n.2.inconnue"));
} }
})) : Uni.createFrom().nullItem()) })) : Uni.createFrom().nullItem())
) )
.call(model -> ((model.getM3_lincence() != -1) ? combRepository.find("licence", .call(model -> ((model.getM3_lincence() != -1) ? combRepository.find("licence",
model.getM3_lincence()).count().invoke(Unchecked.consumer(count -> { model.getM3_lincence()).count().invoke(Unchecked.consumer(count -> {
if (count == 0) { if (count == 0) {
throw new DBadRequestException("Licence membre n°3 inconnue"); throw new DBadRequestException(trad.t("licence.membre.n.3.inconnue"));
} }
})) : Uni.createFrom().nullItem()) })) : Uni.createFrom().nullItem())
); );
@@ -145,7 +151,7 @@ public class AffiliationService {
public Uni<?> saveEdit(AffiliationRequestForm form) { public Uni<?> saveEdit(AffiliationRequestForm form) {
return pre_save(form, false) return pre_save(form, false)
.chain(model -> repositoryRequest.findById(form.getId()) .chain(model -> repositoryRequest.findById(form.getId())
.onItem().ifNull().failWith(new DNotFoundException("Demande d'affiliation non trouvé")) .onItem().ifNull().failWith(new DNotFoundException(trad.t("demande.d.affiliation.non.trouve")))
.chain(origine -> { .chain(origine -> {
origine.setName(model.getName()); origine.setName(model.getName());
origine.setAddress(model.getAddress()); origine.setAddress(model.getAddress());
@@ -174,15 +180,12 @@ public class AffiliationService {
LOGGER.debug("Affiliation Request Created"); LOGGER.debug("Affiliation Request Created");
LOGGER.debug(form.toString()); LOGGER.debug(form.toString());
// noinspection ResultOfMethodCallIgnored,ReactiveStreamsUnusedPublisher // noinspection ReactiveStreamsUnusedPublisher
return pre_save(form, true) return pre_save(form, true)
.chain(model -> Panache.withTransaction(() -> repositoryRequest.persist(model))) .chain(model -> Panache.withTransaction(() -> repositoryRequest.persist(model)))
.onItem() .onItem()
.invoke(model -> Uni.createFrom().future(Utils.replacePhoto(model.getId(), form.getLogo(), media, .invoke(m -> Utils.uploadFile(scanner, form.getLogo(), m.getId(), media, "aff_request/logo"))
"aff_request/logo"))) .invoke(m -> Utils.uploadFile(scanner, form.getStatus(), m.getId(), media, "aff_request/status"))
.onItem()
.invoke(model -> Uni.createFrom().future(Utils.replacePhoto(model.getId(), form.getStatus(), media,
"aff_request/status")))
.call(model -> reactiveMailer.send( .call(model -> reactiveMailer.send(
Mail.withText("no-reply@ffsaf.fr", Mail.withText("no-reply@ffsaf.fr",
"[NOTIF] FFSAF - Nouvelle demande d'affiliation", "[NOTIF] FFSAF - Nouvelle demande d'affiliation",
@@ -201,7 +204,7 @@ public class AffiliationService {
LOGGER.debug(form.toString()); LOGGER.debug(form.toString());
return repositoryRequest.findById(form.getId()) return repositoryRequest.findById(form.getId())
.onItem().ifNull().failWith(new DNotFoundException("Demande d'affiliation non trouvé")) .onItem().ifNull().failWith(new DNotFoundException(trad.t("demande.d.affiliation.non.trouve")))
.map(model -> { .map(model -> {
model.setName(form.getName()); model.setName(form.getName());
model.setState_id(form.getState_id()); model.setState_id(form.getState_id());
@@ -245,11 +248,8 @@ public class AffiliationService {
}) })
.chain(model -> Panache.withTransaction(() -> repositoryRequest.persist(model))) .chain(model -> Panache.withTransaction(() -> repositoryRequest.persist(model)))
.onItem() .onItem()
.invoke(model -> Uni.createFrom().future(Utils.replacePhoto(model.getId(), form.getLogo(), media, .invoke(m -> Utils.uploadFile(scanner, form.getLogo(), m.getId(), media, "aff_request/logo"))
"aff_request/logo"))) .invoke(m -> Utils.uploadFile(scanner, form.getStatus(), m.getId(), media, "aff_request/status"))
.onItem()
.invoke(model -> Uni.createFrom().future(Utils.replacePhoto(model.getId(), form.getStatus(), media,
"aff_request/status")))
.map(__ -> "Ok"); .map(__ -> "Ok");
} }
@@ -309,7 +309,7 @@ public class AffiliationService {
LOGGER.debug(form.toString()); LOGGER.debug(form.toString());
return repositoryRequest.findById(form.getId()) return repositoryRequest.findById(form.getId())
.onItem().ifNull().failWith(new DNotFoundException("Demande d'affiliation non trouvé")) .onItem().ifNull().failWith(new DNotFoundException(trad.t("demande.d.affiliation.non.trouve")))
.chain(req -> .chain(req ->
clubRepository.find("StateId = ?1", form.getState_id()).firstResult() clubRepository.find("StateId = ?1", form.getState_id()).firstResult()
.chain(model -> (model == null) ? acceptNew(form, req) : acceptOld(form, req, model)) .chain(model -> (model == null) ? acceptNew(form, req) : acceptOld(form, req, model))
@@ -319,13 +319,11 @@ public class AffiliationService {
.recoverWithNull() .recoverWithNull()
.call(___ -> setMembre(form.new Member(3), club, req.getSaison())))) .call(___ -> setMembre(form.new Member(3), club, req.getSaison()))))
.onItem() .onItem()
.invoke(model -> Uni.createFrom() .invoke(model -> Utils.uploadFile(scanner, form.getLogo(), form.getId(), media,
.future(Utils.replacePhoto(form.getId(), form.getLogo(), media, "aff_request/logo"))
"aff_request/logo"))) .invoke(model -> Utils.uploadFile(scanner, form.getStatus(), form.getId(), media,
"aff_request/status"))
.onItem() .onItem()
.invoke(model -> Uni.createFrom()
.future(Utils.replacePhoto(form.getId(), form.getStatus(), media,
"aff_request/status")))
.call(model -> Utils.moveMedia(form.getId(), model.getId(), media, "aff_request/logo", .call(model -> Utils.moveMedia(form.getId(), model.getId(), media, "aff_request/logo",
"ppClub")) "ppClub"))
.call(model -> Utils.moveMedia(form.getId(), model.getId(), media, "aff_request/status", .call(model -> Utils.moveMedia(form.getId(), model.getId(), media, "aff_request/status",
@@ -403,7 +401,7 @@ public class AffiliationService {
public Uni<SimpleReqAffiliation> getRequest(long id) { public Uni<SimpleReqAffiliation> getRequest(long id) {
return repositoryRequest.findById(id).map(SimpleReqAffiliation::fromModel) return repositoryRequest.findById(id).map(SimpleReqAffiliation::fromModel)
.onItem().ifNull().failWith(new DNotFoundException("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 -> { .call(out -> clubRepository.find("StateId = ?1", out.getStateId()).firstResult().invoke(c -> {
if (c != null) { if (c != null) {
out.setClub(c.getId()); out.setClub(c.getId());
@@ -427,7 +425,7 @@ public class AffiliationService {
public Uni<List<SimpleAffiliation>> getAffiliation(long id) { public Uni<List<SimpleAffiliation>> getAffiliation(long id) {
return clubRepository.findById(id) return clubRepository.findById(id)
.onItem().ifNull().failWith(new DNotFoundException("Club non trouvé")) .onItem().ifNull().failWith(new DNotFoundException(trad.t("club.non.trouve")))
.call(model -> Mutiny.fetch(model.getAffiliations())) .call(model -> Mutiny.fetch(model.getAffiliations()))
.chain(model -> repositoryRequest.list("state_id = ?1", model.getStateId()) .chain(model -> repositoryRequest.list("state_id = ?1", model.getStateId())
.map(reqs -> reqs.stream().map(req -> .map(reqs -> reqs.stream().map(req ->
@@ -439,11 +437,11 @@ public class AffiliationService {
public Uni<SimpleAffiliation> setAffiliation(long id, int saison) { public Uni<SimpleAffiliation> setAffiliation(long id, int saison) {
return clubRepository.findById(id) return clubRepository.findById(id)
.onItem().ifNull().failWith(new DNotFoundException("Club non trouvé")) .onItem().ifNull().failWith(new DNotFoundException(trad.t("club.non.trouve")))
.call(model -> Mutiny.fetch(model.getAffiliations())) .call(model -> Mutiny.fetch(model.getAffiliations()))
.invoke(Unchecked.consumer(club -> { .invoke(Unchecked.consumer(club -> {
if (club.getAffiliations().stream().anyMatch(affiliation -> affiliation.getSaison() == saison)) { if (club.getAffiliations().stream().anyMatch(affiliation -> affiliation.getSaison() == saison)) {
throw new DBadRequestException("Affiliation déjà existante"); throw new DBadRequestException(trad.t("affiliation.deja.existante"));
} }
})) }))
.chain(club -> .chain(club ->

View File

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

View File

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

View File

@@ -58,7 +58,7 @@ public class CheckoutService {
String organizationSlug; String organizationSlug;
public Uni<Boolean> canDeleteLicence(long id) { public Uni<Boolean> canDeleteLicence(long id) {
return repository.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) { public Uni<String> create(List<Long> ids, SecurityCtx securityCtx) {

View File

@@ -63,6 +63,9 @@ public class ClubService {
@Inject @Inject
LoggerService ls; LoggerService ls;
@Inject
TradService trad;
public SimpleClubModel findByIdOptionalClub(long id) throws Throwable { public SimpleClubModel findByIdOptionalClub(long id) throws Throwable {
return VertxContextSupport.subscribeAndAwait( return VertxContextSupport.subscribeAndAwait(
() -> Panache.withTransaction(() -> repository.findById(id).map(SimpleClubModel::fromModel))); () -> Panache.withTransaction(() -> repository.findById(id).map(SimpleClubModel::fromModel)));
@@ -130,7 +133,7 @@ public class ClubService {
return combRepository.find("userId = ?1", securityCtx.getSubject()).firstResult() return combRepository.find("userId = ?1", securityCtx.getSubject()).firstResult()
.invoke(Unchecked.consumer(m -> { .invoke(Unchecked.consumer(m -> {
if (m == null || m.getClub() == null) if (m == null || m.getClub() == null)
throw new DNotFoundException("Club non trouvé"); throw new DNotFoundException(trad.t("club.non.trouve"));
})) }))
.map(MembreModel::getClub) .map(MembreModel::getClub)
.call(club -> Mutiny.fetch(club.getContact())); .call(club -> Mutiny.fetch(club.getContact()));
@@ -150,7 +153,7 @@ public class ClubService {
return combRepository.find("userId = ?1", securityCtx.getSubject()).firstResult() return combRepository.find("userId = ?1", securityCtx.getSubject()).firstResult()
.invoke(Unchecked.consumer(m -> { .invoke(Unchecked.consumer(m -> {
if (m == null || m.getClub() == null) if (m == null || m.getClub() == null)
throw new DNotFoundException("Club non trouvé"); throw new DNotFoundException(trad.t("club.non.trouve"));
if (!securityCtx.isInClubGroup(m.getClub().getId())) if (!securityCtx.isInClubGroup(m.getClub().getId()))
throw new DForbiddenException(); throw new DForbiddenException();
})) }))
@@ -166,7 +169,7 @@ public class ClubService {
return combRepository.find("userId = ?1", securityCtx.getSubject()).firstResult() return combRepository.find("userId = ?1", securityCtx.getSubject()).firstResult()
.invoke(Unchecked.consumer(m -> { .invoke(Unchecked.consumer(m -> {
if (m == null || m.getClub() == null) if (m == null || m.getClub() == null)
throw new DNotFoundException("Club non trouvé"); throw new DNotFoundException(trad.t("club.non.trouve"));
if (!securityCtx.isInClubGroup(m.getClub().getId())) if (!securityCtx.isInClubGroup(m.getClub().getId()))
throw new DForbiddenException(); throw new DForbiddenException();
})) }))
@@ -183,7 +186,7 @@ public class ClubService {
ls.logUpdate("Contact(s)...", club); ls.logUpdate("Contact(s)...", club);
club.setContact(MAPPER.readValue(form.getContact(), typeRef)); club.setContact(MAPPER.readValue(form.getContact(), typeRef));
} catch (JsonProcessingException e) { } catch (JsonProcessingException e) {
throw new DBadRequestException("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(), ls.logChange("Lieux d'entrainements", club.getTraining_location(), form.getTraining_location(),
@@ -233,7 +236,7 @@ public class ClubService {
ls.logUpdate("Contact(s)...", m); ls.logUpdate("Contact(s)...", m);
m.setContact(MAPPER.readValue(input.getContact(), typeRef)); m.setContact(MAPPER.readValue(input.getContact(), typeRef));
} catch (JsonProcessingException e) { } catch (JsonProcessingException e) {
throw new DBadRequestException("Erreur de format des contacts"); throw new DBadRequestException(trad.t("erreur.de.format.des.contacts"));
} }
} }
return Panache.withTransaction(() -> repository.persist(m)).call(() -> ls.append()); return Panache.withTransaction(() -> repository.persist(m)).call(() -> ls.append());
@@ -287,11 +290,13 @@ public class ClubService {
combModel.setClub(null); combModel.setClub(null);
combModel.setRole(RoleAsso.MEMBRE); combModel.setRole(RoleAsso.MEMBRE);
}).toList()) }).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) Uni.join().all(list.stream().filter(m -> m.getUserId() != null)
.map(m -> keycloakService.clearUser(m.getUserId())).toList()) .map(m -> keycloakService.clearUser(m.getUserId())).toList())
.andCollectFailures()) .andCollectFailures())
.chain(list -> Panache.withTransaction(() -> combRepository.persist(list))) .chain(list -> list.isEmpty() ? Uni.createFrom().voidItem() :
Panache.withTransaction(() -> combRepository.persist(list)))
.map(o -> club) .map(o -> club)
) )
.call(clubModel -> (clubModel.getClubId() == null) ? Uni.createFrom() .call(clubModel -> (clubModel.getClubId() == null) ? Uni.createFrom()

View File

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

View File

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

View File

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

View File

@@ -377,11 +377,19 @@ public class KeycloakService {
public Optional<UserRepresentation> getUser(UUID userId) { public Optional<UserRepresentation> getUser(UUID userId) {
UserResource user = keycloak.realm(realm).users().get(userId.toString()); return getUserById(userId.toString());
}
public Optional<UserRepresentation> getUserById(String userId) {
try {
UserResource user = keycloak.realm(realm).users().get(userId);
if (user == null) if (user == null)
return Optional.empty(); return Optional.empty();
else else
return Optional.of(user.toRepresentation()); return Optional.of(user.toRepresentation());
} catch (Exception e) {
return Optional.empty();
}
} }
private String makeLogin(MembreModel model) { private String makeLogin(MembreModel model) {

View File

@@ -47,6 +47,9 @@ public class LicenceService {
@Inject @Inject
CheckoutService checkoutService; CheckoutService checkoutService;
@Inject
TradService trad;
public Uni<List<LicenceModel>> getLicence(long id, Consumer<MembreModel> checkPerm) { public Uni<List<LicenceModel>> getLicence(long id, Consumer<MembreModel> checkPerm) {
return combRepository.findById(id).invoke(checkPerm) return combRepository.findById(id).invoke(checkPerm)
.chain(combRepository -> Mutiny.fetch(combRepository.getLicences())); .chain(combRepository -> Mutiny.fetch(combRepository.getLicences()));
@@ -119,7 +122,9 @@ public class LicenceService {
.call(genLicenceNumberAndAccountIfNeed()) .call(genLicenceNumberAndAccountIfNeed())
: Uni.createFrom().nullItem() : Uni.createFrom().nullItem()
)) ))
.call(licenceModel -> ls.logA(LogModel.ActionType.ADD, membreModel.getObjectName(), .call(licenceModel -> ls.logA(LogModel.ActionType.ADD,
"%s (valid=%b, pay=%b, %s)" .formatted(membreModel.getObjectName(), model.isValidate(),
model.isPay(), model.getCertificate()),
licenceModel)); licenceModel));
}); });
} else { } else {
@@ -157,7 +162,7 @@ public class LicenceService {
return repository.list("membre.id IN ?1 AND saison = ?2 AND pay = FALSE", ids, Utils.getSaison()) return repository.list("membre.id IN ?1 AND saison = ?2 AND pay = FALSE", ids, Utils.getSaison())
.invoke(Unchecked.consumer(models -> { .invoke(Unchecked.consumer(models -> {
if (models.size() != ids.size()) if (models.size() != ids.size())
throw new DBadRequestException("Erreur lors de lalection des membres"); throw new DBadRequestException(trad.t("erreur.lors.de.la.selection.des.membres"));
})) }))
.call(models -> { .call(models -> {
Uni<?> uni = Uni.createFrom().nullItem(); Uni<?> uni = Uni.createFrom().nullItem();
@@ -174,7 +179,7 @@ public class LicenceService {
.call(__ -> checkoutService.canDeleteLicence(id) .call(__ -> checkoutService.canDeleteLicence(id)
.invoke(Unchecked.consumer(b -> { .invoke(Unchecked.consumer(b -> {
if (!b) throw new DBadRequestException( if (!b) throw new DBadRequestException(
"Impossible de supprimer une licence pour laquelle un paiement est en cours"); trad.t("licence.rm.err1"));
}))) })))
.call(model -> ls.logADelete(model)) .call(model -> ls.logADelete(model))
.chain(model -> Panache.withTransaction(() -> repository.delete(model))); .chain(model -> Panache.withTransaction(() -> repository.delete(model)));
@@ -186,7 +191,7 @@ public class LicenceService {
return repository.find("saison = ?1 AND membre = ?2", Utils.getSaison(), membreModel).count() return repository.find("saison = ?1 AND membre = ?2", Utils.getSaison(), membreModel).count()
.invoke(Unchecked.consumer(count -> { .invoke(Unchecked.consumer(count -> {
if (count > 0) if (count > 0)
throw new DBadRequestException("Licence déjà demandée"); throw new DBadRequestException(trad.t("licence.deja.demandee"));
})).chain(__ -> combRepository.findById(id).chain(membreModel2 -> { })).chain(__ -> combRepository.findById(id).chain(membreModel2 -> {
LicenceModel model = new LicenceModel(); LicenceModel model = new LicenceModel();
model.setClub_id((membreModel2.getClub() == null) ? null : membreModel2.getClub().getId()); model.setClub_id((membreModel2.getClub() == null) ? null : membreModel2.getClub().getId());
@@ -215,13 +220,13 @@ public class LicenceService {
.call(__ -> checkoutService.canDeleteLicence(id) .call(__ -> checkoutService.canDeleteLicence(id)
.invoke(Unchecked.consumer(b -> { .invoke(Unchecked.consumer(b -> {
if (!b) throw new DBadRequestException( if (!b) throw new DBadRequestException(
"Impossible de supprimer une licence pour laquelle un paiement est en cours"); trad.t("licence.rm.err1"));
}))) })))
.invoke(Unchecked.consumer(licenceModel -> { .invoke(Unchecked.consumer(licenceModel -> {
if (licenceModel.isValidate()) 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()) 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)) .call(model -> ls.logADelete(model))
.chain(__ -> Panache.withTransaction(() -> repository.deleteById(id))); .chain(__ -> Panache.withTransaction(() -> repository.deleteById(id)));

View File

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

View File

@@ -7,14 +7,12 @@ import fr.titionfire.ffsaf.data.repository.*;
import fr.titionfire.ffsaf.net2.ServerCustom; import fr.titionfire.ffsaf.net2.ServerCustom;
import fr.titionfire.ffsaf.net2.data.SimpleCombModel; import fr.titionfire.ffsaf.net2.data.SimpleCombModel;
import fr.titionfire.ffsaf.net2.request.SReqComb; import fr.titionfire.ffsaf.net2.request.SReqComb;
import fr.titionfire.ffsaf.rest.data.MeData; import fr.titionfire.ffsaf.rest.data.*;
import fr.titionfire.ffsaf.rest.data.SimpleLicence;
import fr.titionfire.ffsaf.rest.data.SimpleMembre;
import fr.titionfire.ffsaf.rest.data.SimpleMembreInOutData;
import fr.titionfire.ffsaf.rest.exception.DBadRequestException; import fr.titionfire.ffsaf.rest.exception.DBadRequestException;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException; import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.rest.exception.DInternalError; import fr.titionfire.ffsaf.rest.exception.DInternalError;
import fr.titionfire.ffsaf.rest.from.FullMemberForm; import fr.titionfire.ffsaf.rest.from.FullMemberForm;
import fr.titionfire.ffsaf.rest.from.UserSettingForm;
import fr.titionfire.ffsaf.utils.*; import fr.titionfire.ffsaf.utils.*;
import io.quarkus.hibernate.reactive.panache.Panache; import io.quarkus.hibernate.reactive.panache.Panache;
import io.quarkus.hibernate.reactive.panache.PanacheQuery; import io.quarkus.hibernate.reactive.panache.PanacheQuery;
@@ -64,6 +62,9 @@ public class MembreService {
@Inject @Inject
LoggerService ls; LoggerService ls;
@Inject
TradService trad;
public SimpleCombModel find(int licence, String np) throws Throwable { public SimpleCombModel find(int licence, String np) throws Throwable {
return VertxContextSupport.subscribeAndAwait(() -> Panache.withTransaction(() -> return VertxContextSupport.subscribeAndAwait(() -> Panache.withTransaction(() ->
repository.find( repository.find(
@@ -158,7 +159,7 @@ public class MembreService {
"EXISTS (SELECT 1 FROM LicenceModel l WHERE l.membre.id = m.id AND l.saison >= %s)", "EXISTS (SELECT 1 FROM LicenceModel l WHERE l.membre.id = m.id AND l.saison >= %s)",
Utils.getSaison() - 1); Utils.getSaison() - 1);
String clubFilter = "?3 = ?3"; String clubFilter = "(TRUE OR ?3 = ?3)";
if (club != null) { if (club != null) {
if (club instanceof String club_) { if (club instanceof String club_) {
if (!club_.isBlank()) { if (!club_.isBlank()) {
@@ -179,15 +180,21 @@ public class MembreService {
Sort sort = getSort(order); Sort sort = getSort(order);
if (sort == null) 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")));
String finalSearch = search; String finalSearch = search;
return getLicenceListe(licenceRequest, payState) return getLicenceListe(licenceRequest, payState)
.map(l -> l.stream().map(l2 -> l2.getMembre().getId()).toList()) .chain(l -> {
.chain(ids -> {
PanacheQuery<MembreModel> query; PanacheQuery<MembreModel> query;
query = repository.find(queryStr, sort, finalSearch, ids, club).page(Page.ofSize(limit)); query = repository.find(queryStr, sort, finalSearch,
return getPageResult(query, limit, page); l.stream().map(l2 -> l2.getMembre().getId()).toList(), club).page(Page.ofSize(limit));
return getPageResult(query, limit, page)
.call(r -> (r.getResult().isEmpty() || !l.isEmpty() ?
Uni.createFrom().item(l) :
licenceRepository.list("saison = ?1 AND membre.id IN ?2", Utils.getSaison(),
r.getResult().stream().map(SimpleMembre::getId).toList()))
.invoke(l2 -> r.setAdditionalData(l2.stream().map(SimpleLicence::fromModel)))
);
}); });
} }
@@ -198,7 +205,7 @@ public class MembreService {
.call(result -> query.count().invoke(result::setResult_count)) .call(result -> query.count().invoke(result::setResult_count))
.call(result -> query.pageCount() .call(result -> query.pageCount()
.invoke(Unchecked.consumer(pages -> { .invoke(Unchecked.consumer(pages -> {
if (page > pages) throw new DBadRequestException("Page out of range"); if (page > pages) throw new DBadRequestException(trad.t("page.out.of.range"));
})) }))
.invoke(result::setPage_count)) .invoke(result::setPage_count))
.call(result -> query.page(Page.of(page, limit)).list() .call(result -> query.page(Page.of(page, limit)).list()
@@ -209,7 +216,7 @@ public class MembreService {
public Uni<List<SimpleMembreInOutData>> getAllExport(String subject) { public Uni<List<SimpleMembreInOutData>> getAllExport(String subject) {
return repository.find("userId = ?1", subject).firstResult() return repository.find("userId = ?1", subject).firstResult()
.chain(membreModel -> repository.list("club = ?1", membreModel.getClub())) .chain(membreModel -> repository.list("club = ?1", membreModel.getClub()))
.chain(membres -> licenceRepository.list("saison = ?1 AND membre IN ?2", Utils.getSaison(), membres) .chain(membres -> licenceRepository.list("membre IN ?1", membres)
.map(l -> membres.stream().map(m -> SimpleMembreInOutData.fromModel(m, l)).toList())); .map(l -> membres.stream().map(m -> SimpleMembreInOutData.fromModel(m, l)).toList()));
} }
@@ -243,8 +250,8 @@ public class MembreService {
for (MembreModel membreModel : membres) { for (MembreModel membreModel : membres) {
if (!Objects.equals(membreModel.getClub(), clubModel.get())) { if (!Objects.equals(membreModel.getClub(), clubModel.get())) {
LOGGER.info("Similar membres found: " + membreModel); LOGGER.info("Similar membres found: " + membreModel);
throw new DForbiddenException( throw new DForbiddenException(String.format(trad.t("le.membre.appartient.pas.a.votre.club"),
"Le membre n°" + membreModel.getLicence() + " n'appartient pas à votre club"); membreModel.getLicence()));
} }
} }
Uni<Void> uniResult = Uni.createFrom().voidItem(); Uni<Void> uniResult = Uni.createFrom().voidItem();
@@ -270,14 +277,18 @@ public class MembreService {
if (model.getEmail() != null && !model.getEmail().isBlank()) { if (model.getEmail() != null && !model.getEmail().isBlank()) {
if (model.getLicence() != null && !model.getLicence().equals(dataIn.getLicence())) { if (model.getLicence() != null && !model.getLicence().equals(dataIn.getLicence())) {
LOGGER.info("Similar membres found: " + model); LOGGER.info("Similar membres found: " + model);
throw new DBadRequestException("Email '" + model.getEmail() + "' déja utilisé"); throw new DBadRequestException(
String.format(trad.t("email.deja.utilise.par"), model.getEmail(),
model.getFname(), model.getLname()));
} }
if (StringSimilarity.similarity(model.getLname().toUpperCase(), if (StringSimilarity.similarity(model.getLname().toUpperCase(),
dataIn.getNom().toUpperCase()) > 3 || StringSimilarity.similarity( dataIn.getNom().toUpperCase()) > 3 || StringSimilarity.similarity(
model.getFname().toUpperCase(), dataIn.getPrenom().toUpperCase()) > 3) { model.getFname().toUpperCase(), dataIn.getPrenom().toUpperCase()) > 3) {
LOGGER.info("Similar membres found: " + model); LOGGER.info("Similar membres found: " + model);
throw new DBadRequestException("Email '" + model.getEmail() + "' déja utilisé"); throw new DBadRequestException(
String.format(trad.t("email.deja.utilise.par"), model.getEmail(),
model.getFname(), model.getLname()));
} }
} }
@@ -288,7 +299,8 @@ public class MembreService {
model.getFname().toUpperCase(), dataIn.getPrenom().toUpperCase()) > 3)) { model.getFname().toUpperCase(), dataIn.getPrenom().toUpperCase()) > 3)) {
LOGGER.info("Similar membres found: " + model); LOGGER.info("Similar membres found: " + model);
throw new DBadRequestException( throw new DBadRequestException(
"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); ls.logChange("Nom", model.getLname(), dataIn.getNom().toUpperCase(), model);
@@ -296,8 +308,7 @@ public class MembreService {
dataIn.getPrenom().toUpperCase().charAt(0) + dataIn.getPrenom().substring(1), model); dataIn.getPrenom().toUpperCase().charAt(0) + dataIn.getPrenom().substring(1), model);
model.setLname(dataIn.getNom().toUpperCase()); model.setLname(dataIn.getNom().toUpperCase());
model.setFname(dataIn.getPrenom().toUpperCase().charAt(0) + dataIn.getPrenom().substring(1)); model.setFname(Utils.formatPrenom(dataIn.getPrenom()));
if (dataIn.getEmail() != null && !dataIn.getEmail().isBlank()) { if (dataIn.getEmail() != null && !dataIn.getEmail().isBlank()) {
ls.logChange("Email", model.getEmail(), dataIn.getEmail(), model); ls.logChange("Email", model.getEmail(), dataIn.getEmail(), model);
@@ -363,7 +374,7 @@ public class MembreService {
.call(__ -> repository.count("email LIKE ?1 AND id != ?2", membre.getEmail(), id) .call(__ -> repository.count("email LIKE ?1 AND id != ?2", membre.getEmail(), id)
.invoke(Unchecked.consumer(c -> { .invoke(Unchecked.consumer(c -> {
if (c > 0 && !membre.getEmail().isBlank()) if (c > 0 && !membre.getEmail().isBlank())
throw new DBadRequestException("Email déjà utilisé"); throw new DBadRequestException(trad.t("email.deja.utilise"));
}))) })))
.chain(membreModel -> clubRepository.findById(membre.getClub()) .chain(membreModel -> clubRepository.findById(membre.getClub())
.map(club -> new Pair<>(membreModel, club))) .map(club -> new Pair<>(membreModel, club)))
@@ -385,7 +396,7 @@ public class MembreService {
.call(__ -> repository.count("email LIKE ?1 AND id != ?2", membre.getEmail(), id) .call(__ -> repository.count("email LIKE ?1 AND id != ?2", membre.getEmail(), id)
.invoke(Unchecked.consumer(c -> { .invoke(Unchecked.consumer(c -> {
if (c > 0 && !membre.getEmail().isBlank()) if (c > 0 && !membre.getEmail().isBlank())
throw new DBadRequestException("Email déjà utilisé"); throw new DBadRequestException(trad.t("email.deja.utilise"));
}))) })))
.invoke(Unchecked.consumer(membreModel -> { .invoke(Unchecked.consumer(membreModel -> {
if (!securityCtx.isInClubGroup(membreModel.getClub().getId())) if (!securityCtx.isInClubGroup(membreModel.getClub().getId()))
@@ -394,7 +405,7 @@ public class MembreService {
membre.getLname().toUpperCase()) > 3 || StringSimilarity.similarity( membre.getLname().toUpperCase()) > 3 || StringSimilarity.similarity(
membreModel.getFname().toUpperCase(), membre.getFname().toUpperCase()) > 3) { membreModel.getFname().toUpperCase(), membre.getFname().toUpperCase()) > 3) {
throw new DBadRequestException( throw new DBadRequestException(
"Pour enregistrer un nouveau membre, veuillez utilisez le bouton prévue a cette effet."); trad.t("regiter.new.membre"));
} }
})) }))
.invoke(Unchecked.consumer(membreModel -> { .invoke(Unchecked.consumer(membreModel -> {
@@ -403,7 +414,7 @@ public class MembreService {
else if (securityCtx.roleHas("club_secretaire")) source = RoleAsso.SECRETAIRE; else if (securityCtx.roleHas("club_secretaire")) source = RoleAsso.SECRETAIRE;
else if (securityCtx.roleHas("club_respo_intra")) source = RoleAsso.MEMBREBUREAU; else if (securityCtx.roleHas("club_respo_intra")) source = RoleAsso.MEMBREBUREAU;
if (!membre.getRole().equals(membreModel.getRole()) && membre.getRole().level >= source.level) if (!membre.getRole().equals(membreModel.getRole()) && membre.getRole().level >= source.level)
throw new DForbiddenException("Permission insuffisante"); throw new DForbiddenException(trad.t("permission.insuffisante"));
})) }))
.onItem().transform(target -> { .onItem().transform(target -> {
if (!securityCtx.getSubject().equals(target.getUserId())) { if (!securityCtx.getSubject().equals(target.getUserId())) {
@@ -417,7 +428,7 @@ public class MembreService {
private Uni<String> update(Uni<MembreModel> uni, FullMemberForm membre, boolean admin) { private Uni<String> update(Uni<MembreModel> uni, FullMemberForm membre, boolean admin) {
return uni.chain(target -> { return uni.chain(target -> {
ls.logChange("Prénom", target.getFname(), membre.getFname(), target); ls.logChange("Prénom", target.getFname(), membre.getFname(), target);
target.setFname(membre.getFname()); target.setFname(Utils.formatPrenom(membre.getFname()));
ls.logChange("Nom", target.getLname(), membre.getLname(), target); ls.logChange("Nom", target.getLname(), membre.getLname(), target);
target.setLname(membre.getLname().toUpperCase()); target.setLname(membre.getLname().toUpperCase());
ls.logChange("Pays", target.getCountry(), membre.getCountry(), target); ls.logChange("Pays", target.getCountry(), membre.getCountry(), target);
@@ -465,7 +476,8 @@ public class MembreService {
.call(membreModel -> licenceRepository.update("club_id = ?1 where membre = ?2 AND saison = ?3", .call(membreModel -> licenceRepository.update("club_id = ?1 where membre = ?2 AND saison = ?3",
(membreModel.getClub() == null) ? null : membreModel.getClub().getId(), membreModel, (membreModel.getClub() == null) ? null : membreModel.getClub().getId(), membreModel,
Utils.getSaison())) Utils.getSaison()))
.call(membreModel -> membre.getPhoto_data().length > 0 ? ls.logAUpdate("Photo", .call(membreModel -> (membre.getPhoto_data() != null && membre.getPhoto_data()
.size() > 0) ? ls.logAUpdate("Photo",
membreModel) : Uni.createFrom().nullItem()) membreModel) : Uni.createFrom().nullItem())
.map(__ -> "OK"); .map(__ -> "OK");
} }
@@ -475,7 +487,8 @@ public class MembreService {
return clubRepository.findById(input.getClub()) return clubRepository.findById(input.getClub())
.call(__ -> repository.count("email LIKE ?1", input.getEmail()) .call(__ -> repository.count("email LIKE ?1", input.getEmail())
.invoke(Unchecked.consumer(c -> { .invoke(Unchecked.consumer(c -> {
if (c > 0) throw new DBadRequestException("Email déjà utilisé"); if (c > 0 && input.getEmail() != null && !input.getEmail().isBlank())
throw new DBadRequestException(trad.t("email.deja.utilise"));
}))) })))
.chain(clubModel -> { .chain(clubModel -> {
MembreModel model = getMembreModel(input, clubModel); MembreModel model = getMembreModel(input, clubModel);
@@ -491,7 +504,7 @@ public class MembreService {
return repository.find("userId = ?1", subject).firstResult() return repository.find("userId = ?1", subject).firstResult()
.call(__ -> repository.count("email LIKE ?1", input.getEmail()) .call(__ -> repository.count("email LIKE ?1", input.getEmail())
.invoke(Unchecked.consumer(c -> { .invoke(Unchecked.consumer(c -> {
if (c > 0) throw new DBadRequestException("Email déjà utilisé"); if (c > 0) throw new DBadRequestException(trad.t("email.deja.utilise"));
}))) })))
.call(membreModel -> .call(membreModel ->
repository.count( repository.count(
@@ -499,7 +512,7 @@ public class MembreService {
input.getLname(), input.getFname(), membreModel.getClub()) input.getLname(), input.getFname(), membreModel.getClub())
.invoke(Unchecked.consumer(c -> { .invoke(Unchecked.consumer(c -> {
if (c > 0) if (c > 0)
throw new DBadRequestException("Membre déjà existent"); throw new DBadRequestException(trad.t("membre.deja.existent"));
}))) })))
.chain(membreModel -> { .chain(membreModel -> {
MembreModel model = getMembreModel(input, membreModel.getClub()); MembreModel model = getMembreModel(input, membreModel.getClub());
@@ -532,13 +545,13 @@ public class MembreService {
.invoke(Unchecked.consumer(membreModel -> { .invoke(Unchecked.consumer(membreModel -> {
if (membreModel.getLicence() != null) { if (membreModel.getLicence() != null) {
throw new DBadRequestException( throw new DBadRequestException(
"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() .call(membreModel -> licenceRepository.find("membre = ?1", membreModel).count()
.invoke(Unchecked.consumer(l -> { .invoke(Unchecked.consumer(l -> {
if (l > 0) if (l > 0)
throw new DBadRequestException("Impossible de supprimer un membre avec des licences"); throw new DBadRequestException(trad.t("membre.rm.err2"));
}))) })))
.call(membreModel -> (membreModel.getUserId() != null) ? .call(membreModel -> (membreModel.getUserId() != null) ?
keycloakService.removeAccount(membreModel.getUserId()) : Uni.createFrom().nullItem()) keycloakService.removeAccount(membreModel.getUserId()) : Uni.createFrom().nullItem())
@@ -560,8 +573,8 @@ public class MembreService {
private static MembreModel getMembreModel(FullMemberForm input, ClubModel clubModel) { private static MembreModel getMembreModel(FullMemberForm input, ClubModel clubModel) {
MembreModel model = new MembreModel(); MembreModel model = new MembreModel();
model.setFname(input.getFname()); model.setFname(Utils.formatPrenom(input.getFname()));
model.setLname(input.getLname()); model.setLname(input.getLname().toUpperCase());
model.setEmail(input.getEmail()); model.setEmail(input.getEmail());
model.setLicence(null); model.setLicence(null);
model.setGenre(input.getGenre()); model.setGenre(input.getGenre());
@@ -584,13 +597,30 @@ public class MembreService {
public Uni<MeData> getMembre(String subject) { public Uni<MeData> getMembre(String subject) {
MeData meData = new MeData(); MeData meData = new MeData();
return repository.find("userId = ?1", subject).firstResult() return repository.find("userId = ?1", subject).firstResult()
.invoke(meData::setMembre) .invoke(m -> meData.setMembre(m, trad))
.chain(membreModel -> Mutiny.fetch(membreModel.getLicences())) .call(membreModel -> Mutiny.fetch(membreModel.getLicences())
.map(licences -> licences.stream().map(SimpleLicence::fromModel).toList()) .map(licences -> licences.stream().map(SimpleLicence::fromModel).toList())
.invoke(meData::setLicences) .invoke(meData::setLicences))
.call(membreModel -> Mutiny.fetch(membreModel.getSelections())
.map(licences -> licences.stream().map(SimpleSelection::fromModel).toList())
.invoke(meData::setSelections))
.map(__ -> meData); .map(__ -> meData);
} }
public Uni<Void> updateSettings(String subject, UserSettingForm settingForm) {
return repository.find("userId = ?1", subject).firstResult()
.invoke(Unchecked.consumer(membreModel -> {
if (settingForm.getResultPrivacy() != null) {
ls.logChange("Confidentialité des résultats", membreModel.getResultPrivacy(),
settingForm.getResultPrivacy(), membreModel);
membreModel.setResultPrivacy(settingForm.getResultPrivacy());
}
}))
.call(membreModel -> Panache.withTransaction(() -> repository.persist(membreModel)))
.call(membreModel -> ls.append())
.replaceWithVoid();
}
@Scheduled(cron = "0 0 1 1 9 ?") @Scheduled(cron = "0 0 1 1 9 ?")
Uni<Void> everySeason() { Uni<Void> everySeason() {
return repository.list("birth_date IS NOT NULL") return repository.list("birth_date IS NOT NULL")
@@ -600,5 +630,4 @@ public class MembreService {
}).toList()).andCollectFailures()) }).toList()).andCollectFailures())
.map(__ -> null); .map(__ -> null);
} }
} }

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,52 @@
package fr.titionfire.ffsaf.domain.service;
import io.quarkus.websockets.next.WebSocketConnection;
import jakarta.enterprise.context.RequestScoped;
import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;
import jakarta.ws.rs.container.ContainerRequestContext;
import java.util.List;
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 t(String key, WebSocketConnection connection) {
List<String> lang = connection.handshakeRequest().headers().get("Accept-Language");
Locale userLocale = lang != null && !lang.isEmpty() ? Locale.forLanguageTag(lang.get(0)) : fallbackLocale;
return translate(key, userLocale);
}
public String translate(String key) {
ContainerRequestContext requestContext = requestContextInstance.get();
Locale userLocale = (Locale) requestContext.getProperty("userLocale");
return translate(key, userLocale);
}
public String translate(String key, Locale userLocale) {
try {
ResourceBundle messages = ResourceBundle.getBundle("lang.messages", userLocale);
return messages.getString(key);
} catch (MissingResourceException e) {
try {
ResourceBundle fallbackMessages = ResourceBundle.getBundle("lang.messages", fallbackLocale);
return fallbackMessages.getString(key);
} catch (MissingResourceException ex) {
return key;
}
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,92 @@
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;
import java.util.List;
@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/classement")
@Produces(MediaType.APPLICATION_JSON)
public Uni<List<ResultService.ClubClassement>> clubClassement() {
return resultService.getAllClubArray(id);
}
@GET
@Path("/club/data")
@Produces(MediaType.APPLICATION_JSON)
public Uni<?> getClubArray(@QueryParam("club") long club) {
if (club == 0)
return Uni.createFrom().item("");
return resultService.getClubArray2(id, club, null);
}
}

View File

@@ -36,7 +36,7 @@ public class LicenceEndpoints {
@GET @GET
@Path("{id}") @Path("{id}")
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"}) @RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Renvoie les licences d'un membre", description = "Renvoie les licences d'un membre en fonction " + @Operation(summary = "Renvoie les licences d'un membre", description = "Renvoie les licences d'un membre en fonction " +
"de son identifiant") "de son identifiant")
@@ -68,7 +68,7 @@ public class LicenceEndpoints {
@GET @GET
@Path("current/club") @Path("current/club")
@RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"}) @RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Renvoie les licences de la saison en cours (pour les clubs)", description = "Renvoie les " + @Operation(summary = "Renvoie les licences de la saison en cours (pour les clubs)", description = "Renvoie les " +
"licences de la saison en cours (pour les clubs)") "licences de la saison en cours (pour les clubs)")
@@ -83,7 +83,7 @@ public class LicenceEndpoints {
@POST @POST
@Path("pay") @Path("pay")
@RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"}) @RolesAllowed({"club_president", "club_secretaire", "club_tresorier", "club_respo_intra"})
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Operation(summary = "Paiement des licence", description = "Retourne le lien de paiement pour les licence des membre fournie") @Operation(summary = "Paiement des licence", description = "Retourne le lien de paiement pour les licence des membre fournie")
@@ -101,7 +101,7 @@ public class LicenceEndpoints {
@RolesAllowed("federation_admin") @RolesAllowed("federation_admin")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.MULTIPART_FORM_DATA) @Consumes(MediaType.MULTIPART_FORM_DATA)
@Operation(summary = "Créer une licence", description = "Créer 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)") "informations fournies dans le formulaire (pour les administrateurs)")
@APIResponses(value = { @APIResponses(value = {
@APIResponse(responseCode = "200", description = "La licence a été mise à jour avec succès"), @APIResponse(responseCode = "200", description = "La licence a été mise à jour avec succès"),
@@ -161,7 +161,7 @@ public class LicenceEndpoints {
@POST @POST
@Path("club/{id}") @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) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.MULTIPART_FORM_DATA) @Consumes(MediaType.MULTIPART_FORM_DATA)
@Operation(summary = "Demande une nouvelle licence", description = "Demande une nouvelle licence en fonction de" + @Operation(summary = "Demande une nouvelle licence", description = "Demande une nouvelle licence en fonction de" +
@@ -178,7 +178,7 @@ public class LicenceEndpoints {
@DELETE @DELETE
@Path("club/{id}") @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) @Produces(MediaType.TEXT_PLAIN)
@Operation(summary = "Supprime une demande de licence", description = "Supprime une demande de licence en fonction " + @Operation(summary = "Supprime une demande de licence", description = "Supprime une demande de licence en fonction " +
"de son identifiant (pour les clubs)") "de son identifiant (pour les clubs)")

View File

@@ -2,6 +2,7 @@ package fr.titionfire.ffsaf.rest;
import fr.titionfire.ffsaf.data.model.MembreModel; import fr.titionfire.ffsaf.data.model.MembreModel;
import fr.titionfire.ffsaf.domain.service.MembreService; import fr.titionfire.ffsaf.domain.service.MembreService;
import fr.titionfire.ffsaf.domain.service.VirusScannerService;
import fr.titionfire.ffsaf.rest.data.SimpleMembre; import fr.titionfire.ffsaf.rest.data.SimpleMembre;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException; import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.rest.exception.DInternalError; import fr.titionfire.ffsaf.rest.exception.DInternalError;
@@ -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.APIResponse;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses; import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
import org.eclipse.microprofile.openapi.annotations.tags.Tag; import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.jboss.logging.Logger;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -29,10 +31,14 @@ import java.util.function.Consumer;
@Path("api/member") @Path("api/member")
@RolesAllowed({"federation_admin"}) @RolesAllowed({"federation_admin"})
public class MembreAdminEndpoints { public class MembreAdminEndpoints {
private static final Logger LOGGER = Logger.getLogger(MembreAdminEndpoints.class);
@Inject @Inject
MembreService membreService; MembreService membreService;
@Inject
VirusScannerService scannerService;
@ConfigProperty(name = "upload_dir") @ConfigProperty(name = "upload_dir")
String media; String media;
@@ -97,16 +103,8 @@ public class MembreAdminEndpoints {
.invoke(Unchecked.consumer(out -> { .invoke(Unchecked.consumer(out -> {
if (!out.equals("OK")) if (!out.equals("OK"))
throw new DInternalError("Impossible de reconnaitre le fichier: " + out); throw new DInternalError("Impossible de reconnaitre le fichier: " + out);
})).chain(() -> { }))
if (input.getPhoto_data().length > 0) .call(__ -> Utils.uploadFile(scannerService, input.getPhoto_data(), id, media, "ppMembre"));
return Uni.createFrom().future(Utils.replacePhoto(id, input.getPhoto_data(), media, "ppMembre"
)).invoke(Unchecked.consumer(out -> {
if (!out.equals("OK"))
throw new DInternalError("Impossible de reconnaitre le fichier: " + out);
}));
else
return Uni.createFrom().nullItem();
});
} }
@POST @POST
@@ -123,13 +121,8 @@ public class MembreAdminEndpoints {
return membreService.add(input) return membreService.add(input)
.invoke(Unchecked.consumer(id -> { .invoke(Unchecked.consumer(id -> {
if (id == null) throw new InternalError("Fail to creat member data"); if (id == null) throw new InternalError("Fail to creat member data");
})).call(id -> { }))
if (input.getPhoto_data().length > 0) .call(id -> Utils.uploadFile(scannerService, input.getPhoto_data(), id, media, "ppMembre"));
return Uni.createFrom().future(Utils.replacePhoto(id, input.getPhoto_data(), media, "ppMembre"
));
else
return Uni.createFrom().nullItem();
});
} }
@DELETE @DELETE

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,31 @@
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 lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
@AllArgsConstructor
@RegisterForReflection
public class PresetData {
private Long id;
private String name;
private CatPresetModel.SwordType sword;
private CatPresetModel.ShieldType shield;
private List<CatPresetModel.CategorieEmbeddable> categories;
private int mandatoryProtection1;
private int mandatoryProtection2;
public static PresetData fromModel(CatPresetModel model) {
if (model == null)
return null;
return new PresetData(model.getId(), model.getName(), model.getSwordType(), model.getShieldType(),
model.getCategories(), model.getMandatoryProtection1(), model.getMandatoryProtection2());
}
}

View File

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

View File

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

View File

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

View File

@@ -19,34 +19,32 @@ import java.util.Date;
@AllArgsConstructor @AllArgsConstructor
@RegisterForReflection @RegisterForReflection
public class SimpleMembre { public class SimpleMembre {
@Schema(description = "L'identifiant du membre.", example = "1") @Schema(description = "L'identifiant du membre.", examples = "1")
private long id; 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; private String userId;
@Schema(description = "Le nom du membre.", example = "Dupont") @Schema(description = "Le nom du membre.", examples = "Dupont")
private String lname = ""; private String lname = "";
@Schema(description = "Le prénom du membre.", example = "Jean") @Schema(description = "Le prénom du membre.", examples = "Jean")
private String fname = ""; private String fname = "";
@Schema(description = "La catégorie du membre.", example = "SENIOR") @Schema(description = "La catégorie du membre.", examples = "SENIOR")
private Categorie categorie; private Categorie categorie;
@Schema(description = "Le club du membre.") @Schema(description = "Le club du membre.")
private SimpleClubModel club; private SimpleClubModel club;
@Schema(description = "Le genre du membre.", example = "H") @Schema(description = "Le genre du membre.", examples = "H")
private Genre genre; 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; private Integer licence;
@Schema(description = "Le pays du membre.", example = "FR") @Schema(description = "Le pays du membre.", examples = "FR")
private String country; private String country;
@Schema(description = "La date de naissance du membre.") @Schema(description = "La date de naissance du membre.")
private Date birth_date; private Date birth_date;
@Schema(description = "L'adresse e-mail du membre.", example = "jean.dupont@example.com") @Schema(description = "L'adresse e-mail du membre.", examples = "jean.dupont@examples.com")
private String 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")
private RoleAsso role; 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; private GradeArbitrage grade_arbitrage;
@Schema(hidden = true)
private String url_photo;
public static SimpleMembre fromModel(MembreModel model) { public static SimpleMembre fromModel(MembreModel model) {
if (model == null) if (model == null)
@@ -66,7 +64,6 @@ public class SimpleMembre {
.email(model.getEmail()) .email(model.getEmail())
.role(model.getRole()) .role(model.getRole())
.grade_arbitrage(model.getGrade_arbitrage()) .grade_arbitrage(model.getGrade_arbitrage())
.url_photo(model.getUrl_photo())
.build(); .build();
} }
} }

View File

@@ -2,10 +2,14 @@ package fr.titionfire.ffsaf.rest.data;
import fr.titionfire.ffsaf.data.model.LicenceModel; import fr.titionfire.ffsaf.data.model.LicenceModel;
import fr.titionfire.ffsaf.data.model.MembreModel; import fr.titionfire.ffsaf.data.model.MembreModel;
import fr.titionfire.ffsaf.utils.Utils;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@@ -24,7 +28,27 @@ public class SimpleMembreInOutData {
public static SimpleMembreInOutData fromModel(MembreModel membreModel, List<LicenceModel> lc) { public static SimpleMembreInOutData fromModel(MembreModel membreModel, List<LicenceModel> lc) {
LicenceModel currentLicence = lc.stream().filter(l -> l.getMembre().getId().equals(membreModel.getId())) LicenceModel currentLicence = lc.stream().filter(l -> l.getMembre().getId().equals(membreModel.getId()))
.findFirst().orElse(null); .max(Comparator.comparingInt(LicenceModel::getSaison)).orElse(null);
String certif = null;
if (currentLicence != null && currentLicence.getCertificate() != null) {
String[] strings = currentLicence.getCertificate().split("¤");
if (currentLicence.getSaison() == Utils.getSaison()) {
certif = currentLicence.getCertificate();
} else if (strings.length > 1) {
try {
Date date = new SimpleDateFormat("yyyy-MM-dd").parse(strings[1]);
Calendar max = Utils.getFirstDateOfSaison();
max.add(Calendar.YEAR, -2);
if (max.getTime().compareTo(date) < 0) {
certif = currentLicence.getCertificate();
}
} catch (Exception ignored) {
}
}
}
return new SimpleMembreInOutData( return new SimpleMembreInOutData(
membreModel.getLicence(), membreModel.getLicence(),
@@ -33,8 +57,8 @@ public class SimpleMembreInOutData {
membreModel.getEmail(), membreModel.getEmail(),
membreModel.getGenre().str, membreModel.getGenre().str,
membreModel.getBirth_date(), membreModel.getBirth_date(),
currentLicence != null, currentLicence != null && currentLicence.getSaison() == Utils.getSaison(),
currentLicence == null ? null : currentLicence.getCertificate() certif
); );
} }
} }

View File

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

View File

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

View File

@@ -9,6 +9,7 @@ import lombok.ToString;
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.jboss.resteasy.reactive.PartType; import org.jboss.resteasy.reactive.PartType;
import org.jboss.resteasy.reactive.multipart.FileUpload;
@Getter @Getter
@ToString(exclude = {"status", "logo"}) @ToString(exclude = {"status", "logo"})
@@ -17,85 +18,85 @@ public class AffiliationRequestForm {
@FormParam("id") @FormParam("id")
private Long id = null; 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") @FormParam("name")
private String name = null; 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") @FormParam("state_id")
private String state_id = null; 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") @FormParam("adresse")
private String adresse = null; 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") @FormParam("contact")
private String contact = null; 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") @FormParam("saison")
private int saison = -1; 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") @FormParam("status")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @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") @FormParam("logo")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @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") @FormParam("m1_nom")
private String m1_lname = null; 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") @FormParam("m1_prenom")
private String m1_fname = null; private String m1_fname = null;
@Schema(description = "L'adresse e-mail du premier membre de l'association.", 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") @FormParam("m1_mail")
private String m1_email = null; private String m1_email = null;
@Schema(description = "Le numéro de licence du premier membre de l'association. (null si non licencié)", example = "12345") @Schema(description = "Le numéro de licence du premier membre de l'association. (null si non licencié)", examples = "12345")
@FormParam("m1_licence") @FormParam("m1_licence")
private String m1_lincence = null; private String m1_lincence = null;
@Schema(description = "Le rôle du premier membre de l'association. (doit être PRESIDENT)", 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") @FormParam("m1_role")
private RoleAsso m1_role = null; 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") @FormParam("m2_nom")
private String m2_lname = null; private String m2_lname = null;
@Schema(description = "Le prénom du deuxième membre de l'association.", example = "Login", required = true) @Schema(description = "Le prénom du deuxième membre de l'association.", examples = "Login", required = true)
@FormParam("m2_prenom") @FormParam("m2_prenom")
private String m2_fname = null; private String m2_fname = null;
@Schema(description = "L'adresse e-mail du deuxième membre de l'association.", 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") @FormParam("m2_mail")
private String m2_email = null; private String m2_email = null;
@Schema(description = "Le numéro de licence du deuxième membre de l'association. (null si non licencié)", 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") @FormParam("m2_licence")
private String m2_lincence = null; private String m2_lincence = null;
@Schema(description = "Le rôle du deuxième membre de l'association.", example = "SECRETAIRE", required = true) @Schema(description = "Le rôle du deuxième membre de l'association.", examples = "SECRETAIRE", required = true)
@FormParam("m2_role") @FormParam("m2_role")
private RoleAsso m2_role = null; private RoleAsso m2_role = null;
@Schema(description = "Le nom du troisième membre de l'association.", example = "Doe2", required = true) @Schema(description = "Le nom du troisième membre de l'association.", examples = "Doe2", required = true)
@FormParam("m3_nom") @FormParam("m3_nom")
private String m3_lname = null; private String m3_lname = null;
@Schema(description = "Le prénom du troisième membre de l'association.", example = "John2", required = true) @Schema(description = "Le prénom du troisième membre de l'association.", examples = "John2", required = true)
@FormParam("m3_prenom") @FormParam("m3_prenom")
private String m3_fname = null; private String m3_fname = null;
@Schema(description = "L'adresse e-mail du troisième membre de l'association.", 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") @FormParam("m3_mail")
private String m3_email = null; private String m3_email = null;
@@ -103,7 +104,7 @@ public class AffiliationRequestForm {
@FormParam("m3_licence") @FormParam("m3_licence")
private String m3_lincence = null; private String m3_lincence = null;
@Schema(description = "Le rôle du troisième membre de l'association.", example = "MEMBREBUREAU", required = true) @Schema(description = "Le rôle du troisième membre de l'association.", examples = "MEMBREBUREAU", required = true)
@FormParam("m3_role") @FormParam("m3_role")
private RoleAsso m3_role = null; private RoleAsso m3_role = null;

View File

@@ -6,123 +6,124 @@ import jakarta.ws.rs.core.MediaType;
import lombok.Getter; import lombok.Getter;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.jboss.resteasy.reactive.PartType; import org.jboss.resteasy.reactive.PartType;
import org.jboss.resteasy.reactive.multipart.FileUpload;
@Getter @Getter
public class AffiliationRequestSaveForm { public class AffiliationRequestSaveForm {
@Schema(description = "L'identifiant de l'affiliation.", example = "1", required = true) @Schema(description = "L'identifiant de l'affiliation.", examples = "1", required = true)
@FormParam("id") @FormParam("id")
private Long id = null; 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") @FormParam("name")
private String name = null; 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") @FormParam("state_id")
private String state_id = null; 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") @FormParam("address")
private String address = null; 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") @FormParam("contact")
private String contact = null; private String contact = null;
@Schema(description = "Le statut de l'association.") @Schema(description = "Le statut de l'association.")
@FormParam("status") @FormParam("status")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @PartType(MediaType.APPLICATION_OCTET_STREAM)
private byte[] status = new byte[0]; private FileUpload status = null;
@Schema(description = "Le logo de l'association.") @Schema(description = "Le logo de l'association.")
@FormParam("logo") @FormParam("logo")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @PartType(MediaType.APPLICATION_OCTET_STREAM)
private 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") @FormParam("m1_mode")
private Integer m1_mode = null; 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") @FormParam("m1_role")
private RoleAsso m1_role = null; private RoleAsso m1_role = null;
@Schema(description = "Le numéro de licence du premier membre de l'association. (null si non licencié)", 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") @FormParam("m1_licence")
private String m1_lincence = null; 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") @FormParam("m1_lname")
private String m1_lname = null; 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") @FormParam("m1_fname")
private String m1_fname = null; private String m1_fname = null;
@Schema(description = "L'adresse e-mail du premier membre de l'association.", 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") @FormParam("m1_email")
private String m1_email = null; private String m1_email = null;
@Schema(name = "keep_email", @Schema(name = "keep_email",
description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm1_email')", 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") @FormParam("m1_email_mode")
private Integer m1_email_mode = null; private Integer m1_email_mode = null;
@Schema(description = "Mode utiliser pour la sauvegarde du membre 2 (0 = licence mode, 2 = nom, prénom)", 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") @FormParam("m2_mode")
private Integer m2_mode = null; private Integer m2_mode = null;
@Schema(description = "Le rôle du deuxième membre de l'association.", 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") @FormParam("m2_role")
private RoleAsso m2_role = null; private RoleAsso m2_role = null;
@Schema(description = "Le numéro de licence du deuxième membre de l'association. (null si non licencié)", 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") @FormParam("m2_licence")
private String m2_lincence = null; 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") @FormParam("m2_lname")
private String m2_lname = null; private String m2_lname = null;
@Schema(description = "Le prénom du deuxième membre de l'association.", example = "Paul", required = true) @Schema(description = "Le prénom du deuxième membre de l'association.", examples = "Paul", required = true)
@FormParam("m2_fname") @FormParam("m2_fname")
private String m2_fname = null; private String m2_fname = null;
@Schema(description = "L'adresse e-mail du deuxième membre de l'association.", 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") @FormParam("m2_email")
private String m2_email = null; private String m2_email = null;
@Schema(name = "keep_email", @Schema(name = "keep_email",
description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm2_email')", 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") @FormParam("m2_email_mode")
private Integer m2_email_mode = null; private Integer m2_email_mode = null;
@Schema(description = "Mode utiliser pour la sauvegarde du membre 3 (0 = licence mode, 2 = nom, prénom)", 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") @FormParam("m3_mode")
private Integer m3_mode = null; private Integer m3_mode = null;
@Schema(description = "Le rôle du troisième membre de l'association.", 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") @FormParam("m3_role")
private RoleAsso m3_role = null; private RoleAsso m3_role = null;
@Schema(description = "Le numéro de licence du troisième membre de l'association. (null si non licencié)", 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") @FormParam("m3_licence")
private String m3_lincence = null; 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") @FormParam("m3_lname")
private String m3_lname = null; private String m3_lname = null;
@Schema(description = "Le prénom du troisième membre de l'association.", example = "Pierre", required = true) @Schema(description = "Le prénom du troisième membre de l'association.", examples = "Pierre", required = true)
@FormParam("m3_fname") @FormParam("m3_fname")
private String m3_fname = null; private String m3_fname = null;
@Schema(description = "L'adresse e-mail du troisième membre de l'association.", 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") @FormParam("m3_email")
private String m3_email = null; private String m3_email = null;
@Schema(name = "keep_email", @Schema(name = "keep_email",
description = "Conserver l'email de la base de donner (1 = conserve, 0 = replacer par 'm3_email')", 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") @FormParam("m3_email_mode")
private Integer m3_email_mode = null; private Integer m3_email_mode = null;
@@ -174,8 +175,6 @@ public class AffiliationRequestSaveForm {
", state_id=" + state_id + ", state_id=" + state_id +
", address='" + address + '\'' + ", address='" + address + '\'' +
", contact='" + contact + '\'' + ", contact='" + contact + '\'' +
", status_len=" + status.length +
", logo_len=" + logo.length +
", m1_mode=" + m1_mode + ", m1_mode=" + m1_mode +
", m1_role=" + m1_role + ", m1_role=" + m1_role +
", m1_lincence='" + m1_lincence + '\'' + ", m1_lincence='" + m1_lincence + '\'' +

View File

@@ -7,57 +7,58 @@ import lombok.ToString;
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
import org.eclipse.microprofile.openapi.annotations.media.Schema; import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.jboss.resteasy.reactive.PartType; import org.jboss.resteasy.reactive.PartType;
import org.jboss.resteasy.reactive.multipart.FileUpload;
@ToString @ToString
@Getter @Getter
public class FullClubForm { public class FullClubForm {
@FormParam("id") @FormParam("id")
@Schema(description = "Identifiant du club", example = "1", required = true) @Schema(description = "Identifiant du club", examples = "1", required = true)
private String id = null; private String id = null;
@FormParam("name") @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; private String name = null;
@FormParam("country") @FormParam("country")
@Schema(description = "Pays du club", example = "FR", required = true) @Schema(description = "Pays du club", examples = "FR", required = true)
private String country = null; private String country = null;
@FormParam("contact") @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; private String contact = null;
@FormParam("training_location") @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; private String training_location = null;
@FormParam("training_day_time") @FormParam("training_day_time")
@Schema(description = "Liste des jours et horaires d'entraînement (jours 0-6, 0=>lundi) (temps en minute depuis 00:00, 122=>2h02)", 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; private String training_day_time = null;
@FormParam("contact_intern") @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; private String contact_intern = null;
@FormParam("address") @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; private String address = null;
@FormParam("state_id") @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; private String state_id = null;
@FormParam("international") @FormParam("international")
@Schema(description = "Club international", example = "false", required = true) @Schema(description = "Club international", examples = "false", required = true)
private boolean international = false; private boolean international = false;
@FormParam("status") @FormParam("status")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @PartType(MediaType.APPLICATION_OCTET_STREAM)
@Schema(description = "Le statut de l'association.", type = SchemaType.ARRAY, implementation = byte.class) @Schema(description = "Le statut de l'association.", type = SchemaType.ARRAY)
private byte[] status = new byte[0]; private FileUpload status = null;
@FormParam("logo") @FormParam("logo")
@PartType(MediaType.APPLICATION_OCTET_STREAM) @PartType(MediaType.APPLICATION_OCTET_STREAM)
@Schema(description = "Le logo de l'association.", type = SchemaType.ARRAY, implementation = byte.class) @Schema(description = "Le logo de l'association.", type = SchemaType.ARRAY)
private byte[] logo = new byte[0]; private FileUpload logo = null;
} }

View File

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

View File

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

View File

@@ -1,5 +1,6 @@
package fr.titionfire.ffsaf.utils; package fr.titionfire.ffsaf.utils;
import fr.titionfire.ffsaf.domain.service.TradService;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@@ -19,7 +20,7 @@ public enum Categorie {
VETERAN2; VETERAN2;
public String getName(ResourceBundle BUNDLE) { public String getName(ResourceBundle BUNDLE) {
return switch (this){ return switch (this) {
case SUPER_MINI -> BUNDLE.getString("Cat.SUPER_MINI"); case SUPER_MINI -> BUNDLE.getString("Cat.SUPER_MINI");
case MINI_POUSSIN -> BUNDLE.getString("Cat.MINI_POUSSIN"); case MINI_POUSSIN -> BUNDLE.getString("Cat.MINI_POUSSIN");
case POUSSIN -> BUNDLE.getString("Cat.POUSSIN"); case POUSSIN -> BUNDLE.getString("Cat.POUSSIN");
@@ -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() { public String getName() {
return switch (this){ return switch (this) {
case SUPER_MINI -> "Super Mini"; case SUPER_MINI -> "Super Mini";
case MINI_POUSSIN -> "Mini Poussin"; case MINI_POUSSIN -> "Mini Poussin";
case POUSSIN -> "Poussin"; case POUSSIN -> "Poussin";

View File

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

View File

@@ -1,5 +1,6 @@
package fr.titionfire.ffsaf.utils; package fr.titionfire.ffsaf.utils;
import fr.titionfire.ffsaf.domain.service.TradService;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
@RegisterForReflection @RegisterForReflection
@@ -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 @Override
public String toString() { public String toString() {
return str; return str;
} }
} }

View File

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

View File

@@ -10,13 +10,14 @@ import java.util.List;
@Data @Data
@RegisterForReflection @RegisterForReflection
public class PageResult<T> { public class PageResult<T> {
@Schema(description = "Le numéro de la page courante.", example = "1") @Schema(description = "Le numéro de la page courante.", examples = "1")
private int page; private int page;
@Schema(description = "Le nombre d'éléments par page.", example = "10") @Schema(description = "Le nombre d'éléments par page.", examples = "10")
private int page_size; private int page_size;
@Schema(description = "Le nombre total de pages.", example = "5") @Schema(description = "Le nombre total de pages.", examples = "5")
private int page_count; private int page_count;
@Schema(description = "Le nombre total d'éléments.", example = "47") @Schema(description = "Le nombre total d'éléments.", examples = "47")
private long result_count; private long result_count;
private List<T> result = new ArrayList<>(); private List<T> result = new ArrayList<>();
private Object additionalData;
} }

View File

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

View File

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

View File

@@ -1,17 +1,27 @@
package fr.titionfire.ffsaf.utils; package fr.titionfire.ffsaf.utils;
import fr.titionfire.ffsaf.data.model.CompetitionGuestModel;
import fr.titionfire.ffsaf.data.model.MembreModel;
import fr.titionfire.ffsaf.domain.service.VirusScannerService;
import fr.titionfire.ffsaf.rest.exception.DBadRequestException;
import fr.titionfire.ffsaf.rest.exception.DInternalError;
import fr.titionfire.ffsaf.rest.exception.DetailException;
import io.quarkiverse.antivirus.runtime.AntivirusScanResult;
import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.unchecked.Unchecked;
import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import jodd.net.MimeTypes; import jodd.net.MimeTypes;
import org.apache.tika.Tika;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.reactive.multipart.FileUpload;
import java.io.*; import java.io.*;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URLConnection; import java.net.URLConnection;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -109,6 +119,15 @@ public class Utils {
} }
} }
public static Calendar getFirstDateOfSaison() {
Calendar calendar = Calendar.getInstance();
calendar.set(getSaison(), Calendar.SEPTEMBER, 1, 0, 0, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar;
}
public static Calendar toCalendar(Date date) { public static Calendar toCalendar(Date date) {
Calendar cal = Calendar.getInstance(); Calendar cal = Calendar.getInstance();
cal.setTime(date); cal.setTime(date);
@@ -181,44 +200,73 @@ public class Utils {
}); });
} }
public static Future<String> replacePhoto(long id, byte[] input, String media, String dir) { public static Uni<String> uploadFile(VirusScannerService ss, FileUpload file, long id, String media, String dir) {
return CompletableFuture.supplyAsync(() -> { if (file == null || file.size() == 0)
if (input == null || input.length == 0) return Uni.createFrom().item("Ok");
return "OK";
try (InputStream is = new BufferedInputStream(new ByteArrayInputStream(input))) { LOGGER.infof("Received file upload request for: %s (size: %d bytes)", file.fileName(), file.size());
String mimeType; return Uni.createFrom().<InputStream>item(() -> {
try { try {
Tika tika = new Tika(); // Read the entire file into memory for virus scanning
mimeType = tika.detect(is);// Magic.getMagicMatch(input, false).getMimeType(); // 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) { } catch (IOException e) {
mimeType = URLConnection.guessContentTypeFromStream(is); throw new RuntimeException("Failed to read uploaded file: " + e.getMessage(), e);
} }
String[] detectedExtensions = MimeTypes.findExtensionsByMimeTypes(mimeType, false); }).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());
}
}
// File is clean - now we can safely process it
LOGGER.infof("File is clean: %s (size=%d) (contentType=%s)", file.fileName(), file.size(),
file.contentType());
String[] detectedExtensions = MimeTypes.findExtensionsByMimeTypes(file.contentType(), false);
if (detectedExtensions.length == 0) if (detectedExtensions.length == 0)
throw new IOException("Fail to detect file extension for MIME type " + mimeType); throw new DBadRequestException(
"Fail to detect file extension for MIME type " + file.contentType());
File dirFile = new File(media, dir); File dirFile = new File(media, dir);
if (!dirFile.exists()) if (!dirFile.exists())
if (!dirFile.mkdirs()) if (!dirFile.mkdirs())
throw new IOException("Fail to create directory " + dir); throw new DInternalError("Fail to create directory " + dir);
FilenameFilter filter = (directory, filename) -> filename.startsWith(id + "."); FilenameFilter filter = (directory, filename) -> filename.startsWith(id + ".");
File[] files = dirFile.listFiles(filter); File[] files = dirFile.listFiles(filter);
if (files != null) { if (files != null) {
for (File file : files) { for (File f2 : files) {
//noinspection ResultOfMethodCallIgnored //noinspection ResultOfMethodCallIgnored
file.delete(); f2.delete();
} }
} }
String extension = "." + detectedExtensions[0]; Path f = file.filePath();
Files.write(new File(dirFile, id + extension).toPath(), input); System.out.println(f + " -> " + new File(dirFile, id + "." + detectedExtensions[0]));
return "OK"; Files.copy(f, new File(dirFile, id + "." + detectedExtensions[0]).toPath(),
} catch (IOException e) { StandardCopyOption.REPLACE_EXISTING);
return e.getMessage(); return "ok";
} })));
});
} }
public static Uni<Response> getMediaFile(long id, String media, String dirname, public static Uni<Response> getMediaFile(long id, String media, String dirname,
@@ -335,4 +383,46 @@ public class Utils {
return (int) ((calendar.getTimeInMillis() - now.getTimeInMillis()) / (1000 * 60 * 60 * 24)); return (int) ((calendar.getTimeInMillis() - now.getTimeInMillis()) / (1000 * 60 * 60 * 24));
} }
public static String formatPrenom(String input) {
if (input == null || input.isEmpty()) {
return input;
}
StringBuilder result = new StringBuilder();
String[] mots = input.split(" ");
for (String mot : mots) {
if (!mot.isEmpty()) {
String[] parties = mot.split("[-']");
StringBuilder motFormate = new StringBuilder();
for (int i = 0; i < parties.length; i++) {
if (!parties[i].isEmpty()) {
String premiereLettre = parties[i].substring(0, 1).toUpperCase();
String reste = parties[i].substring(1).toLowerCase();
motFormate.append(premiereLettre).append(reste);
}
if (i < parties.length - 1) {
motFormate.append(mot.charAt(mot.indexOf(parties[i]) + parties[i].length()));
}
}
result.append(motFormate).append(" ");
}
}
return result.toString().trim();
}
public static String getFullName(Object... models) {
for (Object model : models) {
if (model == null)
continue;
if (model instanceof MembreModel membreModel)
return membreModel.getFname() + " " + membreModel.getLname();
if (model instanceof CompetitionGuestModel guestModel)
return guestModel.getFname() + " " + guestModel.getLname();
}
return "";
}
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,128 +0,0 @@
package fr.titionfire.ffsaf.ws.recv;
import fr.titionfire.ffsaf.data.model.CardboardModel;
import fr.titionfire.ffsaf.data.model.MatchModel;
import fr.titionfire.ffsaf.data.repository.CardboardRepository;
import fr.titionfire.ffsaf.data.repository.MatchRepository;
import fr.titionfire.ffsaf.domain.entity.CardboardEntity;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
import fr.titionfire.ffsaf.ws.PermLevel;
import fr.titionfire.ffsaf.ws.send.SSCardboard;
import io.quarkus.hibernate.reactive.panache.Panache;
import io.quarkus.hibernate.reactive.panache.common.WithSession;
import io.quarkus.runtime.annotations.RegisterForReflection;
import io.quarkus.websockets.next.WebSocketConnection;
import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.unchecked.Unchecked;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import lombok.Data;
import java.util.Objects;
@WithSession
@ApplicationScoped
@RegisterForReflection
public class RCardboard {
@Inject
MatchRepository matchRepository;
@Inject
CardboardRepository cardboardRepository;
private Uni<MatchModel> getById(long id, WebSocketConnection connection) {
return matchRepository.findById(id)
.invoke(Unchecked.consumer(o -> {
if (o == null)
throw new DNotFoundException("Matche non trouver");
if (!o.getCategory().getCompet().getUuid().equals(connection.pathParam("uuid")))
throw new DForbiddenException("Permission denied");
}));
}
@WSReceiver(code = "sendCardboardChange", permission = PermLevel.TABLE)
public Uni<Void> sendCardboardChange(WebSocketConnection connection, SendCardboard card) {
return getById(card.matchId, connection)
.chain(matchModel -> cardboardRepository.find("(comb.id = ?1 OR guestComb.id = ?2) AND match.id = ?3",
card.combId, card.combId * -1, card.matchId).firstResult()
.chain(model -> {
if (model != null) {
model.setRed(model.getRed() + card.red);
model.setYellow(model.getYellow() + card.yellow);
return Panache.withTransaction(() -> cardboardRepository.persist(model));
}
CardboardModel cardboardModel = new CardboardModel();
cardboardModel.setCompet(matchModel.getCategory().getCompet());
cardboardModel.setMatch(matchModel);
cardboardModel.setRed(card.red);
cardboardModel.setYellow(card.yellow);
cardboardModel.setComb(null);
cardboardModel.setGuestComb(null);
if (card.combId >= 0) {
if (matchModel.getC1_id() != null && matchModel.getC1_id().getId() == card.combId)
cardboardModel.setComb(matchModel.getC1_id());
if (matchModel.getC2_id() != null && matchModel.getC2_id().getId() == card.combId)
cardboardModel.setComb(matchModel.getC2_id());
} else {
if (matchModel.getC1_guest() != null && matchModel.getC1_guest()
.getId() == card.combId * -1)
cardboardModel.setGuestComb(matchModel.getC1_guest());
if (matchModel.getC2_guest() != null && matchModel.getC2_guest()
.getId() == card.combId * -1)
cardboardModel.setGuestComb(matchModel.getC2_guest());
}
if (cardboardModel.getComb() == null && cardboardModel.getGuestComb() == null)
return Uni.createFrom().nullItem();
return Panache.withTransaction(() -> cardboardRepository.persist(cardboardModel));
}))
.call(model -> SSCardboard.sendCardboard(connection, CardboardEntity.fromModel(model)))
.replaceWithVoid();
}
@WSReceiver(code = "getCardboardWithoutThis", permission = PermLevel.VIEW)
public Uni<CardboardAllMatch> getCardboardWithoutThis(WebSocketConnection connection, Long matchId) {
return getById(matchId, connection)
.chain(matchModel -> cardboardRepository.list("compet = ?1 AND match != ?2", matchModel.getCategory().getCompet(), matchModel)
.map(models -> {
CardboardAllMatch out = new CardboardAllMatch();
models.stream().filter(c -> (matchModel.getC1_id() != null
&& Objects.equals(c.getComb(), matchModel.getC1_id()))
|| (matchModel.getC1_guest() != null
&& Objects.equals(c.getGuestComb(), matchModel.getC1_guest())))
.forEach(c -> {
out.c1_yellow += c.getYellow();
out.c1_red += c.getRed();
});
models.stream().filter(c -> (matchModel.getC2_id() != null
&& Objects.equals(c.getComb(), matchModel.getC2_id()))
|| (matchModel.getC2_guest() != null
&& Objects.equals(c.getGuestComb(), matchModel.getC2_guest())))
.forEach(c -> {
out.c2_yellow += c.getYellow();
out.c2_red += c.getRed();
});
return out;
}));
}
@RegisterForReflection
public record SendCardboard(long matchId, long combId, int yellow, int red) {
}
@Data
@RegisterForReflection
public static class CardboardAllMatch {
int c1_yellow = 0;
int c1_red = 0;
int c2_yellow = 0;
int c2_red = 0;
}
}

View File

@@ -1,22 +1,25 @@
package fr.titionfire.ffsaf.ws.recv; package fr.titionfire.ffsaf.ws.recv;
import fr.titionfire.ffsaf.data.model.CategoryModel; import fr.titionfire.ffsaf.data.model.*;
import fr.titionfire.ffsaf.data.model.MatchModel; import fr.titionfire.ffsaf.data.repository.*;
import fr.titionfire.ffsaf.data.model.TreeModel;
import fr.titionfire.ffsaf.data.repository.CategoryRepository;
import fr.titionfire.ffsaf.data.repository.CompetitionRepository;
import fr.titionfire.ffsaf.data.repository.MatchRepository;
import fr.titionfire.ffsaf.data.repository.TreeRepository;
import fr.titionfire.ffsaf.domain.entity.MatchEntity; import fr.titionfire.ffsaf.domain.entity.MatchEntity;
import fr.titionfire.ffsaf.domain.entity.MatchModelExtend;
import fr.titionfire.ffsaf.domain.entity.TreeEntity; import fr.titionfire.ffsaf.domain.entity.TreeEntity;
import fr.titionfire.ffsaf.domain.service.CardService;
import fr.titionfire.ffsaf.domain.service.ResultService;
import fr.titionfire.ffsaf.domain.service.TradService;
import fr.titionfire.ffsaf.rest.data.PresetData;
import fr.titionfire.ffsaf.rest.data.ResultCategoryData;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException; import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.rest.exception.DNotFoundException; import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
import fr.titionfire.ffsaf.utils.TreeNode; import fr.titionfire.ffsaf.utils.TreeNode;
import fr.titionfire.ffsaf.ws.PermLevel; import fr.titionfire.ffsaf.ws.PermLevel;
import fr.titionfire.ffsaf.ws.send.SSCategorie; import fr.titionfire.ffsaf.ws.send.SSCategorie;
import fr.titionfire.ffsaf.ws.send.SSMatch;
import io.quarkus.hibernate.reactive.panache.Panache; import io.quarkus.hibernate.reactive.panache.Panache;
import io.quarkus.hibernate.reactive.panache.common.WithSession; import io.quarkus.hibernate.reactive.panache.common.WithSession;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
import io.quarkus.websockets.next.UserData;
import io.quarkus.websockets.next.WebSocketConnection; import io.quarkus.websockets.next.WebSocketConnection;
import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.unchecked.Unchecked; import io.smallrye.mutiny.unchecked.Unchecked;
@@ -25,8 +28,9 @@ import jakarta.inject.Inject;
import lombok.Data; import lombok.Data;
import org.hibernate.reactive.mutiny.Mutiny; import org.hibernate.reactive.mutiny.Mutiny;
import java.util.ArrayList; import java.util.*;
import java.util.List; import java.util.stream.Collectors;
import java.util.stream.Stream;
@WithSession @WithSession
@ApplicationScoped @ApplicationScoped
@@ -46,13 +50,28 @@ public class RCategorie {
@Inject @Inject
TreeRepository treeRepository; TreeRepository treeRepository;
@Inject
CardService cardService;
@Inject
CardRepository cardRepository;
@Inject
CatPresetRepository catPresetRepository;
@Inject
ResultService resultService;
@Inject
TradService trad;
private Uni<CategoryModel> getById(long id, WebSocketConnection connection) { private Uni<CategoryModel> getById(long id, WebSocketConnection connection) {
return categoryRepository.findById(id) return categoryRepository.findById(id)
.invoke(Unchecked.consumer(o -> { .invoke(Unchecked.consumer(o -> {
if (o == null) if (o == null)
throw new DNotFoundException("Catégorie non trouver"); throw new DNotFoundException(trad.t("categorie.non.trouver", connection));
if (!o.getCompet().getUuid().equals(connection.pathParam("uuid"))) if (!o.getCompet().getUuid().equals(connection.pathParam("uuid")))
throw new DForbiddenException("Permission denied"); throw new DForbiddenException(trad.t("permission.denied", connection));
})); }));
} }
@@ -72,6 +91,9 @@ public class RCategorie {
fullCategory.setName(cat.getName()); fullCategory.setName(cat.getName());
fullCategory.setLiceName(cat.getLiceName()); fullCategory.setLiceName(cat.getLiceName());
fullCategory.setType(cat.getType()); fullCategory.setType(cat.getType());
fullCategory.setTreeAreClassement(cat.isTreeAreClassement());
fullCategory.setFullClassement(cat.isFullClassement());
fullCategory.setPreset(PresetData.fromModel(cat.getPreset()));
}) })
.call(cat -> Mutiny.fetch(cat.getMatchs()) .call(cat -> Mutiny.fetch(cat.getMatchs())
.map(matchModels -> matchModels.stream().filter(o -> o.getCategory_ord() >= 0) .map(matchModels -> matchModels.stream().filter(o -> o.getCategory_ord() >= 0)
@@ -80,6 +102,8 @@ public class RCategorie {
.call(cat -> treeRepository.list("category = ?1 AND level != 0", cat.getId()) .call(cat -> treeRepository.list("category = ?1 AND level != 0", cat.getId())
.map(treeModels -> treeModels.stream().map(TreeEntity::fromModel).toList()) .map(treeModels -> treeModels.stream().map(TreeEntity::fromModel).toList())
.invoke(fullCategory::setTrees)) .invoke(fullCategory::setTrees))
.call(cat -> cardService.getAll(cat.getCompet())
.invoke(fullCategory::setCards))
.map(__ -> fullCategory); .map(__ -> fullCategory);
} }
@@ -94,20 +118,67 @@ public class RCategorie {
categoryModel.setTree(new ArrayList<>()); categoryModel.setTree(new ArrayList<>());
categoryModel.setType(categorie.type); categoryModel.setType(categorie.type);
categoryModel.setLiceName(categorie.liceName); categoryModel.setLiceName(categorie.liceName);
categoryModel.setTreeAreClassement(categorie.treeAreClassement);
categoryModel.setFullClassement(categorie.fullClassement);
if (categorie.preset() != null)
return catPresetRepository.findById(categorie.preset().getId())
.invoke(categoryModel::setPreset)
.chain(__ -> categoryRepository.create(categoryModel));
return categoryRepository.create(categoryModel); return categoryRepository.create(categoryModel);
}) })
.call(cat -> SSCategorie.sendAddCategory(connection, cat)) .invoke(cat -> SSCategorie.sendAddCategory(connection, cat))
.map(CategoryModel::getId); .map(CategoryModel::getId);
} }
@WSReceiver(code = "createOrReplaceCategory", permission = PermLevel.ADMIN)
public Uni<Long> createOrReplaceCategory(WebSocketConnection connection, JustCategorie categorie) {
return matchRepository.list("category.compet.uuid = ?1 AND category.name = ?2", connection.pathParam("uuid"),
categorie.name)
.chain(existing -> {
if (existing.isEmpty())
return createCategory(connection, categorie);
Map<Long, List<MatchModel>> matchesByCategory = existing.stream()
.filter(m -> m.getCategory() != null)
.collect(Collectors.groupingBy(m -> m.getCategory().getId()));
for (Map.Entry<Long, List<MatchModel>> entry : matchesByCategory.entrySet()) {
Long categoryId = entry.getKey();
List<MatchModel> matches = entry.getValue();
if (matches.stream().noneMatch(m -> !m.getScores().isEmpty() || m.isEnd()))
return Panache.withTransaction(() -> updateCategory(connection, categorie, categoryId)
.call(__ -> treeRepository.delete("category = ?1", categoryId))
.call(__ -> matchRepository.delete("category.id = ?1", categoryId)))
.replaceWith(categoryId);
}
return createCategory(connection, categorie);
});
}
@WSReceiver(code = "updateCategory", permission = PermLevel.ADMIN) @WSReceiver(code = "updateCategory", permission = PermLevel.ADMIN)
public Uni<Void> updateCategory(WebSocketConnection connection, JustCategorie categorie) { public Uni<Void> updateCategory(WebSocketConnection connection, JustCategorie categorie) {
return getById(categorie.id, connection) return updateCategory(connection, categorie, categorie.id);
}
private Uni<Void> updateCategory(WebSocketConnection connection, JustCategorie categorie, Long id) {
return getById(id, connection)
.call(cat -> {
if (categorie.preset() == null) {
cat.setPreset(null);
return Uni.createFrom().item(cat);
} else {
return catPresetRepository.findById(categorie.preset().getId())
.invoke(cat::setPreset);
}
})
.chain(cat -> { .chain(cat -> {
cat.setName(categorie.name); cat.setName(categorie.name);
cat.setLiceName(categorie.liceName); cat.setLiceName(categorie.liceName);
cat.setType(categorie.type); cat.setType(categorie.type);
cat.setTreeAreClassement(categorie.treeAreClassement);
cat.setFullClassement(categorie.fullClassement);
return Panache.withTransaction(() -> categoryRepository.persist(cat)); return Panache.withTransaction(() -> categoryRepository.persist(cat));
}) })
.call(cat -> { .call(cat -> {
@@ -118,9 +189,10 @@ public class RCategorie {
uni = uni.chain(__ -> treeRepository.delete("category = ?1", cat.getId())) uni = uni.chain(__ -> treeRepository.delete("category = ?1", cat.getId()))
.chain(__ -> matchRepository.delete("category = ?1 AND category_ord = -42", cat)); .chain(__ -> matchRepository.delete("category = ?1 AND category_ord = -42", cat));
} }
return uni; Uni<Long> finalUni = uni;
return Panache.withTransaction(() -> finalUni);
}) })
.call(cat -> SSCategorie.sendCategory(connection, cat)) .invoke(cat -> SSCategorie.sendCategory(connection, cat))
.replaceWithVoid(); .replaceWithVoid();
} }
@@ -201,14 +273,169 @@ public class RCategorie {
.call(__ -> treeRepository.flush()) .call(__ -> treeRepository.flush())
.call(cat -> treeRepository.list("category = ?1 AND level != 0", cat.getId()) .call(cat -> treeRepository.list("category = ?1 AND level != 0", cat.getId())
.map(treeModels -> treeModels.stream().map(TreeEntity::fromModel).toList()) .map(treeModels -> treeModels.stream().map(TreeEntity::fromModel).toList())
.chain(trees -> SSCategorie.sendTreeCategory(connection, trees))) .invoke(trees -> SSCategorie.sendTreeCategory(connection, trees)))
.replaceWithVoid(); .replaceWithVoid();
} }
@WSReceiver(code = "deleteCategory", permission = PermLevel.ADMIN)
public Uni<Void> deleteCategory(WebSocketConnection connection, Long id) {
return getById(id, connection)
.call(cat -> Panache.withTransaction(() -> treeRepository.delete("category = ?1", cat.getId())
.call(__ -> matchRepository.delete("category = ?1", cat))))
.chain(cat -> Panache.withTransaction(() -> categoryRepository.delete(cat)))
.invoke(__ -> SSCategorie.sendDelCategory(connection, id))
.replaceWithVoid();
}
@WSReceiver(code = "listPreset", permission = PermLevel.VIEW)
public Uni<List<PresetData>> listPreset(WebSocketConnection connection, Object o) {
return catPresetRepository.list("competition.uuid", connection.pathParam("uuid"))
.map(presets -> presets.stream().map(PresetData::fromModel).toList());
}
@WSReceiver(code = "createClassementMatchs", permission = PermLevel.TABLE)
public Uni<Void> createClassementMatchs(WebSocketConnection connection, Long categoryId) {
return getById(categoryId, connection)
.call(cat -> {
PermLevel perm = PermLevel.valueOf(connection.userData().get(UserData.TypedKey.forString("prem")));
if (perm == PermLevel.TABLE) {
return matchRepository.list("category = ?1 AND category_ord = -42", cat.getId())
.chain(l -> l.stream().anyMatch(MatchModel::isEnd) ?
Uni.createFrom().failure(
new DForbiddenException(trad.t("err.match.termine", connection))) :
Uni.createFrom().voidItem());
}
return Uni.createFrom().voidItem();
})
.call(cat -> treeRepository.list("category = ?1 AND level <= -10", cat.getId())
.map(l -> l.stream().map(o -> o.getMatch().getId()).toList())
.call(__ -> treeRepository.delete("category = ?1 AND level <= -10", cat.getId()))
.call(ids -> matchRepository.delete("id IN ?1", ids)))
.call(cat -> Mutiny.fetch(cat.getTree()))
.call(cat -> {
List<MatchModel> toSave = new ArrayList<>();
if (!cat.getTree().isEmpty()) {
for (TreeModel treeModel : cat.getTree())
cleanTree(treeModel, toSave);
}
return Panache.withTransaction(() -> matchRepository.persist(toSave))
.invoke(__ -> SSMatch.sendMatch(connection,
toSave.stream().map(MatchEntity::fromModel).toList()));
})
.chain(cat -> Mutiny.fetch(cat.getMatchs())
.chain(list -> cardRepository.list("competition = ?1", cat.getCompet())
.map(c -> list.stream().map(m -> new MatchModelExtend(m, c)).toList()))
.map(matchModels -> {
ResultCategoryData out = new ResultCategoryData();
resultService.getArray2(matchModels, null, out);
out.getRankArray().remove('-');
return out;
})
.invoke(Unchecked.consumer(result -> {
if (result.getRankArray().size() != 2) {
throw new DForbiddenException(trad.t("configuration.non.supportee", connection));
}
}))
.chain(result -> {
List<MatchModel> toSave = new ArrayList<>();
List<MatchModel> toCreate = new ArrayList<>();
List<TreeModel> toSaveTree = new ArrayList<>();
int treeSize = 0;
List<TreeModel> lastNode = new ArrayList<>();
Optional<TreeModel> tree = cat.getTree().stream().filter(t -> t.getLevel() > 0)
.min(Comparator.comparing(TreeModel::getLevel));
if (tree.isPresent()) {
tree.get().getChildrenAtDepth(tree.get().death() - 1, 0, lastNode);
treeSize = lastNode.size();
}
Iterator<List<ResultCategoryData.RankArray>> iterator = result.getRankArray().values()
.iterator();
List<ResultCategoryData.RankArray> poule1 = iterator.next();
List<ResultCategoryData.RankArray> poule2 = iterator.next();
int maxToMixFill = Math.min(poule1.size(), poule2.size());
int maxToMixTreeFill = Math.min(treeSize, maxToMixFill);
for (int i = 0; i < maxToMixTreeFill; i++) {
CombModel comb1 = poule1.get(i).getComb();
CombModel comb2 = poule2.get(treeSize - i - 1).getComb();
fillMatchComb(lastNode.get(i).getMatch(), comb1, comb2);
toSave.add(lastNode.get(i).getMatch());
}
if (cat.isFullClassement()) {
for (int i = maxToMixTreeFill; i < maxToMixFill; i++) {
MatchModel match = new MatchModel();
match.setCategory(cat);
match.setCategory_ord(-42);
match.setEnd(false);
CombModel comb1 = poule1.get(i).getComb();
CombModel comb2 = poule2.get(i).getComb();
fillMatchComb(match, comb1, comb2);
toCreate.add(match);
toSaveTree.add(new TreeModel(cat.getId(), -10 - i, match));
}
}
return Panache.withTransaction(() -> matchRepository.persist(toSave)
.call(__ -> matchRepository.create(toCreate)))
.call(__ -> toSaveTree.isEmpty() ? Uni.createFrom().voidItem()
: Panache.withTransaction(() -> treeRepository.persist(toSaveTree)))
.map(__ -> Stream.concat(toSave.stream(), toCreate.stream())
.map(MatchEntity::fromModel).toList());
})
)
.onFailure().invoke(t -> System.out.println("error: " + t.getMessage()))
.invoke(matchEntities -> SSMatch.sendMatch(connection, matchEntities))
.call(__ -> treeRepository.list("category = ?1 AND level != 0", categoryId)
.map(treeModels -> treeModels.stream().map(TreeEntity::fromModel).toList())
.invoke(trees -> SSCategorie.sendTreeCategory(connection, trees)))
.replaceWithVoid();
}
private void cleanTree(TreeModel treeModel, List<MatchModel> toSave) {
MatchModel model = treeModel.getMatch();
if (model != null) {
model.setC1_id(null);
model.setC1_guest(null);
model.setC2_id(null);
model.setC2_guest(null);
model.setEnd(false);
model.setDate(null);
model.getScores().clear();
toSave.add(model);
}
if (treeModel.getLeft() != null)
cleanTree(treeModel.getLeft(), toSave);
if (treeModel.getRight() != null)
cleanTree(treeModel.getRight(), toSave);
}
private void fillMatchComb(MatchModel match, CombModel comb1, CombModel comb2) {
if (comb1 instanceof MembreModel m)
match.setC1_id(m);
else if (comb1 instanceof CompetitionGuestModel g)
match.setC1_guest(g);
if (comb2 instanceof MembreModel m)
match.setC2_id(m);
else if (comb2 instanceof CompetitionGuestModel g)
match.setC2_guest(g);
}
@RegisterForReflection @RegisterForReflection
public record JustCategorie(long id, String name, int type, String liceName) { public record JustCategorie(long id, String name, int type, String liceName, boolean treeAreClassement,
boolean fullClassement, PresetData preset) {
public static JustCategorie from(CategoryModel m) { public static JustCategorie from(CategoryModel m) {
return new JustCategorie(m.getId(), m.getName(), m.getType(), m.getLiceName()); return new JustCategorie(m.getId(), m.getName(), m.getType(), m.getLiceName(), m.isTreeAreClassement(),
m.isFullClassement(), PresetData.fromModel(m.getPreset()));
} }
} }
@@ -223,7 +450,11 @@ public class RCategorie {
String name; String name;
int type; int type;
String liceName; String liceName;
boolean treeAreClassement = false;
boolean fullClassement = false;
PresetData preset;
List<TreeEntity> trees = null; List<TreeEntity> trees = null;
List<MatchEntity> matches; List<MatchEntity> matches;
List<CardModel> cards;
} }
} }

View File

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

View File

@@ -0,0 +1,112 @@
package fr.titionfire.ffsaf.ws.recv;
import fr.titionfire.ffsaf.data.model.CardModel;
import fr.titionfire.ffsaf.data.model.CategoryModel;
import fr.titionfire.ffsaf.data.model.MatchModel;
import fr.titionfire.ffsaf.data.repository.CardRepository;
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.domain.entity.MatchModelExtend;
import fr.titionfire.ffsaf.domain.service.ResultService;
import fr.titionfire.ffsaf.domain.service.TradService;
import fr.titionfire.ffsaf.rest.data.ResultCategoryData;
import fr.titionfire.ffsaf.utils.Categorie;
import fr.titionfire.ffsaf.ws.PermLevel;
import io.quarkus.hibernate.reactive.panache.common.WithSession;
import io.quarkus.runtime.annotations.RegisterForReflection;
import io.quarkus.websockets.next.WebSocketConnection;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import org.hibernate.reactive.mutiny.Mutiny;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Stream;
@WithSession
@ApplicationScoped
@RegisterForReflection
public class RPDF {
@Inject
CompetitionRepository competitionRepository;
@Inject
MatchRepository matchRepository;
@Inject
CardRepository cardRepository;
@Inject
CategoryRepository categoryRepository;
@Inject
ResultService resultService;
@Inject
TradService trad;
@Transactional
@WSReceiver(code = "getPodium", permission = PermLevel.VIEW)
public Uni<List<PodiumEntity>> getPodium(WebSocketConnection connection, Object o) {
List<CardModel> cards = new java.util.ArrayList<>();
return cardRepository.list("competition.uuid = ?1", connection.pathParam("uuid"))
.invoke(cards::addAll)
.chain(__ -> matchRepository.list("category.compet.uuid = ?1", connection.pathParam("uuid")))
.chain(matchs -> {
HashMap<CategoryModel, List<MatchModel>> map = new HashMap<>();
for (MatchModel match : matchs) {
if (!map.containsKey(match.getCategory()))
map.put(match.getCategory(), new java.util.ArrayList<>());
map.get(match.getCategory()).add(match);
}
return Multi.createFrom().iterable(map.entrySet())
.onItem().call(entry -> Mutiny.fetch(entry.getKey().getTree()))
.map(entry -> {
ResultCategoryData tmp = new ResultCategoryData();
double cmoy = entry.getValue().stream().flatMap(m -> Stream.of(m.getC1(), m.getC2()))
.filter(c -> c != null && c.getCategorie() != null)
.mapToInt(c -> c.getCategorie().ordinal())
.average().orElse(0);
Categorie categorie_moy = Categorie.values()[(int) Math.ceil(cmoy)];
resultService.getArray2(
entry.getValue().stream().map(m -> new MatchModelExtend(m, cards)).toList(),
null, tmp);
resultService.getClassementArray(entry.getKey(), null, cards, tmp);
String source = "";
if ((entry.getKey().getType() & 2) != 0) {
if (entry.getKey().isTreeAreClassement())
source = trad.t("podium.source.classement", connection);
else
source = trad.t("podium.source.tree", connection);
} else if ((entry.getKey().getType() & 1) != 0)
source = trad.t("podium.source.poule", connection);
return new PodiumEntity(entry.getKey().getName(), source, categorie_moy,
tmp.getClassement());
})
.collect().asList();
});
}
@WSReceiver(code = "getPodiumClub", permission = PermLevel.VIEW)
public Uni<List<ResultService.ClubClassement>> getPodiumClub(WebSocketConnection connection, Object o) {
return resultService.getAllClubArray(connection.pathParam("uuid"), false);
}
@RegisterForReflection
public static record PodiumEntity(String poule_name, String source, Categorie categorie,
List<ResultCategoryData.ClassementData> podium) {
}
}

View File

@@ -6,6 +6,7 @@ import fr.titionfire.ffsaf.ws.PermLevel;
import io.quarkus.hibernate.reactive.panache.common.WithSession; import io.quarkus.hibernate.reactive.panache.common.WithSession;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
import io.quarkus.websockets.next.WebSocketConnection; import io.quarkus.websockets.next.WebSocketConnection;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject; import jakarta.inject.Inject;
@@ -24,14 +25,20 @@ public class RRegister {
@WSReceiver(code = "getRegister", permission = PermLevel.TABLE) @WSReceiver(code = "getRegister", permission = PermLevel.TABLE)
public Uni<List<CombEntity>> getRegister(WebSocketConnection connection, Object o) { public Uni<List<CombEntity>> getRegister(WebSocketConnection connection, Object o) {
return competitionRepository.find("uuid", connection.pathParam("uuid")).firstResult()
.call(cm -> Mutiny.fetch(cm.getInsc()))
.call(cm -> Mutiny.fetch(cm.getGuests()))
.map(cm -> {
ArrayList<CombEntity> combEntities = new ArrayList<>(); ArrayList<CombEntity> combEntities = new ArrayList<>();
combEntities.addAll(cm.getInsc().stream().map(CombEntity::fromModel).toList()); return competitionRepository.find("uuid", connection.pathParam("uuid")).firstResult()
combEntities.addAll(cm.getGuests().stream().map(CombEntity::fromModel).toList()); .call(cm -> Mutiny.fetch(cm.getInsc())
return combEntities; .onItem().transformToMulti(Multi.createFrom()::iterable)
}); .call(r -> Mutiny.fetch(r.getCategoriesInscrites()))
.map(r -> CombEntity.fromModel(r).addCategoriesInscrites(r.getCategoriesInscrites()))
.collect().asList()
.invoke(combEntities::addAll))
.call(cm -> Mutiny.fetch(cm.getGuests())
.onItem().transformToMulti(Multi.createFrom()::iterable)
.call(r -> Mutiny.fetch(r.getCategoriesInscrites()))
.map(r -> CombEntity.fromModel(r).addCategoriesInscrites(r.getCategoriesInscrites()))
.collect().asList()
.invoke(combEntities::addAll))
.replaceWith(combEntities);
} }
} }

View File

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

View File

@@ -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<Float> 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((float) s.stream().mapToDouble(Float::doubleValue)
.average()
.orElse(0));
}
team.setCountry(Stream.concat(
pair.getKey().stream().map(m -> m.getMembre().getCountry()),
pair.getValue().stream().map(CompetitionGuestModel::getCountry))
.filter(Objects::nonNull)
.map(String::toUpperCase)
.collect(Collectors.groupingBy(
e -> e, // Classer par élément
Collectors.counting() // Compter les occurrences
))
.entrySet()
.stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.orElse("FR"));
team.getComb().addAll(
pair.getKey().stream().map(RegisterModel::getMembre).toList());
team.getGuest().addAll(pair.getValue());
CompetitionGuestModel finalTeam = team;
return Panache.withTransaction(
() -> competitionGuestRepository.persistAndFlush(finalTeam))
.map(CombEntity::fromModel);
}))
)
.invoke(combEntity -> {
if (combEntity != null)
SSRegister.sendRegister(connection, combEntity);
});
}
@RegisterForReflection
public record TeamData(List<Long> members, String name) {
}
}

View File

@@ -3,6 +3,7 @@ package fr.titionfire.ffsaf.ws.send;
import fr.titionfire.ffsaf.data.model.CompetitionGuestModel; import fr.titionfire.ffsaf.data.model.CompetitionGuestModel;
import fr.titionfire.ffsaf.data.model.RegisterModel; import fr.titionfire.ffsaf.data.model.RegisterModel;
import fr.titionfire.ffsaf.domain.entity.CombEntity; import fr.titionfire.ffsaf.domain.entity.CombEntity;
import fr.titionfire.ffsaf.domain.service.CardService;
import fr.titionfire.ffsaf.net2.MessageType; import fr.titionfire.ffsaf.net2.MessageType;
import fr.titionfire.ffsaf.ws.CompetitionWS; import fr.titionfire.ffsaf.ws.CompetitionWS;
import fr.titionfire.ffsaf.ws.MessageOut; import fr.titionfire.ffsaf.ws.MessageOut;
@@ -13,6 +14,7 @@ import io.quarkus.websockets.next.UserData;
import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import org.hibernate.reactive.mutiny.Mutiny;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@@ -25,16 +27,48 @@ public class SRegister {
@Inject @Inject
OpenConnections connections; OpenConnections connections;
@Inject
CardService cardService;
public Uni<Void> sendRegister(String uuid, RegisterModel registerModel) { public Uni<Void> sendRegister(String uuid, RegisterModel registerModel) {
return send(uuid, "sendRegister", CombEntity.fromModel(registerModel)); return Mutiny.fetch(registerModel.getCategoriesInscrites()).chain(o ->
send(uuid, "sendRegister", CombEntity.fromModel(registerModel).addCategoriesInscrites(o))
.call(__ -> registerModel.getClub2() == null ? Uni.createFrom().voidItem() :
cardService.addTeamCartToNewComb(registerModel.getMembre().getId(),
registerModel.getClub2().getClubId(), registerModel.getClub2().getName(),
registerModel.getCompetition())
.chain(cardModels -> send(uuid, "sendCards", cardModels))));
}
public Uni<Void> sendRegisterNoFetch(String uuid, RegisterModel registerModel) {
return send(uuid, "sendRegister",
CombEntity.fromModel(registerModel).addCategoriesInscrites(registerModel.getCategoriesInscrites()))
.call(__ -> registerModel.getClub2() == null ? Uni.createFrom().voidItem() :
cardService.addTeamCartToNewComb(registerModel.getMembre().getId(),
registerModel.getClub2().getClubId(), registerModel.getClub2().getName(),
registerModel.getCompetition())
.chain(cardModels -> send(uuid, "sendCards", cardModels)));
} }
public Uni<Void> sendRegister(String uuid, CompetitionGuestModel model) { public Uni<Void> sendRegister(String uuid, CompetitionGuestModel model) {
return send(uuid, "sendRegister", CombEntity.fromModel(model)); return Mutiny.fetch(model.getCategoriesInscrites()).chain(o ->
send(uuid, "sendRegister", CombEntity.fromModel(model).addCategoriesInscrites(o))
.call(__ -> cardService.addTeamCartToNewComb(model.getId() * -1,
null, model.getClub(), model.getCompetition())
.chain(cardModels -> send(uuid, "sendCards", cardModels))));
}
public Uni<Void> sendRegisterNoFetch(String uuid, CompetitionGuestModel model) {
return send(uuid, "sendRegister",
CombEntity.fromModel(model).addCategoriesInscrites(model.getCategoriesInscrites()))
.call(__ -> cardService.addTeamCartToNewComb(model.getId() * -1,
null, model.getClub(), model.getCompetition())
.chain(cardModels -> send(uuid, "sendCards", cardModels)));
} }
public Uni<Void> sendRegisterRemove(String uuid, Long combId) { public Uni<Void> sendRegisterRemove(String uuid, Long combId) {
return send(uuid, "sendRegisterRemove", combId); return send(uuid, "sendRegisterRemove", combId)
.call(__ -> cardService.rmTeamCardFromComb(combId, uuid));
} }
public Uni<Void> send(String uuid, String code, Object data) { public Uni<Void> send(String uuid, String code, Object data) {

View File

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

View File

@@ -1,13 +0,0 @@
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);
}
}

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