/** * This file is part of alf.io. * * alf.io is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * alf.io is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with alf.io. If not, see <http://www.gnu.org/licenses/>. */ package alfio.controller.support; import alfio.manager.FileUploadManager; import alfio.manager.support.PDFTemplateGenerator; import alfio.manager.support.PartialTicketPDFGenerator; import alfio.manager.support.PartialTicketTextGenerator; import alfio.model.Event; import alfio.model.Ticket; import alfio.model.TicketCategory; import alfio.model.TicketReservation; import alfio.model.user.Organization; import alfio.util.LocaleUtil; import alfio.util.TemplateManager; import alfio.util.TemplateResource; import com.openhtmltopdf.DOMBuilder; import com.openhtmltopdf.pdfboxout.PdfBoxRenderer; import com.openhtmltopdf.pdfboxout.PdfRendererBuilder; import lombok.extern.log4j.Log4j2; import org.jsoup.Jsoup; import org.springframework.core.io.ClassPathResource; import javax.servlet.http.HttpServletRequest; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Locale; import java.util.Map; import java.util.Optional; @Log4j2 public final class TemplateProcessor { private TemplateProcessor() {} public static PartialTicketTextGenerator buildPartialEmail(Event event, Organization organization, TicketReservation ticketReservation, TemplateManager templateManager, String ticketURL, HttpServletRequest request) { return (ticket) -> { Map<String, Object> model = TemplateResource.buildModelForTicketEmail(organization, event, ticketReservation, ticketURL, ticket); Locale language = LocaleUtil.getTicketLanguage(ticket, request); return templateManager.renderTemplate(event, TemplateResource.TICKET_EMAIL, model, language); }; } public static PartialTicketTextGenerator buildEmailForOwnerChange(Event e, Ticket oldTicket, Organization organization, String ticketUrl, TemplateManager templateManager, Locale language) { return (newTicket) -> { Map<String, Object> emailModel = TemplateResource.buildModelForTicketHasChangedOwner(organization, e, oldTicket, newTicket, ticketUrl); return templateManager.renderTemplate(e, TemplateResource.TICKET_HAS_CHANGED_OWNER, emailModel, language); }; } public static PDFTemplateGenerator buildPDFTicket(Locale language, Event event, TicketReservation ticketReservation, Ticket ticket, TicketCategory ticketCategory, Organization organization, TemplateManager templateManager, FileUploadManager fileUploadManager, String reservationID) { return () -> { Optional<TemplateResource.ImageData> imageData = extractImageModel(event, fileUploadManager); Map<String, Object> model = TemplateResource.buildModelForTicketPDF(organization, event, ticketReservation, ticketCategory, ticket, imageData, reservationID); String page = templateManager.renderTemplate(event, TemplateResource.TICKET_PDF, model, language); return prepareItextRenderer(page); }; } public static PdfBoxRenderer prepareItextRenderer(String page) { PdfRendererBuilder builder = new PdfRendererBuilder(); builder.withW3cDocument(DOMBuilder.jsoup2DOM(Jsoup.parse(page)), ""); PdfBoxRenderer renderer = builder.buildPdfRenderer(); try (InputStream is = new ClassPathResource("/alfio/font/DejaVuSansMono.ttf").getInputStream()) { renderer.getFontResolver().addFont(() -> is, "DejaVu Sans Mono", null, null, false); } catch(IOException e) { log.warn("error while loading DejaVuSansMono.ttf font", e); } renderer.layout(); return renderer; } public static Optional<TemplateResource.ImageData> extractImageModel(Event event, FileUploadManager fileUploadManager) { if(event.getFileBlobIdIsPresent()) { return fileUploadManager.findMetadata(event.getFileBlobId()).map((metadata) -> { ByteArrayOutputStream baos = new ByteArrayOutputStream(); fileUploadManager.outputFile(metadata.getId(), baos); return TemplateResource.fillWithImageData(metadata, baos.toByteArray()); }); } else { return Optional.empty(); } } public static PartialTicketPDFGenerator buildPartialPDFTicket(Locale language, Event event, TicketReservation ticketReservation, TicketCategory ticketCategory, Organization organization, TemplateManager templateManager, FileUploadManager fileUploadManager, String reservationID) { return (ticket) -> buildPDFTicket(language, event, ticketReservation, ticket, ticketCategory, organization, templateManager, fileUploadManager, reservationID).generate(); } private static Optional<byte[]> buildReceiptOrInvoicePdf(Event event, FileUploadManager fileUploadManager, Locale language, TemplateManager templateManager, Map<String, Object> model, TemplateResource templateResource) { extractImageModel(event, fileUploadManager).ifPresent(imageData -> { model.put("eventImage", imageData.getEventImage()); model.put("imageWidth", imageData.getImageWidth()); model.put("imageHeight", imageData.getEventImage()); }); ByteArrayOutputStream baos = new ByteArrayOutputStream(); String page = templateManager.renderTemplate(event, templateResource, model, language); try { prepareItextRenderer(page).createPDF(baos); return Optional.of(baos.toByteArray()); } catch (IOException ioe) { return Optional.empty(); } } public static Optional<byte[]> buildReceiptPdf(Event event, FileUploadManager fileUploadManager, Locale language, TemplateManager templateManager, Map<String, Object> model) { return buildReceiptOrInvoicePdf(event, fileUploadManager, language, templateManager, model, TemplateResource.RECEIPT_PDF); } public static Optional<byte[]> buildInvoicePdf(Event event, FileUploadManager fileUploadManager, Locale language, TemplateManager templateManager, Map<String, Object> model) { return buildReceiptOrInvoicePdf(event, fileUploadManager, language, templateManager, model, TemplateResource.INVOICE_PDF); } }