/** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at the * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> * frentix GmbH, http://www.frentix.com * <p> */ package org.olat.course.certificate.ui; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.List; import org.apache.commons.io.IOUtils; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocumentCatalog; import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; import org.apache.pdfbox.pdmodel.interactive.form.PDField; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FileElement; import org.olat.core.gui.components.form.flexible.elements.SingleSelection; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.course.certificate.CertificateTemplate; import org.olat.course.certificate.CertificatesManager; import org.olat.fileresource.types.FileResource; import org.springframework.beans.factory.annotation.Autowired; /** * * Initial date: 20.10.2014<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ public class UploadCertificateController extends FormBasicController { protected static final String[] formatKeys = new String[]{ "A4", "Letter" }; protected static final String[] orientationKeys = new String[]{ "portrait", "landscape" }; protected FileElement fileEl; protected SingleSelection orientationEl, formatEl; private CertificateTemplate templateToUpdate; @Autowired private CertificatesManager certificatesManager; public UploadCertificateController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl); initForm(ureq); } public UploadCertificateController(UserRequest ureq, WindowControl wControl, CertificateTemplate template) { super(ureq, wControl); this.templateToUpdate = template; initForm(ureq); } @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { fileEl = uifactory.addFileElement(getWindowControl(), "template.file", formLayout); fileEl.addActionListener(FormEvent.ONCHANGE); String[] orientationValues = new String[]{ translate(orientationKeys[0]), translate(orientationKeys[1]) }; orientationEl = uifactory.addRadiosVertical("orientation", formLayout, orientationKeys, orientationValues); orientationEl.select(orientationKeys[0], true); orientationEl.setVisible(false); formatEl = uifactory.addRadiosVertical("format", formLayout, formatKeys, formatKeys); formatEl.select(formatKeys[0], true); formatEl.setVisible(false); FormLayoutContainer buttonCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); buttonCont.setRootForm(mainForm); formLayout.add(buttonCont); uifactory.addFormSubmitButton("save", buttonCont); uifactory.addFormCancelButton("cancel", buttonCont, ureq, getWindowControl()); } public String getFormat() { String format = null; if(formatEl.isVisible() && formatEl.isOneSelected()) { format = formatEl.getSelectedKey(); } return format; } public String getOrientation() { String format = null; if(orientationEl.isVisible() && orientationEl.isOneSelected()) { format = orientationEl.getSelectedKey(); } return format; } @Override protected void doDispose() { // } @Override protected void formOK(UserRequest ureq) { File template = fileEl.getUploadFile(); if(template != null) { String name = fileEl.getUploadFileName(); if(templateToUpdate == null) { certificatesManager.addTemplate(name, template, getFormat(), getOrientation(), true); } else { certificatesManager.updateTemplate(templateToUpdate, name, template, getFormat(), getOrientation()); } } fireEvent(ureq, Event.DONE_EVENT); } @Override protected void formCancelled(UserRequest ureq) { fireEvent(ureq, Event.CANCELLED_EVENT); } @Override protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { if(source == fileEl) { validateTemplate(); } } @Override protected boolean validateFormLogic(UserRequest ureq) { boolean allOk = true; allOk &= validateTemplate(); return allOk & super.validateFormLogic(ureq); } protected boolean validateTemplate() { boolean allOk = true; File template = fileEl.getUploadFile(); fileEl.clearError(); formatEl.setVisible(false); orientationEl.setVisible(false); if(template != null && template.exists()) { String filename = fileEl.getUploadFileName().toLowerCase(); if(filename.endsWith(".pdf")) { allOk = validatePdf(template); } else if(filename.endsWith(".zip")) { allOk = validateHtml(filename, template); } else { fileEl.setErrorKey("upload.wrong.mimetype", null); allOk &= false; } } return allOk; } private boolean validateHtml(String filename, File template) { boolean allOk = true; try { if(certificatesManager.isHTMLTemplateAllowed()) { Path path = FileResource.getResource(template, filename); IndexVisitor visitor = new IndexVisitor(path); Files.walkFileTree(path, visitor); if(!visitor.hasFound()) { fileEl.setErrorKey("upload.error.noindex", null); } allOk = visitor.hasFound(); formatEl.setVisible(allOk); orientationEl.setVisible(allOk); } else { fileEl.setErrorKey("upload.error.no.phantomjs", null); allOk = false; } } catch (IOException e) { logError("", e); fileEl.setErrorKey("upload.unkown.error", null); allOk = false; } return allOk; } private boolean validatePdf(File template) { boolean allOk = true; PDDocument document = null; try (InputStream in = Files.newInputStream(template.toPath())) { document = PDDocument.load(in); if (document.isEncrypted()) { fileEl.setErrorKey("upload.error.encrypted", null); allOk &= false; } else { //check if we can write the form PDDocumentCatalog docCatalog = document.getDocumentCatalog(); PDAcroForm acroForm = docCatalog.getAcroForm(); if (acroForm != null) { @SuppressWarnings("unchecked") List<PDField> fields = acroForm.getFields(); for(PDField field:fields) { field.setValue("test"); } } document.save(new DevNullOutputStream()); } } catch(IOException ex) { logError("", ex); if(ex.getMessage() != null && ex.getMessage().contains("Don't know how to calculate the position for non-simple fonts")) { fileEl.setErrorKey("upload.error.simplefonts", null); } else { fileEl.setErrorKey("upload.unkown.error", null); } allOk &= false; } catch(Exception ex) { logError("", ex); fileEl.setErrorKey("upload.unkown.error", null); allOk &= false; } finally { IOUtils.closeQuietly(document); } return allOk; } private static class DevNullOutputStream extends OutputStream { @Override public void write(int b){ // } } private static class IndexVisitor extends SimpleFileVisitor<Path> { private final Path root; private boolean found; public IndexVisitor(Path root) { this.root = root; } public boolean hasFound() { return found; } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if(file.getParent().equals(root) && file.getFileName().toString().equals("index.html")) { found = true; } return FileVisitResult.CONTINUE; } } }