From 1df46bb201d506af6949af8699995d67086985d9 Mon Sep 17 00:00:00 2001
From: Oswaldo Acauan <oswaldoacauan@gmail.com>
Date: Fri, 11 Nov 2016 19:02:46 +0000
Subject: [PATCH] Refactor of Presentations API

---
 .../server/modifiers/clearMeetings.js         |  9 +-
 .../server/modifiers/removeMeeting.js         |  9 +-
 .../api/presentations/server/eventHandlers.js |  8 ++
 .../server/handlers/presentationChange.js     | 44 +++++++++
 .../server/handlers/presentationInfoReply.js  | 24 +++++
 .../server/handlers/presentationRemove.js     | 14 +++
 .../imports/api/presentations/server/index.js |  3 +
 .../api/presentations/server/methods.js       |  4 +
 .../server/modifiers/addPresentation.js       | 55 +++++++++++
 .../modifiers/addPresentationToCollection.js  | 23 -----
 .../modifiers/changeCurrentPresentation.js    | 53 ++++++++++
 .../server/modifiers/clearPresentations.js    | 11 +++
 .../modifiers/clearPresentationsCollection.js | 14 ---
 .../server/modifiers/eventHandlers.js         | 96 -------------------
 .../server/modifiers/removePresentation.js    | 28 ++++++
 .../removePresentationFromCollection.js       | 17 ----
 .../api/presentations/server/publications.js  | 10 --
 .../api/presentations/server/publishers.js    | 22 +++++
 .../{addSlideToCollection.js => addSlide.js}  | 55 ++++++++---
 .../server/modifiers/changeCurrentSlide.js    |  6 +-
 ...learSlidesCollection.js => clearSlides.js} |  2 +-
 .../modifiers/clearSlidesPresentation.js      |  4 +-
 .../slides/server/modifiers/resizeSlide.js    | 16 ++--
 .../imports/api/slides/server/publishers.js   |  2 +-
 .../ui/components/whiteboard/container.jsx    | 10 +-
 .../ui/components/whiteboard/service.js       | 69 +++++++------
 bigbluebutton-html5/server/main.js            |  6 +-
 27 files changed, 372 insertions(+), 242 deletions(-)
 create mode 100644 bigbluebutton-html5/imports/api/presentations/server/eventHandlers.js
 create mode 100644 bigbluebutton-html5/imports/api/presentations/server/handlers/presentationChange.js
 create mode 100644 bigbluebutton-html5/imports/api/presentations/server/handlers/presentationInfoReply.js
 create mode 100644 bigbluebutton-html5/imports/api/presentations/server/handlers/presentationRemove.js
 create mode 100644 bigbluebutton-html5/imports/api/presentations/server/index.js
 create mode 100644 bigbluebutton-html5/imports/api/presentations/server/methods.js
 create mode 100755 bigbluebutton-html5/imports/api/presentations/server/modifiers/addPresentation.js
 delete mode 100755 bigbluebutton-html5/imports/api/presentations/server/modifiers/addPresentationToCollection.js
 create mode 100644 bigbluebutton-html5/imports/api/presentations/server/modifiers/changeCurrentPresentation.js
 create mode 100755 bigbluebutton-html5/imports/api/presentations/server/modifiers/clearPresentations.js
 delete mode 100755 bigbluebutton-html5/imports/api/presentations/server/modifiers/clearPresentationsCollection.js
 delete mode 100755 bigbluebutton-html5/imports/api/presentations/server/modifiers/eventHandlers.js
 create mode 100644 bigbluebutton-html5/imports/api/presentations/server/modifiers/removePresentation.js
 delete mode 100755 bigbluebutton-html5/imports/api/presentations/server/modifiers/removePresentationFromCollection.js
 delete mode 100755 bigbluebutton-html5/imports/api/presentations/server/publications.js
 create mode 100644 bigbluebutton-html5/imports/api/presentations/server/publishers.js
 rename bigbluebutton-html5/imports/api/slides/server/modifiers/{addSlideToCollection.js => addSlide.js} (52%)
 rename bigbluebutton-html5/imports/api/slides/server/modifiers/{clearSlidesCollection.js => clearSlides.js} (83%)

diff --git a/bigbluebutton-html5/imports/api/meetings/server/modifiers/clearMeetings.js b/bigbluebutton-html5/imports/api/meetings/server/modifiers/clearMeetings.js
index 627b149114..65e2e45fdc 100755
--- a/bigbluebutton-html5/imports/api/meetings/server/modifiers/clearMeetings.js
+++ b/bigbluebutton-html5/imports/api/meetings/server/modifiers/clearMeetings.js
@@ -5,13 +5,12 @@ import removeMeeting from './removeMeeting';
 import { clearUsersCollection } from '/imports/api/users/server/modifiers/clearUsersCollection';
 import clearChats from '/imports/api/chat/server/modifiers/clearChats';
 import { clearShapesCollection } from '/imports/api/shapes/server/modifiers/clearShapesCollection';
-import { clearSlidesCollection } from '/imports/api/slides/server/modifiers/clearSlidesCollection';
+import clearSlides from '/imports/api/slides/server/modifiers/clearSlides';
 import { clearPollCollection } from '/imports/api/polls/server/modifiers/clearPollCollection';
 import { clearCursorCollection } from '/imports/api/cursor/server/modifiers/clearCursorCollection';
 import { clearCaptionsCollection }
   from '/imports/api/captions/server/modifiers/clearCaptionsCollection';
