fix: affiliation request page minor bug
This commit is contained in:
parent
2737e53de5
commit
6407bf44bc
@ -11,6 +11,7 @@ import fr.titionfire.ffsaf.utils.Utils;
|
|||||||
import io.quarkus.hibernate.reactive.panache.Panache;
|
import io.quarkus.hibernate.reactive.panache.Panache;
|
||||||
import io.quarkus.hibernate.reactive.panache.common.WithSession;
|
import io.quarkus.hibernate.reactive.panache.common.WithSession;
|
||||||
import io.smallrye.mutiny.Uni;
|
import io.smallrye.mutiny.Uni;
|
||||||
|
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 jakarta.ws.rs.NotFoundException;
|
import jakarta.ws.rs.NotFoundException;
|
||||||
@ -57,7 +58,13 @@ public class AffiliationService {
|
|||||||
affModel.setSaison(Utils.getSaison());
|
affModel.setSaison(Utils.getSaison());
|
||||||
|
|
||||||
// noinspection ResultOfMethodCallIgnored
|
// noinspection ResultOfMethodCallIgnored
|
||||||
return Uni.createFrom().item(affModel)
|
return repositoryRequest.count("siret = ?1 and saison = ?2", affModel.getSiret(), affModel.getSaison())
|
||||||
|
.onItem().invoke(Unchecked.consumer(count -> {
|
||||||
|
if (count != 0) {
|
||||||
|
throw new IllegalArgumentException("Affiliation request already exists");
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.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(count -> {
|
model.getM1_lincence()).count().invoke(count -> {
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
@ -293,6 +300,8 @@ public class AffiliationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Uni<?> deleteReqAffiliation(long id) {
|
public Uni<?> deleteReqAffiliation(long id) {
|
||||||
return Panache.withTransaction(() -> repositoryRequest.deleteById(id));
|
return Panache.withTransaction(() -> repositoryRequest.deleteById(id))
|
||||||
|
.call(__ -> Utils.deleteMedia(id, media, "aff_request/logo"))
|
||||||
|
.call(__ -> Utils.deleteMedia(id, media, "aff_request/status"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import jakarta.enterprise.context.ApplicationScoped;
|
|||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
import jakarta.ws.rs.BadRequestException;
|
import jakarta.ws.rs.BadRequestException;
|
||||||
import jakarta.ws.rs.ForbiddenException;
|
import jakarta.ws.rs.ForbiddenException;
|
||||||
|
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||||
import org.eclipse.microprofile.jwt.JsonWebToken;
|
import org.eclipse.microprofile.jwt.JsonWebToken;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -46,6 +47,9 @@ public class MembreService {
|
|||||||
@Inject
|
@Inject
|
||||||
KeycloakService keycloakService;
|
KeycloakService keycloakService;
|
||||||
|
|
||||||
|
@ConfigProperty(name = "upload_dir")
|
||||||
|
String media;
|
||||||
|
|
||||||
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("licence = ?1 AND (lname ILIKE ?2 OR fname ILIKE ?2)",
|
repository.find("licence = ?1 AND (lname ILIKE ?2 OR fname ILIKE ?2)",
|
||||||
@ -217,6 +221,7 @@ public class MembreService {
|
|||||||
keycloakService.removeAccount(membreModel.getUserId()) : Uni.createFrom().nullItem())
|
keycloakService.removeAccount(membreModel.getUserId()) : Uni.createFrom().nullItem())
|
||||||
.call(membreModel -> Panache.withTransaction(() -> repository.delete(membreModel)))
|
.call(membreModel -> Panache.withTransaction(() -> repository.delete(membreModel)))
|
||||||
.invoke(membreModel -> SReqComb.sendRm(serverCustom.clients, id))
|
.invoke(membreModel -> SReqComb.sendRm(serverCustom.clients, id))
|
||||||
|
.call(__ -> Utils.deleteMedia(id, media, "ppMembre"))
|
||||||
.map(__ -> "Ok");
|
.map(__ -> "Ok");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -40,7 +40,6 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Uni<String> moveMedia(long idSrc, long idDest, String media, String dirSrc, String dirDst) {
|
public static Uni<String> moveMedia(long idSrc, long idDest, String media, String dirSrc, String dirDst) {
|
||||||
System.out.println("moveMedia: " + idSrc + " -> " + idDest + " " + media + " " + dirSrc + " " + dirDst);
|
|
||||||
return Uni.createFrom().nullItem().map(__ -> {
|
return Uni.createFrom().nullItem().map(__ -> {
|
||||||
File dirFile = new File(media, dirSrc);
|
File dirFile = new File(media, dirSrc);
|
||||||
if (!dirFile.exists())
|
if (!dirFile.exists())
|
||||||
@ -51,12 +50,12 @@ public class Utils {
|
|||||||
if (!dirDestFile.mkdirs())
|
if (!dirDestFile.mkdirs())
|
||||||
return "Fail to create directory " + dirDestFile;
|
return "Fail to create directory " + dirDestFile;
|
||||||
|
|
||||||
FilenameFilter filter = (directory, filename) -> filename.startsWith(String.valueOf(idSrc));
|
FilenameFilter filter = (directory, filename) -> filename.startsWith(idSrc + ".");
|
||||||
File[] files = dirFile.listFiles(filter);
|
File[] files = dirFile.listFiles(filter);
|
||||||
if (files == null || files.length == 0)
|
if (files == null || files.length == 0)
|
||||||
return "Not found";
|
return "Not found";
|
||||||
|
|
||||||
FilenameFilter filter2 = (directory, filename) -> filename.startsWith(String.valueOf(idDest));
|
FilenameFilter filter2 = (directory, filename) -> filename.startsWith(idDest + ".");
|
||||||
File[] files2 = dirDestFile.listFiles(filter2);
|
File[] files2 = dirDestFile.listFiles(filter2);
|
||||||
if (files2 != null) {
|
if (files2 != null) {
|
||||||
for (File file : files2) {
|
for (File file : files2) {
|
||||||
@ -96,7 +95,7 @@ public class Utils {
|
|||||||
if (!dirFile.mkdirs())
|
if (!dirFile.mkdirs())
|
||||||
throw new IOException("Fail to create directory " + dir);
|
throw new IOException("Fail to create directory " + dir);
|
||||||
|
|
||||||
FilenameFilter filter = (directory, filename) -> filename.startsWith(String.valueOf(id));
|
FilenameFilter filter = (directory, filename) -> filename.startsWith(id +".");
|
||||||
File[] files = dirFile.listFiles(filter);
|
File[] files = dirFile.listFiles(filter);
|
||||||
if (files != null) {
|
if (files != null) {
|
||||||
for (File file : files) {
|
for (File file : files) {
|
||||||
@ -122,7 +121,7 @@ public class Utils {
|
|||||||
public static Uni<Response> getMediaFile(long id, String media, String dirname, String out_filename,
|
public static Uni<Response> getMediaFile(long id, String media, String dirname, String out_filename,
|
||||||
Uni<?> uniBase) throws URISyntaxException {
|
Uni<?> uniBase) throws URISyntaxException {
|
||||||
Future<Pair<File, byte[]>> future = CompletableFuture.supplyAsync(() -> {
|
Future<Pair<File, byte[]>> future = CompletableFuture.supplyAsync(() -> {
|
||||||
FilenameFilter filter = (directory, filename) -> filename.startsWith(String.valueOf(id));
|
FilenameFilter filter = (directory, filename) -> filename.startsWith(id + ".");
|
||||||
File[] files = new File(media, dirname).listFiles(filter);
|
File[] files = new File(media, dirname).listFiles(filter);
|
||||||
if (files != null && files.length > 0) {
|
if (files != null && files.length > 0) {
|
||||||
File file = files[0];
|
File file = files[0];
|
||||||
@ -150,9 +149,25 @@ public class Utils {
|
|||||||
resp.header(HttpHeaders.CONTENT_TYPE, mimeType);
|
resp.header(HttpHeaders.CONTENT_TYPE, mimeType);
|
||||||
resp.header(HttpHeaders.CONTENT_DISPOSITION,
|
resp.header(HttpHeaders.CONTENT_DISPOSITION,
|
||||||
"inline; " + ((out_filename == null) ? "" : "filename=\"" + out_filename + "\""));
|
"inline; " + ((out_filename == null) ? "" : "filename=\"" + out_filename + "\""));
|
||||||
|
|
||||||
System.out.println("getMediaFile: " + mimeType);
|
|
||||||
return resp.build();
|
return resp.build();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Uni<?> deleteMedia(long id, String media, String dir) {
|
||||||
|
return Uni.createFrom().nullItem().map(__ -> {
|
||||||
|
File dirFile = new File(media, dir);
|
||||||
|
if (!dirFile.exists())
|
||||||
|
return "OK";
|
||||||
|
|
||||||
|
FilenameFilter filter = (directory, filename) -> filename.startsWith(id + ".");
|
||||||
|
File[] files = dirFile.listFiles(filter);
|
||||||
|
if (files != null) {
|
||||||
|
for (File file : files) {
|
||||||
|
//noinspection ResultOfMethodCallIgnored
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "Ok";
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,15 +2,30 @@ import {useState} from "react";
|
|||||||
import {apiAxios} from "../utils/Tools.js";
|
import {apiAxios} from "../utils/Tools.js";
|
||||||
import {toast} from "react-toastify";
|
import {toast} from "react-toastify";
|
||||||
import {useNavigate} from "react-router-dom";
|
import {useNavigate} from "react-router-dom";
|
||||||
|
import {RoleList} from "../components/MemberCustomFiels.jsx";
|
||||||
|
|
||||||
|
const notUpperCase = ["de", "la", "le", "les", "des", "du", "d'", "l'", "sur"];
|
||||||
|
|
||||||
|
function formatAdresse(data) {
|
||||||
|
const words = data.split(" ");
|
||||||
|
|
||||||
|
return words.map((word) => {
|
||||||
|
if (notUpperCase.includes(word.toLowerCase())) {
|
||||||
|
return word.toLowerCase();
|
||||||
|
}
|
||||||
|
return word[0].toUpperCase() + word.substring(1).toLowerCase();
|
||||||
|
}).join(" ");
|
||||||
|
}
|
||||||
|
|
||||||
function reconstruireAdresse(infos) {
|
function reconstruireAdresse(infos) {
|
||||||
let adresseReconstruite = "";
|
let adresseReconstruite = "";
|
||||||
adresseReconstruite += infos.numero_voie + ' ' + infos.type_voie + ' ';
|
adresseReconstruite += infos.numero_voie + ' ' + formatAdresse(infos.type_voie) + ' ';
|
||||||
adresseReconstruite += infos.libelle_voie + ', ';
|
|
||||||
|
adresseReconstruite += formatAdresse(infos.libelle_voie) + ', ';
|
||||||
adresseReconstruite += infos.code_postal + ' ' + infos.libelle_commune + ', ';
|
adresseReconstruite += infos.code_postal + ' ' + infos.libelle_commune + ', ';
|
||||||
|
|
||||||
if (infos.complement_adresse) {
|
if (infos.complement_adresse) {
|
||||||
adresseReconstruite += infos.complement_adresse + ', ';
|
adresseReconstruite += infos.complement_adresse.toLowerCase() + ', ';
|
||||||
}
|
}
|
||||||
if (infos.code_cedex && infos.libelle_cedex) {
|
if (infos.code_cedex && infos.libelle_cedex) {
|
||||||
adresseReconstruite += 'Cedex ' + infos.code_cedex + ' - ' + infos.libelle_cedex;
|
adresseReconstruite += 'Cedex ' + infos.code_cedex + ' - ' + infos.libelle_cedex;
|
||||||
@ -31,6 +46,19 @@ export function DemandeAff() {
|
|||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
const formData = new FormData(event.target)
|
const formData = new FormData(event.target)
|
||||||
formData.append("m1_role", event.target.m1_role?.value)
|
formData.append("m1_role", event.target.m1_role?.value)
|
||||||
|
formData.append("rna", event.target.rna?.value)
|
||||||
|
|
||||||
|
let error = false;
|
||||||
|
for (let i = 1; i <= 3; i++) {
|
||||||
|
if (event.target[`m${i}_role`]?.value === "0") {
|
||||||
|
toast.error(`Le rôle du membre ${i} est obligatoire`)
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
toast.promise(
|
toast.promise(
|
||||||
apiAxios.post(`/affiliation/request`, formData, {headers: {'Accept': '*/*'}}),
|
apiAxios.post(`/affiliation/request`, formData, {headers: {'Accept': '*/*'}}),
|
||||||
{
|
{
|
||||||
@ -76,13 +104,11 @@ export function DemandeAff() {
|
|||||||
<MembreInfo role="m3"/>
|
<MembreInfo role="m3"/>
|
||||||
|
|
||||||
<div className="mb-3" style={{marginTop: '1em'}}>
|
<div className="mb-3" style={{marginTop: '1em'}}>
|
||||||
<p>Après validation de votre demande, vous recevrez un login et mot de passe provisoire pour
|
<p>Après validation de votre demande, vous recevrez un identifiant et mot de passe provisoire pour
|
||||||
accéder à votre espace FFSAF</p>
|
accéder à votre espace FFSAF</p>
|
||||||
Notez que pour finaliser votre affiliation, il vous faudra :
|
Notez que pour finaliser votre affiliation, il vous faudra :
|
||||||
<ul>
|
<ul>
|
||||||
<li>Disposer d’au moins trois membres licenciés, dont le président, le trésorier et le
|
<li>Disposer d’au moins trois membres licenciés, dont le président</li>
|
||||||
secrétaire
|
|
||||||
</li>
|
|
||||||
<li>S'être acquitté des cotisations prévues par les règlements fédéraux</li>
|
<li>S'être acquitté des cotisations prévues par les règlements fédéraux</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -158,11 +184,16 @@ function AssoInfo() {
|
|||||||
disabled={!rnaEnable} name="rna" value={rna} onChange={e => setRna(e.target.value)}/>
|
disabled={!rnaEnable} name="rna" value={rna} onChange={e => setRna(e.target.value)}/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="input-group mb-3">
|
<div className="mb-3">
|
||||||
<span className="input-group-text" id="basic-addon1">Adresse*</span>
|
<div className="input-group">
|
||||||
<input type="text" className="form-control" placeholder="Adresse" aria-label="Adresse"
|
<span className="input-group-text" id="basic-addon1">Adresse de contact*</span>
|
||||||
aria-describedby="basic-addon1"
|
<input type="text" className="form-control" placeholder="Adresse de contact" aria-label="Adresse de contact"
|
||||||
required value={adresse} name="adresse" onChange={e => setAdresse(e.target.value)}/>
|
aria-describedby="basic-addon1"
|
||||||
|
required value={adresse} name="adresse" onChange={e => setAdresse(e.target.value)}/>
|
||||||
|
</div>
|
||||||
|
<div className="form-text" id="adresse">Vous pourrez par la suite, ajouter des adresses visibles publiquement pour vos lieux
|
||||||
|
d'entrainement
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="input-group mb-3">
|
<div className="input-group mb-3">
|
||||||
@ -186,7 +217,7 @@ function MembreInfo({role}) {
|
|||||||
<label className="input-group-text" htmlFor="inputGroupSelect01">Rôles</label>
|
<label className="input-group-text" htmlFor="inputGroupSelect01">Rôles</label>
|
||||||
<select className="form-select" id="inputGroupSelect01" defaultValue={role === "m1" ? "PRESIDENT" : 0}
|
<select className="form-select" id="inputGroupSelect01" defaultValue={role === "m1" ? "PRESIDENT" : 0}
|
||||||
disabled={role === "m1"} name={role + "_role"} required>
|
disabled={role === "m1"} name={role + "_role"} required>
|
||||||
<option>Sélectionner...</option>
|
<option value="0">Sélectionner...</option>
|
||||||
<option value="PRESIDENT">Président</option>
|
<option value="PRESIDENT">Président</option>
|
||||||
<option value="TRESORIER">Trésorier</option>
|
<option value="TRESORIER">Trésorier</option>
|
||||||
<option value="SECRETAIRE">Secrétaire</option>
|
<option value="SECRETAIRE">Secrétaire</option>
|
||||||
@ -200,22 +231,23 @@ function MembreInfo({role}) {
|
|||||||
<div className="row g-3 mb-3">
|
<div className="row g-3 mb-3">
|
||||||
<div className="col-sm-3">
|
<div className="col-sm-3">
|
||||||
<div className="form-floating">
|
<div className="form-floating">
|
||||||
<input type="text" className="form-control" id="floatingInput" placeholder="Nom" name={role + "_nom"} defaultValue={role + "-nom"} required/>
|
<input type="text" className="form-control" id="floatingInput" placeholder="Nom" name={role + "_nom"} defaultValue={role + "-nom"}
|
||||||
<label htmlFor="floatingInput">Nom</label>
|
required/>
|
||||||
|
<label htmlFor="floatingInput">Nom*</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-sm-3">
|
<div className="col-sm-3">
|
||||||
<div className="form-floating">
|
<div className="form-floating">
|
||||||
<input type="text" className="form-control" id="floatingInput" placeholder="Prénom"
|
<input type="text" className="form-control" id="floatingInput" placeholder="Prénom"
|
||||||
name={role + "_prenom"} defaultValue={role + "_prenom"} required/>
|
name={role + "_prenom"} defaultValue={role + "_prenom"} required/>
|
||||||
<label htmlFor="floatingInput">Prénom</label>
|
<label htmlFor="floatingInput">Prénom*</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-sm-5">
|
<div className="col-sm-5">
|
||||||
<div className="form-floating">
|
<div className="form-floating">
|
||||||
<input type="email" className="form-control" id="floatingInput" placeholder="name@example.com"
|
<input type="email" className="form-control" id="floatingInput" placeholder="name@example.com"
|
||||||
name={role + "_mail"} defaultValue={role + "-mail@test.com"} required/>
|
name={role + "_mail"} defaultValue={role + "-mail@test.com"} required/>
|
||||||
<label htmlFor="floatingInput">Email</label>
|
<label htmlFor="floatingInput">Email*</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -231,7 +263,7 @@ function MembreInfo({role}) {
|
|||||||
<div className="col-sm-3">
|
<div className="col-sm-3">
|
||||||
<div className="form-floating">
|
<div className="form-floating">
|
||||||
<input type="number" className="form-control" id="floatingInput" placeholder="N° Licence"
|
<input type="number" className="form-control" id="floatingInput" placeholder="N° Licence"
|
||||||
name={role + "_licence"}/>
|
name={role + "_licence"} required/>
|
||||||
<label htmlFor="floatingInput">N° Licence</label>
|
<label htmlFor="floatingInput">N° Licence</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -244,7 +276,7 @@ export function DemandeAffOk() {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-green-800 text-4xl">Demande d'affiliation envoyée avec succès</h1>
|
<h1 className="text-green-800 text-4xl">Demande d'affiliation envoyée avec succès</h1>
|
||||||
<p>Une fois votre demande validée, vous recevrez un login et mot de passe provisoire pour accéder à votre
|
<p>Une fois votre demande validée, vous recevrez un identifiant et mot de passe provisoire pour accéder à votre
|
||||||
espace FFSAF</p>
|
espace FFSAF</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user