First commit

This commit is contained in:
Penar Musaraj 2020-04-03 20:51:51 -04:00
commit e66d8a13e8
10 changed files with 269 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.DS_Store

3
README.md Normal file
View file

@ -0,0 +1,3 @@
# discourse-bbb
Discourse integration with BigBlueButton.

View file

@ -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

View file

@ -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");
}
}
});

View file

@ -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(
`<iframe src="${res.url}" allow="camera;microphone;fullscreen;speaker" width="690" height="500" style="border:none"></iframe>`
);
}
}
})
.catch(function(error) {
popupAjaxError(error);
});
}
function attachButton($elem, fullWindow) {
const buttonLabel = $elem.data("label") || I18n.t("bbb.launch");
$elem.html(
`<button class='launch-bbb btn'>${iconHTML(
"video"
)} ${buttonLabel}</button>`
);
$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" });
});
}
};

View file

@ -0,0 +1,28 @@
{{#d-modal-body title="bbb.modal.title" class="insert-bbb"}}
<div class="insert-bbb-form">
<div class="insert-bbb-input">
<label>{{i18n "bbb.meetingID"}}</label>
{{text-field value=meetingID}}
</div>
<div class="insert-bbb-input">
<label>{{i18n "bbb.button_text"}}</label>
{{text-field value=buttonText placeholderKey="bbb.launch"}}
</div>
<div class="insert-bbb-input">
<label>{{i18n "bbb.attendeePW"}}</label>
{{text-field value=attendeePW}}
</div>
<div class="insert-bbb-input">
<label>{{i18n "bbb.moderatorPW"}}</label>
{{text-field value=moderatorPW}}
</div>
</div>
{{/d-modal-body}}
<div class="modal-footer">
{{d-button class="btn-primary" disabled=insertDisabled label="bbb.modal.insert" action=(action "insert")}}
{{d-button class="btn-danger" label="bbb.modal.cancel" action=(action "cancel")}}
</div>

View file

@ -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

View file

@ -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."

17
config/settings.yml Normal file
View file

@ -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

35
plugin.rb Normal file
View file

@ -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