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 c3b3fde3..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) { 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 8181a343..cc35c019 100644 --- a/app/controllers/bbb_controller.rb +++ b/app/controllers/bbb_controller.rb @@ -2,9 +2,9 @@ class BbbController < ApplicationController # GET /:resource/:id/join def join - if ( !params[:id] ) + if ( params[:id].blank? ) render_response("missing_parameter", "meeting token was not included", :bad_request) - elsif ( !params[:name] ) + elsif ( params[:name].blank? ) render_response("missing_parameter", "user name was not included", :bad_request) else user = User.find_by username: params[:id] @@ -25,6 +25,12 @@ class BbbController < ApplicationController 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 @@ -35,6 +41,6 @@ class BbbController < ApplicationController @message = message @status = status @response = response - render status: @status && return + render status: @status end end diff --git a/app/controllers/landing_controller.rb b/app/controllers/landing_controller.rb index 462f749b..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 @@ -20,7 +24,7 @@ class LandingController < ApplicationController def render_meeting @meeting_id = params[:id] params[:action] = 'meetings' - render :action => 'meeting' + render :action => 'meetings' end def render_room @@ -30,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 f0034065..dce6942d 100644 --- a/app/helpers/bbb_helper.rb +++ b/app/helpers/bbb_helper.rb @@ -29,11 +29,12 @@ module BbbHelper 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] return wait_moderator_res end - # This means that is not created logger.info "Message for the log file #{exc.key}: #{exc.message}" # Prepare parameters for create @@ -79,7 +80,7 @@ module BbbHelper def wait_moderator_res { returncode: false, - messageKey: "WaitModerator", + messageKey: "wait_for_moderator", message: "Waiting for moderator", status: :ok } @@ -88,7 +89,7 @@ module BbbHelper def call_invalid_res { returncode: false, - messageKey: "BBBAPICallInvalid", + messageKey: "BBB_API_call_invalid", message: "BBB API call invalid.", status: :internal_server_error } 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 %>
Hi Everyone diff --git a/app/views/landing/room.html.erb b/app/views/landing/rooms.html.erb similarity index 58% rename from app/views/landing/room.html.erb rename to app/views/landing/rooms.html.erb index 55870e01..7900b70f 100644 --- a/app/views/landing/room.html.erb +++ b/app/views/landing/rooms.html.erb @@ -21,16 +21,18 @@ <%= render 'shared/title', title: page_title %> - <%= render layout: 'shared/center_panel' do %> -
- <% if current_user == @user %> - <%= render 'shared/meeting_url', hidden: false %> - <% else %> - <%= render 'shared/meeting_url', hidden: true %> - <% end %> - <%= render 'shared/join_form', user: current_user %> -
- <% end %> +
+ <%= render layout: 'shared/center_panel' do %> +
+ <% if current_user == @user %> + <%= render 'shared/meeting_url', hidden: false %> + <% else %> + <%= render 'shared/meeting_url', hidden: true %> + <% end %> + <%= render 'shared/join_form', user: current_user %> +
+ <% end %> +
diff --git a/app/views/landing/wait_for_moderator.html.erb b/app/views/landing/wait_for_moderator.html.erb new file mode 100644 index 00000000..b3b53c46 --- /dev/null +++ b/app/views/landing/wait_for_moderator.html.erb @@ -0,0 +1,11 @@ +<% content_for :title do %> +
+ Looks like you're the first one here... +
+ + You will automatically join when the meeting starts + +<% end %> + +<%= render layout: 'shared/center_panel' do %> +<% end %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index e85c3218..7d921a3c 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -3,6 +3,7 @@ Greenlight <%= csrf_meta_tags %> + <%= action_cable_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> diff --git a/app/views/shared/_center_panel.html.erb b/app/views/shared/_center_panel.html.erb index cc3395ec..b2cf8d3f 100644 --- a/app/views/shared/_center_panel.html.erb +++ b/app/views/shared/_center_panel.html.erb @@ -1,4 +1,4 @@ -
+
diff --git a/config/environments/development.rb b/config/environments/development.rb index 6f719704..b91c71aa 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -31,6 +31,12 @@ Rails.application.configure do config.action_mailer.perform_caching = false + # action cable socket URI + config.action_cable.url = "ws://localhost/cable" + + # allowed action cable origins + Rails.application.config.action_cable.allowed_request_origins = ['http://localhost'] + # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log diff --git a/config/routes.rb b/config/routes.rb index 55c6cfce..188c6eb7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,7 @@ +# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html Rails.application.routes.draw do + mount ActionCable.server => '/cable' + resources :users, only: [:edit, :update] get '/users/logout', to: 'sessions#destroy', as: :user_logout @@ -7,9 +10,9 @@ Rails.application.routes.draw do # There are two resources [meetings|rooms] # meetings offer a landing page for NON authenticated users to create and join session in BigBlueButton # rooms offer a customized landing page for authenticated users to create and join session in BigBlueButton - get '/:resource(/:id)', to: 'landing#index', as: :resource + get '/:resource/:id', to: 'landing#index', as: :resource get '/:resource/:id/join', to: 'bbb#join', as: :bbb_join, defaults: { :format => 'json' } + get '/:resource/:id/wait', to: 'landing#wait_for_moderator' root to: 'landing#index', :resource => "meetings" - # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html end