Merge v2.7-alpha (#1951)

* Fix wrong conditional (reported by LGTM) (#1477)

Signed-off-by: Stefan Weil <sw@weilnetz.de>

Co-authored-by: Ahmad Farhat <ahmad.af.farhat@gmail.com>

* Bump rack from 2.2.2 to 2.2.3 (#1839)

Bumps [rack](https://github.com/rack/rack) from 2.2.2 to 2.2.3.
- [Release notes](https://github.com/rack/rack/releases)
- [Changelog](https://github.com/rack/rack/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rack/rack/compare/v2.2.2...2.2.3)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* [FIX]  Unable to edit long recording names #1776  (#1780)

* Allow to set a filter for LDAP authentication

* [FIX] Unable to edit long recording names #1776

Co-authored-by: François Ménabé <francois.menabe@unistra.fr>
Co-authored-by: farhatahmad <ahmad.af.farhat@gmail.com>

* Desgin for Manage Users Tabs (#1777)

* Update _subtitle.html.erb

* Update _manage_users_tags.html.erb

* Update admins.scss

* Update _primary_themes.scss

* Update _manage_users_tags.html.erb

* Minor style changes to manage users (#1845)

* Maintenance banner moved to admin site (#1775)

* initial

* finish

* travis fixes

* travis again

* not required

* Co-authored-by: Tobias Fiebig <t.fiebig@tudelft.nl> (#1296)

Co-authored-by: Ahmad Farhat <ahmad.af.farhat@gmail.com>

* Enhance Room OpenGraph Metadata (#1601)

* Revert "Enhance Room OpenGraph Metadata (#1601)" (#1852)

This reverts commit 3b007c233ae12e0407f216ae269c63d6179f73b8.

* GRN2-xx: Tab title now displays the current page name (#1853)

* Tab title now displays the current page name

* Added page title for the rest of the pages

* Split Site Settings into 3 different tabs (#1858)

* Split Site Settings into 3 different tabs

* Fix copyright

* Added redirect to correct tab

* Make sure settings are displaying when they should

* Update en.yml (#1857)

* Build images for alpha branches (#1867)

* Upgraded jquery to latest version (#1896)

* Added favicon tag (#1898)

* Fixed XSS issue with role name (#1899)

* Update path for coloring redirect (#1908)

* Added a fourth section to the room uid (#1910)

* Fixed issue with insecure room sharing removal (#1914)

* Fixes typo (#1917)

Fixes typo: successfully was written incorrect.

* Fixed order of rooms in server rooms (#1915)

* Change default room sort to latest activity (#1919)

* GRN2-xx: Small changes/improvements to the recording settings (#1851)

* Small changes/improvements to the recording settings

* Replaced room warning with info flash

* Added global setting to enable/disable the recording consent feature

* Replace Legal with Terms (#1931)

* Added a more friendly OpenGraph description when invited to join a room (#1932)

* Fixed issue causing maintenance banner not to hide correctly (#1933)

* Hide recording menu and recording list when it is disabled (#1935)

* Hide recording menu and recording list when it is disabled

* Hide recording list when disabled

* GRN2-xx: Added an auto-refresh after 2 mins while waiting for room to start (#1947)

* Added an auto-refresh after 2 mins while waiting for room to start

* Fixed random issue with test case

* GRN2-xx: Added ability to preupload presentations to rooms (#1895)

* Added ability to preupload presentations to rooms (#1868)

* Added setting to site settings and allowed admins to change the presentation

* Added AWS S3 and GCS Storage ENV variables

* Added check to ensure file extension is correct

* Added icon to remove presentation

* Added testcases for preupload

* Add nginx redirect to solve issue with relative root

* Record title, instead of room name, in the popup (#1924)

* Update _public_recording_row.html.erb

* Update _recording_row.html.erb

Co-authored-by: Stefan Weil <sw@weilnetz.de>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: beckerr-rzht <beckerr@hochschule-trier.de>
Co-authored-by: François Ménabé <francois.menabe@unistra.fr>
Co-authored-by: MrKeksi <mrkeksi@users.noreply.github.com>
Co-authored-by: yanosz <yanosz@users.noreply.github.com>
Co-authored-by: Moritz Schlarb <moschlar@metalabs.de>
Co-authored-by: chronikum <34622984+chronikum@users.noreply.github.com>
Co-authored-by: Mitsutaka Sato <miztaka@honestyworks.jp>
Co-authored-by: hiroshisuga <45039819+hiroshisuga@users.noreply.github.com>
This commit is contained in:
Ahmad Farhat 2020-07-29 11:03:22 -04:00 committed by GitHub
parent 50c2070188
commit 60cf5f7440
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
64 changed files with 1463 additions and 399 deletions

3
.gitignore vendored
View File

@ -17,6 +17,9 @@ vendor/bundle
/public/assets/**
/public/b/**
# Ignore uploaded files
/storage
# Ignore production paths.
/db/production
/db/production-postgres

View File

@ -26,7 +26,7 @@ gem 'coffee-rails', '~> 4.2'
# gem 'mini_racer', platforms: :ruby
# Use jquery as the JavaScript library
gem 'jquery-rails', '~> 4.3.3'
gem 'jquery-rails', '~> 4.4'
gem 'jquery-ui-rails'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
@ -56,7 +56,7 @@ gem 'bn-ldap-authentication', '~> 0.1.4'
gem 'omniauth-bn-office365', '~> 0.1.1'
# BigBlueButton API wrapper.
gem 'bigbluebutton-api-ruby'
gem 'bigbluebutton-api-ruby', git: 'https://github.com/mconf/bigbluebutton-api-ruby.git', branch: 'master'
# Front-end.
gem 'bootstrap', '~> 4.3.1'
@ -76,6 +76,10 @@ gem 'redcarpet'
# For limiting access based on user roles
gem 'cancancan', '~> 2.0'
# Active Storage gems
gem 'aws-sdk-s3', '~> 1.75'
gem 'google-cloud-storage', '~> 1.26'
group :production do
# Use a postgres database in production.
gem 'pg', '~> 0.18'

View File

@ -6,6 +6,20 @@ GIT
tabler-rubygem (0.1.4.1)
autoprefixer-rails (>= 6.0.3)
GIT
remote: https://github.com/mconf/bigbluebutton-api-ruby.git
revision: 91dc495324a6b7e162773227ec3650f8a5b39c50
branch: master
specs:
bigbluebutton-api-ruby (1.7.0)
childprocess (>= 1.0.1)
ffi (>= 1.9.24)
json (>= 1.8.6)
nokogiri (>= 1.10.4)
rack (>= 1.6.11)
rubyzip (>= 1.3.0)
xml-simple (~> 1.1)
GEM
remote: https://rubygems.org/
specs:
@ -58,9 +72,23 @@ GEM
ast (2.4.0)
autoprefixer-rails (9.7.6)
execjs
aws-eventstream (1.1.0)
aws-partitions (1.343.0)
aws-sdk-core (3.104.1)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.239.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1.0)
aws-sdk-kms (1.36.0)
aws-sdk-core (~> 3, >= 3.99.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.75.0)
aws-sdk-core (~> 3, >= 3.104.1)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.1)
aws-sigv4 (1.2.1)
aws-eventstream (~> 1, >= 1.0.2)
bcrypt (3.1.13)
bigbluebutton-api-ruby (1.7.0)
xml-simple (~> 1.1)
bindex (0.8.1)
bn-ldap-authentication (0.1.4)
net-ldap (~> 0)
@ -73,6 +101,7 @@ GEM
builder (3.2.4)
byebug (11.1.3)
cancancan (2.3.0)
childprocess (4.0.0)
coffee-rails (4.2.2)
coffee-script (>= 2.2.0)
railties (>= 4.0.0)
@ -90,7 +119,11 @@ GEM
crack (0.4.3)
safe_yaml (~> 1.0.0)
crass (1.0.6)
declarative (0.0.20)
declarative-option (0.1.0)
diff-lcs (1.3)
digest-crc (0.6.1)
rake (~> 13.0)
docile (1.3.2)
dotenv (2.7.5)
dotenv-rails (2.7.5)
@ -112,16 +145,46 @@ GEM
sassc (>= 1.11)
globalid (0.4.2)
activesupport (>= 4.2.0)
google-api-client (0.42.1)
addressable (~> 2.5, >= 2.5.1)
googleauth (~> 0.9)
httpclient (>= 2.8.1, < 3.0)
mini_mime (~> 1.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.0)
signet (~> 0.12)
google-cloud-core (1.5.0)
google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0)
google-cloud-env (1.3.3)
faraday (>= 0.17.3, < 2.0)
google-cloud-errors (1.0.1)
google-cloud-storage (1.26.2)
addressable (~> 2.5)
digest-crc (~> 0.4)
google-api-client (~> 0.33)
google-cloud-core (~> 1.2)
googleauth (~> 0.9)
mini_mime (~> 1.0)
googleauth (0.13.0)
faraday (>= 0.17.3, < 2.0)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (~> 0.14)
hashdiff (1.0.1)
hashie (4.1.0)
hiredis (0.6.3)
http_accept_language (2.1.1)
httpclient (2.8.3)
i18n (1.8.2)
concurrent-ruby (~> 1.0)
i18n-language-mapping (0.1.2)
jbuilder (2.10.0)
activesupport (>= 5.0.0)
jquery-rails (4.3.5)
jmespath (1.4.0)
jquery-rails (4.4.0)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
@ -144,6 +207,7 @@ GEM
mini_mime (>= 0.1.1)
marcel (0.3.3)
mimemagic (~> 0.3.2)
memoist (0.16.2)
method_source (1.0.0)
mimemagic (0.3.5)
mini_mime (1.0.2)
@ -186,6 +250,7 @@ GEM
omniauth-twitter (1.4.0)
omniauth-oauth (~> 1.1)
rack
os (1.1.0)
pagy (3.8.1)
parallel (1.19.1)
parser (2.7.1.3)
@ -194,7 +259,7 @@ GEM
popper_js (1.16.0)
public_suffix (4.0.5)
puma (3.12.6)
rack (2.2.2)
rack (2.2.3)
rack-test (1.1.0)
rack (>= 1.0, < 3)
rails (5.2.4.3)
@ -237,8 +302,13 @@ GEM
redis (4.1.4)
remote_syslog_logger (1.0.4)
syslog_protocol
representable (3.0.4)
declarative (< 0.1.0)
declarative-option (< 0.2.0)
uber (< 0.2.0)
request_store (1.5.0)
rack (>= 1.4)
retriable (3.1.2)
rexml (3.2.4)
rspec-core (3.9.2)
rspec-support (~> 3.9.3)
@ -268,6 +338,7 @@ GEM
rubocop-ast (0.0.3)
parser (>= 2.7.0.1)
ruby-progressbar (1.10.1)
rubyzip (2.3.0)
safe_yaml (1.0.5)
sassc (2.3.0)
ffi (~> 1.9)
@ -280,6 +351,11 @@ GEM
sequel (5.32.0)
shoulda-matchers (3.1.3)
activesupport (>= 4.0.0)
signet (0.14.0)
addressable (~> 2.3)
faraday (>= 0.17.3, < 2.0)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simplecov (0.16.1)
docile (~> 1.1)
json (>= 1.8, < 3)
@ -313,6 +389,7 @@ GEM
thread_safe (~> 0.1)
tzinfo-data (1.2020.1)
tzinfo (>= 1.0.0)
uber (0.1.0)
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
unicode-display_width (1.7.0)
@ -335,8 +412,9 @@ PLATFORMS
DEPENDENCIES
action-cable-testing
aws-sdk-s3 (~> 1.75)
bcrypt (~> 3.1.7)
bigbluebutton-api-ruby
bigbluebutton-api-ruby!
bn-ldap-authentication (~> 0.1.4)
bootsnap (>= 1.1.0)
bootstrap (~> 4.3.1)
@ -348,11 +426,12 @@ DEPENDENCIES
factory_bot_rails
faker
font-awesome-sass (~> 5.9.0)
google-cloud-storage (~> 1.26)
hiredis
http_accept_language
i18n-language-mapping (~> 0.1.1)
jbuilder (~> 2.5)
jquery-rails (~> 4.3.3)
jquery-rails (~> 4.4)
jquery-ui-rails
listen (~> 3.0.5)
lograge

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -86,8 +86,12 @@ $(document).on('turbolinks:load', function(){
})
}
else if(action == "site_settings"){
var urlParams = new URLSearchParams(window.location.search);
// Only load the colour selectors if on the appearance tab
if (urlParams.get("tab") == null || urlParams.get("tab") == "appearance") {
loadColourSelectors()
}
}
else if (action == "roles"){
// Refreshes the new role modal
$("#newRoleButton").click(function(){
@ -119,19 +123,30 @@ $(document).on('turbolinks:load', function(){
// Change the branding image to the image provided
function changeBrandingImage(path) {
var url = $("#branding-url").val()
$.post(path, {value: url})
$.post(path, {value: url, tab: "appearance"})
}
// Change the Legal URL to the one provided
function changeLegalURL(path) {
var url = $("#legal-url").val()
$.post(path, {value: url})
$.post(path, {value: url, tab: "administration"})
}
// Change the Privacy Policy URL to the one provided
function changePrivacyPolicyURL(path) {
var url = $("#privpolicy-url").val()
$.post(path, {value: url})
$.post(path, {value: url, tab: "administration"})
}
// Display the maintenance Banner
function displayMaintenanceBanner(path) {
var message = $("#maintenance-banner").val()
$.post(path, {value: message, tab: "administration"})
}
// Clear the maintenance Banner
function clearMaintenanceBanner(path) {
$.post(path, {value: "", tab: "administration"})
}
function mergeUsers() {
@ -234,13 +249,13 @@ function loadColourSelectors() {
})
pickrLighten.on("save", (color, instance) => {
$.post($("#coloring-path-lighten").val(), {value: color.toHEXA().toString()}).done(function() {
$.post($("#coloring-path-lighten").val(), {value: color.toHEXA().toString(), tab: "appearance"}).done(function() {
location.reload()
});
})
pickrDarken.on("save", (color, instance) => {
$.post($("#coloring-path-darken").val(), {value: color.toHEXA().toString()}).done(function() {
$.post($("#coloring-path-darken").val(), {value: color.toHEXA().toString(), tab: "appearance"}).done(function() {
location.reload()
});
})

View File

@ -27,7 +27,7 @@
// about supported directives.
//
//= require turbolinks
//= require jquery
//= require jquery3
//= require tabler
//= require tabler.plugins
//= require jquery_ujs

View File

@ -26,9 +26,12 @@ $(document).on('turbolinks:load', function(){
})
$("#maintenance-close").click(function(event) {
//create a cookie that lasts 1 year
var cookieDate = new Date();
cookieDate.setFullYear(cookieDate.getFullYear() + 1); //1 year from now
//create a cookie that lasts 1 day
var cookieDate = new Date()
cookieDate.setDate(cookieDate.getDate() + 1) //1 day from now
console.log("maintenance_window=" + $(event.target).data("date") + "; path=/; expires=" + cookieDate.toUTCString() + ";")
document.cookie = "maintenance_window=" + $(event.target).data("date") + "; path=/; expires=" + cookieDate.toUTCString() + ";"
})
})

View File

@ -48,6 +48,8 @@ $(document).on('turbolinks:load', function(){
$("#create-room-block").click(function(){
showCreateRoom(this)
})
checkIfAutoJoin()
}
// Autofocus on the Room Name label when creating a room only
@ -129,6 +131,27 @@ $(document).on('turbolinks:load', function(){
$("#user-list").append(listItem)
}
})
$("#presentation-upload").change(function(data) {
var file = data.target.files[0]
// Check file type and size to make sure they aren't over the limit
if (validFileUpload(file)) {
$("#presentation-upload-label").text(file.name)
} else {
$("#invalid-file-type").show()
$("#presentation-upload").val("")
$("#presentation-upload-label").text($("#presentation-upload-label").data("placeholder"))
}
})
$(".preupload-room").click(function() {
updatePreuploadPresentationModal(this)
})
$("#remove-presentation").click(function(data) {
removePreuploadPresentation($(this).data("remove"))
})
}
});
@ -138,11 +161,11 @@ function showCreateRoom(target) {
$("#room_access_code").val(null)
$("#createRoomModal form").attr("action", $("body").data('relative-root'))
$("#room_mute_on_join").prop("checked", $("#room_mute_on_join").data("default"))
$("#room_require_moderator_approval").prop("checked", $("#room_require_moderator_approval").data("default"))
$("#room_anyone_can_start").prop("checked", $("#room_anyone_can_start").data("default"))
$("#room_all_join_moderator").prop("checked", $("#room_all_join_moderator").data("default"))
$("#room_recording").prop("checked", $("#room_recording").data("default"))
//show all elements & their children with a create-only class
$(".create-only").each(function() {
@ -197,12 +220,12 @@ function showDeleteRoom(target) {
//Update the createRoomModal to show the correct current settings
function updateCurrentSettings(settings_path){
// Get current room settings and set checkbox
$.get(settings_path, function(room_settings) {
var settings = JSON.parse(room_settings)
$.get(settings_path, function(settings) {
$("#room_mute_on_join").prop("checked", $("#room_mute_on_join").data("default") || settings.muteOnStart)
$("#room_require_moderator_approval").prop("checked", $("#room_require_moderator_approval").data("default") || settings.requireModeratorApproval)
$("#room_anyone_can_start").prop("checked", $("#room_anyone_can_start").data("default") || settings.anyoneCanStart)
$("#room_all_join_moderator").prop("checked", $("#room_all_join_moderator").data("default") || settings.joinModerator)
$("#room_recording").prop("checked", $("#room_recording").data("default") || Boolean(settings.recording))
})
}
@ -264,3 +287,44 @@ function removeSharedUser(target) {
parentLI.classList.add("remove-shared")
}
}
function updatePreuploadPresentationModal(target) {
$.get($(target).data("settings-path"), function(presentation) {
if(presentation.attached) {
$("#current-presentation").show()
$("#presentation-name").text(presentation.name)
$("#change-pres").show()
$("#use-pres").hide()
} else {
$("#current-presentation").hide()
$("#change-pres").hide()
$("#use-pres").show()
}
});
$("#preuploadPresentationModal form").attr("action", $(target).data("path"))
$("#remove-presentation").data("remove", $(target).data("remove"))
// Reset values to original to prevent confusion
$("#presentation-upload").val("")
$("#presentation-upload-label").text($("#presentation-upload-label").data("placeholder"))
$("#invalid-file-type").hide()
}
function removePreuploadPresentation(path) {
$.post(path, {})
}
function validFileUpload(file) {
return file.size/1024/1024 <= 30
}
// Automatically click the join button if this is an action cable reload
function checkIfAutoJoin() {
var url = new URL(window.location.href)
if (url.searchParams.get("reload") == "true") {
$("#joiner-consent").click()
$("#room-join").click()
}
}

View File

@ -27,6 +27,7 @@ $(document).on("turbolinks:load", function(){
}, {
connected: function() {
console.log("connected");
setTimeout(startRefreshTimeout, 120000);
},
disconnected: function(data) {
@ -40,7 +41,7 @@ $(document).on("turbolinks:load", function(){
received: function(data){
console.log(data);
if(data.action = "started"){
if(data.action == "started"){
request_to_join_meeting();
}
}
@ -68,3 +69,10 @@ var request_to_join_meeting = function(){
}
});
}
// Refresh the page after 2 mins and attempt to reconnect to ActionCable
function startRefreshTimeout() {
var url = new URL(window.location.href)
url.searchParams.set("reload","true")
window.location.href = url.href
}

View File

@ -84,10 +84,8 @@
color: white !important;
}
.manage-users-tab {
&:hover {
cursor: pointer;
}
#manage-users-nav.nav-tabs .nav-item {
margin-bottom: -1px;
}
#merge-account-arrow {
@ -97,3 +95,7 @@
z-index: 999;
background: white;
}
.admin-tabs {
justify-content: space-around;
}

View File

@ -145,6 +145,10 @@ input:focus {
border-color: $primary !important;
}
.input-group button:focus {
box-shadow: none !important;
}
.list-group-item-action.active {
color: $primary;
}

View File

@ -113,3 +113,12 @@
background: lightgray;
pointer-events: none;
}
#recording-table .edit_hover_class {
word-break: break-all;
white-space: normal;
}
#room-owner-name {
line-height: 12px;
}

View File

@ -47,6 +47,7 @@ class AdminsController < ApplicationController
# GET /admins/site_settings
def site_settings
@tab = params[:tab] || "appearance"
end
# GET /admins/server_recordings
@ -191,6 +192,7 @@ class AdminsController < ApplicationController
# POST /admins/update_settings
def update_settings
tab = params[:tab] || "settings"
@settings.update_value(params[:setting], params[:value])
flash_message = I18n.t("administrator.flash.settings")
@ -199,7 +201,7 @@ class AdminsController < ApplicationController
flash_message += ". " + I18n.t("administrator.site_settings.recording_visibility.warning")
end
redirect_to admin_site_settings_path, flash: { success: flash_message }
redirect_to admin_site_settings_path(tab: tab), flash: { success: flash_message }
end
# POST /admins/color
@ -207,7 +209,7 @@ class AdminsController < ApplicationController
@settings.update_value("Primary Color", params[:value])
@settings.update_value("Primary Color Lighten", color_lighten(params[:value]))
@settings.update_value("Primary Color Darken", color_darken(params[:value]))
redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") }
redirect_to admin_site_settings_path(tab: "appearance"), flash: { success: I18n.t("administrator.flash.settings") }
end
# POST /admins/registration_method/:method
@ -216,11 +218,11 @@ class AdminsController < ApplicationController
# Only allow change to Join by Invitation if user has emails enabled
if !Rails.configuration.enable_email_verification && new_method == Rails.configuration.registration_methods[:invite]
redirect_to admin_site_settings_path,
redirect_to admin_site_settings_path(tab: "settings"),
flash: { alert: I18n.t("administrator.flash.invite_email_verification") }
else
@settings.update_value("Registration Method", new_method)
redirect_to admin_site_settings_path,
redirect_to admin_site_settings_path(tab: "settings"),
flash: { success: I18n.t("administrator.flash.registration_method_updated") }
end
end
@ -229,7 +231,7 @@ class AdminsController < ApplicationController
def clear_auth
User.include_deleted.where(provider: @user_domain).update_all(social_uid: nil)
redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") }
redirect_to admin_site_settings_path(tab: "settings"), flash: { success: I18n.t("administrator.flash.settings") }
end
# POST /admins/clear_cache
@ -237,14 +239,14 @@ class AdminsController < ApplicationController
Rails.cache.delete("#{@user_domain}/getUser")
Rails.cache.delete("#{@user_domain}/getUserGreenlightCredentials")
redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") }
redirect_to admin_site_settings_path(tab: "settings"), flash: { success: I18n.t("administrator.flash.settings") }
end
# POST /admins/log_level
def log_level
Rails.logger.level = params[:value].to_i
redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") }
redirect_to admin_site_settings_path(tab: "administration"), flash: { success: I18n.t("administrator.flash.settings") }
end
# ROOM CONFIGURATION

View File

@ -84,9 +84,9 @@ class ApplicationController < ActionController::Base
help: I18n.t("errors.maintenance.help"),
}
end
if Rails.configuration.maintenance_window.present?
unless cookies[:maintenance_window] == Rails.configuration.maintenance_window
flash.now[:maintenance] = Rails.configuration.maintenance_window
if @settings.get_value("Maintenance Banner").present?
unless cookies[:maintenance_window] == @settings.get_value("Maintenance Banner")
flash.now[:maintenance] = @settings.get_value("Maintenance Banner")
end
end
end
@ -182,6 +182,18 @@ class ApplicationController < ActionController::Base
end
helper_method :shared_access_allowed
# Indicates whether users are allowed to share rooms
def recording_consent_required?
@settings.get_value("Require Recording Consent") == "true"
end
helper_method :recording_consent_required?
# Returns a list of allowed file types
def allowed_file_types
Rails.configuration.allowed_file_types
end
helper_method :allowed_file_types
# Returns the page that the logo redirects to when clicked on
def home_page
return admins_path if current_user.has_role? :super_admin

View File

@ -61,7 +61,7 @@ module BbbServer
# Creates a meeting on the BigBlueButton server.
def start_session(room, options = {})
create_options = {
record: options[:meeting_recorded].to_s,
record: options[:record].to_s,
logoutURL: options[:meeting_logout_url] || '',
moderatorPW: room.moderator_pw,
attendeePW: room.attendee_pw,
@ -77,11 +77,17 @@ module BbbServer
# Send the create request.
begin
meeting = bbb_server.create_meeting(room.name, room.bbb_id, create_options)
# Update session info.
meeting = if room.presentation.attached?
modules = BigBlueButton::BigBlueButtonModules.new
logger.info("Support: Room #{room.uid} starting using presentation: #{rails_blob_url(room.presentation)}")
modules.add_presentation(:url, rails_blob_url(room.presentation))
bbb_server.create_meeting(room.name, room.bbb_id, create_options, modules)
else
bbb_server.create_meeting(room.name, room.bbb_id, create_options)
end
unless meeting[:messageKey] == 'duplicateWarning'
room.update_attributes(sessions: room.sessions + 1,
last_session: DateTime.now)
room.update_attributes(sessions: room.sessions + 1, last_session: DateTime.now)
end
rescue BigBlueButton::BigBlueButtonException => e
puts "BigBlueButton failed on create: #{e.key}: #{e.message}"

View File

@ -105,6 +105,8 @@ module Joiner
"Room Configuration All Join Moderator"
when "anyoneCanStart"
"Room Configuration Allow Any Start"
when "recording"
"Room Configuration Recording"
end
case @settings.get_value(config)

View File

@ -27,7 +27,7 @@ class RoomsController < ApplicationController
unless: -> { !Rails.configuration.enable_email_verification }
before_action :find_room, except: [:create, :join_specific_room, :cant_create_rooms]
before_action :verify_room_ownership_or_admin_or_shared, only: [:start, :shared_access]
before_action :verify_room_ownership_or_admin, only: [:update_settings, :destroy]
before_action :verify_room_ownership_or_admin, only: [:update_settings, :destroy, :preupload_presentation, :remove_presentation]
before_action :verify_room_ownership_or_shared, only: [:remove_shared_access]
before_action :verify_room_owner_verified, only: [:show, :join],
unless: -> { !Rails.configuration.enable_email_verification }
@ -171,6 +171,7 @@ class RoomsController < ApplicationController
@room_settings = JSON.parse(@room[:room_settings])
opts[:mute_on_start] = room_setting_with_config("muteOnStart")
opts[:require_moderator_approval] = room_setting_with_config("requireModeratorApproval")
opts[:record] = record_meeting
begin
redirect_to join_path(@room, current_user.name, opts, current_user.uid)
@ -209,6 +210,45 @@ class RoomsController < ApplicationController
redirect_back fallback_location: room_path(@room)
end
# GET /:room_uid/current_presentation
def current_presentation
attached = @room.presentation.attached?
# Respond with JSON object of presentation name
respond_to do |format|
format.json { render body: { attached: attached, name: attached ? @room.presentation.filename.to_s : "" }.to_json }
end
end
# POST /:room_uid/preupload_presenstation
def preupload_presentation
begin
raise "Invalid file type" unless valid_file_type
@room.presentation.attach(room_params[:presentation])
flash[:success] = I18n.t("room.preupload_success")
rescue => e
logger.error "Support: Error in updating room presentation: #{e}"
flash[:alert] = I18n.t("room.preupload_error")
end
redirect_back fallback_location: room_path(@room)
end
# POST /:room_uid/remove_presenstation
def remove_presentation
begin
@room.presentation.purge
flash[:success] = I18n.t("room.preupload_remove_success")
rescue => e
logger.error "Support: Error in removing room presentation: #{e}"
flash[:alert] = I18n.t("room.preupload_remove_error")
end
redirect_back fallback_location: room_path(@room)
end
# POST /:room_uid/update_shared_access
def shared_access
begin
@ -240,7 +280,7 @@ class RoomsController < ApplicationController
# POST /:room_uid/remove_shared_access
def remove_shared_access
begin
SharedAccess.find_by!(room_id: @room.id, user_id: params[:user_id]).destroy
SharedAccess.find_by!(room_id: @room.id, user_id: current_user).destroy
flash[:success] = I18n.t("room.remove_shared_access_success")
rescue => e
logger.error "Support: Error in removing room shared access: #{e}"
@ -262,7 +302,7 @@ class RoomsController < ApplicationController
def room_settings
# Respond with JSON object of the room_settings
respond_to do |format|
format.json { render body: @room.room_settings.to_json }
format.json { render body: @room.room_settings }
end
end
@ -291,6 +331,7 @@ class RoomsController < ApplicationController
"requireModeratorApproval": options[:require_moderator_approval] == "1",
"anyoneCanStart": options[:anyone_can_start] == "1",
"joinModerator": options[:all_join_moderator] == "1",
"recording": options[:recording] == "1",
}
room_settings.to_json
@ -298,7 +339,8 @@ class RoomsController < ApplicationController
def room_params
params.require(:room).permit(:name, :auto_join, :mute_on_join, :access_code,
:require_moderator_approval, :anyone_can_start, :all_join_moderator)
:require_moderator_approval, :anyone_can_start, :all_join_moderator,
:recording, :presentation)
end
# Find the room from the uid.
@ -364,4 +406,18 @@ class RoomsController < ApplicationController
current_user.rooms.length >= limit
end
helper_method :room_limit_exceeded
def record_meeting
# If the require consent setting is checked, then check the room setting, else, set to true
if recording_consent_required?
room_setting_with_config("recording")
else
true
end
end
# Checks if the file extension is allowed
def valid_file_type
Rails.configuration.allowed_file_types.split(",").include?(File.extname(room_params[:presentation].original_filename))
end
end

View File

@ -61,6 +61,14 @@ module AdminsHelper
end
end
def preupload_string
if @settings.get_value("Preupload Presentation") == "true"
I18n.t("administrator.site_settings.authentication.enabled")
else
I18n.t("administrator.site_settings.authentication.disabled")
end
end
def recording_default_visibility_string
if @settings.get_value("Default Recording Visibility") == "public"
I18n.t("recording.visibility.public")
@ -80,6 +88,14 @@ module AdminsHelper
end
end
def require_consent_string
if @settings.get_value("Require Recording Consent") == "true"
I18n.t("administrator.site_settings.authentication.enabled")
else
I18n.t("administrator.site_settings.authentication.disabled")
end
end
def log_level_string
case Rails.logger.level
when 0
@ -97,6 +113,10 @@ module AdminsHelper
end
end
def show_log_dropdown
current_user.has_role?(:super_admin) || !Rails.configuration.loadbalanced_configuration
end
def room_limit_number
@settings.get_value("Room Limit").to_i
end

View File

@ -117,4 +117,11 @@ module ApplicationHelper
rescue
false
end
# Specifies which title should be the tab title and returns original string
def title(page_title)
# Only set the content_for if not already set on the page so that only the first title appears as the tab title
content_for(:page_title) { page_title } if content_for(:page_title).blank?
page_title
end
end

View File

@ -41,4 +41,8 @@ module RoomsHelper
def room_configuration(name)
@settings.get_value(name)
end
def preupload_allowed?
@settings.get_value("Preupload Presentation") == "true"
end
end

View File

@ -36,4 +36,8 @@ module ThemingHelper
def user_color
@settings.get_value("Primary Color") || Rails.configuration.primary_color_default
end
def maintenance_banner
@settings.get_value("Maintenance Banner")
end
end

View File

@ -28,7 +28,7 @@ class Ability
highest_role = user.role
if highest_role.get_permission("can_edit_site_settings")
can [:site_settings, :room_configuration, :update_settings,
:update_room_configuration, :coloring, :registration_method], :admin
:update_room_configuration, :coloring, :registration_method, :log_level], :admin
end
if highest_role.get_permission("can_edit_roles")

View File

@ -23,11 +23,15 @@ class Room < ApplicationRecord
before_create :setup
before_destroy :destroy_presentation
validates :name, presence: true
belongs_to :owner, class_name: 'User', foreign_key: :user_id
has_many :shared_access
has_one_attached :presentation
def self.admins_search(string)
active_database = Rails.configuration.database_configuration[Rails.env]["adapter"]
# Postgres requires created_at to be cast to a string
@ -51,6 +55,8 @@ class Room < ApplicationRecord
# Rely on manual ordering if trying to sort by status
return order_by_status(table, running_ids) if column == "status"
return table.order("COALESCE(rooms.last_session,rooms.created_at) DESC") if column == "created_at"
return table.order(Arel.sql("rooms.#{column} #{direction}")) if table.column_names.include?(column)
return table.order(Arel.sql("#{column} #{direction}")) if column == "users.name"
@ -86,15 +92,17 @@ class Room < ApplicationRecord
def self.order_by_status(table, ids)
return table if ids.blank?
order_string = "CASE bbb_id "
# Get active rooms first
active_rooms = table.where(bbb_id: ids)
ids.each_with_index do |id, index|
order_string += "WHEN '#{id}' THEN #{index} "
# Get other rooms sorted by last session date || created at date (whichever is higher)
inactive_rooms = table.where.not(bbb_id: ids).order("COALESCE(rooms.last_session,rooms.created_at) DESC")
active_rooms + inactive_rooms
end
order_string += "ELSE #{ids.length} END"
table.order(Arel.sql(order_string))
def recording_enabled?
JSON.parse(room_settings)["recording"]
end
private
@ -110,9 +118,9 @@ class Room < ApplicationRecord
# Generates a fully random room uid.
def random_room_uid
# 6 character long random string of chars from a..z and 0..9
full_chunk = SecureRandom.alphanumeric(6).downcase
full_chunk = SecureRandom.alphanumeric(9).downcase
[owner.name_chunk, full_chunk[0..2], full_chunk[3..5]].join("-")
[owner.name_chunk, full_chunk[0..2], full_chunk[3..5], full_chunk[6..8]].join("-")
end
# Generates a unique bbb_id based on uuid.
@ -122,4 +130,9 @@ class Room < ApplicationRecord
break bbb_id unless Room.exists?(bbb_id: bbb_id)
end
end
# Before destroying the room, make sure you also destroy the presentation attached
def destroy_presentation
presentation.purge if presentation.attached?
end
end

View File

@ -58,10 +58,14 @@ class Setting < ApplicationRecord
Rails.configuration.registration_method_default
when "Room Authentication"
false
when "Require Recording Consent"
Rails.configuration.require_consent_default
when "Room Limit"
Rails.configuration.number_of_rooms_default
when "Shared Access"
Rails.configuration.shared_access_default
when "Preupload Presentation"
Rails.configuration.preupload_presentation_default
when "Room Configuration Mute On Join"
room_config_setting("mute-on-join")
when "Room Configuration Require Moderator"
@ -70,6 +74,8 @@ class Setting < ApplicationRecord
room_config_setting("anyone-can-start")
when "Room Configuration All Join Moderator"
room_config_setting("all-join-moderator")
when "Room Configuration Recording"
room_config_setting("recording")
end
end

View File

@ -13,6 +13,6 @@
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
%>
<button style="<%= "background-color: #{role_colour(role)};border-color: #{role_colour(role)}" %>" class="user-role btn btn-sm" onclick="filterRole('<%= role.name %>')">
<button style="<%= "background-color: #{role_colour(role)};border-color: #{role_colour(role)}" %>" class="user-role btn btn-sm" onclick="filterRole('<%= escape_javascript(role.name) %>')">
<%= translated_role_name(role) %>
</button>

View File

@ -1,5 +1,5 @@
<%
# BigBlueButton open source conferencing system - http://www.bigbluespan.org/.
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
# Copyright (c) 2018 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
@ -14,20 +14,25 @@
%>
<div class="form-group mt-n3">
<div class="row">
<div class="col-12 tags">
<span id="active" class="btn btn-sm tag manage-users-tab <%= 'selected' if @tab == 'active' %>">
<nav class="row m-0">
<div class="nav col nav-tabs admin-tabs m-0 p-0" id="manage-users-nav" role="tablist">
<a class="nav-item p-3 nav-link <%= 'active' if @tab == 'active' %>" id="Active" href="?tab=active" role="tab" aria-selected="true"><i class="fas mr-3 fa-users"></i>
<%= t("roles.active") %>
</span>
<span id="pending" class="btn btn-sm tag manage-users-tab <%= 'selected' if @tab == 'pending' %>">
</a>
<a class="nav-item p-3 nav-link <%= 'active' if @tab == 'pending' %>" id="Pending" href="?tab=pending" role="tab" aria-selected="false"><i class="fas mr-3 fa-user-clock"></i>
<%= t("roles.pending") %>
</span>
<span id="denied" class="btn btn-sm tag manage-users-tab <%= 'selected' if @tab == 'denied' %>">
</a>
<a class="nav-item p-3 nav-link <%= 'active' if @tab == 'denied' %>" id="Denied" href="?tab=denied" role="tab" aria-selected="false"><i class="fas mr-3 fa-user-times"></i>
<%= t("roles.banned") %>
</span>
<span id="deleted" class="btn btn-sm tag manage-users-tab <%= 'selected' if @tab == 'deleted' %>">
</a>
<a class="nav-item p-3 nav-link <%= 'active' if @tab == 'deleted' %>" id="Deleted" href="?tab=deleted" role="tab" aria-selected="false"><i class="far mr-2 fa-trash-alt"></i>
<%= t("roles.deleted") %>
</span>
</div>
</a>
</div>
<% if admin_invite_registration %>
<%= link_to "#inviteModal", class: "btn btn-primary pt-3", id: "invite-user", "data-toggle": "modal" do %>
<%= t("administrator.users.invite") %><i class="fas fa-paper-plane ml-3"></i>
<% end %>
<% end %>
</nav>
</div>

View File

@ -98,4 +98,31 @@
</div>
</div>
</div>
<% if recording_consent_required? %>
<div class="mb-6 row">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("modal.room_settings.recording") %></label>
<label class="form-label text-muted"><%= t("administrator.room_configuration.recordings.info") %></label>
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<%= room_configuration_string("Room Configuration Recording") %>
</button>
<div class="dropdown-menu">
<%= button_to admin_update_room_configuration_path(setting: "Room Configuration Recording", value: "enabled"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.room_configuration.options.enabled") %>
<% end %>
<%= button_to admin_update_room_configuration_path(setting: "Room Configuration Recording", value: "optional"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.room_configuration.options.optional") %>
<% end %>
<%= button_to admin_update_room_configuration_path(setting: "Room Configuration Recording", value: "disabled"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.room_configuration.options.disabled") %>
<% end %>
</div>
</div>
</div>
</div>
</div>
<% end %>
</div>

View File

@ -65,6 +65,11 @@
<a href="" data-toggle="modal" data-target="#createRoomModal" class="update-room dropdown-item" data-settings-path="<%= room_settings_path(room) %>">
<i class="dropdown-icon fas fa-cog"></i> <%= t("room.settings") %>
</a>
<% if preupload_allowed? %>
<a href="" data-toggle="modal" data-target="#preuploadPresentationModal" class="preupload-room dropdown-item" data-path="<%= preupload_presentation_path(room) %>" data-settings-path="<%= current_presentation_path(room) %>" data-remove="<%= remove_presentation_path(room) %>">
<i class="dropdown-icon fas fa-file-upload"></i> <%= t("room.add_presentation") %>
</a>
<% end %>
<% if shared_access_allowed %>
<a href="" data-toggle="modal" data-target="#shareRoomModal" class="share-room dropdown-item" data-path="<%= room_shared_access_path(room) %>" data-users-path="<%= room_shared_users_path(room) %>">
<i class="dropdown-icon fas fa-users"></i> <%= t("room.share") %>

View File

@ -13,247 +13,30 @@
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
%>
<div class="form-group">
<div class="row">
<div class="col-12">
<div class="mb-6 form-group">
<label class="form-label"><%= t("administrator.site_settings.branding.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.branding.info") %></label>
<div class="input-group">
<input id="branding-url" type="text" class="form-control" value="<%= logo_image %>">
<span class="input-group-append">
<button id="branding-image" onclick="changeBrandingImage('<%= admin_update_settings_path(setting: 'Branding Image') %>')" class="btn btn-primary" type="button"><%= t("administrator.site_settings.branding.change") %></button>
</span>
<div class="form-group mt-n3">
<nav class="row m-0">
<div class="nav col nav-tabs admin-tabs m-0 p-0" >
<a class="nav-item p-3 nav-link <%= 'active' if @tab == 'appearance' %>" href="?tab=appearance" role="tab" aria-selected="true">
<i class="fas mr-3 fa-palette"></i>
<%= t("administrator.site_settings.tabs.appearance") %>
</a>
<a class="nav-item p-3 nav-link <%= 'active' if @tab == 'administration' %>" href="?tab=administration" role="tab" aria-selected="false">
<i class="fas mr-3 fa-toolbox"></i>
<%= t("administrator.site_settings.tabs.administration") %>
</a>
<a class="nav-item p-3 nav-link <%= 'active' if @tab == 'settings' %>" href="?tab=settings" role="tab" aria-selected="false">
<i class="fas mr-3 fa-tools"></i>
<%= t("administrator.site_settings.tabs.settings") %>
</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="mb-6 form-group">
<label class="form-label"><%= t("administrator.site_settings.legal.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.legal.info") %></label>
<div class="input-group">
<input id="legal-url" type="text" class="form-control" value="<%= legal_url %>">
<span class="input-group-append">
<button id="legal-url" onclick="changeLegalURL('<%= admin_update_settings_path(setting: 'Legal URL') %>')" class="btn btn-primary" type="button"><%= t("administrator.site_settings.legal.change") %></button>
</span>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="mb-6 form-group">
<label class="form-label"><%= t("administrator.site_settings.privpolicy.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.privpolicy.info") %></label>
<div class="input-group">
<input id="privpolicy-url" type="text" class="form-control" value="<%= privpolicy_url %>">
<span class="input-group-append">
<button id="privpolicy-url" onclick="changePrivacyPolicyURL('<%= admin_update_settings_path(setting: 'Privacy Policy URL') %>')" class="btn btn-primary" type="button"><%= t("administrator.site_settings.privpolicy.change") %></button>
</span>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="mb-6 form-group">
<label class="form-label"><%= t("administrator.site_settings.color.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.color.info") %></label>
<div class="color-inputs">
<input id="coloring-path-regular" type="hidden" value="<%= admin_coloring_path %>">
<input id="coloring-path-lighten" type="hidden" value="<%= admin_update_settings_path(setting: "Primary Color Lighten") %>">
<input id="coloring-path-darken" type="hidden" value="<%= admin_update_settings_path(setting: "Primary Color Darken") %>">
<div id="colorinput-regular" class="btn primary-regular mr-3">
<%= t("administrator.site_settings.color.regular") %>
</nav>
</div>
<div id="colorinput-lighten" class="btn primary-lighten mr-3">
<%= t("administrator.site_settings.color.lighten") %>
</div>
<% if @tab == "appearance"%>
<%= render "admins/components/site_settings/appearance" %>
<% elsif @tab == "administration"%>
<%= render "admins/components/site_settings/administration" %>
<% else %>
<%= render "admins/components/site_settings/settings" %>
<% end %>
<div id="colorinput-darken" class="btn primary-darken">
<%= t("administrator.site_settings.color.darken") %>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="mb-6 col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.registration.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.registration.info") %></label>
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" id="registrationMethods" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<%= registration_method_string %>
</button>
<div class="dropdown-menu" aria-labelledby="registrationMethods">
<%= button_to admin_change_registration_path(value: "open"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.registration.methods.open") %>
<% end %>
<%= button_to admin_change_registration_path(value: "invite"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.registration.methods.invite") %>
<% end %>
<%= button_to admin_change_registration_path(value: "approval"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.registration.methods.approval") %>
<% end %>
</div>
</div>
</div>
</div>
</div>
<div class="mb-6 row">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.authentication.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.authentication.info") %></label>
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" id="room-auth" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<%= room_authentication_string %>
</button>
<div class="dropdown-menu" aria-labelledby="room-auth">
<%= button_to admin_update_settings_path(setting: "Room Authentication", value: "true"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.authentication.enabled") %>
<% end %>
<%= button_to admin_update_settings_path(setting: "Room Authentication", value: "false"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.authentication.disabled") %>
<% end %>
</div>
</div>
</div>
</div>
</div>
<div class="mb-6 row">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.shared_access.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.shared_access.info") %></label>
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" id="room-auth" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<%= shared_access_string %>
</button>
<div class="dropdown-menu" aria-labelledby="room-auth">
<%= button_to admin_update_settings_path(setting: "Shared Access", value: "true"), class: "dropdown-item" do %>
<%= t("administrator.site_settings.authentication.enabled") %>
<% end %>
<%= button_to admin_update_settings_path(setting: "Shared Access", value: "false"), class: "dropdown-item" do %>
<%= t("administrator.site_settings.authentication.disabled") %>
<% end %>
</div>
</div>
</div>
</div>
</div>
<div class="mb-6 row">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.recording_visibility.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.recording_visibility.info") %></label>
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" id="room-auth" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<%= recording_default_visibility_string %>
</button>
<div class="dropdown-menu" aria-labelledby="room-auth">
<%= button_to admin_update_settings_path(setting: "Default Recording Visibility", value: "public"), class: "dropdown-item", "data-disable": "" do %>
<%= t("recording.visibility.public") %>
<% end %>
<%= button_to admin_update_settings_path(setting: "Default Recording Visibility", value: "private"), class: "dropdown-item", "data-disable": "" do %>
<%= t("recording.visibility.unlisted") %>
<% end %>
</div>
</div>
</div>
</div>
</div>
<div class="mb-6 row">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.rooms.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.rooms.info") %></label>
<div class="row gutters-xs">
<div class="col-auto">
<label class="colorinput">
<%= button_to admin_update_settings_path(setting: "Room Limit", value: 1), class: "colorinput-input", "data-disable": "" do %><% end %>
<span class="colorinput-color <%= room_limit_number == 1 ? "btn-primary" : "btn-outline-primary" %>">1</span>
</label>
</div>
<div class="col-auto">
<label class="colorinput">
<%= button_to admin_update_settings_path(setting: "Room Limit", value: 5), class: "colorinput-input", "data-disable": "" do %><% end %>
<span class="colorinput-color <%= room_limit_number == 5 ? "btn-primary" : "btn-outline-primary" %>">5</span>
</label>
</div>
<div class="col-auto">
<label class="colorinput">
<%= button_to admin_update_settings_path(setting: "Room Limit", value: 10), class: "colorinput-input", "data-disable": "" do %><% end %>
<span class="colorinput-color <%= room_limit_number == 10 ? "btn-primary" : "btn-outline-primary" %>">10</span>
</label>
</div>
<div class="col-auto">
<label class="colorinput">
<%= button_to admin_update_settings_path(setting: "Room Limit", value: 15), class: "colorinput-input", "data-disable": "" do %><% end %>
<span class="colorinput-color <%= room_limit_number == 15 ? "btn-primary" : "btn-outline-primary" %>">15+</span>
</label>
</div>
</div>
</div>
</div>
</div>
<% if current_user.has_role? :super_admin%>
<hr>
<div class="row">
<div class="col-12">
<div class="mb-6 form-group">
<label class="form-label"><%= t("administrator.site_settings.cache.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.cache.info") %></label>
<%= button_to t("administrator.site_settings.cache.button"), admin_clear_cache_path, class: "btn btn-primary", "data-disable": "" %>
</div>
</div>
</div>
<div class="mb-4 row">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.clear_auth.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.clear_auth.info") %></label>
<%= button_to t("administrator.site_settings.clear_auth.button"), admin_clear_auth_path, class: "btn btn-primary" %>
</div>
</div>
</div>
<div class="mb-4 row">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.log_level.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.log_level.information") %></label>
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" id="room-auth" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<%= log_level_string %>
</button>
<div class="dropdown-menu" aria-labelledby="room-auth">
<%= button_to admin_log_level_path(value: 0), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.log_level.debug") %>
<% end %>
<%= button_to admin_log_level_path(value: 1), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.log_level.info") %>
<% end %>
<%= button_to admin_log_level_path(value: 2), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.log_level.warn") %>
<% end %>
<%= button_to admin_log_level_path(value: 3), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.log_level.error") %>
<% end %>
<%= button_to admin_log_level_path(value: 4), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.log_level.fatal") %>
<% end %>
<%= button_to admin_log_level_path(value: 5), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.log_level.unknown") %>
<% end %>
</div>
</div>
</div>
</div>
</div>
<% end %>

View File

@ -0,0 +1,96 @@
<%
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
# Copyright (c) 2018 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/>.
%>
<div class="form-group">
<div class="row mb-2">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.maintenance_banner.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.maintenance_banner.info") %></label>
<div class="input-group">
<input id="maintenance-banner" type="text" class="form-control" value="<%= maintenance_banner %>" placeholder="<%= t("administrator.site_settings.maintenance_banner.time") %>">
<span class="input-group-append">
<button onclick="displayMaintenanceBanner('<%= admin_update_settings_path(setting: 'Maintenance Banner') %>')" class="settings-button btn btn-primary" type="button"><%= t("administrator.site_settings.maintenance_banner.display") %></button>
<button onclick="clearMaintenanceBanner('<%= admin_update_settings_path(setting: 'Maintenance Banner') %>')" class="settings-button btn btn-danger" type="button"><%= t("administrator.site_settings.maintenance_banner.clear") %></button>
</span>
</div>
</div>
</div>
</div>
<div class="row mb-2">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.legal.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.legal.info") %></label>
<div class="input-group">
<input id="legal-url" type="text" class="form-control" value="<%= legal_url %>">
<span class="input-group-append">
<button id="legal-url" onclick="changeLegalURL('<%= admin_update_settings_path(setting: 'Legal URL') %>')" class="btn btn-primary" type="button"><%= t("administrator.site_settings.legal.change") %></button>
</span>
</div>
</div>
</div>
</div>
<div class="row mb-2">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.privpolicy.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.privpolicy.info") %></label>
<div class="input-group">
<input id="privpolicy-url" type="text" class="form-control" value="<%= privpolicy_url %>">
<span class="input-group-append">
<button id="privpolicy-url" onclick="changePrivacyPolicyURL('<%= admin_update_settings_path(setting: 'Privacy Policy URL') %>')" class="btn btn-primary" type="button"><%= t("administrator.site_settings.privpolicy.change") %></button>
</span>
</div>
</div>
</div>
</div>
<% if show_log_dropdown %>
<div class="row">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.log_level.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.log_level.information") %></label>
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" id="room-auth" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<%= log_level_string %>
</button>
<div class="dropdown-menu" aria-labelledby="room-auth">
<%= button_to admin_log_level_path(value: 0), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.log_level.debug") %>
<% end %>
<%= button_to admin_log_level_path(value: 1), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.log_level.info") %>
<% end %>
<%= button_to admin_log_level_path(value: 2), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.log_level.warn") %>
<% end %>
<%= button_to admin_log_level_path(value: 3), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.log_level.error") %>
<% end %>
<%= button_to admin_log_level_path(value: 4), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.log_level.fatal") %>
<% end %>
<%= button_to admin_log_level_path(value: 5), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.log_level.unknown") %>
<% end %>
</div>
</div>
</div>
</div>
</div>
<% end %>
</div>

View File

@ -0,0 +1,56 @@
<%
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
# Copyright (c) 2018 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/>.
%>
<div class="form-group">
<div class="row mb-2">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.branding.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.branding.info") %></label>
<div class="input-group">
<input id="branding-url" type="text" class="form-control" value="<%= logo_image %>">
<span class="input-group-append">
<button id="branding-image" onclick="changeBrandingImage('<%= admin_update_settings_path(setting: 'Branding Image') %>')" class="btn btn-primary" type="button"><%= t("administrator.site_settings.branding.change") %></button>
</span>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.color.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.color.info") %></label>
<div class="color-inputs">
<input id="coloring-path-regular" type="hidden" value="<%= admin_coloring_path %>">
<input id="coloring-path-lighten" type="hidden" value="<%= admin_update_settings_path(setting: "Primary Color Lighten") %>">
<input id="coloring-path-darken" type="hidden" value="<%= admin_update_settings_path(setting: "Primary Color Darken") %>">
<div id="colorinput-regular" class="btn primary-regular mr-3">
<%= t("administrator.site_settings.color.regular") %>
</div>
<div id="colorinput-lighten" class="btn primary-lighten mr-3">
<%= t("administrator.site_settings.color.lighten") %>
</div>
<div id="colorinput-darken" class="btn primary-darken">
<%= t("administrator.site_settings.color.darken") %>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,201 @@
<%
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
# Copyright (c) 2018 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/>.
%>
<div class="form-group">
<div class="row mb-2">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.registration.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.registration.info") %></label>
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" id="registrationMethods" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<%= registration_method_string %>
</button>
<div class="dropdown-menu" aria-labelledby="registrationMethods">
<%= button_to admin_change_registration_path(value: "open"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.registration.methods.open") %>
<% end %>
<%= button_to admin_change_registration_path(value: "invite"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.registration.methods.invite") %>
<% end %>
<%= button_to admin_change_registration_path(value: "approval"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.registration.methods.approval") %>
<% end %>
</div>
</div>
</div>
</div>
</div>
<div class="row mb-2">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.authentication.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.authentication.info") %></label>
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" id="room-auth" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<%= room_authentication_string %>
</button>
<div class="dropdown-menu" aria-labelledby="room-auth">
<%= button_to admin_update_settings_path(setting: "Room Authentication", value: "true"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.authentication.enabled") %>
<% end %>
<%= button_to admin_update_settings_path(setting: "Room Authentication", value: "false"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.authentication.disabled") %>
<% end %>
</div>
</div>
</div>
</div>
</div>
<div class="row mb-2">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.shared_access.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.shared_access.info") %></label>
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" id="room-auth" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<%= shared_access_string %>
</button>
<div class="dropdown-menu" aria-labelledby="room-auth">
<%= button_to admin_update_settings_path(setting: "Shared Access", value: "true"), class: "dropdown-item" do %>
<%= t("administrator.site_settings.authentication.enabled") %>
<% end %>
<%= button_to admin_update_settings_path(setting: "Shared Access", value: "false"), class: "dropdown-item" do %>
<%= t("administrator.site_settings.authentication.disabled") %>
<% end %>
</div>
</div>
</div>
</div>
</div>
<div class="row mb-2">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.preupload.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.preupload.info") %></label>
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" id="room-auth" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<%= preupload_string %>
</button>
<div class="dropdown-menu" aria-labelledby="room-auth">
<%= button_to admin_update_settings_path(setting: "Preupload Presentation", value: "true"), class: "dropdown-item" do %>
<%= t("administrator.site_settings.authentication.enabled") %>
<% end %>
<%= button_to admin_update_settings_path(setting: "Preupload Presentation", value: "false"), class: "dropdown-item" do %>
<%= t("administrator.site_settings.authentication.disabled") %>
<% end %>
</div>
</div>
</div>
</div>
</div>
<div class="row mb-2">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.recording_visibility.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.recording_visibility.info") %></label>
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" id="room-auth" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<%= recording_default_visibility_string %>
</button>
<div class="dropdown-menu" aria-labelledby="room-auth">
<%= button_to admin_update_settings_path(setting: "Default Recording Visibility", value: "public"), class: "dropdown-item", "data-disable": "" do %>
<%= t("recording.visibility.public") %>
<% end %>
<%= button_to admin_update_settings_path(setting: "Default Recording Visibility", value: "private"), class: "dropdown-item", "data-disable": "" do %>
<%= t("recording.visibility.unlisted") %>
<% end %>
</div>
</div>
</div>
</div>
</div>
<div class="row mb-2">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.require_consent.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.require_consent.info") %></label>
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<%= require_consent_string %>
</button>
<div class="dropdown-menu" aria-labelledby="room-auth">
<%= button_to admin_update_settings_path(setting: "Require Recording Consent", value: "true"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.authentication.enabled") %>
<% end %>
<%= button_to admin_update_settings_path(setting: "Require Recording Consent", value: "false"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.authentication.disabled") %>
<% end %>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.rooms.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.rooms.info") %></label>
<div class="row gutters-xs">
<div class="col-auto">
<label class="colorinput">
<%= button_to admin_update_settings_path(setting: "Room Limit", value: 1), class: "colorinput-input", "data-disable": "" do %><% end %>
<span class="colorinput-color <%= room_limit_number == 1 ? "btn-primary" : "btn-outline-primary" %>">1</span>
</label>
</div>
<div class="col-auto">
<label class="colorinput">
<%= button_to admin_update_settings_path(setting: "Room Limit", value: 5), class: "colorinput-input", "data-disable": "" do %><% end %>
<span class="colorinput-color <%= room_limit_number == 5 ? "btn-primary" : "btn-outline-primary" %>">5</span>
</label>
</div>
<div class="col-auto">
<label class="colorinput">
<%= button_to admin_update_settings_path(setting: "Room Limit", value: 10), class: "colorinput-input", "data-disable": "" do %><% end %>
<span class="colorinput-color <%= room_limit_number == 10 ? "btn-primary" : "btn-outline-primary" %>">10</span>
</label>
</div>
<div class="col-auto">
<label class="colorinput">
<%= button_to admin_update_settings_path(setting: "Room Limit", value: 15), class: "colorinput-input", "data-disable": "" do %><% end %>
<span class="colorinput-color <%= room_limit_number == 15 ? "btn-primary" : "btn-outline-primary" %>">15+</span>
</label>
</div>
</div>
</div>
</div>
</div>
<% if current_user.has_role? :super_admin %>
<hr>
<div class="row mb-2">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.cache.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.cache.info") %></label>
<%= button_to t("administrator.site_settings.cache.button"), admin_clear_cache_path, class: "btn btn-primary", "data-disable": "" %>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.clear_auth.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.clear_auth.info") %></label>
<%= button_to t("administrator.site_settings.clear_auth.button"), admin_clear_auth_path, class: "btn btn-primary" %>
</div>
</div>
</div>
<% end %>
</div>

View File

@ -28,6 +28,9 @@
<%= render "shared/modals/delete_room_modal" %>
<%= render "shared/modals/create_room_modal" %>
<% if preupload_allowed? %>
<%= render "shared/modals/preupload_presentation_modal" %>
<% end %>
<% if shared_access_allowed %>
<%= render "shared/modals/share_room_modal" %>
<% end %>

View File

@ -28,13 +28,12 @@
</script>
<% end %>
<title><%= t("bigbluebutton") %></title>
<meta property="og:title" content="<%= t("bigbluebutton", locale: :en) %>" />
<title><%= yield(:page_title).present? ? yield(:page_title) : t("bigbluebutton") %></title>
<meta property="og:title" content="<%= yield(:page_title).present? ? yield(:page_title) : t("bigbluebutton") %>" />
<meta property="og:type" content="website" />
<meta property="og:description" content="<%= t("landing.about", href: "Greenlight", locale: :en) %>" />
<meta property="og:description" content="<%= yield(:page_desc).present? ? yield(:page_desc) : t("landing.about", href: "Greenlight", locale: :en) %>" />
<meta property="og:url" content="<%= request.base_url %>" />
<meta property="og:image" content="<%= logo_image %>" />
<meta name="viewport" content= "width=device-width, user-scalable=no">
<%= csrf_meta_tags %>
@ -48,6 +47,8 @@
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= favicon_link_tag asset_path('favicon.ico') %>
<!-- Primary color styling -->
<%= stylesheet_link_tag themes_primary_path %>

View File

@ -50,6 +50,11 @@
<a href="" data-toggle="modal" data-target="#createRoomModal" class="update-room dropdown-item" data-settings-path="<%= room_settings_path(room) %>">
<i class="dropdown-icon fas fa-cog"></i> <%= t("room.settings") %>
</a>
<% if preupload_allowed? %>
<a href="" data-toggle="modal" data-target="#preuploadPresentationModal" class="preupload-room dropdown-item" data-path="<%= preupload_presentation_path(room) %>" data-settings-path="<%= current_presentation_path(room) %>" data-remove="<%= remove_presentation_path(room) %>">
<i class="dropdown-icon fas fa-file-upload"></i> <%= t("room.add_presentation") %>
</a>
<% end %>
<% if shared_access_allowed %>
<a href="" data-toggle="modal" data-target="#shareRoomModal" class="share-room dropdown-item" data-path="<%= room_shared_access_path(room) %>" data-users-path="<%= room_shared_users_path(room) %>">
<i class="dropdown-icon fas fa-users"></i> <%= t("room.share") %>

View File

@ -18,19 +18,19 @@
<div class="row pt-9">
<div class="col-lg-12 col-sm-12">
<h4 class="text-left"><%= t("room.invited") %></h4>
<h1 class="display-3 text-left mb-3 font-weight-400"><%= @room.name %></h1>
<h1 class="display-3 text-left mb-3 font-weight-400"><%= title(@room.name) %></h1>
<hr class="mt-2 float-left w-25">
</div>
</div>
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-12 form-inline mb-5 align-top">
<div class="col-lg-6 col-md-6 col-sm-12 mb-5">
<% if @room.owner.image.blank? %>
<span class="avatar"><%= @room.owner.name.first %></span>
<% else %>
<span class="avatar" style="background-image: url(<%= @room.owner.image %>)"></span>
<% end %>
<h5 class="font-weight-normal ml-4 mt-3"><%= @room.owner.name %> (<%= t("room.owner") %>)</h5>
<h5 id="room-owner-name" class="font-weight-normal ml-4 mt-3 d-inline-block"><%= @room.owner.name %> (<%= t("room.owner") %>)</h5>
</div>
<div class="col-lg-6 col-md-6 col-sm-12">
@ -40,6 +40,7 @@
</div>
</div>
<% if render_recordings %>
<% recording = room_configuration("Room Configuration Recording") %>
<% if render_recordings && recording != "disabled" %>
<%= render "shared/sessions", recordings: @public_recordings, pagy: @pagy, only_public: true, user_recordings: false, title: t("room.recordings") %>
<% end %>

View File

@ -13,6 +13,8 @@
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
%>
<% content_for(:page_desc) { t("room.invitation_description", name: @room.name) } %>
<% valid_access_code = @room.access_code.nil? || @room.access_code.empty? || @room.access_code == session[:access_code] %>
<%= render 'rooms/components/room_event', render_recordings: valid_access_code do %>
<% if room_authentication_required %>
@ -44,11 +46,17 @@
autofocus: true
%>
<span class="input-group-append">
<button type="submit" class="btn btn-primary btn-sm px-7 form-control join-form">
<button id="room-join" type="submit" class="btn btn-primary btn-sm px-7 form-control join-form">
<%= (!@room_running && @anyone_can_start) ? t("room.start") : t("room.join") %>
</button>
</span>
</div>
<% if recording_consent_required? && @room.recording_enabled? %>
<label class="custom-control custom-checkbox">
<input id="joiner-consent" type="checkbox" class="custom-control-input" required>
<h4 class="text-left text-danger mt-4 custom-control-label"><%= t("room.recording_present") %></h4>
</label>
<% end %>
<% end %>
<% end %>
<% end %>

View File

@ -24,11 +24,10 @@
<div class="row pt-7 pt-sm-9">
<div class="col-lg-8 col-sm-12">
<div id="room-title" class="display-3 form-inline <%= 'edit_hover_class' if current_user.main_room != @room %>" data-path="<%= update_settings_path(@room) %>">
<h1 contenteditable=false id="user-text" class="display-3 text-left mb-3 font-weight-400"><%= title(@room.name) %></h1>
<% if current_user.main_room == @room %>
<h1 contenteditable=false id="user-text" class="display-3 text-left mb-3 font-weight-400"><%= @room.name %></h1>
<a class="disable-click"><i class="fas fa-home align-top home-indicator ml-2"></i></a>
<% else %>
<h1 contenteditable=false id="user-text" class="display-3 text-left mb-3 font-weight-400"><%= @room.name %></h1>
<a><i id="edit-room" class="fa fa-edit align-top home-indicator ml-2" data-edit-room="<%= @room.uid %>"></i></a>
<% end %>
</div>
@ -104,12 +103,19 @@
</div>
</div>
<% recording = room_configuration("Room Configuration Recording") %>
<% if recording != "disabled" %>
<%= render "shared/sessions", recordings: @recordings, pagy: @pagy, only_public: false, shared_room: @shared_room, user_recordings: false, title: t("room.recordings")%>
<% end %>
<%= render "shared/modals/delete_room_modal" %>
<%= render "shared/modals/create_room_modal" %>
<% if preupload_allowed? %>
<%= render "shared/modals/preupload_presentation_modal" %>
<% end %>
<% if shared_access_allowed %>
<%= render "shared/modals/share_room_modal" %>
<%= render "shared/modals/remove_access_modal" %>

View File

@ -27,7 +27,7 @@
<% elsif key.eql? "maintenance" %>
<div class="alert alert-info alert-dismissible text-center mb-0">
<%= value %>
<button id="maintenance-close" type="button" data-date="<%= Rails.configuration.maintenance_window %>" class="close" data-dismiss="alert">&times</button>
<button id="maintenance-close" type="button" data-date="<%= URI.encode(value) %>" class="close" data-dismiss="alert">&times</button>
</div>
<% elsif key.eql? "info" %>
<div class="alert alert-info alert-dismissible text-center mb-0">

View File

@ -31,7 +31,9 @@
<i class="fas fa-home pr-1 "></i><span class="d-none d-sm-inline-block"><%= t("header.dropdown.home") %></span>
<% end %>
<% if current_user.role.get_permission("can_create_rooms") && !current_user.has_role?(:super_admin) %>
<% recording = room_configuration("Room Configuration Recording") %>
<% if current_user.role.get_permission("can_create_rooms") && !current_user.has_role?(:super_admin) &&
recording != "disabled" %>
<% all_rec_page = params[:controller] == "users" && params[:action] == "recordings" ? "active" : "" %>
<%= link_to get_user_recordings_path(current_user), class: "px-3 mx-1 mt-1 header-nav #{all_rec_page}" do %>
<i class="fas fa-video pr-1"></i><span class="d-none d-sm-inline-block"><%= t("header.all_recordings") %></span>

View File

@ -16,10 +16,11 @@
<tr>
<td>
<div id="recording-title" class="edit_hover_class" data-recordid="<%= recording[:recordID] %>" data-room-uid="<%= room_uid_from_bbb(recording[:meetingID]) %>" data-path="<%= rename_recording_path(meetingID: recording[:meetingID], record_id: recording[:recordID]) %>">
<span id="recording-text" title="<%= recording[:name] %>">
<% if recording[:metadata][:name] %>
<span id="recording-text" title="<%= recording[:metadata][:name] %>">
<%= recording[:metadata][:name] %>
<% else %>
<span id="recording-text" title="<%= recording[:name] %>">
<%= recording[:name] %>
<% end %>
</span>

View File

@ -16,10 +16,11 @@
<tr>
<td>
<div id="recording-title" class="edit_hover_class" data-recordid="<%= recording[:recordID] %>" data-room-uid="<%= room_uid_from_bbb(recording[:meetingID]) %>" data-path="<%= rename_recording_path(meetingID: recording[:meetingID], record_id: recording[:recordID]) %>">
<span id='recording-text' title="<%= recording[:name] %>">
<% if recording[:metadata][:name] %>
<span id='recording-text' title="<%= recording[:metadata][:name] %>">
<%= recording[:metadata][:name] %>
<% else %>
<span id='recording-text' title="<%= recording[:name] %>">
<%= recording[:name] %>
<% end %>
</span>

View File

@ -16,18 +16,10 @@
<div class="row mt-2">
<% if search %>
<div class="col-md-6">
<p class="subtitle"><%= subtitle %></p>
<p class="subtitle"><%= title(subtitle) %></p>
</div>
<div class="col-md-6 mb-4">
<% if admin_invite_registration %>
<div id="invite-user" class="d-inline-block float-right ml-3">
<%= link_to "#inviteModal", :class => "btn btn-primary", "data-toggle": "modal" do %>
<%= t("administrator.users.invite") %> <i class="fas fa-paper-plane ml-1"></i>
<% end %>
</div>
<% end %>
<div id="search-bar" class="d-inline-block float-right">
<div class="input-group">
<input id="search-input" type="text" class="form-control" placeholder="<%= t("settings.search") %>..." value="<%= @search %>">
@ -46,7 +38,7 @@
</div>
<% else %>
<div class="col-12">
<p class="subtitle"><%= subtitle %></p>
<p class="subtitle"><%= title(subtitle) %></p>
</div>
<% end %>
</div>

View File

@ -69,7 +69,6 @@
<span class="custom-switch-indicator float-right cursor-pointer"></span>
</label>
<% end %>
<% moderator = room_configuration("Room Configuration All Join Moderator") %>
<% if moderator != "disabled" %>
<label class="custom-switch pl-0 mt-3 mb-3 w-100 text-left d-inline-block <%= "enabled-setting" if moderator == "enabled" %>">
@ -78,7 +77,14 @@
<span class="custom-switch-indicator float-right cursor-pointer"></span>
</label>
<% end %>
<% recording = room_configuration("Room Configuration Recording") %>
<% if recording_consent_required? && recording != "disabled" %>
<label class="custom-switch pl-0 mt-3 mb-3 w-100 text-left d-inline-block <%= "enabled-setting" if recording == "enabled" %>">
<span class="custom-switch-description"><%= t("modal.room_settings.recording")%></span>
<%= f.check_box :recording, class: "not-running-only custom-switch-input", data: { default: recording == "enabled" }, checked: false %>
<span class="custom-switch-indicator not-running-only float-right cursor-pointer"></span>
</label>
<% end %>
<label id="auto-join-label" class="create-only custom-switch pl-0 mt-3 mb-3 w-100 text-left d-inline-block">
<span class="custom-switch-description"><%= t("modal.create_room.auto_join") %></span>
<%= f.check_box :auto_join, class: "custom-switch-input", checked: false %>

View File

@ -0,0 +1,52 @@
<%
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
# Copyright (c) 2018 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/>.
%>
<div class="modal fade" id="preuploadPresentationModal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content text-center">
<div class="modal-body">
<div class="card-body p-sm-6">
<div class="card-title">
<h3><%= t("modal.preupload.title") %></h3>
</div>
<div id="current-presentation" class='mt-5 text-left'>
<label class='form-label'><%= t('modal.preupload.current') %></label>
<div class='list-group-item text-left'>
<span id="presentation-name"></span>
<span id="remove-presentation" class="text-primary float-right cursor-pointer"><i class="fas fa-trash-alt"></i></span>
</div>
</div>
<div class="mt-5">
<%= form_for(:room, method: :post, url: "/") do |f| %>
<p id="invalid-file-type" class="text-danger"><%= t("modal.preupload.invalid") %></p>
<div class="input-group mb-3">
<div class="custom-file text-left">
<%= f.label :presentation, t("modal.preupload.choose", type: allowed_file_types), id:"presentation-upload-label", class: "custom-file-label", "data-placeholder": t("modal.preupload.choose", type: allowed_file_types) %>
<%= f.file_field :presentation, id: "presentation-upload", class: "custom-file-input cursor-pointer", accept: allowed_file_types, required: "true" %>
</div>
</div>
<%= f.submit t("modal.preupload.change"), id: "change-pres", class: "btn btn-primary btn-block" %>
<%= f.submit t("modal.preupload.use"), id: "use-pres", class: "btn btn-primary btn-block" %>
<% end %>
</div>
</div>
<div class="card-footer">
<p><%= t("modal.preupload.footer") %></p>
</div>
</div>
</div>
</div>
</div>

View File

@ -23,7 +23,6 @@
</div>
<%= button_to "/", method: :delete, id: "remove-shared-confirm", class: "btn btn-danger my-1 btn-del-room" do %>
<%= hidden_field_tag :user_id, current_user.id %>
<%= t("modal.remove_shared.delete") %>
<% end %>

View File

@ -128,6 +128,9 @@ module Greenlight
config.report_issue_url = ENV["REPORT_ISSUE_URL"]
config.help_url = ENV["HELP_URL"].nil? ? "https://docs.bigbluebutton.org/greenlight/gl-overview.html" : ENV["HELP_URL"]
# File types allowed in preupload presentation
config.allowed_file_types = ".doc,.docx,.pptx,.pdf"
# DEFAULTS
# Default branding image if the user does not specify one
@ -157,6 +160,12 @@ module Greenlight
# Allow users to share rooms by default
config.shared_access_default = "true"
# Don't require recording consent by default
config.require_consent_default = "false"
# Don't allow users to preupload presentations by default
config.preupload_presentation_default = "false"
# Default admin password
config.admin_password_default = ENV['ADMIN_PASSWORD'] || 'administrator'
end

View File

@ -61,7 +61,13 @@ Rails.application.configure do
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
# Store uploaded files on the local file system (see config/storage.yml for options)
config.active_storage.service = :local
config.active_storage.service = if ENV["AWS_ACCESS_KEY_ID"].present?
:amazon
elsif ENV["GCS_PRIVATE_KEY_ID"].present?
:google
else
:local
end
# Mount Action Cable outside main process or domain
# config.action_cable.mount_path = nil

View File

@ -36,7 +36,7 @@ en:
enabled: Enabled
info: Only allow authenticated users to join a room
title: Require Authentication for Rooms
user-info: You must sign in to Greenlight to join this room
user-info: You must sign in above to join this room.
branding:
change: Change Image
info: Change the branding image that appears in the top left corner
@ -45,9 +45,9 @@ en:
invalid: Invalid URL
legal:
change: Change URL
info: Change the Legal Link that appears in the bottom of the page
placeholder: Legal URL...
title: Legal
info: Change the Terms Link that appears in the bottom of the page
placeholder: Terms URL...
title: Terms
invalid: Invalid URL
privpolicy:
change: Change URL
@ -82,6 +82,18 @@ en:
info: Set the default recording visbility for new recordings
title: Recording Default Visibility
warning: This setting will only be applied to rooms that aren't running
require_consent:
info: This setting enables a room setting that allows room owners to specify which rooms can be recorded. Users joining a recorded room must consent before joining.
title: Require Room Owner and Joiner Consent to Recording
maintenance_banner:
info: Displays a Banner to inform the user of a scheduled maintenance
title: Maintenance Banner
display: Set
clear: Clear
time: "Example: Update scheduled on December 13 @ 23:00 ET. Users may experience problems signing in."
preupload:
info: Users can preupload a presentation to be used as the default presentation for that specific room
title: Allow Users to Preupload Presentations
registration:
info: Change the way that users register to the website
title: Registration Method
@ -96,6 +108,10 @@ en:
info: Setting to disabled will remove the button from the Room options dropdown, preventing users from sharing rooms
title: Allow Users to Share Rooms
subtitle: Customize Greenlight
tabs:
appearance: Appearance
administration: Administration
settings: Settings
title: Site Settings
flash:
approved: User has been successfully approved.
@ -150,6 +166,8 @@ en:
info: Allows any user to start the meeting at any time. By default, only the room owner can start the meeting.
all_moderator:
info: Gives all users moderator privileges in BigBlueButton when they join the meeting.
recordings:
info: Allows room owners to specify whether they want the option to record a room or not. If enabled, the moderator must still click the "Record" button once the meeting has started.
options:
disabled: Disabled
enabled: Always Enabled
@ -261,7 +279,7 @@ en:
designs: Custom Designs
authentication: User Authentication
footer:
legal: Legal
legal: Terms
privpolicy: Privacy Policy
powered_by: Powered by %{href}.
forgot_password:
@ -393,6 +411,14 @@ en:
or: or
with: Sign in with %{provider}
forgot_password: Forgot Password?
preupload:
change: Replace Presentation
choose: Choose a file (%{type})
current: "Current Presentation:"
footer: Depending on the size of the presentation, it may require additional time to upload before it can be used.
invalid: Invalid size/file type. Please see the restrictions below.
title: Add Presentation
use: Use Presentation
rename_recording:
remove_shared:
title: Are you sure you want to remove this room from your room list?
@ -407,6 +433,7 @@ en:
require_approval: Require moderator approval before joining
start: Allow any user to start this meeting
footer_text: Adjustment to your room can be done at anytime.
recording: Allow room to be recorded
rename_room:
name_placeholder: Enter a new room name...
share_access:
@ -501,6 +528,7 @@ en:
user: User
room:
access_code_required: Please enter a valid access code to join the room
add_presentation: Add Presentation
create_room: Create a Room
create_room_error: There was an error creating the room
create_room_success: Room created successfully
@ -510,7 +538,9 @@ en:
fail: Failed to delete room (%{error})
enter_the_access_code: Enter the room's access code
invalid_provider: You have entered an invalid url. Please check the url and try again.
invitation_description: You have been invited to join %{name} using BigBlueButton. To join, click the link above and enter your name.
invited: You have been invited to join
recording_present: The session is going to be recorded. This may include voice and video from your side.
invite_participants: Invite Participants
join: Join
last_session: Last session on %{session}
@ -527,6 +557,10 @@ en:
recent_rooms: Go To a Recently Joined Room
title: Join a Room
no_sessions: This room has no sessions, yet!
preupload_success: Successfully added presentation
preupload_error: There was an error updating the room presentation
preupload_remove_success: Successfully removed presentation
preupload_remove_error: There was an error removing the room presentation
recordings: Room Recordings
room_limit: You have reached the maximum number of rooms allowed
room_limit_exceeded: You have exceeded the number of rooms allowed. Please delete %{difference} room(s) to access this room.

View File

@ -122,6 +122,9 @@ Rails.application.routes.draw do
patch '/', to: 'rooms#update', as: :update_room
get '/room_settings', to: 'rooms#room_settings'
post '/update_settings', to: 'rooms#update_settings'
get '/current_presentation', to: 'rooms#current_presentation'
post '/preupload_presentation', to: 'rooms#preupload_presentation'
post '/remove_presentation', to: 'rooms#remove_presentation'
post '/update_shared_access', to: 'rooms#shared_access', as: :room_shared_access
delete '/remove_shared_access', to: 'rooms#remove_shared_access', as: :room_remove_shared_access
get '/shared_users', to: 'rooms#shared_users', as: :room_shared_users

View File

@ -7,19 +7,29 @@ local:
root: <%= Rails.root.join("storage") %>
# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
# amazon:
# service: S3
# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
# region: us-east-1
# bucket: your_own_bucket
amazon:
service: S3
access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
region: <%= ENV['AWS_REGION'] %>
bucket: <%= ENV['AWS_BUCKET'] %>
# Remember not to checkin your GCS keyfile to a repository
# google:
# service: GCS
# project: your_project
# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
# bucket: your_own_bucket
google:
service: GCS
project: "<%= ENV['GCS_PROJECT'] %>"
bucket: "<%= ENV['GCS_BUCKET'] %>"
credentials:
type: 'service_account'
project_id: "<%= ENV['GCS_PROJECT_ID'] %>"
private_key_id: "<%= ENV['GCS_PRIVATE_KEY_ID'] %>"
private_key: "<%= ENV['GCS_PRIVATE_KEY']&.lines&.join("\\n") %>"
client_email: "<%= ENV['GCS_CLIENT_EMAIL'] %>"
client_id: "<%= ENV['GCS_CLIENT_ID'] %>"
auth_uri: 'https://accounts.google.com/o/oauth2/auth'
token_uri: 'https://accounts.google.com/o/oauth2/token'
auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs'
client_x509_cert_url: "<%= ENV['GCS_CLIENT_CERT'] %>"
# Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
# microsoft:

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
# This migration comes from active_storage (originally 20170806125915)
class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
def change
create_table :active_storage_blobs do |t|
t.string :key, null: false
t.string :filename, null: false
t.string :content_type
t.text :metadata
t.bigint :byte_size, null: false
t.string :checksum, null: false
t.datetime :created_at, null: false
t.index [:key], unique: true
end
create_table :active_storage_attachments do |t|
t.string :name, null: false
t.references :record, null: false, polymorphic: true, index: false
t.references :blob, null: false
t.datetime :created_at, null: false
t.index [:record_type, :record_id, :name, :blob_id], name: "index_active_storage_attachments_uniqueness", unique: true
t.foreign_key :active_storage_blobs, column: :blob_id
end
end
end

View File

@ -10,7 +10,28 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2020_04_13_150518) do
ActiveRecord::Schema.define(version: 2020_06_15_190507) do
create_table "active_storage_attachments", force: :cascade do |t|
t.string "name", null: false
t.string "record_type", null: false
t.integer "record_id", null: false
t.integer "blob_id", null: false
t.datetime "created_at", null: false
t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
end
create_table "active_storage_blobs", force: :cascade do |t|
t.string "key", null: false
t.string "filename", null: false
t.string "content_type"
t.text "metadata"
t.bigint "byte_size", null: false
t.string "checksum", null: false
t.datetime "created_at", null: false
t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
end
create_table "features", force: :cascade do |t|
t.integer "setting_id"

View File

@ -17,6 +17,7 @@ services:
# tag: $LOG_TAG
volumes:
- ./log:/usr/src/app/log
- ./storage:/usr/src/app/storage
# When using sqlite3 as the database
# - ./db/production:/usr/src/app/db/production
# When using postgresql as the database

View File

@ -24,3 +24,10 @@ location /b/cable {
client_body_timeout 6h;
send_timeout 6h;
}
# Only needed if using presentations and deployed at a relative root (ex "/b")
# If deploying at "/", delete the section below
location /rails/active_storage {
return 301 /b$request_uri;
}

View File

@ -80,6 +80,20 @@ a {
}
}
.nav-tabs .nav-link{
&.active {
border-color: $primary-color !important;
}
&:not(.active){
color: #9aa0ac !important;
&:hover:not(.disabled) {
border-color: $primary-color;
color: $primary-color !important;
}
}
}
.dropdown-item {
color: #6e7687 !important;
&:hover {

View File

@ -33,4 +33,18 @@ namespace :room do
end
end
end
task four: :environment do
Room.all.each do |room|
next if room.uid.split("-").length > 3
begin
new_uid = room.uid + "-" + SecureRandom.alphanumeric(3).downcase
puts "Updating #{room.uid} to #{new_uid}"
room.update_attributes(uid: new_uid)
rescue => e
puts "Failed to update #{room.uid} to #{new_uid} - #{e}"
end
end
end
end

View File

@ -47,7 +47,7 @@ namespace :user do
user.set_role(u[:role])
puts "Account succesfully created."
puts "Account successfully created."
puts "Email: #{u[:email]}"
puts "Password: #{u[:password]}"
puts "Role: #{u[:role]}"

View File

@ -156,7 +156,8 @@ RELATIVE_URL_ROOT=/b
# require-moderator-approval: Require moderators to approve new users before they can join the room
# anyone-can-start: Allows anyone with the join url to start the room in BigBlueButton
# all-join-moderator: All users join as moderators in BigBlueButton
ROOM_FEATURES=mute-on-join,require-moderator-approval,anyone-can-start,all-join-moderator
# recording: Sessions are recorded
ROOM_FEATURES=mute-on-join,require-moderator-approval,anyone-can-start,all-join-moderator,recording
# Specify the maximum number of records to be sent to the BigBlueButton API in one call
# Default is set to 25 records
@ -258,3 +259,24 @@ DB_PASSWORD=password
# invite - For invite only registration
# approval - For approve/decline registration
DEFAULT_REGISTRATION=open
# Preupload Presentation Storage
#
# By default, if Preupload Presentation is enabled for rooms, presentations are uploaded locally to ~/greenlight/storage
# If you prefer to use AWS S3 or GCS Storage, you can set the variables below
#
# For AWS S3:
# AWS_ACCESS_KEY_ID=
# AWS_SECRET_ACCESS_KEY=
# AWS_REGION=
# AWS_BUCKET=
#
# For GCS Storage:
# GCS_PROJECT_ID=
# GCS_PRIVATE_KEY_ID=
# GCS_PRIVATE_KEY=
# GCS_CLIENT_EMAIL=
# GCS_CLIENT_ID=
# GCS_CLIENT_CERT=
# GCS_PROJECT=
# GCS_BUCKET=

View File

@ -50,7 +50,7 @@ if [ -z $CD_REF_NAME ]; then
export CD_REF_NAME=$(git branch | grep \* | cut -d ' ' -f2)
fi
if [ "$CD_REF_NAME" != "master" ] && [[ "$CD_REF_NAME" != *"release"* ]] && ( [ -z "$CD_BUILD_ALL" ] || [ "$CD_BUILD_ALL" != "true" ] ); then
if [ "$CD_REF_NAME" != "master" ] && [[ "$CD_REF_NAME" != *"release"* ]] && [[ "$CD_REF_NAME" != *"alpha"* ]] && ( [ -z "$CD_BUILD_ALL" ] || [ "$CD_BUILD_ALL" != "true" ] ); then
echo "#### Docker image for $CD_REF_SLUG:$CD_REF_NAME won't be built"
exit 0
fi

View File

@ -290,12 +290,12 @@ describe AdminsController, type: :controller do
@request.session[:user_id] = @admin.id
fake_image_url = "example.com"
post :update_settings, params: { setting: "Branding Image", value: fake_image_url }
post :update_settings, params: { setting: "Branding Image", value: fake_image_url, tab: "appearance" }
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Branding Image")
expect(feature[:value]).to eq(fake_image_url)
expect(response).to redirect_to(admin_site_settings_path)
expect(response).to redirect_to(admin_site_settings_path(tab: "appearance"))
end
end
@ -307,12 +307,12 @@ describe AdminsController, type: :controller do
@request.session[:user_id] = @admin.id
fake_url = "example.com"
post :update_settings, params: { setting: "Legal URL", value: fake_url }
post :update_settings, params: { setting: "Legal URL", value: fake_url, tab: "administration" }
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Legal URL")
expect(feature[:value]).to eq(fake_url)
expect(response).to redirect_to(admin_site_settings_path)
expect(response).to redirect_to(admin_site_settings_path(tab: "administration"))
end
end
@ -324,12 +324,12 @@ describe AdminsController, type: :controller do
@request.session[:user_id] = @admin.id
fake_url = "example.com"
post :update_settings, params: { setting: "Privacy Policy URL", value: fake_url }
post :update_settings, params: { setting: "Privacy Policy URL", value: fake_url, tab: "administration" }
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Privacy Policy URL")
expect(feature[:value]).to eq(fake_url)
expect(response).to redirect_to(admin_site_settings_path)
expect(response).to redirect_to(admin_site_settings_path(tab: "administration"))
end
end
@ -346,7 +346,7 @@ describe AdminsController, type: :controller do
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Primary Color")
expect(feature[:value]).to eq(primary_color)
expect(response).to redirect_to(admin_site_settings_path)
expect(response).to redirect_to(admin_site_settings_path(tab: "appearance"))
end
it "changes the primary-lighten on the page" do
@ -356,12 +356,12 @@ describe AdminsController, type: :controller do
@request.session[:user_id] = @admin.id
primary_color = Faker::Color.hex_color
post :update_settings, params: { setting: "Primary Color Lighten", value: primary_color }
post :update_settings, params: { setting: "Primary Color Lighten", value: primary_color, tab: "appearance" }
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Primary Color Lighten")
expect(feature[:value]).to eq(primary_color)
expect(response).to redirect_to(admin_site_settings_path)
expect(response).to redirect_to(admin_site_settings_path(tab: "appearance"))
end
it "changes the primary-darken on the page" do
@ -371,12 +371,12 @@ describe AdminsController, type: :controller do
@request.session[:user_id] = @admin.id
primary_color = Faker::Color.hex_color
post :update_settings, params: { setting: "Primary Color Darken", value: primary_color }
post :update_settings, params: { setting: "Primary Color Darken", value: primary_color, tab: "appearance" }
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Primary Color Darken")
expect(feature[:value]).to eq(primary_color)
expect(response).to redirect_to(admin_site_settings_path)
expect(response).to redirect_to(admin_site_settings_path(tab: "appearance"))
end
end
end
@ -396,7 +396,7 @@ describe AdminsController, type: :controller do
expect(feature[:value]).to eq(Rails.configuration.registration_methods[:invite])
expect(flash[:success]).to be_present
expect(response).to redirect_to(admin_site_settings_path)
expect(response).to redirect_to(admin_site_settings_path(tab: "settings"))
end
it "does not allow the user to change to invite if emails are off" do
@ -409,7 +409,7 @@ describe AdminsController, type: :controller do
post :registration_method, params: { value: "invite" }
expect(flash[:alert]).to be_present
expect(response).to redirect_to(admin_site_settings_path)
expect(response).to redirect_to(admin_site_settings_path(tab: "settings"))
end
end
@ -425,7 +425,7 @@ describe AdminsController, type: :controller do
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Room Authentication")
expect(feature[:value]).to eq("true")
expect(response).to redirect_to(admin_site_settings_path)
expect(response).to redirect_to(admin_site_settings_path(tab: "settings"))
end
end
@ -441,7 +441,7 @@ describe AdminsController, type: :controller do
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Room Limit")
expect(feature[:value]).to eq("5")
expect(response).to redirect_to(admin_site_settings_path)
expect(response).to redirect_to(admin_site_settings_path(tab: "settings"))
end
end
@ -457,7 +457,25 @@ describe AdminsController, type: :controller do
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Default Recording Visibility")
expect(feature[:value]).to eq("public")
expect(response).to redirect_to(admin_site_settings_path)
expect(response).to redirect_to(admin_site_settings_path(tab: "settings"))
end
end
context "POST #maintenance_banner" do
it "displays a banner with the maintenance string" do
allow(Rails.configuration).to receive(:loadbalanced_configuration).and_return(true)
allow_any_instance_of(User).to receive(:greenlight_account?).and_return(true)
@request.session[:user_id] = @admin.id
fake_banner_string = "Maintenance work at 2 pm"
post :update_settings, params: { setting: "Maintenance Banner", value: fake_banner_string, tab: "administration" }
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Maintenance Banner")
expect(flash[:success]).to be_present
expect(feature[:value]).to eq(fake_banner_string)
expect(response).to redirect_to(admin_site_settings_path(tab: "administration"))
end
end
@ -473,7 +491,7 @@ describe AdminsController, type: :controller do
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Shared Access")
expect(feature[:value]).to eq("false")
expect(response).to redirect_to(admin_site_settings_path)
expect(response).to redirect_to(admin_site_settings_path(tab: "settings"))
end
end
@ -537,7 +555,7 @@ describe AdminsController, type: :controller do
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Shared Access")
expect(feature[:value]).to eq("false")
expect(response).to redirect_to(admin_site_settings_path)
expect(response).to redirect_to(admin_site_settings_path(tab: "settings"))
end
it "doesn't allow a user with the incorrect permission to edit site settings" do

View File

@ -185,7 +185,7 @@ describe RoomsController, type: :controller do
room_params = { name: name, "mute_on_join": "1",
"require_moderator_approval": "1", "anyone_can_start": "1", "all_join_moderator": "1" }
json_room_settings = "{\"muteOnStart\":true,\"requireModeratorApproval\":true," \
"\"anyoneCanStart\":true,\"joinModerator\":true}"
"\"anyoneCanStart\":true,\"joinModerator\":true,\"recording\":false}"
post :create, params: { room: room_params }
@ -202,8 +202,10 @@ describe RoomsController, type: :controller do
@owner.main_room.update_attribute(:room_settings, { "muteOnStart": true, "requireModeratorApproval": true,
"anyoneCanStart": true, "joinModerator": true }.to_json)
json_room_settings = "{\"muteOnStart\":true,\"requireModeratorApproval\":true," \
"\"anyoneCanStart\":true,\"joinModerator\":true}"
json_room_settings = { "anyoneCanStart" => true,
"joinModerator" => true,
"muteOnStart" => true,
"requireModeratorApproval" => true }
get :room_settings, params: { room_uid: @owner.main_room }, format: :json
@ -571,7 +573,7 @@ describe RoomsController, type: :controller do
it "properly updates room name through the room settings modal and redirects to current page" do
@request.session[:user_id] = @user.id
name = Faker::Games::Pokemon.name
name = Faker::Name.first_name
room_params = { room_uid: @secondary_room.uid, room: { "name": name } }
@ -583,9 +585,9 @@ describe RoomsController, type: :controller do
it "properly updates room settings through the room settings modal and redirects to current page" do
@request.session[:user_id] = @user.id
room_params = { "mute_on_join": "1", "name": @secondary_room.name }
room_params = { "mute_on_join": "1", "name": @secondary_room.name, "recording": "1" }
formatted_room_params = "{\"muteOnStart\":true,\"requireModeratorApproval\":false," \
"\"anyoneCanStart\":false,\"joinModerator\":false}" # JSON string format
"\"anyoneCanStart\":false,\"joinModerator\":false,\"recording\":true}" # JSON string format
expect { post :update_settings, params: { room_uid: @secondary_room.uid, room: room_params } }
.to change { @secondary_room.reload.room_settings }
@ -608,7 +610,7 @@ describe RoomsController, type: :controller do
room_params = { "mute_on_join": "1", "name": @secondary_room.name }
formatted_room_params = "{\"muteOnStart\":true,\"requireModeratorApproval\":false," \
"\"anyoneCanStart\":false,\"joinModerator\":false}" # JSON string format
"\"anyoneCanStart\":false,\"joinModerator\":false,\"recording\":false}" # JSON string format
expect { post :update_settings, params: { room_uid: @secondary_room.uid, room: room_params } }
.to change { @secondary_room.reload.room_settings }
@ -814,4 +816,107 @@ describe RoomsController, type: :controller do
expect(response).to redirect_to root_path
end
end
describe "POST #preupload_presentation" do
before do
@user = create(:user)
@file = fixture_file_upload('files/sample.pdf', 'application/pdf')
@invalid_file = fixture_file_upload('files/invalid.jpg', 'image/jpg')
allow(Rails.configuration).to receive(:preupload_presentation_default).and_return("true")
end
it "adds a presentation to the room" do
@request.session[:user_id] = @user.id
post :preupload_presentation, params: { room_uid: @user.main_room, room: { presentation: @file } }
expect(@user.main_room.presentation.attached?).to be true
expect(flash[:success]).to be_present
expect(response).to redirect_to @user.main_room
end
it "rejects file types that are not allowed" do
@request.session[:user_id] = @user.id
post :preupload_presentation, params: { room_uid: @user.main_room, room: { presentation: @invalid_file } }
expect(@user.main_room.presentation.attached?).to be false
expect(flash[:alert]).to be_present
expect(response).to redirect_to @user.main_room
end
it "allows admins to add a presentation to the room" do
allow_any_instance_of(User).to receive(:admin_of?).and_return(true)
@admin = create(:user)
@admin.set_role :admin
@request.session[:user_id] = @admin.id
post :preupload_presentation, params: { room_uid: @user.main_room, room: { presentation: @file } }
expect(@user.main_room.presentation.attached?).to be true
expect(flash[:success]).to be_present
expect(response).to redirect_to @user.main_room
end
it "redirects to root path if not admin of current user" do
allow_any_instance_of(User).to receive(:admin_of?).and_return(false)
@admin = create(:user)
@admin.set_role :admin
@request.session[:user_id] = @admin.id
post :preupload_presentation, params: { room_uid: @user.main_room, room: { presentation: @file } }
expect(response).to redirect_to(root_path)
end
end
describe "POST #remove_presentation" do
before do
@user = create(:user)
@user.main_room.presentation.attach(fixture_file_upload('files/sample.pdf', 'application/pdf'))
allow(Rails.configuration).to receive(:shared_access_default).and_return("true")
end
it "removes a presentation from a room" do
@request.session[:user_id] = @user.id
expect(@user.main_room.presentation.attached?).to be true
post :remove_presentation, params: { room_uid: @user.main_room }
@user.main_room.reload
expect(@user.main_room.presentation.attached?).to be false
expect(flash[:success]).to be_present
expect(response).to redirect_to @user.main_room
end
it "allows admins to remove a presentation from a room" do
allow_any_instance_of(User).to receive(:admin_of?).and_return(true)
@admin = create(:user)
@admin.set_role :admin
@request.session[:user_id] = @admin.id
expect(@user.main_room.presentation.attached?).to be true
post :remove_presentation, params: { room_uid: @user.main_room }
@user.main_room.reload
expect(@user.main_room.presentation.attached?).to be false
expect(flash[:success]).to be_present
expect(response).to redirect_to @user.main_room
end
it "redirects to root path if not admin of current user" do
allow_any_instance_of(User).to receive(:admin_of?).and_return(false)
@admin = create(:user)
@admin.set_role :admin
@request.session[:user_id] = @admin.id
post :preupload_presentation, params: { room_uid: @user.main_room, room: { presentation: @file } }
expect(response).to redirect_to(root_path)
end
end
end

BIN
spec/fixtures/files/invalid.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

198
spec/fixtures/files/sample.pdf vendored Normal file
View File

@ -0,0 +1,198 @@
%PDF-1.3
%âãÏÓ
1 0 obj
<<
/Type /Catalog
/Outlines 2 0 R
/Pages 3 0 R
>>
endobj
2 0 obj
<<
/Type /Outlines
/Count 0
>>
endobj
3 0 obj
<<
/Type /Pages
/Count 2
/Kids [ 4 0 R 6 0 R ]
>>
endobj
4 0 obj
<<
/Type /Page
/Parent 3 0 R
/Resources <<
/Font <<
/F1 9 0 R
>>
/ProcSet 8 0 R
>>
/MediaBox [0 0 612.0000 792.0000]
/Contents 5 0 R
>>
endobj
5 0 obj
<< /Length 1074 >>
stream
2 J
BT
0 0 0 rg
/F1 0027 Tf
57.3750 722.2800 Td
( A Simple PDF File ) Tj
ET
BT
/F1 0010 Tf
69.2500 688.6080 Td
( This is a small demonstration .pdf file - ) Tj
ET
BT
/F1 0010 Tf
69.2500 664.7040 Td
( just for use in the Virtual Mechanics tutorials. More text. And more ) Tj
ET
BT
/F1 0010 Tf
69.2500 652.7520 Td
( text. And more text. And more text. And more text. ) Tj
ET
BT
/F1 0010 Tf
69.2500 628.8480 Td
( And more text. And more text. And more text. And more text. And more ) Tj
ET
BT
/F1 0010 Tf
69.2500 616.8960 Td
( text. And more text. Boring, zzzzz. And more text. And more text. And ) Tj
ET
BT
/F1 0010 Tf
69.2500 604.9440 Td
( more text. And more text. And more text. And more text. And more text. ) Tj
ET
BT
/F1 0010 Tf
69.2500 592.9920 Td
( And more text. And more text. ) Tj
ET
BT
/F1 0010 Tf
69.2500 569.0880 Td
( And more text. And more text. And more text. And more text. And more ) Tj
ET
BT
/F1 0010 Tf
69.2500 557.1360 Td
( text. And more text. And more text. Even more. Continued on page 2 ...) Tj
ET
endstream
endobj
6 0 obj
<<
/Type /Page
/Parent 3 0 R
/Resources <<
/Font <<
/F1 9 0 R
>>
/ProcSet 8 0 R
>>
/MediaBox [0 0 612.0000 792.0000]
/Contents 7 0 R
>>
endobj
7 0 obj
<< /Length 676 >>
stream
2 J
BT
0 0 0 rg
/F1 0027 Tf
57.3750 722.2800 Td
( Simple PDF File 2 ) Tj
ET
BT
/F1 0010 Tf
69.2500 688.6080 Td
( ...continued from page 1. Yet more text. And more text. And more text. ) Tj
ET
BT
/F1 0010 Tf
69.2500 676.6560 Td
( And more text. And more text. And more text. And more text. And more ) Tj
ET
BT
/F1 0010 Tf
69.2500 664.7040 Td
( text. Oh, how boring typing this stuff. But not as boring as watching ) Tj
ET
BT
/F1 0010 Tf
69.2500 652.7520 Td
( paint dry. And more text. And more text. And more text. And more text. ) Tj
ET
BT
/F1 0010 Tf
69.2500 640.8000 Td
( Boring. More, a little more text. The end, and just as well. ) Tj
ET
endstream
endobj
8 0 obj
[/PDF /Text]
endobj
9 0 obj
<<
/Type /Font
/Subtype /Type1
/Name /F1
/BaseFont /Helvetica
/Encoding /WinAnsiEncoding
>>
endobj
10 0 obj
<<
/Creator (Rave \(http://www.nevrona.com/rave\))
/Producer (Nevrona Designs)
/CreationDate (D:20060301072826)
>>
endobj
xref
0 11
0000000000 65535 f
0000000019 00000 n
0000000093 00000 n
0000000147 00000 n
0000000222 00000 n
0000000390 00000 n
0000001522 00000 n
0000001690 00000 n
0000002423 00000 n
0000002456 00000 n
0000002574 00000 n
trailer
<<
/Size 11
/Root 1 0 R
/Info 10 0 R
>>
startxref
2714
%%EOF