From 4c83b80b6da0f5e2f69360c16f34dea2a3821a4b Mon Sep 17 00:00:00 2001 From: Thibaut Valentin Date: Thu, 6 Feb 2025 11:11:10 +0100 Subject: [PATCH] fix(build): create sub-app make_pdf --- .gitea/workflows/deploy_in_prod.yml | 8 +- pom.xml | 7 +- src/main/docker/Dockerfile.native | 5 +- .../ffsaf/domain/service/MembreService.java | 244 +++++------------- src/main/pdf_gen/.gitignore | 38 +++ src/main/pdf_gen/pom.xml | 51 ++++ .../src/main/java/fr/titionfire/Main.java | 223 ++++++++++++++++ .../src/main/java/fr/titionfire/PdfData.java | 19 ++ .../src/main/resources}/DMSans-Regular.ttf | Bin .../FFSSAF-bord-blanc-fond-transparent.png | Bin .../main/resources/blank-profile-picture.png | Bin 0 -> 37098 bytes .../com/lowagie/reflect-config.json | 9 - .../fr/titionfire/reflect-config.json | 44 ---- src/main/resources/application.properties | 2 + .../src/pages/admin/member/LicenceCard.jsx | 1 + 15 files changed, 415 insertions(+), 236 deletions(-) create mode 100644 src/main/pdf_gen/.gitignore create mode 100644 src/main/pdf_gen/pom.xml create mode 100644 src/main/pdf_gen/src/main/java/fr/titionfire/Main.java create mode 100644 src/main/pdf_gen/src/main/java/fr/titionfire/PdfData.java rename src/main/{resources/asset => pdf_gen/src/main/resources}/DMSans-Regular.ttf (100%) rename src/main/{resources/asset => pdf_gen/src/main/resources}/FFSSAF-bord-blanc-fond-transparent.png (100%) create mode 100644 src/main/pdf_gen/src/main/resources/blank-profile-picture.png delete mode 100644 src/main/resources/META-INF/native-image/com/lowagie/reflect-config.json delete mode 100644 src/main/resources/META-INF/native-image/fr/titionfire/reflect-config.json diff --git a/.gitea/workflows/deploy_in_prod.yml b/.gitea/workflows/deploy_in_prod.yml index 9e706ea..1c31f63 100644 --- a/.gitea/workflows/deploy_in_prod.yml +++ b/.gitea/workflows/deploy_in_prod.yml @@ -45,6 +45,12 @@ jobs: mkdir -p src/main/resources/META-INF/ mv src/main/webapp/dist src/main/resources/META-INF/resources + - name: Build backend make_pdf tool + run: | + cd src/main/pdf_gen + mvn clean compile assembly:single + cd ../../.. + - name: Build backend run: | chmod 740 mvnw @@ -57,7 +63,7 @@ jobs: username: ${{ secrets.SSH_USER }} port: ${{ secrets.SSH_PORT }} key: ${{ secrets.SSH_KEY }} - source: "target/*-runner,src/main/resources/cacerts,src/main/docker/Dockerfile.native,docker-compose.yml,.dockerignore" + source: "target/*-runner,src/main/resources/cacerts,src/main/docker/Dockerfile.native,docker-compose.yml,.dockerignore,src/main/pdf_gen/target/pdf_gen-*.jar" target: ${{ secrets.TARGET_DIR }} # Need to create it first on the VPS - name: Re-start ffsaf container diff --git a/pom.xml b/pom.xml index ed769d2..22a16d3 100644 --- a/pom.xml +++ b/pom.xml @@ -75,11 +75,6 @@ 2.0.4 - - io.quarkiverse.openpdf - quarkus-openpdf - 3.1.2 - io.quarkus quarkus-junit5 @@ -211,7 +206,7 @@ false - --initialize-at-run-time=com.fasterxml.jackson.databind.ext.DOMDeserializer\,com.lowagie + --initialize-at-run-time=com.fasterxml.jackson.databind.ext.DOMDeserializer true false diff --git a/src/main/docker/Dockerfile.native b/src/main/docker/Dockerfile.native index 06f4983..aae442e 100644 --- a/src/main/docker/Dockerfile.native +++ b/src/main/docker/Dockerfile.native @@ -14,13 +14,16 @@ # docker run -i --rm -p 8080:8080 quarkus/ffsaf-site # ### -FROM registry.access.redhat.com/ubi8/ubi-minimal:8.9 +# replace FROM registry.access.redhat.com/ubi8/ubi-minimal:8.9 for jvm need sub application (ie. make_pdf) +FROM registry.access.redhat.com/ubi8/openjdk-17:1.18 + WORKDIR /work/ RUN chown 1001 /work \ && chmod "g+rwX" /work \ && chown 1001:root /work COPY --chown=1001:root target/*-runner /work/application COPY --chown=1001:root src/main/resources/cacerts /work/cacerts +COPY --chown=1001:root src/main/pdf_gen/target/pdf_gen-*.jar /work/make_pdf.jar RUN mkdir /work/media && chown -R 1001:root /work/media EXPOSE 8080 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 af3415d..7d8e1a9 100644 --- a/src/main/java/fr/titionfire/ffsaf/domain/service/MembreService.java +++ b/src/main/java/fr/titionfire/ffsaf/domain/service/MembreService.java @@ -1,10 +1,5 @@ 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; @@ -38,18 +33,20 @@ 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 org.jboss.logging.Logger; import java.io.*; -import java.nio.file.Files; -import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.List; -import java.util.Objects; +import java.util.UUID; +import java.util.concurrent.TimeUnit; @WithSession @ApplicationScoped public class MembreService { + private static final Logger LOGGER = Logger.getLogger(MembreService.class); @Inject CombRepository repository; @@ -66,6 +63,9 @@ public class MembreService { @ConfigProperty(name = "upload_dir") String media; + @ConfigProperty(name = "pdf-maker.jar-path") + String pdfMakerJarPath; + public SimpleCombModel find(int licence, String np) throws Throwable { return VertxContextSupport.subscribeAndAwait(() -> Panache.withTransaction(() -> repository.find("licence = ?1 AND (lname ILIKE ?2 OR fname ILIKE ?2)", @@ -315,11 +315,11 @@ public class MembreService { .findFirst() .orElseThrow(() -> new DNotFoundException("Pas de licence pour la saison en cours")); - ByteArrayOutputStream out = new ByteArrayOutputStream(); try { - make_pdf(m, out, licence); + byte[] buff = make_pdf(m, licence); + if (buff == null) + throw new IOException("Error making pdf"); - byte[] buff = out.toByteArray(); String mimeType = "application/pdf"; Response.ResponseBuilder resp = Response.ok(buff); @@ -336,185 +336,79 @@ public class MembreService { })); } - 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(); + private byte[] make_pdf(MembreModel m, LicenceModel licence) throws IOException, InterruptedException { + List cmd = new ArrayList<>(); + cmd.add("java"); + cmd.add("-jar"); + cmd.add(pdfMakerJarPath); - 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"); + UUID uuid = UUID.randomUUID(); - 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()); + cmd.add("/tmp/" + uuid + ".pdf"); + cmd.add(m.getFname()); + cmd.add(m.getLname()); + cmd.add(m.getGenre().str); + cmd.add(m.getCategorie().getName()); + cmd.add(licence.getCertificate() == null ? "" : licence.getCertificate()); + cmd.add(Utils.getSaison() + ""); + cmd.add(m.getLicence() + ""); + cmd.add(m.getClub().getName()); + cmd.add(m.getClub().getNo_affiliation() + ""); + cmd.add(m.getBirth_date() == null ? "--" : new SimpleDateFormat("dd/MM/yyyy").format(m.getBirth_date())); - // 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())); + cmd.add(file.getAbsolutePath()); } else { - memberPhoto = Image.getInstance( - Objects.requireNonNull(getClass().getClassLoader().getResource("asset/blank-profile-picture.png"))); + cmd.add("/dev/null"); } - 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); - String[] cert; - if (licence.getCertificate() != null && !licence.getCertificate().isBlank()) { - cert = licence.getCertificate().split("¤"); - if (cert.length <= 1){ - cert = new String[]{licence.getCertificate(), "--"}; - }else{ - try { - cert[1] = sdf.format(new SimpleDateFormat("yyyy-MM-dd").parse(cert[1])); - } catch (ParseException e) { - cert[1] = "--"; - } + ProcessBuilder processBuilder = new ProcessBuilder(cmd); + processBuilder.redirectErrorStream(true); + Process process = processBuilder.start(); + + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + + StringBuilder builder = new StringBuilder(); + Thread t = new Thread(() -> { + try { + String line; + while ((line = reader.readLine()) != null) + builder.append(line).append("\n"); + } catch (Exception ignored) { } + }); + t.start(); + + int code = -1; + if (!process.waitFor(30, TimeUnit.SECONDS)) { + process.destroy(); + builder.append("Timeout..."); } else { - cert = new String[]{"--", "--"}; + code = process.exitValue(); } - // 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 " + cert[0] + ", le " + cert[1], bodyFont)); - memberTable.addCell(new Phrase("")); // Empty cell for spacing + if (t.isAlive()) + t.interrupt(); - document.add(memberTable); + LOGGER.debug("PDF maker: " + builder); - // 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(); + if (code != 0) { + throw new IOException("Error code: " + code); + } else { + File file = new File("/tmp/" + uuid + ".pdf"); + try (FileInputStream fis = new FileInputStream(file)) { + byte[] buff = fis.readAllBytes(); + //noinspection ResultOfMethodCallIgnored + file.delete(); + return buff; + } catch (IOException e) { + //noinspection ResultOfMethodCallIgnored + file.delete(); + } + return null; + } } } diff --git a/src/main/pdf_gen/.gitignore b/src/main/pdf_gen/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/src/main/pdf_gen/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/src/main/pdf_gen/pom.xml b/src/main/pdf_gen/pom.xml new file mode 100644 index 0000000..7e4c3bf --- /dev/null +++ b/src/main/pdf_gen/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + fr.titionfire + pdf_gen + 1.0-SNAPSHOT + + + 17 + 17 + UTF-8 + + + + + com.github.librepdf + openpdf + 2.0.3 + + + + + + + maven-assembly-plugin + + + + fr.titionfire.Main + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + + \ No newline at end of file diff --git a/src/main/pdf_gen/src/main/java/fr/titionfire/Main.java b/src/main/pdf_gen/src/main/java/fr/titionfire/Main.java new file mode 100644 index 0000000..e6ba272 --- /dev/null +++ b/src/main/pdf_gen/src/main/java/fr/titionfire/Main.java @@ -0,0 +1,223 @@ +package fr.titionfire; + +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 java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Objects; + +public class Main { + public static void main(String[] args) { + PdfData pdfData = new PdfData(); + + File dest = new File(args[0]); + pdfData.fname = args[1]; + pdfData.lname = args[2]; + pdfData.genre = args[3]; + pdfData.categorie = args[4]; + pdfData.certificate = args[5]; + pdfData.saison = Integer.parseInt(args[6]); + pdfData.licence = Integer.parseInt(args[7]); + pdfData.club = args[8]; + pdfData.club_no = Integer.parseInt(args[9]); + pdfData.birth_date = args[10]; + pdfData.photo_file = new File(args[11]); + + try { + FileOutputStream out = new FileOutputStream(dest); + new Main().make_pdf(pdfData, out); + } catch (IOException ignored) { + ignored.printStackTrace(); + System.exit(1); + } + + System.out.println("PDF generated successfully"); + System.exit(0); + } + + private void make_pdf(PdfData pdfData, FileOutputStream out) 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 " + pdfData.saison + "-" + (pdfData.saison + 1) + " de " + pdfData.lname + " " + pdfData.fname); + document.addCreationDate(); + document.addProducer("https://www.ffsaf.fr"); + + InputStream fontStream = Main.class.getClassLoader().getResourceAsStream("DMSans-Regular.ttf"); + if (fontStream == null) { + throw new IOException("Font file not found"); + } + BaseFont customFont = BaseFont.createFont("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("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 " + pdfData.saison + "-" + (pdfData.saison + 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; + if (pdfData.photo_file != null && pdfData.photo_file.exists()) { + memberPhoto = Image.getInstance(Files.readAllBytes(pdfData.photo_file.toPath())); + } else { + memberPhoto = Image.getInstance( + Objects.requireNonNull(getClass().getClassLoader().getResource("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); + + String[] cert; + if (pdfData.certificate != null && !pdfData.certificate.isBlank()) { + cert = pdfData.certificate.split("¤"); + if (cert.length <= 1) { + cert = new String[]{pdfData.certificate, "--"}; + } else { + try { + cert[1] = sdf.format(new SimpleDateFormat("yyyy-MM-dd").parse(cert[1])); + } catch (ParseException e) { + cert[1] = "--"; + } + } + } else { + cert = new String[]{"--", "--"}; + } + + // Adding member details + memberTable.addCell(new Phrase("NOM : " + pdfData.lname.toUpperCase(), bodyFont)); + memberTable.addCell(new Phrase("Prénom : " + pdfData.fname, bodyFont)); + memberTable.addCell(new Phrase("Licence n° : " + pdfData.licence, bodyFont)); + memberTable.addCell(new Phrase("Certificat médical par " + cert[0] + ", le " + cert[1], bodyFont)); + memberTable.addCell(new Phrase("")); // Empty cell for spacing + + document.add(memberTable); + + // Adding spacing + document.add(new Paragraph("\n")); + + Paragraph memberClub = new Paragraph("CLUB : " + pdfData.club.toUpperCase(), bodyFont); + document.add(memberClub); + + Paragraph memberClubNumber = new Paragraph("N° club : " + pdfData.club_no, bodyFont); + document.add(memberClubNumber); + + // Adding spacing + document.add(new Paragraph("\n")); + + Paragraph memberBirthdate = new Paragraph("Date de naissance : " + pdfData.birth_date, bodyFont); + document.add(memberBirthdate); + + Paragraph memberGender = new Paragraph("Sexe : " + pdfData.genre, bodyFont); + document.add(memberGender); + + Paragraph memberAgeCategory = new Paragraph("Catégorie d'âge : " + pdfData.categorie, 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(); + } +} \ No newline at end of file diff --git a/src/main/pdf_gen/src/main/java/fr/titionfire/PdfData.java b/src/main/pdf_gen/src/main/java/fr/titionfire/PdfData.java new file mode 100644 index 0000000..7e0a4f6 --- /dev/null +++ b/src/main/pdf_gen/src/main/java/fr/titionfire/PdfData.java @@ -0,0 +1,19 @@ +package fr.titionfire; + +import java.io.File; +import java.util.Date; + +public class PdfData { + int saison; + int licence; + String fname; + String lname; + String club; + int club_no; + String categorie; + String genre; + String birth_date; + String certificate; + + File photo_file; +} diff --git a/src/main/resources/asset/DMSans-Regular.ttf b/src/main/pdf_gen/src/main/resources/DMSans-Regular.ttf similarity index 100% rename from src/main/resources/asset/DMSans-Regular.ttf rename to src/main/pdf_gen/src/main/resources/DMSans-Regular.ttf diff --git a/src/main/resources/asset/FFSSAF-bord-blanc-fond-transparent.png b/src/main/pdf_gen/src/main/resources/FFSSAF-bord-blanc-fond-transparent.png similarity index 100% rename from src/main/resources/asset/FFSSAF-bord-blanc-fond-transparent.png rename to src/main/pdf_gen/src/main/resources/FFSSAF-bord-blanc-fond-transparent.png diff --git a/src/main/pdf_gen/src/main/resources/blank-profile-picture.png b/src/main/pdf_gen/src/main/resources/blank-profile-picture.png new file mode 100644 index 0000000000000000000000000000000000000000..9e342938b026768edad7fdfbe04b6e551388efd9 GIT binary patch literal 37098 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/META-INF/native-image/com/lowagie/reflect-config.json b/src/main/resources/META-INF/native-image/com/lowagie/reflect-config.json deleted file mode 100644 index 25ed93f..0000000 --- a/src/main/resources/META-INF/native-image/com/lowagie/reflect-config.json +++ /dev/null @@ -1,9 +0,0 @@ -[ - { - "name": "com.lowagie.text.pdf.GrayColor", - "allDeclaredConstructors": true, - "allPublicConstructors": true, - "allDeclaredMethods": true, - "allPublicMethods": true - } -] diff --git a/src/main/resources/META-INF/native-image/fr/titionfire/reflect-config.json b/src/main/resources/META-INF/native-image/fr/titionfire/reflect-config.json deleted file mode 100644 index 6dabb2f..0000000 --- a/src/main/resources/META-INF/native-image/fr/titionfire/reflect-config.json +++ /dev/null @@ -1,44 +0,0 @@ -[ - { - "name": "fr.titionfire.ffsaf", - "allDeclaredConstructors": true, - "allPublicConstructors": true, - "allDeclaredMethods": true, - "allPublicMethods": true - }, - { - "name": "sun.font.Font2D", - "allDeclaredConstructors": true, - "allPublicConstructors": true, - "allDeclaredMethods": true, - "allPublicMethods": true - }, - { - "name": "sun.font.CompositeFont", - "allDeclaredConstructors": true, - "allPublicConstructors": true, - "allDeclaredMethods": true, - "allPublicMethods": true - }, - { - "name": "sun.awt.SunHints", - "allDeclaredConstructors": true, - "allPublicConstructors": true, - "allDeclaredMethods": true, - "allPublicMethods": true - }, - { - "name": "java.awt.RenderingHints", - "allDeclaredConstructors": true, - "allPublicConstructors": true, - "allDeclaredMethods": true, - "allPublicMethods": true - }, - { - "name": "sun.font.FontUtilities", - "allDeclaredConstructors": true, - "allPublicConstructors": true, - "allDeclaredMethods": true, - "allPublicMethods": true - } -] \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index ee898d3..245f2f5 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -14,6 +14,8 @@ quarkus.hibernate-orm.physical-naming-strategy=fr.titionfire.ffsaf.data.SafcaNam quarkus.http.cors=true quarkus.quartz.start-mode=forced +%dev.pdf-maker.jar-path=src\\main\\pdf_gen\\target\\pdf_gen-1.0-SNAPSHOT-jar-with-dependencies.jar +pdf-maker.jar-path=/work/make_pdf.jar %dev.quarkus.log.min-level=ALL %dev.quarkus.log.category."fr.titionfire.ffsaf".level=ALL diff --git a/src/main/webapp/src/pages/admin/member/LicenceCard.jsx b/src/main/webapp/src/pages/admin/member/LicenceCard.jsx index 5c677ed..fde03d3 100644 --- a/src/main/webapp/src/pages/admin/member/LicenceCard.jsx +++ b/src/main/webapp/src/pages/admin/member/LicenceCard.jsx @@ -92,6 +92,7 @@ function sendLicence(event, dispatch) { const formData = new FormData(event.target); formData.set('licence', event.target.licence?.value?.length > 0 ? event.target.licence?.value : null) + formData.set('certificate', `${event.target.certificateBy?.value}¤${event.target.certificateDate?.value}`) toast.promise( apiAxios.post(`/licence/${formData.get('membre')}`, formData),