Skip to content

Commit

Permalink
LTI-257: Added shared rooms feature (bigbluebutton#260)
Browse files Browse the repository at this point in the history
* replace current room with shared room if use_shared_room

needs fixing:
- keep old room, only change front page (not edit)

* Added shared rooms feature

* handle user error

---------

Co-authored-by: Jesus Federico <[email protected]>
  • Loading branch information
Mariam05 and jfederico committed Jan 23, 2024
1 parent 13feef8 commit 5a93f70
Show file tree
Hide file tree
Showing 14 changed files with 170 additions and 58 deletions.
82 changes: 46 additions & 36 deletions app/controllers/concerns/bbb_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,17 @@ module BbbHelper
# Sets a BigBlueButtonApi object for interacting with the API.
def bbb
@bbb_credentials ||= initialize_bbb_credentials
bbb_url = remove_slash(@bbb_credentials.endpoint(@room.tenant))
bbb_secret = @bbb_credentials.secret(@room.tenant)
bbb_url = remove_slash(@bbb_credentials.endpoint(room.tenant))
bbb_secret = @bbb_credentials.secret(room.tenant)
BigBlueButton::BigBlueButtonApi.new(bbb_url, bbb_secret, '1.0', Rails.logger)
rescue StandardError => e
logger.error("Error in creating BBB object: #{e}")
raise RoomsError::CustomError.new(code: 500, message: 'There was an error initializing BigBlueButton credentials', key: 'BigBlueButton Error')
end

# Generates URL for joining the current @room meeting.
# Generates URL for joining the current room meeting.
def join_meeting_url
return unless @room && @user
return unless room && @user

unless bbb
@error = {
Expand All @@ -51,40 +51,40 @@ def join_meeting_url
end

create_meeting
role = @user.moderator?(bigbluebutton_moderator_roles) || string_to_bool(@room.allModerators) ? 'moderator' : 'viewer'
role = @user.moderator?(bigbluebutton_moderator_roles) || string_to_bool(room.allModerators) ? 'moderator' : 'viewer'
join_options = {}
join_options[:createTime] = meeting_info[:createTime]
join_options[:userID] = @user.uid
bbb.join_meeting_url(@room.handler, @user.username(t("default.bigbluebutton.#{role}")), @room.attributes[role], join_options)
bbb.join_meeting_url(room.handler, @user.username(t("default.bigbluebutton.#{role}")), room.attributes[role], join_options)
end

# Create meeting for the current @room.
# Create meeting for the current room.
def create_meeting
record = bigbluebutton_recording_enabled ? string_to_bool(@room.record) : false
record = bigbluebutton_recording_enabled ? string_to_bool(room.record) : false
create_options = {
moderatorPW: @room.moderator,
attendeePW: @room.viewer,
welcome: @room.welcome,
moderatorPW: room.moderator,
attendeePW: room.viewer,
welcome: room.welcome,
record: record,
logoutURL: autoclose_url,
lockSettingsDisableCam: string_to_bool(@room.lockSettingsDisableCam),
lockSettingsDisableMic: string_to_bool(@room.lockSettingsDisableMic),
lockSettingsDisableNote: string_to_bool(@room.lockSettingsDisableNote),
lockSettingsDisablePrivateChat: string_to_bool(@room.lockSettingsDisablePrivateChat),
lockSettingsDisablePublicChat: string_to_bool(@room.lockSettingsDisablePublicChat),
autoStartRecording: string_to_bool(@room.autoStartRecording),
allowStartStopRecording: string_to_bool(@room.allowStartStopRecording),
'meta_description': @room.description.truncate(128, separator: ' '),
lockSettingsDisableCam: string_to_bool(room.lockSettingsDisableCam),
lockSettingsDisableMic: string_to_bool(room.lockSettingsDisableMic),
lockSettingsDisableNote: string_to_bool(room.lockSettingsDisableNote),
lockSettingsDisablePrivateChat: string_to_bool(room.lockSettingsDisablePrivateChat),
lockSettingsDisablePublicChat: string_to_bool(room.lockSettingsDisablePublicChat),
autoStartRecording: string_to_bool(room.autoStartRecording),
allowStartStopRecording: string_to_bool(room.allowStartStopRecording),
'meta_description': room.description.truncate(128, separator: ' '),
}
# Send the create request.
bbb.create_meeting(@room.name, @room.handler, create_options)
bbb.create_meeting(room.name, room.handler, create_options)
end

# Perform ends meeting for the current @room.
# Perform ends meeting for the current room.
def end_meeting
response = { returncode: 'FAILED' }
begin
response = bbb.end_meeting(@room.handler, @room.moderator)
response = bbb.end_meeting(room.handler, room.moderator)
rescue BigBlueButton::BigBlueButtonException
# this can be thrown if all participants left (clicked 'x' before pressing the end button)
end
Expand All @@ -95,30 +95,30 @@ def end_meeting
def meeting_info
info = { returncode: 'FAILED' }
begin
info = bbb.get_meeting_info(@room.handler, @user)
info = bbb.get_meeting_info(room.handler, @user)
rescue BigBlueButton::BigBlueButtonException => e
logger.error(e.to_s)
end
info
end

# Checks if the meeting for current @room is running.
# Checks if the meeting for current room is running.
def meeting_running?
bbb.is_meeting_running?(@room.handler)
bbb.is_meeting_running?(room.handler)
rescue BigBlueButton::BigBlueButtonException => e
logger.error(e.to_s)
end

# Fetches all recordings for a room.
def recordings
res = Rails.cache.fetch("#{@room.handler}/#{RECORDINGS_KEY}", expires_in: 30.minutes) if Rails.configuration.cache_enabled
res ||= bbb.get_recordings(meetingID: @room.handler)
res = Rails.cache.fetch("#{room.handler}/#{RECORDINGS_KEY}", expires_in: 30.minutes) if Rails.configuration.cache_enabled
res ||= bbb.get_recordings(meetingID: room.handler)
recordings_formatted(res)
end

# Fetch an individual recording
def recording(record_id)
r = bbb.get_recordings(meetingID: @room.handler, recordID: record_id)
r = bbb.get_recordings(meetingID: room.handler, recordID: record_id)
unless r.key?(:error)

r[:playbacks] = if !r[:playback] || !r[:playback][:format]
Expand All @@ -137,7 +137,7 @@ def recording(record_id)

def server_running?
begin
bbb.get_meeting_info(@room.handler, @user)
bbb.get_meeting_info(room.handler, @user)
rescue BigBlueButton::BigBlueButtonException => e
logger.info('We could not find a meeting with that meeting ID')
return e.to_s
Expand All @@ -148,34 +148,34 @@ def server_running?

# Deletes a recording.
def delete_recording(record_id)
Rails.cache.delete("#{@room.handler}/#{RECORDINGS_KEY}") if Rails.configuration.cache_enabled
Rails.cache.delete("#{room.handler}/#{RECORDINGS_KEY}") if Rails.configuration.cache_enabled
bbb.delete_recordings(record_id)
end

# Publishes a recording.
def publish_recording(record_id)
Rails.cache.delete("#{@room.handler}/#{RECORDINGS_KEY}") if Rails.configuration.cache_enabled
Rails.cache.delete("#{room.handler}/#{RECORDINGS_KEY}") if Rails.configuration.cache_enabled
bbb.publish_recordings(record_id, true)
end

# Unpublishes a recording.
def unpublish_recording(record_id)
Rails.cache.delete("#{@room.handler}/#{RECORDINGS_KEY}") if Rails.configuration.cache_enabled
Rails.cache.delete("#{room.handler}/#{RECORDINGS_KEY}") if Rails.configuration.cache_enabled
bbb.publish_recordings(record_id, false)
end

# Updates a recording.
def update_recording(record_id, meta)
Rails.cache.delete("#{@room.handler}/#{RECORDINGS_KEY}") if Rails.configuration.cache_enabled
Rails.cache.delete("#{room.handler}/#{RECORDINGS_KEY}") if Rails.configuration.cache_enabled
meta[:recordID] = record_id
bbb.send_api_request('updateRecordings', meta)
end

# Check if the current @user must wait for moderator to join the current @room.
# Check if the current @user must wait for moderator to join the current room.
def wait_for_mod?
return unless @room && @user
return unless room && @user

wait_setting = @room.waitForModerator != '0'
wait_setting = room.waitForModerator != '0'
wait_setting && !@user.moderator?(bigbluebutton_moderator_roles)
end

Expand Down Expand Up @@ -268,4 +268,14 @@ def recordings_formatted(res)
def string_to_bool(value)
ActiveModel::Type::Boolean.new.cast(value)
end

# If the room is using a shared code, then use the shared room's recordings and bbb link
def room
use_shared_room? ? @shared_room : @room
end

# Returns true only if @room.use_shared_code and the shared code is valid
def use_shared_room?
@room.use_shared_code && Room.where(code: @room.shared_code, tenant: @room.tenant).exists?
end
end
10 changes: 5 additions & 5 deletions app/controllers/concerns/broker_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ module BrokerHelper
# Fetch tenant settings from the broker
def tenant_settings(options = {})
tenant = options[:tenant] || @room&.tenant || ''
Rails.cache.fetch("rooms/tenant_settings/#{tenant}", expires_in: 1.hour) do
bbbltibroker_url = omniauth_bbbltibroker_url("/api/v1/tenants/#{tenant}")
get_response = RestClient.get(bbbltibroker_url, 'Authorization' => "Bearer #{omniauth_client_token(omniauth_bbbltibroker_url)}")
# Rails.cache.fetch("rooms/tenant_settings/#{tenant}", expires_in: 1.hour) do
bbbltibroker_url = omniauth_bbbltibroker_url("/api/v1/tenants/#{tenant}")
get_response = RestClient.get(bbbltibroker_url, 'Authorization' => "Bearer #{omniauth_client_token(omniauth_bbbltibroker_url)}")

JSON.parse(get_response)
end
JSON.parse(get_response)
# end
rescue StandardError => e
Rails.logger.error("Could not fetch tenant credentials from broker. Error message: #{e}")
nil
Expand Down
19 changes: 17 additions & 2 deletions app/controllers/rooms_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,16 @@ def create
# PATCH/PUT /rooms/1.json
def update
respond_to do |format|
if @room.update(room_params)
# block update if shared_code doesn't exist
shared_code = room_params[:shared_code]
code_found = shared_code.blank? ? true : Room.where(code: shared_code, tenant: @room.tenant).exists?

if code_found && @room.update(room_params)
format.html { redirect_to(room_path(@room, launch_nonce: params[:launch_nonce]), notice: t('default.room.updated')) }
format.json { render(:show, status: :ok, location: @room) }
else
# If the room wasn't updated because a code was not found then show an error message
flash.now[:alert] = code_found ? nil : t('error.room.codenotfound.message')
format.html { render(:edit) }
format.json { render(json: @error, status: :unprocessable_entity) }
end
Expand Down Expand Up @@ -267,6 +273,9 @@ def authenticate_user!
# Use callbacks to share common setup or constraints between actions.
def set_room
@room = Room.find_by(id: params[:id])
@shared_room = Room.find_by(code: @room.shared_code, tenant: @room.tenant) if @room&.use_shared_code
logger.debug("Room with id #{params[:id]} is using shared code: #{@room&.shared_code}") if @room&.use_shared_code

# Exit with error if room was not found
set_error('notfound', :not_found) && return unless @room
# Exit with error by re-setting the room to nil if the session for the room.handler is not set
Expand Down Expand Up @@ -337,6 +346,9 @@ def room_params
:all_moderators,
:hide_name,
:hide_description,
:code,
:shared_code,
:use_shared_code,
settings: Room.stored_attributes[:settings]
)
end
Expand All @@ -353,7 +365,10 @@ def launch_params_to_new_room_params(handler, handler_legacy, launch_params)
all_moderators: message_has_custom?(launch_params, 'all_moderators') || false,
hide_name: message_has_custom?(launch_params, 'hide_name') || false,
hide_description: message_has_custom?(launch_params, 'hide_description') || false,
settings: message_has_custom?(launch_params, 'settings') || {}
settings: message_has_custom?(launch_params, 'settings') || {},
code: '',
shared_code: '',
use_shared_code: false
)
end

