First commit
This commit is contained in:
commit
e66d8a13e8
10 changed files with 269 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.DS_Store
|
3
README.md
Normal file
3
README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# discourse-bbb
|
||||
|
||||
Discourse integration with BigBlueButton.
|
51
app/controllers/bbb_client_controller.rb
Normal file
51
app/controllers/bbb_client_controller.rb
Normal 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
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
});
|
80
assets/javascripts/discourse/initializers/bbb.js.es6
Normal file
80
assets/javascripts/discourse/initializers/bbb.js.es6
Normal 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" });
|
||||
});
|
||||
}
|
||||
};
|
28
assets/javascripts/discourse/templates/modal/insert-bbb.hbs
Normal file
28
assets/javascripts/discourse/templates/modal/insert-bbb.hbs
Normal 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>
|
13
config/locales/client.en.yml
Normal file
13
config/locales/client.en.yml
Normal 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
|
7
config/locales/server.en.yml
Normal file
7
config/locales/server.en.yml
Normal 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
17
config/settings.yml
Normal 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
35
plugin.rb
Normal 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
|
Loading…
Reference in a new issue