diff --git a/Gemfile b/Gemfile
index b5df803e..715bf098 100644
--- a/Gemfile
+++ b/Gemfile
@@ -89,3 +89,6 @@ gem 'yt', '~> 0.28.0'
# Simple HTTP client.
gem 'faraday'
+
+# For device detection to determine BigBlueButton client.
+gem 'browser'
diff --git a/Gemfile.lock b/Gemfile.lock
index 148fa847..f542f067 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -46,6 +46,7 @@ GEM
sass (~> 3.2)
bootstrap-social-rails (4.12.0)
railties (>= 3.1)
+ browser (2.5.1)
builder (3.2.3)
byebug (9.0.6)
climate_control (0.2.0)
@@ -279,6 +280,7 @@ DEPENDENCIES
bigbluebutton-api-ruby
bootstrap-sass (= 3.3.0.0)
bootstrap-social-rails (~> 4.12)
+ browser
byebug
coffee-rails (~> 4.2)
dotenv-rails
diff --git a/app/assets/javascripts/active_meetings.js b/app/assets/javascripts/active_meetings.js
index aef51e6a..68215234 100644
--- a/app/assets/javascripts/active_meetings.js
+++ b/app/assets/javascripts/active_meetings.js
@@ -117,8 +117,8 @@ var initialPopulate = function(){
// Populate waiting meetings.
Object.keys(data['waiting']).forEach(function(key) {
- WAITING[name] = {'name': key, 'users': data['waiting'][key]}
- updateMeetingText(WAITING[name])
+ WAITING[key] = {'name': key, 'users': data['waiting'][key]}
+ updateMeetingText(WAITING[key])
})
// Add the meetings to the active meetings list.
diff --git a/app/assets/javascripts/channels/meeting_updates.js b/app/assets/javascripts/channels/meeting_updates.js
index 505cf143..4580490e 100644
--- a/app/assets/javascripts/channels/meeting_updates.js
+++ b/app/assets/javascripts/channels/meeting_updates.js
@@ -55,6 +55,8 @@
body: I18n.user_waiting_body.replace(/%{user}/, data.user).replace(/%{meeting}/, '"'+data.meeting_name+'"')
});
}
+ } else if(data.action === 'unable_to_join') {
+ showAlert(I18n.unable_to_join_mobile, 6000)
}
}
});
diff --git a/app/assets/javascripts/landing.js b/app/assets/javascripts/landing.js
index 92857f35..1f59002e 100644
--- a/app/assets/javascripts/landing.js
+++ b/app/assets/javascripts/landing.js
@@ -60,7 +60,7 @@
jqxhr.done(function(data) {
if (data.messageKey === 'wait_for_moderator') {
waitForModerator(Meeting.getInstance().getURL());
- } else {
+ } else if (data.messageKey === 'ok') {
$(location).attr("href", data.response.join_url);
}
});
diff --git a/app/assets/javascripts/shared.js.erb b/app/assets/javascripts/shared.js.erb
index 0a5f3e1b..7af47440 100644
--- a/app/assets/javascripts/shared.js.erb
+++ b/app/assets/javascripts/shared.js.erb
@@ -69,7 +69,8 @@ var showNotification = function(title, options) {
if (Notification.permission === "granted") {
var icon = '<%= asset_path("bbb-logo.png") %>';
options = $.extend(options, {
- icon: icon
+ icon: icon,
+ tag: 'UserWaiting'
});
var notification = new Notification(title, options);
notification.onclick = function() {
diff --git a/app/controllers/bbb_controller.rb b/app/controllers/bbb_controller.rb
index 01491635..a87457f0 100644
--- a/app/controllers/bbb_controller.rb
+++ b/app/controllers/bbb_controller.rb
@@ -93,7 +93,10 @@ class BbbController < ApplicationController
if bbb_res[:returncode] && current_user == user
JoinMeetingJob.perform_later(user, params[:id], base_url)
WaitingList.empty(options[:room_owner], options[:meeting_name])
- # user will be waiting for a moderator
+ # the user can't join because they are on mobile and HTML5 is not enabled.
+ elsif bbb_res[:messageKey] == 'unable_to_join'
+ NotifyUserCantJoinJob.perform_later(user.encrypted_id, params[:id], params[:name])
+ # user will be waiting for a moderator
else
NotifyUserWaitingJob.perform_later(user.encrypted_id, params[:id], params[:name])
end
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 8e5be0b3..f8866ca1 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -19,13 +19,19 @@ class UsersController < ActionController::Base
# For updating a users background image.
def update
- # Make sure they actually select a file.
- if params[:user] then
+ if params[:commit] == t('upload')
+ # Make sure they actually select a file.
+ if params[:user] then
+ @user = User.find(params[:id])
+ @user.assign_attributes(background: user_params[:background])
+ flash[:danger] = t('invalid_file') unless @user.save
+ else
+ flash[:danger] = t('no_file')
+ end
+ elsif params[:commit] == t('switch_clients')
+ # Switch the users default client.
@user = User.find(params[:id])
- @user.assign_attributes(background: user_params[:background])
- flash[:danger] = t('invalid_file') unless @user.save
- else
- flash[:danger] = t('no_file')
+ @user.update_attributes(use_html5: !@user.use_html5)
end
# Reload the page to apply changes and show flash messages.
diff --git a/app/helpers/landing_helper.rb b/app/helpers/landing_helper.rb
index b2b3e74a..4c74f406 100644
--- a/app/helpers/landing_helper.rb
+++ b/app/helpers/landing_helper.rb
@@ -16,4 +16,8 @@
module LandingHelper
+ def html5_enabled?
+ Rails.configuration.html5_enabled
+ end
+
end
diff --git a/app/jobs/notify_user_cant_join_job.rb b/app/jobs/notify_user_cant_join_job.rb
new file mode 100644
index 00000000..69da5dfe
--- /dev/null
+++ b/app/jobs/notify_user_cant_join_job.rb
@@ -0,0 +1,24 @@
+# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
+#
+# Copyright (c) 2016 BigBlueButton Inc. and by respective authors (see below).
+#
+# This program is free software; you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free Software
+# Foundation; either version 3.0 of the License, or (at your option) any later
+# version.
+#
+# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with BigBlueButton; if not, see .
+
+class NotifyUserCantJoinJob < ApplicationJob
+ queue_as :default
+
+ def perform(room, meeting, user)
+ payload = { action: 'unable_to_join', user: user, meeting_name: meeting }
+ ActionCable.server.broadcast "#{room}-#{meeting}_meeting_updates_channel", payload
+ end
+end
diff --git a/app/lib/bbb_api.rb b/app/lib/bbb_api.rb
index d0e3d89c..fccf0216 100644
--- a/app/lib/bbb_api.rb
+++ b/app/lib/bbb_api.rb
@@ -53,71 +53,109 @@ module BbbApi
if !bbb
return call_invalid_res
else
- meeting_id = bbb_meeting_id(meeting_token)
+ # Verify HTML5 is running.
+ html5_running = Rails.configuration.html5_enabled
+
+ # Determine if the user is on mobile.
+ browser = Browser.new(request.user_agent)
+ mobile = browser.device.tablet?
+
+ # If the user is on mobile and the BigBlueButton server isn't running the HTML5 client,
+ # they can't join or create meetings.
+ if mobile and !html5_running then
+ return unable_to_join_res
+ else
+ meeting_id = bbb_meeting_id(meeting_token)
- # See if the meeting is running
- begin
- bbb_meeting_info = bbb.get_meeting_info(meeting_id, nil)
- rescue BigBlueButton::BigBlueButtonException => exc
- # This means that is not created
+ # See if the meeting is running
+ begin
+ bbb_meeting_info = bbb.get_meeting_info(meeting_id, nil)
+ rescue BigBlueButton::BigBlueButtonException => exc
+ # This means that is not created
- if options[:wait_for_moderator] && !options[:user_is_moderator]
+ if options[:wait_for_moderator] && !options[:user_is_moderator]
+ return wait_moderator_res
+ end
+
+ logger.info "Message for the log file #{exc.key}: #{exc.message}"
+
+ # Prepare parameters for create
+ logout_url = options[:meeting_logout_url] || "#{request.base_url}"
+ moderator_password = random_password(12)
+ viewer_password = random_password(12)
+ meeting_options = {
+ record: options[:meeting_recorded].to_s,
+ logoutURL: logout_url,
+ moderatorPW: moderator_password,
+ attendeePW: viewer_password,
+ moderatorOnlyMessage: options[:moderator_message],
+ "meta_#{BbbApi::META_LISTED}": false,
+ "meta_#{BbbApi::META_TOKEN}": meeting_token
+ }
+
+ meeting_options.merge!(
+ { "meta_#{BbbApi::META_HOOK_URL}": options[:hook_url] }
+ ) if options[:hook_url]
+
+ # these parameters are used to filter recordings by room and meeting
+ meeting_options.merge!(
+ { "meta_room-id": options[:room_owner],
+ "meta_meeting-name": options[:meeting_name]}
+ ) if options[:room_owner]
+
+ # Only register webhooks if they are enabled it's not a guest meeting.
+ if Rails.configuration.use_webhooks && params[:resource] == 'rooms'
+ webhook_register(options[:hook_url], meeting_id)
+ end
+
+ # Create the meeting
+ begin
+ bbb.create_meeting(options[:meeting_name], meeting_id, meeting_options)
+ rescue BigBlueButton::BigBlueButtonException => exc
+ logger.info "BBB error on create #{exc.key}: #{exc.message}"
+ end
+
+ # And then get meeting info
+ bbb_meeting_info = bbb.get_meeting_info( meeting_id, nil )
+ end
+
+ if options[:wait_for_moderator] && !options[:user_is_moderator] && bbb_meeting_info[:moderatorCount] <= 0
return wait_moderator_res
end
- logger.info "Message for the log file #{exc.key}: #{exc.message}"
-
- # Prepare parameters for create
- logout_url = options[:meeting_logout_url] || "#{request.base_url}"
- moderator_password = random_password(12)
- viewer_password = random_password(12)
- meeting_options = {
- record: options[:meeting_recorded].to_s,
- logoutURL: logout_url,
- moderatorPW: moderator_password,
- attendeePW: viewer_password,
- moderatorOnlyMessage: options[:moderator_message],
- "meta_#{BbbApi::META_LISTED}": false,
- "meta_#{BbbApi::META_TOKEN}": meeting_token
- }
- meeting_options.merge!(
- { "meta_#{BbbApi::META_HOOK_URL}": options[:hook_url] }
- ) if options[:hook_url]
-
- # these parameters are used to filter recordings by room and meeting
- meeting_options.merge!(
- { "meta_room-id": options[:room_owner],
- "meta_meeting-name": options[:meeting_name]}
- ) if options[:room_owner]
-
- # Only register webhooks if they are enabled it's not a guest meeting.
- if Rails.configuration.use_webhooks && params[:resource] == 'rooms'
- webhook_register(options[:hook_url], meeting_id)
+ # Get the join url
+ if (options[:user_is_moderator])
+ password = bbb_meeting_info[:moderatorPW]
+ else
+ password = bbb_meeting_info[:attendeePW]
+ end
+
+ # Determine which client to join as.
+ if current_user.nil?
+ use_html5 = Rails.configuration.use_html5_by_default
+ else
+ use_html5 = current_user.use_html5
+ end
+
+ # Restrict client if needed.
+ if mobile && html5_running
+ # Must use HTML5 because they are on mobile.
+ use_html5 = true
+ elsif !mobile && !html5_running
+ # HTML5 is not running, so must use Flash.
+ use_html5 = false
+ end
+
+ # Generate the join URL.
+ if use_html5
+ clientURL = bbb_endpoint.gsub('bigbluebutton/', 'html5client/join')
+ join_url = bbb.join_meeting_url(meeting_id, full_name, password, {clientURL: clientURL})
+ else
+ join_url = bbb.join_meeting_url(meeting_id, full_name, password)
end
- # Create the meeting
- begin
- bbb.create_meeting(options[:meeting_name], meeting_id, meeting_options)
- rescue BigBlueButton::BigBlueButtonException => exc
- logger.info "BBB error on create #{exc.key}: #{exc.message}"
- end
-
- # And then get meeting info
- bbb_meeting_info = bbb.get_meeting_info( meeting_id, nil )
+ return success_join_res(join_url)
end
-
- if options[:wait_for_moderator] && !options[:user_is_moderator] && bbb_meeting_info[:moderatorCount] <= 0
- return wait_moderator_res
- end
-
- # Get the join url
- if (options[:user_is_moderator])
- password = bbb_meeting_info[:moderatorPW]
- else
- password = bbb_meeting_info[:attendeePW]
- end
- join_url = bbb.join_meeting_url(meeting_id, full_name, password )
- return success_join_res(join_url)
end
end
@@ -300,6 +338,15 @@ module BbbApi
}
}
end
+
+ def unable_to_join_res
+ {
+ returncode: false,
+ messageKey: "unable_to_join",
+ message: "Unable to join.",
+ status: :ok
+ }
+ end
def wait_moderator_res
{
diff --git a/app/views/landing/preferences.html.erb b/app/views/landing/preferences.html.erb
index 542d8d3a..3871cb75 100644
--- a/app/views/landing/preferences.html.erb
+++ b/app/views/landing/preferences.html.erb
@@ -23,6 +23,7 @@
<% if @user %>
+
<%= t('background_image') %>
<%= t('background_image') + ": " + (@user.background_file_name || '') %>
<%= form_for @user, :html => { :multipart => true } do |f| %>
@@ -31,6 +32,18 @@
<%= f.submit t('upload'), class: 'btn btn-info' %>
<% end %>
+
+
+
<%= t('prefered_client') %>
+ <% if html5_enabled? %>
+
<%= t('currently_joining_with', client: @user.use_html5 ? t('client_html5') : t('client_flash')) %>
+ <%= form_for @user do |f| %>
+ <%= f.submit t('switch_clients'), class: 'btn btn-info' %>
+ <% end %>
+ <% else %>
+
<%= t('html5_not_enabled') %>
+ <% end %>
+
<% else %>
<%= t('preferences_logged') %>
<% end %>
diff --git a/config/application.rb b/config/application.rb
index 7102d908..37390904 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -48,6 +48,7 @@ module Greenlight
config.disable_guest_access = ENV['DISABLE_GUEST_ACCESS'] && ENV['DISABLE_GUEST_ACCESS'] == "true"
config.enable_youtube_uploading = ENV['ENABLE_YOUTUBE_UPLOADING'] && ENV['ENABLE_YOUTUBE_UPLOADING'] == "true"
config.enable_qrcode_generation = ENV['ENABLE_QRCODE_GENERATION'] && ENV['ENABLE_QRCODE_GENERATION'] == "true"
+ config.use_html5_by_default = ENV['USE_HTML5_BY_DEFAULT'] == "true"
# SMTP and action mailer
if config.mail_notifications
diff --git a/config/initializers/html5_client.rb b/config/initializers/html5_client.rb
new file mode 100644
index 00000000..37fdd8de
--- /dev/null
+++ b/config/initializers/html5_client.rb
@@ -0,0 +1,19 @@
+# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
+#
+# Copyright (c) 2016 BigBlueButton Inc. and by respective authors (see below).
+#
+# This program is free software; you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free Software
+# Foundation; either version 3.0 of the License, or (at your option) any later
+# version.
+#
+# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with BigBlueButton; if not, see
.
+
+# Send a request to check if the HTML5 client is enabled on the BigBlueButton server.
+res = Faraday.get(Rails.configuration.bigbluebutton_endpoint.gsub('bigbluebutton/', 'html5client/check'))
+Rails.application.config.html5_enabled = res.status == 200
diff --git a/config/locales/en-us.yml b/config/locales/en-us.yml
index 15a5de77..d7e2486e 100644
--- a/config/locales/en-us.yml
+++ b/config/locales/en-us.yml
@@ -70,14 +70,18 @@ en-US:
recording_unpublished: Recording was unpublished
share: Share
successful_upload: Recording successfully uploaded to Youtube!
+ unable_to_join_mobile: This BigBlueButton server does not use the HTML5 client, which means you are unable to join on mobile.
unpublish_recording: Hide recording
unlisted: Unlisted
unpublished: No one
upload_youtube: Youtube
user_waiting_body: "%{user} is waiting to join %{meeting}!"
user_waiting_title: A user is waiting
+ client_html5: HTML5
+ client_flash: Flash
copied: Copied
copy_error: Use Ctrl-c to copy
+ currently_joining_with: Currently prefering the %{client} client.
create_your_session: Create your own meeting
date_recorded: Date
disallowed_characters_msg: Characters not allowed in meeting name $&,
@@ -94,6 +98,7 @@ en-US:
hi_all: Hi Everyone
home_page: Home page
home_title: Welcome to BigBlueButton
+ html5_not_enabled: This server is not HTML5 enabled, so you must use the Flash client.
invalid_file: You may only upload an image file (jpg, gif, png).
invalid_login: Invalid log in credentials.
invite: Invite
@@ -157,6 +162,7 @@ en-US:
past_recordings: Past Recordings
preferences: Preferences
preferences_logged: You must be logged in to edit preferences.
+ prefered_client: Prefered Client
presentation: Presentation
previous_meetings: (previous meetings)
qrcode:
@@ -176,6 +182,7 @@ en-US:
start: Start
start_join: Start
start_meeting: Start meeting
+ switch_clients: Switch Clients
test_mailer:
test_email:
subject: Test Email
diff --git a/db/migrate/20170928183010_add_use_html5_to_users.rb b/db/migrate/20170928183010_add_use_html5_to_users.rb
new file mode 100644
index 00000000..4518ea3f
--- /dev/null
+++ b/db/migrate/20170928183010_add_use_html5_to_users.rb
@@ -0,0 +1,5 @@
+class AddUseHtml5ToUsers < ActiveRecord::Migration[5.0]
+ def change
+ add_column :users, :use_html5, :boolean, default: false
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 4aff0bb8..b35d0051 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,22 +10,23 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20170518190442) do
+ActiveRecord::Schema.define(version: 20170928183010) do
create_table "users", force: :cascade do |t|
- t.string "provider", null: false
- t.string "uid", null: false
+ t.string "provider", null: false
+ t.string "uid", null: false
t.string "name"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.string "username"
- t.string "encrypted_id", null: false
+ t.string "encrypted_id", null: false
t.string "email"
t.string "background_file_name"
t.string "background_content_type"
t.integer "background_file_size"
t.datetime "background_updated_at"
t.string "token"
+ t.boolean "use_html5", default: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["encrypted_id"], name: "index_users_on_encrypted_id", unique: true
t.index ["provider", "uid"], name: "index_users_on_provider_and_uid", unique: true
diff --git a/sample.env b/sample.env
index b3781cb0..2fdb1dc2 100644
--- a/sample.env
+++ b/sample.env
@@ -23,6 +23,17 @@ SECRET_KEY_BASE=
# BIGBLUEBUTTON_ENDPOINT=
# BIGBLUEBUTTON_SECRET=
+# Set default client (optional)
+#
+# By default, GreenLight will join users to a BigBlueButton session using the Flash
+# client. By setting USE_HTML5_BY_DEFAULT to true, you can configure GreenLight to
+# use the HTML5 client by default. GreenLight will only use the default for
+# non-authenticated users. Users who have authenticated are able to set their
+# prefered client under preferences. Also note that if the HTML5 client is not
+# running on a BigBlueButton server, all clients will be joined using Flash
+# regardless on any settings.
+USE_HTML5_BY_DEFAULT=false
+
# Twitter Login Provider (optional)
#
# You will need to register the app at https://apps.twitter.com/
diff --git a/scripts/greenlight_recording_notify.rb b/scripts/greenlight_recording_notify.rb
index 470bfa0e..682b925c 100755
--- a/scripts/greenlight_recording_notify.rb
+++ b/scripts/greenlight_recording_notify.rb
@@ -49,7 +49,7 @@ def getParticipantsInfo(events_xml)
end
def get_id_from_event(event)
- (event.xpath('externalUserId').empty?) ? event.xpath('userId').text.split('_')[0] : event.xpath('externalUserId').text
+ (event.xpath('externalUserId').empty?) ? event.xpath('userId').text : event.xpath('externalUserId').text
end
# Gets the join and leave times for each user, as well as total duration of stay.