-import { clearPresentationsCollection }
-  from '/imports/api/presentations/server/modifiers/clearPresentationsCollection';
+import clearPresentations from '/imports/api/presentations/server/modifiers/clearPresentations';
 
 export default function clearMeetings() {
   return Meetings.remove({}, (err) => {
@@ -19,9 +18,9 @@ export default function clearMeetings() {
     clearChats();
     clearCursorCollection();
     clearPollCollection();
-    clearPresentationsCollection();
+    clearPresentations();
     clearShapesCollection();
-    clearSlidesCollection();
+    clearSlides();
     clearUsersCollection();
 
     return Logger.info('Cleared Meetings (all)');
diff --git a/bigbluebutton-html5/imports/api/meetings/server/modifiers/removeMeeting.js b/bigbluebutton-html5/imports/api/meetings/server/modifiers/removeMeeting.js
index 2fc7118f68..d3379a15f9 100755
--- a/bigbluebutton-html5/imports/api/meetings/server/modifiers/removeMeeting.js
+++ b/bigbluebutton-html5/imports/api/meetings/server/modifiers/removeMeeting.js
@@ -5,13 +5,12 @@ import Logger from '/imports/startup/server/logger';
 import { clearUsersCollection } from '/imports/api/users/server/modifiers/clearUsersCollection';
 import clearChats from '/imports/api/chat/server/modifiers/clearChats';
 import { clearShapesCollection } from '/imports/api/shapes/server/modifiers/clearShapesCollection';
-import { clearSlidesCollection } from '/imports/api/slides/server/modifiers/clearSlidesCollection';
+import clearSlides from '/imports/api/slides/server/modifiers/clearSlides';
 import { clearPollCollection } from '/imports/api/polls/server/modifiers/clearPollCollection';
 import { clearCursorCollection } from '/imports/api/cursor/server/modifiers/clearCursorCollection';
 import { clearCaptionsCollection }
   from '/imports/api/captions/server/modifiers/clearCaptionsCollection';
-import { clearPresentationsCollection }
-  from '/imports/api/presentations/server/modifiers/clearPresentationsCollection';
+import clearPresentations from '/imports/api/presentations/server/modifiers/clearPresentations';
 
 export default function removeMeeting(meetingId) {
   check(meetingId, String);
@@ -30,9 +29,9 @@ export default function removeMeeting(meetingId) {
       clearChats(meetingId);
       clearCursorCollection(meetingId);
       clearPollCollection(meetingId);
-      clearPresentationsCollection(meetingId);
+      clearPresentations(meetingId);
       clearShapesCollection(meetingId);
-      clearSlidesCollection(meetingId);
+      clearSlides(meetingId);
       clearUsersCollection(meetingId);
 
       return Logger.info(`Removed meeting id=${meetingId}`);
diff --git a/bigbluebutton-html5/imports/api/presentations/server/eventHandlers.js b/bigbluebutton-html5/imports/api/presentations/server/eventHandlers.js
new file mode 100644
index 0000000000..aebbffb09b
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/presentations/server/eventHandlers.js
@@ -0,0 +1,8 @@
+import RedisPubSub from '/imports/startup/server/redis';
+import handlePresentationRemove from './handlers/presentationRemove';
+import handlePresentationChange from './handlers/presentationChange';
+import handlePresentationInfoReply from './handlers/presentationInfoReply';
+
+RedisPubSub.on('presentation_removed_message', handlePresentationRemove);
+RedisPubSub.on('presentation_shared_message', handlePresentationChange);
+RedisPubSub.on('get_presentation_info_reply', handlePresentationInfoReply);
diff --git a/bigbluebutton-html5/imports/api/presentations/server/handlers/presentationChange.js b/bigbluebutton-html5/imports/api/presentations/server/handlers/presentationChange.js
new file mode 100644
index 0000000000..3c1731aa1d
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/presentations/server/handlers/presentationChange.js
@@ -0,0 +1,44 @@
+import { check } from 'meteor/check';
+import Logger from '/imports/startup/server/logger';
+import Presentations from '/imports/api/presentations';
+
+import addPresentation from '../modifiers/addPresentation';
+
+const clearCurrentPresentation = (meetingId, presentationId) => {
+  let selector = {
+    meetingId,
+    presentationId: { $ne: presentationId },
+    'presentation.current': true,
+  };
+
+  let modifier = {
+    $set: { 'presentation.current': false },
+  };
+
+  let cb = (err, numChanged) => {
+    if (err) {
+      return Logger.error(`Unsetting the current presentation: ${err}`);
+    }
+
+    if (numChanged) {
+      return Logger.info(`Unsetted as current presentation`);
+    }
+  };
+
+  return Presentations.update(selector, modifier, cb);
+};
+
+export default function handlePresentationChange({ payload }) {
+  const meetingId = payload.meeting_id;
+  const presentation = payload.presentation;
+
+  check(meetingId, String);
+  check(presentation, Object);
+
+  // We need to clear the flag of the older current presentation ¯\_(ツ)_/¯
+  if (presentation.current) {
+    clearCurrentPresentation(meetingId, presentation.id);
+  }
+
+  return addPresentation(meetingId, presentation);
+};
diff --git a/bigbluebutton-html5/imports/api/presentations/server/handlers/presentationInfoReply.js b/bigbluebutton-html5/imports/api/presentations/server/handlers/presentationInfoReply.js
new file mode 100644
index 0000000000..0b42afd2db
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/presentations/server/handlers/presentationInfoReply.js
@@ -0,0 +1,24 @@
+import Logger from '/imports/startup/server/logger';
+import { check } from 'meteor/check';
+import { inReplyToHTML5Client } from '/imports/api/common/server/helpers';
+
+import addPresentation from '../modifiers/addPresentation';
+
+export default function handlePresentationInfoReply({ payload }) {
+  if (!inReplyToHTML5Client({ payload })) {
+    return;
+  }
+
+  const meetingId = payload.meeting_id;
+  const presentations = payload.presentations;
+
+  check(meetingId, String);
+  check(presentations, Array);
+
+  let presentationsAdded = [];
+  presentations.forEach(presentation => {
+    presentationsAdded.push(addPresentation(meetingId, presentation));
+  });
+
+  return presentationsAdded;
+};
diff --git a/bigbluebutton-html5/imports/api/presentations/server/handlers/presentationRemove.js b/bigbluebutton-html5/imports/api/presentations/server/handlers/presentationRemove.js
new file mode 100644
index 0000000000..ba589c6484
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/presentations/server/handlers/presentationRemove.js
@@ -0,0 +1,14 @@
+import Logger from '/imports/startup/server/logger';
+import { check } from 'meteor/check';
+
+import removePresentation from '../modifiers/removePresentation';
+
+export default function handlePresentationRemove({ payload }) {
+  const meetingId = payload.meeting_id;
+  const presentationId = payload.presentation_id;
+
+  check(meetingId, String);
+  check(presentationId, String);
+
+  return removePresentation(meetingId, presentationId);
+};
diff --git a/bigbluebutton-html5/imports/api/presentations/server/index.js b/bigbluebutton-html5/imports/api/presentations/server/index.js
new file mode 100644
index 0000000000..92451ac76b
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/presentations/server/index.js
@@ -0,0 +1,3 @@
+import './eventHandlers';
+import './methods';
+import './publishers';
diff --git a/bigbluebutton-html5/imports/api/presentations/server/methods.js b/bigbluebutton-html5/imports/api/presentations/server/methods.js
new file mode 100644
index 0000000000..1ce65c3698
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/presentations/server/methods.js
@@ -0,0 +1,4 @@
+import { Meteor } from 'meteor/meteor';
+
+Meteor.methods({
+});
diff --git a/bigbluebutton-html5/imports/api/presentations/server/modifiers/addPresentation.js b/bigbluebutton-html5/imports/api/presentations/server/modifiers/addPresentation.js
new file mode 100755
index 0000000000..e87c110988
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/presentations/server/modifiers/addPresentation.js
@@ -0,0 +1,55 @@
+import { check } from 'meteor/check';
+import Presentations from '/imports/api/presentations';
+import Logger from '/imports/startup/server/logger';
+
+import addSlide from '/imports/api/slides/server/modifiers/addSlide';
+
+const addSlides = (meetingId, presentationId, slides) => {
+  let slidesAdded = [];
+
+  slides.forEach(slide => {
+    slidesAdded.push(addSlide(meetingId, presentationId, slide));
+  });
+
+  return slidesAdded;
+};
+
+export default function addPresentation(meetingId, presentation) {
+  check(meetingId, String);
+  check(presentation, Object);
+
+  const selector = {
+    meetingId,
+    'presentation.id': presentation.id,
+  };
+
+  const modifier = {
+    $set: {
+      meetingId,
+      presentation: {
+        id: presentation.id,
+        name: presentation.name,
+        current: presentation.current,
+      },
+    },
+  };
+
+  const cb = (err, numChanged) => {
+    if (err) {
+      return Logger.error(`Adding presentation to collection: ${err}`);
+    }
+
+    addSlides(meetingId, presentation.id, presentation.pages);
+
+    const { insertedId } = numChanged;
+    if (insertedId) {
+      return Logger.info(`Added presentation id=${presentation.id} meeting=${meetingId}`);
+    }
+
+    if (numChanged) {
+      return Logger.info(`Upserted presentation id=${presentation.id} meeting=${meetingId}`);
+    }
+  };
+
+  return Presentations.upsert(selector, modifier, cb);
+};
diff --git a/bigbluebutton-html5/imports/api/presentations/server/modifiers/addPresentationToCollection.js b/bigbluebutton-html5/imports/api/presentations/server/modifiers/addPresentationToCollection.js
deleted file mode 100755
index 7ee32531da..0000000000
--- a/bigbluebutton-html5/imports/api/presentations/server/modifiers/addPresentationToCollection.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import Presentations from '/imports/api/presentations';
-
-export function addPresentationToCollection(meetingId, presentationObject) {
-  //check if the presentation is already in the collection
-  const presentationObj = Presentations.findOne({
-    meetingId: meetingId,
-    'presentation.id': presentationObject.id,
-  });
-  if (presentationObj == null) {
-    const entry = {
-      meetingId: meetingId,
-      presentation: {
-        id: presentationObject.id,
-        name: presentationObject.name,
-        current: presentationObject.current,
-      },
-    };
-    return Presentations.insert(entry);
-
-    //logger.info "presentation added id =[#{id}]:#{presentationObject.id} in #{meetingId}.
-    // Presentations.size is now #{Presentations.find({meetingId: meetingId}).count()}"
-  }
-};
diff --git a/bigbluebutton-html5/imports/api/presentations/server/modifiers/changeCurrentPresentation.js b/bigbluebutton-html5/imports/api/presentations/server/modifiers/changeCurrentPresentation.js
new file mode 100644
index 0000000000..8657e563aa
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/presentations/server/modifiers/changeCurrentPresentation.js
@@ -0,0 +1,53 @@
+import { check } from 'meteor/check';
+import Presentations from '/imports/api/presentations';
+import Logger from '/imports/startup/server/logger';
+
+export default function changeCurrentPresentation(meetingId, presentationId) {
+  check(meetingId, String);
+  check(presentationId, String);
+
+  const oldCurrent = {
+    selector: {
+      meetingId,
+      'presentation.current': true,
+    },
+    modifier: {
+      $set: { 'presentation.current': false },
+    },
+    callback: (err) => {
+      if (err) {
+        return Logger.error(`Unsetting the current presentation: ${err}`);
+      }
+
+      return Logger.info(`Unsetted as current presentation`);
+    },
+  };
+
+  const newCurrent = {
+    selector: {
+      meetingId,
+      'presentation.id': presentationId,
+    },
+    modifier: {
+      $set: { 'presentation.current': true },
+    },
+    callback: (err) => {
+      if (err) {
+        return Logger.error(`Setting as current presentation id=${presentationId}: ${err}`);
+      }
+
+      return Logger.info(`Setted as current presentation id=${presentationId}`);
+    },
+  };
+
+  const oldPresentation = Presentations.findOne(oldCurrent.selector);
+  const newPresentation = Presentations.findOne(newCurrent.selector);
+
+  if (newPresentation) {
+    Presentations.update(newPresentation._id, newCurrent.modifier, newCurrent.callback);
+  }
+
+  if (oldPresentation) {
+    Presentations.update(oldPresentation._id, oldCurrent.modifier, oldCurrent.callback);
+  }
+};
diff --git a/bigbluebutton-html5/imports/api/presentations/server/modifiers/clearPresentations.js b/bigbluebutton-html5/imports/api/presentations/server/modifiers/clearPresentations.js
new file mode 100755
index 0000000000..4301e51856
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/presentations/server/modifiers/clearPresentations.js
@@ -0,0 +1,11 @@
+import Presentations from '/imports/api/slides';
+import Logger from '/imports/startup/server/logger';
+
+export default function clearPresentations(meetingId) {
+  if (meetingId) {
+    return Presentations.remove({ meetingId: meetingId },
+      Logger.info(`Cleared Presentations (${meetingId})`));
+  } else {
+    return Presentations.remove({}, Logger.info('Cleared Presentations (all)'));
+  }
+};
diff --git a/bigbluebutton-html5/imports/api/presentations/server/modifiers/clearPresentationsCollection.js b/bigbluebutton-html5/imports/api/presentations/server/modifiers/clearPresentationsCollection.js
deleted file mode 100755
index 2fb5af1d18..0000000000
--- a/bigbluebutton-html5/imports/api/presentations/server/modifiers/clearPresentationsCollection.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import Presentations from '/imports/api/presentations';
-import { logger } from '/imports/startup/server/logger';
-
-// called on server start and meeting end
-export function clearPresentationsCollection() {
-  const meetingId = arguments[0];
-  if (meetingId != null) {
-    return Presentations.remove({
-      meetingId: meetingId,
-    }, logger.info(`cleared Presentations Collection (meetingId: ${meetingId}!`));
-  } else {
-    return Presentations.remove({}, logger.info('cleared Presentations Collection(all meetings)!'));
-  }
-};
diff --git a/bigbluebutton-html5/imports/api/presentations/server/modifiers/eventHandlers.js b/bigbluebutton-html5/imports/api/presentations/server/modifiers/eventHandlers.js
deleted file mode 100755
index 1808939f76..0000000000
--- a/bigbluebutton-html5/imports/api/presentations/server/modifiers/eventHandlers.js
+++ /dev/null
@@ -1,96 +0,0 @@
-import { eventEmitter } from '/imports/startup/server';
-import { removePresentationFromCollection } from './removePresentationFromCollection';
-import { addPresentationToCollection } from './addPresentationToCollection';
-import { appendMessageHeader, publish, inReplyToHTML5Client }
-  from '/imports/api/common/server/helpers';
-import addSlideToCollection from '/imports/api/slides/server/modifiers/addSlideToCollection';
-import Slides from '/imports/api/slides';
-import Presentations from '/imports/api/presentations';
-import { logger } from '/imports/startup/server/logger';
-
-eventEmitter.on('presentation_removed_message', function (arg) {
-  const meetingId = arg.payload.meeting_id;
-  const presentationId = arg.payload.presentation_id;
-  if (meetingId != null && presentationId != null) {
-    removePresentationFromCollection(meetingId, presentationId);
-  }
-
-  return arg.callback();
-});
-
-eventEmitter.on('presentation_shared_message', function (arg) {
-  const payload = arg.payload;
-  const meetingId = payload.meeting_id;
-  if (payload.presentation != null && payload.presentation.id != null && meetingId != null) {
-    const presentationId = payload.presentation.id;
-
-    // change the currently displayed presentation to presentation.current = false
-    Presentations.update({
-      'presentation.current': true,
-      meetingId: meetingId,
-    }, {
-      $set: {
-        'presentation.current': false,
-      },
-    });
-
-    //update(if already present) entirely the presentation with the fresh data
-    removePresentationFromCollection(meetingId, presentationId);
-    addPresentationToCollection(meetingId, payload.presentation);
-    const pages = payload.presentation.pages;
-    for (j = 0; j < pages.length; j++) {
-      const slide = pages[j];
-      addSlideToCollection(
-        meetingId,
-        presentationId,
-        slide
-      );
-    }
-  }
-
-  return arg.callback();
-});
-
-eventEmitter.on('get_presentation_info_reply', function (arg) {
-  const REDIS_CONFIG = Meteor.settings.redis;
-
-  if (inReplyToHTML5Client(arg)) {
-    const payload = arg.payload;
-    const meetingId = payload.meeting_id;
-    const presentations = payload.presentations;
-    for (let k = 0; k < payload.presentations.length; k++) {
-      const presentation = presentations[k];
-      addPresentationToCollection(meetingId, presentation);
-      const pages = presentation.pages;
-      for (let l = 0; l < pages.length; l++) {
-        const page = pages[l];
-
-        //add the slide to the collection
-        addSlideToCollection(meetingId, presentation.id, page);
-
-        //request for shapes
-        const whiteboardId = `${presentation.id}/${page.num}`;
-
-        //logger.info "the whiteboard_id here is:" + whiteboardId
-
-        const replyTo = `${meetingId}/nodeJSapp`;
-        let message = {
-          payload: {
-            meeting_id: meetingId,
-            requester_id: 'nodeJSapp',
-            whiteboard_id: whiteboardId,
-            reply_to: replyTo,
-          },
-        };
-        if (!!whiteboardId && !!meetingId) {
-          message = appendMessageHeader('request_whiteboard_annotation_history_request', message);
-          publish(REDIS_CONFIG.channels.toBBBApps.whiteboard, message);
-        } else {
-          logger.info('did not have enough information to send a user_leaving_request');
-        }
-      }
-    }
-  }
-
-  return arg.callback();
-});
diff --git a/bigbluebutton-html5/imports/api/presentations/server/modifiers/removePresentation.js b/bigbluebutton-html5/imports/api/presentations/server/modifiers/removePresentation.js
new file mode 100644
index 0000000000..5af60c05c3
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/presentations/server/modifiers/removePresentation.js
@@ -0,0 +1,28 @@
+import { check } from 'meteor/check';
+import Presentations from '/imports/api/presentations';
+import Logger from '/imports/startup/server/logger';
+
+import clearSlidesPresentation from '/imports/api/slides/server/modifiers/clearSlidesPresentation';
+
+export default function removePresentation(meetingId, presentationId) {
+  check(meetingId, String);
+  check(presentationId, String);
+
+  const selector = {
+    meetingId,
+    presentationId,
+  };
+
+  const cb = (err, numChanged) => {
+    if (err) {
+      return Logger.error(`Removing presentation from collection: ${err}`);
+    }
+
+    if (numChanged) {
+      clearSlidesPresentation(meetingId, presentationId);
+      return Logger.info(`Removed presentation id=${presentationId} meeting=${meetingId}`);
+    }
+  };
+
+  return Presentations.remove(selector, cb);
+};
diff --git a/bigbluebutton-html5/imports/api/presentations/server/modifiers/removePresentationFromCollection.js b/bigbluebutton-html5/imports/api/presentations/server/modifiers/removePresentationFromCollection.js
deleted file mode 100755
index d0c74e7743..0000000000
--- a/bigbluebutton-html5/imports/api/presentations/server/modifiers/removePresentationFromCollection.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import Slides from '/imports/api/slides';
-import Presentations from '/imports/api/presentations';
-import { logger } from '/imports/startup/server/logger';
-
-export function removePresentationFromCollection(meetingId, presentationId) {
-  const presentationObject = Presentations.findOne({
-    meetingId: meetingId,
-    'presentation.id': presentationId,
-  });
-  if (presentationObject != null) {
-    Slides.remove({
-      presentationId: presentationId,
-    }, logger.info(`cleared Slides Collection (presentationId: ${presentationId}!`));
-    Presentations.remove(presentationObject._id);
-    return logger.info(`----removed presentation[${presentationId}] from ${meetingId}`);
-  }
-};
diff --git a/bigbluebutton-html5/imports/api/presentations/server/publications.js b/bigbluebutton-html5/imports/api/presentations/server/publications.js
deleted file mode 100755
index ba6d95022f..0000000000
--- a/bigbluebutton-html5/imports/api/presentations/server/publications.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import Presentations from '/imports/api/presentations';
-import { logger } from '/imports/startup/server/logger';
-
-Meteor.publish('presentations', function (credentials) {
-  const { meetingId } = credentials;
-  logger.info(`publishing presentations for ${meetingId}`);
-  return Presentations.find({
-    meetingId: meetingId,
-  });
-});
diff --git a/bigbluebutton-html5/imports/api/presentations/server/publishers.js b/bigbluebutton-html5/imports/api/presentations/server/publishers.js
new file mode 100644
index 0000000000..cd6be803fd
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/presentations/server/publishers.js
@@ -0,0 +1,22 @@
+import { Meteor } from 'meteor/meteor';
+import { check } from 'meteor/check';
+import Presentations from '/imports/api/presentations';
+import Logger from '/imports/startup/server/logger';
+import { isAllowedTo } from '/imports/startup/server/userPermissions';
+
+Meteor.publish('presentations', (credentials) => {
+  // TODO: Some publishers have ACL and others dont
+  // if (!isAllowedTo('@@@', credentials)) {
+  //   this.error(new Meteor.Error(402, "The user was not authorized to subscribe for 'presentations'"));
+  // }
+
+  const { meetingId, requesterUserId, requesterToken } = credentials;
+
+  check(meetingId, String);
+  check(requesterUserId, String);
+  check(requesterToken, String);
+
+  Logger.info(`Publishing Presentations for ${meetingId} ${requesterUserId} ${requesterToken}`);
+
+  return Presentations.find({ meetingId });
+});
diff --git a/bigbluebutton-html5/imports/api/slides/server/modifiers/addSlideToCollection.js b/bigbluebutton-html5/imports/api/slides/server/modifiers/addSlide.js
similarity index 52%
rename from bigbluebutton-html5/imports/api/slides/server/modifiers/addSlideToCollection.js
rename to bigbluebutton-html5/imports/api/slides/server/modifiers/addSlide.js
index 020ae8c8bb..93b1e0571c 100755
--- a/bigbluebutton-html5/imports/api/slides/server/modifiers/addSlideToCollection.js
+++ b/bigbluebutton-html5/imports/api/slides/server/modifiers/addSlide.js
@@ -1,12 +1,29 @@
 import probe from 'probe-image-size';
+import { Meteor } from 'meteor/meteor';
 import { check } from 'meteor/check';
+import RedisPubSub from '/imports/startup/server/redis';
 import Slides from '/imports/api/slides';
 import Logger from '/imports/startup/server/logger';
 import { SVG, PNG } from '/imports/utils/mimeTypes';
 
+const requestWhiteboardHistory = (meetingId, slideId) => {
+  const REDIS_CONFIG = Meteor.settings.redis;
+  const CHANNEL = REDIS_CONFIG.channels.toBBBApps.whiteboard;
+  const EVENT_NAME = 'request_whiteboard_annotation_history_request';
+
+  let payload = {
+    meeting_id: meetingId,
+    requester_id: 'nodeJSapp',
+    whiteboard_id: slideId,
+    reply_to: `${meetingId}/nodeJSapp`,
+  };
+
+  return RedisPubSub.publish(CHANNEL, EVENT_NAME, payload);
+};
+
 const SUPPORTED_TYPES = [SVG, PNG];
 
-export default function addSlideToCollection(meetingId, presentationId, slide) {
+export default function addSlide(meetingId, presentationId, slide) {
   check(meetingId, String);
   check(presentationId, String);
   check(slide, Object);
@@ -21,9 +38,10 @@ export default function addSlideToCollection(meetingId, presentationId, slide) {
 
   const modifier = {
     $set: {
-      meetingId: meetingId,
-      presentationId: presentationId,
+      meetingId,
+      presentationId,
       slide: {
+        id: slide.id,
         height_ratio: slide.height_ratio,
         y_offset: slide.y_offset,
         num: slide.num,
@@ -31,7 +49,6 @@ export default function addSlideToCollection(meetingId, presentationId, slide) {
         current: slide.current,
         img_uri: imageUri,
         txt_uri: slide.txt_uri,
-        id: slide.id,
         width_ratio: slide.width_ratio,
         swf_uri: slide.swf_uri,
         thumb_uri: slide.thumb_uri,
@@ -49,27 +66,37 @@ export default function addSlideToCollection(meetingId, presentationId, slide) {
     const { insertedId } = numChanged;
 
     if (insertedId) {
-      fetchImageSizes(insertedId, imageUri);
-      return Logger.info(`Added slide id=${insertedId} to presentation=${presentationId}`);
+      requestWhiteboardHistory(meetingId, slide.id);
+      return Logger.info(`Added slide id=${slide.id} to presentation=${presentationId}`);
+    }
+
+    if (numChanged) {
+      return Logger.info(`Upserted slide id=${slide.id} to presentation=${presentationId}`);
     }
   };
 
-  return Slides.upsert(selector, modifier, cb);
+  return fetchImageSizes(imageUri)
+    .then(({ width, height }) => {
+      modifier.$set.slide.width = width;
+      modifier.$set.slide.height = height;
+
+      return Slides.upsert(selector, modifier, cb);
+    })
+    .catch(reason =>
+      Logger.error(`Error parsing image size. ${reason}. slide=${slide.id} uri=${imageUri}`));
 };
 
-const fetchImageSizes = (slideId, imageUri) =>
+const fetchImageSizes = (imageUri) =>
   probe(imageUri)
   .then(result => {
     if (!SUPPORTED_TYPES.includes(result.mime)) {
       throw `Invalid image type, received ${result.mime} expecting ${SUPPORTED_TYPES.join()}`;
     }
 
-    return Slides.update(slideId, {
-      $set: {
-        width: result.width,
-        height: result.height,
-      },
-    });
+    return {
+      width: result.width,
+      height: result.height,
+    };
   })
   .catch(reason => {
     Logger.error(`Error parsing image size. ${reason}. slide=${slide.id} uri=${imageUri}`);
diff --git a/bigbluebutton-html5/imports/api/slides/server/modifiers/changeCurrentSlide.js b/bigbluebutton-html5/imports/api/slides/server/modifiers/changeCurrentSlide.js
index f3b6db32e7..c022d5f042 100755
--- a/bigbluebutton-html5/imports/api/slides/server/modifiers/changeCurrentSlide.js
+++ b/bigbluebutton-html5/imports/api/slides/server/modifiers/changeCurrentSlide.js
@@ -21,7 +21,7 @@ export default function changeCurrentSlide(meetingId, presentationId, slideId) {
         return Logger.error(`Unsetting the current slide: ${err}`);
       }
 
-      return Logger.info(`Unsetted as current slide`);
+      return Logger.info(`Unsetted the current slide`);
     },
   };
 
@@ -47,10 +47,10 @@ export default function changeCurrentSlide(meetingId, presentationId, slideId) {
   const newSlide = Slides.findOne(newCurrent.selector);
 
   if (newSlide) {
-    Slides.update(newSlide.id, newCurrent.modifier, newCurrent.callback);
+    Slides.update(newSlide._id, newCurrent.modifier, newCurrent.callback);
   }
 
   if (oldSlide) {
-    Slides.update(oldSlide.id, oldCurrent.modifier, oldCurrent.callback);
+    Slides.update(oldSlide._id, oldCurrent.modifier, oldCurrent.callback);
   }
 };
diff --git a/bigbluebutton-html5/imports/api/slides/server/modifiers/clearSlidesCollection.js b/bigbluebutton-html5/imports/api/slides/server/modifiers/clearSlides.js
similarity index 83%
rename from bigbluebutton-html5/imports/api/slides/server/modifiers/clearSlidesCollection.js
rename to bigbluebutton-html5/imports/api/slides/server/modifiers/clearSlides.js
index 9de4c1f04f..868290d952 100755
--- a/bigbluebutton-html5/imports/api/slides/server/modifiers/clearSlidesCollection.js
+++ b/bigbluebutton-html5/imports/api/slides/server/modifiers/clearSlides.js
@@ -1,7 +1,7 @@
 import Slides from '/imports/api/slides';
 import Logger from '/imports/startup/server/logger';
 
-export default function clearSlidesCollection(meetingId) {
+export default function clearSlides(meetingId) {
   if (meetingId) {
     return Slides.remove({ meetingId: meetingId }, Logger.info(`Cleared Slides (${meetingId})`));
   } else {
diff --git a/bigbluebutton-html5/imports/api/slides/server/modifiers/clearSlidesPresentation.js b/bigbluebutton-html5/imports/api/slides/server/modifiers/clearSlidesPresentation.js
index ff7be924fe..4d65bab039 100644
--- a/bigbluebutton-html5/imports/api/slides/server/modifiers/clearSlidesPresentation.js
+++ b/bigbluebutton-html5/imports/api/slides/server/modifiers/clearSlidesPresentation.js
@@ -2,10 +2,12 @@ import Slides from '/imports/api/slides';
 import Logger from '/imports/startup/server/logger';
 import { check } from 'meteor/check';
 
-export default function clearSlidesPresentation(presentationId) {
+export default function clearSlidesPresentation(meetingId, presentationId) {
+  check(meetingId, String);
   check(presentationId, String);
 
   const selector = {
+    meetingId,
     presentationId,
   };
 
diff --git a/bigbluebutton-html5/imports/api/slides/server/modifiers/resizeSlide.js b/bigbluebutton-html5/imports/api/slides/server/modifiers/resizeSlide.js
index 80a5ebed30..6eae4cdc3c 100644
--- a/bigbluebutton-html5/imports/api/slides/server/modifiers/resizeSlide.js
+++ b/bigbluebutton-html5/imports/api/slides/server/modifiers/resizeSlide.js
@@ -17,21 +17,21 @@ export default function resizeSlide(meetingId, presentationId, slideId, slide) {
 
   const modifier = {
     $set: {
-      slide: {
-        width_ratio: slide.width_ratio,
-        height_ratio: slide.height_ratio,
-        x_offset: slide.x_offset,
-        y_offset: slide.y_offset,
-      },
+      'slide.width_ratio': slide.width_ratio,
+      'slide.height_ratio': slide.height_ratio,
+      'slide.x_offset': slide.x_offset,
+      'slide.y_offset': slide.y_offset,
     },
   };
 
-  const cb = (err) => {
+  const cb = (err, numChanged) => {
     if (err) {
       return Logger.error(`Resizing slide id=${slideId}: ${err}`);
     }
 
-    return Logger.info(`Resized slide id=${slideId}`);
+    if (numChanged) {
+      return Logger.info(`Resized slide id=${slideId}`);
+    }
   };
 
   return Slides.update(selector, modifier, cb);
diff --git a/bigbluebutton-html5/imports/api/slides/server/publishers.js b/bigbluebutton-html5/imports/api/slides/server/publishers.js
index d1c68318a5..0c121386e0 100644
--- a/bigbluebutton-html5/imports/api/slides/server/publishers.js
+++ b/bigbluebutton-html5/imports/api/slides/server/publishers.js
@@ -18,5 +18,5 @@ Meteor.publish('slides', (credentials) => {
 
   Logger.info(`Publishing Slides for ${meetingId} ${requesterUserId} ${requesterToken}`);
 
-  return Slides.find({ meetingId: meetingId });
+  return Slides.find({ meetingId });
 });
diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/container.jsx b/bigbluebutton-html5/imports/ui/components/whiteboard/container.jsx
index 09b93f2688..3f26411e35 100755
--- a/bigbluebutton-html5/imports/ui/components/whiteboard/container.jsx
+++ b/bigbluebutton-html5/imports/ui/components/whiteboard/container.jsx
@@ -17,7 +17,9 @@ class WhiteboardContainer extends Component {
   }
 }
 
-export default createContainer(() => {
-  const data = WhiteboardService.getWhiteboardData();
-  return data;
-}, WhiteboardContainer);
+export default createContainer(() => ({
+  currentSlide: WhiteboardService.getCurrentSlide(),
+  shapes: WhiteboardService.getCurrentShapes(),
+  cursor: WhiteboardService.getCurrentCursor(),
+  userIsPresenter: WhiteboardService.isPresenter(),
+}), WhiteboardContainer);
diff --git a/bigbluebutton-html5/imports/ui/components/whiteboard/service.js b/bigbluebutton-html5/imports/ui/components/whiteboard/service.js
index 2bb735ab82..9d1b3cc356 100755
--- a/bigbluebutton-html5/imports/ui/components/whiteboard/service.js
+++ b/bigbluebutton-html5/imports/ui/components/whiteboard/service.js
@@ -3,48 +3,47 @@ import Shapes from '/imports/api/shapes';
 import Slides from '/imports/api/slides';
 import Cursor from '/imports/api/cursor';
 import Users from '/imports/api/users';
-import AuthSingleton from '/imports/ui/services/auth/index.js';
-
-let getWhiteboardData = () => {
-  let currentSlide;
-  let shapes;
-  let cursor;
-  let userIsPresenter;
-  let currentPresentation = Presentations.findOne({
-      'presentation.current': true,
-    });
-
-  if (currentPresentation != null) {
-    currentSlide = Slides.findOne({
-      presentationId: currentPresentation.presentation.id,
-      'slide.current': true,
-    });
+import Auth from '/imports/ui/services/auth';
+
+const getCurrentPresentation = () => Presentations.findOne({
+  'presentation.current': true,
+});
+
+const getCurrentSlide = () => {
+  const currentPresentation = getCurrentPresentation();
+
+  if (!currentPresentation) {
+    return null;
   }
 
-  if (currentSlide != null) {
-    shapes = Shapes.find({
-        whiteboardId: currentSlide.slide.id,
-      }).fetch();
+  return Slides.findOne({
+    presentationId: currentPresentation.presentation.id,
+    'slide.current': true,
+  });
+};
 
-    cursor = Cursor.findOne({
-      meetingId: currentSlide.meetingId,
-    });
+const getCurrentShapes = () => {
+  const currentSlide = getCurrentSlide();
 
-    // Get user to check if they are the presenter
-    userIsPresenter = Users.findOne({
-      meetingId: currentSlide.meetingId,
-      userId: AuthSingleton.getCredentials().requesterUserId,
-    }).user.presenter;
+  if (!currentSlide) {
+    return null;
   }
 
-  return {
-    currentSlide: currentSlide,
-    shapes: shapes,
-    cursor: cursor,
-    userIsPresenter: userIsPresenter,
-  };
+  return Shapes.find({
+    whiteboardId: currentSlide.slide.id,
+  }).fetch();
 };
 
+const getCurrentCursor = () => Cursor.findOne({});
+
+const isPresenter = () => Users.findOne({
+  userId: Auth.userID,
+}).user.presenter;
+
 export default {
-  getWhiteboardData,
+  getCurrentPresentation,
+  getCurrentSlide,
+  getCurrentShapes,
+  getCurrentCursor,
+  isPresenter,
 };
diff --git a/bigbluebutton-html5/server/main.js b/bigbluebutton-html5/server/main.js
index f0d0eca31a..6d0a06ca78 100755
--- a/bigbluebutton-html5/server/main.js
+++ b/bigbluebutton-html5/server/main.js
@@ -24,11 +24,7 @@ import '/imports/api/polls/server/modifiers/clearPollCollection';
 import '/imports/api/polls/server/modifiers/updatePollCollection';
 import '/imports/api/polls/server/modifiers/eventHandlers';
 
-import '/imports/api/presentations/server/publications';
-import '/imports/api/presentations/server/modifiers/addPresentationToCollection';
-import '/imports/api/presentations/server/modifiers/clearPresentationsCollection';
-import '/imports/api/presentations/server/modifiers/removePresentationFromCollection';
-import '/imports/api/presentations/server/modifiers/eventHandlers';
+import '/imports/api/presentations/server';
 
 import '/imports/api/shapes/server/publications';
 import '/imports/api/shapes/server/modifiers/addShapeToCollection';
-- 
GitLab