diff --git a/bigbluebutton-html5/imports/api/presentation-upload-token/server/handlers/presentationUploadTokenPass.js b/bigbluebutton-html5/imports/api/presentation-upload-token/server/handlers/presentationUploadTokenPass.js index ada7c2d43acb6024306249efc2ca161a25c8d49b..0859c5627ee31e93d33dbc06a50250f0128bd58a 100644 --- a/bigbluebutton-html5/imports/api/presentation-upload-token/server/handlers/presentationUploadTokenPass.js +++ b/bigbluebutton-html5/imports/api/presentation-upload-token/server/handlers/presentationUploadTokenPass.js @@ -27,6 +27,7 @@ export default function handlePresentationUploadTokenPass({ body, header }, meet filename, authzToken, failed: false, + used: false, }; const cb = (err) => { diff --git a/bigbluebutton-html5/imports/api/presentation-upload-token/server/methods.js b/bigbluebutton-html5/imports/api/presentation-upload-token/server/methods.js index 1666146edd206db9f9eaa5e57c94398797587424..d417f740c88d9797edbc9672b03a9ef7795d459c 100644 --- a/bigbluebutton-html5/imports/api/presentation-upload-token/server/methods.js +++ b/bigbluebutton-html5/imports/api/presentation-upload-token/server/methods.js @@ -1,6 +1,8 @@ import { Meteor } from 'meteor/meteor'; import requestPresentationUploadToken from './methods/requestPresentationUploadToken'; +import setUsedToken from './methods/setUsedToken'; Meteor.methods({ requestPresentationUploadToken, + setUsedToken, }); diff --git a/bigbluebutton-html5/imports/api/presentation-upload-token/server/methods/setUsedToken.js b/bigbluebutton-html5/imports/api/presentation-upload-token/server/methods/setUsedToken.js new file mode 100644 index 0000000000000000000000000000000000000000..a09c9d7c1f658c0198c7042a0d68f6e98450666c --- /dev/null +++ b/bigbluebutton-html5/imports/api/presentation-upload-token/server/methods/setUsedToken.js @@ -0,0 +1,30 @@ +import PresentationUploadToken from '/imports/api/presentation-upload-token'; +import Logger from '/imports/startup/server/logger'; +import { check } from 'meteor/check'; + +export default function setUsedToken(credentials, authzToken) { + const { meetingId, requesterUserId, requesterToken } = credentials; + check(meetingId, String); + check(requesterUserId, String); + check(requesterToken, String); + + const payload = { + $set: { + used: true, + }, + }; + const cb = (err) => { + if (err) { + Logger.error(`Unable to set token as used : ${err}`); + return; + } + + Logger.info(`Token: ${authzToken} has been set as used in meeting=${meetingId}`); + }; + + return PresentationUploadToken.update({ + meetingId, + userId: requesterUserId, + authzToken, + }, payload, cb); +} diff --git a/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/service.js b/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/service.js index a293d18d38cbb7557605629efd9e2c2d25b1432c..a6bd269f2a669ae91e8e49a343767b2f6504e586 100644 --- a/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/service.js +++ b/bigbluebutton-html5/imports/ui/components/presentation/presentation-uploader/service.js @@ -62,74 +62,90 @@ const dispatchTogglePresentationDownloadable = (presentation, newState) => { makeCall('setPresentationDownloadable', presentation.id, newState); }; -const observePresentationConversion = (meetingId, filename, onConversion) => - new Promise((resolve) => { - const conversionTimeout = setTimeout(() => { - onConversion({ - done: true, - error: true, - status: 'TIMEOUT', - }); - }, CONVERSION_TIMEOUT); +const observePresentationConversion = ( + meetingId, + filename, + onConversion, +) => new Promise((resolve) => { + const conversionTimeout = setTimeout(() => { + onConversion({ + done: true, + error: true, + status: 'TIMEOUT', + }); + }, CONVERSION_TIMEOUT); - const didValidate = (doc) => { - clearTimeout(conversionTimeout); - resolve(doc); - }; + const didValidate = (doc) => { + clearTimeout(conversionTimeout); + resolve(doc); + }; - Tracker.autorun((c) => { - const query = Presentations.find({ meetingId }); + Tracker.autorun((c) => { + const query = Presentations.find({ meetingId }); - query.observe({ - changed: (newDoc) => { - if (newDoc.name !== filename) return; + query.observe({ + changed: (newDoc) => { + if (newDoc.name !== filename) return; - onConversion(newDoc.conversion); + onConversion(newDoc.conversion); - if (newDoc.conversion.done) { - c.stop(); - didValidate(newDoc); - } - }, - }); + if (newDoc.conversion.done) { + c.stop(); + didValidate(newDoc); + } + }, }); }); +}); -const requestPresentationUploadToken = (podId, meetingId, filename) => - new Promise((resolve, reject) => { - makeCall('requestPresentationUploadToken', podId, filename); - - let computation = null; - const timeout = setTimeout(() => { - computation.stop(); - reject({ code: 408, message: 'requestPresentationUploadToken timeout' }); - }, TOKEN_TIMEOUT); - - Tracker.autorun((c) => { - computation = c; - const sub = Meteor.subscribe('presentation-upload-token', Auth.credentials, podId, filename); - if (!sub.ready()) return; - - const PresentationToken = PresentationUploadToken.findOne({ - podId, - meetingId, - filename, - }); +const requestPresentationUploadToken = ( + podId, + meetingId, + filename, +) => new Promise((resolve, reject) => { + makeCall('requestPresentationUploadToken', podId, filename); + + let computation = null; + const timeout = setTimeout(() => { + computation.stop(); + reject({ code: 408, message: 'requestPresentationUploadToken timeout' }); + }, TOKEN_TIMEOUT); + + Tracker.autorun((c) => { + computation = c; + const sub = Meteor.subscribe('presentation-upload-token', Auth.credentials, podId, filename); + if (!sub.ready()) return; + + const PresentationToken = PresentationUploadToken.findOne({ + podId, + meetingId, + filename, + used: false, + }); - if (!PresentationToken || !('failed' in PresentationToken)) return; + if (!PresentationToken || !('failed' in PresentationToken)) return; - if (!PresentationToken.failed) { - clearTimeout(timeout); - resolve(PresentationToken.authzToken); - } + if (!PresentationToken.failed) { + clearTimeout(timeout); + resolve(PresentationToken.authzToken); + } - if (PresentationToken.failed) { - reject({ code: 401, message: 'requestPresentationUploadToken failed' }); - } - }); + if (PresentationToken.failed) { + reject({ code: 401, message: `requestPresentationUploadToken token ${PresentationToken.authzToken} failed` }); + } }); +}); -const uploadAndConvertPresentation = (file, downloadable, podId, meetingId, endpoint, onUpload, onProgress, onConversion) => { +const uploadAndConvertPresentation = ( + file, + downloadable, + podId, + meetingId, + endpoint, + onUpload, + onProgress, + onConversion, +) => { const data = new FormData(); data.append('presentation_name', file.name); data.append('Filename', file.name); @@ -148,7 +164,10 @@ const uploadAndConvertPresentation = (file, downloadable, podId, meetingId, endp }; return requestPresentationUploadToken(podId, meetingId, file.name) - .then(token => futch(endpoint.replace('upload', `${token}/upload`), opts, onProgress)) + .then((token) => { + makeCall('setUsedToken', token); + return futch(endpoint.replace('upload', `${token}/upload`), opts, onProgress); + }) .then(() => observePresentationConversion(meetingId, file.name, onConversion)) // Trap the error so we can have parallel upload .catch((error) => { @@ -158,12 +177,15 @@ const uploadAndConvertPresentation = (file, downloadable, podId, meetingId, endp }); }; -const uploadAndConvertPresentations = (presentationsToUpload, meetingId, podId, uploadEndpoint) => - Promise.all(presentationsToUpload.map(p => - uploadAndConvertPresentation( - p.file, p.isDownloadable, podId, meetingId, uploadEndpoint, - p.onUpload, p.onProgress, p.onConversion, - ))); +const uploadAndConvertPresentations = ( + presentationsToUpload, + meetingId, + podId, + uploadEndpoint, +) => Promise.all(presentationsToUpload.map(p => uploadAndConvertPresentation( + p.file, p.isDownloadable, podId, meetingId, uploadEndpoint, + p.onUpload, p.onProgress, p.onConversion, +))); const setPresentation = (presentationId, podId) => makeCall('setPresentation', presentationId, podId); @@ -173,8 +195,10 @@ const removePresentation = (presentationId, podId) => { makeCall('removePresentation', presentationId, podId); }; -const removePresentations = (presentationsToRemove, podId) => - Promise.all(presentationsToRemove.map(p => removePresentation(p.id, podId))); +const removePresentations = ( + presentationsToRemove, + podId, +) => Promise.all(presentationsToRemove.map(p => removePresentation(p.id, podId))); const persistPresentationChanges = (oldState, newState, uploadEndpoint, podId) => { const presentationsToUpload = newState.filter(p => !p.upload.done);