feat: pdf generation
This commit is contained in:
parent
6b38405e94
commit
aac126cb87
6
pom.xml
6
pom.xml
@ -129,6 +129,12 @@
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-cache</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.librepdf</groupId>
|
||||
<artifactId>openpdf</artifactId>
|
||||
<version>2.0.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
|
||||
@ -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<MembreModel> getByIdWithLicence(long id) {
|
||||
return repository.findById(id)
|
||||
.call(m -> Mutiny.fetch(m.getLicences()));
|
||||
}
|
||||
|
||||
public Uni<MembreModel> getByLicence(long licence) {
|
||||
return repository.find("licence = ?1", licence).firstResult();
|
||||
}
|
||||
@ -276,4 +295,204 @@ public class MembreService {
|
||||
.invoke(meData::setLicences)
|
||||
.map(__ -> meData);
|
||||
}
|
||||
|
||||
public Uni<Response> getLicencePdf(String subject) {
|
||||
return getLicencePdf(repository.find("userId = ?1", subject).firstResult()
|
||||
.call(m -> Mutiny.fetch(m.getLicences())));
|
||||
}
|
||||
|
||||
public Uni<Response> getLicencePdf(Uni<MembreModel> 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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<String, IAction> iMap) {
|
||||
RFile rFile = new RFile();
|
||||
|
||||
iMap.put("requestSend", rFile.requestSend);
|
||||
}
|
||||
}
|
||||
@ -9,6 +9,5 @@ public class RegisterAction {
|
||||
|
||||
RComb.register(iMap);
|
||||
RClub.register(iMap);
|
||||
RFile.register(iMap);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<MeData> 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<Response> 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<Response> 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<Response> getLicencePDF(@PathParam("id") long id) {
|
||||
return membreService.getLicencePdf(membreService.getByIdWithLicence(id).onItem().invoke(checkPerm));
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<byte[]> 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();
|
||||
});
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@ -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<String, FileRecv> 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;
|
||||
}
|
||||
}
|
||||
BIN
src/main/resources/asset/DMSans-Regular.ttf
Normal file
BIN
src/main/resources/asset/DMSans-Regular.ttf
Normal file
Binary file not shown.
BIN
src/main/resources/asset/FFSSAF-bord-blanc-fond-transparent.png
Normal file
BIN
src/main/resources/asset/FFSSAF-bord-blanc-fond-transparent.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
BIN
src/main/resources/asset/blank-profile-picture.png
Normal file
BIN
src/main/resources/asset/blank-profile-picture.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
BIN
src/main/webapp/public/blank-profile-picture.png
Normal file
BIN
src/main/webapp/public/blank-profile-picture.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
@ -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'}}/>
|
||||
</div>
|
||||
|
||||
<a href={`${vite_url}/api/member/me/licence`} target='#'>
|
||||
<button className="btn btn-primary" type="button" id="button-addon1"
|
||||
onClick={e => null}>
|
||||
Téléchargée la licence <FontAwesomeIcon icon={faFilePdf}></FontAwesomeIcon>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@ -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'}}/>
|
||||
</div>
|
||||
<a href={`${vite_url}/api/member/${data.id}/licence`} target='#'>
|
||||
<button className="btn btn-primary" type="button" id="button-addon1"
|
||||
onClick={e => null}>
|
||||
Téléchargée la licence <FontAwesomeIcon icon={faFilePdf}></FontAwesomeIcon>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
@ -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'}}/>
|
||||
</div>
|
||||
<a href={`${vite_url}/api/member/${data.id}/licence`} target='#'>
|
||||
<button className="btn btn-primary" type="button" id="button-addon1"
|
||||
onClick={e => null}>
|
||||
Téléchargée la licence <FontAwesomeIcon icon={faFilePdf}></FontAwesomeIcon>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user