diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/DocumentConversionServiceImp.java b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/DocumentConversionServiceImp.java index e9e7d3b489b337e0e3538c60a69454bf42d9481e..6d19bfe6f354e501366d6e24c8400bb7ea81510a 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/DocumentConversionServiceImp.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/DocumentConversionServiceImp.java @@ -35,7 +35,7 @@ public class DocumentConversionServiceImp implements DocumentConversionService { private static Logger log = LoggerFactory.getLogger(DocumentConversionServiceImp.class); private IBbbWebApiGWApp gw; - private OfficeToPdfConversionService officeToPdfConversionService; + private OfficeToPdfConversion officeToPdfConversionService; private SwfSlidesGenerationProgressNotifier notifier; private PresentationFileProcessor presentationFileProcessor; @@ -161,7 +161,7 @@ public class DocumentConversionServiceImp implements DocumentConversionService { gw = m; } - public void setOfficeToPdfConversionService(OfficeToPdfConversionService s) { + public void setOfficeToPdfConversionService(OfficeToPdfConversion s) { officeToPdfConversionService = s; } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/Office2PdfPageConverter.java b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/Office2PdfPageConverter.java index 96233285cb8cf6c1e5383238c264c64db4d1c84e..585272e028c3b31017bd3628fb5d5319ef93e1ec 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/Office2PdfPageConverter.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/Office2PdfPageConverter.java @@ -19,10 +19,7 @@ package org.bigbluebutton.presentation.imp; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; +import java.io.*; import java.util.HashMap; import java.util.Map; @@ -41,8 +38,10 @@ import com.google.gson.Gson; public abstract class Office2PdfPageConverter { private static Logger log = LoggerFactory.getLogger(Office2PdfPageConverter.class); +// public static boolean convert(File presentationFile, File output, int page, UploadedPresentation pres, +// LocalConverter converter){ public static boolean convert(File presentationFile, File output, int page, UploadedPresentation pres, - LocalConverter converter){ + String presOfficeConversionExec){ FileInputStream inputStream = null; FileOutputStream outputStream = null; @@ -58,14 +57,39 @@ public abstract class Office2PdfPageConverter { String logStr = gson.toJson(logData); log.info(" --analytics-- data={}", logStr); - final DocumentFormat sourceFormat = DefaultDocumentFormatRegistry.getFormatByExtension( - FilenameUtils.getExtension(presentationFile.getName())); +// This method using Jod as office converter was replaced by a customizable script (solving issue https://github.com/bigbluebutton/bigbluebutton/issues/10699) +// final DocumentFormat sourceFormat = DefaultDocumentFormatRegistry.getFormatByExtension( +// FilenameUtils.getExtension(presentationFile.getName())); +// +// inputStream = new FileInputStream(presentationFile); +// outputStream = new FileOutputStream(output); +// +// converter.convert(inputStream).as(sourceFormat).to(outputStream).as(DefaultDocumentFormatRegistry.PDF).execute(); +// outputStream.flush(); + + try { + log.info("Calling conversion script " + presOfficeConversionExec); + +// String convertScriptPath = "/usr/share/bbb-libreoffice-conversion/convert.sh"; + Process p = Runtime.getRuntime().exec(String.format(presOfficeConversionExec + " %s %s", presentationFile.getAbsolutePath(), output.getAbsolutePath())); + + BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream())); + BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream())); + String s = null; + + // read the output from the command + while ((s = stdInput.readLine()) != null) { + log.info(s); + } - inputStream = new FileInputStream(presentationFile); - outputStream = new FileOutputStream(output); + // read any errors from the attempted command + while ((s = stdError.readLine()) != null) { + log.error(s); + } - converter.convert(inputStream).as(sourceFormat).to(outputStream).as(DefaultDocumentFormatRegistry.PDF).execute(); - outputStream.flush(); + } catch (IOException e) { + log.error("Exception while calling convert script: ", presentationFile.getName(), e.getMessage()); + } if (output.exists()) { return true; diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/OfficeToPdfConversion.java b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/OfficeToPdfConversion.java new file mode 100644 index 0000000000000000000000000000000000000000..6f3b78569fedc5fc19e213f60cceadb21bb37e97 --- /dev/null +++ b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/OfficeToPdfConversion.java @@ -0,0 +1,133 @@ +/** + * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ + * + * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below). + * + * This program is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation; either version 3.0 of the License, or (at your option) any later + * version. + * + * BigBlueButton 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. + * + */ +package org.bigbluebutton.presentation.imp; + +import com.google.gson.Gson; +import com.sun.star.document.UpdateDocMode; +import org.bigbluebutton.presentation.ConversionMessageConstants; +import org.bigbluebutton.presentation.SupportedFileTypes; +import org.bigbluebutton.presentation.UploadedPresentation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +public class OfficeToPdfConversion { + private static Logger log = LoggerFactory.getLogger(OfficeToPdfConversion.class); + private OfficeDocumentValidator2 officeDocumentValidator; + private boolean skipOfficePrecheck = false; + private String presOfficeConversionExec = null; + /* + * Convert the Office document to PDF. If successful, update + * UploadPresentation.uploadedFile with the new PDF out and + * UploadPresentation.lastStepSuccessful to TRUE. + */ + public UploadedPresentation convertOfficeToPdf(UploadedPresentation pres) { + initialize(pres); + if (SupportedFileTypes.isOfficeFile(pres.getFileType())) { + // Check if we need to precheck office document + if (!skipOfficePrecheck && officeDocumentValidator.isValid(pres)) { + Map<String, Object> logData = new HashMap<>(); + logData.put("meetingId", pres.getMeetingId()); + logData.put("presId", pres.getId()); + logData.put("filename", pres.getName()); + logData.put("logCode", "problems_office_to_pdf_validation"); + logData.put("message", "Problems detected prior to converting the file to PDF."); + Gson gson = new Gson(); + String logStr = gson.toJson(logData); + log.warn(" --analytics-- data={}", logStr); + pres.setConversionStatus(ConversionMessageConstants.OFFICE_DOC_CONVERSION_INVALID_KEY); + return pres; + } + File pdfOutput = setupOutputPdfFile(pres); + if (convertOfficeDocToPdf(pres, pdfOutput)) { + Map<String, Object> logData = new HashMap<>(); + logData.put("meetingId", pres.getMeetingId()); + logData.put("presId", pres.getId()); + logData.put("filename", pres.getName()); + logData.put("logCode", "office_to_pdf_success"); + logData.put("message", "Successfully converted office file to pdf."); + Gson gson = new Gson(); + String logStr = gson.toJson(logData); + log.info(" --analytics-- data={}", logStr); + makePdfTheUploadedFileAndSetStepAsSuccess(pres, pdfOutput); + } else { + Map<String, Object> logData = new HashMap<>(); + logData.put("meetingId", pres.getMeetingId()); + logData.put("presId", pres.getId()); + logData.put("filename", pres.getName()); + logData.put("logCode", "office_to_pdf_failed"); + logData.put("message", "Failed to convert " + pres.getUploadedFile().getAbsolutePath() + " to Pdf."); + Gson gson = new Gson(); + String logStr = gson.toJson(logData); + log.warn(" --analytics-- data={}", logStr); + pres.setConversionStatus(ConversionMessageConstants.OFFICE_DOC_CONVERSION_FAILED_KEY); + return pres; + } + } + return pres; + } + public void initialize(UploadedPresentation pres) { + pres.setConversionStatus(ConversionMessageConstants.OFFICE_DOC_CONVERSION_FAILED_KEY); + } + private File setupOutputPdfFile(UploadedPresentation pres) { + File presentationFile = pres.getUploadedFile(); + String filenameWithoutExt = presentationFile.getAbsolutePath().substring(0, + presentationFile.getAbsolutePath().lastIndexOf('.')); + return new File(filenameWithoutExt + ".pdf"); + } + private boolean convertOfficeDocToPdf(UploadedPresentation pres, + File pdfOutput) { + boolean success = false; + int attempts = 0; + while(!success) { + final Map<String, Object> loadProperties = new HashMap<>(); + loadProperties.put("Hidden", true); + loadProperties.put("ReadOnly", true); + loadProperties.put("UpdateDocMode", UpdateDocMode.NO_UPDATE); + + success = Office2PdfPageConverter.convert(pres.getUploadedFile(), pdfOutput, 0, pres, ""); + } + + return success; + } + + private void makePdfTheUploadedFileAndSetStepAsSuccess(UploadedPresentation pres, File pdf) { + pres.setUploadedFile(pdf); + pres.setConversionStatus(ConversionMessageConstants.OFFICE_DOC_CONVERSION_SUCCESS_KEY); + } + + public void setOfficeDocumentValidator(OfficeDocumentValidator2 v) { + officeDocumentValidator = v; + } + + public void setSkipOfficePrecheck(boolean skipOfficePrecheck) { + this.skipOfficePrecheck = skipOfficePrecheck; + } + + public void setPresOfficeConversionExec(String presOfficeConversionExec) { + this.presOfficeConversionExec = presOfficeConversionExec; + } + +} + diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/OfficeToPdfConversionService.java b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/OfficeToPdfConversionService.java index 7501d01268814b923f78040edd0a18c2d5a66a14..152fe4480ad2a8857bede8b537e870054ffcffee 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/OfficeToPdfConversionService.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/presentation/imp/OfficeToPdfConversionService.java @@ -120,7 +120,8 @@ public class OfficeToPdfConversionService { .filterChain(new OfficeDocumentConversionFilter()) .build(); - success = Office2PdfPageConverter.convert(pres.getUploadedFile(), pdfOutput, 0, pres, documentConverter); +// success = Office2PdfPageConverter.convert(pres.getUploadedFile(), pdfOutput, 0, pres, documentConverter); + success = Office2PdfPageConverter.convert(pres.getUploadedFile(), pdfOutput, 0, pres, ""); if(!success) { // In case of failure, try with other open Office Manager diff --git a/bbb-libreoffice/assets/convert-local.sh b/bbb-libreoffice/assets/convert-local.sh new file mode 100644 index 0000000000000000000000000000000000000000..106f3a57f7761230a0c629601d764bf8d833dca5 --- /dev/null +++ b/bbb-libreoffice/assets/convert-local.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +#echo "First arg: $1" +#echo "Second arg: $2" + +#foldername=$(date +"%Y%m%d-%H%M%S") +#filename=$(basename $1) + +#foldername="/tmp/bbb-libreoffice-conversion/$(cat /proc/sys/kernel/random/uuid)" + + +#tmpDirectory="/tmp/bbb-libreoffice-conversion/$(cat /proc/sys/kernel/random/uuid)" + +while [ -z "$randomDirectoryName" -o -d "/tmp/bbb-libreoffice-conversion/$randomDirectoryName" ]; do + randomDirectoryName=$(shuf -i 100000000-999999999 -n 1) +done + +#randomDirectoryName=001 + +mkdir -p "/tmp/bbb-libreoffice-conversion/" +mkdir "/tmp/bbb-libreoffice-conversion/$randomDirectoryName/" +cp "$1" "/tmp/bbb-libreoffice-conversion/$randomDirectoryName/file" +sudo /usr/bin/docker run --rm --network none --env="HOME=/tmp/" -w /tmp/ --user=$(printf %05d `id -u`) -v "/tmp/bbb-libreoffice-conversion/$randomDirectoryName/":/data/ --rm bbb-soffice sh -c "/usr/bin/soffice -env:UserInstallation=file:///tmp/ --convert-to pdf --outdir /data /data/file" +cp "/tmp/bbb-libreoffice-conversion/$randomDirectoryName/file.pdf" "$2" +rm -r "/tmp/bbb-libreoffice-conversion/$randomDirectoryName/" + +exit 0 diff --git a/bbb-libreoffice/assets/convert-remote.sh b/bbb-libreoffice/assets/convert-remote.sh new file mode 100644 index 0000000000000000000000000000000000000000..cdc55b693114fe9772809020fec72bf9b13071b8 --- /dev/null +++ b/bbb-libreoffice/assets/convert-remote.sh @@ -0,0 +1,7 @@ +#/bin/bash +# This is a sample script - adjust it per your need +# 1 - setup a server with JOD-CONVERTER-REST ( docker run --memory 512m --rm -p 8080:8080 eugenmayer/jodconverter:rest ) +# 2 - replace the HOST information in below command with your server host +#echo "Not configured" +#exit 1 +curl -X POST "http://127.0.0.1:8080/lool/convert-to/pdf" -H "accept: application/octet-stream" -H "Content-Type: multipart/form-data" -F "data=@$1" > $2 diff --git a/bigbluebutton-web/grails-app/conf/bigbluebutton.properties b/bigbluebutton-web/grails-app/conf/bigbluebutton.properties index c62481f1e42982bcd993095866e00daa717297ee..61096be40af6c99ba951f75e071b13a0e8f41ff4 100755 --- a/bigbluebutton-web/grails-app/conf/bigbluebutton.properties +++ b/bigbluebutton-web/grails-app/conf/bigbluebutton.properties @@ -56,6 +56,10 @@ sofficeManagers=4 # Port number of the first soffice process sofficeBasePort=8201 +#---------------------------------------------------- +# Executable for presentation office conversion +presOfficeConversionExec=/usr/share/bbb-libreoffice-conversion/convert.sh + #---------------------------------------------------- # Working directory prefix for each soffice process. # The value of this is appended with the number of the diff --git a/bigbluebutton-web/grails-app/conf/spring/doc-conversion.xml b/bigbluebutton-web/grails-app/conf/spring/doc-conversion.xml index e7bc7f34c408b550e5576ddc7e50d3a3fcf95311..7b2336a5bd0d16b47496bf2da94133c086bb677b 100755 --- a/bigbluebutton-web/grails-app/conf/spring/doc-conversion.xml +++ b/bigbluebutton-web/grails-app/conf/spring/doc-conversion.xml @@ -25,7 +25,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. <bean id="documentConversionService" class="org.bigbluebutton.presentation.DocumentConversionServiceImp"> <property name="bbbWebApiGWApp" ref="bbbWebApiGWApp"/> - <property name="officeToPdfConversionService" ref="officeToPdfConversionService"/> + <property name="officeToPdfConversionService" ref="officeToPdfConversion"/> <property name="presentationFileProcessor" ref="presentationFileProcessor"/> <property name="swfSlidesGenerationProgressNotifier" ref="swfSlidesGenerationProgressNotifier"/> </bean> @@ -44,6 +44,12 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. <property name="sofficeWorkingDirBase" value="${sofficeWorkingDirBase:/var/tmp/soffice_}"/> </bean> + <bean id="officeToPdfConversion" class="org.bigbluebutton.presentation.imp.OfficeToPdfConversion"> + <property name="officeDocumentValidator" ref="officeDocumentValidator"/> + <property name="skipOfficePrecheck" value="${skipOfficePrecheck}"/> + <property name="presOfficeConversionExec" value="${presOfficeConversionExec:/usr/share/bbb-libreoffice-conversion/convert.sh}"/> + </bean> + <bean id="pageExtractor" class="org.bigbluebutton.presentation.imp.PageExtractorImp"/> <bean id="png2SwfConverter" class="org.bigbluebutton.presentation.imp.Png2SwfPageConverter">