diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index ce912696..34532f70 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -14,4 +14,5 @@ //= require jquery-ui //= require bootstrap-sprockets //= require turbolinks +//= require_self //= require_tree . diff --git a/app/assets/javascripts/channels/moderator_joins.js b/app/assets/javascripts/channels/moderator_joins.js new file mode 100644 index 00000000..3b1339da --- /dev/null +++ b/app/assets/javascripts/channels/moderator_joins.js @@ -0,0 +1,27 @@ +(function() { + + var initRooms = function() { + App.messages = App.cable.subscriptions.create({ + channel: 'ModeratorJoinsChannel', + username: window.location.pathname.split('/').pop() + }, + { + received: function(data) { + if (!Meeting.getInstance().getModJoined()) { + Meeting.getInstance().setModJoined(true); + if (Meeting.getInstance().getWaitingForMod()) { + loopJoin(); + } + } + } + }); + }; + + $(document).on("turbolinks:load", function() { + if ($("body[data-controller=landing]").get(0)) { + if ($("body[data-action=rooms]").get(0)) { + initRooms(); + } + } + }); +}).call(this); diff --git a/app/assets/javascripts/landing.js b/app/assets/javascripts/landing.js index 9ede6b12..1e9e48e2 100644 --- a/app/assets/javascripts/landing.js +++ b/app/assets/javascripts/landing.js @@ -1,21 +1,35 @@ (function() { + var waitForModerator = function(url) { + $.get(url + "/wait", function(html) { + $(".center-panel-wrapper").html(html); + }); + if (!Meeting.getInstance().getWaitingForMod()) { + Meeting.getInstance().setWaitingForMod(true); + if (Meeting.getInstance().getModJoined()) { + loopJoin(); + } + } + }; + var init = function() { $('.meeting-join').click (function (event) { var url = $('.meeting-url').val(); var name = $('.meeting-user-name').val(); - $.ajax({ - url : url + "/join?name=" + name, - dataType : "json", - type : 'GET', - success : function(data) { + Meeting.getInstance().setURL(url); + Meeting.getInstance().setName(name); + var jqxhr = Meeting.getInstance().getjoinMeetingURL(); + + jqxhr.done(function(data) { + if (data.messageKey === 'wait_for_moderator') { + waitForModerator(url); + } else { $(location).attr("href", data.response.join_url); - }, - error : function(xhr, status, error) { - }, - complete : function(xhr, status) { } }); + jqxhr.fail(function(xhr, status, error) { + console.info("meeting join failed"); + }); }); $('.meeting-url-copy').click (function (e) { @@ -33,16 +47,22 @@ var link = window.location.protocol + '//' + window.location.hostname + - '/' + - 'meetings/' + + '/meetings/' + Math.trunc(Math.random() * 1000000000); $('.meeting-url').val(link); }); - - $('.meeting-url').val(''); - $('.generate-link').click(); + if (meetingId = $('.meeting-url').data('meetingId')) { + var link = window.location.protocol + + '//' + + window.location.hostname + + '/meetings/' + + meetingId; + $('.meeting-url').val(link) + } else { + $('.generate-link').click(); + } }; var initRooms = function() { diff --git a/app/assets/javascripts/shared.js b/app/assets/javascripts/shared.js new file mode 100644 index 00000000..edf84fc9 --- /dev/null +++ b/app/assets/javascripts/shared.js @@ -0,0 +1,55 @@ +var meetingInstance = null; +class Meeting { + constructor(url, name) { + this.url = url; + this.name = name; + } + + static getInstance() { + if (meetingInstance) { + return meetingInstance; + } + var url = $('.meeting-url').val(); + var name = $('.meeting-user-name').val(); + meetingInstance = new Meeting(url, name); + return meetingInstance; + } + + getjoinMeetingURL() { + return $.get(this.url + "/join?name=" + this.name, function() { + }); + }; + + setURL(url) { + this.url = url; + } + setName(name) { + this.name = name; + } + setModJoined(modJoined) { + this.modJoined = modJoined; + } + getModJoined() { + return this.modJoined; + } + setWaitingForMod(wMod) { + this.waitingForMod = wMod; + } + getWaitingForMod() { + return this.waitingForMod; + } +} + +var loopJoin = function() { + var jqxhr = Meeting.getInstance().getjoinMeetingURL(); + jqxhr.done(function(data) { + if (data.messageKey === 'wait_for_moderator') { + setTimeout(loopJoin, 5000); + } else { + $(location).attr("href", data.response.join_url); + } + }); + jqxhr.fail(function(xhr, status, error) { + console.info("meeting join failed"); + }); +} diff --git a/app/assets/stylesheets/shared.scss b/app/assets/stylesheets/shared.scss index cea5f60a..73718437 100644 --- a/app/assets/stylesheets/shared.scss +++ b/app/assets/stylesheets/shared.scss @@ -27,7 +27,7 @@ html, body { border: 0; } -.content-box { +.center-panel { .center-block { float: none; } diff --git a/app/channels/moderator_joins_channel.rb b/app/channels/moderator_joins_channel.rb new file mode 100644 index 00000000..1d5cd143 --- /dev/null +++ b/app/channels/moderator_joins_channel.rb @@ -0,0 +1,5 @@ +class ModeratorJoinsChannel < ApplicationCable::Channel + def subscribed + stream_from "moderator_#{params[:username]}_join_channel" + end +end diff --git a/app/controllers/bbb_controller.rb b/app/controllers/bbb_controller.rb index 9e50f497..cc35c019 100644 --- a/app/controllers/bbb_controller.rb +++ b/app/controllers/bbb_controller.rb @@ -1,33 +1,46 @@ class BbbController < ApplicationController - # GET /join - # GET /join.json + # GET /:resource/:id/join def join - if ( !params.has_key?(:id) ) + if ( params[:id].blank? ) render_response("missing_parameter", "meeting token was not included", :bad_request) - elsif ( !params.has_key?(:name) ) + elsif ( params[:name].blank? ) render_response("missing_parameter", "user name was not included", :bad_request) else - bbb_join_url = helpers.bbb_join_url(params[:id], false, params[:name], false, "#{request.base_url}/#{params[:resource]}/#{params[:id]}") - if bbb_join_url[:returncode] - logger.info "#Execute the redirect" - render_response("ok", "execute the redirect", :ok, {:join_url => bbb_join_url[:join_url]}) + user = User.find_by username: params[:id] + + options = if user + { + wait_for_moderator: true, + user_is_moderator: current_user == user + } else - render_response("bigbluebutton_error", "join url could not be created", :internal_server_error) + {} end + options[:meeting_logout_url] = "#{request.base_url}/#{params[:resource]}/#{params[:id]}" + + bbb_res = helpers.bbb_join_url( + params[:id], + params[:name], + options + ) + + + if bbb_res[:returncode] && current_user && current_user == user + ActionCable.server.broadcast "moderator_#{user.username}_join_channel", + moderator: "joined" + end + + render_response bbb_res[:messageKey], bbb_res[:message], bbb_res[:status], bbb_res[:response] end end private def render_response(messageKey, message, status, response={}) - respond_to do |format| - if (status == :ok) - format.html { render :template => "bbb/join" } - format.json { render :json => { :messageKey => messageKey, :message => message, :status => status, :response => response }, :status => status } - else - format.html { render :template => "errors/error" } - format.json { render :json => { :messageKey => messageKey, :message => message, :status => status, :response => response }, :status => status } - end - end + @messageKey = messageKey + @message = message + @status = status + @response = response + render status: @status end end diff --git a/app/controllers/landing_controller.rb b/app/controllers/landing_controller.rb index 689080ef..76baeebe 100644 --- a/app/controllers/landing_controller.rb +++ b/app/controllers/landing_controller.rb @@ -10,6 +10,10 @@ class LandingController < ApplicationController end end + def wait_for_moderator + render layout: false + end + def admin? @user == current_user end @@ -18,8 +22,9 @@ class LandingController < ApplicationController private def render_meeting + @meeting_id = params[:id] params[:action] = 'meetings' - render :action => 'meeting' + render :action => 'meetings' end def render_room @@ -29,7 +34,7 @@ class LandingController < ApplicationController redirect_to root_path return end - render :action => 'room' + render :action => 'rooms' end end diff --git a/app/helpers/bbb_helper.rb b/app/helpers/bbb_helper.rb index 91130568..dce6942d 100644 --- a/app/helpers/bbb_helper.rb +++ b/app/helpers/bbb_helper.rb @@ -13,10 +13,15 @@ module BbbHelper return password end - def bbb_join_url(meeting_token, meeting_recorded=false, user_fullname='User', user_is_moderator=false, meeting_logout_url=nil) + def bbb_join_url(meeting_token, full_name, options={}) + options[:meeting_recorded] ||= false + options[:user_is_moderator] ||= false + options[:wait_for_moderator] ||= false + options[:meeting_logout_url] ||= nil + bbb ||= BigBlueButton::BigBlueButtonApi.new(bbb_endpoint + "api", bbb_secret, "0.8", true) if !bbb - return { :returncode => false, :messageKey => "BBBAPICallInvalid", :message => "BBB API call invalid." } + return call_invalid_res else meeting_id = (Digest::SHA1.hexdigest(Rails.application.secrets[:secret_key_base]+meeting_token)).to_s @@ -25,13 +30,18 @@ module BbbHelper 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] + return wait_moderator_res + end + logger.info "Message for the log file #{exc.key}: #{exc.message}" # Prepare parameters for create - logout_url = meeting_logout_url || logout_url = "#{request.base_url}" + logout_url = options[:meeting_logout_url] || "#{request.base_url}" moderator_password = random_password(12) viewer_password = random_password(12) - meeting_options = {:record => meeting_recorded.to_s, :logoutURL => logout_url, :moderatorPW => moderator_password, :attendeePW => viewer_password } + meeting_options = {:record => options[:meeting_recorded].to_s, :logoutURL => logout_url, :moderatorPW => moderator_password, :attendeePW => viewer_password } # Create the meeting bbb.create_meeting(meeting_token, meeting_id, meeting_options) @@ -40,14 +50,48 @@ module BbbHelper 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 + # Get the join url - if (user_is_moderator) + 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, user_fullname, password ) - return { :returncode => true, :join_url => join_url, :messageKey => "", :message => "" } + join_url = bbb.join_meeting_url(meeting_id, full_name, password ) + return success_res(join_url) end end + + def success_res(join_url) + { + returncode: true, + messageKey: "ok", + message: "Execute the redirect", + status: :ok, + response: { + join_url: join_url + } + } + end + + def wait_moderator_res + { + returncode: false, + messageKey: "wait_for_moderator", + message: "Waiting for moderator", + status: :ok + } + end + + def call_invalid_res + { + returncode: false, + messageKey: "BBB_API_call_invalid", + message: "BBB API call invalid.", + status: :internal_server_error + } + end end diff --git a/app/views/bbb/end.html.erb b/app/views/bbb/end.html.erb deleted file mode 100644 index ad2b2d3f..00000000 --- a/app/views/bbb/end.html.erb +++ /dev/null @@ -1,2 +0,0 @@ -
Find me in app/views/bbb/end.html.erb
diff --git a/app/views/bbb/join.html.erb b/app/views/bbb/join.html.erb deleted file mode 100644 index 55f29286..00000000 --- a/app/views/bbb/join.html.erb +++ /dev/null @@ -1,2 +0,0 @@ -Find me in app/views/bbb/join.html.erb
diff --git a/app/views/bbb/join.jbuilder b/app/views/bbb/join.jbuilder new file mode 100644 index 00000000..cc60f524 --- /dev/null +++ b/app/views/bbb/join.jbuilder @@ -0,0 +1,8 @@ +json.messageKey @messageKey +json.message @message +json.status @status +if @response + json.response do + json.join_url(@response[:join_url]) if @response[:join_url] + end +end diff --git a/app/views/landing/meeting.html.erb b/app/views/landing/meetings.html.erb similarity index 99% rename from app/views/landing/meeting.html.erb rename to app/views/landing/meetings.html.erb index d853e2fc..9bef80de 100644 --- a/app/views/landing/meeting.html.erb +++ b/app/views/landing/meetings.html.erb @@ -1,5 +1,3 @@ - - <% content_for :title do %>