From e66d8a13e805e9b72cbe17c10f1417c0b70ba765 Mon Sep 17 00:00:00 2001 From: Penar Musaraj Date: Fri, 3 Apr 2020 20:51:51 -0400 Subject: [PATCH] First commit --- .gitignore | 1 + README.md | 3 + app/controllers/bbb_client_controller.rb | 51 ++++++++++++ .../controllers/insert-bbb.js.es6 | 34 ++++++++ .../discourse/initializers/bbb.js.es6 | 80 +++++++++++++++++++ .../discourse/templates/modal/insert-bbb.hbs | 28 +++++++ config/locales/client.en.yml | 13 +++ config/locales/server.en.yml | 7 ++ config/settings.yml | 17 ++++ plugin.rb | 35 ++++++++ 10 files changed, 269 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 app/controllers/bbb_client_controller.rb create mode 100644 assets/javascripts/discourse-bbb/controllers/insert-bbb.js.es6 create mode 100644 assets/javascripts/discourse/initializers/bbb.js.es6 create mode 100644 assets/javascripts/discourse/templates/modal/insert-bbb.hbs create mode 100644 config/locales/client.en.yml create mode 100644 config/locales/server.en.yml create mode 100644 config/settings.yml create mode 100644 plugin.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..0294806 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# discourse-bbb + +Discourse integration with BigBlueButton. diff --git a/app/controllers/bbb_client_controller.rb b/app/controllers/bbb_client_controller.rb new file mode 100644 index 0000000..c9883b6 --- /dev/null +++ b/app/controllers/bbb_client_controller.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true +require 'digest/sha1' + +module BigBlue + class BbbClientController < ApplicationController + before_action :ensure_logged_in + + def create + render json: { + url: build_url(params) + } + end + + private + + def build_url(args) + return false unless SiteSetting.bbb_endpoint && SiteSetting.bbb_secret + + meeting_id = args['meetingID'] + url = SiteSetting.bbb_endpoint + secret = SiteSetting.bbb_secret + attendee_pw = args['attendeePW'] + moderator_pw = args['moderatorPW'] + + query = { + meetingID: meeting_id, + attendeePW: attendee_pw, + moderatorPW: moderator_pw + }.to_query + + checksum = Digest::SHA1.hexdigest ("create" + query + secret) + + create_url = "#{url}create?#{query}&checksum=#{checksum}" + response = Excon.get(create_url) + + if response.status != 200 + Rails.logger.warn("Could not create meeting: #{response.inspect}") + return false + end + + join_params = { + fullName: current_user.name || current_user.username, + meetingID: meeting_id, + password: attendee_pw # TODO: pass moderator username or staff as moderator? + }.to_query + + join_checksum = Digest::SHA1.hexdigest ("join" + join_params + secret) + "#{url}join?#{join_params}&checksum=#{join_checksum}" + end + end +end diff --git a/assets/javascripts/discourse-bbb/controllers/insert-bbb.js.es6 b/assets/javascripts/discourse-bbb/controllers/insert-bbb.js.es6 new file mode 100644 index 0000000..e807278 --- /dev/null +++ b/assets/javascripts/discourse-bbb/controllers/insert-bbb.js.es6 @@ -0,0 +1,34 @@ +import Controller from "@ember/controller"; +import ModalFunctionality from "discourse/mixins/modal-functionality"; + +export default Controller.extend(ModalFunctionality, { + keyDown(e) { + if (e.keyCode === 13) { + e.preventDefault(); + e.stopPropagation(); + return false; + } + }, + + onShow() { + this.setProperties({ + meetingID: "", + attendeePW: "", + moderatorPW: "", + buttonText: "" + }); + }, + + actions: { + insert() { + const btnTxt = this.buttonText ? ` label="${this.buttonText}"` : ""; + this.toolbarEvent.addText( + `[wrap=discourse-bbb meetingID="${this.meetingID}"${btnTxt} attendeePW="${this.attendeePW}" moderatorPW="${this.moderatorPW}"][/wrap]` + ); + this.send("closeModal"); + }, + cancel() { + this.send("closeModal"); + } + } +}); diff --git a/assets/javascripts/discourse/initializers/bbb.js.es6 b/assets/javascripts/discourse/initializers/bbb.js.es6 new file mode 100644 index 0000000..d3192f3 --- /dev/null +++ b/assets/javascripts/discourse/initializers/bbb.js.es6 @@ -0,0 +1,80 @@ +import { withPluginApi } from "discourse/lib/plugin-api"; +import showModal from "discourse/lib/show-modal"; +import { iconHTML } from "discourse-common/lib/icon-library"; +import { ajax } from "discourse/lib/ajax"; +import { popupAjaxError } from "discourse/lib/ajax-error"; + +function launchBBB($elem, fullWindow) { + const data = $elem.data(); + + ajax("/bbb/create.json", { + type: "POST", + data: data + }) + .then(res => { + if (res.url) { + console.log(fullWindow); + if (fullWindow) { + window.location.href = res.url; + } else { + $elem.children().hide(); + $elem.append( + `` + ); + } + } + }) + .catch(function(error) { + popupAjaxError(error); + }); +} + +function attachButton($elem, fullWindow) { + const buttonLabel = $elem.data("label") || I18n.t("bbb.launch"); + + $elem.html( + `` + ); + $elem.find("button").on("click", () => launchBBB($elem, fullWindow)); +} + +function attachBBB($elem, helper) { + if (helper) { + const siteSettings = Discourse.__container__.lookup("site-settings:main"); + const fullWindow = siteSettings.bbb_full_window; + + $elem.find("[data-wrap=discourse-bbb]").each((idx, val) => { + attachButton($(val), fullWindow); + }); + } +} + +export default { + name: "insert-bbb", + + initialize() { + withPluginApi("0.8.31", api => { + const currentUser = api.getCurrentUser(); + const siteSettings = api.container.lookup("site-settings:main"); + + api.onToolbarCreate(toolbar => { + if (siteSettings.bbb_staff_only && !currentUser.staff) { + return; + } + + toolbar.addButton({ + title: "bbb.composer_title", + id: "insertBBB", + group: "insertions", + icon: "fab-bootstrap", + perform: e => + showModal("insert-bbb").setProperties({ toolbarEvent: e }) + }); + }); + + api.decorateCooked(attachBBB, { id: "discourse-bbb" }); + }); + } +}; diff --git a/assets/javascripts/discourse/templates/modal/insert-bbb.hbs b/assets/javascripts/discourse/templates/modal/insert-bbb.hbs new file mode 100644 index 0000000..8e31926 --- /dev/null +++ b/assets/javascripts/discourse/templates/modal/insert-bbb.hbs @@ -0,0 +1,28 @@ +{{#d-modal-body title="bbb.modal.title" class="insert-bbb"}} +
+
+ + {{text-field value=meetingID}} +
+ +
+ + {{text-field value=buttonText placeholderKey="bbb.launch"}} +
+ +
+ + {{text-field value=attendeePW}} +
+ +
+ + {{text-field value=moderatorPW}} +
+
+{{/d-modal-body}} + + diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml new file mode 100644 index 0000000..8de24d3 --- /dev/null +++ b/config/locales/client.en.yml @@ -0,0 +1,13 @@ +en: + js: + bbb: + composer_title: BigBlueButton Integration + meetingID: Meeting ID + button_text: Button label (optional) + attendeePW: Attendee password + moderatorPW: Moderator password + launch: Start Video Conference + modal: + insert: Insert + cancel: Cancel + title: Add BBB Integration diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml new file mode 100644 index 0000000..cd5b143 --- /dev/null +++ b/config/locales/server.en.yml @@ -0,0 +1,7 @@ +en: + site_settings: + bbb_enabled: "Enable BigBlueButton integration" + bbb_endpoint: "BigBlueButton Server URL (must include `api/`, as in: mysite.com/bigbluebutton/api/)." + bbb_secret: "BigBlueButton Shared Secret" + bbb_full_window: "If unchecked, video conference will load in an iframe." + bbb_staff_only: "Only show toolbar button to staff members." diff --git a/config/settings.yml b/config/settings.yml new file mode 100644 index 0000000..29c3f4b --- /dev/null +++ b/config/settings.yml @@ -0,0 +1,17 @@ +plugins: + bbb_enabled: + default: false + client: true + bbb_endpoint: + default: "" + client: false + bbb_secret: + default: "" + client: false + secret: true + bbb_full_window: + default: true + client: true + bbb_staff_only: + default: true + client: true diff --git a/plugin.rb b/plugin.rb new file mode 100644 index 0000000..0e53589 --- /dev/null +++ b/plugin.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +# name: discourse-bbb +# about: Integrate BigBlueButton in Discourse. +# version: 1.0.0 +# authors: Penar Musaraj +# url: https://github.com/pmusaraj/discourse-bbb + +enabled_site_setting :bbb_enabled +register_svg_icon "fab-bootstrap" +register_svg_icon "video" + +after_initialize do + [ + "../app/controllers/bbb_client_controller", + ].each { |path| require File.expand_path(path, __FILE__) } + + module ::BigBlue + PLUGIN_NAME ||= "discourse-bbb".freeze + + class Engine < ::Rails::Engine + engine_name BigBlue::PLUGIN_NAME + isolate_namespace BigBlue + end + end + + BigBlue::Engine.routes.draw do + post '/create' => 'bbb_client#create', constraints: { format: :json } + end + + Discourse::Application.routes.append do + mount ::BigBlue::Engine, at: "/bbb" + end + +end