303 Commits

Author SHA1 Message Date
dcaa79245c Merge pull request 'dev' (#124) from dev into master
Reviewed-on: #124
2026-08-06 14:17:49 +00:00
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
72f8a27272 Merge pull request 'fix: cache refresh v2' (#123) from dev into master
Reviewed-on: #123
2026-03-23 21:12:00 +00: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
a1e5006e95 Merge pull request 'fix: cache refresh' (#122) from dev into master
Reviewed-on: #122
2026-03-23 15:31:19 +00: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
d357328e48 Merge pull request 'fix: add log in getAllClubArray' (#121) from dev into master
Reviewed-on: #121
2026-03-23 15:06:51 +00: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
f9e4b83ad3 Merge pull request 'hot fix: remove save score button 2' (#120) from dev into master
Reviewed-on: #120
2026-03-21 11:09:17 +00: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
ae087084e9 Merge pull request 'hot fix: remove save score button' (#119) from dev into master
Reviewed-on: #119
2026-03-21 11:00:12 +00: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
5afef2bcab Merge pull request 'fix: change obs lice name location' (#118) from dev into master
Reviewed-on: #118
2026-03-20 15:40:37 +00: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
55d39e02d2 Merge pull request 'fix: clear pub aff when no cat select' (#117) from dev into master
Reviewed-on: #117
2026-03-20 15:11:17 +00: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
d5c1273e18 Merge pull request 'fix: change methode for move upload file' (#116) from dev into master
Reviewed-on: #116
2026-03-18 12:07:58 +00: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
eda96d5ed2 Merge pull request 'fix: add more log for file copy' (#115) from dev into master
Reviewed-on: #115
2026-03-18 10:07:00 +00: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
3a4e2f160f Merge pull request 'fix: add log for file copy' (#114) from dev into master
Reviewed-on: #114
2026-03-18 09:48:37 +00: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
2b84854ef2 Merge pull request 'fix: obs support wss' (#113) from dev into master
Reviewed-on: #113
2026-03-17 22:16:29 +00: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
fc3bea7f76 Merge pull request 'fix: language detection' (#112) from dev into master
Reviewed-on: #112
2026-03-16 11:19:50 +00: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
e67e01640a Merge pull request 'fix: club guest mixing in result' (#111) from dev into master
Reviewed-on: #111
2026-03-10 17:47:33 +00: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
e870ffdda0 Merge pull request 'fix: eslint version' (#110) from dev into master
Reviewed-on: #110
2026-03-09 12:19:27 +00: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
378a17ba75 Merge pull request 'dev' (#109) from dev into master
Reviewed-on: #109
2026-03-09 12:10:46 +00: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
3cb12826d0 Merge pull request 'dev' (#108) from dev into master
Reviewed-on: #108
2026-02-20 16:59:40 +00: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
72b248d09d Merge pull request 'dev' (#107) from dev into master
Reviewed-on: #107
2026-02-06 16:18:39 +00: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
34a6911fa0 Merge pull request 'dev' (#106) from dev into master
Reviewed-on: #106
2026-01-30 14:07:08 +00: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
59ba31ae2d Merge pull request 'dev' (#105) from dev into master
Reviewed-on: #105
2026-01-23 15:49:24 +00: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
4b56aa0209 Merge pull request 'dev' (#104) from dev into master
Reviewed-on: #104
2026-01-18 15:19:12 +00: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
eefa77369a Merge pull request 'feat: update js npm lib' (#103) from dev into master
Reviewed-on: #103
2026-01-16 15:21:11 +00: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
a942798a6c Merge pull request 'feat: add match eq support' (#102) from dev into master
Reviewed-on: #102
2026-01-16 14:37:55 +00: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
876545630a Merge pull request 'fix: translate backend asset includes in native' (#101) from dev into master
Reviewed-on: #101
2026-01-16 13:22:09 +00: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
cad6d14ba8 Merge pull request 'fix: translate backend add log' (#100) from dev into master
Reviewed-on: #100
2026-01-16 12:59:33 +00: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
d3fb884ab4 Merge pull request 'fix: Me page' (#75) from dev into master
Reviewed-on: #75
2025-12-26 13:16:56 +00:00
81faafe2de fix: Me page
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m46s
2025-12-26 14:16:30 +01:00
ee730be570 Merge pull request 'dev' (#74) from dev into master
Reviewed-on: #74
2025-12-25 19:03:17 +00:00
4856326b29 feat: html mail for all public
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 11m4s
2025-12-25 19:59:47 +01:00
b94f4b43ce fix: reword message + fix missing comb un cat list (cma) 2025-12-25 19:27:15 +01:00
795d044c0b fix:typo 2025-12-25 19:25:56 +01:00
dc5ab9c3c4 feat: add inactif member filter 2025-12-20 18:22:24 +01:00
870891a77c Merge pull request 'dev' (#73) from dev into master
Reviewed-on: #73
2025-12-19 15:14:04 +00:00
7e1356b621 fix: cm auto ask new category on empty competition
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m17s
2025-12-19 16:13:37 +01:00
b689521e56 fix: comb register with null license 2025-12-19 16:02:28 +01:00
e81f475402 Merge pull request 'dev-comp' (#72) from dev into master
Reviewed-on: #72
2025-12-19 13:47:40 +00:00
095a5fcede Merge branch 'dev-comp' into dev
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m20s
2025-12-19 14:43:46 +01:00
73f026210c feat: cm home page 2025-12-19 14:37:24 +01:00
4b969e6d69 feat: add CardPanel 2025-12-19 00:30:35 +01:00
4706af27f8 feat: add tooltip for menu 2025-12-18 19:19:25 +01:00
3e8c19534b feat: add score panel 2025-12-18 19:00:39 +01:00
3decc6d0e0 Merge pull request 'dev' (#71) from dev into master
Reviewed-on: #71
2025-12-18 15:37:19 +00:00
254fd7d73f feat: html email
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m5s
2025-12-18 16:36:30 +01:00
12a75d003c feat: mask inactive club on map 2025-12-18 15:33:45 +01:00
7f957b98f2 fix: deleteLicence Panache missing transaction context 2025-12-18 15:24:32 +01:00
8b2c9613fd Merge pull request 'dev' (#70) from dev into master
Reviewed-on: #70
2025-12-18 14:03:51 +00:00
50b49c40e3 fix: error 500 when license is null
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m6s
2025-12-18 15:03:22 +01:00
47d3921e05 fix: email typo 2025-12-18 14:57:26 +01:00
ecc9753237 Merge pull request 'feat: add cat filter on mass license validation' (#69) from dev into master
Reviewed-on: #69
2025-12-18 13:47:32 +00:00
7c4addd525 feat: add cat filter on mass license validation
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m27s
2025-12-18 14:46:52 +01:00
a1b5ca2694 fix: pubAdd chrono init 2025-12-17 21:00:43 +01:00
c5f7b81ac3 feat: move to MatchPanel 2025-12-17 20:54:04 +01:00
7f999733dc feat: chrono 2025-12-17 20:43:49 +01:00
0ac92fcda3 feat: add public screen 2025-12-15 23:08:46 +01:00
8e01fb46f8 feat: SmartLogoBackground 2025-12-15 21:00:19 +01:00
09a51edd5f wip: public screen 2025-12-10 00:08:14 +01:00
354fbfede9 feat: add flag svg 2025-12-09 22:49:25 +01:00
ef5b707697 feat: cm table next tree match + lock scores 2025-12-07 19:45:09 +01:00
489bfeb354 feat: cm table matches & scores 2025-12-07 15:12:48 +01:00
a8565534e6 update README.md 2025-12-05 15:28:03 +01:00
bb901392fc feat: cm admin poule editor 2025-12-02 15:58:20 +01:00
6f61db6817 feat: cm admin poule selector 2025-11-30 21:52:05 +01:00
00701fb874 feat: cm admin comb selector 2025-11-30 19:16:32 +01:00
936392f8bd feat: add guest comb to competition register form 2025-11-30 18:38:18 +01:00
f6d4bb0fe4 wip: cm admin comb selector 2025-11-26 12:37:32 +01:00
160c7d59e3 fix: move data model to good package 2025-11-25 18:43:40 +01:00
9689201a8c feat: add anti-blink timer 2025-11-25 17:24:21 +01:00
083d72fbfa feat: update Bootstrap 2025-11-25 17:18:25 +01:00
1c7466d883 fix: categorie perm 2025-11-25 17:17:48 +01:00
c9c8c8536d feat: add categorie info in CM 2025-11-24 19:28:04 +01:00
b1bcf75e56 feat: categorie on CM 2025-11-24 15:56:15 +01:00
b78b3f005b feat: implement ws 2025-11-21 14:06:46 +01:00
a83088387b wip: implement ws base 2025-11-20 23:39:02 +01:00
22fa896ee0 feat: competition result 2025-11-19 17:53:11 +01:00
f8976deb91 feat: re-add siret/rna api 2025-11-19 16:47:14 +01:00
eb9badb4a1 fix: error on loading logo on maps 2025-11-19 16:47:14 +01:00
661fcdb16b fix: remove siret/rna api 2025-11-19 16:47:14 +01:00
b2ad633b21 feat: membre list filter history 2025-11-19 16:47:13 +01:00
1b5bf8ba6c feat: add categorie filter membre search 2025-11-19 16:47:13 +01:00
bf75d9d036 feat: make user-friendly cat name 2025-11-19 16:47:13 +01:00
9457c5749a feat: add ordering for member page 2025-11-19 16:47:13 +01:00
c7f56881cd feat: upgrade club groupe name in kc when club is rename 2025-11-19 16:47:13 +01:00
aebcd62aa9 feat: upgrade aff find to user all id (Rna, siret, siren) 2025-11-19 16:47:13 +01:00
c2eecf4906 fix: certifDate NaN all membre export 2025-11-19 16:47:13 +01:00
87b3bc12e0 fix: null licence on import 2025-11-19 16:47:13 +01:00
3d3d63e58c fix: add more log to import 2025-11-19 16:47:13 +01:00
81c115c655 fix: empty mail on import 2025-11-19 16:47:13 +01:00
a7ba1d16a4 feat: remove kc new account mail 2025-11-19 16:47:13 +01:00
645949a2f6 feat: add cache to getAssoInfo 2025-11-19 16:47:13 +01:00
beb40db1b1 feat: merge rna and siret fields 2025-11-19 16:47:13 +01:00
61a4af6ff1 fix: club delete on RegisterModel 2025-11-19 16:47:13 +01:00
d9fc68298c feat: allow empty mail 2025-11-19 16:47:13 +01:00
fccea5bf6a fix: aff renew select length 2025-11-19 16:47:13 +01:00
ee476cd0e2 feat: remove saison selection on aff req 2025-11-19 16:47:13 +01:00
b320d7db37 fix: affiliation ok login msg 2025-11-19 16:47:13 +01:00
80fef98e07 feat: add email tooltip 2025-11-19 16:47:13 +01:00
7e80703c04 feat: add re-login message 2025-11-19 16:47:10 +01:00
cc4a3e4e06 fix: null email on import 2025-11-19 16:46:46 +01:00
9e28356f2c fix: log detail 2025-11-19 16:46:46 +01:00
77d66813c7 fix: log detail 2025-11-19 16:46:46 +01:00
7625da1d4b feat: add aff req log detail
fix: membre import null email filter
2025-11-19 16:46:46 +01:00
4262845074 fix: typo 2025-11-19 16:46:46 +01:00
b84e10de44 feat: keep log 2025-11-19 16:46:46 +01:00
ac6563ac95 fix: club order 2025-11-19 16:46:46 +01:00
baf57c3464 fix: log message length 2025-11-19 16:46:46 +01:00
43fcbb5ef6 Merge pull request 'feat: re-add siret/rna api' (#68) from dev into master
Reviewed-on: #68
2025-11-19 14:31:46 +00:00
fefc5d651b feat: re-add siret/rna api
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m4s
2025-11-19 15:26:36 +01:00
163d9b23e9 Merge pull request 'fix: error on loading logo on maps' (#67) from dev into master
Reviewed-on: #67
2025-11-18 21:02:58 +00:00
53509820c6 fix: error on loading logo on maps
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 9m58s
2025-11-18 22:02:13 +01:00
a8ad3a7558 Merge pull request 'fix: remove siret/rna api' (#66) from dev into master
Reviewed-on: #66
2025-11-18 20:46:34 +00:00
f46e268d39 fix: remove siret/rna api
Some checks failed
Deploy Production Server / if_merged (pull_request) Failing after 1m33s
2025-11-18 21:46:05 +01:00
abad3194a4 Merge pull request 'dev' (#65) from dev into master
Reviewed-on: #65
2025-11-18 19:32:14 +00:00
6e7eec0587 feat: membre list filter history
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m16s
2025-11-18 15:45:18 +01:00
8c83668364 feat: add categorie filter membre search 2025-11-18 14:02:02 +01:00
771c06ccd8 feat: make user-friendly cat name 2025-11-18 13:27:49 +01:00
b479b992cf feat: add ordering for member page 2025-11-17 21:48:24 +01:00
f018e52afa Merge pull request 'dev' (#64) from dev into master
Reviewed-on: #64
2025-11-14 15:55:53 +00:00
be2f01c070 feat: upgrade club groupe name in kc when club is rename
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m13s
2025-11-14 16:38:44 +01:00
9ab50238b9 feat: upgrade aff find to user all id (Rna, siret, siren) 2025-11-14 16:17:40 +01:00
cf5d93630f fix: certifDate NaN all membre export 2025-11-14 14:46:58 +01:00
e5e17d3862 Merge pull request 'fix: null licence on import' (#63) from dev into master
Reviewed-on: #63
2025-11-14 13:32:09 +00:00
7410569ced fix: null licence on import
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m3s
2025-11-14 14:31:37 +01:00
b107f443aa Merge pull request 'fix: add more log to import' (#62) from dev into master
Reviewed-on: #62
2025-11-14 13:15:27 +00:00
8e2d68ebd5 fix: add more log to import
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m10s
2025-11-14 14:14:22 +01:00
f050127fd7 Merge pull request 'dev' (#61) from dev into master
Reviewed-on: #61
2025-11-14 12:45:53 +00:00
d02fd63834 fix: empty mail on import
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m30s
2025-11-14 13:43:51 +01:00
b143cc759f feat: remove kc new account mail 2025-11-12 16:38:35 +01:00
cc5534ef00 feat: add cache to getAssoInfo 2025-11-12 16:15:40 +01:00
26f56006f6 feat: merge rna and siret fields 2025-11-12 14:56:28 +01:00
f8dacee3e7 Merge pull request 'fix: club delete on RegisterModel' (#60) from dev into master
Reviewed-on: #60
2025-11-08 18:09:04 +00:00
ed1f30f2b6 fix: club delete on RegisterModel
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m17s
2025-11-08 19:08:41 +01:00
8517e9824c Merge pull request 'feat: allow empty mail' (#59) from dev into master
Reviewed-on: #59
2025-11-08 17:45:02 +00:00
6cec8ff31d feat: allow empty mail
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m16s
2025-11-08 18:44:35 +01:00
e7deba52e9 Merge pull request 'dev' (#58) from dev into master
Reviewed-on: #58
2025-11-07 15:31:18 +00:00
d95c173fa8 fix: aff renew select length
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m51s
2025-11-07 16:19:49 +01:00
8a0e4423f2 feat: remove saison selection on aff req 2025-11-07 16:13:37 +01:00
b956236934 fix: affiliation ok login msg 2025-11-07 15:57:36 +01:00
7767c98304 feat: add email tooltip 2025-11-07 15:55:10 +01:00
7e380ccb69 feat: add re-login message 2025-11-07 15:31:25 +01:00
94d1148eb1 fix: null email on import 2025-11-07 15:30:56 +01:00
8a14f58ce5 Merge pull request 'fix: log detail' (#57) from dev into master
Reviewed-on: #57
2025-11-05 21:06:54 +00:00
79dbbdaaec fix: log detail
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m27s
2025-11-05 22:06:36 +01:00
bf5704db54 Merge pull request 'fix: log detail' (#56) from dev into master
Reviewed-on: #56
2025-11-05 20:43:26 +00:00
dec98f9508 fix: log detail
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m22s
2025-11-05 21:43:05 +01:00
d3a62e980d Merge pull request 'feat: add aff req log detail' (#55) from dev into master
Reviewed-on: #55
2025-11-05 20:19:10 +00:00
b89ed62795 feat: add aff req log detail
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m33s
fix: membre import null email filter
2025-11-05 21:18:29 +01:00
5ffc9fb495 Merge pull request 'fix: typo' (#54) from dev into master
Reviewed-on: #54
2025-09-05 18:31:45 +00:00
5e48bc4623 fix: typo
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 9m51s
2025-09-05 20:31:10 +02:00
81b953fb05 Merge pull request 'dev' (#53) from dev into master
Reviewed-on: #53
2025-09-03 19:47:13 +00:00
c6659f8d85 feat: keep log
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m19s
2025-09-03 21:46:26 +02:00
e86fe42b3d fix: club order 2025-09-03 21:35:36 +02:00
ef528aa524 fix: log message length 2025-09-03 19:53:19 +02:00
d1c7f37a94 feat: competition result 2025-09-03 18:56:58 +02:00
e6cc4cbc96 Merge pull request 'dev' (#52) from dev into master
Reviewed-on: #52
2025-08-21 09:43:54 +00:00
587173c79f feat: exel export register data
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m16s
2025-08-21 11:37:03 +02:00
0fc871bd46 feat: ban competition + competition list sort 2025-08-21 11:11:04 +02:00
2a1bdfbdcb feat: helloasso competition register 2025-08-20 22:38:05 +02:00
11dca5630c feat: register for club and free mode
wip: helloasso
2025-08-20 16:48:11 +02:00
c58dedf80a Merge pull request 'competition rework' (#51) from dev into master
Reviewed-on: #51
2025-08-18 09:33:51 +00:00
dedae02676 feat: rework competition perm, naming, competition data
All checks were successful
Deploy Production Server / if_merged (pull_request) Successful in 10m6s
2025-08-17 22:07:12 +02:00
9e9391465d feat: update competition perm 2025-08-16 11:14:41 +02:00
515 changed files with 28791 additions and 4895 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
@@ -76,6 +97,7 @@ jobs:
key: ${{ secrets.SSH_KEY }} key: ${{ secrets.SSH_KEY }}
script: | script: |
cd ${{ secrets.TARGET_DIR }} cd ${{ secrets.TARGET_DIR }}
docker logs ffsaf > "log/ffsaf_logs_$(date +"%Y-%m-%d_%H-%M-%S").log" 2>&1
docker stop ffsaf docker stop ffsaf
docker rm ffsaf docker rm ffsaf
docker compose up --build -d ffsaf docker compose up --build -d ffsaf

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

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

View File

@@ -20,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

23
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,12 +123,17 @@
<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>
<artifactId>quarkus-mailer</artifactId> <artifactId>quarkus-mailer</artifactId>
</dependency> </dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-websockets-next</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>

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();
LOG.infof("Request %s %s from IP %s", method, path, address); if (!path.equals("/api")) {
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

@@ -1,20 +1,17 @@
package fr.titionfire.ffsaf.data.id; package fr.titionfire.ffsaf.data.id;
import fr.titionfire.ffsaf.data.model.CompetitionModel; import jakarta.persistence.Embeddable;
import fr.titionfire.ffsaf.data.model.MembreModel; import lombok.*;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
@Data @Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@Embeddable
public class RegisterId implements Serializable { public class RegisterId implements Serializable {
@ManyToOne private Long competitionId;
@JoinColumn(name = "id_competition") private Long membreId;
private CompetitionModel competition;
@ManyToOne
@JoinColumn(name = "id_membre")
private MembreModel membre;
} }

View File

@@ -21,8 +21,7 @@ public class AffiliationRequestModel {
Long id; Long id;
String name; String name;
long siret; String state_id;
String RNA;
String address; String address;
String contact; String contact;

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

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

@@ -17,8 +17,8 @@ import java.util.List;
@RegisterForReflection @RegisterForReflection
@Entity @Entity
@Table(name = "poule") @Table(name = "category")
public class PouleModel { public class CategoryModel {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
Long id; Long id;
@@ -34,12 +34,24 @@ public class PouleModel {
CompetitionModel compet; CompetitionModel compet;
@OneToMany(fetch = FetchType.LAZY) @OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "id_poule", referencedColumnName = "id") @JoinColumn(name = "id_category", referencedColumnName = "id")
List<MatchModel> matchs; List<MatchModel> matchs;
@OneToMany(fetch = FetchType.LAZY) @OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "id_poule", referencedColumnName = "id") @JoinColumn(name = "id_category", referencedColumnName = "id")
List<TreeModel> tree; List<TreeModel> tree;
Integer type; Integer type;
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

@@ -55,11 +55,8 @@ public class ClubModel implements LoggableModel {
@Schema(description = "Adresse postale du club", example = "1 rue de l'exemple, 75000 Paris") @Schema(description = "Adresse postale du club", example = "1 rue de l'exemple, 75000 Paris")
String address; String address;
@Schema(description = "RNA du club", example = "W123456789") @Schema(description = "Numéro SIRET ou RNA du club", example = "12345678901234")
String RNA; String StateId;
@Schema(description = "Numéro SIRET du club", example = "12345678901234")
Long SIRET;
@Schema(description = "Numéro d'affiliation du club", example = "12345") @Schema(description = "Numéro d'affiliation du club", example = "12345")
Long no_affiliation; Long no_affiliation;

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

@@ -0,0 +1,115 @@
package fr.titionfire.ffsaf.data.model;
import fr.titionfire.ffsaf.utils.Categorie;
import fr.titionfire.ffsaf.utils.Genre;
import fr.titionfire.ffsaf.utils.ResultPrivacy;
import io.quarkus.runtime.annotations.RegisterForReflection;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@RegisterForReflection
@Entity
@Table(name = "competition_guest")
public class CompetitionGuestModel implements CombModel {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "competition", referencedColumnName = "id")
CompetitionModel competition;
String lname = "";
String fname = "";
Categorie categorie = null;
String club = null;
Genre genre = null;
String country = "fr";
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) {
this.fname = s.substring(0, s.indexOf(" "));
this.lname = s.substring(s.indexOf(" ") + 1);
}
@Override
public Long getCombId() {
return this.id * -1;
}
@Override
public String getName() {
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,6 +1,8 @@
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 io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
import jakarta.persistence.*; import jakarta.persistence.*;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@@ -8,6 +10,7 @@ import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@@ -21,6 +24,7 @@ import java.util.List;
@Table(name = "compet") @Table(name = "compet")
public class CompetitionModel { public class CompetitionModel {
@Id @Id
@Access(AccessType.PROPERTY)
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
Long id; Long id;
@@ -36,9 +40,47 @@ public class CompetitionModel {
String uuid; String uuid;
Date date; Date date;
Date todate;
@Column(columnDefinition = "TEXT")
String description;
String adresse;
Date startRegister;
Date endRegister;
RegisterMode registerMode;
boolean publicVisible;
@OneToMany(mappedBy = "competition", fetch = FetchType.LAZY, cascade = CascadeType.ALL) @OneToMany(mappedBy = "competition", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
List<RegisterModel> insc; List<RegisterModel> insc;
@OneToMany(mappedBy = "competition", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
List<CompetitionGuestModel> guests = new ArrayList<>();
@OneToMany(mappedBy = "competition", fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
List<CatPresetModel> catPreset = new ArrayList<>();
List<Categorie> requiredWeight = new ArrayList<>();
List<Long> banMembre = new ArrayList<>();
String owner; String owner;
List<String> admin = new ArrayList<>();
@Column(name = "table_")
List<String> table = new ArrayList<>();
@Column(columnDefinition = "TEXT")
String data1;
@Column(columnDefinition = "TEXT")
String data2;
@Column(columnDefinition = "TEXT")
String data3;
@Column(columnDefinition = "TEXT")
String data4;
@Column(columnDefinition = "TEXT")
String config;
} }

View File

@@ -0,0 +1,41 @@
package fr.titionfire.ffsaf.data.model;
import fr.titionfire.ffsaf.data.id.RegisterId;
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 = "helloasso_register")
public class HelloAssoRegisterModel {
@EmbeddedId
RegisterId id;
@MapsId("competitionId")
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name = "id_competition")
CompetitionModel competition;
@MapsId("membreId")
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name = "id_membre")
MembreModel membre;
Integer orderId;
public HelloAssoRegisterModel(CompetitionModel competition, MembreModel membre, Integer orderId) {
this.id = new RegisterId(competition.getId(), membre.getId());
this.competition = competition;
this.membre = membre;
this.orderId = orderId;
}
}

View File

@@ -30,8 +30,10 @@ public class LogModel {
Long target_id; Long target_id;
@Column(columnDefinition = "TEXT")
String target_name; String target_name;
@Column(columnDefinition = "TEXT")
String message; String message;
public enum ActionType { public enum ActionType {
@@ -39,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,13 +1,16 @@
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.*;
import lombok.*; import lombok.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Objects;
@Getter @Getter
@Setter @Setter
@@ -32,25 +35,119 @@ public class MatchModel {
@JoinColumn(name = "c1", referencedColumnName = "id") @JoinColumn(name = "c1", referencedColumnName = "id")
MembreModel c1_id = null; MembreModel c1_id = null;
String c1_str = null; @ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "c1_guest", referencedColumnName = "id")
CompetitionGuestModel c1_guest = null;
@ManyToOne(fetch = FetchType.EAGER) @ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "c2", referencedColumnName = "id") @JoinColumn(name = "c2", referencedColumnName = "id")
MembreModel c2_id = null; MembreModel c2_id = null;
String c2_str = null; @ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "c2_guest", referencedColumnName = "id")
CompetitionGuestModel c2_guest = null;
@ManyToOne(fetch = FetchType.EAGER) @ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "id_poule", referencedColumnName = "id") @JoinColumn(name = "id_category", referencedColumnName = "id")
PouleModel poule = null; CategoryModel category = null;
long poule_ord = 0; long category_ord = 0;
boolean isEnd = true; boolean isEnd = true;
Date date = null;
@ElementCollection(fetch = FetchType.EAGER) @ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "score", joinColumns = @JoinColumn(name = "id_match")) @CollectionTable(name = "score", joinColumns = @JoinColumn(name = "id_match"))
List<ScoreEmbeddable> scores = new ArrayList<>(); List<ScoreEmbeddable> scores = new ArrayList<>();
char groupe = 'A'; char poule = 'A';
public String getC1Name(MembreModel model, ResultPrivacy privacy) {
if (c1_id != null)
return c1_id.getName(model, privacy);
if (c1_guest != null)
return c1_guest.getName(model, privacy);
return "";
}
public String getC2Name(MembreModel model, ResultPrivacy privacy) {
if (c2_id != null)
return c2_id.getName(model, privacy);
if (c2_guest != null)
return c2_guest.getName(model, privacy);
return "";
}
public String getC1Name() {
if (c1_id != null)
return c1_id.getName();
if (c1_guest != null)
return c1_guest.getName();
return "";
}
public String getC2Name() {
if (c2_id != null)
return c2_id.getName();
if (c2_guest != null)
return c2_guest.getName();
return "";
}
public int win() {
int sum = 0;
for (ScoreEmbeddable score : this.getScores()) {
if (score.getS1() == -1000 || score.getS2() == -1000)
continue;
if (score.getS1() > score.getS2())
sum++;
else if (score.getS1() < score.getS2())
sum--;
}
return sum;
}
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;
@@ -82,4 +85,43 @@ public class MembreModel implements LoggableModel {
public LogModel.ObjectType getObjectType() { public LogModel.ObjectType getObjectType() {
return LogModel.ObjectType.Membre; return LogModel.ObjectType.Membre;
} }
@Override
public String toString() {
return "MembreModel{" +
"id=" + id +
", userId='" + userId + '\'' +
", lname='" + lname + '\'' +
", fname='" + fname + '\'' +
", categorie=" + categorie +
", genre=" + genre +
", licence=" + licence +
", country='" + country + '\'' +
", birth_date=" + birth_date +
", email='" + email + '\'' +
", role=" + role +
", grade_arbitrage=" + grade_arbitrage +
'}';
}
@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

@@ -8,6 +8,11 @@ import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import java.util.ArrayList;
import java.util.List;
@Getter @Getter
@Setter @Setter
@@ -17,24 +22,78 @@ import lombok.Setter;
@Entity @Entity
@Table(name = "register") @Table(name = "register")
@IdClass(RegisterId.class)
public class RegisterModel { public class RegisterModel {
@Id
@EmbeddedId
RegisterId id;
@MapsId("competitionId")
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "id_competition") @JoinColumn(name = "id_competition")
CompetitionModel competition; CompetitionModel competition;
@Id @MapsId("membreId")
@ManyToOne(fetch = FetchType.EAGER) @ManyToOne(fetch = FetchType.EAGER)
@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;
@ManyToOne(fetch = FetchType.EAGER) @ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "club") @JoinColumn(name = "club")
@OnDelete(action = OnDeleteAction.SET_NULL)
ClubModel club = null; ClubModel club = null;
@Column(nullable = false, columnDefinition = "boolean default false")
boolean lockEdit = false;
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@JoinTable(
name = "categories_insc_comb",
joinColumns = {
@JoinColumn(name = "id_competition", referencedColumnName = "id_competition"),
@JoinColumn(name = "id_membre", referencedColumnName = "id_membre")
},
inverseJoinColumns = @JoinColumn(name = "category_id")
)
List<CatPresetModel> categoriesInscrites = new ArrayList<>();
public RegisterModel(CompetitionModel competition, MembreModel membre, Float weight, int overCategory,
Categorie categorie, ClubModel club) {
this.id = new RegisterId(competition.getId(), membre.getId());
this.competition = competition;
this.membre = membre;
this.weight = weight;
this.overCategory = overCategory;
this.categorie = categorie;
this.club = club;
}
public String getName() {
return membre.fname + " " + membre.lname;
}
public ClubModel getClub2() {
if (club == null)
return membre.club;
return club;
}
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

@@ -7,6 +7,9 @@ import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
@Getter @Getter
@Setter @Setter
@AllArgsConstructor @AllArgsConstructor
@@ -20,8 +23,8 @@ public class TreeModel {
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
Long id; Long id;
@Column(name = "id_poule") @Column(name = "id_category")
Long poule; Long category;
Integer level; Integer level;
@@ -36,4 +39,68 @@ public class TreeModel {
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST) @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
@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() {
List<TreeModel> out = new ArrayList<>();
this.flat(out);
return out;
}
private void flat(List<TreeModel> out) {
out.add(this);
if (this.right != null)
this.right.flat(out);
if (this.left != null)
this.left.flat(out);
}
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

@@ -1,9 +1,10 @@
package fr.titionfire.ffsaf.data.repository; package fr.titionfire.ffsaf.data.repository;
import fr.titionfire.ffsaf.data.model.PouleModel; import fr.titionfire.ffsaf.data.model.CardModel;
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 PouleRepository implements PanacheRepositoryBase<PouleModel, Long> { public class CardRepository implements PanacheRepositoryBase<CardModel, Long> {
}
}

View File

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

View File

@@ -0,0 +1,19 @@
package fr.titionfire.ffsaf.data.repository;
import fr.titionfire.ffsaf.data.model.CategoryModel;
import fr.titionfire.ffsaf.utils.CompetitionSystem;
import io.quarkus.hibernate.reactive.panache.Panache;
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class CategoryRepository implements PanacheRepositoryBase<CategoryModel, Long> {
public Uni<CategoryModel> create(CategoryModel categoryModel) {
categoryModel.setSystem(CompetitionSystem.INTERNAL);
return Panache.withTransaction(() -> this.persist(categoryModel)
.invoke(categoryModel1 -> categoryModel1.setSystemId(categoryModel1.getId())))
.chain(this::persist);
}
}

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

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

View File

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

View File

@@ -1,9 +1,33 @@
package fr.titionfire.ffsaf.data.repository; package fr.titionfire.ffsaf.data.repository;
import fr.titionfire.ffsaf.data.model.MatchModel; import fr.titionfire.ffsaf.data.model.MatchModel;
import fr.titionfire.ffsaf.utils.CompetitionSystem;
import io.quarkus.hibernate.reactive.panache.Panache;
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase; import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.ApplicationScoped;
import java.util.List;
@ApplicationScoped @ApplicationScoped
public class MatchRepository implements PanacheRepositoryBase<MatchModel, Long> { public class MatchRepository implements PanacheRepositoryBase<MatchModel, Long> {
public Uni<MatchModel> create(MatchModel matchModel) {
matchModel.setSystem(CompetitionSystem.INTERNAL);
return Panache.withTransaction(() -> this.persistAndFlush(matchModel)
.invoke(matchModel1 -> matchModel1.setSystemId(matchModel1.getId())))
.chain(this::persist);
}
public Uni<Void> create(List<MatchModel> matchModel) {
if (matchModel.isEmpty())
return Uni.createFrom().voidItem();
matchModel.forEach(model -> model.setSystem(CompetitionSystem.INTERNAL));
return Panache.withTransaction(() -> this.persist(matchModel)
.call(__ -> this.flush())
.invoke(__ -> matchModel.forEach(model -> model.setSystemId(model.getId())))
.map(__ -> matchModel))
.chain(this::persist);
}
} }

View File

@@ -1,9 +1,11 @@
package fr.titionfire.ffsaf.data.repository; package fr.titionfire.ffsaf.data.repository;
import fr.titionfire.ffsaf.data.id.RegisterId;
import fr.titionfire.ffsaf.data.model.RegisterModel; import fr.titionfire.ffsaf.data.model.RegisterModel;
import io.quarkus.hibernate.reactive.panache.PanacheRepository; import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped @ApplicationScoped
public class RegisterRepository implements PanacheRepository<RegisterModel> { public class RegisterRepository implements PanacheRepositoryBase<RegisterModel, RegisterId> {
} }

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

@@ -2,8 +2,22 @@ package fr.titionfire.ffsaf.data.repository;
import fr.titionfire.ffsaf.data.model.TreeModel; import fr.titionfire.ffsaf.data.model.TreeModel;
import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase; import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase;
import io.quarkus.hibernate.reactive.panache.common.WithTransaction;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped @ApplicationScoped
public class TreeRepository implements PanacheRepositoryBase<TreeModel, Long> { public class TreeRepository implements PanacheRepositoryBase<TreeModel, Long> {
@WithTransaction
public Uni<Boolean> deleteTree(TreeModel entity) {
Uni<Boolean> uni = Uni.createFrom().item(false);
if (entity == null)
return uni;
if (entity.getLeft() != null)
uni = uni.chain(__ -> this.deleteTree(entity.getLeft()));
if (entity.getRight() != null)
uni = uni.chain(__ -> this.deleteTree(entity.getRight()));
return uni.chain(__ -> this.deleteById(entity.getId()));
}
} }

View File

@@ -22,8 +22,7 @@ public class ClubEntity {
private String training_location; private String training_location;
private String training_day_time; private String training_day_time;
private String contact_intern; private String contact_intern;
private String RNA; private String StateId;
private Long SIRET;
private Long no_affiliation; private Long no_affiliation;
private boolean international; private boolean international;
@@ -41,8 +40,7 @@ public class ClubEntity {
.training_location(model.getTraining_location()) .training_location(model.getTraining_location())
.training_day_time(model.getTraining_day_time()) .training_day_time(model.getTraining_day_time())
.contact_intern(model.getContact_intern()) .contact_intern(model.getContact_intern())
.RNA(model.getRNA()) .StateId(model.getStateId())
.SIRET(model.getSIRET())
.no_affiliation(model.getNo_affiliation()) .no_affiliation(model.getNo_affiliation())
.international(model.isInternational()) .international(model.isInternational())
.build(); .build();

View File

@@ -0,0 +1,76 @@
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.MembreModel;
import fr.titionfire.ffsaf.data.model.RegisterModel;
import fr.titionfire.ffsaf.utils.Categorie;
import fr.titionfire.ffsaf.utils.Genre;
import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
@Data
@AllArgsConstructor
@RegisterForReflection
public class CombEntity {
private long id;
private String lname;
private String fname;
Categorie categorie;
String club_uuid;
String club_str;
Genre genre;
String country;
int overCategory;
Float weight;
List<CombEntity> teamMembers;
List<Long> categoriesInscrites;
public static CombEntity fromModel(MembreModel model) {
if (model == null)
return null;
return new CombEntity(model.getId(), model.getLname(), model.getFname(), model.getCategorie(),
model.getClub() == null ? null : model.getClub().getClubId(),
model.getClub() == null ? "Sans club" : model.getClub().getName(), model.getGenre(), model.getCountry(),
0, null, new ArrayList<>(), new ArrayList<>());
}
public static CombEntity fromModel(CompetitionGuestModel model) {
if (model == null)
return null;
return new CombEntity(model.getId() * -1, model.getLname(), model.getFname(), model.getCategorie(), null,
model.getClub(), model.getGenre(), model.getCountry(), 0,
model.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) {
if (registerModel == null || registerModel.getMembre() == null)
return null;
MembreModel model = registerModel.getMembre();
return new CombEntity(model.getId(), model.getLname(), model.getFname(), registerModel.getCategorie(),
registerModel.getClub2() == null ? null : registerModel.getClub2().getClubId(),
registerModel.getClub2() == null ? "Sans club" : registerModel.getClub2().getName(), model.getGenre(),
model.getCountry(), registerModel.getOverCategory(),
registerModel.getWeight2() != null ? registerModel.getWeight2() : registerModel.getWeight(),
new ArrayList<>(), new ArrayList<>());
}
}

View File

@@ -0,0 +1,38 @@
package fr.titionfire.ffsaf.domain.entity;
import fr.titionfire.ffsaf.data.model.MatchModel;
import fr.titionfire.ffsaf.utils.ScoreEmbeddable;
import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.Date;
import java.util.List;
@Data
@AllArgsConstructor
@RegisterForReflection
public class MatchEntity {
private long id;
private CombEntity c1;
private CombEntity c2;
private long categorie_ord = 0;
private boolean isEnd;
private long categorie;
private Date date;
private List<ScoreEmbeddable> scores;
private char poule;
public static MatchEntity fromModel(MatchModel model) {
if (model == null)
return null;
return new MatchEntity(model.getId(),
(model.getC1_id() == null) ? CombEntity.fromModel(model.getC1_guest()) : CombEntity.fromModel(
model.getC1_id()),
(model.getC2_id() == null) ? CombEntity.fromModel(model.getC2_guest()) : CombEntity.fromModel(
model.getC2_id()),
model.getCategory_ord(), model.isEnd(), model.getCategory().getId(), model.getDate(),
model.getScores(),
model.getPoule());
}
}

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

@@ -0,0 +1,71 @@
package fr.titionfire.ffsaf.domain.entity;
import fr.titionfire.ffsaf.data.model.TreeModel;
import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
@RegisterForReflection
public class TreeEntity {
private Long id;
private Long categorie;
private Integer level;
private MatchEntity match;
private TreeEntity left;
private TreeEntity right;
private TreeEntity associatedNode;
public static TreeEntity fromModel(TreeModel model) {
if (model == null)
return null;
return new TreeEntity(model.getId(), model.getCategory(), model.getLevel(), MatchEntity.fromModel(model.getMatch()), fromModel(model.getLeft()),
fromModel(model.getRight()), null);
}
public TreeEntity getMatchNode(Long matchId) {
if (this.match != null && this.match.getId() == matchId) {
return this;
} else {
if (this.left != null) {
TreeEntity left = this.left.getMatchNode(matchId);
if (left != null) {
return left;
}
}
if (this.right != null) {
TreeEntity right = this.right.getMatchNode(matchId);
if (right != null) {
return right;
}
}
}
return null;
}
public static TreeEntity getParent(TreeEntity current, TreeEntity target) {
if (current == null) {
return null;
} else if (current.equals(target)) {
return null;
} else if (target.equals(current.left) || target.equals(current.right)) {
return current;
} else {
TreeEntity left = getParent(current.left, target);
if (left != null)
return left;
return getParent(current.right, target);
}
}
public static void setAssociated(TreeEntity current, TreeEntity next) {
if (current == null || next == null) {
return;
}
current.setAssociatedNode(next);
setAssociated(current.getLeft(), next.getLeft());
setAssociated(current.getRight(), next.getRight());
}
}

View File

@@ -2,6 +2,8 @@ package fr.titionfire.ffsaf.domain.service;
import fr.titionfire.ffsaf.data.model.*; import fr.titionfire.ffsaf.data.model.*;
import fr.titionfire.ffsaf.data.repository.*; import fr.titionfire.ffsaf.data.repository.*;
import fr.titionfire.ffsaf.rest.client.SirenService;
import fr.titionfire.ffsaf.rest.client.StateIdService;
import fr.titionfire.ffsaf.rest.data.SimpleAffiliation; import fr.titionfire.ffsaf.rest.data.SimpleAffiliation;
import fr.titionfire.ffsaf.rest.data.SimpleReqAffiliation; import fr.titionfire.ffsaf.rest.data.SimpleReqAffiliation;
import fr.titionfire.ffsaf.rest.exception.DBadRequestException; import fr.titionfire.ffsaf.rest.exception.DBadRequestException;
@@ -21,15 +23,19 @@ import io.smallrye.mutiny.unchecked.Unchecked;
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject; 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.hibernate.reactive.mutiny.Mutiny; import org.hibernate.reactive.mutiny.Mutiny;
import org.jboss.logging.Logger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream; import java.util.stream.Stream;
@WithSession @WithSession
@ApplicationScoped @ApplicationScoped
public class AffiliationService { public class AffiliationService {
private static final Logger LOGGER = Logger.getLogger(AffiliationService.class);
@Inject @Inject
CombRepository combRepository; CombRepository combRepository;
@@ -58,12 +64,24 @@ public class AffiliationService {
@Inject @Inject
LoggerService ls; LoggerService ls;
@Inject
VirusScannerService scanner;
@RestClient
StateIdService stateIdService;
@RestClient
SirenService sirenService;
@ConfigProperty(name = "upload_dir") @ConfigProperty(name = "upload_dir")
String media; String media;
@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();
} }
@@ -71,46 +89,60 @@ public class AffiliationService {
public Uni<AffiliationRequestModel> pre_save(AffiliationRequestForm form, boolean unique) { public Uni<AffiliationRequestModel> pre_save(AffiliationRequestForm form, boolean unique) {
AffiliationRequestModel affModel = form.toModel(); AffiliationRequestModel affModel = form.toModel();
int currentSaison = Utils.getSaison(); int currentSaison = Utils.getSaison();
List<String> out = new ArrayList<>();
out.add(affModel.getState_id());
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(() -> repositoryRequest.count("siret = ?1 and saison = ?2", affModel.getSiret(), .chain(() -> ((affModel.getState_id().charAt(0) == 'W') ? stateIdService.get_rna(
affModel.getSaison())) affModel.getState_id()) : sirenService.get_unite(affModel.getState_id())
.onItem().invoke(Unchecked.consumer(count -> { .chain(stateIdService::getAssoDataFromUnit)).onItem().transform(o -> {
if (count != 0 && unique) { if (o.getRna() != null && !o.getRna().isBlank())
throw new DBadRequestException("Demande d'affiliation déjà existante"); out.add(o.getRna());
} if (o.getSiren() != null && !o.getSiren().isBlank())
})) out.add(o.getSiren());
.chain(() -> clubRepository.find("SIRET = ?1", affModel.getSiret()).firstResult().chain(club -> if (o.getIdentite().getSiret_siege() != null && !o.getIdentite().getSiret_siege().isBlank())
out.add(o.getIdentite().getSiret_siege());
return out;
}).onFailure().recoverWithItem(out)
.chain(a -> repositoryRequest.count("state_id IN ?1 and saison = ?2",
out, affModel.getSaison()))
.onItem().invoke(Unchecked.consumer(count -> {
if (count != 0 && unique) {
throw new DBadRequestException(trad.t("demande.d.affiliation.deja.existante"));
}
}))
)
.chain(() -> clubRepository.find("StateId IN ?1", out).firstResult().chain(club ->
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())
); );
@@ -119,10 +151,9 @@ 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.setRNA(model.getRNA());
origine.setAddress(model.getAddress()); origine.setAddress(model.getAddress());
origine.setContact(model.getContact()); origine.setContact(model.getContact());
origine.setM1_lname(model.getM1_lname()); origine.setM1_lname(model.getM1_lname());
@@ -146,15 +177,15 @@ public class AffiliationService {
} }
public Uni<String> save(AffiliationRequestForm form) { public Uni<String> save(AffiliationRequestForm form) {
// noinspection ResultOfMethodCallIgnored,ReactiveStreamsUnusedPublisher LOGGER.debug("Affiliation Request Created");
LOGGER.debug(form.toString());
// 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",
@@ -169,12 +200,14 @@ public class AffiliationService {
} }
public Uni<?> saveAdmin(AffiliationRequestSaveForm form) { public Uni<?> saveAdmin(AffiliationRequestSaveForm form) {
LOGGER.debug("Affiliation Request Saved");
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.setSiret(form.getSiret()); model.setState_id(form.getState_id());
model.setRNA(form.getRna());
model.setAddress(form.getAddress()); model.setAddress(form.getAddress());
model.setContact(form.getContact()); model.setContact(form.getContact());
@@ -215,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");
} }
@@ -259,7 +289,9 @@ public class AffiliationService {
}).call(m -> Panache.withTransaction(() -> combRepository.persist(m))); }).call(m -> Panache.withTransaction(() -> combRepository.persist(m)));
} }
}) })
.call(m -> ((m.getUserId() == null) ? keycloakService.initCompte(m.getId()) : .call(m -> ((m.getUserId() == null) ? keycloakService.initCompte(m.getId())
.onFailure().invoke(t -> LOGGER.warnf("Failed to init account: %s", t.getMessage())).onFailure()
.recoverWithNull() :
keycloakService.setClubGroupMembre(m, club).map(__ -> m.getUserId())) keycloakService.setClubGroupMembre(m, club).map(__ -> m.getUserId()))
.call(userId -> keycloakService.setAutoRoleMembre(userId, m.getRole(), m.getGrade_arbitrage())) .call(userId -> keycloakService.setAutoRoleMembre(userId, m.getRole(), m.getGrade_arbitrage()))
.call(userId -> keycloakService.setEmail(userId, m.getEmail()))) .call(userId -> keycloakService.setEmail(userId, m.getEmail())))
@@ -267,28 +299,31 @@ public class AffiliationService {
.call(l1 -> l1 != null && l1.stream().anyMatch(l -> l.getSaison() == saison) ? .call(l1 -> l1 != null && l1.stream().anyMatch(l -> l.getSaison() == saison) ?
Uni.createFrom().nullItem() : Uni.createFrom().nullItem() :
Panache.withTransaction(() -> licenceRepository.persist( Panache.withTransaction(() -> licenceRepository.persist(
new LicenceModel(null, m, club.getId(), saison, null, true, false))) new LicenceModel(null, m, club.getId(), saison, null, true, false)))
.call(licenceModel -> ls.logA(LogModel.ActionType.ADD, m.getObjectName(), .call(licenceModel -> ls.logA(LogModel.ActionType.ADD, m.getObjectName(),
licenceModel)))); licenceModel))));
} }
public Uni<?> accept(AffiliationRequestSaveForm form) { public Uni<?> accept(AffiliationRequestSaveForm form) {
LOGGER.debug("Affiliation Request Accepted");
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("SIRET = ?1", form.getSiret()).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))
.call(club -> setMembre(form.new Member(1), club, req.getSaison()) .call(club -> setMembre(form.new Member(1), club, req.getSaison()).onFailure()
.call(__ -> setMembre(form.new Member(2), club, req.getSaison()) .recoverWithNull()
.call(__ -> setMembre(form.new Member(2), club, req.getSaison()).onFailure()
.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",
@@ -298,13 +333,13 @@ public class AffiliationService {
} }
private Uni<ClubModel> acceptNew(AffiliationRequestSaveForm form, AffiliationRequestModel model) { private Uni<ClubModel> acceptNew(AffiliationRequestSaveForm form, AffiliationRequestModel model) {
LOGGER.debug("New Club Accepted");
return Uni.createFrom().nullItem() return Uni.createFrom().nullItem()
.chain(() -> { .chain(() -> {
ClubModel club = new ClubModel(); ClubModel club = new ClubModel();
club.setName(form.getName()); club.setName(form.getName());
club.setCountry("FR"); club.setCountry("FR");
club.setSIRET(form.getSiret()); club.setStateId(form.getState_id());
club.setRNA(form.getRna());
club.setAddress(form.getAddress()); club.setAddress(form.getAddress());
club.setContact_intern(form.getContact()); club.setContact_intern(form.getContact());
club.setAffiliations(new ArrayList<>()); club.setAffiliations(new ArrayList<>());
@@ -318,43 +353,56 @@ public class AffiliationService {
.map(c -> club)); .map(c -> club));
}) })
.call(club -> reactiveMailer.send( .call(club -> reactiveMailer.send(
Mail.withText(form.getM1_email(), Mail.withHtml(form.getM1_email(), "FFSAF - Creation de votre compte sur l'intranet",
"FFSAF - Acceptation de votre demande d'affiliation", String.format(Utils.HTML_HEADER, "FFSAF - Creation de votre compte sur l'intranet") +
String.format( String.format("""
""" <p>Votre demande d'affiliation pour le club <span class="highlight">%s</span> a été acceptée.</p>
Bonjour, <p>LLe numéro d'affiliation de votre club est le <span class="highlight">%d</span>.</p>
""",
Votre demande d'affiliation pour le club %s a été acceptée. club.getName(), club.getNo_affiliation()) +
Le numéro d'affiliation de votre club est le %d. Utils.HTML_FOOTER
)
Cordialement, .setText(String.format("""
L'équipe de la FFSAF Bonjour,
""", club.getName(), club.getNo_affiliation())
).setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("contact@ffsaf.fr") Votre demande d'affiliation pour le club %s a été acceptée.
Le numéro d'affiliation de votre club est le %d.
Cordialement,
L'équipe de la FFSAF
""", club.getName(), club.getNo_affiliation()))
.setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("contact@ffsaf.fr")
.addTo(form.getM2_email(), form.getM3_email()) .addTo(form.getM2_email(), form.getM3_email())
)); ));
} }
private Uni<ClubModel> acceptOld(AffiliationRequestSaveForm form, AffiliationRequestModel model, ClubModel club) { private Uni<ClubModel> acceptOld(AffiliationRequestSaveForm form, AffiliationRequestModel model, ClubModel club) {
AtomicBoolean nameChange = new AtomicBoolean(false);
LOGGER.debug("Old Club Accepted");
return Uni.createFrom().nullItem() return Uni.createFrom().nullItem()
.chain(() -> { .chain(() -> {
club.setName(form.getName()); if (!form.getName().equals(club.getName())) {
club.setName(form.getName());
nameChange.set(true);
}
club.setCountry("FR"); club.setCountry("FR");
club.setSIRET(form.getSiret()); club.setStateId(form.getState_id());
club.setRNA(form.getRna());
club.setAddress(form.getAddress()); club.setAddress(form.getAddress());
club.setContact_intern(form.getContact()); club.setContact_intern(form.getContact());
return Panache.withTransaction(() -> clubRepository.persist(club) return Panache.withTransaction(() -> clubRepository.persist(club)
.chain(() -> repository.persist(new AffiliationModel(null, club, model.getSaison()))) .chain(() -> repository.persist(new AffiliationModel(null, club, model.getSaison())))
.chain(() -> repositoryRequest.delete(model))); .chain(() -> repositoryRequest.delete(model)))
.call(() -> nameChange.get() ? keycloakService.updateGroupFromClub(
club) // update group in keycloak
: Uni.createFrom().nullItem());
}) })
.map(__ -> club); .map(__ -> club);
} }
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("SIRET = ?1", out.getSiret()).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());
out.setClub_name(c.getName()); out.setClub_name(c.getName());
@@ -367,7 +415,7 @@ public class AffiliationService {
public Uni<List<SimpleAffiliation>> getCurrentSaisonAffiliation() { public Uni<List<SimpleAffiliation>> getCurrentSaisonAffiliation() {
return repositoryRequest.list("saison = ?1 or saison = ?1 + 1", Utils.getSaison()) return repositoryRequest.list("saison = ?1 or saison = ?1 + 1", Utils.getSaison())
.map(models -> models.stream() .map(models -> models.stream()
.map(model -> new SimpleAffiliation(model.getId() * -1, model.getSiret(), model.getSaison(), .map(model -> new SimpleAffiliation(model.getId() * -1, model.getState_id(), model.getSaison(),
false)).toList()) false)).toList())
.chain(aff -> repository.list("saison = ?1", Utils.getSaison()) .chain(aff -> repository.list("saison = ?1", Utils.getSaison())
.map(models -> models.stream().map(SimpleAffiliation::fromModel).toList()) .map(models -> models.stream().map(SimpleAffiliation::fromModel).toList())
@@ -377,11 +425,11 @@ 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("siret = ?1", model.getSIRET()) .chain(model -> repositoryRequest.list("state_id = ?1", model.getStateId())
.map(reqs -> reqs.stream().map(req -> .map(reqs -> reqs.stream().map(req ->
new SimpleAffiliation(req.getId() * -1, model.getId(), req.getSaison(), false))) new SimpleAffiliation(req.getId() * -1, model.getStateId(), req.getSaison(), false)))
.map(aff2 -> Stream.concat(aff2, .map(aff2 -> Stream.concat(aff2,
model.getAffiliations().stream().map(SimpleAffiliation::fromModel)).toList()) model.getAffiliations().stream().map(SimpleAffiliation::fromModel)).toList())
); );
@@ -389,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 ->
@@ -411,26 +459,32 @@ public class AffiliationService {
return Panache.withTransaction(() -> repository.deleteById(id)); return Panache.withTransaction(() -> repository.deleteById(id));
} }
public Uni<?> deleteReqAffiliation(long id, String reason) { public Uni<?> deleteReqAffiliation(long id, String reason, boolean federationAdmin) {
return repositoryRequest.findById(id) return repositoryRequest.findById(id)
.call(aff -> reactiveMailer.send( .call(aff -> federationAdmin ? reactiveMailer.send(
Mail.withText(aff.getM1_email(), Mail.withHtml(aff.getM1_email(), "FFSAF - Votre demande d'affiliation a été rejetée.",
"FFSAF - Votre demande d'affiliation a été rejetée.", String.format(Utils.HTML_HEADER, "FFSAF - Votre demande d'affiliation a été rejetée.") +
String.format( String.format("""
""" <p>Votre demande d'affiliation pour le club %s a été rejetée pour la/les raison(s) suivante(s):<br/>%s</p>
Bonjour, <p>Si vous rencontrez un problème ou si vous avez des questions, n'hésitez pas à nous contacter à l'adresse <a href="mailto:contact@ffsaf.fr">contact@ffsaf.fr</a>.</p>
""",
Votre demande d'affiliation pour le club %s a été rejetée pour la/les raison(s) suivante(s): aff.getName(), reason) +
%s Utils.HTML_FOOTER
)
Si vous rencontrez un problème ou si vous avez des questions, n'hésitez pas à nous contacter à l'adresse contact@ffsaf.fr. .setText(String.format("""
Bonjour,
Cordialement,
L'équipe de la FFSAF Votre demande d'affiliation pour le club %s a été rejetée pour la/les raison(s) suivante(s):
""", aff.getName(), reason) %s
).setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("contact@ffsaf.fr")
Si vous rencontrez un problème ou si vous avez des questions, n'hésitez pas à nous contacter à l'adresse contact@ffsaf.fr.
Cordialement,
L'équipe de la FFSAF
""", aff.getName(), reason))
.setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("contact@ffsaf.fr")
.addTo(aff.getM2_email(), aff.getM3_email()) .addTo(aff.getM2_email(), aff.getM3_email())
)) ) : Uni.createFrom().nullItem())
.chain(aff -> Panache.withTransaction(() -> repositoryRequest.delete(aff))) .chain(aff -> Panache.withTransaction(() -> repositoryRequest.delete(aff)))
.call(__ -> Utils.deleteMedia(id, media, "aff_request/logo")) .call(__ -> Utils.deleteMedia(id, media, "aff_request/logo"))
.call(__ -> Utils.deleteMedia(id, media, "aff_request/status")); .call(__ -> Utils.deleteMedia(id, media, "aff_request/status"));

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

@@ -1,12 +1,9 @@
package fr.titionfire.ffsaf.domain.service; package fr.titionfire.ffsaf.domain.service;
import fr.titionfire.ffsaf.data.model.MatchModel; import fr.titionfire.ffsaf.data.model.*;
import fr.titionfire.ffsaf.data.model.MembreModel;
import fr.titionfire.ffsaf.data.model.PouleModel;
import fr.titionfire.ffsaf.data.model.TreeModel;
import fr.titionfire.ffsaf.data.repository.*; import fr.titionfire.ffsaf.data.repository.*;
import fr.titionfire.ffsaf.rest.data.PouleData; import fr.titionfire.ffsaf.rest.data.CategoryData;
import fr.titionfire.ffsaf.rest.data.PouleFullData; import fr.titionfire.ffsaf.rest.data.CategoryFullData;
import fr.titionfire.ffsaf.rest.data.TreeData; import fr.titionfire.ffsaf.rest.data.TreeData;
import fr.titionfire.ffsaf.utils.CompetitionSystem; import fr.titionfire.ffsaf.utils.CompetitionSystem;
import fr.titionfire.ffsaf.utils.SecurityCtx; import fr.titionfire.ffsaf.utils.SecurityCtx;
@@ -25,10 +22,10 @@ import java.util.stream.Stream;
@WithSession @WithSession
@ApplicationScoped @ApplicationScoped
public class PouleService { public class CategoryService {
@Inject @Inject
PouleRepository repository; CategoryRepository repository;
@Inject @Inject
CompetitionRepository competRepository; CompetitionRepository competRepository;
@@ -45,43 +42,35 @@ public class PouleService {
@Inject @Inject
CompetPermService permService; CompetPermService permService;
public Uni<PouleData> getById(SecurityCtx securityCtx, CompetitionSystem system, Long id) { @Inject
CompetitionGuestRepository competitionGuestRepository;
@Inject
TradService trad;
public Uni<CategoryData> getByIdAdmin(SecurityCtx securityCtx, CompetitionSystem system, Long id) {
return repository.find("systemId = ?1 AND system = ?2", id, system) return repository.find("systemId = ?1 AND system = ?2", id, system)
.firstResult() .firstResult()
.onItem().ifNull().failWith(() -> new RuntimeException("Poule not found")) .onItem().ifNull().failWith(() -> new RuntimeException(trad.t("categorie.non.trouver")))
.call(data -> permService.hasViewPerm(securityCtx, data.getCompet())) .call(data -> permService.hasAdminViewPerm(securityCtx, data.getCompet()))
.map(PouleData::fromModel); .map(CategoryData::fromModel);
} }
public Uni<List<PouleData>> getAll(SecurityCtx securityCtx, CompetitionSystem system) { public Uni<List<CategoryData>> getAllAdmin(SecurityCtx securityCtx, CompetitionSystem system) {
return repository.list("system = ?1", system) return permService.getAllHaveAdminAccess(securityCtx)
.chain(o -> .chain(ids -> repository.list("system = ?1 AND compet.id IN ?2", system, ids))
permService.getAllHaveAccess(securityCtx.getSubject()) .map(pouleModels -> pouleModels.stream().map(CategoryData::fromModel).toList());
.chain(map -> Uni.createFrom().item(o.stream()
.filter(p -> {
if (securityCtx.getSubject().equals(p.getCompet().getOwner()))
return true;
if (p.getSystem() == CompetitionSystem.SAFCA) {
if (map.containsKey(p.getCompet().getId()))
return map.get(p.getId()).equals("admin");
return securityCtx.roleHas("federation_admin")
|| securityCtx.roleHas("safca_super_admin");
}
return securityCtx.roleHas("federation_admin");
})
.map(PouleData::fromModel).toList())
));
} }
public Uni<PouleData> addOrUpdate(SecurityCtx securityCtx, CompetitionSystem system, PouleData data) { public Uni<CategoryData> addOrUpdate(SecurityCtx securityCtx, CompetitionSystem system, CategoryData data) {
return repository.find("systemId = ?1 AND system = ?2", data.getId(), system).firstResult() return repository.find("systemId = ?1 AND system = ?2", data.getId(), system).firstResult()
.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 -> {
PouleModel model = new PouleModel(); CategoryModel model = new CategoryModel();
model.setId(null); model.setId(null);
model.setSystem(system); model.setSystem(system);
@@ -99,7 +88,7 @@ public class PouleService {
o.setType(data.getType()); o.setType(data.getType());
return Panache.withTransaction(() -> repository.persist(o)); return Panache.withTransaction(() -> repository.persist(o));
} }
}).map(PouleData::fromModel); }).map(CategoryData::fromModel);
} }
private MatchModel findMatch(List<MatchModel> matchModelList, Long id) { private MatchModel findMatch(List<MatchModel> matchModelList, Long id) {
@@ -128,7 +117,7 @@ public class PouleService {
} }
} }
private Uni<TreeModel> persisteTree(TreeData data, List<TreeModel> node, PouleModel poule, private Uni<TreeModel> persisteTree(TreeData data, List<TreeModel> node, CategoryModel poule,
List<MatchModel> matchModelList) { List<MatchModel> matchModelList) {
TreeModel mm = findNode(node, data.getMatch()); TreeModel mm = findNode(node, data.getMatch());
if (mm == null) { if (mm == null) {
@@ -136,7 +125,7 @@ public class PouleService {
mm.setId(null); mm.setId(null);
} }
mm.setLevel(data.getLevel()); mm.setLevel(data.getLevel());
mm.setPoule(poule.getId()); mm.setCategory(poule.getId());
mm.setMatch(findMatch(matchModelList, data.getMatch())); mm.setMatch(findMatch(matchModelList, data.getMatch()));
return Uni.createFrom().item(mm) return Uni.createFrom().item(mm)
@@ -147,16 +136,16 @@ public class PouleService {
.chain(o -> Panache.withTransaction(() -> treeRepository.persist(o))); .chain(o -> Panache.withTransaction(() -> treeRepository.persist(o)));
} }
public Uni<?> syncPoule(SecurityCtx securityCtx, CompetitionSystem system, PouleFullData data) { public Uni<?> syncCategory(SecurityCtx securityCtx, CompetitionSystem system, CategoryFullData data) {
return repository.find("systemId = ?1 AND system = ?2", data.getId(), system) return repository.find("systemId = ?1 AND system = ?2", data.getId(), system)
.firstResult() .firstResult()
.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 -> {
PouleModel model = new PouleModel(); CategoryModel model = new CategoryModel();
model.setId(null); model.setId(null);
model.setSystem(system); model.setSystem(system);
model.setSystemId(data.getId()); model.setSystemId(data.getId());
@@ -172,10 +161,10 @@ public class PouleService {
o.setType(data.getType()); o.setType(data.getType());
WorkData workData = new WorkData(); WorkData workData = new WorkData();
workData.poule = o; workData.category = o;
return workData; return workData;
}) })
.call(o -> Panache.withTransaction(() -> repository.persist(o.poule))) .call(o -> Panache.withTransaction(() -> repository.persist(o.category)))
.call(o -> (data.getMatches() == null || data.getMatches().isEmpty()) ? Uni.createFrom().nullItem() : .call(o -> (data.getMatches() == null || data.getMatches().isEmpty()) ? Uni.createFrom().nullItem() :
Uni.createFrom() Uni.createFrom()
.item(data.getMatches().stream().flatMap(m -> Stream.of(m.getC1_id(), m.getC2_id()) .item(data.getMatches().stream().flatMap(m -> Stream.of(m.getC1_id(), m.getC2_id())
@@ -185,9 +174,18 @@ public class PouleService {
.invoke(o2 -> o2.forEach(m -> o.membres.put(m.getId(), m))) .invoke(o2 -> o2.forEach(m -> o.membres.put(m.getId(), m)))
) )
) )
.call(o -> Mutiny.fetch(o.category.getCompet().getGuests())
.invoke(o2 -> o2.forEach(m -> o.guest.put(m.getFname() + " " + m.getLname(), m)))
.map(o2 -> data.getMatches().stream().flatMap(m -> Stream.of(m.getC1_str(), m.getC2_str())
.filter(Objects::nonNull)).distinct().filter(s -> !o.guest.containsKey(s)).map(
CompetitionGuestModel::new).toList())
.call(o3 -> o3.isEmpty() ? Uni.createFrom().nullItem() :
Uni.join().all(o3.stream().map(o4 -> competitionGuestRepository.persist(o4)).toList())
.andFailFast())
.invoke(o2 -> o2.forEach(m -> o.guest.put(m.getFname() + " " + m.getLname(), m))))
.invoke(in -> { .invoke(in -> {
ArrayList<TreeModel> node = new ArrayList<>(); ArrayList<TreeModel> node = new ArrayList<>();
for (TreeModel treeModel : in.poule.getTree()) for (TreeModel treeModel : in.category.getTree())
flatTreeChild(treeModel, node); flatTreeChild(treeModel, node);
ArrayList<TreeData> new_node = new ArrayList<>(); ArrayList<TreeData> new_node = new ArrayList<>();
@@ -204,7 +202,7 @@ public class PouleService {
n.setLeft(null); n.setLeft(null);
}); });
in.toRmMatch = in.poule.getMatchs().stream() in.toRmMatch = in.category.getMatchs().stream()
.filter(m -> data.getMatches().stream().noneMatch(m2 -> m2.getId().equals(m.getSystemId()))) .filter(m -> data.getMatches().stream().noneMatch(m2 -> m2.getId().equals(m.getSystemId())))
.map(MatchModel::getId).toList(); .map(MatchModel::getId).toList();
}) })
@@ -219,21 +217,21 @@ public class PouleService {
.call(in -> data.getMatches().isEmpty() ? Uni.createFrom().nullItem() : .call(in -> data.getMatches().isEmpty() ? Uni.createFrom().nullItem() :
Uni.join().all( Uni.join().all(
data.getMatches().stream().map(m -> { data.getMatches().stream().map(m -> {
MatchModel mm = findMatch(in.poule.getMatchs(), m.getId()); MatchModel mm = findMatch(in.category.getMatchs(), m.getId());
if (mm == null) { if (mm == null) {
mm = new MatchModel(); mm = new MatchModel();
mm.setId(null); mm.setId(null);
mm.setSystem(system); mm.setSystem(system);
mm.setSystemId(m.getId()); mm.setSystemId(m.getId());
} }
mm.setPoule(in.poule); mm.setCategory(in.category);
mm.setPoule_ord(m.getPoule_ord()); mm.setCategory_ord(m.getCategory_ord());
mm.setC1_str(m.getC1_str()); mm.setC1_guest(in.guest.getOrDefault(m.getC1_str(), null));
mm.setC2_str(m.getC2_str()); mm.setC2_guest(in.guest.getOrDefault(m.getC2_str(), null));
mm.setC1_id(in.membres.getOrDefault(m.getC1_id(), null)); mm.setC1_id(in.membres.getOrDefault(m.getC1_id(), null));
mm.setC2_id(in.membres.getOrDefault(m.getC2_id(), null)); mm.setC2_id(in.membres.getOrDefault(m.getC2_id(), null));
mm.setEnd(m.isEnd()); mm.setEnd(m.isEnd());
mm.setGroupe(m.getGroupe()); mm.setPoule(m.getPoule());
mm.getScores().clear(); mm.getScores().clear();
mm.getScores().addAll(m.getScores()); mm.getScores().addAll(m.getScores());
@@ -244,14 +242,15 @@ public class PouleService {
.andCollectFailures()) .andCollectFailures())
.call(in -> data.getTrees().isEmpty() ? Uni.createFrom().nullItem() : .call(in -> data.getTrees().isEmpty() ? Uni.createFrom().nullItem() :
Uni.join().all(data.getTrees().stream() Uni.join().all(data.getTrees().stream()
.map(m -> persisteTree(m, in.poule.getTree(), in.poule, in.match)).toList()) .map(m -> persisteTree(m, in.category.getTree(), in.category, in.match)).toList())
.andCollectFailures()) .andCollectFailures())
.map(__ -> "OK"); .map(__ -> "OK");
} }
private static class WorkData { private static class WorkData {
PouleModel poule; CategoryModel category;
HashMap<Long, MembreModel> membres = new HashMap<>(); HashMap<Long, MembreModel> membres = new HashMap<>();
HashMap<String, CompetitionGuestModel> guest = new HashMap<>();
List<MatchModel> match = new ArrayList<>(); List<MatchModel> match = new ArrayList<>();
List<Long> toRmMatch; List<Long> toRmMatch;
List<TreeModel> unlinkNode; List<TreeModel> unlinkNode;
@@ -260,7 +259,7 @@ public class PouleService {
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("Poule 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() :
@@ -274,7 +273,7 @@ public class PouleService {
Panache.withTransaction(() -> treeRepository.delete("id IN ?1", in))) Panache.withTransaction(() -> treeRepository.delete("id IN ?1", in)))
) )
) )
.call(o -> matchRepository.delete("poule.id = ?1", o.getId())) .call(o -> matchRepository.delete("category.id = ?1", o.getId()))
.chain(model -> Panache.withTransaction(() -> repository.delete("id", model.getId()))); .chain(model -> Panache.withTransaction(() -> repository.delete("id", model.getId())));
} }
} }

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

@@ -5,15 +5,13 @@ import com.fasterxml.jackson.core.type.TypeReference;
import fr.titionfire.ffsaf.data.model.AffiliationModel; import fr.titionfire.ffsaf.data.model.AffiliationModel;
import fr.titionfire.ffsaf.data.model.ClubModel; import fr.titionfire.ffsaf.data.model.ClubModel;
import fr.titionfire.ffsaf.data.model.MembreModel; import fr.titionfire.ffsaf.data.model.MembreModel;
import fr.titionfire.ffsaf.data.repository.AffiliationRepository;
import fr.titionfire.ffsaf.data.repository.ClubRepository; import fr.titionfire.ffsaf.data.repository.ClubRepository;
import fr.titionfire.ffsaf.data.repository.CombRepository; import fr.titionfire.ffsaf.data.repository.CombRepository;
import fr.titionfire.ffsaf.net2.ServerCustom; import fr.titionfire.ffsaf.net2.ServerCustom;
import fr.titionfire.ffsaf.net2.data.SimpleClubModel; import fr.titionfire.ffsaf.net2.data.SimpleClubModel;
import fr.titionfire.ffsaf.net2.request.SReqClub; import fr.titionfire.ffsaf.net2.request.SReqClub;
import fr.titionfire.ffsaf.rest.data.ClubMapData; import fr.titionfire.ffsaf.rest.data.*;
import fr.titionfire.ffsaf.rest.data.DeskMember;
import fr.titionfire.ffsaf.rest.data.RenewAffData;
import fr.titionfire.ffsaf.rest.data.SimpleClubList;
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;
@@ -35,6 +33,7 @@ import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.hibernate.reactive.mutiny.Mutiny; import org.hibernate.reactive.mutiny.Mutiny;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer; import java.util.function.Consumer;
import static fr.titionfire.ffsaf.net2.Client_Thread.MAPPER; import static fr.titionfire.ffsaf.net2.Client_Thread.MAPPER;
@@ -46,6 +45,9 @@ public class ClubService {
@Inject @Inject
ClubRepository repository; ClubRepository repository;
@Inject
AffiliationRepository affiliationRepository;
@Inject @Inject
ServerCustom serverCustom; ServerCustom serverCustom;
@@ -61,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)));
@@ -128,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()));
@@ -144,6 +149,19 @@ public class ClubService {
.toList()); .toList());
} }
public Uni<List<VerySimpleMembre>> getMembers(SecurityCtx securityCtx) {
return combRepository.find("userId = ?1", securityCtx.getSubject()).firstResult()
.invoke(Unchecked.consumer(m -> {
if (m == null || m.getClub() == null)
throw new DNotFoundException(trad.t("club.non.trouve"));
if (!securityCtx.isInClubGroup(m.getClub().getId()))
throw new DForbiddenException();
}))
.chain(m -> combRepository.list("club = ?1", m.getClub()))
.map(membreModels -> membreModels.stream()
.map(m -> new VerySimpleMembre(m.getLname(), m.getFname(), m.getLicence())).toList());
}
public Uni<String> updateOfUser(SecurityCtx securityCtx, PartClubForm form) { public Uni<String> updateOfUser(SecurityCtx securityCtx, PartClubForm form) {
TypeReference<HashMap<Contact, String>> typeRef = new TypeReference<>() { TypeReference<HashMap<Contact, String>> typeRef = new TypeReference<>() {
}; };
@@ -151,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();
})) }))
@@ -168,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(),
@@ -183,12 +201,17 @@ public class ClubService {
} }
public Uni<String> update(long id, FullClubForm input) { public Uni<String> update(long id, FullClubForm input) {
AtomicBoolean nameChange = new AtomicBoolean(false);
return repository.findById(id).call(m -> Mutiny.fetch(m.getContact())) return repository.findById(id).call(m -> Mutiny.fetch(m.getContact()))
.onItem().transformToUni(Unchecked.function(m -> { .onItem().transformToUni(Unchecked.function(m -> {
TypeReference<HashMap<Contact, String>> typeRef = new TypeReference<>() { TypeReference<HashMap<Contact, String>> typeRef = new TypeReference<>() {
}; };
m.setName(input.getName()); if (!input.getName().equals(m.getName())) {
m.setName(input.getName());
nameChange.set(true);
}
m.setCountry(input.getCountry()); m.setCountry(input.getCountry());
m.setInternational(input.isInternational()); m.setInternational(input.isInternational());
@@ -201,11 +224,9 @@ public class ClubService {
m.setTraining_day_time(input.getTraining_day_time()); m.setTraining_day_time(input.getTraining_day_time());
ls.logChange("Contact interne", m.getContact_intern(), input.getContact_intern(), m); ls.logChange("Contact interne", m.getContact_intern(), input.getContact_intern(), m);
m.setContact_intern(input.getContact_intern()); m.setContact_intern(input.getContact_intern());
ls.logChange("N° RNA", m.getRNA(), input.getRna(), m); if (input.getState_id() != null && !input.getState_id().isBlank()) {
m.setRNA(input.getRna()); ls.logChange("N° SIRET", m.getClubId(), input.getState_id(), m);
if (input.getSiret() != null && !input.getSiret().isBlank()) { m.setStateId(input.getState_id());
ls.logChange("N° SIRET", m.getSIRET(), input.getSiret(), m);
m.setSIRET(Long.parseLong(input.getSiret()));
} }
ls.logChange("Adresse administrative", m.getAddress(), input.getAddress(), m); ls.logChange("Adresse administrative", m.getAddress(), input.getAddress(), m);
m.setAddress(input.getAddress()); m.setAddress(input.getAddress());
@@ -215,11 +236,14 @@ 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());
})) }))
.call(clubModel -> nameChange.get() ? keycloakService.updateGroupFromClub(
clubModel) // update group in keycloak
: Uni.createFrom().nullItem())
.invoke(membreModel -> SReqClub.sendIfNeed(serverCustom.clients, .invoke(membreModel -> SReqClub.sendIfNeed(serverCustom.clients,
SimpleClubModel.fromModel(membreModel))) SimpleClubModel.fromModel(membreModel)))
.map(__ -> "OK"); .map(__ -> "OK");
@@ -241,9 +265,8 @@ public class ClubService {
clubModel.setTraining_location(input.getTraining_location()); clubModel.setTraining_location(input.getTraining_location());
clubModel.setTraining_day_time(input.getTraining_day_time()); clubModel.setTraining_day_time(input.getTraining_day_time());
clubModel.setContact_intern(input.getContact_intern()); clubModel.setContact_intern(input.getContact_intern());
clubModel.setRNA(input.getRna()); if (input.getState_id() != null && !input.getState_id().isBlank())
if (input.getSiret() != null && !input.getSiret().isBlank()) clubModel.setStateId(input.getState_id());
clubModel.setSIRET(Long.parseLong(input.getSiret()));
clubModel.setAddress(input.getAddress()); clubModel.setAddress(input.getAddress());
try { try {
@@ -267,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()
@@ -290,9 +315,9 @@ public class ClubService {
.call(clubModel -> Mutiny.fetch(clubModel.getAffiliations())) .call(clubModel -> Mutiny.fetch(clubModel.getAffiliations()))
.invoke(clubModel -> { .invoke(clubModel -> {
data.setName(clubModel.getName()); data.setName(clubModel.getName());
data.setSiret(clubModel.getSIRET()); data.setState_id(clubModel.getStateId());
data.setRna(clubModel.getRNA());
data.setAddress(clubModel.getAddress()); data.setAddress(clubModel.getAddress());
data.setContact(clubModel.getContact_intern());
data.setSaison( data.setSaison(
clubModel.getAffiliations().stream().max(Comparator.comparing(AffiliationModel::getSaison)) clubModel.getAffiliations().stream().max(Comparator.comparing(AffiliationModel::getSaison))
.map(AffiliationModel::getSaison).map(i -> Math.min(i + 1, Utils.getSaison() + 1)) .map(AffiliationModel::getSaison).map(i -> Math.min(i + 1, Utils.getSaison() + 1))
@@ -308,9 +333,11 @@ public class ClubService {
} }
public Uni<List<ClubMapData>> getMapData() { public Uni<List<ClubMapData>> getMapData() {
return repository.list("international", false).toMulti().flatMap(list -> Multi.createFrom().iterable(list)) return affiliationRepository.list("saison >= ?1 AND club.international = ?2", Utils.getSaison() - 1, false)
.call(clubModel -> Mutiny.fetch(clubModel.getContact())) .toMulti().flatMap(list -> Multi.createFrom().iterable(list))
.map(clubModel -> { .call(affiliationModel -> Mutiny.fetch(affiliationModel.getClub().getContact()))
.map(affiliationModel -> {
ClubModel clubModel = affiliationModel.getClub();
ClubMapData data = new ClubMapData(); ClubMapData data = new ClubMapData();
data.setName(clubModel.getName()); data.setName(clubModel.getName());

View File

@@ -2,11 +2,13 @@ package fr.titionfire.ffsaf.domain.service;
import fr.titionfire.ffsaf.data.model.CompetitionModel; import fr.titionfire.ffsaf.data.model.CompetitionModel;
import fr.titionfire.ffsaf.data.repository.CompetitionRepository; import fr.titionfire.ffsaf.data.repository.CompetitionRepository;
import fr.titionfire.ffsaf.data.repository.RegisterRepository;
import fr.titionfire.ffsaf.net2.ServerCustom; import fr.titionfire.ffsaf.net2.ServerCustom;
import fr.titionfire.ffsaf.net2.data.SimpleCompet; 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.rest.exception.DForbiddenException; import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.utils.CompetitionSystem; import fr.titionfire.ffsaf.utils.CompetitionSystem;
import fr.titionfire.ffsaf.utils.RegisterMode;
import fr.titionfire.ffsaf.utils.SecurityCtx; import fr.titionfire.ffsaf.utils.SecurityCtx;
import io.quarkus.cache.Cache; import io.quarkus.cache.Cache;
import io.quarkus.cache.CacheName; import io.quarkus.cache.CacheName;
@@ -15,7 +17,10 @@ import io.smallrye.mutiny.unchecked.Unchecked;
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@@ -28,6 +33,9 @@ public class CompetPermService {
@Inject @Inject
ServerCustom serverCustom; ServerCustom serverCustom;
@Inject
CompetitionRepository competitionRepository;
@Inject @Inject
@CacheName("safca-config") @CacheName("safca-config")
Cache cache; Cache cache;
@@ -37,76 +45,240 @@ public class CompetPermService {
Cache cacheAccess; Cache cacheAccess;
@Inject @Inject
CompetitionRepository competitionRepository; @CacheName("have-access")
Cache cacheNoneAccess;
@Inject
RegisterRepository registerRepository;
public Uni<SimpleCompet> getSafcaConfig(long id) { public Uni<SimpleCompet> getSafcaConfig(long id) {
return cache.get(id, k -> { return cache.get(id, k -> {
CompletableFuture<SimpleCompet> f = new CompletableFuture<>(); CompletableFuture<SimpleCompet> f = new CompletableFuture<>();
SReqCompet.getConfig(serverCustom.clients, id, f); SReqCompet.getConfig(serverCustom.clients, id, f);
System.out.println("get config");
try { try {
return f.get(1500, TimeUnit.MILLISECONDS); return f.get(500, TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) { } catch (InterruptedException | ExecutionException | TimeoutException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
}); });
} }
public Uni<HashMap<Long, String>> getAllHaveAccess(String subject) { public Uni<List<Long>> getAllHaveAdminAccess(SecurityCtx securityCtx) {
return cacheAccess.get(subject, k -> { ArrayList<Long> out = new ArrayList<>();
CompletableFuture<HashMap<Long, String>> f = new CompletableFuture<>();
SReqCompet.getAllHaveAccess(serverCustom.clients, subject, f); Uni<HashMap<Long, String>> safca = cacheAccess.getAsync(securityCtx.getSubject(),
System.out.println("get all have access"); k -> competitionRepository.list("system = ?1", CompetitionSystem.SAFCA)
try { .chain(competitionModels -> {
return f.get(1500, TimeUnit.MILLISECONDS); CompletableFuture<HashMap<String, String>> f = new CompletableFuture<>();
} catch (InterruptedException | ExecutionException | TimeoutException e) { SReqCompet.getAllHaveAccess(serverCustom.clients, securityCtx.getSubject(), f);
throw new RuntimeException(e); return Uni.createFrom().future(f, Duration.ofMillis(500))
} .onFailure().recoverWithItem(new HashMap<>())
}); .map(map_ -> {
HashMap<Long, String> map = new HashMap<>();
map_.forEach((key, value) -> map.put(Long.parseLong(key), value));
for (CompetitionModel model : competitionModels) {
if (model.getOwner().equals(securityCtx.getSubject()))
map.putIfAbsent(model.getId(), "owner");
else if (securityCtx.roleHas("federation_admin")
|| securityCtx.roleHas("safca_super_admin"))
map.putIfAbsent(model.getId(), "admin");
}
return map;
});
}))
.onFailure().call(throwable -> cacheAccess.invalidate(securityCtx.getSubject()));
Uni<HashMap<Long, String>> none = cacheNoneAccess.getAsync(securityCtx.getSubject(),
k -> competitionRepository.list("system = ?1", CompetitionSystem.INTERNAL)
.map(competitionModels -> {
HashMap<Long, String> map = new HashMap<>();
for (CompetitionModel model : competitionModels) {
if (model.getOwner().equals(securityCtx.getSubject()))
map.putIfAbsent(model.getId(), "owner");
else if (securityCtx.roleHas("federation_admin"))
map.putIfAbsent(model.getId(), "admin");
else if (securityCtx.isInClubGroup(
model.getClub().getId()) && (securityCtx.isClubAdmin()))
map.putIfAbsent(model.getId(), "admin");
else if (model.getAdmin().contains(securityCtx.getSubject()))
map.putIfAbsent(model.getId(), "admin");
else if (model.getTable().contains(securityCtx.getSubject()))
map.putIfAbsent(model.getId(), "table");
}
return map;
}));
return safca.invoke(map ->
map.forEach((k, v) -> {
if (v.equals("owner") || v.equals("admin"))
out.add(k);
})
)
.call(__ -> none.invoke(map ->
map.forEach((k, v) -> {
if (v.equals("owner") || v.equals("admin"))
out.add(k);
})
))
.map(__ -> out.stream().distinct().toList());
} }
/**
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has view perm
*/
public Uni<CompetitionModel> hasViewPerm(SecurityCtx securityCtx, CompetitionModel competitionModel) { public Uni<CompetitionModel> hasViewPerm(SecurityCtx securityCtx, CompetitionModel competitionModel) {
return hasViewPerm(securityCtx, Uni.createFrom().item(competitionModel)); return hasViewPerm(securityCtx, Uni.createFrom().item(competitionModel));
} }
/**
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has view perm
*/
public Uni<CompetitionModel> hasViewPerm(SecurityCtx securityCtx, long id) { public Uni<CompetitionModel> hasViewPerm(SecurityCtx securityCtx, long id) {
return hasViewPerm(securityCtx, competitionRepository.findById(id)); return hasViewPerm(securityCtx, competitionRepository.findById(id));
} }
private Uni<CompetitionModel> hasViewPerm(SecurityCtx securityCtx, Uni<CompetitionModel> in) { /**
return in.call(o -> ( * @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has view perm
securityCtx.getSubject().equals(o.getOwner()) || securityCtx.roleHas("federation_admin")) ? */
Uni.createFrom().nullItem() public Uni<CompetitionModel> hasViewPerm(SecurityCtx securityCtx, Uni<CompetitionModel> in) {
: return in.call(cm -> (cm.isPublicVisible() || cm.getRegisterMode() == RegisterMode.FREE
o.getSystem() == CompetitionSystem.SAFCA ? || cm.getRegisterMode() == RegisterMode.HELLOASSO
hasSafcaViewPerm(securityCtx, o.getId()) || (cm.getRegisterMode() == RegisterMode.CLUB_ADMIN && securityCtx.isClubAdmin())) ?
: Uni.createFrom().nullItem().invoke(Unchecked.consumer(__ -> { Uni.createFrom().nullItem() :
if (!securityCtx.isInClubGroup(o.getClub().getId())) hasAdminViewPerm(securityCtx, cm).onFailure()
throw new DForbiddenException(); .recoverWithUni(__ ->
}) registerRepository.count("membre.userId = ?1 AND competition = ?2",
)); securityCtx.getSubject(), cm).map(Unchecked.function(c -> {
if (c == 0)
throw new DForbiddenException();
return cm;
}))
));
} }
/**
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has admin view perm
*/
public Uni<CompetitionModel> hasAdminViewPerm(SecurityCtx securityCtx, CompetitionModel competitionModel) {
return hasAdminViewPerm(securityCtx, Uni.createFrom().item(competitionModel));
}
/**
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has admin view perm
*/
public Uni<CompetitionModel> hasAdminViewPerm(SecurityCtx securityCtx, long id) {
return hasAdminViewPerm(securityCtx, competitionRepository.findById(id));
}
/**
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has admin view perm
*/
public Uni<CompetitionModel> hasAdminViewPerm(SecurityCtx securityCtx, Uni<CompetitionModel> in) {
return in.call(Unchecked.function(o -> {
if (securityCtx.getSubject().equals(o.getOwner()) || securityCtx.roleHas("federation_admin"))
return Uni.createFrom().nullItem();
if (o.getSystem() == CompetitionSystem.SAFCA)
return hasSafcaViewPerm(securityCtx, o.getId());
if (o.getAdmin().contains(securityCtx.getSubject()))
return Uni.createFrom().nullItem();
if (!securityCtx.isInClubGroup(o.getClub().getId())) // Only membre club pass here
throw new DForbiddenException();
if (o.getSystem() == CompetitionSystem.INTERNAL)
if (securityCtx.isClubAdmin())
return Uni.createFrom().nullItem();
throw new DForbiddenException();
})
);
}
/**
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has edit perm
*/
public Uni<CompetitionModel> hasEditPerm(SecurityCtx securityCtx, CompetitionModel competitionModel) { public Uni<CompetitionModel> hasEditPerm(SecurityCtx securityCtx, CompetitionModel competitionModel) {
return hasEditPerm(securityCtx, Uni.createFrom().item(competitionModel)); return hasEditPerm(securityCtx, Uni.createFrom().item(competitionModel));
} }
/**
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has edit perm
*/
public Uni<CompetitionModel> hasEditPerm(SecurityCtx securityCtx, long id) { public Uni<CompetitionModel> hasEditPerm(SecurityCtx securityCtx, long id) {
return hasEditPerm(securityCtx, competitionRepository.findById(id)); return hasEditPerm(securityCtx, competitionRepository.findById(id));
} }
/**
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has edit perm
*/
public Uni<CompetitionModel> hasEditPerm(SecurityCtx securityCtx, Uni<CompetitionModel> in) { public Uni<CompetitionModel> hasEditPerm(SecurityCtx securityCtx, Uni<CompetitionModel> in) {
return in.call(o -> ( return in.call(Unchecked.function(o -> {
securityCtx.getSubject().equals(o.getOwner()) || securityCtx.roleHas("federation_admin")) ? if (securityCtx.getSubject().equals(o.getOwner()) || securityCtx.roleHas("federation_admin"))
Uni.createFrom().nullItem() return Uni.createFrom().nullItem();
:
o.getSystem() == CompetitionSystem.SAFCA ? if (o.getSystem() == CompetitionSystem.SAFCA)
hasSafcaEditPerm(securityCtx, o.getId()) return hasSafcaEditPerm(securityCtx, o.getId());
: Uni.createFrom().nullItem().invoke(Unchecked.consumer(__ -> {
if (!securityCtx.isInClubGroup(o.getClub().getId())) if (o.getSystem() == CompetitionSystem.INTERNAL) {
throw new DForbiddenException(); if (securityCtx.isInClubGroup(o.getClub().getId()) && securityCtx.isClubAdmin())
}) return Uni.createFrom().nullItem();
));
if (o.getAdmin().contains(securityCtx.getSubject()))
return Uni.createFrom().nullItem();
throw new DForbiddenException();
}
throw new DForbiddenException();
})
);
}
/**
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has edit perm
*/
public Uni<CompetitionModel> hasTablePerm(SecurityCtx securityCtx, CompetitionModel competitionModel) {
return hasTablePerm(securityCtx, Uni.createFrom().item(competitionModel));
}
/**
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has edit perm
*/
public Uni<CompetitionModel> hasTablePerm(SecurityCtx securityCtx, long id) {
return hasTablePerm(securityCtx, competitionRepository.findById(id));
}
/**
* @return {@link fr.titionfire.ffsaf.data.model.CompetitionModel} if securityCtx has edit perm
*/
public Uni<CompetitionModel> hasTablePerm(SecurityCtx securityCtx, Uni<CompetitionModel> in) {
return in.call(Unchecked.function(o -> {
if (securityCtx.getSubject().equals(o.getOwner()) || securityCtx.roleHas("federation_admin"))
return Uni.createFrom().nullItem();
if (o.getSystem() == CompetitionSystem.SAFCA)
return hasSafcaTablePerm(securityCtx, o.getId());
if (o.getSystem() == CompetitionSystem.INTERNAL) {
if (securityCtx.isInClubGroup(o.getClub().getId()) && securityCtx.isClubAdmin())
return Uni.createFrom().nullItem();
if (o.getAdmin().contains(securityCtx.getSubject()))
return Uni.createFrom().nullItem();
if (o.getTable().contains(securityCtx.getSubject()))
return Uni.createFrom().nullItem();
throw new DForbiddenException();
}
throw new DForbiddenException();
})
);
} }
private Uni<?> hasSafcaViewPerm(SecurityCtx securityCtx, long id) { private Uni<?> hasSafcaViewPerm(SecurityCtx securityCtx, long id) {
@@ -114,8 +286,8 @@ public class CompetPermService {
Uni.createFrom().nullItem() Uni.createFrom().nullItem()
: :
getSafcaConfig(id).chain(Unchecked.function(o -> { getSafcaConfig(id).chain(Unchecked.function(o -> {
if (!o.admin().contains(UUID.fromString(securityCtx.getSubject())) && !o.table() if (!o.admin().contains(UUID.fromString(securityCtx.getSubject()))
.contains(UUID.fromString(securityCtx.getSubject()))) && !o.table().contains(UUID.fromString(securityCtx.getSubject())))
throw new DForbiddenException(); throw new DForbiddenException();
return Uni.createFrom().nullItem(); return Uni.createFrom().nullItem();
})); }));
@@ -131,4 +303,16 @@ public class CompetPermService {
return Uni.createFrom().nullItem(); return Uni.createFrom().nullItem();
})); }));
} }
private Uni<?> hasSafcaTablePerm(SecurityCtx securityCtx, long id) {
return securityCtx.roleHas("safca_super_admin") ?
Uni.createFrom().nullItem()
:
getSafcaConfig(id).chain(Unchecked.function(o -> {
if (!o.admin().contains(UUID.fromString(securityCtx.getSubject()))
&& !o.table().contains(UUID.fromString(securityCtx.getSubject())))
throw new DForbiddenException();
return Uni.createFrom().nullItem();
}));
}
} }

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

@@ -85,6 +85,31 @@ public class KeycloakService {
return Uni.createFrom().item(club::getClubId); return Uni.createFrom().item(club::getClubId);
} }
public Uni<String> updateGroupFromClub(ClubModel club) {
if (club.getClubId() == null) {
return getGroupFromClub(club);
} else {
LOGGER.infof("Updating name of club group %d-%s...", club.getId(), club.getName());
return vertx.getOrCreateContext().executeBlocking(() -> {
GroupRepresentation clubGroup =
keycloak.realm(realm).groups().groups().stream().filter(g -> g.getName().equals("club"))
.findAny()
.orElseThrow(() -> new KeycloakException("Fail to fetch group %s".formatted("club")));
keycloak.realm(realm).groups().group(clubGroup.getId()).getSubGroups(0, 1000, true).stream()
.filter(g -> g.getName().startsWith(club.getId() + "-")).findAny()
.ifPresent(groupRepresentation -> {
groupRepresentation.setName(club.getId() + "-" + club.getName());
keycloak.realm(realm).groups().group(groupRepresentation.getId())
.update(groupRepresentation);
});
return club.getClubId();
}
);
}
}
public Uni<String> getUserFromMember(MembreModel membreModel) { public Uni<String> getUserFromMember(MembreModel membreModel) {
if (membreModel.getUserId() == null) { if (membreModel.getUserId() == null) {
return Uni.createFrom() return Uni.createFrom()
@@ -131,24 +156,32 @@ public class KeycloakService {
return oldEmail; return oldEmail;
}).call(oldEmail -> oldEmail == null || !enabled_email ? Uni.createFrom().item("") : }).call(oldEmail -> oldEmail == null || !enabled_email ? Uni.createFrom().item("") :
reactiveMailer.send( reactiveMailer.send(
Mail.withText(oldEmail, Mail.withHtml(oldEmail, "FFSAF - Changement de votre adresse email",
"FFSAF - Changement de votre adresse email", String.format(Utils.HTML_HEADER, "FFSAF - Changement de votre adresse email") +
String.format( String.format("""
""" <p>Suite à la modification de votre adresse email fournie lors de votre (ré)inscription à la FFSAF,<br/>
Bonjour, vous allez recevoir dans les prochaines minutes un email de vérification de votre nouvelle adresse sur celle-ci.</p>
<p>Ancienne adresse email : <span class="highlight">%s</span><br/>Nouvelle adresse email : <span class="highlight">%s</span></p>
Suite à la modification de votre adresse email fournie lors de votre (ré)inscription à la FFSAF, <p>Si vous n'avez pas demandé cette modification, veuillez contacter le support à l'adresse <a href="mailto:support@ffsaf.fr">support@ffsaf.fr</a>.</p>
vous allez recevoir dans les prochaines minutes un email de vérification de votre nouvelle adresse sur celle-ci. """,
oldEmail, email) +
Ancienne adresse email : %s Utils.HTML_FOOTER
Nouvelle adresse email : %s )
.setText(String.format("""
Si vous n'avez pas demandé cette modification, veuillez contacter le support à l'adresse support@ffsaf.fr. Bonjour,
Cordialement, Suite à la modification de votre adresse email fournie lors de votre (ré)inscription à la FFSAF,
L'équipe de la FFSAF vous allez recevoir dans les prochaines minutes un email de vérification de votre nouvelle adresse sur celle-ci.
""", oldEmail, email)
).setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("support@ffsaf.fr") Ancienne adresse email : %s
Nouvelle adresse email : %s
Si vous n'avez pas demandé cette modification, veuillez contacter le support à l'adresse support@ffsaf.fr.
Cordialement,
L'équipe de la FFSAF
""", oldEmail, email))
.setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("support@ffsaf.fr")
).onFailure().invoke(e -> LOGGER.error("Fail to send email", e))); ).onFailure().invoke(e -> LOGGER.error("Fail to send email", e)));
} }
@@ -199,16 +232,16 @@ public class KeycloakService {
public Uni<String> initCompte(long id) { public Uni<String> initCompte(long id) {
return membreService.getById(id).invoke(Unchecked.consumer(membreModel -> { return membreService.getById(id).invoke(Unchecked.consumer(membreModel -> {
if (membreModel.getUserId() != null) if (membreModel.getUserId() != null)
throw new KeycloakException("User already linked to the user id=" + id); throw new KeycloakException("User already linked to the user id=" + id);
if (membreModel.getEmail() == null) if (membreModel.getEmail() == null)
throw new KeycloakException("User email is null"); throw new KeycloakException("User email is null");
if (membreModel.getFname() == null || membreModel.getLname() == null) if (membreModel.getFname() == null || membreModel.getLname() == null)
throw new KeycloakException("User name is null"); throw new KeycloakException("User name is null");
})).chain(membreModel -> creatUser(membreModel).chain(user -> { })).chain(membreModel -> creatUser(membreModel).chain(user -> {
LOGGER.infof("Set user id %s to membre %s", user.getId(), membreModel.getId()); LOGGER.infof("Set user id %s to membre %s", user.getId(), membreModel.getId());
return membreService.setUserId(membreModel.getId(), user.getId()).map(__ -> user.getId()); return membreService.setUserId(membreModel.getId(), user.getId()).map(__ -> user.getId());
})); }));
} }
private Uni<UserRepresentation> creatUser(MembreModel membreModel) { private Uni<UserRepresentation> creatUser(MembreModel membreModel) {
@@ -231,9 +264,6 @@ public class KeycloakService {
user.setEmail(membreModel.getEmail()); user.setEmail(membreModel.getEmail());
user.setEnabled(true); user.setEnabled(true);
user.setRequiredActions(List.of(RequiredAction.VERIFY_EMAIL.name(),
RequiredAction.UPDATE_PASSWORD.name()));
try (Response response = keycloak.realm(realm).users().create(user)) { try (Response response = keycloak.realm(realm).users().create(user)) {
if (!response.getStatusInfo().equals(Response.Status.CREATED) && !response.getStatusInfo() if (!response.getStatusInfo().equals(Response.Status.CREATED) && !response.getStatusInfo()
.equals(Response.Status.CONFLICT)) .equals(Response.Status.CONFLICT))
@@ -245,29 +275,43 @@ public class KeycloakService {
return getUser(login).orElseThrow( return getUser(login).orElseThrow(
() -> new KeycloakException("Fail to fetch user %s".formatted(finalLogin))); () -> new KeycloakException("Fail to fetch user %s".formatted(finalLogin)));
}) })
.call(user -> enabled_email ?
vertx.getOrCreateContext().executeBlocking(() -> {
keycloak.realm(realm).users().get(user.getId())
.executeActionsEmail(List.of(RequiredAction.VERIFY_EMAIL.name(),
RequiredAction.UPDATE_PASSWORD.name()));
return null;
}) : Uni.createFrom().nullItem())
.invoke(user -> membreModel.setUserId(user.getId())) .invoke(user -> membreModel.setUserId(user.getId()))
.call(user -> updateRole(user.getId(), List.of("safca_user"), List.of()))
.call(user -> enabled_email ? reactiveMailer.send( .call(user -> enabled_email ? reactiveMailer.send(
Mail.withText(user.getEmail(), Mail.withHtml(user.getEmail(), "FFSAF - Creation de votre compte sur l'intranet",
"FFSAF - Creation de votre compte sur l'intranet", String.format(Utils.HTML_HEADER, "Création de votre compte intranet FFSAF") +
String.format( String.format(
"""
<p>Suite &agrave; votre premi&egrave;re inscription <span class="highlight">%s</span> &agrave; la <strong>F&eacute;d&eacute;ration France Soft Armored Fighting (FFSAF)</strong>, votre compte intranet a &eacute;t&eacute; cr&eacute;&eacute;.</p>
<p>Ce compte vous permettra de :</p>
<ul>
<li>Consulter vos informations personnelles,</li>
<li>Vous inscrire aux comp&eacute;titions (bient&ocirc;t disponible),</li>
<li>Consulter les r&eacute;sultats des comp&eacute;titions.</li>
</ul>
<p>L&rsquo;intranet est accessible &agrave; l&rsquo;adresse suivante :</p>
<p style="text-align: center;"><a href="https://intra.ffsaf.fr" class="button">Acc&eacute;der &agrave; l&apos;intranet</a></p>
<p>Votre nom d&rsquo;utilisateur est : <span class="highlight">%s</span></p>
<p>Pour d&eacute;finir votre mot de passe, rendez-vous sur l&rsquo;intranet : <strong>Connexion &gt; Mot de passe oubli&eacute; ?</strong></p>
<p>Si vous n&rsquo;avez pas demand&eacute; cette inscription, veuillez contacter le support &agrave; l&rsquo;adresse : <a href="mailto:support@ffsaf.fr">support@ffsaf.fr</a>.</p>
<p class="footer">(Pas de panique, nous ne vous enverrons pas de message autre que ceux concernant votre compte.)</p>
""",
membreModel.getRole() == RoleAsso.MEMBRE ? "par votre club (" + membreModel.getClub()
.getName() + ") " : "", user.getUsername()) +
Utils.HTML_FOOTER
)
.setText(String.format(
""" """
Bonjour, Bonjour,
Suite à votre première inscription %sà la Fédération Française de Soft Armored Fighting (FFSAF), votre compte pour accéder à l'intranet a été créé. Suite à votre première inscription %sà la Fédération France Soft Armored Fighting (FFSAF), votre compte intranet a été créé.
Ce compte vous permettra de consulter vos informations, de vous inscrire aux compétitions et de consulter vos résultats. Ce compte vous permettra de consulter vos informations et, dans un futur proche, de vous inscrire aux compétitions ainsi que d'en consulter les résultats.
Vous allez recevoir dans les prochaines minutes un email vous demandant de vérifier votre email et de définir un mot de passe.
L'intranet est accessible à l'adresse suivante : https://intra.ffsaf.fr L'intranet est accessible à l'adresse suivante : https://intra.ffsaf.fr
Votre nom d'utilisateur est : %s Votre nom d'utilisateur est : %s
Pour définir votre mot de passe, rendez-vous sur l'intranet > "Connexion" > "Mot de passe oublié ?"
Si vous n'avez pas demandé cette inscription, veuillez contacter le support à l'adresse support@ffsaf.fr. Si vous n'avez pas demandé cette inscription, veuillez contacter le support à l'adresse support@ffsaf.fr.
(Pas de panique, nous ne vous enverrons pas de message autre que ce concernant votre compte) (Pas de panique, nous ne vous enverrons pas de message autre que ce concernant votre compte)
@@ -275,8 +319,8 @@ public class KeycloakService {
L'équipe de la FFSAF L'équipe de la FFSAF
""", """,
membreModel.getRole() == RoleAsso.MEMBRE ? "par votre club (" + membreModel.getClub() membreModel.getRole() == RoleAsso.MEMBRE ? "par votre club (" + membreModel.getClub()
.getName() + ") " : "", user.getUsername()) .getName() + ") " : "", user.getUsername()))
).setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("support@ffsaf.fr") .setFrom("FFSAF <no-reply@ffsaf.fr>").setReplyTo("support@ffsaf.fr")
) : Uni.createFrom().nullItem()) ) : Uni.createFrom().nullItem())
.call(user -> membreService.setUserId(membreModel.getId(), user.getId())) .call(user -> membreService.setUserId(membreModel.getId(), user.getId()))
.call(user -> setClubGroupMembre(membreModel, membreModel.getClub())); .call(user -> setClubGroupMembre(membreModel, membreModel.getClub()));
@@ -333,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());
if (user == null) }
public Optional<UserRepresentation> getUserById(String userId) {
try {
UserResource user = keycloak.realm(realm).users().get(userId);
if (user == null)
return Optional.empty();
else
return Optional.of(user.toRepresentation());
} catch (Exception e) {
return Optional.empty(); return Optional.empty();
else }
return Optional.of(user.toRepresentation());
} }
private String makeLogin(MembreModel model) { private String makeLogin(MembreModel model) {

View File

@@ -18,6 +18,7 @@ import io.smallrye.mutiny.unchecked.Unchecked;
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 org.hibernate.reactive.mutiny.Mutiny;
import org.jboss.logging.Logger;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -26,6 +27,7 @@ import java.util.function.Function;
@WithSession @WithSession
@ApplicationScoped @ApplicationScoped
public class LicenceService { public class LicenceService {
private static final Logger LOGGER = Logger.getLogger(LicenceService.class);
@Inject @Inject
LicenceRepository repository; LicenceRepository repository;
@@ -45,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()));
@@ -82,6 +87,26 @@ public class LicenceService {
)); ));
} }
public Uni<?> validePaymentLicences(List<Long> ids) {
Uni<String> uni = Uni.createFrom().nullItem();
for (Long id : ids) {
uni = uni.chain(__ -> repository.find("membre.id = ?1 AND saison = ?2", id, Utils.getSaison()).firstResult()
.chain(model -> {
if (!model.isPay())
ls.logUpdate("payment (admin) de la licence", model);
return validatePayLicences(model);
}))
.map(__ -> "OK");
}
return uni.call(__ -> ls.append());
}
protected Uni<LicenceModel> validatePayLicences(LicenceModel model) {
model.setPay(true);
return Panache.withTransaction(() -> repository.persist(model));
}
public Uni<LicenceModel> setLicence(long id, LicenceForm form) { public Uni<LicenceModel> setLicence(long id, LicenceForm form) {
if (form.getId() == -1) { if (form.getId() == -1) {
return combRepository.findById(id).chain(membreModel -> { return combRepository.findById(id).chain(membreModel -> {
@@ -97,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 {
@@ -119,13 +146,15 @@ public class LicenceService {
} }
private Function<MembreModel, Uni<?>> genLicenceNumberAndAccountIfNeed() { private Function<MembreModel, Uni<?>> genLicenceNumberAndAccountIfNeed() {
return membreModel -> ((membreModel.getLicence() <= 0) ? return membreModel -> ((membreModel.getLicence() == null || membreModel.getLicence() <= 0) ?
sequenceRepository.getNextValueInTransaction(SequenceType.Licence) sequenceRepository.getNextValueInTransaction(SequenceType.Licence)
.invoke(i -> membreModel.setLicence(Math.toIntExact(i))) .invoke(i -> membreModel.setLicence(Math.toIntExact(i)))
.chain(() -> combRepository.persist(membreModel)) .chain(() -> combRepository.persist(membreModel))
: Uni.createFrom().nullItem()) : Uni.createFrom().nullItem())
.call(__ -> (membreModel.getUserId() == null) ? .call(__ -> (membreModel.getUserId() == null) ?
keycloakService.initCompte(membreModel.getId()) keycloakService.initCompte(membreModel.getId()).onFailure()
.invoke(t -> LOGGER.infof("Failed to init account: %s", t.getMessage())).onFailure()
.recoverWithNull()
: Uni.createFrom().nullItem()); : Uni.createFrom().nullItem());
} }
@@ -133,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();
@@ -150,10 +179,10 @@ public class LicenceService {
.call(__ -> checkoutService.canDeleteLicence(id) .call(__ -> checkoutService.canDeleteLicence(id)
.invoke(Unchecked.consumer(b -> { .invoke(Unchecked.consumer(b -> {
if (!b) throw new DBadRequestException( if (!b) throw new DBadRequestException(
"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 -> repository.delete(model)); .chain(model -> Panache.withTransaction(() -> repository.delete(model)));
} }
public Uni<LicenceModel> askLicence(long id, LicenceForm form, Consumer<MembreModel> checkPerm) { public Uni<LicenceModel> askLicence(long id, LicenceForm form, Consumer<MembreModel> checkPerm) {
@@ -162,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());
@@ -191,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

@@ -1,9 +1,11 @@
package fr.titionfire.ffsaf.domain.service; package fr.titionfire.ffsaf.domain.service;
import fr.titionfire.ffsaf.data.model.CompetitionGuestModel;
import fr.titionfire.ffsaf.data.model.MatchModel; import fr.titionfire.ffsaf.data.model.MatchModel;
import fr.titionfire.ffsaf.data.repository.CategoryRepository;
import fr.titionfire.ffsaf.data.repository.CombRepository; import fr.titionfire.ffsaf.data.repository.CombRepository;
import fr.titionfire.ffsaf.data.repository.CompetitionGuestRepository;
import fr.titionfire.ffsaf.data.repository.MatchRepository; import fr.titionfire.ffsaf.data.repository.MatchRepository;
import fr.titionfire.ffsaf.data.repository.PouleRepository;
import fr.titionfire.ffsaf.rest.data.MatchData; import fr.titionfire.ffsaf.rest.data.MatchData;
import fr.titionfire.ffsaf.rest.exception.DNotFoundException; import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
import fr.titionfire.ffsaf.utils.CompetitionSystem; import fr.titionfire.ffsaf.utils.CompetitionSystem;
@@ -25,7 +27,7 @@ public class MatchService {
MatchRepository repository; MatchRepository repository;
@Inject @Inject
PouleRepository pouleRepository; CategoryRepository categoryRepository;
@Inject @Inject
CombRepository combRepository; CombRepository combRepository;
@@ -33,17 +35,20 @@ public class MatchService {
@Inject @Inject
CompetPermService permService; CompetPermService permService;
public Uni<MatchData> getById(SecurityCtx securityCtx, CompetitionSystem system, Long id) { @Inject
CompetitionGuestRepository competitionGuestRepository;
public Uni<MatchData> getByIdAdmin(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 DNotFoundException("Match not found")) .onItem().ifNull().failWith(() -> new DNotFoundException("Match not found"))
.call(data -> permService.hasViewPerm(securityCtx, data.getPoule().getCompet())) .call(data -> permService.hasAdminViewPerm(securityCtx, data.getCategory().getCompet()))
.map(MatchData::fromModel); .map(MatchData::fromModel);
} }
public Uni<List<MatchData>> getAllByPoule(SecurityCtx securityCtx, CompetitionSystem system, Long id) { public Uni<List<MatchData>> getAllByPouleAdmin(SecurityCtx securityCtx, CompetitionSystem system, Long id) {
return pouleRepository.find("systemId = ?1 AND system = ?2", id, system).firstResult() return categoryRepository.find("systemId = ?1 AND system = ?2", id, system).firstResult()
.onItem().ifNull().failWith(() -> new DNotFoundException("Poule not found")) .onItem().ifNull().failWith(() -> new DNotFoundException("Poule not found"))
.call(data -> permService.hasViewPerm(securityCtx, data.getCompet())) .call(data -> permService.hasAdminViewPerm(securityCtx, data.getCompet()))
.chain(data -> repository.list("poule = ?1", data.getId()) .chain(data -> repository.list("poule = ?1", data.getId())
.map(o -> o.stream().map(MatchData::fromModel).toList())); .map(o -> o.stream().map(MatchData::fromModel).toList()));
} }
@@ -52,21 +57,21 @@ public class MatchService {
return repository.find("systemId = ?1 AND system = ?2", data.getId(), system).firstResult() return repository.find("systemId = ?1 AND system = ?2", data.getId(), system).firstResult()
.chain(o -> { .chain(o -> {
if (o == null) { if (o == null) {
return pouleRepository.find("systemId = ?1 AND system = ?2", data.getPoule(), system) return categoryRepository.find("systemId = ?1 AND system = ?2", data.getCategory(), system)
.firstResult() .firstResult()
.onItem().ifNull().failWith(() -> new DNotFoundException("Poule not found")) .onItem().ifNull().failWith(() -> new DNotFoundException("Poule not found"))
.call(o2 -> permService.hasEditPerm(securityCtx, o2.getCompet())) .call(o2 -> permService.hasEditPerm(securityCtx, o2.getCompet()))
.map(pouleModel -> { .map(categoryModel -> {
MatchModel model = new MatchModel(); MatchModel model = new MatchModel();
model.setId(null); model.setId(null);
model.setSystem(system); model.setSystem(system);
model.setSystemId(data.getId()); model.setSystemId(data.getId());
model.setPoule(pouleModel); model.setCategory(categoryModel);
return model; return model;
}); });
} else { } else {
return pouleRepository.find("systemId = ?1 AND system = ?2", data.getPoule(), system) return categoryRepository.find("systemId = ?1 AND system = ?2", data.getCategory(), system)
.firstResult() .firstResult()
.onItem().ifNull().failWith(() -> new DNotFoundException("Poule not found")) .onItem().ifNull().failWith(() -> new DNotFoundException("Poule not found"))
.call(o2 -> permService.hasEditPerm(securityCtx, o2.getCompet())) .call(o2 -> permService.hasEditPerm(securityCtx, o2.getCompet()))
@@ -75,9 +80,7 @@ public class MatchService {
} }
) )
.chain(o -> { .chain(o -> {
o.setC1_str(data.getC1_str()); o.setCategory_ord(data.getCategory_ord());
o.setC2_str(data.getC2_str());
o.setPoule_ord(data.getPoule_ord());
o.getScores().clear(); o.getScores().clear();
o.getScores().addAll(data.getScores()); o.getScores().addAll(data.getScores());
@@ -88,6 +91,20 @@ public class MatchService {
.chain(() -> (data.getC1_id() == null) ? .chain(() -> (data.getC1_id() == null) ?
Uni.createFrom().nullItem() : combRepository.findById(data.getC2_id())) Uni.createFrom().nullItem() : combRepository.findById(data.getC2_id()))
.invoke(o::setC2_id) .invoke(o::setC2_id)
.chain(() -> (data.getC1_str() == null) ?
Uni.createFrom()
.item((CompetitionGuestModel) null) : competitionGuestRepository.find(
"fname = ?1 AND lname = ?2",
data.getC1_str().substring(0, data.getC1_str().indexOf(" ")),
data.getC1_str().substring(data.getC1_str().indexOf(" ") + 1)).firstResult())
.invoke(o::setC1_guest)
.chain(() -> (data.getC2_str() == null) ?
Uni.createFrom()
.item((CompetitionGuestModel) null) : competitionGuestRepository.find(
"fname = ?1 AND lname = ?2",
data.getC2_str().substring(0, data.getC2_str().indexOf(" ")),
data.getC2_str().substring(data.getC2_str().indexOf(" ") + 1)).firstResult())
.invoke(o::setC2_guest)
.chain(() -> Panache.withTransaction(() -> repository.persist(o))); .chain(() -> Panache.withTransaction(() -> repository.persist(o)));
}) })
.map(MatchData::fromModel); .map(MatchData::fromModel);
@@ -97,7 +114,7 @@ public class MatchService {
List<ScoreEmbeddable> scores) { List<ScoreEmbeddable> scores) {
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 DNotFoundException("Match not found")) .onItem().ifNull().failWith(() -> new DNotFoundException("Match not found"))
.call(o2 -> permService.hasEditPerm(securityCtx, o2.getPoule().getCompet())) .call(o2 -> permService.hasEditPerm(securityCtx, o2.getCategory().getCompet()))
.invoke(data -> { .invoke(data -> {
data.getScores().clear(); data.getScores().clear();
data.getScores().addAll(scores); data.getScores().addAll(scores);
@@ -109,7 +126,7 @@ public class MatchService {
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 DNotFoundException("Match not found")) .onItem().ifNull().failWith(() -> new DNotFoundException("Match not found"))
.call(o2 -> permService.hasEditPerm(securityCtx, o2.getPoule().getCompet())) .call(o2 -> permService.hasEditPerm(securityCtx, o2.getCategory().getCompet()))
.chain(data -> Panache.withTransaction(() -> repository.delete(data))); .chain(data -> Panache.withTransaction(() -> repository.delete(data)));
} }
} }

View File

@@ -7,13 +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.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;
@@ -63,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(
@@ -102,66 +104,97 @@ public class MembreService {
return baseUni; return baseUni;
} }
public Uni<PageResult<SimpleMembre>> searchAdmin(int limit, int page, String search, String club, private Sort getSort(String order) {
int licenceRequest, int payState) {
if (search == null)
search = "";
search = "%" + search.replaceAll(" ", "% %") + "%";
String finalSearch = search; Sort sort;
Uni<List<LicenceModel>> baseUni = getLicenceListe(licenceRequest, payState); if (order == null || order.isBlank()) {
sort = Sort.ascending("fname", "lname");
} else {
sort = Sort.empty();
return baseUni for (String e : order.split(",")) {
.map(l -> l.stream().map(l2 -> l2.getMembre().getId()).toList()) String[] split = e.split(" ");
.chain(ids -> { if (split.length == 2) {
PanacheQuery<MembreModel> query; sort = sort.and(split[0],
split[1].equals("n") ? Sort.Direction.Ascending : Sort.Direction.Descending);
} else {
return null;
}
}
}
String idf = ((licenceRequest == 0 || licenceRequest == 4) ? "NOT IN" : "IN"); return sort;
if (club == null || club.isBlank()) {
query = repository.find(
"id " + idf + " ?2 AND (" + FIND_NAME_REQUEST + ")",
Sort.ascending("fname", "lname"), finalSearch, ids)
.page(Page.ofSize(limit));
} else {
if (club.equals("null")) {
query = repository.find(
"id " + idf + " ?2 AND club IS NULL AND (" + FIND_NAME_REQUEST + ")",
Sort.ascending("fname", "lname"), finalSearch, ids).page(Page.ofSize(limit));
} else {
query = repository.find(
"id " + idf + " ?3 AND LOWER(club.name) LIKE LOWER(?2) AND (" + FIND_NAME_REQUEST + ")",
Sort.ascending("fname", "lname"), finalSearch, club + "%", ids)
.page(Page.ofSize(limit));
}
}
return getPageResult(query, limit, page);
});
} }
public Uni<PageResult<SimpleMembre>> search(int limit, int page, String search, int licenceRequest, int payState, public Uni<PageResult<SimpleMembre>> search(int limit, int page, String search, int licenceRequest, int payState,
String subject) { String order, String categorie, Boolean archive, String subject) {
return repository.find("userId = ?1", subject).firstResult()
.invoke(Unchecked.consumer(membreModel -> {
if (membreModel == null || membreModel.getClub() == null)
throw new DForbiddenException();
}))
.chain(membreModel ->
searchAdmin(limit, page, search, membreModel.getClub(), licenceRequest, payState, order,
categorie, archive));
}
public Uni<PageResult<SimpleMembre>> searchAdmin(int limit, int page, String search, Object club,
int licenceRequest, int payState, String order, String categorie,
Boolean archive) {
if (search == null) if (search == null)
search = ""; search = "";
search = "%" + search.replaceAll(" ", "% %") + "%"; search = "%" + search.replaceAll(" ", "% %") + "%";
String categorieFilter;
if (categorie == null || categorie.isBlank())
categorieFilter = " True";
else
categorieFilter = "categorie = " + Categorie.valueOf(categorie).ordinal();
String archiveFilter;
if (archive == null || archive)
archiveFilter = "True";
else
archiveFilter = String.format(
"EXISTS (SELECT 1 FROM LicenceModel l WHERE l.membre.id = m.id AND l.saison >= %s)",
Utils.getSaison() - 1);
String clubFilter = "(TRUE OR ?3 = ?3)";
if (club != null) {
if (club instanceof String club_) {
if (!club_.isBlank()) {
if (club_.equals("null"))
clubFilter = "club IS NULL AND ?3 = ?3";
else
clubFilter = "LOWER(club.name) LIKE LOWER(?3)";
}
} else if (club instanceof ClubModel)
clubFilter = "club = ?3";
}
String queryStr = String.format(
"SELECT m FROM MembreModel m WHERE id %s ?2 AND %s AND (%s) AND %s AND %s",
(licenceRequest == 0 || licenceRequest == 4) ? "NOT IN" : "IN", clubFilter, FIND_NAME_REQUEST,
categorieFilter,
archiveFilter);
Sort sort = getSort(order);
if (sort == null)
return Uni.createFrom().failure(new DInternalError(trad.t("erreur.lors.calcul.du.trie")));
String finalSearch = search; String finalSearch = search;
return getLicenceListe(licenceRequest, payState)
Uni<List<LicenceModel>> baseUni = getLicenceListe(licenceRequest, payState); .chain(l -> {
PanacheQuery<MembreModel> query;
return baseUni query = repository.find(queryStr, sort, finalSearch,
.map(l -> l.stream().map(l2 -> l2.getMembre().getId()).toList()) l.stream().map(l2 -> l2.getMembre().getId()).toList(), club).page(Page.ofSize(limit));
.chain(ids -> { return getPageResult(query, limit, page)
String idf = ((licenceRequest == 0 || licenceRequest == 4) ? "NOT IN" : "IN"); .call(r -> (r.getResult().isEmpty() || !l.isEmpty() ?
Uni.createFrom().item(l) :
return repository.find("userId = ?1", subject).firstResult() licenceRepository.list("saison = ?1 AND membre.id IN ?2", Utils.getSaison(),
.chain(membreModel -> { r.getResult().stream().map(SimpleMembre::getId).toList()))
PanacheQuery<MembreModel> query = repository.find( .invoke(l2 -> r.setAdditionalData(l2.stream().map(SimpleLicence::fromModel)))
"id " + idf + " ?3 AND club = ?2 AND (" + FIND_NAME_REQUEST + ")", );
Sort.ascending("fname", "lname"), finalSearch, membreModel.getClub(), ids)
.page(Page.ofSize(limit));
return getPageResult(query, limit, page);
});
}); });
} }
@@ -172,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()
@@ -183,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()));
} }
@@ -197,6 +230,11 @@ public class MembreService {
return Uni.createFrom().nullItem(); return Uni.createFrom().nullItem();
AtomicReference<ClubModel> clubModel = new AtomicReference<>(); AtomicReference<ClubModel> clubModel = new AtomicReference<>();
LOGGER.debugf("Membre import (size=%d)", data2.size());
for (SimpleMembreInOutData simpleMembreInOutData : data2) {
LOGGER.debugf("-> %s", simpleMembreInOutData.toString());
}
return repository.find("userId = ?1", subject).firstResult() return repository.find("userId = ?1", subject).firstResult()
.chain(membreModel -> { .chain(membreModel -> {
clubModel.set(membreModel.getClub()); clubModel.set(membreModel.getClub());
@@ -205,20 +243,24 @@ public class MembreService {
return repository.list("licence IN ?1 OR LOWER(lname || ' ' || fname) IN ?2 OR email IN ?3", return repository.list("licence IN ?1 OR LOWER(lname || ' ' || fname) IN ?2 OR email IN ?3",
data2.stream().map(SimpleMembreInOutData::getLicence).filter(Objects::nonNull).toList(), data2.stream().map(SimpleMembreInOutData::getLicence).filter(Objects::nonNull).toList(),
data2.stream().map(o -> (o.getNom() + " " + o.getPrenom()).toLowerCase()).toList(), data2.stream().map(o -> (o.getNom() + " " + o.getPrenom()).toLowerCase()).toList(),
data2.stream().map(SimpleMembreInOutData::getEmail).filter(Objects::nonNull).toList()); data2.stream().map(SimpleMembreInOutData::getEmail).filter(o -> o != null && !o.isBlank())
.toList());
}) })
.call(Unchecked.function(membres -> { .call(Unchecked.function(membres -> {
for (MembreModel membreModel : membres) { for (MembreModel membreModel : membres) {
if (!Objects.equals(membreModel.getClub(), clubModel.get())) if (!Objects.equals(membreModel.getClub(), clubModel.get())) {
throw new DForbiddenException( LOGGER.info("Similar membres found: " + membreModel);
"Le membre n°" + membreModel.getLicence() + " n'appartient pas à votre club"); throw new DForbiddenException(String.format(trad.t("le.membre.appartient.pas.a.votre.club"),
membreModel.getLicence()));
}
} }
Uni<Void> uniResult = Uni.createFrom().voidItem(); Uni<Void> uniResult = Uni.createFrom().voidItem();
for (SimpleMembreInOutData dataIn : data2) { for (SimpleMembreInOutData dataIn : data2) {
MembreModel model = membres.stream() MembreModel model = membres.stream()
.filter(m -> Objects.equals(m.getLicence(), dataIn.getLicence()) || m.getLname() .filter(m -> (dataIn.getLicence() != null && Objects.equals(m.getLicence(),
.equals(dataIn.getNom()) && m.getFname().equals(dataIn.getPrenom()) || dataIn.getLicence())) || m.getLname().equals(dataIn.getNom()) && m.getFname()
Objects.equals(m.getFname(), dataIn.getEmail())).findFirst() .equals(dataIn.getPrenom()) || (dataIn.getEmail() != null && !dataIn.getEmail()
.isBlank() && Objects.equals(m.getFname(), dataIn.getEmail()))).findFirst()
.orElseGet(() -> { .orElseGet(() -> {
MembreModel mm = new MembreModel(); MembreModel mm = new MembreModel();
mm.setClub(clubModel.get()); mm.setClub(clubModel.get());
@@ -226,16 +268,27 @@ public class MembreService {
mm.setCountry("FR"); mm.setCountry("FR");
return mm; return mm;
}); });
if (model.getId() != null) {
LOGGER.debugf("updating -> %s", dataIn.toString());
} else {
LOGGER.debugf("creating -> %s", dataIn.toString());
}
if (model.getEmail() != null) { if (model.getEmail() != null && !model.getEmail().isBlank()) {
if (model.getLicence() != null && !model.getLicence().equals(dataIn.getLicence())) { if (model.getLicence() != null && !model.getLicence().equals(dataIn.getLicence())) {
throw new DBadRequestException("Email déja utiliser"); LOGGER.info("Similar membres found: " + model);
throw new DBadRequestException(
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) {
throw new DBadRequestException("Email déja utiliser"); LOGGER.info("Similar membres found: " + model);
throw new DBadRequestException(
String.format(trad.t("email.deja.utilise.par"), model.getEmail(),
model.getFname(), model.getLname()));
} }
} }
@@ -244,8 +297,10 @@ public class MembreService {
if ((!add && StringSimilarity.similarity(model.getLname().toUpperCase(), if ((!add && StringSimilarity.similarity(model.getLname().toUpperCase(),
dataIn.getNom().toUpperCase()) > 3) || (!add && StringSimilarity.similarity( dataIn.getNom().toUpperCase()) > 3) || (!add && StringSimilarity.similarity(
model.getFname().toUpperCase(), dataIn.getPrenom().toUpperCase()) > 3)) { model.getFname().toUpperCase(), dataIn.getPrenom().toUpperCase()) > 3)) {
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);
@@ -253,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);
@@ -319,8 +373,8 @@ public class MembreService {
return update(repository.findById(id) return update(repository.findById(id)
.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) if (c > 0 && !membre.getEmail().isBlank())
throw new DBadRequestException("Email déjà utiliser"); throw new DBadRequestException(trad.t("email.deja.utilise"));
}))) })))
.chain(membreModel -> clubRepository.findById(membre.getClub()) .chain(membreModel -> clubRepository.findById(membre.getClub())
.map(club -> new Pair<>(membreModel, club))) .map(club -> new Pair<>(membreModel, club)))
@@ -341,8 +395,8 @@ public class MembreService {
return update(repository.findById(id) return update(repository.findById(id)
.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) if (c > 0 && !membre.getEmail().isBlank())
throw new DBadRequestException("Email déjà utiliser"); throw new DBadRequestException(trad.t("email.deja.utilise"));
}))) })))
.invoke(Unchecked.consumer(membreModel -> { .invoke(Unchecked.consumer(membreModel -> {
if (!securityCtx.isInClubGroup(membreModel.getClub().getId())) if (!securityCtx.isInClubGroup(membreModel.getClub().getId()))
@@ -351,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 -> {
@@ -360,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())) {
@@ -374,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);
@@ -422,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");
} }
@@ -432,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à utiliser"); 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);
@@ -448,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à utiliser"); if (c > 0) throw new DBadRequestException(trad.t("email.deja.utilise"));
}))) })))
.call(membreModel -> .call(membreModel ->
repository.count( repository.count(
@@ -456,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());
@@ -489,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())
@@ -517,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());
@@ -541,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")
@@ -557,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,909 @@
package fr.titionfire.ffsaf.domain.service;
import fr.titionfire.ffsaf.data.model.*;
import fr.titionfire.ffsaf.data.repository.*;
import fr.titionfire.ffsaf.domain.entity.MatchModelExtend;
import fr.titionfire.ffsaf.rest.data.ResultCategoryData;
import fr.titionfire.ffsaf.rest.exception.DBadRequestException;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
import fr.titionfire.ffsaf.utils.*;
import io.quarkus.cache.Cache;
import io.quarkus.cache.CacheName;
import io.quarkus.hibernate.reactive.panache.common.WithSession;
import io.quarkus.runtime.annotations.RegisterForReflection;
import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.unchecked.Unchecked;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import lombok.Builder;
import lombok.Data;
import org.hibernate.reactive.mutiny.Mutiny;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
@WithSession
@ApplicationScoped
public class ResultService {
@Inject
CompetitionRepository compRepository;
@Inject
RegisterRepository registerRepository;
@Inject
MembreService membreService;
@Inject
ClubRepository clubRepository;
@Inject
CompetitionGuestRepository competitionGuestRepository;
@Inject
CategoryRepository categoryRepository;
@Inject
MatchRepository matchRepository;
@Inject
CardRepository cardRepository;
@Inject
TradService trad;
@Inject
@CacheName("club-classement")
Cache cacheClubClassement;
private static final HashMap<String, Long> cacheClubClassementExp = new HashMap<>();
private static final HashMap<Long, String> combTempIds = new HashMap<>();
private static String getCombTempId(Long key) {
synchronized (combTempIds) {
if (!combTempIds.containsKey(key)) {
combTempIds.put(key, UUID.randomUUID().toString());
}
return combTempIds.get(key);
}
}
private static Long getCombTempId(String value) {
synchronized (combTempIds) {
for (Map.Entry<Long, String> entry : combTempIds.entrySet()) {
if (entry.getValue().equals(value)) {
return entry.getKey();
}
}
return null;
}
}
private static final HashMap<String, Long> clubTempIds = new HashMap<>();
private static Long getClubTempId(String key) {
synchronized (clubTempIds) {
if (!clubTempIds.containsKey(key)) {
clubTempIds.put(key, (System.currentTimeMillis() + clubTempIds.size()) * -1);
}
return clubTempIds.get(key);
}
}
private static String getClubTempId(Long value) {
synchronized (clubTempIds) {
for (Map.Entry<String, Long> entry : clubTempIds.entrySet()) {
if (entry.getValue().equals(value)) {
return entry.getKey();
}
}
return null;
}
}
public Uni<List<Object[]>> getList(SecurityCtx securityCtx) {
return membreService.getByAccountId(securityCtx.getSubject())
.chain(m -> registerRepository.list(
"membre = ?1 OR (TRUE = ?2 AND membre.club = ?3)",
m, securityCtx.isClubAdmin(), m.getClub()))
.onItem().transformToMulti(Multi.createFrom()::iterable)
.onItem().call(r -> Mutiny.fetch(r.getCompetition()))
.onItem().transform(RegisterModel::getCompetition)
.collect().asList()
.chain(l -> compRepository.list("owner = ?1 OR ?1 IN admin", securityCtx.getSubject())
.map(l2 -> Stream.concat(l.stream(), l2.stream()).distinct()
.map(c -> new Object[]{c.getUuid(), c.getName(), c.getDate()}).toList())
);
}
public Uni<HashMap<String, Long>> getCategoryList(String uuid, SecurityCtx securityCtx) {
return hasAccess(uuid, securityCtx).chain(__ -> getCategoryList(uuid));
}
public Uni<HashMap<String, Long>> getCategoryList(String uuid) {
return categoryRepository.list("compet.uuid = ?1", uuid)
.map(categoryModels -> {
HashMap<String, Long> map = new HashMap<>();
categoryModels.stream()
.sorted(Comparator.comparing(CategoryModel::getName))
.forEachOrdered(categoryModel -> map.put(categoryModel.getName(), categoryModel.getId()));
return map;
});
}
public Uni<ResultCategoryData> getCategory(String uuid, long poule, SecurityCtx securityCtx) {
return hasAccess(uuid, securityCtx).chain(membreModel -> getData(uuid, poule, membreModel));
}
public Uni<ResultCategoryData> getCategory(String uuid, long poule) {
return getData(uuid, poule, null);
}
private Uni<ResultCategoryData> getData(String uuid, long poule, MembreModel membreModel) {
List<CardModel> cards = new ArrayList<>();
return matchRepository.list("category.compet.uuid = ?1 AND category.id = ?2", uuid, poule)
.call(list -> list.isEmpty() ? Uni.createFrom().voidItem() :
Mutiny.fetch(list.get(0).getCategory().getTree()))
.chain(list -> cardRepository.list("competition.uuid = ?1", uuid).invoke(cards::addAll)
.map(c -> list.stream().map(m -> new MatchModelExtend(m, c)).toList()))
.map(matchModels -> {
ResultCategoryData out = new ResultCategoryData();
CategoryModel categoryModel = matchModels.get(0).getCategory();
out.setName(categoryModel.getName());
out.setType(categoryModel.getType());
out.setLiceName(categoryModel.getLiceName() == null ? new String[]{} : categoryModel.getLiceName()
.split(";"));
out.setGenTime(System.currentTimeMillis());
out.setTreeIsClassement(categoryModel.isTreeAreClassement());
getArray2(matchModels, membreModel, out);
getTree(categoryModel.getTree(), membreModel, cards, out);
getClassementArray(categoryModel, membreModel, cards, out);
return out;
});
}
public void getArray2(List<MatchModelExtend> matchModels_, MembreModel membreModel, ResultCategoryData out) {
List<MatchModelExtend> matchModels = matchModels_.stream().filter(o -> o.getCategory_ord() >= 0).toList();
HashMap<Character, List<MatchModelExtend>> matchMap = new HashMap<>();
for (MatchModelExtend model : matchModels) {
char g = model.getPoule();
if (!matchMap.containsKey(g))
matchMap.put(g, new ArrayList<>());
matchMap.get(g).add(model);
}
matchMap.forEach((c, matchEntities) -> {
List<ResultCategoryData.PouleArrayData> matchs = matchEntities.stream()
.sorted(Comparator.comparing(MatchModelExtend::getCategory_ord))
.map(o -> ResultCategoryData.PouleArrayData.fromModel(o, membreModel,
ResultPrivacy.REGISTERED_ONLY_NO_DETAILS))
.toList();
List<ResultCategoryData.RankArray> rankArray = matchEntities.stream()
.flatMap(m -> Stream.of(m.getC1_id(), m.getC2_id(), m.getC1_guest(), m.getC2_guest()))
.distinct()
.filter(Objects::nonNull)
.map(comb -> {
CombStat stat = makeStat(matchEntities, comb);
return new ResultCategoryData.RankArray(0, comb,
comb.getName(membreModel, ResultPrivacy.REGISTERED_ONLY_NO_DETAILS), stat.score, stat.w,
stat.pointMake, stat.pointTake, stat.getPointRate());
})
.filter(r -> r.getPointMake() > 0 || r.getPointTake() > 0)
.sorted(Comparator
.comparing(ResultCategoryData.RankArray::getScore)
.thenComparing(ResultCategoryData.RankArray::getWin)
.thenComparing(ResultCategoryData.RankArray::getPointRate).reversed())
.toList();
out.getMatchs().put(c, matchs);
int lastScore = -1;
int lastWin = -1;
float pointRate = 0;
int rank = 0;
for (ResultCategoryData.RankArray rankArray1 : rankArray) {
if (rankArray1.getScore() != lastScore || rankArray1.getWin() != lastWin || pointRate != rankArray1.getPointRate()) {
lastScore = rankArray1.getScore();
lastWin = rankArray1.getWin();
pointRate = rankArray1.getPointRate();
rank++;
}
rankArray1.setRank(rank);
}
out.getRankArray().put(c, rankArray);
});
}
public void getClassementArray(CategoryModel categoryModel, MembreModel membreModel, List<CardModel> cards,
ResultCategoryData out) {
if ((categoryModel.getType() & 2) != 0) {
AtomicInteger rank = new AtomicInteger(0);
categoryModel.getTree().stream()
.filter(t -> t.getLevel() > 0)
.sorted(Comparator.comparing(TreeModel::getLevel))
.forEach(treeModel -> makeClassementRow(membreModel,
new MatchModelExtend(treeModel.getMatch(), cards), out, rank));
categoryModel.getTree().stream()
.filter(t -> t.getLevel() <= -10)
.sorted(Comparator.comparing(TreeModel::getLevel).reversed())
.forEach(treeModel -> makeClassementRow(membreModel,
new MatchModelExtend(treeModel.getMatch(), cards), out, rank));
} else {
for (List<ResultCategoryData.RankArray> list : out.getRankArray().values()) {
for (ResultCategoryData.RankArray r : list) {
out.getClassement()
.add(new ResultCategoryData.ClassementData(r.getRank(), r.getComb(), r.getName()));
}
}
}
}
private static void makeClassementRow(MembreModel membreModel, MatchModelExtend m, ResultCategoryData out,
AtomicInteger rank) {
if (m.isEnd()) {
if (m.getWin() > 0) {
out.getClassement()
.add(new ResultCategoryData.ClassementData(rank.incrementAndGet(), m.getC1(),
m.getC1Name(membreModel, ResultPrivacy.REGISTERED_ONLY_NO_DETAILS)));
out.getClassement()
.add(new ResultCategoryData.ClassementData(rank.incrementAndGet(), m.getC2(),
m.getC2Name(membreModel, ResultPrivacy.REGISTERED_ONLY_NO_DETAILS)));
} else if (m.getWin() < 0) {
out.getClassement()
.add(new ResultCategoryData.ClassementData(rank.incrementAndGet(), m.getC2(),
m.getC2Name(membreModel, ResultPrivacy.REGISTERED_ONLY_NO_DETAILS)));
out.getClassement()
.add(new ResultCategoryData.ClassementData(rank.incrementAndGet(), m.getC1(),
m.getC1Name(membreModel, ResultPrivacy.REGISTERED_ONLY_NO_DETAILS)));
} else {
out.getClassement()
.add(new ResultCategoryData.ClassementData(rank.incrementAndGet(), m.getC1(),
m.getC1Name(membreModel, ResultPrivacy.REGISTERED_ONLY_NO_DETAILS)));
out.getClassement()
.add(new ResultCategoryData.ClassementData(rank.get(), m.getC2(),
m.getC2Name(membreModel, ResultPrivacy.REGISTERED_ONLY_NO_DETAILS)));
}
} else {
out.getClassement().add(new ResultCategoryData.ClassementData(rank.incrementAndGet(), null, null));
out.getClassement().add(new ResultCategoryData.ClassementData(rank.incrementAndGet(), null, null));
}
}
private static void convertTree(TreeModel src, TreeNode<ResultCategoryData.TreeData> dst, MembreModel membreModel,
ResultPrivacy privacy, List<CardModel> cards) {
dst.setData(
ResultCategoryData.TreeData.from(new MatchModelExtend(src.getMatch(), cards), src.getLevel(),
membreModel, privacy));
if (src.getLeft() != null) {
dst.setLeft(new TreeNode<>());
convertTree(src.getLeft(), dst.getLeft(), membreModel, privacy, cards);
}
if (src.getRight() != null) {
dst.setRight(new TreeNode<>());
convertTree(src.getRight(), dst.getRight(), membreModel, privacy, cards);
}
}
private void getTree(List<TreeModel> treeModels, MembreModel membreModel, List<CardModel> cards,
ResultCategoryData out) {
ArrayList<TreeNode<ResultCategoryData.TreeData>> trees = new ArrayList<>();
treeModels.stream()
.filter(t -> t.getLevel() != 0)
.sorted(Comparator.comparing(TreeModel::getLevel))
.forEach(treeModel -> {
TreeNode<ResultCategoryData.TreeData> root = new TreeNode<>();
convertTree(treeModel, root, membreModel, ResultPrivacy.REGISTERED_ONLY_NO_DETAILS, cards);
trees.add(root);
});
out.setTrees(trees);
}
public Uni<CombsArrayData> getAllCombArray(String uuid, SecurityCtx securityCtx) {
return hasAccess(uuid, securityCtx)
.chain(membreModel -> getAllCombArray_(uuid, membreModel));
}
public Uni<CombsArrayData> getAllCombArrayPublic(String uuid) {
return getAllCombArray_(uuid, null);
}
private Uni<CombsArrayData> getAllCombArray_(String uuid, MembreModel membreModel) {
return registerRepository.list("competition.uuid = ?1", uuid)
.chain(registers -> matchRepository.list("category.compet.uuid = ?1", uuid)
.chain(matchModels -> cardRepository.list("competition.uuid = ?1", uuid)
.map(cards -> new Pair<>(registers,
matchModels.stream().map(m -> new MatchModelExtend(m, cards)).toList()))))
.map(pair -> {
List<RegisterModel> registers = pair.getKey();
List<MatchModelExtend> matchModels = pair.getValue();
CombsArrayData.CombsArrayDataBuilder builder = CombsArrayData.builder();
List<CombsArrayData.CombsData> combs = matchModels.stream()
.flatMap(m -> Stream.of(m.getC1_id(), m.getC2_id(), m.getC1_guest(), m.getC2_guest()))
.filter(Objects::nonNull)
.distinct()
.map(comb -> {
var builder2 = CombsArrayData.CombsData.builder();
CombStat stat = makeStat(matchModels, comb);
Categorie categorie = null;
String clubName = null;
Optional<RegisterModel> register = registers.stream()
.filter(r -> Objects.equals(r.getMembre(), comb)).findFirst();
if (register.isPresent()) {
categorie = register.get().getCategorie2();
ClubModel club = register.get().getClub2();
clubName = (club == null) ? trad.t("no.licence") : club.getName();
} else if (comb instanceof CompetitionGuestModel guestModel) {
categorie = guestModel.getCategorie();
clubName = guestModel.getClub();
} else if (comb instanceof MembreModel model) {
categorie = model.getCategorie();
clubName = (model.getClub() == null) ? trad.t("no.licence")
: model.getClub().getName();
}
builder2.cat((categorie == null) ? "---" : categorie.getName(trad));
builder2.name(comb.getName(membreModel, ResultPrivacy.REGISTERED_ONLY));
builder2.w(stat.w);
builder2.l(stat.l);
builder2.ratioVictoire((stat.l == 0) ? stat.w : (float) stat.w / stat.l);
builder2.club(clubName);
builder2.pointMake(stat.pointMake);
builder2.pointTake(stat.pointTake);
builder2.ratioPoint(stat.getPointRate());
return builder2.build();
})
.sorted(Comparator.comparing(CombsArrayData.CombsData::name))
.toList();
builder.nb_insc(combs.size());
builder.tt_match((int) matchModels.stream().filter(MatchModelExtend::isEnd).count());
builder.point(matchModels.stream()
.filter(MatchModelExtend::isEnd)
.flatMap(m -> m.getScoresToCompute().stream())
.mapToInt(s -> s.getS1() + s.getS2()).sum());
builder.combs(combs);
return builder.build();
});
}
public Uni<HashMap<String, String>> getCombList(String uuid, SecurityCtx securityCtx) {
return hasAccess(uuid, securityCtx)
.chain(membreModel -> getCombList(uuid, ResultPrivacy.REGISTERED_ONLY));
}
public Uni<HashMap<String, String>> getCombList(String uuid) {
return getCombList(uuid, ResultPrivacy.PUBLIC);
}
private Uni<HashMap<String, String>> getCombList(String uuid, ResultPrivacy privacy) {
return registerRepository.list("competition.uuid = ?1 AND membre.resultPrivacy <= ?2", uuid, privacy)
.map(models -> {
HashMap<String, String> map = new HashMap<>();
models.forEach(
r -> map.put(r.getMembre().getName(), getCombTempId(r.getMembre().getId())));
return map;
})
.chain(map -> competitionGuestRepository.list("competition.uuid = ?1 AND lname != \"__team\"", uuid)
.map(models -> {
models.forEach(guestModel -> map.put(guestModel.getName(),
getCombTempId(guestModel.getId() * -1)));
return map;
})
);
}
public Uni<?> getCombArrayPublic(String uuid, String combTempId, SecurityCtx securityCtx) {
return hasAccess(uuid, securityCtx)
.chain(membreModel -> getCombArrayPublic(uuid, combTempId, ResultPrivacy.REGISTERED_ONLY));
}
public Uni<?> getCombArrayPublic(String uuid, String combTempId) {
return getCombArrayPublic(uuid, combTempId, ResultPrivacy.PUBLIC);
}
private Uni<?> getCombArrayPublic(String uuid, String combTempId, ResultPrivacy privacy) {
CombArrayData.CombArrayDataBuilder builder = CombArrayData.builder();
Long id = getCombTempId(combTempId);
if (id == null) {
return Uni.createFrom().failure(new DForbiddenException(trad.t("comb.not.found")));
}
Uni<List<MatchModelExtend>> uni;
if (id >= 0) {
uni = registerRepository.find("membre.id = ?1 AND competition.uuid = ?2 AND membre.resultPrivacy <= ?3", id,
uuid, privacy).firstResult()
.chain(Unchecked.function(registerModel -> {
if (registerModel == null)
throw new DBadRequestException(trad.t("combattant.non.inscrit"));
builder.name(Utils.getFullName(registerModel.getMembre()));
builder.club((registerModel.getClub2() == null) ? trad.t("no.licence") :
registerModel.getClub2().getName());
builder.cat((registerModel.getCategorie2() == null) ? "---" :
registerModel.getCategorie2().getName(trad));
return matchRepository.list(
"SELECT DISTINCT m FROM MatchModel m LEFT JOIN m.c1_guest.comb c1g LEFT JOIN m.c2_guest.comb c2g " +
"WHERE m.category.compet.uuid = ?1 AND (m.c1_id = ?2 OR m.c2_id = ?2 OR c1g = ?2 OR c2g = ?2)",
uuid, registerModel.getMembre())
.chain(matchModels -> cardRepository.list("competition.uuid = ?1", uuid)
.map(cards -> matchModels.stream().map(m -> new MatchModelExtend(m, cards))
.toList()));
}));
} else {
uni = competitionGuestRepository.find("id = ?1 AND competition.uuid = ?2", -id, uuid).firstResult()
.chain(guestModel -> {
builder.name(Utils.getFullName(guestModel));
builder.club(guestModel.getClub());
builder.cat(
(guestModel.getCategorie() == null) ? "---" : guestModel.getCategorie().getName(trad));
return matchRepository.list(
"SELECT DISTINCT m FROM MatchModel m LEFT JOIN m.c1_guest.guest c1g LEFT JOIN m.c2_guest.guest c2g " +
"WHERE m.category.compet.uuid = ?1 AND (m.c1_guest = ?2 OR m.c2_guest = ?2 OR c1g = ?2 OR c2g = ?2)",
uuid, guestModel)
.chain(matchModels -> cardRepository.list("competition.uuid = ?1", uuid)
.map(cards -> matchModels.stream().map(m -> new MatchModelExtend(m, cards))
.toList()));
});
}
return uni.invoke(matchModels -> {
List<CategoryModel> pouleModels = matchModels.stream().map(MatchModelExtend::getCategory).distinct()
.toList();
List<CombArrayData.MatchsData> matchs = new ArrayList<>();
AtomicInteger sumW = new AtomicInteger();
AtomicInteger sumPointMake = new AtomicInteger(0);
AtomicInteger sumPointTake = new AtomicInteger(0);
for (MatchModelExtend matchModel : matchModels) {
if ((matchModel.getC1_id() == null && matchModel.getC1_guest() == null) ||
(matchModel.getC2_id() == null && matchModel.getC2_guest() == null))
continue;
var builder2 = CombArrayData.MatchsData.builder();
builder2.date(matchModel.getDate());
builder2.poule(pouleModels.stream().filter(p -> p.equals(matchModel.getCategory()))
.map(CategoryModel::getName).findFirst().orElse(""));
builder2.end(matchModel.isEnd());
AtomicInteger pointMake = new AtomicInteger();
AtomicInteger pointTake = new AtomicInteger();
if (matchModel.isC1(id)) {
builder2.adv(matchModel.getC2Name());
if (matchModel.isEnd()) {
matchModel.getScoresToCompute()
.forEach(scoreEntity -> {
pointMake.addAndGet(scoreEntity.getS1());
pointTake.addAndGet(scoreEntity.getS2());
});
builder2.score(matchModel.getScoresToPrint().stream()
.map(s -> new Integer[]{s.getS1(), s.getS2()}).toList());
} else {
builder2.score(new ArrayList<>());
}
builder2.win(matchModel.isEnd() && matchModel.getWin() > 0);
} else {
builder2.adv(matchModel.getC1Name());
if (matchModel.isEnd()) {
matchModel.getScoresToCompute()
.forEach(scoreEntity -> {
pointMake.addAndGet(scoreEntity.getS2());
pointTake.addAndGet(scoreEntity.getS1());
});
builder2.score(matchModel.getScoresToPrint().stream()
.map(s -> new Integer[]{s.getS2(), s.getS1()}).toList());
} else {
builder2.score(new ArrayList<>());
}
builder2.win(matchModel.isEnd() && matchModel.getWin() < 0);
}
builder2.eq(matchModel.isEnd() && matchModel.getWin() == 0);
builder2.ratio(
(pointTake.get() == 0) ? pointMake.get() : (float) pointMake.get() / pointTake.get());
sumPointMake.addAndGet(pointMake.get());
sumPointTake.addAndGet(pointTake.get());
matchs.add(builder2.build());
if (builder2.win)
sumW.getAndIncrement();
}
builder.totalWin(sumW.get());
builder.pointRatio(
(sumPointTake.get() == 0) ? sumPointMake.get() : (float) sumPointMake.get() / sumPointTake.get());
builder.pointMake(sumPointMake.get());
builder.pointTake(sumPointTake.get());
matchs.sort(Comparator.comparing(CombArrayData.MatchsData::poule)
.thenComparing(CombArrayData.MatchsData::adv));
builder.matchs(matchs);
})
.map(__ -> builder.build());
}
@Builder
@RegisterForReflection
public static record CombsArrayData(int nb_insc, int tt_match, long point, List<CombsData> combs) {
@Builder
@RegisterForReflection
public static record CombsData(String cat, String club, String name, int w, int l, float ratioVictoire,
float ratioPoint, int pointMake, int pointTake) {
}
}
@Builder
@RegisterForReflection
public static record CombArrayData(String name, String club, String cat, int totalWin,
float pointRatio, int pointMake, int pointTake, List<MatchsData> matchs) {
@Builder
@RegisterForReflection
public static record MatchsData(Date date, String poule, String adv, List<Integer[]> score, float ratio,
boolean win, boolean eq, boolean end) {
}
}
public Uni<HashMap<String, Long>> getClubList(String uuid, SecurityCtx securityCtx) {
return hasAccess(uuid, securityCtx).chain(__ -> getClubList(uuid));
}
public Uni<HashMap<String, Long>> getClubList(String uuid) {
return registerRepository.list("competition.uuid = ?1", uuid)
.map(registers -> {
HashMap<String, Long> registerMap = new HashMap<>();
registers.stream().map(RegisterModel::getClub2).distinct().filter(Objects::nonNull)
.forEach(registerClub -> registerMap.put(registerClub.getName(), registerClub.getId()));
return registerMap;
})
.chain(map -> competitionGuestRepository.list("competition.uuid = ?1", uuid)
.map(guests -> {
guests.stream().map(CompetitionGuestModel::getClub).distinct()
.filter(Objects::nonNull)
.forEach(guestClub -> map.putIfAbsent(guestClub,
getClubTempId(guestClub)));
return map;
})
);
}
public Uni<ClubArrayData> getClubArray(String uuid, Long id, SecurityCtx securityCtx) {
return hasAccess(uuid, securityCtx).chain(membreModel -> getClubArray2(uuid, id, membreModel));
}
public Uni<ClubArrayData> getClubArray2(String uuid, Long id, MembreModel membreModel) {
if (id < 0) {
String clubName = getClubTempId(id);
if (clubName == null) {
return Uni.createFrom().failure(new DForbiddenException(trad.t("club.not.found")));
}
return competitionGuestRepository.list("competition.uuid = ?1 AND club = ?2", uuid, clubName)
.call(list -> {
if (list.isEmpty())
return Uni.createFrom().failure(new DBadRequestException(trad.t("club.not.found")));
return Uni.createFrom().voidItem();
})
.chain(guests -> matchRepository.list(
"SELECT DISTINCT m FROM MatchModel m LEFT JOIN m.c1_guest.guest c1g LEFT JOIN m.c2_guest.guest c2g " +
"WHERE m.category.compet.uuid = ?1 AND (m.c1_guest IN ?2 OR m.c2_guest IN ?2 OR c1g IN ?2 OR c2g IN ?2)",
uuid, guests)
.chain(mm -> cardRepository.list("competition.uuid = ?1", uuid)
.map(cards ->
getClubArray2(clubName, guests.stream().map(o -> (CombModel) o).toList(),
mm.stream().map(m -> new MatchModelExtend(m, cards)).toList(),
new ArrayList<>(), membreModel)
)));
} else {
return cardRepository.list("competition.uuid = ?1", uuid)
.chain(cards -> clubRepository.findById(id).chain(clubModel ->
registerRepository.list("competition.uuid = ?1 AND membre.club = ?2", uuid, clubModel)
.chain(registers -> matchRepository.list(
"SELECT DISTINCT m FROM MatchModel m LEFT JOIN m.c1_guest.comb c1g LEFT JOIN m.c2_guest.comb c2g " +
"WHERE m.category.compet.uuid = ?1 AND (m.c1_id IN ?2 OR m.c2_id IN ?2 OR c1g IN ?2 OR c2g IN ?2)",
uuid, registers.stream().map(RegisterModel::getMembre).toList())
.map(matchModels -> matchModels.stream()
.map(m -> new MatchModelExtend(m, cards)))
.chain(s -> competitionGuestRepository.list(
"competition.uuid = ?1 AND club = ?2", uuid, clubModel.getName())
.chain(guests -> matchRepository.list(
"SELECT DISTINCT m FROM MatchModel m LEFT JOIN m.c1_guest.guest c1g LEFT JOIN m.c2_guest.guest c2g " +
"WHERE m.category.compet.uuid = ?1 AND (m.c1_guest IN ?2 OR m.c2_guest IN ?2 OR c1g IN ?2 OR c2g IN ?2)",
uuid, guests)
.map(mm -> new Pair<>(guests, Stream.concat(s, mm.stream()
.map(m -> new MatchModelExtend(m, cards)))
.distinct().toList()))
))
.map(p ->
getClubArray2(clubModel.getName(),
Stream.concat(
registers.stream().map(RegisterModel::getMembre),
p.getKey().stream()
).toList(),
p.getValue(), registers, membreModel)
))));
}
}
private ClubArrayData getClubArray2(String name, List<CombModel> combs, List<MatchModelExtend> matchModels,
List<RegisterModel> registers, MembreModel membreModel) {
ClubArrayData.ClubArrayDataBuilder builder = ClubArrayData.builder();
builder.name(name);
builder.nb_insc(combs.size());
ArrayList<Long> win_ids = new ArrayList<>();
ArrayList<Long> match_ids = new ArrayList<>();
List<ClubArrayData.CombData> combData = combs.stream().map(comb -> {
var builder2 = ClubArrayData.CombData.builder();
CombStat stat = makeStat(matchModels, comb);
Categorie categorie = null;
Optional<RegisterModel> register = registers.stream()
.filter(r -> Objects.equals(r.getMembre(), comb)).findFirst();
if (register.isPresent()) {
categorie = register.get().getCategorie2();
} else if (comb instanceof CompetitionGuestModel guestModel) {
categorie = guestModel.getCategorie();
} else if (comb instanceof MembreModel model) {
categorie = model.getCategorie();
}
builder2.cat((categorie == null) ? "---" : categorie.getName(trad));
builder2.name(comb.getName(membreModel, ResultPrivacy.REGISTERED_ONLY));
builder2.w(stat.w);
builder2.l(stat.l);
builder2.ratioVictoire((stat.l == 0) ? stat.w : (float) stat.w / stat.l);
builder2.pointMake(stat.pointMake);
builder2.pointTake(stat.pointTake);
builder2.ratioPoint(stat.getPointRate());
win_ids.addAll(stat.win_ids);
match_ids.addAll(stat.match_ids);
return builder2.build();
})
.sorted(Comparator.comparing(ClubArrayData.CombData::name))
.toList();
builder.nb_match((int) match_ids.stream().distinct().count());
builder.match_w((int) win_ids.stream().distinct().count());
builder.ratioVictoire((float) combData.stream().filter(c -> c.l + c.w != 0)
.mapToDouble(ClubArrayData.CombData::ratioVictoire).average().orElse(0L));
builder.pointMake(combData.stream().mapToInt(ClubArrayData.CombData::pointMake).sum());
builder.pointTake(combData.stream().mapToInt(ClubArrayData.CombData::pointTake).sum());
builder.ratioPoint((float) combData.stream().filter(c -> c.l + c.w != 0)
.mapToDouble(ClubArrayData.CombData::ratioPoint).average().orElse(0L));
builder.combs(combData);
return builder.build();
}
private static CombStat makeStat(List<MatchModelExtend> matchModels, CombModel comb) {
CombStat stat = new CombStat();
matchModels.stream()
.filter(m -> m.isEnd() && (m.isC1(comb) || m.isC2(comb)))
.forEach(matchModel -> {
stat.match_ids.add(matchModel.getId());
int win = matchModel.getWin();
if (win == 0) {
stat.score += 1;
} else if ((matchModel.isC1(comb) && win > 0) || matchModel.isC2(comb) && win < 0) {
stat.w++;
stat.win_ids.add(matchModel.getId());
stat.score += 2;
} else {
stat.l++;
}
matchModel.getScoresToCompute()
.forEach(score -> {
if (matchModel.isC1(comb)) {
stat.pointMake += score.getS1();
stat.pointTake += score.getS2();
} else {
stat.pointMake += score.getS2();
stat.pointTake += score.getS1();
}
});
});
return stat;
}
@Builder
@RegisterForReflection
public static record ClubArrayData(String name, int nb_insc, int nb_match, int match_w, float ratioVictoire,
float ratioPoint, int pointMake, int pointTake, List<CombData> combs) {
@Builder
@RegisterForReflection
public static record CombData(String cat, String name, int w, int l, float ratioVictoire,
float ratioPoint, int pointMake, int pointTake) {
}
}
public Uni<List<ClubClassement>> getAllClubArray(String uuid) {
return getAllClubArray(uuid, true);
}
public Uni<List<ClubClassement>> getAllClubArray(String uuid, SecurityCtx securityCtx) {
return hasAccess(uuid, securityCtx).chain(membreModel -> getAllClubArray(uuid, true));
}
public Uni<List<ClubClassement>> getAllClubArray(String uuid, boolean cache) {
List<CardModel> cards = new java.util.ArrayList<>();
return (!cache || cacheClubClassementExp.getOrDefault(uuid, 0L) < System.currentTimeMillis() ?
cacheClubClassement.invalidate(uuid).invoke(() -> cacheClubClassementExp.remove(uuid)) :
Uni.createFrom().voidItem()
).chain(o -> cacheClubClassement.getAsync(uuid, k -> cardRepository.list("competition.uuid = ?1", uuid)
.invoke(__ -> System.out.println("Cache miss for club classement with uuid " + uuid))
.invoke(cards::addAll)
.chain(__ -> matchRepository.list("category.compet.uuid = ?1", 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();
getArray2(entry.getValue().stream().map(m -> new MatchModelExtend(m, cards))
.toList(),
null, tmp);
getClassementArray(entry.getKey(), null, cards, tmp);
return tmp;
})
.collect().asList();
})
.map(categoryData -> {
HashMap<String, ClubClassement> clubMap = new HashMap<>();
categoryData.forEach(
c -> c.getClassement().stream().map(ResultCategoryData.ClassementData::comb)
.filter(Objects::nonNull)
.distinct()
.map(comb -> {
if (comb instanceof MembreModel membreModel2) {
return (membreModel2.getClub() != null) ? membreModel2.getClub()
.getName() : "";
} else if (comb instanceof CompetitionGuestModel guestModel) {
return guestModel.getClub();
}
return "";
})
.filter(s -> s != null && !s.isBlank() && !s.equals("Team"))
.distinct()
.forEach(clubName -> clubMap.putIfAbsent(clubName,
new ClubClassement(clubName))));
categoryData.forEach(c -> c.getClassement().forEach(classementData -> {
if (classementData.rank() > 3)
return;
if (classementData.comb() != null) {
String clubName = "";
if (classementData.comb() instanceof MembreModel membreModel2) {
clubName = (membreModel2.getClub() != null) ? membreModel2.getClub()
.getName() : "";
} else if (classementData.comb() instanceof CompetitionGuestModel guestModel) {
clubName = guestModel.getClub();
}
if (clubName != null && !clubName.isBlank()
&& !clubName.equals("Team") && clubMap.containsKey(clubName)) {
ClubClassement entity = clubMap.get(clubName);
entity.score[classementData.rank() - 1]++;
entity.tt_score += 4 - classementData.rank();
}
}
}));
return clubMap.values().stream()
.sorted(Comparator.comparingInt((ClubClassement c) -> c.tt_score)
.thenComparingInt(c -> c.score[0])
.thenComparingInt(c -> c.score[1])
.thenComparingInt(c -> c.score[2]).reversed())
.toList();
})
.invoke(__ -> cacheClubClassementExp.put(uuid, System.currentTimeMillis() + 60 * 1000L))
));
}
@Data
@RegisterForReflection
public static class ClubClassement {
String name;
Integer[] score = new Integer[]{0, 0, 0};
int tt_score = 0;
public ClubClassement(String name) {
this.name = name;
}
}
@RegisterForReflection
public static class CombStat {
public int w;
public int l;
public int score;
public int pointMake;
public int pointTake;
public ArrayList<Long> win_ids = new ArrayList<>();
public ArrayList<Long> match_ids = new ArrayList<>();
public CombStat() {
this.w = 0;
this.l = 0;
this.score = 0;
this.pointMake = 0;
this.pointTake = 0;
}
public float getPointRate() {
return (pointTake == 0) ? pointMake : (float) pointMake / pointTake;
}
}
private Uni<MembreModel> hasAccess(String uuid, SecurityCtx securityCtx) {
return registerRepository.find("membre.userId = ?1 AND competition.uuid = ?2", securityCtx.getSubject(), uuid)
.firstResult()
.chain(Unchecked.function(o -> {
if (o != null)
return Uni.createFrom().item(o.getMembre());
return membreService.getByAccountId(securityCtx.getSubject()).chain(m -> {
if (securityCtx.isClubAdmin()) {
return registerRepository.count("membre.club = ?2 AND competition.uuid = ?1",
uuid, m.getClub()).chain(c -> {
if (c > 0) return Uni.createFrom().item(m);
return compRepository.count("uuid = ?1 AND (owner = ?2 OR ?2 IN admin)",
uuid, securityCtx.getSubject())
.chain(c2 -> {
if (c2 > 0) return Uni.createFrom().item(m);
return Uni.createFrom().failure(new DForbiddenException(
trad.t("access.denied")));
});
});
} else {
return compRepository.count("uuid = ?1 AND (owner = ?2 OR ?2 IN admin)", uuid,
securityCtx.getSubject())
.chain(c2 -> {
if (c2 > 0) return Uni.createFrom().item(m);
return Uni.createFrom()
.failure(new DForbiddenException(trad.t("access.denied")));
});
}
});
}));
}
}

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

@@ -1,4 +0,0 @@
package fr.titionfire.ffsaf.domain.service;
public class TreeService {
}

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

@@ -13,13 +13,25 @@ public class WebhookService {
@Inject @Inject
CheckoutService checkoutService; CheckoutService checkoutService;
@Inject
CompetitionService competitionService;
@ConfigProperty(name = "helloasso.organizationSlug") @ConfigProperty(name = "helloasso.organizationSlug")
String organizationSlug; String organizationSlug;
public Uni<Response> helloAssoNotification(HelloassoNotification notification) { public Uni<Response> helloAssoNotification(HelloassoNotification notification) {
if (notification.getEventType().equals("Payment")){ if (notification.getEventType().equals("Payment")) {
if (notification.getData().getOrder().getOrganizationSlug().equalsIgnoreCase(organizationSlug)){ if (notification.getData().getOrder().getFormType().equals("Checkout")) {
return checkoutService.paymentStatusChange(notification.getData().getState(), notification.getMetadata()); if (notification.getData().getOrder().getOrganizationSlug().equalsIgnoreCase(organizationSlug)) {
return checkoutService.paymentStatusChange(notification.getData().getState(),
notification.getMetadata());
}
} else if (notification.getData().getOrder().getFormType().equals("Event")) {
return competitionService.unregisterHelloAsso(notification.getData());
}
}else if (notification.getEventType().equals("Order")){
if (notification.getData().getFormType().equals("Event")) {
return competitionService.registerHelloAsso(notification.getData());
} }
} }

View File

@@ -24,7 +24,7 @@ public class SReqCompet {
} }
public static void getAllHaveAccess(ArrayList<Client_Thread> client_Thread, String userId, public static void getAllHaveAccess(ArrayList<Client_Thread> client_Thread, String userId,
CompletableFuture<HashMap<Long, String>> future) { CompletableFuture<HashMap<String, String>> future) {
if (client_Thread.isEmpty()) return; if (client_Thread.isEmpty()) return;
client_Thread.get(0).sendReq(userId, "getAllHaveAccess", client_Thread.get(0).sendReq(userId, "getAllHaveAccess",
new JsonConsumer<>(HashMap.class, future::complete)); new JsonConsumer<>(HashMap.class, future::complete));

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"}) @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é.")
@@ -107,7 +107,7 @@ public class AffiliationRequestEndpoints {
if (o.getClub() == null && !securityCtx.roleHas("federation_admin")) if (o.getClub() == null && !securityCtx.roleHas("federation_admin"))
throw new DForbiddenException(); throw new DForbiddenException();
})).invoke(o -> checkPerm.accept(o.getClub())) })).invoke(o -> checkPerm.accept(o.getClub()))
.chain(o -> service.deleteReqAffiliation(id, reason)); .chain(o -> service.deleteReqAffiliation(id, reason, securityCtx.roleHas("federation_admin")));
} }
@PUT @PUT
@@ -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 " +
@@ -186,6 +186,6 @@ public class AffiliationRequestEndpoints {
public Uni<Response> getStatus( public Uni<Response> getStatus(
@Parameter(description = "L'identifiant de la demande d'affiliation") @PathParam("id") long id) throws URISyntaxException { @Parameter(description = "L'identifiant de la demande d'affiliation") @PathParam("id") long id) throws URISyntaxException {
return Utils.getMediaFile(id, media, "aff_request/status", "affiliation_request_" + id, return Utils.getMediaFile(id, media, "aff_request/status", "affiliation_request_" + id,
Uni.createFrom().nullItem()); Uni.createFrom().nullItem(), false);
} }
} }

View File

@@ -1,9 +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.data.UniteLegaleRoot; import fr.titionfire.ffsaf.rest.client.StateIdService;
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;
@@ -12,18 +15,27 @@ import org.eclipse.microprofile.rest.client.inject.RestClient;
@Path("api/asso") @Path("api/asso")
public class AssoEndpoints { public class AssoEndpoints {
@RestClient
StateIdService stateIdService;
@RestClient @RestClient
SirenService sirenService; SirenService sirenService;
@Inject
TradService trad;
@GET @GET
@Path("siren/{siren}") @Path("state_id/{stateId}")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Operation(hidden = true) @Operation(hidden = true)
public Uni<UniteLegaleRoot> getInfoSiren(@PathParam("siren") String siren) { public Uni<AssoData> getAssoInfo(@PathParam("stateId") String stateId) {
return sirenService.get_unite(siren).onFailure().transform(throwable -> { return ((stateId.charAt(0) == 'W') ? stateIdService.get_rna(stateId) : sirenService.get_unite(
stateId).chain(stateIdService::getAssoDataFromUnit)).onFailure().transform(throwable -> {
if (throwable instanceof WebApplicationException exception) { if (throwable instanceof WebApplicationException exception) {
if (exception.getResponse().getStatus() == 404)
return new DNotFoundException(trad.t("service.momentanement.indisponible"));
if (exception.getResponse().getStatus() == 400) if (exception.getResponse().getStatus() == 400)
return new DNotFoundException("Siret introuvable"); return new DNotFoundException(trad.t("asso.introuvable"));
} }
return throwable; return throwable;
}); });

View File

@@ -1,8 +1,8 @@
package fr.titionfire.ffsaf.rest; package fr.titionfire.ffsaf.rest;
import fr.titionfire.ffsaf.domain.service.PouleService; import fr.titionfire.ffsaf.domain.service.CategoryService;
import fr.titionfire.ffsaf.rest.data.PouleData; import fr.titionfire.ffsaf.rest.data.CategoryData;
import fr.titionfire.ffsaf.rest.data.PouleFullData; import fr.titionfire.ffsaf.rest.data.CategoryFullData;
import fr.titionfire.ffsaf.utils.CompetitionSystem; import fr.titionfire.ffsaf.utils.CompetitionSystem;
import fr.titionfire.ffsaf.utils.SecurityCtx; import fr.titionfire.ffsaf.utils.SecurityCtx;
import io.quarkus.security.Authenticated; import io.quarkus.security.Authenticated;
@@ -14,14 +14,14 @@ import jakarta.ws.rs.core.MediaType;
import java.util.List; import java.util.List;
@Authenticated @Authenticated
@Path("api/poule/{system}/") @Path("api/poule/{system}/admin/")
public class PouleEndpoints { public class CategoryAdminEndpoints {
@PathParam("system") @PathParam("system")
private CompetitionSystem system; private CompetitionSystem system;
@Inject @Inject
PouleService service; CategoryService service;
@Inject @Inject
SecurityCtx securityCtx; SecurityCtx securityCtx;
@@ -30,28 +30,28 @@ public class PouleEndpoints {
@GET @GET
@Path("{id}") @Path("{id}")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Uni<PouleData> getById(@PathParam("id") Long id) { public Uni<CategoryData> getByIdAdmin(@PathParam("id") Long id) {
return service.getById(securityCtx, system, id); return service.getByIdAdmin(securityCtx, system, id);
} }
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Uni<List<PouleData>> getAll() { public Uni<List<CategoryData>> getAllAdmin() {
return service.getAll(securityCtx, system); return service.getAllAdmin(securityCtx, system);
} }
@POST @POST
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Uni<PouleData> addOrUpdate(PouleData data) { public Uni<CategoryData> addOrUpdate(CategoryData data) {
return service.addOrUpdate(securityCtx, system, data); return service.addOrUpdate(securityCtx, system, data);
} }
@POST @POST
@Path("sync") @Path("sync")
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public Uni<?> syncPoule(PouleFullData data) { public Uni<?> syncCategory(CategoryFullData data) {
return service.syncPoule(securityCtx, system, data); return service.syncCategory(securityCtx, system, data);
} }
@DELETE @DELETE

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;
@@ -29,6 +30,7 @@ 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 java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -46,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();
@@ -69,7 +77,8 @@ public class ClubEndpoints {
@APIResponse(responseCode = "500", description = "Erreur interne du serveur") @APIResponse(responseCode = "500", description = "Erreur interne du serveur")
}) })
public Uni<List<SimpleClubModel>> getAll() { public Uni<List<SimpleClubModel>> getAll() {
return clubService.getAll().map(clubModels -> clubModels.stream().map(SimpleClubModel::fromModel).toList()); return clubService.getAll().map(clubModels -> clubModels.stream().map(SimpleClubModel::fromModel).sorted(
Comparator.comparing(SimpleClubModel::getName)).toList());
} }
@GET @GET
@@ -79,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
@@ -107,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")
@@ -119,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
@@ -143,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
@@ -179,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
@@ -228,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é")
@@ -240,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" +
@@ -262,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 = {
@@ -275,9 +257,26 @@ public class ClubEndpoints {
return pdfService.getAffiliationPdf(securityCtx.getSubject()); return pdfService.getAffiliationPdf(securityCtx.getSubject());
} }
@GET
@Path("/members")
@RolesAllowed({"club_president", "club_secretaire", "club_respo_intra", "club_tresorier"})
@Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Revoie tout les membres de votre club")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "List des membres"),
@APIResponse(responseCode = "403", description = "Accès refusé"),
@APIResponse(responseCode = "404", description = "L'utilisateur n'est pas membre d'un club"),
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
})
public Uni<List<VerySimpleMembre>> getMembers() {
return clubService.getMembers(securityCtx);
}
@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,
@@ -288,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é")
@@ -316,7 +315,7 @@ public class ClubEndpoints {
@Parameter(description = "Identifiant long (clubId) de club") @PathParam("clubId") String clubId) { @Parameter(description = "Identifiant long (clubId) de club") @PathParam("clubId") String clubId) {
return clubService.getByClubId(clubId).chain(Unchecked.function(clubModel -> { return clubService.getByClubId(clubId).chain(Unchecked.function(clubModel -> {
try { try {
return Utils.getMediaFile((clubModel != null) ? clubModel.getId() : -1, media, "ppClub", return Utils.getMediaFileNoDefault((clubModel != null) ? clubModel.getId() : -1, media, "ppClub",
Uni.createFrom().nullItem()); Uni.createFrom().nullItem());
} catch (URISyntaxException e) { } catch (URISyntaxException e) {
throw new InternalError(); throw new InternalError();
@@ -326,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"),
@@ -339,7 +338,7 @@ public class ClubEndpoints {
return clubService.getById(id).onItem().invoke(checkPerm).chain(Unchecked.function(clubModel -> { return clubService.getById(id).onItem().invoke(checkPerm).chain(Unchecked.function(clubModel -> {
try { try {
return Utils.getMediaFile(clubModel.getId(), media, "clubStatus", return Utils.getMediaFile(clubModel.getId(), media, "clubStatus",
"statue-" + clubModel.getName(), Uni.createFrom().nullItem()); "statue-" + clubModel.getName(), Uni.createFrom().nullItem(), false);
} catch (URISyntaxException e) { } catch (URISyntaxException e) {
throw new InternalError(); throw new InternalError();
} }

View File

@@ -0,0 +1,58 @@
package fr.titionfire.ffsaf.rest;
import fr.titionfire.ffsaf.domain.service.CompetitionService;
import fr.titionfire.ffsaf.rest.data.CompetitionData;
import fr.titionfire.ffsaf.utils.CompetitionSystem;
import fr.titionfire.ffsaf.utils.SecurityCtx;
import io.quarkus.security.Authenticated;
import io.smallrye.mutiny.Uni;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import java.util.List;
@Path("api/competition/admin")
public class CompetitionAdminEndpoints {
@Inject
CompetitionService service;
@Inject
SecurityCtx securityCtx;
@GET
@Path("{id}")
@Authenticated
@Produces(MediaType.APPLICATION_JSON)
public Uni<CompetitionData> getByIdAdmin(@PathParam("id") Long id) {
return service.getByIdAdmin(securityCtx, id);
}
@GET
@Path("all")
@Authenticated
@Produces(MediaType.APPLICATION_JSON)
public Uni<List<CompetitionData>> getAllAdmin() {
return service.getAllAdmin(securityCtx);
}
@GET
@Path("all/{system}")
@Authenticated
@Produces(MediaType.APPLICATION_JSON)
public Uni<List<CompetitionData>> getAllSystemAdmin(@PathParam("system") CompetitionSystem system) {
return service.getAllSystemAdmin(securityCtx, system);
}
@GET
@Path("all/{system}/table")
@Authenticated
@Produces(MediaType.APPLICATION_JSON)
public Uni<List<CompetitionData>> getAllSystemTable(@PathParam("system") CompetitionSystem system) {
return service.getAllSystemTable(securityCtx, system);
}
}

View File

@@ -1,11 +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.CompetitionSystem;
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;
@@ -29,34 +25,49 @@ public class CompetitionEndpoints {
@Path("{id}") @Path("{id}")
@Authenticated @Authenticated
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Uni<CompetitionData> getById(@PathParam("id") Long id) { public Uni<CompetitionData> getById(@PathParam("id") Long id, @QueryParam("light") boolean light) {
return service.getById(securityCtx, id); if (light)
return service.getById(securityCtx, id);
else
return service.getByIdAdmin(securityCtx, id);
} }
@GET @GET
@Path("{id}/register") @Path("{id}/register/{source}")
@Authenticated @Authenticated
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Uni<List<SimpleRegisterComb>> getRegister(@PathParam("id") Long id) { public Uni<List<SimpleRegisterComb>> getRegister(@PathParam("id") Long id, @PathParam("source") String source) {
return service.getRegister(securityCtx, id); return service.getRegister(securityCtx, id, source);
} }
@POST @POST
@Path("{id}/register") @Path("{id}/register/{source}")
@Authenticated @Authenticated
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Operation(hidden = true) @Operation(hidden = true)
public Uni<SimpleRegisterComb> addRegisterComb(@PathParam("id") Long id, RegisterRequestData data) { public Uni<SimpleRegisterComb> addRegisterComb(@PathParam("id") Long id, @PathParam("source") String source,
return service.addRegisterComb(securityCtx, id, data); RegisterRequestData data) {
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}") @Path("{id}/register/{comb_id}/{source}")
@Authenticated @Authenticated
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Operation(hidden = true) @Operation(hidden = true)
public Uni<Void> removeRegisterComb(@PathParam("id") Long id, @PathParam("comb_id") Long combId) { public Uni<Void> removeRegisterComb(@PathParam("id") Long id, @PathParam("comb_id") Long combId,
return service.removeRegisterComb(securityCtx, id, combId); @PathParam("source") String source, @QueryParam("ban") boolean ban) {
return service.removeRegisterComb(securityCtx, id, combId, source, ban);
} }
@GET @GET
@@ -67,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")
@@ -76,14 +102,6 @@ public class CompetitionEndpoints {
return service.getAll(securityCtx); return service.getAll(securityCtx);
} }
@GET
@Path("all/{system}")
@Authenticated
@Produces(MediaType.APPLICATION_JSON)
public Uni<List<CompetitionData>> getAllSystem(@PathParam("system") CompetitionSystem system) {
return service.getAllSystem(securityCtx, system);
}
@POST @POST
@Authenticated @Authenticated
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@@ -99,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 = {
@@ -115,8 +115,8 @@ public class CompteEndpoints {
else toRemove.add("safca_super_admin"); else toRemove.add("safca_super_admin");
if (form.isSafca_user()) toAdd.add("safca_user"); if (form.isSafca_user()) toAdd.add("safca_user");
else toRemove.add("safca_user"); else toRemove.add("safca_user");
if (form.isSafca_create_compet()) toAdd.add("safca_create_compet"); if (form.isCreate_compet()) toAdd.add("create_compet");
else toRemove.add("safca_create_compet"); else toRemove.add("create_compet");
return service.updateRole(id, toAdd, toRemove); return service.updateRole(id, toAdd, toRemove);
} }

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"),
@@ -118,7 +118,7 @@ public class LicenceEndpoints {
@RolesAllowed("federation_admin") @RolesAllowed("federation_admin")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@Operation(summary = "Validation licence", description = "Valide en masse les licence de l'année en cours (pour les administrateurs)") @Operation(summary = "Validation licence", description = "Valide en masse les licences de l'année en cours (pour les administrateurs)")
@APIResponses(value = { @APIResponses(value = {
@APIResponse(responseCode = "200", description = "Les licences ont été mise à jour avec succès"), @APIResponse(responseCode = "200", description = "Les licences ont été mise à jour avec succès"),
@APIResponse(responseCode = "403", description = "Accès refusé"), @APIResponse(responseCode = "403", description = "Accès refusé"),
@@ -128,6 +128,21 @@ public class LicenceEndpoints {
return licenceService.valideLicences(ids); return licenceService.valideLicences(ids);
} }
@POST
@Path("validate-pay")
@RolesAllowed("federation_admin")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Operation(summary = "Validation du payment des licences", description = "Valide en masse le payment des licences de l'année en cours (pour les administrateurs)")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "Les licences ont été mise à jour avec succès"),
@APIResponse(responseCode = "403", description = "Accès refusé"),
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
})
public Uni<?> validePaymentLicences(@Parameter(description = "Id des membres a valider") List<Long> ids) {
return licenceService.validePaymentLicences(ids);
}
@DELETE @DELETE
@Path("{id}") @Path("{id}")
@RolesAllowed("federation_admin") @RolesAllowed("federation_admin")
@@ -146,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" +
@@ -163,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

@@ -14,8 +14,8 @@ import jakarta.ws.rs.core.MediaType;
import java.util.List; import java.util.List;
@Authenticated @Authenticated
@Path("api/match/{system}/") @Path("api/match/{system}/admin")
public class MatchEndpoints { public class MatchAdminEndpoints {
@PathParam("system") @PathParam("system")
private CompetitionSystem system; private CompetitionSystem system;
@@ -30,15 +30,15 @@ public class MatchEndpoints {
@GET @GET
@Path("{id}") @Path("{id}")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Uni<MatchData> getById(@PathParam("id") Long id) { public Uni<MatchData> getByIdAdmin(@PathParam("id") Long id) {
return service.getById(securityCtx, system, id); return service.getByIdAdmin(securityCtx, system, id);
} }
@GET @GET
@Path("getAllByPoule/{id}") @Path("getAllByPoule/{id}")
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
public Uni<List<MatchData>> getAllByPoule(@PathParam("id") Long id) { public Uni<List<MatchData>> getAllByPouleAdmin(@PathParam("id") Long id) {
return service.getAllByPoule(securityCtx, system, id); return service.getAllByPouleAdmin(securityCtx, system, id);
} }
@POST @POST

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;
@@ -58,13 +64,17 @@ public class MembreAdminEndpoints {
@Parameter(description = "Page à consulter") @QueryParam("page") Integer page, @Parameter(description = "Page à consulter") @QueryParam("page") Integer page,
@Parameter(description = "Text à rechercher") @QueryParam("search") String search, @Parameter(description = "Text à rechercher") @QueryParam("search") String search,
@Parameter(description = "Club à filter") @QueryParam("club") String club, @Parameter(description = "Club à filter") @QueryParam("club") String club,
@Parameter(description = "Etat de la demande de licence: 0 -> sans demande, 1 -> avec demande ou validée, 2 -> toute les demande non validée, 3 -> validée, 4 -> tout, 5 -> demande complete, 6 -> demande incomplete") @QueryParam("licenceRequest") int licenceRequest, @Parameter(description = "Catégorie à filter") @QueryParam("categorie") String categorie,
@Parameter(description = "Etat du payment: 0 -> non payer, 1 -> payer, 2 -> tout") @QueryParam("payment") int payment) { @Parameter(description = "Inclure les archive") @QueryParam("archive") Boolean archive,
@Parameter(description = "État de la demande de licence: 0 -> sans demande, 1 -> avec demande ou validée, 2 -> toute les demande non validée, 3 -> validée, 4 -> tout, 5 -> demande complete, 6 -> demande incomplete") @QueryParam("licenceRequest") int licenceRequest,
@Parameter(description = "État du payment: 0 -> non payer, 1 -> payer, 2 -> tout") @QueryParam("payment") int payment,
@Parameter(description = "Ordre") @QueryParam("order") String order) {
if (limit == null) if (limit == null)
limit = 50; limit = 50;
if (page == null || page < 1) if (page == null || page < 1)
page = 1; page = 1;
return membreService.searchAdmin(limit, page - 1, search, club, licenceRequest, payment); return membreService.searchAdmin(limit, page - 1, search, club, licenceRequest, payment, order,
categorie, archive);
} }
@GET @GET
@@ -93,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
@@ -119,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)
@@ -50,13 +53,17 @@ public class MembreClubEndpoints {
@Parameter(description = "Nombre max de résulta (max 50)") @QueryParam("limit") Integer limit, @Parameter(description = "Nombre max de résulta (max 50)") @QueryParam("limit") Integer limit,
@Parameter(description = "Page à consulter") @QueryParam("page") Integer page, @Parameter(description = "Page à consulter") @QueryParam("page") Integer page,
@Parameter(description = "Text à rechercher") @QueryParam("search") String search, @Parameter(description = "Text à rechercher") @QueryParam("search") String search,
@Parameter(description = "Catégorie à filter") @QueryParam("categorie") String categorie,
@Parameter(description = "Inclure les archive") @QueryParam("archive") Boolean archive,
@Parameter(description = "Etat de la demande de licence: 0 -> sans demande, 1 -> avec demande ou validée, 2 -> toute les demande non validée, 3 -> validée, 4 -> tout, 5 -> demande complete, 6 -> demande incomplete") @QueryParam("licenceRequest") int licenceRequest, @Parameter(description = "Etat de la demande de licence: 0 -> sans demande, 1 -> avec demande ou validée, 2 -> toute les demande non validée, 3 -> validée, 4 -> tout, 5 -> demande complete, 6 -> demande incomplete") @QueryParam("licenceRequest") int licenceRequest,
@Parameter(description = "Etat du payment: 0 -> non payer, 1 -> payer, 2 -> tout") @QueryParam("payment") int payment) { @Parameter(description = "Etat du payment: 0 -> non payer, 1 -> payer, 2 -> tout") @QueryParam("payment") int payment,
@Parameter(description = "Ordre") @QueryParam("order") String order) {
if (limit == null) if (limit == null)
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, securityCtx.getSubject()); return membreService.search(limit, page - 1, search, licenceRequest, payment, order, categorie, archive,
securityCtx.getSubject());
} }
@GET @GET
@@ -104,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
@@ -131,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

@@ -0,0 +1,79 @@
package fr.titionfire.ffsaf.rest;
import fr.titionfire.ffsaf.domain.service.ResultService;
import fr.titionfire.ffsaf.rest.data.ResultCategoryData;
import fr.titionfire.ffsaf.utils.SecurityCtx;
import io.quarkus.security.Authenticated;
import io.smallrye.mutiny.Uni;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import java.util.HashMap;
import java.util.List;
@Authenticated
@Path("api/result")
public class ResultEndpoints {
@Inject
ResultService resultService;
@Inject
SecurityCtx securityCtx;
@GET
@Path("list")
public Uni<List<Object[]>> getList() {
return resultService.getList(securityCtx);
}
@GET
@Path("{uuid}/category/list")
public Uni<HashMap<String, Long>> getCategoryList(@PathParam("uuid") String uuid) {
return resultService.getCategoryList(uuid, securityCtx);
}
@GET
@Path("{uuid}/category/{id}")
public Uni<ResultCategoryData> getCategory(@PathParam("uuid") String uuid, @PathParam("id") long id) {
return resultService.getCategory(uuid, id, securityCtx);
}
@GET
@Path("{uuid}/club/list")
public Uni<HashMap<String, Long>> getClubList(@PathParam("uuid") String uuid) {
return resultService.getClubList(uuid, securityCtx);
}
@GET
@Path("{uuid}/club/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
@Path("{uuid}/comb")
public Uni<ResultService.CombsArrayData> getComb(@PathParam("uuid") String uuid) {
return resultService.getAllCombArray(uuid, securityCtx);
}
}

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,6 +1,7 @@
package fr.titionfire.ffsaf.rest.client; package fr.titionfire.ffsaf.rest.client;
import fr.titionfire.ffsaf.rest.data.UniteLegaleRoot; import fr.titionfire.ffsaf.rest.data.UniteLegaleRoot;
import io.quarkus.cache.CacheResult;
import io.smallrye.mutiny.Uni; import io.smallrye.mutiny.Uni;
import jakarta.ws.rs.GET; import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path; import jakarta.ws.rs.Path;
@@ -15,5 +16,6 @@ public interface SirenService {
@GET @GET
@Path("/v3/unites_legales/{SIREN}") @Path("/v3/unites_legales/{SIREN}")
@CacheResult(cacheName = "AssoData_siren")
Uni<UniteLegaleRoot> get_unite(@PathParam("SIREN") String siren); Uni<UniteLegaleRoot> get_unite(@PathParam("SIREN") String siren);
} }

View File

@@ -0,0 +1,48 @@
package fr.titionfire.ffsaf.rest.client;
import fr.titionfire.ffsaf.rest.data.AssoData;
import fr.titionfire.ffsaf.rest.data.UniteLegaleRoot;
import io.quarkus.cache.CacheResult;
import io.smallrye.mutiny.Uni;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
@Path("/")
@RegisterRestClient
public interface StateIdService {
@GET
@Path("/associations/{rna}")
@CacheResult(cacheName = "AssoData_rna")
Uni<AssoData> get_rna(@PathParam("rna") String rna);
default Uni<AssoData> getAssoDataFromUnit(UniteLegaleRoot u) {
AssoData assoData = new AssoData();
assoData.setSiren(u.getUnite_legale().getSiren());
assoData.setRna(u.getUnite_legale().getIdentifiant_association());
AssoData.Identite identite = new AssoData.Identite();
identite.setNom(u.getUnite_legale().getDenomination());
identite.setSiret_siege(u.getUnite_legale().getEtablissement_siege().getSiret());
assoData.setIdentite(identite);
AssoData.Address address = new AssoData.Address();
StringBuilder voie = new StringBuilder();
if (u.getUnite_legale().getEtablissement_siege().getNumero_voie() != null)
voie.append(u.getUnite_legale().getEtablissement_siege().getNumero_voie()).append(' ');
if (u.getUnite_legale().getEtablissement_siege().getType_voie() != null)
voie.append(u.getUnite_legale().getEtablissement_siege().getType_voie()).append(' ');
if (u.getUnite_legale().getEtablissement_siege().getLibelle_voie() != null)
voie.append(u.getUnite_legale().getEtablissement_siege().getLibelle_voie()).append(' ');
address.setVoie(voie.toString().trim());
address.setComplement(u.getUnite_legale().getEtablissement_siege().getComplement_adresse());
address.setCode_postal(u.getUnite_legale().getEtablissement_siege().getCode_postal());
address.setCommune(
new AssoData.Commune(u.getUnite_legale().getEtablissement_siege().getLibelle_commune()));
assoData.setCoordonnees(new AssoData.Coordonnee(address));
return Uni.createFrom().item(assoData);
}
}

View File

@@ -5,6 +5,8 @@ import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.util.List;
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@@ -12,11 +14,14 @@ import lombok.NoArgsConstructor;
public class NotificationData { public class NotificationData {
private Order order; private Order order;
private Integer id; private Integer id;
private String formSlug;
private String formType;
private String organizationSlug; private String organizationSlug;
private String checkoutIntentId; private String checkoutIntentId;
private String oldSlugOrganization; // Pour les changements de nom d'association private String oldSlugOrganization; // Pour les changements de nom d'association
private String newSlugOrganization; private String newSlugOrganization;
private String state; // Pour les formulaires private String state; // Pour les formulaires
private List<Item> items;
@Data @Data
@@ -26,5 +31,35 @@ public class NotificationData {
public static class Order { public static class Order {
private Integer id; private Integer id;
private String organizationSlug; private String organizationSlug;
private String formSlug;
private String formType;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@RegisterForReflection
public static class Item {
private String name;
private User user;
private List<CustomField> customFields;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@RegisterForReflection
public static class User {
private String firstName;
private String lastName;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@RegisterForReflection
public static class CustomField {
private String name;
private String answer;
} }
} }

View File

@@ -0,0 +1,48 @@
package fr.titionfire.ffsaf.rest.data;
import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@RegisterForReflection
public class AssoData {
String siren;
String rna;
Identite identite;
Coordonnee coordonnees;
@Data
@RegisterForReflection
public static class Identite {
String nom;
String siret_siege;
}
@Data
@RegisterForReflection
@NoArgsConstructor
@AllArgsConstructor
public static class Coordonnee {
Address adresse_gestion;
}
@Data
@RegisterForReflection
public static class Address {
String voie;
String complement;
String code_postal;
String pays;
Commune commune;
}
@Data
@RegisterForReflection
@NoArgsConstructor
@AllArgsConstructor
public static class Commune {
String nom;
}
}

View File

@@ -1,6 +1,6 @@
package fr.titionfire.ffsaf.rest.data; package fr.titionfire.ffsaf.rest.data;
import fr.titionfire.ffsaf.data.model.PouleModel; import fr.titionfire.ffsaf.data.model.CategoryModel;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
@@ -8,16 +8,16 @@ import lombok.Data;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@RegisterForReflection @RegisterForReflection
public class PouleData { public class CategoryData {
private Long id; private Long id;
private String name; private String name;
private Long compet; private Long compet;
private Integer type; private Integer type;
public static PouleData fromModel(PouleModel model) { public static CategoryData fromModel(CategoryModel model) {
if (model == null) if (model == null)
return null; return null;
return new PouleData(model.getSystemId(), model.getName(), model.getCompet().getId(), model.getType()); return new CategoryData(model.getSystemId(), model.getName(), model.getCompet().getId(), model.getType());
} }
} }

View File

@@ -7,7 +7,7 @@ import java.util.List;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
public class PouleFullData { public class CategoryFullData {
private Long id; private Long id;
private String name; private String name;
private Long compet; private Long compet;

View File

@@ -1,15 +1,20 @@
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.CompetitionModel; import fr.titionfire.ffsaf.data.model.CompetitionModel;
import fr.titionfire.ffsaf.data.model.RegisterModel;
import fr.titionfire.ffsaf.utils.Categorie; import fr.titionfire.ffsaf.utils.Categorie;
import fr.titionfire.ffsaf.utils.CompetitionSystem; import fr.titionfire.ffsaf.utils.CompetitionSystem;
import fr.titionfire.ffsaf.data.model.RegisterModel; import fr.titionfire.ffsaf.utils.RegisterMode;
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.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@@ -17,26 +22,82 @@ import java.util.List;
public class CompetitionData { public class CompetitionData {
private Long id; private Long id;
private String name; private String name;
private String description;
private String adresse;
private String uuid; private String uuid;
private Date date; private Date date;
private Date toDate;
private CompetitionSystem system; private CompetitionSystem system;
private RegisterMode registerMode;
private Date startRegister;
private Date endRegister;
private boolean publicVisible;
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 canEditRegisters;
private String data1;
private String data2;
private String data3;
private String data4;
private String config;
private List<PresetData> presets;
private List<Categorie> requiredWeight;
public CompetitionData() {
this(null, "", "", "", "", new Date(), new Date(),
CompetitionSystem.INTERNAL, RegisterMode.FREE, new Date(), new Date(), true,
null, "", "", null, true, true,
"", "", "", "", "{}", new ArrayList<>(), new ArrayList<>());
}
public static CompetitionData fromModel(CompetitionModel model) { public static CompetitionData fromModel(CompetitionModel model) {
if (model == null) if (model == null)
return null; return null;
return new CompetitionData(model.getId(), model.getName(), model.getUuid(), model.getDate(), model.getSystem(), return new CompetitionData(model.getId(), model.getName(), model.getDescription(), model.getAdresse(),
model.getClub().getId(), model.getClub().getName(), model.getOwner(), null); model.getUuid(), model.getDate(), model.getTodate(), model.getSystem(),
model.getRegisterMode(), model.getStartRegister(), model.getEndRegister(), model.isPublicVisible(),
model.getClub().getId(), model.getClub().getName(), model.getOwner(), null, false, false,
model.getData1(), model.getData2(), model.getData3(), model.getData4(), model.getConfig(),
new ArrayList<>(), model.getRequiredWeight());
} }
public CompetitionData addInsc(List<RegisterModel> insc) { public static CompetitionData fromModelLight(CompetitionModel model) {
this.registers = insc.stream() if (model == null)
.map(i -> new SimpleRegister(i.getMembre().getId(), i.getOverCategory(), i.getWeight(), return null;
i.getCategorie(), (i.getClub() == null) ? null : i.getClub().getId())).toList();
CompetitionData out = new CompetitionData(model.getId(), model.getName(), model.getDescription(),
model.getAdresse(), "", model.getDate(), model.getTodate(), null,
model.getRegisterMode(), model.getStartRegister(), model.getEndRegister(), model.isPublicVisible(),
null, model.getClub().getName(), "", null, false, false,
"", "", "", "", "{}", new ArrayList<>(), model.getRequiredWeight());
if (model.getRegisterMode() == RegisterMode.HELLOASSO) {
out.setData1(model.getData1());
out.setData2(model.getData2());
}
return out;
}
public CompetitionData addInsc(List<RegisterModel> insc, List<CompetitionGuestModel> guests) {
this.registers = Stream.concat(
insc.stream()
.map(i -> new SimpleRegister(i.getMembre().getId(), i.getOverCategory(), i.getWeight2(),
i.getCategorie(), (i.getClub() == null) ? null : i.getClub().getId(),
(i.getClub() == null) ? null : i.getClub().getName())),
guests.stream()
.map(i -> new SimpleRegister(i.getId() * -1, 0, i.getWeight2(),
i.getCategorie(), null, i.getClub()))).toList();
return this;
}
public CompetitionData addPresets(List<CatPresetModel> presets) {
this.presets = presets.stream().map(PresetData::fromModel).toList();
return this; return this;
} }
@@ -46,8 +107,9 @@ public class CompetitionData {
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;
} }
} }

View File

@@ -17,10 +17,10 @@ public class MatchData {
private String c1_str; private String c1_str;
private Long c2_id; private Long c2_id;
private String c2_str; private String c2_str;
private Long poule; private Long category;
private long poule_ord; private long category_ord;
private boolean isEnd = true; private boolean isEnd = true;
private char groupe; private char poule;
private List<ScoreEmbeddable> scores; private List<ScoreEmbeddable> scores;
public static MatchData fromModel(MatchModel model) { public static MatchData fromModel(MatchModel model) {
@@ -28,9 +28,11 @@ public class MatchData {
return null; return null;
return new MatchData(model.getSystemId(), return new MatchData(model.getSystemId(),
(model.getC1_id() == null) ? null : model.getC1_id().getId(), model.getC1_str(), (model.getC1_id() == null) ? null : model.getC1_id().getId(),
(model.getC2_id() == null) ? null : model.getC2_id().getId(), model.getC2_str(), (model.getC1_guest() == null) ? null : model.getC1_guest().getName(),
model.getPoule().getId(), model.getPoule_ord(), model.isEnd(), model.getGroupe(), (model.getC2_id() == null) ? null : model.getC2_id().getId(),
(model.getC2_guest() == null) ? null : model.getC2_guest().getName(),
model.getCategory().getId(), model.getCategory_ord(), model.isEnd(), model.getPoule(),
model.getScores()); model.getScores());
} }
} }

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().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

@@ -1,15 +1,35 @@
package fr.titionfire.ffsaf.rest.data; package fr.titionfire.ffsaf.rest.data;
import fr.titionfire.ffsaf.utils.Categorie;
import fr.titionfire.ffsaf.utils.Genre;
import io.quarkus.runtime.annotations.RegisterForReflection; import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data @Data
@AllArgsConstructor
@NoArgsConstructor
@RegisterForReflection @RegisterForReflection
public class RegisterRequestData { public class RegisterRequestData {
private Long licence; private Long licence;
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 List<Long> categoriesInscrites;
// for guest registration only
private Long id = null;
private Categorie categorie = Categorie.CADET;
private Genre genre = Genre.NA;
private String club = null;
private String country = null;
private boolean quick = false;
} }

View File

@@ -17,9 +17,9 @@ import java.util.List;
@RegisterForReflection @RegisterForReflection
public class RenewAffData { public class RenewAffData {
String name; String name;
Long siret; String state_id;
String rna;
String address; String address;
String contact;
int saison; int saison;
List<RenewMember> members; List<RenewMember> members;

View File

@@ -0,0 +1,83 @@
package fr.titionfire.ffsaf.rest.data;
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.TreeNode;
import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@Data
@NoArgsConstructor
@RegisterForReflection
public class ResultCategoryData {
int type;
String name;
boolean treeIsClassement;
HashMap<Character, List<PouleArrayData>> matchs = new HashMap<>();
HashMap<Character, List<RankArray>> rankArray = new HashMap<>();
ArrayList<TreeNode<TreeData>> trees;
List<ClassementData> classement = new ArrayList<>();
String[] liceName;
long genTime;
@Data
@AllArgsConstructor
@RegisterForReflection
public static class RankArray {
int rank;
@JsonIgnore
CombModel comb;
String name;
int score;
int win;
int pointMake;
int pointTake;
float pointRate;
}
@RegisterForReflection
public record PouleArrayData(String red, boolean red_w, List<Integer[]> score, boolean blue_w, String blue,
boolean eq, boolean end, Date date) {
public static PouleArrayData fromModel(MatchModelExtend matchModel, MembreModel membreModel,
ResultPrivacy privacy) {
return new PouleArrayData(
matchModel.getC1Name(membreModel, privacy),
matchModel.isEnd() && matchModel.getWin() > 0,
matchModel.isEnd() ?
matchModel.getScoresToPrint().stream().map(s -> new Integer[]{s.getS1(), s.getS2()})
.toList()
: new ArrayList<>(),
matchModel.isEnd() && matchModel.getWin() < 0,
matchModel.getC2Name(membreModel, privacy),
matchModel.isEnd() && matchModel.getWin() == 0,
matchModel.isEnd(),
matchModel.getDate());
}
}
@RegisterForReflection
public static record TreeData(long id, String c1FullName, String c2FullName, List<ScoreEmbeddable> scores,
boolean end, int win, int level, Date date) {
public static TreeData from(MatchModelExtend match, int level, MembreModel membreModel, ResultPrivacy privacy) {
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

@@ -14,8 +14,8 @@ import org.eclipse.microprofile.openapi.annotations.media.Schema;
public class SimpleAffiliation { public class SimpleAffiliation {
@Schema(description = "L'identifiant de l'affiliation.", example = "1") @Schema(description = "L'identifiant de l'affiliation.", example = "1")
private Long id; private Long id;
@Schema(description = "L'identifiant du club associé à l'affiliation.", example = "123") @Schema(description = "L'identifiant du club associé à l'affiliation si id > 0 sinon n° SIRET ou RNA du club.", example = "123")
private Long club; private String club;
@Schema(description = "La saison de l'affiliation.", example = "2022") @Schema(description = "La saison de l'affiliation.", example = "2022")
private int saison; private int saison;
@Schema(description = "Indique si l'affiliation est validée ou non.", example = "true") @Schema(description = "Indique si l'affiliation est validée ou non.", example = "true")
@@ -27,7 +27,7 @@ public class SimpleAffiliation {
return new SimpleAffiliationBuilder() return new SimpleAffiliationBuilder()
.id(model.getId()) .id(model.getId())
.club(model.getClub().getId()) .club(String.valueOf(model.getClub().getId()))
.saison(model.getSaison()) .saison(model.getSaison())
.validate(true) .validate(true)
.build(); .build();

View File

@@ -36,10 +36,8 @@ public class SimpleClub {
private String contact_intern; private String contact_intern;
@Schema(description = "Adresse postale du club", example = "1 rue de l'exemple, 75000 Paris") @Schema(description = "Adresse postale du club", example = "1 rue de l'exemple, 75000 Paris")
private String address; private String address;
@Schema(description = "RNA du club", example = "W123456789") @Schema(description = "Numéro SIRET ou RNA du club", example = "12345678901234")
private String RNA; private String state_id;
@Schema(description = "Numéro SIRET du club", example = "12345678901234")
private Long SIRET;
@Schema(description = "Numéro d'affiliation du club", example = "12345") @Schema(description = "Numéro d'affiliation du club", example = "12345")
private Long no_affiliation; private Long no_affiliation;
@Schema(description = "Club international", example = "false") @Schema(description = "Club international", example = "false")
@@ -60,8 +58,7 @@ public class SimpleClub {
.training_location(model.getTraining_location()) .training_location(model.getTraining_location())
.training_day_time(model.getTraining_day_time()) .training_day_time(model.getTraining_day_time())
.contact_intern(model.getContact_intern()) .contact_intern(model.getContact_intern())
.RNA(model.getRNA()) .state_id(model.getStateId())
.SIRET(model.getSIRET())
.no_affiliation(model.getNo_affiliation()) .no_affiliation(model.getNo_affiliation())
.international(model.isInternational()) .international(model.isInternational())
.address(model.getAddress()) .address(model.getAddress())

View File

@@ -20,8 +20,8 @@ public class SimpleClubList {
String name; String name;
@Schema(description = "Pays du club", example = "FR") @Schema(description = "Pays du club", example = "FR")
String country; String country;
@Schema(description = "Numéro SIRET du club", example = "12345678901234") @Schema(description = "Numéro SIRET ou RNA du club", example = "12345678901234")
Long siret; String state_id;
@Schema(description = "Numéro d'affiliation du club", example = "12345") @Schema(description = "Numéro d'affiliation du club", example = "12345")
Long no_affiliation; Long no_affiliation;
@@ -29,7 +29,7 @@ public class SimpleClubList {
if (model == null) if (model == null)
return null; return null;
return new SimpleClubList(model.getId(), model.getName(), model.getCountry(), model.getSIRET(), return new SimpleClubList(model.getId(), model.getName(), model.getCountry(), model.getStateId(),
model.getNo_affiliation()); model.getNo_affiliation());
} }
} }

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,36 +1,59 @@
package fr.titionfire.ffsaf.rest.data; package fr.titionfire.ffsaf.rest.data;
import fr.titionfire.ffsaf.data.model.LicenceModel; import fr.titionfire.ffsaf.data.model.*;
import fr.titionfire.ffsaf.data.model.MembreModel;
import fr.titionfire.ffsaf.net2.data.SimpleClubModel; import fr.titionfire.ffsaf.net2.data.SimpleClubModel;
import fr.titionfire.ffsaf.data.model.RegisterModel; import fr.titionfire.ffsaf.utils.Categorie;
import fr.titionfire.ffsaf.utils.Genre;
import fr.titionfire.ffsaf.utils.Utils; 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;
private String fname; private String fname;
private String lname; private String lname;
private String categorie; private Genre genre;
private String country;
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 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();
return new SimpleRegisterComb(membreModel.getId(), membreModel.getFname(), membreModel.getLname(), return new SimpleRegisterComb(membreModel.getId(), membreModel.getFname(), membreModel.getLname(),
(register.getCategorie() == null) ? "Catégorie inconnue" : register.getCategorie().getName(), membreModel.getGenre(), membreModel.getCountry(),
(register.getCategorie() == null) ? null : register.getCategorie(),
SimpleClubModel.fromModel(register.getClub()), membreModel.getLicence(), register.getWeight(), 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(), new ArrayList<>());
}
public static SimpleRegisterComb fromModel(CompetitionGuestModel guest) {
return new SimpleRegisterComb(guest.getId() * -1, guest.getFname(), guest.getLname(),
guest.getGenre(), guest.getCountry(), guest.getCategorie(),
new SimpleClubModel(null, guest.getClub(), "fr", null),
null, guest.getWeight(), guest.getWeightReal(), 0, false, false,
new ArrayList<>());
}
public SimpleRegisterComb setCategorieInscrite(List<CatPresetModel> presets) {
this.categoriesInscrites = presets.stream().map(CatPresetModel::getId).toList();
return this;
} }
} }

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