diff --git a/.gitignore b/.gitignore index 9610294..ab7fed3 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,4 @@ nb-configuration.xml /src/main/resources/META-INF/resources/ /media/ /media-ext/ +/sign.jpg diff --git a/docker-compose.yml b/docker-compose.yml index de813ce..1de12bc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,6 +10,7 @@ services: - ${PWD}/ffsaf.properties:/work/config/application.properties - ${PWD}/ffsaf_cle_prive.jks:/work/cle_prive.jks - ${PWD}/mail-truststore.p12:/work/mail-truststore.p12 + - ${PWD}/sign.jpg:/work/sign.jpg - ${PWD}/ffsaf-media:/work/media depends_on: ffsaf-db: diff --git a/src/main/java/fr/titionfire/ffsaf/domain/service/AffiliationService.java b/src/main/java/fr/titionfire/ffsaf/domain/service/AffiliationService.java index f1d4566..cc7bf88 100644 --- a/src/main/java/fr/titionfire/ffsaf/domain/service/AffiliationService.java +++ b/src/main/java/fr/titionfire/ffsaf/domain/service/AffiliationService.java @@ -20,11 +20,18 @@ 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.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; import java.util.stream.Stream; @WithSession diff --git a/src/main/java/fr/titionfire/ffsaf/domain/service/ClubService.java b/src/main/java/fr/titionfire/ffsaf/domain/service/ClubService.java index 82ff6d9..e67c58c 100644 --- a/src/main/java/fr/titionfire/ffsaf/domain/service/ClubService.java +++ b/src/main/java/fr/titionfire/ffsaf/domain/service/ClubService.java @@ -31,10 +31,16 @@ 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 org.jboss.logging.Logger; +import java.io.*; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import static fr.titionfire.ffsaf.net2.Client_Thread.MAPPER; @@ -42,6 +48,7 @@ import static fr.titionfire.ffsaf.net2.Client_Thread.MAPPER; @WithSession @ApplicationScoped public class ClubService { + private static final Logger LOGGER = Logger.getLogger(ClubService.class); @Inject ClubRepository repository; @@ -61,6 +68,12 @@ public class ClubService { @Inject LoggerService ls; + @ConfigProperty(name = "pdf-maker.jar-path") + String pdfMakerJarPath; + + @ConfigProperty(name = "pdf-maker.sign-file") + String sign_file; + public SimpleClubModel findByIdOptionalClub(long id) throws Throwable { return VertxContextSupport.subscribeAndAwait( () -> Panache.withTransaction(() -> repository.findById(id).map(SimpleClubModel::fromModel))); @@ -333,4 +346,120 @@ public class ClubService { return data; }).collect().asList(); } + + public Uni getAffiliationPdf(String subject) { + return getAffiliationPdf( + combRepository.find("userId = ?1", subject).firstResult() + .invoke(Unchecked.consumer(m -> { + if (m == null || m.getClub() == null) + throw new DNotFoundException("Club non trouvé"); + })) + .map(MembreModel::getClub) + .call(m -> Mutiny.fetch(m.getAffiliations()))); + } + + public Uni getAffiliationPdf(long id) { + return getAffiliationPdf( + repository.findById(id) + .invoke(Unchecked.consumer(m -> { + if (m == null) + throw new DNotFoundException("Club non trouvé"); + })) + .call(m -> Mutiny.fetch(m.getAffiliations()))); + } + + + private Uni getAffiliationPdf(Uni uniBase) { + return uniBase + .map(Unchecked.function(m -> { + if (m.getAffiliations().stream() + .noneMatch(licenceModel -> licenceModel.getSaison() == Utils.getSaison() - 1)) + throw new DNotFoundException("Pas d'affiliation pour la saison en cours"); + + try { + byte[] buff = make_pdf(m); + if (buff == null) + throw new IOException("Error making pdf"); + + 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'affiliation " + Utils.getSaison() + "-" + + (Utils.getSaison() + 1) + " de " + m.getName() + ".pdf\""); + return resp.build(); + } catch (Exception e) { + throw new IOException(e); + } + })); + } + + private byte[] make_pdf(ClubModel m) throws IOException, InterruptedException { + List cmd = new ArrayList<>(); + cmd.add("java"); + cmd.add("-jar"); + cmd.add(pdfMakerJarPath); + + UUID uuid = UUID.randomUUID(); + + cmd.add("/tmp/" + uuid + ".pdf"); + cmd.add("club"); + cmd.add(m.getName()); + cmd.add(Utils.getSaison() + ""); + cmd.add(m.getNo_affiliation() + ""); + cmd.add(new File(sign_file).getAbsolutePath()); + + return getPdf(cmd, uuid, LOGGER); + } + + static byte[] getPdf(List cmd, UUID uuid, Logger logger) throws IOException, InterruptedException { + 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 { + code = process.exitValue(); + } + + if (t.isAlive()) + t.interrupt(); + + logger.debug("PDF maker: " + builder); + + 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/java/fr/titionfire/ffsaf/domain/service/MembreService.java b/src/main/java/fr/titionfire/ffsaf/domain/service/MembreService.java index 041a9cb..3e044f7 100644 --- a/src/main/java/fr/titionfire/ffsaf/domain/service/MembreService.java +++ b/src/main/java/fr/titionfire/ffsaf/domain/service/MembreService.java @@ -33,12 +33,15 @@ import org.eclipse.microprofile.config.inject.ConfigProperty; import org.hibernate.reactive.mutiny.Mutiny; import org.jboss.logging.Logger; -import java.io.*; +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; import java.text.SimpleDateFormat; import java.util.*; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import static fr.titionfire.ffsaf.domain.service.ClubService.getPdf; + @WithSession @ApplicationScoped @@ -506,6 +509,7 @@ public class MembreService { UUID uuid = UUID.randomUUID(); cmd.add("/tmp/" + uuid + ".pdf"); + cmd.add("membre"); cmd.add(m.getFname()); cmd.add(m.getLname()); cmd.add(m.getGenre().str); @@ -526,50 +530,6 @@ public class MembreService { cmd.add("/dev/null"); } - 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 { - code = process.exitValue(); - } - - if (t.isAlive()) - t.interrupt(); - - LOGGER.debug("PDF maker: " + builder); - - 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; - } + return getPdf(cmd, uuid, LOGGER); } } diff --git a/src/main/java/fr/titionfire/ffsaf/rest/ClubEndpoints.java b/src/main/java/fr/titionfire/ffsaf/rest/ClubEndpoints.java index 5b47e91..a9e7657 100644 --- a/src/main/java/fr/titionfire/ffsaf/rest/ClubEndpoints.java +++ b/src/main/java/fr/titionfire/ffsaf/rest/ClubEndpoints.java @@ -207,6 +207,21 @@ public class ClubEndpoints { return clubService.delete(id); } + @GET + @Path("/{id}/affiliation") + @RolesAllowed({"federation_admin"}) + @Operation(summary = "Renvoie l'attestation d'affiliation du club en fonction de son identifiant", description = + "Renvoie l'attestation d'affiliation du club en fonction de son identifiant") + @APIResponses(value = { + @APIResponse(responseCode = "200", description = "L'attestation d'affiliation"), + @APIResponse(responseCode = "403", description = "Accès refusé"), + @APIResponse(responseCode = "404", description = "Le club n'existe pas ou n'a pas d'affiliation active"), + @APIResponse(responseCode = "500", description = "Erreur interne du serveur") + }) + public Uni getAffiliation(@Parameter(description = "Identifiant de club") @PathParam("id") long id) { + return clubService.getAffiliationPdf(id); + } + @GET @Path("/me") @RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"}) @@ -241,13 +256,28 @@ public class ClubEndpoints { return clubService.updateOfUser(securityCtx, form); } + @GET + @Path("/me/affiliation") + @RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"}) + @Operation(summary = "Renvoie l'attestation d'affiliation du club de l'utilisateur connecté", description = + "Renvoie l'attestation d'affiliation du club de l'utilisateur connecté") + @APIResponses(value = { + @APIResponse(responseCode = "200", description = "L'attestation d'affiliation"), + @APIResponse(responseCode = "403", description = "Accès refusé"), + @APIResponse(responseCode = "404", description = "Le club n'a pas d'affiliation active"), + @APIResponse(responseCode = "500", description = "Erreur interne du serveur") + }) + public Uni getMeAffiliation() { + return clubService.getAffiliationPdf(securityCtx.getSubject()); + } + @GET @Path("/renew/{id}") @RolesAllowed({"club_president", "club_secretaire", "club_respo_intra"}) @Produces(MediaType.APPLICATION_JSON) @Operation(hidden = true) public Uni getRenew(@PathParam("id") long id, @QueryParam("m1") long m1_id, - @QueryParam("m2") long m2_id, @QueryParam("m3") long m3_id) { + @QueryParam("m2") long m2_id, @QueryParam("m3") long m3_id) { return Uni.createFrom().item(id).invoke(checkPerm2) .chain(__ -> clubService.getRenewData(id, List.of(m1_id, m2_id, m3_id))); } 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 index 77d0be7..a9df659 100644 --- a/src/main/pdf_gen/src/main/java/fr/titionfire/Main.java +++ b/src/main/pdf_gen/src/main/java/fr/titionfire/Main.java @@ -1,11 +1,11 @@ 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 com.lowagie.text.Font; +import com.lowagie.text.Image; +import com.lowagie.text.pdf.*; +import java.awt.*; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -13,37 +13,231 @@ import java.io.InputStream; 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; 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); + if (args[1].equals("membre")) { + PdfData pdfData = new PdfData(); + pdfData.fname = args[2]; + pdfData.lname = args[3]; + pdfData.genre = args[4]; + pdfData.categorie = args[5]; + pdfData.certificate = args[6]; + pdfData.saison = Integer.parseInt(args[7]); + pdfData.licence = Integer.parseInt(args[8]); + pdfData.club = args[9]; + pdfData.club_no = Integer.parseInt(args[10]); + pdfData.birth_date = args[11]; + pdfData.photo_file = new File(args[12]); + + try { + FileOutputStream out = new FileOutputStream(dest); + new Main().make_pdf(pdfData, out); + } catch (IOException e) { + e.printStackTrace(); + System.exit(1); + } + } else { + PdfDataClub pdfData = new PdfDataClub(); + pdfData.name = args[2]; + pdfData.saison = Integer.parseInt(args[3]); + pdfData.club_no = Integer.parseInt(args[4]); + pdfData.sign_file = new File(args[5]); + + try { + FileOutputStream out = new FileOutputStream(dest); + new Main().make_pdf_club(pdfData, out); + } catch (IOException e) { + e.printStackTrace(); + System.exit(1); + } } System.out.println("PDF generated successfully"); System.exit(0); } + public static class BorderEvent implements PdfPTableEvent { + public void tableLayout(PdfPTable table, float[][] widths, + float[] heights, int headerRows, int rowStart, + PdfContentByte[] canvases) { + float[] width = widths[0]; + float x1 = width[0]; + float x2 = width[width.length - 1]; + float y1 = heights[0]; + float y2 = heights[heights.length - 1]; + PdfContentByte cb = canvases[PdfPTable.LINECANVAS]; + cb.setLineWidth(3); + cb.rectangle(x1, y1, x2 - x1, y2 - y1); + cb.stroke(); + + cb.setLineWidth(1); + cb.rectangle(x1 + 4, y1 - 4, x2 - x1 - 8, y2 - y1 + 8); + cb.stroke(); + + cb.resetRGBColorStroke(); + } + } + + private void make_pdf_club(PdfDataClub pdfData, FileOutputStream out) throws IOException { + Document document = new Document(PageSize.A4.rotate()); + PdfWriter.getInstance(document, out); + document.open(); + + document.addCreator("FFSAF"); + document.addTitle( + "Attestation d'affiliation " + pdfData.saison + "-" + (pdfData.saison + 1) + " - " + pdfData.name); + document.addCreationDate(); + document.addProducer("https://www.ffsaf.fr"); + + InputStream fontStream = Main.class.getClassLoader().getResourceAsStream("Helvetica.ttf"); + if (fontStream == null) + throw new IOException("Font file not found"); + BaseFont customFont = BaseFont.createFont("Helvetica.ttf", BaseFont.WINANSI, BaseFont.EMBEDDED, true, + null, fontStream.readAllBytes()); + + InputStream fontStream2 = Main.class.getClassLoader().getResourceAsStream("Helvetica-Bold.ttf"); + if (fontStream2 == null) + throw new IOException("Font file not found"); + BaseFont customFontBold = BaseFont.createFont("Helvetica-Bold.ttf", BaseFont.WINANSI, BaseFont.EMBEDDED, true, + null, fontStream2.readAllBytes()); + + InputStream fontStream3 = Main.class.getClassLoader().getResourceAsStream("helvetica-light.ttf"); + if (fontStream3 == null) + throw new IOException("Font file not found"); + BaseFont customFontLight = BaseFont.createFont("helvetica-light.ttf", BaseFont.WINANSI, BaseFont.EMBEDDED, true, + null, fontStream3.readAllBytes()); + + // Creating the main table + PdfPTable mainTable = new PdfPTable(1); + mainTable.setWidthPercentage(100); + mainTable.setSpacingBefore(0f); + mainTable.setSpacingAfter(0f); + mainTable.getDefaultCell().setBorder(PdfPCell.NO_BORDER); + mainTable.setExtendLastRow(true); + + mainTable.setTableEvent(new BorderEvent()); + + // Creating the main table + PdfPTable headerRow = new PdfPTable(2); + headerRow.setWidths(new float[]{1, 2}); + headerRow.getDefaultCell().setBorder(PdfPCell.NO_BORDER); + + // Adding logo + Image logo = Image.getInstance( + Objects.requireNonNull( + getClass().getClassLoader().getResource("Logo-FFSAF-2023.png"))); + logo.scaleToFit(160, 160); + PdfPCell logoCell = new PdfPCell(logo); + logoCell.setHorizontalAlignment(Element.ALIGN_CENTER); + logoCell.setVerticalAlignment(Element.ALIGN_MIDDLE); + logoCell.setPadding(0); + logoCell.setRowspan(1); + logoCell.setPaddingTop(20); + logoCell.setPaddingBottom(20); + logoCell.setBorder(PdfPCell.NO_BORDER); + headerRow.addCell(logoCell); + + List pList = new ArrayList<>(); + pList.add(new Paragraph("Fédération", new Font(customFontBold, 16, Font.NORMAL))); + pList.add(new Paragraph("FRANCE SOFT ARMORED FIGHTING", new Font(customFontBold, 18, Font.NORMAL))); + pList.add(new Paragraph("Association loi 1901 n° W633001595\n ", new Font(customFontLight, 11, Font.NORMAL))); + pList.add(new Paragraph("5 place de la Barreyre", new Font(customFont, 11, Font.NORMAL))); + pList.add(new Paragraph("63320 Champeix\n ", new Font(customFont, 11, Font.NORMAL))); + pList.add(new Paragraph("ffsaf.fr", new Font(customFontBold, 14, Font.NORMAL))); + + PdfPCell headerCell = new PdfPCell(); + pList.forEach(p -> p.setAlignment(Element.ALIGN_CENTER)); + pList.forEach(headerCell::addElement); + headerCell.setHorizontalAlignment(Element.ALIGN_CENTER); + headerCell.setVerticalAlignment(Element.ALIGN_MIDDLE); + headerCell.setBorder(PdfPCell.NO_BORDER); + headerRow.addCell(headerCell); + mainTable.addCell(headerRow); + + pList.clear(); + pList.add(new Paragraph("CLUB AFFILIÉ SAISON " + pdfData.saison + "-" + (pdfData.saison + 1) + "\n ", + new Font(customFontBold, 24, Font.NORMAL))); + pList.add(new Paragraph(pdfData.name, new Font(customFontBold, 20, Font.NORMAL, new Color(0, 112, 192)))); + pList.add(new Paragraph(String.format("- association n°%03d -\n ", pdfData.club_no), + new Font(customFont, 18, Font.TIMES_ROMAN))); + + PdfPCell bodyCell = new PdfPCell(); + pList.forEach(p -> p.setAlignment(Element.ALIGN_CENTER)); + pList.forEach(bodyCell::addElement); + bodyCell.setHorizontalAlignment(Element.ALIGN_CENTER); + bodyCell.setVerticalAlignment(Element.ALIGN_MIDDLE); + bodyCell.setBorder(PdfPCell.NO_BORDER); + mainTable.addCell(bodyCell); + + PdfPTable footerRow = new PdfPTable(2); + footerRow.setWidths(new float[]{2, 1}); + footerRow.getDefaultCell().setBorder(PdfPCell.NO_BORDER); + + + PdfPTable footerSubRow = new PdfPTable(2); + footerSubRow.setWidths(new float[]{1, 5}); + footerSubRow.getDefaultCell().setBorder(PdfPCell.NO_BORDER); + + Image logo2 = Image.getInstance( + Objects.requireNonNull( + getClass().getClassLoader().getResource("safef.jpg"))); + logo2.scaleToFit(65, 65); + PdfPCell logo2Cell = new PdfPCell(logo2); + logo2Cell.setHorizontalAlignment(Element.ALIGN_LEFT); + logo2Cell.setVerticalAlignment(Element.ALIGN_MIDDLE); + logo2Cell.setPadding(0); + logo2Cell.setRowspan(1); + logo2Cell.setPaddingLeft(7); + logo2Cell.setBorder(PdfPCell.NO_BORDER); + footerSubRow.addCell(logo2Cell); + + pList.clear(); + pList.add(new Paragraph("La FFSAF est fondatrice et affilié à la SAFE Federation.", + new Font(customFontBold, 10, Font.NORMAL))); + pList.add(new Paragraph("Soft Armored Fighting European Federation", + new Font(customFontLight, 10, Font.TIMES_ROMAN))); + + PdfPCell footerCell = new PdfPCell(); + pList.forEach(p -> p.setAlignment(Element.ALIGN_LEFT)); + pList.forEach(footerCell::addElement); + footerCell.setHorizontalAlignment(Element.ALIGN_LEFT); + footerCell.setVerticalAlignment(Element.ALIGN_MIDDLE); + footerCell.setBorder(PdfPCell.NO_BORDER); + footerSubRow.addCell(footerCell); + footerRow.addCell(footerSubRow); + + pList.clear(); + pList.add(new Paragraph("Le président de la FFSAF,", new Font(customFont, 13, Font.NORMAL))); + pList.add(new Paragraph("Guillaume Andrieux", new Font(customFontBold, 13, Font.NORMAL))); + + PdfPCell footerCell2 = new PdfPCell(); + pList.forEach(p -> p.setAlignment(Element.ALIGN_LEFT)); + pList.forEach(footerCell2::addElement); + + Image sign = Image.getInstance(Files.readAllBytes(pdfData.sign_file.toPath())); + sign.scaleToFit(120, 60); + sign.setSpacingBefore(10); + footerCell2.addElement(sign); + + footerCell2.setHorizontalAlignment(Element.ALIGN_LEFT); + footerCell2.setVerticalAlignment(Element.ALIGN_MIDDLE); + footerCell2.setBorder(PdfPCell.NO_BORDER); + footerRow.addCell(footerCell2); + + mainTable.addCell(footerRow); + document.add(mainTable); + + // Close the document + document.close(); + } + private void make_pdf(PdfData pdfData, FileOutputStream out) throws IOException { SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); Document document = new Document(); @@ -81,7 +275,7 @@ public class Main { // Adding logo Image logo = Image.getInstance( Objects.requireNonNull( - getClass().getClassLoader().getResource("FFSSAF-bord-blanc-fond-transparent.png"))); + getClass().getClassLoader().getResource("Logo-FFSAF-2023.png"))); logo.scaleToFit(120, 120); PdfPCell logoCell = new PdfPCell(logo); logoCell.setHorizontalAlignment(Element.ALIGN_CENTER); @@ -135,7 +329,8 @@ public class Main { // Adding member photo Image memberPhoto; - if (pdfData.photo_file != null && pdfData.photo_file.exists() && pdfData.photo_file.getAbsolutePath().equals("/dev/null")) { + if (pdfData.photo_file != null && pdfData.photo_file.exists() && !pdfData.photo_file.getAbsolutePath() + .equals("/dev/null")) { memberPhoto = Image.getInstance(Files.readAllBytes(pdfData.photo_file.toPath())); } else { memberPhoto = Image.getInstance( @@ -168,7 +363,7 @@ public class Main { // 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(String.format("Licence n° : %05d", 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 @@ -180,7 +375,7 @@ public class Main { Paragraph memberClub = new Paragraph("CLUB : " + pdfData.club.toUpperCase(), bodyFont); document.add(memberClub); - Paragraph memberClubNumber = new Paragraph("N° club : " + pdfData.club_no, bodyFont); + Paragraph memberClubNumber = new Paragraph(String.format("N° club : %03d ", pdfData.club_no), bodyFont); document.add(memberClubNumber); // Adding spacing diff --git a/src/main/pdf_gen/src/main/java/fr/titionfire/PdfDataClub.java b/src/main/pdf_gen/src/main/java/fr/titionfire/PdfDataClub.java new file mode 100644 index 0000000..5e3f26a --- /dev/null +++ b/src/main/pdf_gen/src/main/java/fr/titionfire/PdfDataClub.java @@ -0,0 +1,10 @@ +package fr.titionfire; + +import java.io.File; + +public class PdfDataClub { + int saison; + int club_no; + String name; + public File sign_file; +} diff --git a/src/main/pdf_gen/src/main/resources/FFSSAF-bord-blanc-fond-transparent.png b/src/main/pdf_gen/src/main/resources/FFSSAF-bord-blanc-fond-transparent.png deleted file mode 100644 index e4d6e6d..0000000 Binary files a/src/main/pdf_gen/src/main/resources/FFSSAF-bord-blanc-fond-transparent.png and /dev/null differ diff --git a/src/main/pdf_gen/src/main/resources/Helvetica-Bold.ttf b/src/main/pdf_gen/src/main/resources/Helvetica-Bold.ttf new file mode 100644 index 0000000..332b66c Binary files /dev/null and b/src/main/pdf_gen/src/main/resources/Helvetica-Bold.ttf differ diff --git a/src/main/pdf_gen/src/main/resources/Helvetica.ttf b/src/main/pdf_gen/src/main/resources/Helvetica.ttf new file mode 100644 index 0000000..718f22d Binary files /dev/null and b/src/main/pdf_gen/src/main/resources/Helvetica.ttf differ diff --git a/src/main/pdf_gen/src/main/resources/Logo-FFSAF-2023.png b/src/main/pdf_gen/src/main/resources/Logo-FFSAF-2023.png new file mode 100644 index 0000000..d44c9ce Binary files /dev/null and b/src/main/pdf_gen/src/main/resources/Logo-FFSAF-2023.png differ diff --git a/src/main/pdf_gen/src/main/resources/helvetica-light.ttf b/src/main/pdf_gen/src/main/resources/helvetica-light.ttf new file mode 100644 index 0000000..ecc9264 Binary files /dev/null and b/src/main/pdf_gen/src/main/resources/helvetica-light.ttf differ diff --git a/src/main/pdf_gen/src/main/resources/safef.jpg b/src/main/pdf_gen/src/main/resources/safef.jpg new file mode 100644 index 0000000..6c5cf0a Binary files /dev/null and b/src/main/pdf_gen/src/main/resources/safef.jpg differ diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 7152b9c..c4eee2d 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -14,6 +14,7 @@ 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 +pdf-maker.sign-file=/work/sign.jpg %dev.quarkus.log.min-level=ALL %dev.quarkus.log.category."fr.titionfire.ffsaf".level=ALL diff --git a/src/main/webapp/src/pages/admin/club/AffiliationCard.jsx b/src/main/webapp/src/pages/admin/club/AffiliationCard.jsx index 0d7e7f7..6a42772 100644 --- a/src/main/webapp/src/pages/admin/club/AffiliationCard.jsx +++ b/src/main/webapp/src/pages/admin/club/AffiliationCard.jsx @@ -2,13 +2,15 @@ import {useLoadingSwitcher} from "../../../hooks/useLoading.jsx"; import {useFetch} from "../../../hooks/useFetch.js"; import {useEffect, useReducer, useState} from "react"; import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; -import {faEye, faPen} from "@fortawesome/free-solid-svg-icons"; +import {faEye, faFilePdf, faPen} from "@fortawesome/free-solid-svg-icons"; import {AxiosError} from "../../../components/AxiosError.jsx"; import {apiAxios, errFormater, getSaison} from "../../../utils/Tools.js"; import {toast} from "react-toastify"; import {SimpleReducer} from "../../../utils/SimpleReducer.jsx"; import {useNavigate} from "react-router-dom"; +const vite_url = import.meta.env.VITE_URL; + export function AffiliationCard({clubData}) { const setLoading = useLoadingSwitcher() const {data, error} = useFetch(`/affiliation/${clubData.id}`, setLoading, 1) @@ -49,6 +51,13 @@ export function AffiliationCard({clubData}) { })} {error && } + + + +
removeAffiliation(affiliation.id, dispatch)}>Supprimer}
-} \ No newline at end of file +} diff --git a/src/main/webapp/src/pages/club/club/AffiliationCard.jsx b/src/main/webapp/src/pages/club/club/AffiliationCard.jsx index aa483fb..168963a 100644 --- a/src/main/webapp/src/pages/club/club/AffiliationCard.jsx +++ b/src/main/webapp/src/pages/club/club/AffiliationCard.jsx @@ -2,13 +2,15 @@ import {useLoadingSwitcher} from "../../../hooks/useLoading.jsx"; import {useFetch} from "../../../hooks/useFetch.js"; import {useEffect, useReducer, useState} from "react"; import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; -import {faEye, faPen} from "@fortawesome/free-solid-svg-icons"; +import {faEye, faFilePdf, faPen} from "@fortawesome/free-solid-svg-icons"; import {AxiosError} from "../../../components/AxiosError.jsx"; import {apiAxios, getSaison} from "../../../utils/Tools.js"; import {toast} from "react-toastify"; import {SimpleReducer} from "../../../utils/SimpleReducer.jsx"; import {useNavigate} from "react-router-dom"; +const vite_url = import.meta.env.VITE_URL; + export function AffiliationCard({clubData}) { const setLoading = useLoadingSwitcher() const {data, error} = useFetch(`/affiliation/${clubData.id}`, setLoading, 1) @@ -37,6 +39,13 @@ export function AffiliationCard({clubData}) { })} {error && } + + + +
Suivant
-} \ No newline at end of file +}