diff --git a/pom.xml b/pom.xml
index 413b042..609c526 100644
--- a/pom.xml
+++ b/pom.xml
@@ -129,6 +129,12 @@
io.quarkus
quarkus-cache
+
+
+ com.github.librepdf
+ openpdf
+ 2.0.3
+
diff --git a/src/main/java/fr/titionfire/ffsaf/domain/service/MembreService.java b/src/main/java/fr/titionfire/ffsaf/domain/service/MembreService.java
index 6b6b4c4..672f059 100644
--- a/src/main/java/fr/titionfire/ffsaf/domain/service/MembreService.java
+++ b/src/main/java/fr/titionfire/ffsaf/domain/service/MembreService.java
@@ -1,6 +1,12 @@
package fr.titionfire.ffsaf.domain.service;
+import com.lowagie.text.*;
+import com.lowagie.text.pdf.BaseFont;
+import com.lowagie.text.pdf.PdfPCell;
+import com.lowagie.text.pdf.PdfPTable;
+import com.lowagie.text.pdf.PdfWriter;
import fr.titionfire.ffsaf.data.model.ClubModel;
+import fr.titionfire.ffsaf.data.model.LicenceModel;
import fr.titionfire.ffsaf.data.model.MembreModel;
import fr.titionfire.ffsaf.data.repository.ClubRepository;
import fr.titionfire.ffsaf.data.repository.CombRepository;
@@ -13,6 +19,7 @@ import fr.titionfire.ffsaf.rest.data.SimpleLicence;
import fr.titionfire.ffsaf.rest.data.SimpleMembre;
import fr.titionfire.ffsaf.rest.exception.DBadRequestException;
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
+import fr.titionfire.ffsaf.rest.exception.DNotFoundException;
import fr.titionfire.ffsaf.rest.from.ClubMemberForm;
import fr.titionfire.ffsaf.rest.from.FullMemberForm;
import fr.titionfire.ffsaf.utils.*;
@@ -26,10 +33,17 @@ import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.unchecked.Unchecked;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
+import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.hibernate.reactive.mutiny.Mutiny;
+import java.io.*;
+import java.nio.file.Files;
+import java.text.SimpleDateFormat;
import java.util.List;
+import java.util.Objects;
@WithSession
@@ -111,6 +125,11 @@ public class MembreService {
return repository.findById(id);
}
+ public Uni getByIdWithLicence(long id) {
+ return repository.findById(id)
+ .call(m -> Mutiny.fetch(m.getLicences()));
+ }
+
public Uni getByLicence(long licence) {
return repository.find("licence = ?1", licence).firstResult();
}
@@ -276,4 +295,204 @@ public class MembreService {
.invoke(meData::setLicences)
.map(__ -> meData);
}
+
+ public Uni getLicencePdf(String subject) {
+ return getLicencePdf(repository.find("userId = ?1", subject).firstResult()
+ .call(m -> Mutiny.fetch(m.getLicences())));
+ }
+
+ public Uni getLicencePdf(Uni uniBase) {
+ return uniBase
+ .map(Unchecked.function(m -> {
+ LicenceModel licence = m.getLicences().stream()
+ .filter(licenceModel -> licenceModel.getSaison() == Utils.getSaison() && licenceModel.isValidate())
+ .findFirst()
+ .orElseThrow(() -> new DNotFoundException("Pas de licence pour la saison en cours"));
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try {
+ make_pdf(m, out, licence);
+
+ byte[] buff = out.toByteArray();
+ String mimeType = "application/pdf";
+
+ Response.ResponseBuilder resp = Response.ok(buff);
+ resp.type(MediaType.APPLICATION_OCTET_STREAM);
+ resp.header(HttpHeaders.CONTENT_LENGTH, buff.length);
+ resp.header(HttpHeaders.CONTENT_TYPE, mimeType);
+ resp.header(HttpHeaders.CONTENT_DISPOSITION,
+ "inline; " + "filename=\"Attestation d'adhésion " + Utils.getSaison() + "-" +
+ (Utils.getSaison() + 1) + " de " + m.getLname() + " " + m.getFname() + ".pdf\"");
+ return resp.build();
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+ }));
+ }
+
+ private void make_pdf(MembreModel m, ByteArrayOutputStream out, LicenceModel licence) throws IOException {
+ SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
+ Document document = new Document();
+ PdfWriter.getInstance(document, out);
+ document.open();
+
+ document.addCreator("FFSAF");
+ document.addTitle(
+ "Attestation d'adhésion " + Utils.getSaison() + "-" + (Utils.getSaison() + 1) + " de " + m.getLname() + " " + m.getFname());
+ document.addCreationDate();
+ document.addProducer("https://www.ffsaf.fr");
+
+ InputStream fontStream = MembreService.class.getClassLoader().getResourceAsStream("asset/DMSans-Regular.ttf");
+ if (fontStream == null) {
+ throw new IOException("Font file not found");
+ }
+ BaseFont customFont = BaseFont.createFont("asset/DMSans-Regular.ttf", BaseFont.WINANSI, BaseFont.EMBEDDED, true,
+ null, fontStream.readAllBytes());
+
+ // Adding font
+ Font headerFont = new Font(customFont, 26, Font.BOLD);
+ Font subHeaderFont = new Font(customFont, 16, Font.BOLD);
+ Font bigFont = new Font(customFont, 18, Font.BOLD);
+ Font bodyFont = new Font(customFont, 15, Font.BOLD);
+ Font smallFont = new Font(customFont, 10, Font.NORMAL);
+
+ // Creating the main table
+ PdfPTable mainTable = new PdfPTable(2);
+ mainTable.setWidthPercentage(100);
+ mainTable.setSpacingBefore(20f);
+ mainTable.setSpacingAfter(0f);
+ mainTable.setWidths(new float[]{120, 300});
+ mainTable.getDefaultCell().setBorder(PdfPCell.NO_BORDER);
+
+ // Adding logo
+ Image logo = Image.getInstance(
+ Objects.requireNonNull(
+ getClass().getClassLoader().getResource("asset/FFSSAF-bord-blanc-fond-transparent.png")));
+ logo.scaleToFit(120, 120);
+ PdfPCell logoCell = new PdfPCell(logo);
+ logoCell.setHorizontalAlignment(Element.ALIGN_CENTER);
+ logoCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
+ logoCell.setPadding(0);
+ logoCell.setRowspan(1);
+ logoCell.setBorder(PdfPCell.NO_BORDER);
+ mainTable.addCell(logoCell);
+
+ // Adding header
+ PdfPCell headerCell = new PdfPCell(new Phrase("FEDERATION FRANCE\nSOFT ARMORED FIGHTING", headerFont));
+ headerCell.setHorizontalAlignment(Element.ALIGN_CENTER);
+ headerCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
+ headerCell.setBorder(PdfPCell.NO_BORDER);
+ mainTable.addCell(headerCell);
+
+ document.add(mainTable);
+
+ Paragraph addr = new Paragraph("5 place de la Barreyre\n63320 Champeix", subHeaderFont);
+ addr.setAlignment(Element.ALIGN_CENTER);
+ addr.setSpacingAfter(2f);
+ document.add(addr);
+
+ Paragraph association = new Paragraph("Association loi 1901 W633001595\nSIRET 829 458 355 00015", smallFont);
+ association.setAlignment(Element.ALIGN_CENTER);
+ document.add(association);
+
+ // Adding spacing
+ document.add(new Paragraph("\n\n"));
+
+ // Adding attestation
+ PdfPTable attestationTable = new PdfPTable(1);
+ attestationTable.setWidthPercentage(60);
+ PdfPCell attestationCell = new PdfPCell(
+ new Phrase("ATTESTATION D'ADHESION\nSaison " + Utils.getSaison() + "-" + (Utils.getSaison() + 1),
+ bigFont));
+ attestationCell.setHorizontalAlignment(Element.ALIGN_CENTER);
+ attestationCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
+ attestationCell.setPadding(20f);
+ attestationTable.addCell(attestationCell);
+ document.add(attestationTable);
+
+ // Adding spacing
+ document.add(new Paragraph("\n\n"));
+
+ // Adding member details table
+ PdfPTable memberTable = new PdfPTable(2);
+ memberTable.setWidthPercentage(100);
+ memberTable.setWidths(new float[]{130, 300});
+ memberTable.getDefaultCell().setBorder(PdfPCell.NO_BORDER);
+
+ // Adding member photo
+ Image memberPhoto;
+ FilenameFilter filter = (directory, filename) -> filename.startsWith(m.getId() + ".");
+ File[] files = new File(media, "ppMembre").listFiles(filter);
+ if (files != null && files.length > 0) {
+ File file = files[0];
+ memberPhoto = Image.getInstance(Files.readAllBytes(file.toPath()));
+ } else {
+ memberPhoto = Image.getInstance(
+ Objects.requireNonNull(getClass().getClassLoader().getResource("asset/blank-profile-picture.png")));
+ }
+ memberPhoto.scaleToFit(120, 150);
+ PdfPCell photoCell = new PdfPCell(memberPhoto);
+ photoCell.setHorizontalAlignment(Element.ALIGN_CENTER);
+ photoCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
+ photoCell.setRowspan(5);
+ photoCell.setBorder(PdfPCell.NO_BORDER);
+ memberTable.addCell(photoCell);
+
+ // Adding member details
+ memberTable.addCell(new Phrase("NOM : " + m.getLname().toUpperCase(), bodyFont));
+ memberTable.addCell(new Phrase("Prénom : " + m.getFname(), bodyFont));
+ memberTable.addCell(new Phrase("Licence n° : " + m.getLicence(), bodyFont));
+ memberTable.addCell(new Phrase("Certificat médical par Dr " + licence.getCertificate(), bodyFont));
+ memberTable.addCell(new Phrase("")); // Empty cell for spacing
+
+ document.add(memberTable);
+
+ // Adding spacing
+ document.add(new Paragraph("\n"));
+
+ Paragraph memberClub = new Paragraph("CLUB : " + m.getClub().getName().toUpperCase(), bodyFont);
+ document.add(memberClub);
+
+ Paragraph memberClubNumber = new Paragraph("N° club : " + m.getClub().getNo_affiliation(), bodyFont);
+ document.add(memberClubNumber);
+
+ // Adding spacing
+ document.add(new Paragraph("\n"));
+
+ Paragraph memberBirthdate = new Paragraph(
+ "Date de naissance : " + ((m.getBirth_date() == null) ? "--" : sdf.format(m.getBirth_date())),
+ bodyFont);
+ document.add(memberBirthdate);
+
+ Paragraph memberGender = new Paragraph("Sexe : " + m.getGenre().str, bodyFont);
+ document.add(memberGender);
+
+ Paragraph memberAgeCategory = new Paragraph("Catégorie d'âge : " + m.getCategorie().getName(), bodyFont);
+ document.add(memberAgeCategory);
+
+ // Adding spacing
+ document.add(new Paragraph("\n\n"));
+
+ // Adding attestation text
+ PdfPTable textTable = new PdfPTable(1);
+ textTable.setWidthPercentage(100);
+ PdfPCell textCell = new PdfPCell(new Phrase(
+ """
+ Ce document atteste que l’adhérent
+ - est valablement enregistré auprès de la FFSAF,
+ - est assuré dans sa pratique du Béhourd Léger et du Battle Arc en entraînement et en compétition.
+
+ Il peut donc s’inscrire à tout tournoi organisé sous l’égide de la FFSAF s’il remplit les éventuelles
+ conditions de qualification.
+ Il peut participer à tout entraînement dans un club affilié si celui ci autorise les visiteurs.""",
+ smallFont));
+ textCell.setHorizontalAlignment(Element.ALIGN_LEFT);
+ textCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
+ textCell.setBorder(PdfPCell.NO_BORDER);
+ textTable.addCell(textCell);
+ document.add(textTable);
+
+ // Close the document
+ document.close();
+ }
}
diff --git a/src/main/java/fr/titionfire/ffsaf/net2/packet/RFile.java b/src/main/java/fr/titionfire/ffsaf/net2/packet/RFile.java
deleted file mode 100644
index 2820eb1..0000000
--- a/src/main/java/fr/titionfire/ffsaf/net2/packet/RFile.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package fr.titionfire.ffsaf.net2.packet;
-
-import fr.titionfire.ffsaf.ws.FileSocket;
-import jakarta.enterprise.context.ApplicationScoped;
-import org.jboss.logging.Logger;
-
-import java.util.HashMap;
-import java.util.UUID;
-
-@ApplicationScoped
-public class RFile {
- private static final Logger LOGGER = Logger.getLogger(RFile.class);
-
- final IAction requestSend = (client_Thread, message) -> {
- try {
- switch (message.data().get("type").asText()) {
- case "match":
- String code = UUID.randomUUID() + "-" + UUID.randomUUID();
-
- FileSocket.FileRecv fileRecv = new FileSocket.FileRecv(null, message.data().get("name").asText(), null, null,
- System.currentTimeMillis());
- FileSocket.sessions.put(code, fileRecv);
-
- client_Thread.sendRepTo(code, message);
- break;
- default:
- client_Thread.sendErrTo("", message);
- break;
-
- }
- } catch (Throwable e) {
- LOGGER.error(e.getMessage(), e);
- client_Thread.sendErrTo(e.getMessage(), message);
- }
- };
-
- public static void register(HashMap iMap) {
- RFile rFile = new RFile();
-
- iMap.put("requestSend", rFile.requestSend);
- }
-}
diff --git a/src/main/java/fr/titionfire/ffsaf/net2/packet/RegisterAction.java b/src/main/java/fr/titionfire/ffsaf/net2/packet/RegisterAction.java
index 3078ab9..bc7fe66 100644
--- a/src/main/java/fr/titionfire/ffsaf/net2/packet/RegisterAction.java
+++ b/src/main/java/fr/titionfire/ffsaf/net2/packet/RegisterAction.java
@@ -9,6 +9,5 @@ public class RegisterAction {
RComb.register(iMap);
RClub.register(iMap);
- RFile.register(iMap);
}
}
diff --git a/src/main/java/fr/titionfire/ffsaf/rest/MembreEndpoints.java b/src/main/java/fr/titionfire/ffsaf/rest/MembreEndpoints.java
index c281ea1..46ef260 100644
--- a/src/main/java/fr/titionfire/ffsaf/rest/MembreEndpoints.java
+++ b/src/main/java/fr/titionfire/ffsaf/rest/MembreEndpoints.java
@@ -85,12 +85,29 @@ public class MembreEndpoints {
"membre connecté, y compris le club et les licences")
@APIResponses(value = {
@APIResponse(responseCode = "200", description = "Les informations du membre connecté"),
+ @APIResponse(responseCode = "403", description = "Accès refusé"),
@APIResponse(responseCode = "500", description = "Erreur interne du serveur")
})
public Uni getMe() {
return membreService.getMembre(securityCtx.getSubject());
}
+ @GET
+ @Path("me/licence")
+ @Authenticated
+ @Produces(MediaType.APPLICATION_JSON)
+ @Operation(summary = "Renvoie l'attestation d'adhesion du membre connecté", description = "Renvoie l'attestation d'adhesion du " +
+ "membre connecté, y compris le club et les licences")
+ @APIResponses(value = {
+ @APIResponse(responseCode = "200", description = "L'attestation d'adhesion"),
+ @APIResponse(responseCode = "403", description = "Accès refusé"),
+ @APIResponse(responseCode = "404", description = "Le membre n'a pas de licence active"),
+ @APIResponse(responseCode = "500", description = "Erreur interne du serveur")
+ })
+ public Uni getMeLicence() {
+ return membreService.getLicencePdf(securityCtx.getSubject());
+ }
+
@GET
@Path("{id}/photo")
@RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
@@ -104,4 +121,18 @@ public class MembreEndpoints {
public Uni getPhoto(@PathParam("id") long id) throws URISyntaxException {
return Utils.getMediaFile(id, media, "ppMembre", membreService.getById(id).onItem().invoke(checkPerm));
}
+
+ @GET
+ @Path("{id}/licence")
+ @RolesAllowed({"federation_admin", "club_president", "club_secretaire", "club_respo_intra"})
+ @Operation(summary = "Renvoie le pdf de la licence d'un membre", description = "Renvoie le pdf de la licence d'un membre en fonction de son identifiant")
+ @APIResponses(value = {
+ @APIResponse(responseCode = "200", description = "Le pdf de la licence"),
+ @APIResponse(responseCode = "403", description = "Accès refusé"),
+ @APIResponse(responseCode = "404", description = "Le membre n'existe pas ou n'a pas de licence active"),
+ @APIResponse(responseCode = "500", description = "Erreur interne du serveur")
+ })
+ public Uni getLicencePDF(@PathParam("id") long id) {
+ return membreService.getLicencePdf(membreService.getByIdWithLicence(id).onItem().invoke(checkPerm));
+ }
}
diff --git a/src/main/java/fr/titionfire/ffsaf/utils/Utils.java b/src/main/java/fr/titionfire/ffsaf/utils/Utils.java
index 360e492..f93aa36 100644
--- a/src/main/java/fr/titionfire/ffsaf/utils/Utils.java
+++ b/src/main/java/fr/titionfire/ffsaf/utils/Utils.java
@@ -12,7 +12,6 @@ import net.sf.jmimemagic.MagicParseException;
import org.jboss.logging.Logger;
import java.io.*;
-import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLConnection;
import java.nio.file.Files;
@@ -95,7 +94,7 @@ public class Utils {
if (!dirFile.mkdirs())
throw new IOException("Fail to create directory " + dir);
- FilenameFilter filter = (directory, filename) -> filename.startsWith(id +".");
+ FilenameFilter filter = (directory, filename) -> filename.startsWith(id + ".");
File[] files = dirFile.listFiles(filter);
if (files != null) {
for (File file : files) {
@@ -134,22 +133,45 @@ public class Utils {
return null;
});
- URI uri = new URI("https://mdbcdn.b-cdn.net/img/Photos/new-templates/bootstrap-chat/ava2.webp");
+ Future future2 = CompletableFuture.supplyAsync(() -> {
+ try (InputStream st = Utils.class.getClassLoader().getResourceAsStream("asset/blank-profile-picture.png")) {
+ if (st == null)
+ return null;
+ return st.readAllBytes();
+ } catch (IOException ignored) {
+ }
+ return null;
+ });
return uniBase.chain(__ -> Uni.createFrom().future(future)
- .map(filePair -> {
- if (filePair == null)
- return Response.temporaryRedirect(uri).build();
+ .chain(filePair -> {
+ if (filePair == null) {
+ return Uni.createFrom().future(future2).map(data -> {
+ if (data == null)
+ return Response.noContent().build();
- String mimeType = URLConnection.guessContentTypeFromName(filePair.getKey().getName());
+ String mimeType = "image/apng";
+ Response.ResponseBuilder resp = Response.ok(data);
+ resp.type(MediaType.APPLICATION_OCTET_STREAM);
+ resp.header(HttpHeaders.CONTENT_LENGTH, data.length);
+ resp.header(HttpHeaders.CONTENT_TYPE, mimeType);
+ resp.header(HttpHeaders.CONTENT_DISPOSITION,
+ "inline; " + ((out_filename == null) ? "" : "filename=\"" + out_filename + "\""));
+ return resp.build();
+ });
+ } else {
+ return Uni.createFrom().item(() -> {
+ String mimeType = URLConnection.guessContentTypeFromName(filePair.getKey().getName());
- Response.ResponseBuilder resp = Response.ok(filePair.getValue());
- resp.type(MediaType.APPLICATION_OCTET_STREAM);
- resp.header(HttpHeaders.CONTENT_LENGTH, filePair.getValue().length);
- resp.header(HttpHeaders.CONTENT_TYPE, mimeType);
- resp.header(HttpHeaders.CONTENT_DISPOSITION,
- "inline; " + ((out_filename == null) ? "" : "filename=\"" + out_filename + "\""));
- return resp.build();
+ Response.ResponseBuilder resp = Response.ok(filePair.getValue());
+ resp.type(MediaType.APPLICATION_OCTET_STREAM);
+ resp.header(HttpHeaders.CONTENT_LENGTH, filePair.getValue().length);
+ resp.header(HttpHeaders.CONTENT_TYPE, mimeType);
+ resp.header(HttpHeaders.CONTENT_DISPOSITION,
+ "inline; " + ((out_filename == null) ? "" : "filename=\"" + out_filename + "\""));
+ return resp.build();
+ });
+ }
}));
}
diff --git a/src/main/java/fr/titionfire/ffsaf/ws/FileSocket.java b/src/main/java/fr/titionfire/ffsaf/ws/FileSocket.java
deleted file mode 100644
index 283a09b..0000000
--- a/src/main/java/fr/titionfire/ffsaf/ws/FileSocket.java
+++ /dev/null
@@ -1,165 +0,0 @@
-package fr.titionfire.ffsaf.ws;
-
-import io.quarkus.runtime.annotations.RegisterForReflection;
-import jakarta.enterprise.context.ApplicationScoped;
-import jakarta.websocket.*;
-import jakarta.websocket.server.PathParam;
-import jakarta.websocket.server.ServerEndpoint;
-import lombok.AllArgsConstructor;
-import org.eclipse.microprofile.config.inject.ConfigProperty;
-import org.jboss.logging.Logger;
-
-import java.io.*;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-@ServerEndpoint("/api/ws/file/{code}")
-@ApplicationScoped
-public class FileSocket {
- private static final Logger logger = Logger.getLogger(FileSocket.class);
- public static Map sessions = new ConcurrentHashMap<>();
-
- @ConfigProperty(name = "upload_dir")
- String media;
-
- /*@Scheduled(every = "10s")
- void increment() {
- sessions.forEach((key, value) -> {
- if (System.currentTimeMillis() - value.time > 60000) {
- closeAndDelete(value);
- if (value.session != null && value.session.isOpen()) {
- try {
- value.session.close(new CloseReason(CloseReason.CloseCodes.VIOLATED_POLICY, "Timeout"));
- } catch (IOException e) {
- StringWriter errors = new StringWriter();
- e.printStackTrace(new PrintWriter(errors));
- logger.error(errors.toString());
- }
- }
- sessions.remove(key);
- }
- });
- }*/
-
- @OnOpen
- public void onOpen(Session session, @PathParam("code") String code) {
- try {
- if (sessions.containsKey(code)) {
- FileRecv fileRecv = sessions.get(code);
- fileRecv.session = session;
- fileRecv.file = new File(media + "-ext", "record/" + fileRecv.name);
- fileRecv.fos = new FileOutputStream(fileRecv.file, false);
- logger.info("Start reception of file: " + fileRecv.file.getAbsolutePath());
- } else {
- session.close(new CloseReason(CloseReason.CloseCodes.VIOLATED_POLICY, "File not found"));
- }
- } catch (IOException e) {
- StringWriter errors = new StringWriter();
- e.printStackTrace(new PrintWriter(errors));
- logger.error(errors.toString());
- }
- }
-
- @OnClose
- public void onClose(Session session, @PathParam("code") String code) {
- if (sessions.containsKey(code)) {
- FileRecv fileRecv = sessions.get(code);
- if (fileRecv.fos != null) {
- try {
- fileRecv.fos.close();
- } catch (IOException e) {
- StringWriter errors = new StringWriter();
- e.printStackTrace(new PrintWriter(errors));
- logger.error(errors.toString());
- }
- }
- logger.info("File received: " + fileRecv.file.getAbsolutePath());
- sessions.remove(code);
- }
- }
-
- @OnError
- public void onError(Session session, @PathParam("code") String code, Throwable throwable) {
- if (sessions.containsKey(code)) {
- closeAndDelete(sessions.get(code));
- sessions.remove(code);
- }
- logger.error("Error on file reception: " + throwable.getMessage());
- }
-
-
- @OnMessage
- public void onMessage(String message, @PathParam("code") String code) {
- if (message.equals("cancel")) {
- if (sessions.containsKey(code)) {
- closeAndDelete(sessions.get(code));
- sessions.remove(code);
- }
- logger.error("Error file " + code + " are cancel by the client");
- }
- }
-
- private void closeAndDelete(FileRecv fileRecv) {
- if (fileRecv.fos != null) {
- try {
- fileRecv.fos.close();
- } catch (IOException e) {
- StringWriter errors = new StringWriter();
- e.printStackTrace(new PrintWriter(errors));
- logger.error(errors.toString());
- }
- }
- if (fileRecv.file.exists()) {
- //noinspection ResultOfMethodCallIgnored
- fileRecv.file.delete();
- }
- }
-
- @OnMessage
- public void onMessage(byte[] data, @PathParam("code") String code) {
- int length = (data[1] << 7) | data[2];
-
- byte check_sum = 0;
- for (int j = 3; j < length + 3; j++) {
- check_sum = (byte) (check_sum ^ data[j]);
- }
- // System.out.println(length + " - " + data[1] + " - " + data[0] + " - " + check_sum);
-
- if (sessions.containsKey(code)) {
- FileRecv fileRecv = sessions.get(code);
-
- if (check_sum != data[0]) {
- fileRecv.session.getAsyncRemote().sendText("Error: Checksum error", result -> {
- if (result.getException() != null) {
- logger.error("Unable to send message: " + result.getException());
- }
- });
- return;
- }
-
- try {
- fileRecv.fos.write(data, 3, length);
- } catch (IOException e) {
- StringWriter errors = new StringWriter();
- e.printStackTrace(new PrintWriter(errors));
- logger.error(errors.toString());
- }
-
- fileRecv.session.getAsyncRemote().sendText("ok", result -> {
- if (result.getException() != null) {
- logger.error("Unable to send message: " + result.getException());
- }
- });
- }
- }
-
- @AllArgsConstructor
- @RegisterForReflection
- public static class FileRecv {
- Session session;
- String name;
- File file;
- FileOutputStream fos;
- long time;
- }
-}
diff --git a/src/main/resources/asset/DMSans-Regular.ttf b/src/main/resources/asset/DMSans-Regular.ttf
new file mode 100644
index 0000000..07266ae
Binary files /dev/null and b/src/main/resources/asset/DMSans-Regular.ttf differ
diff --git a/src/main/resources/asset/FFSSAF-bord-blanc-fond-transparent.png b/src/main/resources/asset/FFSSAF-bord-blanc-fond-transparent.png
new file mode 100644
index 0000000..e4d6e6d
Binary files /dev/null and b/src/main/resources/asset/FFSSAF-bord-blanc-fond-transparent.png differ
diff --git a/src/main/resources/asset/blank-profile-picture.png b/src/main/resources/asset/blank-profile-picture.png
new file mode 100644
index 0000000..9e34293
Binary files /dev/null and b/src/main/resources/asset/blank-profile-picture.png differ
diff --git a/src/main/webapp/public/blank-profile-picture.png b/src/main/webapp/public/blank-profile-picture.png
new file mode 100644
index 0000000..9e34293
Binary files /dev/null and b/src/main/webapp/public/blank-profile-picture.png differ
diff --git a/src/main/webapp/src/pages/MePage.jsx b/src/main/webapp/src/pages/MePage.jsx
index edaa3fa..3ae80a2 100644
--- a/src/main/webapp/src/pages/MePage.jsx
+++ b/src/main/webapp/src/pages/MePage.jsx
@@ -4,7 +4,7 @@ import {useFetch} from "../hooks/useFetch.js";
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
import {
faCalendarDay,
- faEnvelope, faFlag,
+ faEnvelope, faFilePdf, faFlag,
faInfoCircle,
faMars,
faMarsAndVenus,
@@ -77,6 +77,13 @@ function PhotoCard({data}) {
alt="avatar"
className="rounded-circle img-fluid" style={{object_fit: 'contain'}}/>
+
+
+
+
;
}
diff --git a/src/main/webapp/src/pages/admin/member/MemberPage.jsx b/src/main/webapp/src/pages/admin/member/MemberPage.jsx
index dc02918..7cf7cad 100644
--- a/src/main/webapp/src/pages/admin/member/MemberPage.jsx
+++ b/src/main/webapp/src/pages/admin/member/MemberPage.jsx
@@ -9,6 +9,8 @@ import {LicenceCard} from "./LicenceCard.jsx";
import {toast} from "react-toastify";
import {apiAxios, errFormater} from "../../../utils/Tools.js";
import {ConfirmDialog} from "../../../components/ConfirmDialog.jsx";
+import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
+import {faFilePdf} from "@fortawesome/free-solid-svg-icons";
const vite_url = import.meta.env.VITE_URL;
@@ -83,6 +85,12 @@ function PhotoCard({data}) {
alt="avatar"
className="rounded-circle img-fluid" style={{object_fit: 'contain'}}/>
+
+
+
;
}
diff --git a/src/main/webapp/src/pages/club/member/MemberPage.jsx b/src/main/webapp/src/pages/club/member/MemberPage.jsx
index 1d44a65..66a9709 100644
--- a/src/main/webapp/src/pages/club/member/MemberPage.jsx
+++ b/src/main/webapp/src/pages/club/member/MemberPage.jsx
@@ -8,6 +8,8 @@ import {LicenceCard} from "./LicenceCard.jsx";
import {ConfirmDialog} from "../../../components/ConfirmDialog.jsx";
import {apiAxios, errFormater} from "../../../utils/Tools.js";
import {toast} from "react-toastify";
+import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
+import {faFilePdf} from "@fortawesome/free-solid-svg-icons";
const vite_url = import.meta.env.VITE_URL;
@@ -81,6 +83,12 @@ function PhotoCard({data}) {
alt="avatar"
className="rounded-circle img-fluid" style={{object_fit: 'contain'}}/>
+
+
+
;
}