restructure app
This commit is contained in:
parent
5042e2572c
commit
32ec2bacce
18
Gemfile.lock
18
Gemfile.lock
|
@ -1,8 +1,6 @@
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
action_interceptor (1.1.0)
|
||||
rails (>= 3.1)
|
||||
actioncable (5.0.7)
|
||||
actionpack (= 5.0.7)
|
||||
nio4r (>= 1.2, < 3.0)
|
||||
|
@ -79,12 +77,6 @@ GEM
|
|||
faraday (0.12.2)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ffi (1.9.23)
|
||||
fine_print (3.1.0)
|
||||
action_interceptor (>= 1.0)
|
||||
jquery-rails
|
||||
rails (>= 3.1)
|
||||
responders
|
||||
squeel
|
||||
font-awesome-sass (5.0.13)
|
||||
sassc (>= 1.11)
|
||||
globalid (0.4.1)
|
||||
|
@ -141,8 +133,6 @@ GEM
|
|||
omniauth-twitter (1.4.0)
|
||||
omniauth-oauth (~> 1.1)
|
||||
rack
|
||||
polyamorous (1.1.0)
|
||||
activerecord (>= 3.0)
|
||||
popper_js (1.12.9)
|
||||
puma (3.11.4)
|
||||
rack (2.0.5)
|
||||
|
@ -179,9 +169,6 @@ GEM
|
|||
rb-fsevent (0.10.3)
|
||||
rb-inotify (0.9.10)
|
||||
ffi (>= 0.5.0, < 2)
|
||||
responders (2.4.0)
|
||||
actionpack (>= 4.2.0, < 5.3)
|
||||
railties (>= 4.2.0, < 5.3)
|
||||
rspec-core (3.7.1)
|
||||
rspec-support (~> 3.7.0)
|
||||
rspec-expectations (3.7.0)
|
||||
|
@ -227,10 +214,6 @@ GEM
|
|||
activesupport (>= 4.0)
|
||||
sprockets (>= 3.0.0)
|
||||
sqlite3 (1.3.13)
|
||||
squeel (1.2.3)
|
||||
activerecord (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
polyamorous (~> 1.1.0)
|
||||
tabler-rubygem (0.1.2)
|
||||
autoprefixer-rails (>= 6.0.3)
|
||||
thor (0.20.0)
|
||||
|
@ -265,7 +248,6 @@ DEPENDENCIES
|
|||
dotenv-rails
|
||||
factory_bot_rails
|
||||
faker
|
||||
fine_print
|
||||
font-awesome-sass (~> 5.0.13)
|
||||
jbuilder (~> 2.5)
|
||||
jquery-rails
|
||||
|
|
|
@ -48,6 +48,10 @@ $rule-color: lightblue;
|
|||
padding-bottom: 56.25%;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.start-block {
|
||||
background-color: white;
|
||||
border: 3px solid lightblue;
|
||||
|
@ -66,6 +70,10 @@ iframe{
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
html, body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
// Place all the styles related to the Meetings controller here.
|
||||
// They will automatically be included in application.css.
|
||||
// You can use Sass (SCSS) here: http://sass-lang.com/
|
|
@ -47,9 +47,9 @@ class ApplicationController < ActionController::Base
|
|||
def default_meeting_options
|
||||
{
|
||||
user_is_moderator: false,
|
||||
meeting_logout_url: request.base_url + logout_room_path(@room.uid),
|
||||
meeting_logout_url: request.base_url + logout_room_path(@room),
|
||||
meeting_recorded: true,
|
||||
moderator_message: "To invite someone to the meeting, send them this link:\n\n#{request.base_url + room_path(@room.uid)}"
|
||||
moderator_message: "To invite someone to the meeting, send them this link:\n\n#{request.base_url + room_path(@room)}"
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,6 @@ class MainController < ApplicationController
|
|||
|
||||
# GET /
|
||||
def index
|
||||
@meeting = Meeting.new
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
class MeetingsController < ApplicationController
|
||||
|
||||
# GET /m/:meeting_uid
|
||||
def show
|
||||
@meeting = Meeting.find_by(uid: params[:meeting_uid])
|
||||
if @meeting
|
||||
|
||||
else
|
||||
# Handle meeting doesn't exist.
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
# POST /m/:meeting_uid
|
||||
def join
|
||||
meeting = Meeting.find_by(uid: params[:meeting_uid])
|
||||
if meeting
|
||||
# If the user is logged in, join using their authenticated name.
|
||||
if current_user
|
||||
redirect_to meeting.join_path(current_user.name)
|
||||
# Otherwise, use their inputed join name.
|
||||
elsif params[:join_name]
|
||||
redirect_to meeting.join_path(params[:join_name])
|
||||
end
|
||||
else
|
||||
# Handle meeting doesn't exist.
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
# POST /m
|
||||
def create
|
||||
meeting = Meeting.new(meeting_params)
|
||||
if meeting.save
|
||||
redirect_to meeting_path(meeting_uid: meeting.uid)
|
||||
else
|
||||
redirect_to root_path
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def meeting_params
|
||||
params.require(:meeting).permit(:name)
|
||||
end
|
||||
end
|
|
@ -1,27 +1,46 @@
|
|||
class RoomsController < ApplicationController
|
||||
|
||||
before_action :find_room, :verify_room_ownership
|
||||
skip_before_action :verify_room_ownership, only: [:show, :join, :wait]
|
||||
before_action :find_room, except: :create
|
||||
|
||||
# GET /r/:room_uid
|
||||
#before_action :verify_room_ownership
|
||||
#skip_before_action :verify_room_ownership, only: [:create, :show, :join, :wait]
|
||||
|
||||
# POST /r
|
||||
def create
|
||||
room = Room.new(name: room_params[:name])
|
||||
room.user = current_user
|
||||
|
||||
if room.save
|
||||
redirect_to room
|
||||
else
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
# GET/POST /r/:room_uid
|
||||
def show
|
||||
opts = default_meeting_options
|
||||
|
||||
if @meeting.is_running?
|
||||
if @room.is_running?
|
||||
if current_user
|
||||
# If you don't own the room but the meeting is running, join up.
|
||||
if !@room.owned_by?(current_user)
|
||||
opts[:user_is_moderator] = false
|
||||
redirect_to @meeting.join_path(current_user.name, opts)
|
||||
redirect_to @room.join_path(current_user, opts)
|
||||
end
|
||||
else
|
||||
# If you're unauthenticated, you must enter a name to join the meeting.
|
||||
redirect_to join_room_path(@room.uid)
|
||||
if params[:join_name]
|
||||
redirect_to @room.join_path(params[:join_name], opts)
|
||||
else
|
||||
# Render the join page so they can supply their name.
|
||||
render :join
|
||||
end
|
||||
end
|
||||
else
|
||||
# If the meeting isn't running and you don't own the room, go to the waiting page.
|
||||
if !@room.owned_by?(current_user)
|
||||
redirect_to wait_room_path(@room.uid)
|
||||
redirect_to wait_room_path(@room)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -31,47 +50,19 @@ class RoomsController < ApplicationController
|
|||
# Join the user in and start the meeting.
|
||||
opts = default_meeting_options
|
||||
opts[:user_is_moderator] = true
|
||||
redirect_to @meeting.join_path(current_user.name, opts)
|
||||
end
|
||||
|
||||
# GET /r/:room_uid/join
|
||||
def join
|
||||
if @meeting.is_running?
|
||||
opts = default_meeting_options
|
||||
|
||||
if current_user
|
||||
# If the user exists, join them in.
|
||||
opts[:user_is_moderator] = @room.owned_by?(current_user)
|
||||
redirect_to @meeting.join_path(current_user.name, opts)
|
||||
else
|
||||
# If they are unauthenticated, prompt for join name.
|
||||
if params[:join_name]
|
||||
redirect_to @meeting.join_path(params[:join_name], opts)
|
||||
else
|
||||
# Render the join page so they can supply their name.
|
||||
render :join
|
||||
end
|
||||
end
|
||||
else
|
||||
if @room.owned_by?(current_user)
|
||||
# Redirect owner to room.
|
||||
redirect_to room_path(@room.uid)
|
||||
else
|
||||
# Otherwise, they have to wait for the meeting to start.
|
||||
redirect_to wait_room_path(@room.uid)
|
||||
end
|
||||
end
|
||||
redirect_to @room.join_path(current_user, opts)
|
||||
end
|
||||
|
||||
# GET/POST /r/:room_uid/wait
|
||||
def wait
|
||||
if @meeting.is_running?
|
||||
if @room.is_running?
|
||||
if current_user
|
||||
# If they are logged in and waiting, use their account name.
|
||||
redirect_to @meeting.join_path(current_user.name, default_meeting_options)
|
||||
redirect_to @room.join_path(current_user, default_meeting_options)
|
||||
elsif !params[:unauthenticated_join_name].blank?
|
||||
# Otherwise, use the name they submitted on the wating page.
|
||||
redirect_to @meeting.join_path(params[:unauthenticated_join_name], default_meeting_options)
|
||||
redirect_to @room.join_path(params[:unauthenticated_join_name], default_meeting_options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -79,7 +70,7 @@ class RoomsController < ApplicationController
|
|||
# GET /r/:room_uid/logout
|
||||
def logout
|
||||
# Redirect the owner to their room.
|
||||
redirect_to room_path(@room.uid)
|
||||
redirect_to root_path
|
||||
end
|
||||
|
||||
# GET /r/:room_uid/sessions
|
||||
|
@ -89,6 +80,10 @@ class RoomsController < ApplicationController
|
|||
|
||||
private
|
||||
|
||||
def room_params
|
||||
params.require(:room).permit(:name, :auto_join)
|
||||
end
|
||||
|
||||
# Find the room from the uid.
|
||||
def find_room
|
||||
@room = Room.find_by(uid: params[:room_uid])
|
||||
|
@ -97,8 +92,6 @@ class RoomsController < ApplicationController
|
|||
# Handle room doesn't exist.
|
||||
|
||||
end
|
||||
|
||||
@meeting = @room.meeting
|
||||
end
|
||||
|
||||
# Ensure the user is logged into the room they are accessing.
|
||||
|
|
|
@ -1,156 +0,0 @@
|
|||
class Meeting < ApplicationRecord
|
||||
|
||||
before_create :generate_meeting_id
|
||||
|
||||
validates :name, presence: true
|
||||
|
||||
belongs_to :room, optional: true
|
||||
|
||||
RETURNCODE_SUCCESS = "SUCCESS"
|
||||
|
||||
# Creates a meeting on the BigBlueButton server.
|
||||
def start_meeting(options = {})
|
||||
create_options = {
|
||||
record: options[:meeting_recorded].to_s,
|
||||
logoutURL: options[:meeting_logout_url] || '',
|
||||
moderatorPW: random_password(12),
|
||||
attendeePW: random_password(12),
|
||||
moderatorOnlyMessage: options[:moderator_message]
|
||||
}
|
||||
|
||||
#meeting_options.merge!(
|
||||
#{ "meta_room-id": options[:room_owner],
|
||||
# "meta_meeting-name": options[:meeting_name]}
|
||||
#) if options[:room_owner]
|
||||
|
||||
# Send the create request.
|
||||
begin
|
||||
bbb.create_meeting(name, uid, create_options)
|
||||
rescue BigBlueButton::BigBlueButtonException => exc
|
||||
puts "BigBlueButton failed on create: #{exc.key}: #{exc.message}"
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a URL to join a user into a meeting.
|
||||
def join_path(username, options = {})
|
||||
# Create the meeting if it isn't running.
|
||||
start_meeting(options) unless is_running?
|
||||
|
||||
# Set meeting options.
|
||||
options[:meeting_logout_url] ||= nil
|
||||
options[:moderator_message] ||= ''
|
||||
options[:user_is_moderator] ||= false
|
||||
options[:meeting_recorded] ||= false
|
||||
|
||||
#options[:wait_for_moderator] ||= false
|
||||
#options[:meeting_name] ||= name
|
||||
#options[:room_owner] ||= nil
|
||||
|
||||
return call_invalid_res if !bbb
|
||||
|
||||
# Get the meeting info.
|
||||
meeting_info = bbb.get_meeting_info(uid, nil)
|
||||
|
||||
# Determine the password to use when joining.
|
||||
password = if options[:user_is_moderator]
|
||||
meeting_info[:moderatorPW]
|
||||
else
|
||||
meeting_info[:attendeePW]
|
||||
end
|
||||
|
||||
# Generate the join URL.
|
||||
bbb.join_meeting_url(uid, username, password)
|
||||
end
|
||||
|
||||
# Fetches all recordings for a meeting.
|
||||
def recordings
|
||||
res = bbb.get_recordings(meetingID: uid)
|
||||
res[:recordings]
|
||||
end
|
||||
|
||||
# Checks if a meeting is running on the BigBlueButton server.
|
||||
def is_running?
|
||||
begin
|
||||
bbb.get_meeting_info(uid, nil)
|
||||
return true
|
||||
rescue BigBlueButton::BigBlueButtonException => exc
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def bbb_endpoint
|
||||
Rails.configuration.bigbluebutton_endpoint
|
||||
end
|
||||
|
||||
def bbb_secret
|
||||
Rails.configuration.bigbluebutton_secret
|
||||
end
|
||||
|
||||
# Sets a BigBlueButtonApi object for interacting with the API.
|
||||
def bbb
|
||||
@bbb ||= if Rails.configuration.loadbalanced_configuration
|
||||
lb_user = retrieve_loadbalanced_credentials(self.room.user.provider)
|
||||
BigBlueButton::BigBlueButtonApi.new(remove_slash(lb_user["apiURL"]), lb_user["secret"], "0.8")
|
||||
else
|
||||
BigBlueButton::BigBlueButtonApi.new(remove_slash(bbb_endpoint), bbb_secret, "0.8")
|
||||
end
|
||||
end
|
||||
|
||||
# Rereives the loadbalanced BigBlueButton credentials for a user.
|
||||
def retrieve_loadbalanced_credentials(provider)
|
||||
# Include Omniauth accounts under the Greenlight provider.
|
||||
provider = "greenlight" if Rails.configuration.providers.include?(provider.to_sym)
|
||||
|
||||
# Build the URI.
|
||||
uri = encode_bbb_url(
|
||||
Rails.configuration.loadbalancer_endpoint,
|
||||
Rails.configuration.loadbalancer_secret,
|
||||
{name: provider}
|
||||
)
|
||||
|
||||
# Make the request.
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
http.use_ssl = (uri.scheme == 'https')
|
||||
response = http.get(uri.request_uri)
|
||||
|
||||
unless response.kind_of?(Net::HTTPSuccess)
|
||||
raise "Error retrieving provider credentials: #{response.code} #{response.message}"
|
||||
end
|
||||
|
||||
# Parse XML.
|
||||
doc = XmlSimple.xml_in(response.body, 'ForceArray' => false)
|
||||
|
||||
# Return the user credentials if the request succeeded on the loadbalancer.
|
||||
return doc['user'] if doc['returncode'] == RETURNCODE_SUCCESS
|
||||
|
||||
raise "User with provider #{provider} does not exist." if doc['messageKey'] == "noSuchUser"
|
||||
raise "API call #{url} failed with #{doc['messageKey']}."
|
||||
end
|
||||
|
||||
# Builds a request to retrieve credentials from the load balancer.
|
||||
def encode_bbb_url(base_url, secret, params)
|
||||
encoded_params = OAuth::Helper.normalize(params)
|
||||
string = "getUser" + encoded_params + secret
|
||||
checksum = OpenSSL::Digest.digest('sha1', string).unpack("H*").first
|
||||
|
||||
URI.parse("#{base_url}?#{encoded_params}&checksum=#{checksum}")
|
||||
end
|
||||
|
||||
# Removes trailing forward slash from a URL.
|
||||
def remove_slash(s)
|
||||
s.nil? ? nil : s.chomp("/")
|
||||
end
|
||||
|
||||
# Generates a BigBlueButton meeting id from a meeting token.
|
||||
def generate_meeting_id
|
||||
self.uid = Digest::SHA1.hexdigest(Rails.application.secrets[:secret_key_base] + name + Time.now.to_i.to_s).to_s
|
||||
end
|
||||
|
||||
# Generates a random password for a meeting.
|
||||
def random_password(length)
|
||||
o = ([('a'..'z'), ('A'..'Z')].map do |i| i.to_a end).flatten
|
||||
((0...length).map do o[rand(o.length)] end).join
|
||||
end
|
||||
end
|
|
@ -1,23 +1,174 @@
|
|||
class Room < ApplicationRecord
|
||||
|
||||
before_create :set_uid
|
||||
before_create :generate_uids
|
||||
|
||||
belongs_to :user
|
||||
has_one :meeting
|
||||
|
||||
RETURNCODE_SUCCESS = "SUCCESS"
|
||||
|
||||
def to_param
|
||||
uid
|
||||
end
|
||||
|
||||
# Determines if a user owns a room.
|
||||
def owned_by?(user)
|
||||
return false if user.nil?
|
||||
user.room == self
|
||||
user.rooms.include?(self)
|
||||
end
|
||||
|
||||
# Checks if a room is running on the BigBlueButton server.
|
||||
def is_running?
|
||||
begin
|
||||
bbb.get_meeting_info(bbb_id, nil)
|
||||
return true
|
||||
rescue BigBlueButton::BigBlueButtonException => exc
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
# Determines the invite URL for the room.
|
||||
def invite_path
|
||||
"/r/#{uid}"
|
||||
end
|
||||
|
||||
# Creates a meeting on the BigBlueButton server.
|
||||
def start_session(options = {})
|
||||
create_options = {
|
||||
record: options[:meeting_recorded].to_s,
|
||||
logoutURL: options[:meeting_logout_url] || '',
|
||||
moderatorPW: random_password(12),
|
||||
attendeePW: random_password(12),
|
||||
moderatorOnlyMessage: options[:moderator_message]
|
||||
}
|
||||
|
||||
#meeting_options.merge!(
|
||||
#{ "meta_room-id": options[:room_owner],
|
||||
# "meta_meeting-name": options[:meeting_name]}
|
||||
#) if options[:room_owner]
|
||||
|
||||
# Send the create request.
|
||||
begin
|
||||
bbb.create_meeting(name, bbb_id, create_options)
|
||||
rescue BigBlueButton::BigBlueButtonException => exc
|
||||
puts "BigBlueButton failed on create: #{exc.key}: #{exc.message}"
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a URL to join a user into a meeting.
|
||||
def join_path(user, options = {})
|
||||
user = user.name if user.is_a?(User)
|
||||
|
||||
# Create the meeting if it isn't running.
|
||||
start_session(options) unless is_running?
|
||||
|
||||
# Set meeting options.
|
||||
options[:meeting_logout_url] ||= nil
|
||||
options[:moderator_message] ||= ''
|
||||
options[:user_is_moderator] ||= false
|
||||
options[:meeting_recorded] ||= false
|
||||
|
||||
#options[:wait_for_moderator] ||= false
|
||||
#options[:meeting_name] ||= name
|
||||
#options[:room_owner] ||= nil
|
||||
|
||||
return call_invalid_res if !bbb
|
||||
|
||||
# Get the meeting info.
|
||||
meeting_info = bbb.get_meeting_info(bbb_id, nil)
|
||||
|
||||
# Determine the password to use when joining.
|
||||
password = if options[:user_is_moderator]
|
||||
meeting_info[:moderatorPW]
|
||||
else
|
||||
meeting_info[:attendeePW]
|
||||
end
|
||||
|
||||
# Generate the join URL.
|
||||
bbb.join_meeting_url(bbb_id, user, password)
|
||||
end
|
||||
|
||||
# Fetches all recordings for a meeting.
|
||||
def recordings
|
||||
res = bbb.get_recordings(meetingID: bbb_id)
|
||||
res[:recordings]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Generates a uid for the room.
|
||||
def set_uid
|
||||
digest = user.id.to_s + user.provider + user.username
|
||||
digest += user.uid unless user.uid.nil?
|
||||
|
||||
self.uid = [user.name.split(' ').first.downcase, Digest::SHA1.hexdigest(digest)[0..7]].join('-')
|
||||
def bbb_endpoint
|
||||
Rails.configuration.bigbluebutton_endpoint
|
||||
end
|
||||
end
|
||||
|
||||
def bbb_secret
|
||||
Rails.configuration.bigbluebutton_secret
|
||||
end
|
||||
|
||||
# Sets a BigBlueButtonApi object for interacting with the API.
|
||||
def bbb
|
||||
@bbb = BigBlueButton::BigBlueButtonApi.new(remove_slash(bbb_endpoint), bbb_secret, "0.8")
|
||||
#@bbb ||= if Rails.configuration.loadbalanced_configuration
|
||||
# lb_user = retrieve_loadbalanced_credentials(self.room.user.provider)
|
||||
# BigBlueButton::BigBlueButtonApi.new(remove_slash(lb_user["apiURL"]), lb_user["secret"], "0.8")
|
||||
#else
|
||||
# BigBlueButton::BigBlueButtonApi.new(remove_slash(bbb_endpoint), bbb_secret, "0.8")
|
||||
#end
|
||||
end
|
||||
|
||||
# Generates a uid for the room and BigBlueButton.
|
||||
def generate_uids
|
||||
self.uid = [user.firstname, (0...8).map { (65 + rand(26)).chr }.join].join('-')
|
||||
self.bbb_id = Digest::SHA1.hexdigest(Rails.application.secrets[:secret_key_base] + Time.now.to_i.to_s).to_s
|
||||
end
|
||||
|
||||
# Rereives the loadbalanced BigBlueButton credentials for a user.
|
||||
def retrieve_loadbalanced_credentials(provider)
|
||||
# Include Omniauth accounts under the Greenlight provider.
|
||||
provider = "greenlight" if Rails.configuration.providers.include?(provider.to_sym)
|
||||
|
||||
# Build the URI.
|
||||
uri = encode_bbb_url(
|
||||
Rails.configuration.loadbalancer_endpoint,
|
||||
Rails.configuration.loadbalancer_secret,
|
||||
{name: provider}
|
||||
)
|
||||
|
||||
# Make the request.
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
http.use_ssl = (uri.scheme == 'https')
|
||||
response = http.get(uri.request_uri)
|
||||
|
||||
unless response.kind_of?(Net::HTTPSuccess)
|
||||
raise "Error retrieving provider credentials: #{response.code} #{response.message}"
|
||||
end
|
||||
|
||||
# Parse XML.
|
||||
doc = XmlSimple.xml_in(response.body, 'ForceArray' => false)
|
||||
|
||||
# Return the user credentials if the request succeeded on the loadbalancer.
|
||||
return doc['user'] if doc['returncode'] == RETURNCODE_SUCCESS
|
||||
|
||||
raise "User with provider #{provider} does not exist." if doc['messageKey'] == "noSuchUser"
|
||||
raise "API call #{url} failed with #{doc['messageKey']}."
|
||||
end
|
||||
|
||||
# Builds a request to retrieve credentials from the load balancer.
|
||||
def encode_bbb_url(base_url, secret, params)
|
||||
encoded_params = OAuth::Helper.normalize(params)
|
||||
string = "getUser" + encoded_params + secret
|
||||
checksum = OpenSSL::Digest.digest('sha1', string).unpack("H*").first
|
||||
|
||||
URI.parse("#{base_url}?#{encoded_params}&checksum=#{checksum}")
|
||||
end
|
||||
|
||||
# Removes trailing forward slash from a URL.
|
||||
def remove_slash(s)
|
||||
s.nil? ? nil : s.chomp("/")
|
||||
end
|
||||
|
||||
# Generates a random password for a meeting.
|
||||
def random_password(length)
|
||||
o = ([('a'..'z'), ('A'..'Z')].map do |i| i.to_a end).flatten
|
||||
((0...length).map do o[rand(o.length)] end).join
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,7 +3,7 @@ class User < ApplicationRecord
|
|||
after_create :initialize_room
|
||||
before_save { email.downcase! unless email.nil? }
|
||||
|
||||
has_one :room
|
||||
has_many :rooms
|
||||
|
||||
validates :name, length: { maximum: 24 }, presence: true
|
||||
validates :username, presence: true
|
||||
|
@ -89,7 +89,6 @@ class User < ApplicationRecord
|
|||
|
||||
# Initializes a room for the user.
|
||||
def initialize_room
|
||||
room = Room.create(user_id: self.id)
|
||||
Meeting.create(room_id: room.id, name: "Example")
|
||||
Room.create(user_id: self.id, name: firstname + "'s Room")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -33,6 +33,11 @@
|
|||
<%= yield %>
|
||||
|
||||
<%= render "shared/footer" %>
|
||||
|
||||
<!-- Modal Load -->
|
||||
<% if current_user %>
|
||||
<%= render "shared/modals/create_room_modal" %>
|
||||
<% end %>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
<div class="row invite-join-wrapper hidden">
|
||||
<div class="col-xs-6">
|
||||
<%= render 'shared/title', title: t('invite') do %>
|
||||
<span><%= t('invite_description') %></span>
|
||||
<% end %>
|
||||
<%= render 'shared/meeting_url', hidden: false %>
|
||||
</div>
|
||||
<div class="verticle-line"></div>
|
||||
<div class="col-xs-6">
|
||||
<%= render 'shared/title', title: t('join'), title_class: 'join-meeting-title' %>
|
||||
<button type="button" class="btn btn-primary center-block meeting-start has-tooltip" data-placement="top" title="<%= t('start_meeting') %>">
|
||||
<%= t('start_join') %>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
<% if current_user %>
|
||||
<h1 id="user-text" class="display-3 text-center text-primary mt-9"><%= "Welcome, #{current_user.firstname}." %></h1>
|
||||
<%= render "shared/modals/create_room_modal" %>
|
||||
<% else %>
|
||||
<h1 id="main-text" class="display-3 text-center text-primary mt-9">Teach Students Online.</h1>
|
||||
<%= render "shared/modals/video_modal" %>
|
||||
|
@ -10,47 +9,19 @@
|
|||
<hr class="small-rule">
|
||||
|
||||
<% if current_user %>
|
||||
<div class="row">
|
||||
<% 3.times do %>
|
||||
<div class="col-4">
|
||||
<div class="card">
|
||||
<div class="card-body p-1">
|
||||
<table class="table table-hover table-outline table-vcenter text-nowrap card-table">
|
||||
<tbody>
|
||||
<td>
|
||||
<span class="colorinput-color bg-azure"></span>
|
||||
</td>
|
||||
<td>
|
||||
<div>Example Room</div>
|
||||
<div class="small text-muted">
|
||||
<i>Created on June 17th, 2017</i>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<div class="item-action dropdown">
|
||||
<a href="javascript:void(0)" data-toggle="dropdown" class="icon"><i class="fe fe-more-vertical"></i></a>
|
||||
<div class="dropdown-menu dropdown-menu-right">
|
||||
<a href="javascript:void(0)" class="dropdown-item"><i class="dropdown-icon fe fe-tag"></i> Action </a>
|
||||
<a href="javascript:void(0)" class="dropdown-item"><i class="dropdown-icon fe fe-edit-2"></i> Another action </a>
|
||||
<a href="javascript:void(0)" class="dropdown-item"><i class="dropdown-icon fe fe-message-square"></i> Something else here</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a href="javascript:void(0)" class="dropdown-item"><i class="dropdown-icon fe fe-link"></i> Separated link</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="row">
|
||||
<% current_user.rooms.each do |room| %>
|
||||
<div class="col-4">
|
||||
<%= link_to room do %>
|
||||
<%= render "shared/components/room_block", room: room %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<!-- <%= render "shared/start_meeting" %> -->
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<% else %>
|
||||
<%= render "shared/features" %>
|
||||
<%= render "shared/features" %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
<h4>This is an unauthenticated meeting page.</h4>
|
||||
|
||||
<% if current_user %>
|
||||
<%= link_to "Join", join_meeting_path(uid: @meeting.uid), {method: :post} %>
|
||||
<% else %>
|
||||
<p>Enter a name to join the session.</p>
|
||||
<%= form_tag join_meeting_path do %>
|
||||
<%= text_field_tag "join_name" %>
|
||||
<%= submit_tag "Join" %>
|
||||
<% end %>
|
||||
<% end %>
|
|
@ -1,7 +1,7 @@
|
|||
<p>The join the meeting, enter a name.</p>
|
||||
|
||||
<p>Enter a name to start a session.</p>
|
||||
<%= form_tag join_room_path(room_uid: @room.uid) do %>
|
||||
<%= form_tag room_path(@room) do %>
|
||||
<%= text_field_tag "join_name" %>
|
||||
<%= submit_tag "Join" %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
|
|
@ -1,17 +1,6 @@
|
|||
<div class="container">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-10 offset-1">
|
||||
<p style="font-size: 25px;">Sessions</p>
|
||||
<!-- <div class="input-icon float-right">
|
||||
<input type="text" class="form-control" placeholder="Search for...">
|
||||
<span class="input-icon-addon">
|
||||
<i class="fe fe-search"></i>
|
||||
</span>
|
||||
</div> -->
|
||||
<hr>
|
||||
</div>
|
||||
</div>
|
||||
<%= render "shared/components/subtitle", subtitle: "Sessions" %>
|
||||
|
||||
<div class="col-10 offset-1">
|
||||
<div class="card">
|
||||
|
@ -82,9 +71,9 @@
|
|||
|
||||
Sessions
|
||||
<br><br>
|
||||
<%= @meeting.recordings %>
|
||||
<%= @room.recordings %>
|
||||
|
||||
<% @meeting.recordings.each do |rec| %>
|
||||
<% @room.recordings.each do |rec| %>
|
||||
<p><%= rec[:metadata][:meetingName] %></p>
|
||||
<% Array.wrap(rec[:playback][:format]).each do |form| %>
|
||||
<%= link_to form[:type], form[:url] %>
|
||||
|
|
|
@ -1,20 +1,15 @@
|
|||
<p>This is a room.</p>
|
||||
|
||||
<p><%= @room.user.name %><p>
|
||||
<p><%= @room.meeting.uid %><p>
|
||||
<p><%= @room.uid %><p>
|
||||
|
||||
<%= link_to 'Sessions', sessions_path %>
|
||||
<%= link_to 'Settings', root_path %>
|
||||
|
||||
<p>Click below to join the meeting.</p>
|
||||
|
||||
<% if @room.meeting.is_running? %>
|
||||
<% if @room.is_running? %>
|
||||
<p>meeting is already running</p>
|
||||
<% else %>
|
||||
<%= link_to "Start Meeting", start_room_path(@room.uid) %>
|
||||
<%= link_to "Start Room", start_room_path(@room) %>
|
||||
<% end %>
|
||||
|
||||
<br><br>
|
||||
|
||||
<%= link_to 'Logout', logout_path %>
|
||||
<%= link_to "Sessions", sessions_path(@room) %>
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
<div class="center-panel">
|
||||
<div class="row">
|
||||
<div class="center-block center-panel-size col-xs-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<% if bigbluebutton_endpoint_default? %>
|
||||
<div class="panel-alert alert alert-danger"><%= t('warning_bigbluebutton_endpoint_default') %></div>
|
||||
<% end %>
|
||||
<h3 class="title-wrapper text-center">
|
||||
<%= yield :title %>
|
||||
</h3>
|
||||
<%= yield %>
|
||||
</div>
|
||||
<%= yield :footer %>
|
||||
<div class="help-link">
|
||||
<%= link_to t('help'), 'http://bigbluebutton.org/videos/', target: '_blank' %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,9 +1,9 @@
|
|||
<div class="header py-4 mb-6">
|
||||
<div class="container">
|
||||
<div class="d-flex">
|
||||
<a class="header-brand" href="{{ site.base }}/index.html">
|
||||
<%= link_to root_path, class: "header-brand" do %>
|
||||
<%= image_tag("bbb_logo.png", class: "header-brand-img") %>
|
||||
</a>
|
||||
<% end %>
|
||||
|
||||
<div class="d-flex order-lg-2 ml-auto">
|
||||
<% if current_user %>
|
||||
|
@ -24,10 +24,22 @@
|
|||
<small class="text-muted d-block mt-1"><%= current_user.subtitle %></small>
|
||||
</span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right dropdown-menu-arrow" x-placement="bottom-end" style="position: absolute; transform: translate3d(-56px, 32px, 0px); top: 0px; left: 0px; will-change: transform;">
|
||||
<a class="dropdown-item" href="#">
|
||||
<i class="dropdown-icon fe fe-user"></i> Sessions
|
||||
</a>
|
||||
<%= link_to settings_path, class: "dropdown-item" do %>
|
||||
<i class="dropdown-icon fe fe-settings"></i> Settings
|
||||
<% end %>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="#">
|
||||
<i class="dropdown-icon fe fe-help-circle"></i> Need help?
|
||||
</a>
|
||||
<%= link_to logout_path, class: "dropdown-item" do %>
|
||||
<i class="dropdown-icon fe fe-log-out"></i> Sign out
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<%= link_to logout_path do %>
|
||||
<i class="fas fa-sign-out-alt fa-2x px-5"></i>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<button type="submit" class="btn btn-pill btn-outline-primary ml-auto" data-toggle="modal" data-target="#loginModal">Login</button>
|
||||
<%= render "shared/modals/login_modal" %>
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
<div class="meeting-name-form-wrapper">
|
||||
<input type="text" class="form-control meeting-name" placeholder="Enter meeting name." maxlength="<%= meeting_name_limit %>">
|
||||
</div>
|
|
@ -1,17 +0,0 @@
|
|||
<span class="signup">
|
||||
<% if current_user %>
|
||||
<div class="text-center">
|
||||
<% if @main_room %>
|
||||
<span><%= t('logged_in_description_html', link: link_to(current_user.name, room_path(current_user))) %></span>
|
||||
<% else %>
|
||||
<%= link_to(t('return_to_room'), room_path(current_user)) %>
|
||||
<% end %>
|
||||
<div><%= link_to t('logout'), logout_url %></div>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="text-center">
|
||||
<span><%= t('login_description') %></span>
|
||||
<div><%= link_to t('login'), login_url %></div>
|
||||
</div>
|
||||
<% end %>
|
||||
</span>
|
|
@ -1,7 +0,0 @@
|
|||
<% title_class ||= '' %>
|
||||
<div class="title-wrapper text-center">
|
||||
<div class="title">
|
||||
<h2 class="<%= title_class if title_class %>"><%= title %></h2>
|
||||
<%= yield %>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,27 @@
|
|||
<div class="card">
|
||||
<div class="card-body p-1">
|
||||
<table class="table table-hover table-outline table-vcenter text-nowrap card-table">
|
||||
<tbody>
|
||||
<td>
|
||||
<span class="colorinput-color bg-azure"></span>
|
||||
</td>
|
||||
<td>
|
||||
<div><%= room.name %></div>
|
||||
<div class="small text-muted">
|
||||
<i>Created on <%= room.created_at.strftime("%B #{room.created_at.day.ordinalize}, %Y") %></i>
|
||||
</div>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<div class="item-action dropdown">
|
||||
<a href="javascript:void(0)" data-toggle="dropdown" class="icon"><i class="fe fe-more-vertical"></i></a>
|
||||
<div class="dropdown-menu dropdown-menu-right">
|
||||
<a href="javascript:void(0)" class="dropdown-item"><i class="dropdown-icon fe fe-tag"></i> Action </a>
|
||||
<a href="javascript:void(0)" class="dropdown-item"><i class="dropdown-icon fe fe-edit-2"></i> Another action </a>
|
||||
<a href="javascript:void(0)" class="dropdown-item"><i class="dropdown-icon fe fe-trash"></i> Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,6 @@
|
|||
<div class="row">
|
||||
<div class="col-10 offset-1">
|
||||
<p class="subtitle"><%= subtitle %></p>
|
||||
<hr>
|
||||
</div>
|
||||
</div>
|
|
@ -8,28 +8,27 @@
|
|||
</div>
|
||||
|
||||
<hr class="small-rule">
|
||||
<div class="form-group">
|
||||
<%= form_for(:room, url: create_room_path) do |f| %>
|
||||
<div class="input-icon">
|
||||
<span class="input-icon-addon">
|
||||
<i class="fas fa-chalkboard-teacher"></i>
|
||||
</span>
|
||||
<input type="email" class="form-control" placeholder="Enter a room name...">
|
||||
<%= f.text_field :name, class: "form-control", placeholder: "Enter a room name...", autocomplete: :off %>
|
||||
</div>
|
||||
<label class="custom-switch mt-5 mb-5 float-left">
|
||||
<input type="checkbox" name="custom-switch-checkbox" class="custom-switch-input">
|
||||
<%= f.check_box :auto_join, class: "custom-switch-input", checked: true %>
|
||||
<span class="custom-switch-indicator"></span>
|
||||
<span class="custom-switch-description">Automatically join me into the room when created.</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-footer">
|
||||
<button type="submit" class="btn btn-outline-primary btn-block btn-pill">Create Room</button>
|
||||
<%= f.submit "Create Room", class: "btn btn-outline-primary btn-block btn-pill" %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<p>You will be free to delete this room at any time.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
<div class="container">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-10 offset-1">
|
||||
<p style="font-size: 25px;">Settings</p>
|
||||
<hr>
|
||||
</div>
|
||||
</div>
|
||||
<%= render "shared/components/subtitle", subtitle: "Settings" %>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-2 offset-1">
|
||||
|
@ -108,7 +103,7 @@
|
|||
settingsButtons = $('.setting-btn');
|
||||
settingsViews = $('.setting-view');
|
||||
|
||||
$(window).on('load', function(){
|
||||
$(document).ready(function(){
|
||||
settingsButtons.each(function(i, btn) {
|
||||
if(i != 0){ $(settingsViews[i]).hide(); }
|
||||
$(btn).click(function(){
|
||||
|
@ -122,4 +117,4 @@ $(window).on('load', function(){
|
|||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
|
|
@ -1,20 +1,15 @@
|
|||
Rails.application.routes.draw do
|
||||
|
||||
# Room routes.
|
||||
scope '/r/:room_uid' do
|
||||
get '/', to: 'rooms#show', as: :room
|
||||
get '/start', to: 'rooms#start', as: :start_room
|
||||
get '/join', to: 'rooms#join', as: :join_room
|
||||
match '/wait', to: 'rooms#wait', as: :wait_room, via: [:get, :post]
|
||||
get '/logout', to: 'rooms#logout', as: :logout_room
|
||||
get '/sessions', to: 'rooms#sessions', as: :sessions
|
||||
end
|
||||
|
||||
# Meeting routes.
|
||||
scope '/m' do
|
||||
post '/', to: 'meetings#create', as: :create_meeting
|
||||
get '/:meeting_uid', to: 'meetings#show', as: :meeting
|
||||
post '/:meeting_uid', to: 'meetings#join', as: :join_meeting
|
||||
scope '/r' do
|
||||
post '/', to: 'rooms#create', as: :create_room
|
||||
scope '/:room_uid' do
|
||||
match '/', to: 'rooms#show', as: :room, via: [:get, :post]
|
||||
get '/start', to: 'rooms#start', as: :start_room
|
||||
match '/wait', to: 'rooms#wait', as: :wait_room, via: [:get, :post]
|
||||
get '/logout', to: 'rooms#logout', as: :logout_room
|
||||
get '/sessions', to: 'rooms#sessions', as: :sessions
|
||||
end
|
||||
end
|
||||
|
||||
# Signup routes.
|
||||
|
|
|
@ -2,7 +2,9 @@ class CreateRooms < ActiveRecord::Migration[5.0]
|
|||
def change
|
||||
create_table :rooms do |t|
|
||||
t.belongs_to :user, index: true
|
||||
t.string :name, index: true
|
||||
t.string :uid, index: true
|
||||
t.string :bbb_id, index: true
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
class CreateMeetings < ActiveRecord::Migration[5.0]
|
||||
def change
|
||||
create_table :meetings do |t|
|
||||
t.belongs_to :room, index: true
|
||||
t.string :name, index: true
|
||||
t.string :uid, index: true
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
17
db/schema.rb
17
db/schema.rb
|
@ -10,24 +10,17 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20180504131713) do
|
||||
|
||||
create_table "meetings", force: :cascade do |t|
|
||||
t.integer "room_id"
|
||||
t.string "name"
|
||||
t.string "uid"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["name"], name: "index_meetings_on_name"
|
||||
t.index ["room_id"], name: "index_meetings_on_room_id"
|
||||
t.index ["uid"], name: "index_meetings_on_uid"
|
||||
end
|
||||
ActiveRecord::Schema.define(version: 20180504131705) do
|
||||
|
||||
create_table "rooms", force: :cascade do |t|
|
||||
t.integer "user_id"
|
||||
t.string "name"
|
||||
t.string "uid"
|
||||
t.string "bbb_id"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["bbb_id"], name: "index_rooms_on_bbb_id"
|
||||
t.index ["name"], name: "index_rooms_on_name"
|
||||
t.index ["uid"], name: "index_rooms_on_uid"
|
||||
t.index ["user_id"], name: "index_rooms_on_user_id"
|
||||
end
|
||||
|
|
Reference in New Issue