Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LTI-257: Added shared rooms feature #260

Merged
merged 4 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 && [email protected]?(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
Loading