Merge pull request #5651 from ritzalam/download-presentation

- toggle presentation downloads
This commit is contained in:
Richard Alam 2018-06-07 15:32:08 -04:00 committed by GitHub
commit 7dfe3f3093
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 168 additions and 75 deletions

View File

@ -16,20 +16,7 @@ trait PresentationConversionCompletedSysPubMsgHdlr {
liveMeeting: LiveMeeting, bus: MessageBus
): MeetingState2x = {
def broadcastPresentationConversionCompletedEvtMsg(podId: String, userId: String, messageKey: String,
code: String, presentation: PresentationVO): Unit = {
val routing = Routing.addMsgToClientRouting(
MessageTypes.BROADCAST_TO_MEETING,
liveMeeting.props.meetingProp.intId, userId
)
val envelope = BbbCoreEnvelope(PresentationConversionCompletedEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(PresentationConversionCompletedEvtMsg.NAME, liveMeeting.props.meetingProp.intId, userId)
val body = PresentationConversionCompletedEvtMsgBody(podId, messageKey, code, presentation)
val event = PresentationConversionCompletedEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
}
val meetingId = liveMeeting.props.meetingProp.intId
val pages = new collection.mutable.HashMap[String, PageVO]
@ -39,15 +26,20 @@ trait PresentationConversionCompletedSysPubMsgHdlr {
pages += page.id -> page
}
val pres = new PresentationInPod(msg.body.presentation.id, msg.body.presentation.name, msg.body.presentation.current,
pages.toMap, msg.body.presentation.downloadable)
val downloadable = msg.body.presentation.downloadable
val presentationId = msg.body.presentation.id
val pres = new PresentationInPod(presentationId, msg.body.presentation.name, msg.body.presentation.current,
pages.toMap, downloadable)
val presVO = PresentationPodsApp.translatePresentationToPresentationVO(pres)
val podId = msg.body.podId
val newState = for {
pod <- PresentationPodsApp.getPresentationPod(state, podId)
} yield {
broadcastPresentationConversionCompletedEvtMsg(pod.id, msg.header.userId, msg.body.messageKey, msg.body.code, presVO)
PresentationSender.broadcastPresentationConversionCompletedEvtMsg(bus, meetingId,
pod.id, msg.header.userId, msg.body.messageKey, msg.body.code, presVO)
PresentationSender.broadcastSetPresentationDownloadableEvtMsg(bus, meetingId, pod.id,
msg.header.userId, presentationId, downloadable, pres.name)
var pods = state.presentationPodManager.addPod(pod)
pods = pods.addPresentationToPod(pod.id, pres)

View File

@ -0,0 +1,47 @@
package org.bigbluebutton.core.apps.presentationpod
import org.bigbluebutton.common2.domain.PresentationVO
import org.bigbluebutton.common2.msgs._
import org.bigbluebutton.core.bus.MessageBus
object PresentationSender {
def broadcastSetPresentationDownloadableEvtMsg(
bus: MessageBus,
meetingId: String,
podId: String, userId: String,
presentationId: String,
downloadable: Boolean,
presFilename: String
): Unit = {
val routing = Routing.addMsgToClientRouting(
MessageTypes.BROADCAST_TO_MEETING,
meetingId, userId
)
val envelope = BbbCoreEnvelope(SetPresentationDownloadableEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(SetPresentationDownloadableEvtMsg.NAME, meetingId, userId)
val body = SetPresentationDownloadableEvtMsgBody(podId, presentationId, downloadable, presFilename)
val event = SetPresentationDownloadableEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
}
def broadcastPresentationConversionCompletedEvtMsg(
bus: MessageBus,
meetingId: String,
podId: String, userId: String, messageKey: String,
code: String, presentation: PresentationVO
): Unit = {
val routing = Routing.addMsgToClientRouting(
MessageTypes.BROADCAST_TO_MEETING,
meetingId, userId
)
val envelope = BbbCoreEnvelope(PresentationConversionCompletedEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(PresentationConversionCompletedEvtMsg.NAME, meetingId, userId)
val body = PresentationConversionCompletedEvtMsgBody(podId, messageKey, code, presentation)
val event = PresentationConversionCompletedEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
}
}

View File

@ -14,26 +14,14 @@ trait SetPresentationDownloadablePubMsgHdlr extends RightsManagementTrait {
liveMeeting: LiveMeeting, bus: MessageBus
): MeetingState2x = {
val meetingId = liveMeeting.props.meetingProp.intId
if (filterPresentationMessage(liveMeeting.users2x, msg.header.userId) &&
permissionFailed(PermissionCheck.GUEST_LEVEL, PermissionCheck.PRESENTER_LEVEL, liveMeeting.users2x, msg.header.userId)) {
val meetingId = liveMeeting.props.meetingProp.intId
val reason = "No permission to remove presentation from meeting."
PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
state
} else {
def broadcastSetPresentationDownloadableEvtMsg(podId: String, userId: String, presentationId: String, downloadable: Boolean): Unit = {
val routing = Routing.addMsgToClientRouting(
MessageTypes.BROADCAST_TO_MEETING,
liveMeeting.props.meetingProp.intId, userId
)
val envelope = BbbCoreEnvelope(SetPresentationDownloadableEvtMsg.NAME, routing)
val header = BbbClientMsgHeader(SetPresentationDownloadableEvtMsg.NAME, liveMeeting.props.meetingProp.intId, userId)
val body = SetPresentationDownloadableEvtMsgBody(podId, presentationId, downloadable)
val event = SetPresentationDownloadableEvtMsg(header, body)
val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
bus.outGW.send(msgEvent)
}
val podId = msg.body.podId
val presentationId = msg.body.presentationId
@ -41,8 +29,10 @@ trait SetPresentationDownloadablePubMsgHdlr extends RightsManagementTrait {
val newState = for {
pod <- PresentationPodsApp.getPresentationPod(state, podId)
pres <- pod.getPresentation(presentationId)
} yield {
broadcastSetPresentationDownloadableEvtMsg(pod.id, msg.header.userId, presentationId, downloadable)
PresentationSender.broadcastSetPresentationDownloadableEvtMsg(bus, meetingId, pod.id,
msg.header.userId, presentationId, downloadable, pres.name)
val pods = state.presentationPodManager.setPresentationDownloadableInPod(pod.id, presentationId, downloadable)
state.update(pods)

View File

@ -75,8 +75,6 @@ class FromAkkaAppsMsgSenderActor(msgSender: MessageSender)
msgSender.send(fromAkkaAppsPresRedisChannel, json)
case RemovePresentationEvtMsg.NAME =>
msgSender.send(fromAkkaAppsPresRedisChannel, json)
case SetPresentationDownloadableEvtMsg.NAME =>
msgSender.send(fromAkkaAppsPresRedisChannel, json)
case SetCurrentPresentationEvtMsg.NAME =>
msgSender.send(fromAkkaAppsPresRedisChannel, json)

View File

@ -129,7 +129,7 @@ case class RemovePresentationEvtMsgBody(podId: String, presentationId: String)
object SetPresentationDownloadableEvtMsg { val NAME = "SetPresentationDownloadableEvtMsg"}
case class SetPresentationDownloadableEvtMsg(header: BbbClientMsgHeader, body: SetPresentationDownloadableEvtMsgBody) extends BbbCoreMsg
case class SetPresentationDownloadableEvtMsgBody(podId: String, presentationId: String, downloadable: Boolean)
case class SetPresentationDownloadableEvtMsgBody(podId: String, presentationId: String, downloadable: Boolean, presFilename: String)
object ResizeAndMovePageEvtMsg { val NAME = "ResizeAndMovePageEvtMsg"}
case class ResizeAndMovePageEvtMsg(header: BbbClientMsgHeader, body: ResizeAndMovePageEvtMsgBody) extends BbbCoreMsg

View File

@ -18,6 +18,7 @@
package org.bigbluebutton.api;
import java.io.File;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
@ -856,6 +857,8 @@ public class MeetingService implements MessageListener {
processGuestPolicyChanged((GuestPolicyChanged) message);
} else if (message instanceof RecordChapterBreak) {
processRecordingChapterBreak((RecordChapterBreak) message);
} else if (message instanceof MakePresentationDownloadableMsg) {
processMakePresentationDownloadableMsg((MakePresentationDownloadableMsg) message);
}
}
};
@ -874,6 +877,14 @@ public class MeetingService implements MessageListener {
recordingService.kickOffRecordingChapterBreak(msg.meetingId, msg.timestamp);
}
private void processMakePresentationDownloadableMsg(MakePresentationDownloadableMsg msg) {
recordingService.processMakePresentationDownloadableMsg(msg);
}
public File getDownloadablePresentationFile(String meetingId, String presId, String presFilename) {
return recordingService.getDownloadablePresentationFile(meetingId, presId, presFilename);
}
public void start() {
log.info("Starting Meeting Service.");
try {

View File

@ -36,6 +36,7 @@ import java.util.Set;
import org.apache.commons.io.FileUtils;
import org.bigbluebutton.api.domain.Recording;
import org.bigbluebutton.api.domain.RecordingMetadata;
import org.bigbluebutton.api.messaging.messages.MakePresentationDownloadableMsg;
import org.bigbluebutton.api.util.RecordingMetadataReaderHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -49,6 +50,41 @@ public class RecordingService {
private String deletedDir = "/var/bigbluebutton/deleted";
private RecordingMetadataReaderHelper recordingServiceHelper;
private String recordStatusDir;
private String presentationBaseDir;
private void copyPresentationFile(File presFile, File dlownloadableFile) {
try {
FileUtils.copyFile(presFile, dlownloadableFile);
} catch (IOException ex) {
log.error("Failed to copy file: " + ex);
}
}
public void processMakePresentationDownloadableMsg(MakePresentationDownloadableMsg msg) {
File presDir = Util.getPresentationDir(presentationBaseDir, msg.meetingId, msg.presId);
File downloadableFile = new File(presDir.getAbsolutePath() + File.separatorChar + msg.presFilename);
if (presDir != null) {
if (msg.downloadable) {
File presFile = new File(presDir.getAbsolutePath() + File.separatorChar + msg.presId + ".pdf");
copyPresentationFile(presFile, downloadableFile);
} else {
if (downloadableFile.exists()) {
if(downloadableFile.delete()) {
log.info("File deleted. {}", downloadableFile.getAbsolutePath());
} else {
log.warn("Failed to delete. {}", downloadableFile.getAbsolutePath());
}
}
}
}
}
public File getDownloadablePresentationFile(String meetingId, String presId, String presFilename) {
File presDir = Util.getPresentationDir(presentationBaseDir, meetingId, presId);
File downloadableFile = new File(presDir.getAbsolutePath() + File.separatorChar + presFilename);
return downloadableFile;
}
public void kickOffRecordingChapterBreak(String meetingId, Long timestamp) {
String done = recordStatusDir + "/" + meetingId + "-" + timestamp + ".done";
@ -287,6 +323,10 @@ public class RecordingService {
unpublishedDir = dir;
}
public void setPresentationBaseDir(String dir) {
presentationBaseDir = dir;
}
public void setPublishedDir(String dir) {
publishedDir = dir;
}

View File

@ -14,7 +14,7 @@ public final class Util {
return presId + "." + fileExt;
}
public static File createPresentationDirectory(String meetingId, String presentationDir, String presentationId) {
public static File createPresentationDir(String meetingId, String presentationDir, String presentationId) {
String meetingPath = presentationDir + File.separatorChar + meetingId + File.separatorChar + meetingId;
String presPath = meetingPath + File.separatorChar + presentationId;
File dir = new File(presPath);
@ -24,11 +24,14 @@ public final class Util {
return null;
}
public static File downloadPresentationDirectory(String uploadDirectory) {
File dir = new File(uploadDirectory + File.separatorChar + "download");
if (dir.mkdirs()) {
public static File getPresentationDir(String presentationBaseDir, String meetingId, String presentationId) {
String meetingPath = presentationBaseDir + File.separatorChar + meetingId + File.separatorChar + meetingId;
String presPath = meetingPath + File.separatorChar + presentationId;
File dir = new File(presPath);
if (dir.exists()) {
return dir;
}
return null;
}
}

View File

@ -0,0 +1,15 @@
package org.bigbluebutton.api.messaging.messages;
public class MakePresentationDownloadableMsg implements IMessage {
public final String meetingId;
public final String presId;
public final String presFilename;
public final Boolean downloadable;
public MakePresentationDownloadableMsg(String meetingId, String presId, String presFilename, Boolean downloadable) {
this.meetingId = meetingId;
this.presId = presId;
this.presFilename = presFilename;
this.downloadable = downloadable;
}
}

View File

@ -93,6 +93,8 @@ class ReceivedJsonMsgHdlrActor(val msgFromAkkaAppsEventBus: MsgFromAkkaAppsEvent
route[GuestPolicyChangedEvtMsg](envelope, jsonNode)
case RecordingChapterBreakSysMsg.NAME =>
route[RecordingChapterBreakSysMsg](envelope, jsonNode)
case SetPresentationDownloadableEvtMsg.NAME =>
route[SetPresentationDownloadableEvtMsg](envelope, jsonNode)
case _ =>
//log.debug("************ Cannot route envelope name " + envelope.name)
// do nothing

View File

@ -41,7 +41,7 @@ class OldMeetingMsgHdlrActor(val olgMsgGW: OldMessageReceivedGW)
case m: GuestsWaitingApprovedEvtMsg => handleGuestsWaitingApprovedEvtMsg(m)
case m: GuestPolicyChangedEvtMsg => handleGuestPolicyChangedEvtMsg(m)
case m: RecordingChapterBreakSysMsg => handleRecordingChapterBreakSysMsg(m)
case m: SetPresentationDownloadableEvtMsg => handleSetPresentationDownloadableEvtMsg(m)
case _ => log.error("***** Cannot handle " + msg.envelope.name)
}
}
@ -140,4 +140,14 @@ class OldMeetingMsgHdlrActor(val olgMsgGW: OldMessageReceivedGW)
val m = new GuestStatusChangedEventMsg(msg.header.meetingId, u)
olgMsgGW.handle(m)
}
def handleSetPresentationDownloadableEvtMsg(msg: SetPresentationDownloadableEvtMsg): Unit = {
val meetingId = msg.header.meetingId
val presId = msg.body.presentationId
val downloadable = msg.body.downloadable
val presFilename = msg.body.presFilename
val m = new MakePresentationDownloadableMsg(meetingId, presId, presFilename, downloadable)
olgMsgGW.handle(m)
}
}

View File

@ -198,8 +198,9 @@ package org.bigbluebutton.modules.present.business
*
*/
public function startDownload(e:DownloadEvent):void {
var presentationName:String = e.fileNameToDownload;
var downloadUri:String = host + "/bigbluebutton/presentation/" + conference + "/" + room + "/" + presentationName + "/download";
var presFilename:String = e.presFilename;
var presId:String = e.presId
var downloadUri:String = host + "/bigbluebutton/presentation/download/" + room + "/" + presId + "/" + presFilename;
LOGGER.debug("PresentationApplication::downloadPresentation()... " + downloadUri);
var req:URLRequest = new URLRequest(downloadUri);
navigateToURL(req,"_blank");

View File

@ -25,7 +25,8 @@ package org.bigbluebutton.modules.present.events
public static const CLOSE_DOWNLOAD_WINDOW:String = "CLOSE_DOWNLOAD_WINDOW";
public static const DOWNLOAD_PRESENTATION:String = "DOWNLOAD_PRESENTATION";
public var fileNameToDownload:String;
public var presFilename:String;
public var presId:String;
public var podId:String;
public function DownloadEvent(type:String) {

View File

@ -13,7 +13,8 @@
private function downloadPresentation():void {
var downloadEvent:DownloadEvent = new DownloadEvent(DownloadEvent.DOWNLOAD_PRESENTATION);
downloadEvent.fileNameToDownload = data.id as String;
downloadEvent.presId = data.id as String;
downloadEvent.presFilename = data.name as String;
globalDispatch.dispatchEvent(downloadEvent);
}
]]>

View File

@ -49,7 +49,7 @@ class UrlMappings {
action = [GET:'showTextfile']
}
"/presentation/$conference/$room/$presentation_name/download"(controller:"presentation") {
"/presentation/download/$meetingId/$presId/$presFilename"(controller:"presentation") {
action = [GET:'downloadFile']
}

View File

@ -99,6 +99,7 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<property name="publishedDir" value="${publishedDir}"/>
<property name="unpublishedDir" value="${unpublishedDir}"/>
<property name="recordingServiceHelper" ref="recordingServiceHelper"/>
<property name="presentationBaseDir" value="${presentationDir}"/>
</bean>
<bean id="configServiceHelper" class="org.bigbluebutton.api.ClientConfigServiceHelperImp"/>

View File

@ -93,7 +93,7 @@ class PresentationController {
def filenameExt = FilenameUtils.getExtension(presFilename);
String presentationDir = presentationService.getPresentationDir()
def presId = Util.generatePresentationId(presFilename)
File uploadDir = Util.createPresentationDirectory(meetingId, presentationDir, presId)
File uploadDir = Util.createPresentationDir(meetingId, presentationDir, presId)
if (uploadDir != null) {
def newFilename = Util.createNewFilename(presId, filenameExt)
@ -102,18 +102,6 @@ class PresentationController {
def isDownloadable = params.boolean('is_downloadable') //instead of params.is_downloadable
def podId = params.pod_id
log.debug "@AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA..." + podId
if(isDownloadable) {
log.debug "@Creating download directory..."
File downloadDir = Util.downloadPresentationDirectory(uploadDir.absolutePath)
if (downloadDir != null) {
def notValidCharsRegExp = /[^0-9a-zA-Z_\.]/
def downloadableFileName = presFilename.replaceAll(notValidCharsRegExp, '-')
def downloadableFile = new File( downloadDir.absolutePath + File.separatorChar + downloadableFileName )
downloadableFile << pres.newInputStream()
}
}
def presentationBaseUrl = presentationService.presentationBaseUrl
UploadedPresentation uploadedPres = new UploadedPresentation(podId, meetingId, presId,
@ -276,16 +264,18 @@ class PresentationController {
}
def downloadFile = {
def presentationName = params.presentation_name
def conf = params.conference
def rm = params.room
println "Controller: Download request for $presentationName"
def presId = params.presId
def presFilename = params.presFilename
def meetingId = params.meetingId
log.debug "Controller: Download request for $presFilename"
String presentationDir = presentationService.getPresentationDir()
InputStream is = null;
try {
def pres = presentationService.getFile(conf, rm, presentationName)
def pres = meetingService.getDownloadablePresentationFile(meetingId, presId, presFilename)
if (pres.exists()) {
println "Controller: Sending pdf reply for $presentationName"
log.debug "Controller: Sending pdf reply for $presFilename"
def bytes = pres.readBytes()
def responseName = pres.getName();
@ -293,10 +283,10 @@ class PresentationController {
response.addHeader("Cache-Control", "no-cache")
response.outputStream << bytes;
} else {
println "$pres does not exist."
log.warn "$pres does not exist."
}
} catch (IOException e) {
println("Error reading file.\n" + e.getMessage());
log.error("Error reading file.\n" + e.getMessage());
}
return null;

View File

@ -168,15 +168,6 @@ class PresentationService {
}
def getFile = {conf, room, presentationName ->
println "download request for $presentationName"
def fileDirectory = new File(roomDirectory(conf, room).absolutePath + File.separatorChar + presentationName + File.separatorChar +
"download")
//list the files of the download directory ; it must have only 1 file to download
def list = fileDirectory.listFiles()
//new File(pdfFile)
list[0]
}
}
/*** Helper classes **/