commit
4037b6304e
@ -0,0 +1,24 @@ |
||||
# See https://help.github.com/articles/ignoring-files for more about ignoring files. |
||||
# |
||||
# If you find yourself ignoring temporary files generated by your text editor |
||||
# or operating system, you probably want to add a global ignore instead: |
||||
# git config --global core.excludesfile '~/.gitignore_global' |
||||
|
||||
# Ignore bundler config. |
||||
/.bundle |
||||
|
||||
# Ignore the default SQLite database. |
||||
/db/*.sqlite3 |
||||
/db/*.sqlite3-journal |
||||
|
||||
# Ignore all logfiles and tempfiles. |
||||
/log/* |
||||
/tmp/* |
||||
!/log/.keep |
||||
!/tmp/.keep |
||||
|
||||
# Ignore Byebug command history file. |
||||
.byebug_history |
||||
|
||||
# Ignore environment configuration. |
||||
.env |
@ -0,0 +1,69 @@ |
||||
source 'https://rubygems.org' |
||||
|
||||
git_source(:github) do |repo_name| |
||||
repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") |
||||
"https://github.com/#{repo_name}.git" |
||||
end |
||||
|
||||
|
||||
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails' |
||||
gem 'rails', '~> 5.0.7' |
||||
# Use sqlite3 as the database for Active Record |
||||
gem 'sqlite3' |
||||
# Use Puma as the app server |
||||
gem 'puma', '~> 3.0' |
||||
# Use SCSS for stylesheets |
||||
gem 'sass-rails', '~> 5.0' |
||||
# Use Uglifier as compressor for JavaScript assets |
||||
gem 'uglifier', '>= 1.3.0' |
||||
# Use CoffeeScript for .coffee assets and views |
||||
gem 'coffee-rails', '~> 4.2' |
||||
# See https://github.com/rails/execjs#readme for more supported runtimes |
||||
# gem 'therubyracer', platforms: :ruby |
||||
|
||||
# Use jquery as the JavaScript library |
||||
gem 'jquery-rails' |
||||
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks |
||||
gem 'turbolinks', '~> 5' |
||||
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder |
||||
gem 'jbuilder', '~> 2.5' |
||||
# Use Redis adapter to run Action Cable in production |
||||
# gem 'redis', '~> 3.0' |
||||
# Use ActiveModel has_secure_password |
||||
# gem 'bcrypt', '~> 3.1.7' |
||||
|
||||
# Authentication. |
||||
gem 'omniauth' |
||||
gem 'omniauth-twitter' |
||||
gem 'omniauth-google-oauth2' |
||||
|
||||
# BigBlueButton API wrapper. |
||||
gem 'bigbluebutton-api-ruby' |
||||
|
||||
# Front-end. |
||||
gem 'bootstrap-sass', '3.3.0.0' |
||||
gem 'bootstrap-social-rails', '~> 4.12' |
||||
gem 'font-awesome-sass', '4.7.0' |
||||
|
||||
# Use Capistrano for deployment |
||||
# gem 'capistrano-rails', group: :development |
||||
|
||||
group :development, :test do |
||||
# Call 'byebug' anywhere in the code to stop execution and get a debugger console |
||||
gem 'byebug', platform: :mri |
||||
|
||||
# Environment configuration. |
||||
gem 'dotenv-rails' |
||||
end |
||||
|
||||
group :development do |
||||
# Access an IRB console on exception pages or by using <%= console %> anywhere in the code. |
||||
gem 'web-console', '>= 3.3.0' |
||||
gem 'listen', '~> 3.0.5' |
||||
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring |
||||
gem 'spring' |
||||
gem 'spring-watcher-listen', '~> 2.0.0' |
||||
end |
||||
|
||||
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem |
||||
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] |
@ -0,0 +1,229 @@ |
||||
GEM |
||||
remote: https://rubygems.org/ |
||||
specs: |
||||
actioncable (5.0.7) |
||||
actionpack (= 5.0.7) |
||||
nio4r (>= 1.2, < 3.0) |
||||
websocket-driver (~> 0.6.1) |
||||
actionmailer (5.0.7) |
||||
actionpack (= 5.0.7) |
||||
actionview (= 5.0.7) |
||||
activejob (= 5.0.7) |
||||
mail (~> 2.5, >= 2.5.4) |
||||
rails-dom-testing (~> 2.0) |
||||
actionpack (5.0.7) |
||||
actionview (= 5.0.7) |
||||
activesupport (= 5.0.7) |
||||
rack (~> 2.0) |
||||
rack-test (~> 0.6.3) |
||||
rails-dom-testing (~> 2.0) |
||||
rails-html-sanitizer (~> 1.0, >= 1.0.2) |
||||
actionview (5.0.7) |
||||
activesupport (= 5.0.7) |
||||
builder (~> 3.1) |
||||
erubis (~> 2.7.0) |
||||
rails-dom-testing (~> 2.0) |
||||
rails-html-sanitizer (~> 1.0, >= 1.0.3) |
||||
activejob (5.0.7) |
||||
activesupport (= 5.0.7) |
||||
globalid (>= 0.3.6) |
||||
activemodel (5.0.7) |
||||
activesupport (= 5.0.7) |
||||
activerecord (5.0.7) |
||||
activemodel (= 5.0.7) |
||||
activesupport (= 5.0.7) |
||||
arel (~> 7.0) |
||||
activesupport (5.0.7) |
||||
concurrent-ruby (~> 1.0, >= 1.0.2) |
||||
i18n (>= 0.7, < 2) |
||||
minitest (~> 5.1) |
||||
tzinfo (~> 1.1) |
||||
arel (7.1.4) |
||||
bigbluebutton-api-ruby (1.6.0) |
||||
xml-simple (~> 1.1) |
||||
bindex (0.5.0) |
||||
bootstrap-sass (3.3.0.0) |
||||
sass (~> 3.2) |
||||
bootstrap-social-rails (4.12.0) |
||||
railties (>= 3.1) |
||||
builder (3.2.3) |
||||
byebug (10.0.2) |
||||
coffee-rails (4.2.2) |
||||
coffee-script (>= 2.2.0) |
||||
railties (>= 4.0.0) |
||||
coffee-script (2.4.1) |
||||
coffee-script-source |
||||
execjs |
||||
coffee-script-source (1.12.2) |
||||
concurrent-ruby (1.0.5) |
||||
crass (1.0.4) |
||||
dotenv (2.2.1) |
||||
dotenv-rails (2.2.1) |
||||
dotenv (= 2.2.1) |
||||
railties (>= 3.2, < 5.2) |
||||
erubis (2.7.0) |
||||
execjs (2.7.0) |
||||
faraday (0.12.2) |
||||
multipart-post (>= 1.2, < 3) |
||||
ffi (1.9.23) |
||||
font-awesome-sass (4.7.0) |
||||
sass (>= 3.2) |
||||
globalid (0.4.1) |
||||
activesupport (>= 4.2.0) |
||||
hashie (3.5.7) |
||||
i18n (1.0.1) |
||||
concurrent-ruby (~> 1.0) |
||||
jbuilder (2.7.0) |
||||
activesupport (>= 4.2.0) |
||||
multi_json (>= 1.2) |
||||
jquery-rails (4.3.3) |
||||
rails-dom-testing (>= 1, < 3) |
||||
railties (>= 4.2.0) |
||||
thor (>= 0.14, < 2.0) |
||||
jwt (1.5.6) |
||||
listen (3.0.8) |
||||
rb-fsevent (~> 0.9, >= 0.9.4) |
||||
rb-inotify (~> 0.9, >= 0.9.7) |
||||
loofah (2.2.2) |
||||
crass (~> 1.0.2) |
||||
nokogiri (>= 1.5.9) |
||||
mail (2.7.0) |
||||
mini_mime (>= 0.1.1) |
||||
method_source (0.9.0) |
||||
mini_mime (1.0.0) |
||||
mini_portile2 (2.3.0) |
||||
minitest (5.11.3) |
||||
multi_json (1.13.1) |
||||
multi_xml (0.6.0) |
||||
multipart-post (2.0.0) |
||||
nio4r (2.3.1) |
||||
nokogiri (1.8.2) |
||||
mini_portile2 (~> 2.3.0) |
||||
oauth (0.5.4) |
||||
oauth2 (1.4.0) |
||||
faraday (>= 0.8, < 0.13) |
||||
jwt (~> 1.0) |
||||
multi_json (~> 1.3) |
||||
multi_xml (~> 0.5) |
||||
rack (>= 1.2, < 3) |
||||
omniauth (1.8.1) |
||||
hashie (>= 3.4.6, < 3.6.0) |
||||
rack (>= 1.6.2, < 3) |
||||
omniauth-google-oauth2 (0.5.3) |
||||
jwt (>= 1.5) |
||||
omniauth (>= 1.1.1) |
||||
omniauth-oauth2 (>= 1.5) |
||||
omniauth-oauth (1.1.0) |
||||
oauth |
||||
omniauth (~> 1.0) |
||||
omniauth-oauth2 (1.5.0) |
||||
oauth2 (~> 1.1) |
||||
omniauth (~> 1.2) |
||||
omniauth-twitter (1.4.0) |
||||
omniauth-oauth (~> 1.1) |
||||
rack |
||||
puma (3.11.4) |
||||
rack (2.0.5) |
||||
rack-test (0.6.3) |
||||
rack (>= 1.0) |
||||
rails (5.0.7) |
||||
actioncable (= 5.0.7) |
||||
actionmailer (= 5.0.7) |
||||
actionpack (= 5.0.7) |
||||
actionview (= 5.0.7) |
||||
activejob (= 5.0.7) |
||||
activemodel (= 5.0.7) |
||||
activerecord (= 5.0.7) |
||||
activesupport (= 5.0.7) |
||||
bundler (>= 1.3.0) |
||||
railties (= 5.0.7) |
||||
sprockets-rails (>= 2.0.0) |
||||
rails-dom-testing (2.0.3) |
||||
activesupport (>= 4.2.0) |
||||
nokogiri (>= 1.6) |
||||
rails-html-sanitizer (1.0.4) |
||||
loofah (~> 2.2, >= 2.2.2) |
||||
railties (5.0.7) |
||||
actionpack (= 5.0.7) |
||||
activesupport (= 5.0.7) |
||||
method_source |
||||
rake (>= 0.8.7) |
||||
thor (>= 0.18.1, < 2.0) |
||||
rake (12.3.1) |
||||
rb-fsevent (0.10.3) |
||||
rb-inotify (0.9.10) |
||||
ffi (>= 0.5.0, < 2) |
||||
sass (3.5.6) |
||||
sass-listen (~> 4.0.0) |
||||
sass-listen (4.0.0) |
||||
rb-fsevent (~> 0.9, >= 0.9.4) |
||||
rb-inotify (~> 0.9, >= 0.9.7) |
||||
sass-rails (5.0.7) |
||||
railties (>= 4.0.0, < 6) |
||||
sass (~> 3.1) |
||||
sprockets (>= 2.8, < 4.0) |
||||
sprockets-rails (>= 2.0, < 4.0) |
||||
tilt (>= 1.1, < 3) |
||||
spring (2.0.2) |
||||
activesupport (>= 4.2) |
||||
spring-watcher-listen (2.0.1) |
||||
listen (>= 2.7, < 4.0) |
||||
spring (>= 1.2, < 3.0) |
||||
sprockets (3.7.1) |
||||
concurrent-ruby (~> 1.0) |
||||
rack (> 1, < 3) |
||||
sprockets-rails (3.2.1) |
||||
actionpack (>= 4.0) |
||||
activesupport (>= 4.0) |
||||
sprockets (>= 3.0.0) |
||||
sqlite3 (1.3.13) |
||||
thor (0.20.0) |
||||
thread_safe (0.3.6) |
||||
tilt (2.0.8) |
||||
turbolinks (5.1.1) |
||||
turbolinks-source (~> 5.1) |
||||
turbolinks-source (5.1.0) |
||||
tzinfo (1.2.5) |
||||
thread_safe (~> 0.1) |
||||
uglifier (4.1.10) |
||||
execjs (>= 0.3.0, < 3) |
||||
web-console (3.6.2) |
||||
actionview (>= 5.0) |
||||
activemodel (>= 5.0) |
||||
bindex (>= 0.4.0) |
||||
railties (>= 5.0) |
||||
websocket-driver (0.6.5) |
||||
websocket-extensions (>= 0.1.0) |
||||
websocket-extensions (0.1.3) |
||||
xml-simple (1.1.5) |
||||
|
||||
PLATFORMS |
||||
ruby |
||||
|
||||
DEPENDENCIES |
||||
bigbluebutton-api-ruby |
||||
bootstrap-sass (= 3.3.0.0) |
||||
bootstrap-social-rails (~> 4.12) |
||||
byebug |
||||
coffee-rails (~> 4.2) |
||||
dotenv-rails |
||||
font-awesome-sass (= 4.7.0) |
||||
jbuilder (~> 2.5) |
||||
jquery-rails |
||||
listen (~> 3.0.5) |
||||
omniauth |
||||
omniauth-google-oauth2 |
||||
omniauth-twitter |
||||
puma (~> 3.0) |
||||
rails (~> 5.0.7) |
||||
sass-rails (~> 5.0) |
||||
spring |
||||
spring-watcher-listen (~> 2.0.0) |
||||
sqlite3 |
||||
turbolinks (~> 5) |
||||
tzinfo-data |
||||
uglifier (>= 1.3.0) |
||||
web-console (>= 3.3.0) |
||||
|
||||
BUNDLED WITH |
||||
1.15.4 |
@ -0,0 +1,24 @@ |
||||
# README |
||||
|
||||
This README would normally document whatever steps are necessary to get the |
||||
application up and running. |
||||
|
||||
Things you may want to cover: |
||||
|
||||
* Ruby version |
||||
|
||||
* System dependencies |
||||
|
||||
* Configuration |
||||
|
||||
* Database creation |
||||
|
||||
* Database initialization |
||||
|
||||
* How to run the test suite |
||||
|
||||
* Services (job queues, cache servers, search engines, etc.) |
||||
|
||||
* Deployment instructions |
||||
|
||||
* ... |
@ -0,0 +1,6 @@ |
||||
# Add your own tasks in files placed in lib/tasks ending in .rake, |
||||
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. |
||||
|
||||
require_relative 'config/application' |
||||
|
||||
Rails.application.load_tasks |
@ -0,0 +1,3 @@ |
||||
//= link_tree ../images
|
||||
//= link_directory ../javascripts .js
|
||||
//= link_directory ../stylesheets .css
|
After Width: | Height: | Size: 1.1 MiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 771 B |
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,16 @@ |
||||
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
||||
// listed below.
|
||||
//
|
||||
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
||||
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
|
||||
//
|
||||
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
||||
// compiled file. JavaScript code in this file should be added after the last require_* statement.
|
||||
//
|
||||
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
||||
// about supported directives.
|
||||
//
|
||||
//= require jquery
|
||||
//= require jquery_ujs
|
||||
//= require turbolinks
|
||||
//= require_tree .
|
@ -0,0 +1,13 @@ |
||||
// Action Cable provides the framework to deal with WebSockets in Rails.
|
||||
// You can generate new channels where WebSocket features live using the rails generate channel command.
|
||||
//
|
||||
//= require action_cable
|
||||
//= require_self
|
||||
//= require_tree ./channels
|
||||
|
||||
(function() { |
||||
this.App || (this.App = {}); |
||||
|
||||
App.cable = ActionCable.createConsumer(); |
||||
|
||||
}).call(this); |
@ -0,0 +1,3 @@ |
||||
# Place all the behaviors and hooks related to the matching controller here. |
||||
# All this logic will automatically be available in application.js. |
||||
# You can use CoffeeScript in this file: http://coffeescript.org/ |
@ -0,0 +1,3 @@ |
||||
# Place all the behaviors and hooks related to the matching controller here. |
||||
# All this logic will automatically be available in application.js. |
||||
# You can use CoffeeScript in this file: http://coffeescript.org/ |
@ -0,0 +1,3 @@ |
||||
# Place all the behaviors and hooks related to the matching controller here. |
||||
# All this logic will automatically be available in application.js. |
||||
# You can use CoffeeScript in this file: http://coffeescript.org/ |
@ -0,0 +1,3 @@ |
||||
# Place all the behaviors and hooks related to the matching controller here. |
||||
# All this logic will automatically be available in application.js. |
||||
# You can use CoffeeScript in this file: http://coffeescript.org/ |
@ -0,0 +1,161 @@ |
||||
/* |
||||
* This is a manifest file that'll be compiled into application.css, which will include all the files |
||||
* listed below. |
||||
* |
||||
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, |
||||
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. |
||||
* |
||||
* You're free to add application-wide styles to this file and they'll appear at the bottom of the |
||||
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS |
||||
* files in this directory. Styles in this file should be added after the last require_* statement. |
||||
* It is generally better to create a new file per style scope. |
||||
* |
||||
*= require_tree . |
||||
*= require_self |
||||
*/ |
||||
|
||||
// BigBlueButton open source conferencing system - http://www.bigbluebutton.org/. |
||||
// |
||||
// Copyright (c) 2016 BigBlueButton Inc. and by respective authors (see below). |
||||
// |
||||
// This program is free software; you can redistribute it and/or modify it under the |
||||
// terms of the GNU Lesser General Public License as published by the Free Software |
||||
// Foundation; either version 3.0 of the License, or (at your option) any later |
||||
// version. |
||||
// |
||||
// BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY |
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A |
||||
// PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. |
||||
// |
||||
// You should have received a copy of the GNU Lesser General Public License along |
||||
// with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
@import "bootstrap"; |
||||
|
||||
html, body { |
||||
width: 100%; |
||||
height: 100%; |
||||
background: #ffffff; |
||||
} |
||||
|
||||
.container-fluid { |
||||
height: 100%; |
||||
} |
||||
|
||||
.background { |
||||
height: 350px; |
||||
width: 100%; |
||||
background-position: center; |
||||
background-size: cover; |
||||
background-repeat: no-repeat; |
||||
} |
||||
|
||||
body[data-controller=landing].app-background { |
||||
@extend .background; |
||||
} |
||||
|
||||
#alerts { |
||||
position: absolute; |
||||
top: 10px; |
||||
left: 50%; |
||||
margin-left: -250px; |
||||
width: 500px; |
||||
z-index: 999; |
||||
} |
||||
|
||||
.header { |
||||
padding: 20px 40px; |
||||
margin-bottom: 160px; |
||||
.logo { |
||||
max-width: 150px; |
||||
max-height: 50px; |
||||
} |
||||
} |
||||
|
||||
.footer { |
||||
padding: 20px; |
||||
} |
||||
|
||||
.center-block { |
||||
float: none; |
||||
} |
||||
.center-panel-wrapper { |
||||
height: 100%; |
||||
} |
||||
.center-panel { |
||||
height: 100%; |
||||
.center-panel-size { |
||||
max-width: 1200px |
||||
} |
||||
.center-panel-content-size { |
||||
height: 100%; |
||||
max-width: 1100px; |
||||
} |
||||
|
||||
.panel { |
||||
position: relative; |
||||
overflow: hidden; |
||||
} |
||||
|
||||
.input-spacing { |
||||
margin-top: 15px; |
||||
} |
||||
|
||||
.panel-footer { |
||||
background-color: white; |
||||
} |
||||
|
||||
.panel-body { |
||||
padding-bottom: 40px; |
||||
} |
||||
|
||||
.title-wrapper { |
||||
margin-bottom: 30px; |
||||
} |
||||
|
||||
.join-form-wrapper { |
||||
.center-block { |
||||
max-width: 400px; |
||||
} |
||||
.join-form { |
||||
width: 100%; |
||||
} |
||||
.btn { |
||||
width: initial; |
||||
} |
||||
} |
||||
|
||||
.meeting-url-wrapper { |
||||
.meeting-url { |
||||
cursor: default; |
||||
} |
||||
} |
||||
|
||||
.loading-wrapper { |
||||
text-align: center; |
||||
} |
||||
} |
||||
|
||||
.popover { |
||||
max-width: none; |
||||
} |
||||
|
||||
.verticle-line { |
||||
// parent must be position relative to work |
||||
width: 1px; |
||||
background-color: lightgray; |
||||
height: 100%; |
||||
position: absolute; |
||||
left: 50%; |
||||
} |
||||
|
||||
.invite-join-wrapper { |
||||
position: relative; |
||||
} |
||||
|
||||
.help-link { |
||||
position: absolute; |
||||
top: 0; |
||||
right: 0; |
||||
padding-right: 3px; |
||||
} |
@ -0,0 +1,121 @@ |
||||
// Place all the styles related to the Main controller here. |
||||
// They will automatically be included in application.css. |
||||
// You can use Sass (SCSS) here: http://sass-lang.com/ |
||||
|
||||
.meeting-url-button-group { |
||||
padding-top: 5px; |
||||
width: 150px; |
||||
text-align: center; |
||||
} |
||||
|
||||
.meeting-url-qrcode-group { |
||||
padding-top: 5px; |
||||
width: 128px; |
||||
text-align: center; |
||||
} |
||||
|
||||
.previously-joined, .actives { |
||||
list-style-type: none; |
||||
margin:auto; |
||||
width: 200px; |
||||
padding: 0; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
.meetings { |
||||
|
||||
} |
||||
|
||||
.rooms { |
||||
|
||||
.table-wrapper { |
||||
padding: 40px 50px 10px 50px; |
||||
|
||||
#recordings { |
||||
thead { |
||||
th:after { |
||||
content: none; //removes the sort icon in table header |
||||
} |
||||
} |
||||
.dataTables_empty { |
||||
text-align: center; |
||||
} |
||||
.timeago { |
||||
margin-left: 5px; |
||||
font-size: 13px; |
||||
cursor: pointer; |
||||
color: #999; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
.img-thumbnail{ |
||||
padding: 4px; |
||||
background-color: white; |
||||
border: 1px solid #dddddd; |
||||
border-radius: 4px; |
||||
|
||||
&.large{ |
||||
display: none; |
||||
} |
||||
|
||||
&:hover + &.large{ |
||||
display: inline-block; |
||||
position: absolute; |
||||
z-index: 1; |
||||
} |
||||
} |
||||
|
||||
.meeting-url-group { |
||||
position: relative; |
||||
} |
||||
|
||||
.recording-update-trigger { |
||||
&.recording-unpublished { |
||||
color: red; |
||||
} |
||||
|
||||
&.recording-unlisted { |
||||
color: #e3a91e; |
||||
} |
||||
|
||||
&.recording-published { |
||||
color: green; |
||||
} |
||||
} |
||||
|
||||
.fa-spinner { |
||||
width: 100%; |
||||
text-align: center; |
||||
} |
||||
|
||||
.disabled-button { |
||||
opacity: 0.5; |
||||
} |
||||
|
||||
.youtube-red { |
||||
color: red; |
||||
} |
||||
|
||||
.cloud-blue { |
||||
color: cornflowerblue; |
||||
} |
||||
|
||||
.green-check { |
||||
color: limegreen; |
||||
} |
||||
|
||||
.top-buffer { |
||||
margin-top: 8px; |
||||
} |
||||
|
||||
.tooltip-wrapper { |
||||
display: inline-block; |
||||
} |
||||
|
||||
#youtube-footer{ |
||||
font-size: 10px; |
||||
text-align: center; |
||||
margin-top: 10px; |
||||
} |
@ -0,0 +1,3 @@ |
||||
// 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/ |
@ -0,0 +1,3 @@ |
||||
// Place all the styles related to the Rooms controller here. |
||||
// They will automatically be included in application.css. |
||||
// You can use Sass (SCSS) here: http://sass-lang.com/ |
@ -0,0 +1,50 @@ |
||||
// Place all the styles related to the Sessions controller here. |
||||
// They will automatically be included in application.css. |
||||
// You can use Sass (SCSS) here: http://sass-lang.com/ |
||||
|
||||
.login { |
||||
.center-panel { |
||||
.center-panel-size { |
||||
max-width: 400px; |
||||
} |
||||
} |
||||
} |
||||
|
||||
a.signin-link { |
||||
&:hover, &:focus { |
||||
cursor: pointer; |
||||
text-decoration: none; |
||||
} |
||||
} |
||||
|
||||
.signin-link { |
||||
.signin-icon { |
||||
vertical-align: middle; |
||||
width: 35px; |
||||
height: 35px; |
||||
} |
||||
.signin-button { |
||||
background: white; |
||||
width: 250px; |
||||
border: thin solid #888; |
||||
border-radius: 2px; |
||||
white-space: nowrap; |
||||
padding: 5px; |
||||
margin-bottom: 14px; |
||||
} |
||||
.signin-icon-wrapper { |
||||
display: inline-block; |
||||
width: 40px; |
||||
} |
||||
.signin-text-wrapper { |
||||
display: inline-block; |
||||
width: 200px; |
||||
} |
||||
.signin-text { |
||||
font-family: 'Roboto', sans-serif; |
||||
vertical-align: middle; |
||||
font-size: 14px; |
||||
font-weight: bold; |
||||
color: #444; |
||||
} |
||||
} |
@ -0,0 +1,4 @@ |
||||
module ApplicationCable |
||||
class Channel < ActionCable::Channel::Base |
||||
end |
||||
end |
@ -0,0 +1,4 @@ |
||||
module ApplicationCable |
||||
class Connection < ActionCable::Connection::Base |
||||
end |
||||
end |
@ -0,0 +1,41 @@ |
||||
require 'bigbluebutton_api' |
||||
|
||||
class ApplicationController < ActionController::Base |
||||
include SessionsHelper |
||||
|
||||
protect_from_forgery with: :exception |
||||
|
||||
MEETING_NAME_LIMIT = 90 |
||||
USER_NAME_LIMIT = 30 |
||||
|
||||
def meeting_name_limit |
||||
MEETING_NAME_LIMIT |
||||
end |
||||
helper_method :meeting_name_limit |
||||
|
||||
def user_name_limit |
||||
USER_NAME_LIMIT |
||||
end |
||||
helper_method :user_name_limit |
||||
|
||||
# Determines if the BigBlueButton endpoint is configured (or set to default). |
||||
def bigbluebutton_endpoint_default? |
||||
Rails.configuration.bigbluebutton_endpoint_default == Rails.configuration.bigbluebutton_endpoint |
||||
end |
||||
helper_method :bigbluebutton_endpoint_default? |
||||
|
||||
private |
||||
|
||||
# Ensure the user is logged into the room they are accessing. |
||||
def verify_room_ownership |
||||
return unless params.include?(:room_uid) |
||||
@room = Room.find_by(uid: params[:room_uid]) |
||||
|
||||
# Redirect to correct room or root if not logged in. |
||||
if current_user.nil? |
||||
redirect_to root_path |
||||
elsif @room.nil? || current_user != @room.user |
||||
redirect_to room_path(current_user.room.uid) |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,9 @@ |
||||
class MainController < ApplicationController |
||||
|
||||
# GET / |
||||
def index |
||||
# If the user is logged in already, move them along to their room. |
||||
redirect_to room_path(current_user.room.uid) if current_user |
||||
end |
||||
|
||||
end |
@ -0,0 +1,82 @@ |
||||
class MeetingsController < ApplicationController |
||||
|
||||
before_action :verify_room_ownership |
||||
skip_before_action :verify_room_ownership, only: [:join, :wait] |
||||
|
||||
# GET /rooms/:room_uid/meetings |
||||
def index |
||||
|
||||
end |
||||
|
||||
# GET /rooms/:room_uid/meetings/:meeting_uid |
||||
def show |
||||
|
||||
end |
||||
|
||||
# POST /rooms/:room_uid/meetings |
||||
def create |
||||
@meeting = Meeting.new(meeting_params(@room)) |
||||
|
||||
if @meeting.save |
||||
# Create the meeting on the BigBlueButton server and join the user into the meeting. |
||||
redirect_to join_meeting_path(room_uid: @room.uid, meeting_uid: @meeting.uid) |
||||
else |
||||
# Meeting couldn't be created, handle error. |
||||
|
||||
end |
||||
end |
||||
|
||||
# GET /rooms/:room_uid/meetings/:meeting_uid/join |
||||
def join |
||||
@meeting = Meeting.find_by(uid: params[:meeting_uid]) |
||||
|
||||
if @meeting |
||||
opts = default_meeting_options |
||||
if @meeting.is_running? |
||||
if current_user |
||||
# Check if the current user is the room/session owner. |
||||
opts[:user_is_moderator] = @meeting.room.owned_by?(current_user) |
||||
redirect_to @meeting.join_path(current_user.name, opts) |
||||
else |
||||
# If the unauthenticated user has supplied a join name. |
||||
if params[:join_name] |
||||
redirect_to @meeting.join_path(params[:join_name], opts) |
||||
else |
||||
# Render the join page so they can supploy their name. |
||||
render :join |
||||
end |
||||
end |
||||
else |
||||
# Only start the meeting if owner is joining first. |
||||
if current_user && @meeting.room.owned_by?(current_user) |
||||
opts[:user_is_moderator] = true |
||||
redirect_to @meeting.join_path(current_user.name, opts) |
||||
else |
||||
# Send the user to a polling page that will auto join them when it starts. |
||||
# The wait action/page handles input of name for unauthenticated users. |
||||
render :wait |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
# GET /rooms/:room_uid/meetings/:meeting_uid/wait |
||||
def wait |
||||
|
||||
end |
||||
|
||||
private |
||||
|
||||
def meeting_params(room) |
||||
params.require(:meeting).permit(:name).merge!(room_id: room.id) |
||||
end |
||||
|
||||
def default_meeting_options |
||||
{ |
||||
user_is_moderator: false, |
||||
meeting_logout_url: request.base_url + room_path(room_uid: @meeting.room.uid), |
||||
moderator_message: "To invite someone to the meeting, send them this link: |
||||
#{request.base_url + join_meeting_path(room_uid: @meeting.room.uid, meeting_uid: @meeting.uid)}" |
||||
} |
||||
end |
||||
end |
@ -0,0 +1,9 @@ |
||||
class RoomsController < ApplicationController |
||||
|
||||
before_action :verify_room_ownership |
||||
|
||||
# GET /rooms/:room_uid |
||||
def index |
||||
@meeting = Meeting.new |
||||
end |
||||
end |
@ -0,0 +1,22 @@ |
||||
class SessionsController < ApplicationController |
||||
|
||||
# GET /login |
||||
def new |
||||
end |
||||
|
||||
# GET /logout |
||||
def destroy |
||||
logout |
||||
end |
||||
|
||||
# GET/POST /auth/:provider/callback |
||||
def create |
||||
user = User.from_omniauth(request.env['omniauth.auth']) |
||||
login(user) |
||||
end |
||||
|
||||
# POST /auth/failure |
||||
def fail |
||||
|
||||
end |
||||
end |
@ -0,0 +1,14 @@ |
||||
module ApplicationHelper |
||||
|
||||
# Gets all configured omniauth providers. |
||||
def configured_providers |
||||
Rails.configuration.providers.select do |provider| |
||||
Rails.configuration.send("omniauth_#{provider}") |
||||
end |
||||
end |
||||
|
||||
# Generates the login URL for a specific provider. |
||||
def omniauth_login_url(provider) |
||||
"/auth/#{provider}" |
||||
end |
||||
end |
@ -0,0 +1,149 @@ |
||||
module BigBlueHelper |
||||
|
||||
META_LISTED = "gl-listed" |
||||
META_TOKEN = "gl-token" |
||||
|
||||
def bbb_endpoint |
||||
Rails.configuration.bigbluebutton_endpoint |
||||
end |
||||
|
||||
def bbb_secret |
||||
Rails.configuration.bigbluebutton_secret |
||||
end |
||||
|
||||
def bbb |
||||
@bbb ||= BigBlueButton::BigBlueButtonApi.new(bbb_endpoint + "api", bbb_secret, "0.8") |
||||
end |
||||
|
||||
# Generates a BigBlueButton meeting id from a meeting token. |
||||
def bbb_meeting_id(id) |
||||
Digest::SHA1.hexdigest(Rails.application.secrets[:secret_key_base] + id).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 |
||||
|
||||
# Checks if a meeting is running on the BigBlueButton server. |
||||
def meeting_is_running?(id) |
||||
begin |
||||
bbb.get_meeting_info(id, nil) |
||||
return true |
||||
rescue BigBlueButton::BigBlueButtonException => exc |
||||
return false |
||||
end |
||||
end |
||||
|
||||
def start_meeting(options) |
||||
meeting_id = bbb_meeting_id(name) |
||||
|
||||
# Need to create the meeting on the BigBlueButton server. |
||||
create_options = { |
||||
record: options[:meeting_recorded].to_s, |
||||
#logoutURL: options[:meeting_logout_url] || request.base_url, |
||||
moderatorPW: random_password(12), |
||||
attendeePW: random_password(12), |
||||
moderatorOnlyMessage: options[:moderator_message], |
||||
"meta_#{BigBlueHelper::META_LISTED}": false, |
||||
"meta_#{BigBlueHelper::META_TOKEN}": name |
||||
} |
||||
|
||||
#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, meeting_id, create_options) |
||||
rescue BigBlueButton::BigBlueButtonException => exc |
||||
puts "BigBlueButton failed on create: #{exc.key}: #{exc.message}" |
||||
end |
||||
|
||||
# Get the meeting info. |
||||
#bbb_meeting_info = bbb.get_meeting_info(meeting_id, nil) |
||||
|
||||
meeting_id |
||||
end |
||||
|
||||
# Generates a URL to join a BigBlueButton session. |
||||
def join_url(meeting_id, username, options = {}) |
||||
options[:meeting_recorded] ||= false |
||||
options[:user_is_moderator] ||= false |
||||
options[:wait_for_moderator] ||= false |
||||
options[:meeting_logout_url] ||= nil |
||||
options[:meeting_name] ||= name |
||||
options[:room_owner] ||= nil |
||||
options[:moderator_message] ||= '' |
||||
|
||||
return call_invalid_res if !bbb |
||||
|
||||
# Get the meeting info. |
||||
meeting_info = bbb.get_meeting_info(meeting_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(meeting_id, username, password) |
||||
end |
||||
|
||||
# Generates a URL to join a BigBlueButton session. |
||||
def join_url_old(meeting_token, full_name, options={}) |
||||
options[:meeting_recorded] ||= false |
||||
options[:user_is_moderator] ||= false |
||||
options[:wait_for_moderator] ||= false |
||||
options[:meeting_logout_url] ||= nil |
||||
options[:meeting_name] ||= meeting_token |
||||
options[:room_owner] ||= nil |
||||
options[:moderator_message] ||= '' |
||||
|
||||
return call_invalid_res if !bbb |
||||
|
||||
meeting_id = bbb_meeting_id(meeting_token) |
||||
|
||||
unless meeting_is_running?(meeting_id) |
||||
# Need to create the meeting on the BigBlueButton server. |
||||
create_options = { |
||||
record: options[:meeting_recorded].to_s, |
||||
logoutURL: options[:meeting_logout_url] || request.base_url, |
||||
moderatorPW: random_password(12), |
||||
attendeePW: random_password(12), |
||||
moderatorOnlyMessage: options[:moderator_message], |
||||
"meta_#{BigBlueHelper::META_LISTED}": false, |
||||
"meta_#{BigBlueHelper::META_TOKEN}": meeting_token |
||||
} |
||||
|
||||
#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(options[:meeting_name], meeting_id, create_options) |
||||
rescue BigBlueButton::BigBlueButtonException => exc |
||||
puts "BigBlueButton failed on create: #{exc.key}: #{exc.message}" |
||||
end |
||||
|
||||
# Get the meeting info. |
||||
bbb_meeting_info = bbb.get_meeting_info(meeting_id, nil) |
||||
end |
||||
|
||||
# Determine the password to use when joining. |
||||
password = if options[:user_is_moderator] |
||||
bbb_meeting_info[:moderatorPW] |
||||
else |
||||
bbb_meeting_info[:attendeePW] |
||||
end |
||||
|
||||
# Generate the join URL. |
||||
bbb.join_meeting_url(meeting_id, full_name, password) |
||||
end |
||||
end |
@ -0,0 +1,2 @@ |
||||
module MainHelper |
||||
end |
@ -0,0 +1,2 @@ |
||||
module MeetingsHelper |
||||
end |
@ -0,0 +1,2 @@ |
||||
module RoomsHelper |
||||
end |
@ -0,0 +1,18 @@ |
||||
module SessionsHelper |
||||
# Logs a user into GreenLight. |
||||
def login(user) |
||||
session[:user_id] = user.id |
||||
redirect_to room_path(user.room.uid) |
||||
end |
||||
|
||||
# Logs current user out of GreenLight. |
||||
def logout |
||||
session.delete(:user_id) if current_user |
||||
redirect_to root_path |
||||
end |
||||
|
||||
# Retrieves the current user. |
||||
def current_user |
||||
@current_user ||= User.find_by(id: session[:user_id]) |
||||
end |
||||
end |
@ -0,0 +1,2 @@ |
||||
class ApplicationJob < ActiveJob::Base |
||||
end |
@ -0,0 +1,4 @@ |
||||
class ApplicationMailer < ActionMailer::Base |
||||
default from: 'from@example.com' |
||||
layout 'mailer' |
||||
end |
@ -0,0 +1,3 @@ |
||||
class ApplicationRecord < ActiveRecord::Base |
||||
self.abstract_class = true |
||||
end |
@ -0,0 +1,99 @@ |
||||
class Meeting < ApplicationRecord |
||||
|
||||
before_create :generate_meeting_id |
||||
|
||||
belongs_to :room |
||||
|
||||
# Creates a meeting on the BigBlueButton server. |
||||
def create(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], |
||||
"meta_#{BigBlueHelper::META_LISTED}": false, |
||||
"meta_#{BigBlueHelper::META_TOKEN}": name |
||||
} |
||||
|
||||
#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. |
||||
create(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 |
||||
|
||||
# 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 |
||||
|
||||
# Use one common instance of the BigBlueButton API for all meetings. |
||||
def bbb |
||||
@@bbb ||= BigBlueButton::BigBlueButtonApi.new(bbb_endpoint + "api", bbb_secret, "0.8") |
||||
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 |
@ -0,0 +1,17 @@ |
||||
class Room < ApplicationRecord |
||||
|
||||
before_create :set_uid |
||||
|
||||
belongs_to :user |
||||
has_many :meetings |
||||
|
||||
def owned_by?(user) |
||||
user.room == self |
||||
end |
||||
|
||||
private |
||||
|
||||
def set_uid |
||||
self.uid = Digest::SHA1.hexdigest(user.uid + user.provider + user.username)[0..12] |
||||
end |
||||
end |
@ -0,0 +1,51 @@ |
||||
class User < ApplicationRecord |
||||
|
||||
has_one :room |
||||
|
||||
class << self |
||||
|
||||
# Generates a user from omniauth. |
||||
def from_omniauth(auth) |
||||
user = find_or_initialize_by(uid: auth['uid'], provider: auth['provider']) |
||||
user.name = send("#{auth['provider']}_name", auth) |
||||
user.username = send("#{auth['provider']}_username", auth) |
||||
user.email = send("#{auth['provider']}_email", auth) |
||||
#user.token = auth['credentials']['token'] |
||||
|
||||
# Create a room for the user if they don't have one. |
||||
user.room = Room.create unless user.room |
||||
|
||||
user.save! |
||||
user |
||||
end |
||||
|
||||
private |
||||
|
||||
# Provider attributes. |
||||
def twitter_name(auth) |
||||
auth['info']['name'] |
||||
end |
||||
|
||||
def twitter_username(auth) |
||||
auth['info']['nickname'] |
||||
end |
||||
|
||||
def twitter_email(auth) |
||||
auth['info']['email'] |
||||
end |
||||
|
||||
def google_name(auth) |
||||
auth['info']['name'] |
||||
end |
||||
|
||||
def google_username(auth) |
||||
auth['info']['email'].split('@').first |
||||
end |
||||
|
||||
def google_email(auth) |
||||
auth['info']['email'] |
||||
end |
||||
|
||||
end |
||||
|
||||
end |
@ -0,0 +1,43 @@ |
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
<title>Greenlight20</title> |
||||
<%= csrf_meta_tags %> |
||||
|
||||
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> |
||||
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> |
||||
</head> |
||||
|
||||
<body class="app-background" data-controller="<%= params[:controller] %>" data-action="<%= params[:action] %>" |
||||
data-resource="<%= params[:resource] %>" |
||||
data-current-user="<%= current_user.try(:encrypted_id) %>" |
||||
style="background-image:url(<%= image_path('background.png') if params[:controller] == 'main' %>);"> |
||||
|
||||
<!-- Messages --> |
||||
<div id='alerts'> |
||||
<div class='flash-alerts'> |
||||
<% flash.each do |name, msg| %> |
||||
<div class="alert alert-<%= name %> alert-dismissible fade in" role="alert"> |
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"> |
||||
<span aria-hidden="true">×</span> |
||||
</button> |
||||
<span class="alert-message"><%= msg %></span> |
||||
</div> |
||||
<% end %> |
||||
</div> |
||||
</div> |
||||
|
||||
<!-- Header --> |
||||
<div class='header'> |
||||
<span class="logo-wrapper pull-left"> |
||||
<% if current_user %> |
||||
<%= link_to image_tag("bbb_logo.png", :alt => "BigBlueButton", :class => "logo"), room_path(current_user) %> |
||||
<% else %> |
||||
<%= link_to image_tag("bbb_logo.png", :alt => "BigBlueButton", :class => "logo"), root_path %> |
||||
<% end %> |
||||
</span> |
||||
</div> |
||||
|
||||
<%= yield %> |
||||
</body> |
||||
</html> |
@ -0,0 +1,13 @@ |
||||
<!DOCTYPE html> |
||||
<html> |
||||