Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature (api): Add preUploadedPresentation param to API's /create via GET #18953

Merged
merged 5 commits into from Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 15 additions & 1 deletion bbb-common-web/src/main/java/org/bigbluebutton/api/Util.java
Expand Up @@ -2,11 +2,14 @@

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;

public final class Util {
Expand Down Expand Up @@ -50,8 +53,19 @@ public static String generatePresentationId(String presFilename) {
return DigestUtils.sha1Hex(presFilename + uuid) + "-" + timestamp;
}

public static String extractFilenameFromUrl(String preUploadedPresentation) throws MalformedURLException {
URL url = new URL(preUploadedPresentation);
String filename = FilenameUtils.getName(url.getPath());
String extension = FilenameUtils.getExtension(url.getPath());
if (extension == null || extension.isEmpty()) return null;
return filename;
}
public static String createNewFilename(String presId, String fileExt) {
return presId + "." + fileExt;
if (!fileExt.isEmpty()) {
return presId + "." + fileExt;
} else {
return presId;
}
}

public static File createPresentationDir(String meetingId, String presentationDir, String presentationId) {
Expand Down
@@ -1,5 +1,7 @@
package org.bigbluebutton.presentation;

import org.bigbluebutton.api.domain.Extension;

import java.util.*;

import static org.bigbluebutton.presentation.FileTypeConstants.*;
Expand Down Expand Up @@ -43,7 +45,16 @@ public class MimeTypeUtils {
put(FileTypeConstants.SVG, Arrays.asList(SVG));
}
};


public String getExtensionBasedOnMimeType(String mimeType) {
return EXTENSIONS_MIME.entrySet()
.stream()
.filter(entry -> entry.getValue().contains(mimeType))
.map(Map.Entry::getKey)
.findFirst()
.orElse(null);
}

public Boolean extensionMatchMimeType(String mimeType, String finalExtension) {
finalExtension = finalExtension.toLowerCase();

Expand Down
Expand Up @@ -108,14 +108,21 @@ public static String detectMimeType(File pres) {
return "";
}

public static String detectFileExtensionBasedOnMimeType(File pres) {
String mimeType = detectMimeType(pres);
return mimeTypeUtils.getExtensionBasedOnMimeType(mimeType);
}

public static Boolean isPresentationMimeTypeValid(File pres, String fileExtension) {
String mimeType = detectMimeType(pres);

if (mimeType.equals("")) {
log.error("Not able to detect mimeType.");
return false;
}

if (!mimeTypeUtils.getValidMimeTypes().contains(mimeType)) {
log.error("MimeType is not valid for this meeting, [{}]", mimeType);
return false;
}

Expand Down
Expand Up @@ -21,6 +21,7 @@ package org.bigbluebutton.web.controllers
import com.google.gson.Gson
import grails.web.context.ServletContextHolder
import groovy.json.JsonBuilder
import groovy.xml.MarkupBuilder
import org.apache.commons.codec.binary.Base64
import org.apache.commons.codec.digest.DigestUtils
import org.apache.commons.io.FilenameUtils
Expand All @@ -43,7 +44,6 @@ import org.bigbluebutton.web.services.turn.TurnEntry
import org.bigbluebutton.web.services.turn.StunServer
import org.bigbluebutton.web.services.turn.RemoteIceCandidate
import org.json.JSONArray

import javax.servlet.ServletRequest

class ApiController {
Expand Down Expand Up @@ -1378,6 +1378,37 @@ class ApiController {
Boolean isDefaultPresentationCurrent = false;
def listOfPresentation = []
def presentationListHasCurrent = false
Boolean hasPresentationUrlInParameter = false


String[] pu = request.getParameterMap().get("preUploadedPresentation")
String[] puName = request.getParameterMap().get("preUploadedPresentationName")
if (pu != null) {
String preUploadedPresentation = pu[0]
hasPresentationUrlInParameter = true
def xmlString = new StringWriter()
def xml = new MarkupBuilder(xmlString)
String filename
if (puName == null) {
filename = Util.extractFilenameFromUrl(preUploadedPresentation)
if (filename == null) {
filename = "untitled"
}
} else {
filename = puName[0]
}
xml.document (
removable: "true",
downloadable: "false",
url: preUploadedPresentation,
filename: filename,
isPreUploadedPresentationFromParameter: "true"
)

def parsedXml = new XmlSlurper().parseText(xmlString.toString())

listOfPresentation << parsedXml
}

// This part of the code is responsible for organize the presentations in a certain order
// It selects the one that has the current=true, and put it in the 0th place.
Expand All @@ -1387,10 +1418,17 @@ class ApiController {
log.warn("Insert Document API called without a payload - ignoring")
return;
}
listOfPresentation << [name: "default", current: true];
if (hasPresentationUrlInParameter) {
if (!preUploadedPresentationOverrideDefault) {
listOfPresentation << [name: "default", current: true]
}
} else {
listOfPresentation << [name: "default", current: true]
}

} else {
def xml = new XmlSlurper().parseText(requestBody);
Boolean hasCurrent = false;
Boolean hasCurrent = hasPresentationUrlInParameter;
xml.children().each { module ->
log.debug("module config found: [${module.@name}]");

Expand Down Expand Up @@ -1425,6 +1463,7 @@ class ApiController {
def Boolean isRemovable = true;
def Boolean isDownloadable = false;
def Boolean isInitialPresentation = false;
def Boolean isPreUploadedPresentationFromParameter = false

if (document.name != null && "default".equals(document.name)) {
if (presentationService.defaultUploadedPresentation) {
Expand All @@ -1433,11 +1472,15 @@ class ApiController {
}
downloadAndProcessDocument(presentationService.defaultUploadedPresentation, conf.getInternalId(),
document.current /* default presentation */, '', false,
true, isInitialPresentation);
true, isInitialPresentation, isPreUploadedPresentationFromParameter);
} else {
log.error "Default presentation could not be read, it is (" + presentationService.defaultUploadedPresentation + ")", "error"
}
} else {
if (!StringUtils.isEmpty(document.@isPreUploadedPresentationFromParameter.toString())) {
isPreUploadedPresentationFromParameter = java.lang.Boolean.parseBoolean(
document.@isPreUploadedPresentationFromParameter.toString());
}
// Extracting all properties inside the xml
if (!StringUtils.isEmpty(document.@removable.toString())) {
isRemovable = java.lang.Boolean.parseBoolean(document.@removable.toString());
Expand All @@ -1464,7 +1507,7 @@ class ApiController {
fileName = document.@filename.toString();
}
downloadAndProcessDocument(document.@url.toString(), conf.getInternalId(), isCurrent /* default presentation */,
fileName, isDownloadable, isRemovable, isInitialPresentation);
fileName, isDownloadable, isRemovable, isInitialPresentation, isPreUploadedPresentationFromParameter);
} else if (!StringUtils.isEmpty(document.@name.toString())) {
def b64 = new Base64()
def decodedBytes = b64.decode(document.text().getBytes())
Expand Down Expand Up @@ -1534,7 +1577,8 @@ class ApiController {
}
}

def downloadAndProcessDocument(address, meetingId, current, fileName, isDownloadable, isRemovable, isInitialPresentation) {
def downloadAndProcessDocument(address, meetingId, current, fileName, isDownloadable, isRemovable,
isInitialPresentation, isPreUploadedPresentationFromParameter) {
log.debug("ApiController#downloadAndProcessDocument(${address}, ${meetingId}, ${fileName})");
String presOrigFilename;
if (StringUtils.isEmpty(fileName)) {
Expand All @@ -1559,7 +1603,7 @@ class ApiController {
def pres = null
def presId

if (presFilename == "" || filenameExt == "") {
if (presFilename == "" || (filenameExt == "" && !isPreUploadedPresentationFromParameter)) {
log.debug("presentation is null by default")
return
} else {
Expand All @@ -1576,6 +1620,22 @@ class ApiController {
uploadFailReasons.add("failed_to_download_file")
uploadFailed = true
}

if (isPreUploadedPresentationFromParameter && filenameExt.isEmpty()) {
String fileExtension = SupportedFileTypes.detectFileExtensionBasedOnMimeType(pres)
newFilename = Util.createNewFilename(presId, fileExtension)
newFilePath = uploadDir.absolutePath + File.separatorChar + newFilename
File destination = new File(newFilePath)
filenameExt = fileExtension
presFilename = Util.createNewFilename(presFilename, fileExtension)
if (pres.renameTo(destination)) {
log.info("Presentation coming from URL parameter is at ${destination.getAbsolutePath()}")
pres = destination
} else {
log.error("Error while renaming presentation from URL parameter to ${destination.getAbsolutePath()}, " +
"consider sending it through `/insertDocument`")
}
}
} else {
log.error("Null presentation directory meeting=[${meetingId}], presentationDir=[${presentationDir}], presId=[${presId}]")
uploadFailReasons.add("null_presentation_dir")
Expand Down