From f5095b1e4dade0975cfcd9042478f831c042c262 Mon Sep 17 00:00:00 2001 From: Josh Date: Wed, 7 Jun 2017 11:06:31 -0400 Subject: [PATCH 1/9] change checksum handling & show active meetings --- app/assets/stylesheets/main/landing.scss | 2 +- app/channels/refresh_meetings_channel.rb | 21 +++ app/controllers/bbb_controller.rb | 33 +++- app/controllers/landing_controller.rb | 4 + app/views/landing/_previously_joined.html.erb | 143 +++++++++++++++++- config/locales/en-us.yml | 1 + config/routes.rb | 1 + 7 files changed, 195 insertions(+), 10 deletions(-) create mode 100644 app/channels/refresh_meetings_channel.rb diff --git a/app/assets/stylesheets/main/landing.scss b/app/assets/stylesheets/main/landing.scss index b68180d3..d8a63cf8 100644 --- a/app/assets/stylesheets/main/landing.scss +++ b/app/assets/stylesheets/main/landing.scss @@ -19,7 +19,7 @@ width: 100px; } -.previously-joined { +.previously-joined, .actives { list-style-type: none; margin:auto; width: 200px; diff --git a/app/channels/refresh_meetings_channel.rb b/app/channels/refresh_meetings_channel.rb new file mode 100644 index 00000000..ebb973ff --- /dev/null +++ b/app/channels/refresh_meetings_channel.rb @@ -0,0 +1,21 @@ +# 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 RefreshMeetingsChannel < ApplicationCable::Channel + def subscribed + stream_from "refresh_meetings" + end +end diff --git a/app/controllers/bbb_controller.rb b/app/controllers/bbb_controller.rb index 6b47975b..dc2350e1 100644 --- a/app/controllers/bbb_controller.rb +++ b/app/controllers/bbb_controller.rb @@ -111,8 +111,8 @@ class BbbController < ApplicationController head(:ok) && return unless validate_checksum begin - data = JSON.parse(read_body(request)) - treat_callback_event(data["event"]) + data = JSON.parse(params['event']) + treat_callback_event(data) rescue Exception => e logger.error "Error parsing webhook data. Data: #{data}, exception: #{e.inspect}" @@ -242,6 +242,15 @@ class BbbController < ApplicationController else logger.error "Bad format for event #{event}, won't process" end + elsif eventName == "meeting_created_message" + # Fire an Actioncable event that updates _previously_joined for the client. + actioncable_event('create', params['id']) + elsif eventName == "meeting_destroyed_event" + actioncable_event('destroy', params['id']) + elsif eventName == "user_joined_message" + actioncable_event('join', params['id'], event['payload']['user']['role']) + elsif eventName == "user_left_message" + actioncable_event('leave', params['id'], event['payload']['user']['role']) else logger.info "Callback event will not be treated. Event name: #{eventName}" end @@ -249,15 +258,31 @@ class BbbController < ApplicationController render head(:ok) && return end + def actioncable_event(method, id, role = 'none') + ActionCable.server.broadcast 'refresh_meetings', + method: method, + meeting: id, + role: role + end + # Validates the checksum received in a callback call. # If the checksum doesn't match, renders an ok and aborts execution. def validate_checksum secret = ENV['BIGBLUEBUTTON_SECRET'] checksum = params["checksum"] - data = read_body(request) + + # Decode and break the body into parts. + parts = URI.decode_www_form(read_body(request)) + + # Convert the data into the correct checksum format, replace ruby hash arrows. + converted_data = {parts[0][0]=>parts[0][1],parts[1][0]=>parts[1][1].to_i}.to_s.gsub!('=>', ':') + + # Manually remove the space between the two elements. + converted_data[converted_data.rindex("timestamp") - 2] = '' + callback_url = uri_remove_param(request.original_url, "checksum") - checksum_str = "#{callback_url}#{data}#{secret}" + checksum_str = "#{callback_url}#{converted_data}#{secret}" calculated_checksum = Digest::SHA1.hexdigest(checksum_str) if calculated_checksum != checksum diff --git a/app/controllers/landing_controller.rb b/app/controllers/landing_controller.rb index bcc83bd1..4f67eec3 100644 --- a/app/controllers/landing_controller.rb +++ b/app/controllers/landing_controller.rb @@ -34,6 +34,10 @@ class LandingController < ApplicationController end end + def send_data + render json: bbb.get_meetings + end + def wait_for_moderator render layout: false end diff --git a/app/views/landing/_previously_joined.html.erb b/app/views/landing/_previously_joined.html.erb index 77470322..67cd04d0 100644 --- a/app/views/landing/_previously_joined.html.erb +++ b/app/views/landing/_previously_joined.html.erb @@ -13,9 +13,142 @@ # with BigBlueButton; if not, see . %> - <% end %> - +<%= javascript_include_tag "active_meetings.js" %> diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index e56f0bfe..b434024f 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -9,3 +9,4 @@ Rails.application.config.assets.version = '1.0' # Precompile additional assets. # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. Rails.application.config.assets.precompile += %w( fa/gl-fa.css ) +Rails.application.config.assets.precompile += %w( active_meetings.js ) From 291d815056a3c85d27c2746b55233d8a7189ae4f Mon Sep 17 00:00:00 2001 From: Josh Date: Wed, 7 Jun 2017 15:48:47 -0400 Subject: [PATCH 3/9] don't show active meetings when not logged in --- app/views/landing/_previously_joined.html.erb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/views/landing/_previously_joined.html.erb b/app/views/landing/_previously_joined.html.erb index c9c6c2c0..ad404847 100644 --- a/app/views/landing/_previously_joined.html.erb +++ b/app/views/landing/_previously_joined.html.erb @@ -30,6 +30,17 @@ +<% else %> + <% end %> <%= javascript_include_tag "active_meetings.js" %> From b9ace4dfa68a76028036e7d250c41b3205ed1427 Mon Sep 17 00:00:00 2001 From: Josh Date: Wed, 7 Jun 2017 16:24:29 -0400 Subject: [PATCH 4/9] redirect to user when clicking logo if found --- app/views/layouts/application.html.erb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 0eee7309..3dd492f3 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -66,7 +66,11 @@ with BigBlueButton; if not, see .
- <%= link_to image_tag("bbb-logo.png", :alt => "BigBlueButton", :class => "logo"), root_path %> + <% if current_user %> + <%= link_to image_tag("bbb-logo.png", :alt => "BigBlueButton", :class => "logo"), meeting_room_path('rooms', User.find(current_user).encrypted_id) %> + <% else %> + <%= link_to image_tag("bbb-logo.png", :alt => "BigBlueButton", :class => "logo"), root_path %> + <% end %>
From 42f0c14b493c303a56fead0628149892c8d24104 Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 8 Jun 2017 10:28:56 -0400 Subject: [PATCH 5/9] add/remove from previous meetings & loading spinner --- app/assets/javascripts/active_meetings.js | 30 ++++++++++++++----- app/assets/stylesheets/main/landing.scss | 5 ++++ app/views/landing/_previously_joined.html.erb | 12 +++++--- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/app/assets/javascripts/active_meetings.js b/app/assets/javascripts/active_meetings.js index ac656fe7..0427d015 100644 --- a/app/assets/javascripts/active_meetings.js +++ b/app/assets/javascripts/active_meetings.js @@ -1,3 +1,4 @@ +// Handles action cable events from bbb-webhooks and initial population of active meetings. MEETINGS = {} @@ -5,18 +6,19 @@ MEETINGS = {} if($('body').data('current-user')){ App.messages = App.cable.subscriptions.create('RefreshMeetingsChannel', { received: function(data) { - console.log(data) + console.log('Recieved ' + data['method'] + ' action for ' + data['meeting'] + '.') if(isPreviouslyJoined(data['meeting'])){ if(data['method'] == 'create'){ - // Create an empty meeting. MEETINGS[data['meeting']] = {'name': data['meeting'], 'participants': 0, 'moderators': 0} renderActiveMeeting(MEETINGS[data['meeting']]) + updatePreviousMeetings(); } else if(data['method'] == 'destroy'){ removeActiveMeeting(MEETINGS[data['meeting']]) + PreviousMeetings.append([data['meeting']]) delete MEETINGS[data['meeting']] } else if(data['method'] == 'join'){ handleUser(data, 1) @@ -29,6 +31,15 @@ if($('body').data('current-user')){ }); } +updatePreviousMeetings = function(){ + $("ul.previously-joined li").each(function(idx, li) { + previous_meeting = $(li); + if(Object.keys(MEETINGS).indexOf(previous_meeting.text()) > -1){ + previous_meeting.remove() + } + }); +} + handleUser = function(data, n){ if(data['role'] == 'MODERATOR'){ MEETINGS[data['meeting']]['moderators'] += n @@ -39,7 +50,7 @@ handleUser = function(data, n){ } updateMeetingText = function(meeting){ - $('#' + meeting['name']).html('' + meeting['name'] + ' (' + + $('#' + meeting['name'].replace(' ', '_')).html('' + meeting['name'] + ' (' + meeting['participants'] + ((meeting['participants'] == 1) ? ' user, ' : ' users, ') + meeting['moderators'] + ((meeting['moderators'] == 1) ? ' mod)' : ' mods)')) } @@ -57,9 +68,13 @@ initialPopulate = function(){ 'moderators': moderators} if(isPreviouslyJoined(name)){ renderActiveMeeting(MEETINGS[name]) - // remove it. } } + }).done(function(){ + // Remove from previous meetings if they are active. + updatePreviousMeetings(); + $('.hidden-list').show(); + $('.fa-spinner').hide(); }); } @@ -69,7 +84,7 @@ isPreviouslyJoined = function(meeting){ } renderActiveMeeting = function(m){ - var meeting_item = $('
  • ' + m['name'] + '' + + var meeting_item = $('
  • ' + m['name'] + '' + ' (' + m['participants'] + ' users, ' + m['moderators'] + ' mods)' + '
  • ') $('.actives').append(meeting_item); @@ -80,8 +95,7 @@ renderActiveMeeting = function(m){ } removeActiveMeeting = function(meeting){ - $('#' + meeting['name']).remove() - //$(".actives:contains('" + meeting['name'] + "')").remove() + $('#' + meeting['name'].replace(' ', '_')).remove() } // Directly join a meeting from active meetings. @@ -114,4 +128,4 @@ joinMeeting = function(meeting_name){ } } -if($('body').data('current-user')){ console.log('Populating active meetings.'); initialPopulate() } +if($('body').data('current-user')){ console.log('Populating active meetings.'); setTimeout(initialPopulate, 1250); } diff --git a/app/assets/stylesheets/main/landing.scss b/app/assets/stylesheets/main/landing.scss index d8a63cf8..53dc2a34 100644 --- a/app/assets/stylesheets/main/landing.scss +++ b/app/assets/stylesheets/main/landing.scss @@ -89,3 +89,8 @@ color: green; } } + +.fa-spinner { + width: 100%; + text-align: center; +} diff --git a/app/views/landing/_previously_joined.html.erb b/app/views/landing/_previously_joined.html.erb index ad404847..bede4087 100644 --- a/app/views/landing/_previously_joined.html.erb +++ b/app/views/landing/_previously_joined.html.erb @@ -16,14 +16,18 @@ <% if current_user %>