Expand Down
29 changes: 26 additions & 3 deletions app/javascript/packs/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ $(document).on('turbolinks:load', function(){
if (wait_mod_checked){
$('#allModerators_checkbox').prop("checked", false);
}
})


})

function check_record_status(){
var record_checked = $('#record_checkbox').prop("checked");
Expand All @@ -52,4 +50,29 @@ $(document).on('turbolinks:load', function(){
$('#record_checkbox').on('click', function() {
check_record_status();
})

// If shared room is selected, allow the code field to be editable
$('#use_shared_code_checkbox').on('click', function() {
var use_shared_code_checked = $('#use_shared_code_checkbox').prop("checked");
if (use_shared_code_checked){
$('#shared_code_field').prop("disabled", false);
$('#shared_code_field').val('');
} else {
$('#shared_code_field').prop("disabled", true);
console.log("code_val: = ",$('#room_code_value').val() )
$('#shared_code_field').val($('#room_code_value').val());
}
})

function checkSharedCodeCheckboxStatus() {
var sharedcode_checked = $('#use_shared_code_checkbox').prop("checked");
if (!sharedcode_checked){
$('#shared_code_field').prop("disabled", true);
} else {
$('#shared_code_field').prop("disabled", false);
}
}

checkSharedCodeCheckboxStatus();

});
14 changes: 13 additions & 1 deletion app/models/room.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,19 @@
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
class Room < ApplicationRecord
before_save :default_values
validates :code, uniqueness: true

store_accessor :settings, [:lockSettingsDisableCam, :lockSettingsDisableMic, :lockSettingsDisablePrivateChat, :lockSettingsDisablePublicChat, :lockSettingsDisableNote]
store_accessor :settings, [:waitForModerator, :allModerators, :record, :autoStartRecording, :allowStartStopRecording]

# after_find is used for the following so that rooms that already exist will have these fields upon launch
after_find :initialize_setting_defaults, if: :settings_blank?
after_find :delete_settings
after_find :set_empty_code

attr_accessor :can_grade

RECORDING_SETTINGS = [:record, :autoStartRecording, :allowStartStopRecording].freeze
CODE_LENGTH = 10

def default_values
self.handler ||= Digest::SHA1.hexdigest(SecureRandom.uuid)
Expand Down Expand Up @@ -101,4 +105,12 @@ def bool_to_binary(value)

'0'
end

# Assign a random alphanumeric code to the room if it doesn't already have one
# Assign the shared_code to equal to the room's code.
def set_empty_code
self.code = SecureRandom.alphanumeric(CODE_LENGTH) if code.blank?
self.shared_code = code if shared_code.blank?
save!
end
end
19 changes: 19 additions & 0 deletions app/views/rooms/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,25 @@
<hr>
<% end %>

<!-- Shared Room Stuff -->
<%= form.hidden_field :code, id: 'room_code_value', value: @room.code %>

<div class="field form-group input-group w-full pt-4">
<%= form.label t('default.room.code') %>
<%= form.text_field :shared_code, class: "form-control input mt-1 block disabled:border-slate-200 disabled:text-slate-500 disabled:shadow-none disabled:bg-slate-100", id: 'shared_code_field', disabled: true %>
</div>

<% unless flash[:alert] == nil %>
<div class="ml-3 text-sm font-medium text-red-500">
<%= flash.alert %>
</div>
<% end %>
<div class="field form-group input-group">
<%= form.check_box :use_shared_code, id: 'use_shared_code_checkbox' %>&nbsp;
<%= t('default.room.usesharedcode') %>&nbsp;
<br>
</div>


<div class="actions pt-6">
<div class = "flex-row">
Expand Down
Loading

0 comments on commit 5a93f70

Please sign in to comment.