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/assets/**
/public/b/** /public/b/**
# Ignore uploaded files
/storage
# Ignore production paths. # Ignore production paths.
/db/production /db/production
/db/production-postgres /db/production-postgres

View File

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

View File

@ -6,6 +6,20 @@ GIT
tabler-rubygem (0.1.4.1) tabler-rubygem (0.1.4.1)
autoprefixer-rails (>= 6.0.3) 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 GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
@ -58,9 +72,23 @@ GEM
ast (2.4.0) ast (2.4.0)
autoprefixer-rails (9.7.6) autoprefixer-rails (9.7.6)
execjs 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) bcrypt (3.1.13)
bigbluebutton-api-ruby (1.7.0)
xml-simple (~> 1.1)
bindex (0.8.1) bindex (0.8.1)
bn-ldap-authentication (0.1.4) bn-ldap-authentication (0.1.4)
net-ldap (~> 0) net-ldap (~> 0)
@ -73,6 +101,7 @@ GEM
builder (3.2.4) builder (3.2.4)
byebug (11.1.3) byebug (11.1.3)
cancancan (2.3.0) cancancan (2.3.0)
childprocess (4.0.0)
coffee-rails (4.2.2) coffee-rails (4.2.2)
coffee-script (>= 2.2.0) coffee-script (>= 2.2.0)
railties (>= 4.0.0) railties (>= 4.0.0)
@ -90,7 +119,11 @@ GEM
crack (0.4.3) crack (0.4.3)
safe_yaml (~> 1.0.0) safe_yaml (~> 1.0.0)
crass (1.0.6) crass (1.0.6)
declarative (0.0.20)
declarative-option (0.1.0)
diff-lcs (1.3) diff-lcs (1.3)
digest-crc (0.6.1)
rake (~> 13.0)
docile (1.3.2) docile (1.3.2)
dotenv (2.7.5) dotenv (2.7.5)
dotenv-rails (2.7.5) dotenv-rails (2.7.5)
@ -112,16 +145,46 @@ GEM
sassc (>= 1.11) sassc (>= 1.11)
globalid (0.4.2) globalid (0.4.2)
activesupport (>= 4.2.0) 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) hashdiff (1.0.1)
hashie (4.1.0) hashie (4.1.0)
hiredis (0.6.3) hiredis (0.6.3)
http_accept_language (2.1.1) http_accept_language (2.1.1)
httpclient (2.8.3)
i18n (1.8.2) i18n (1.8.2)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
i18n-language-mapping (0.1.2) i18n-language-mapping (0.1.2)
jbuilder (2.10.0) jbuilder (2.10.0)
activesupport (>= 5.0.0) activesupport (>= 5.0.0)
jquery-rails (4.3.5) jmespath (1.4.0)
jquery-rails (4.4.0)
rails-dom-testing (>= 1, < 3) rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0) railties (>= 4.2.0)
thor (>= 0.14, < 2.0) thor (>= 0.14, < 2.0)
@ -144,6 +207,7 @@ GEM
mini_mime (>= 0.1.1) mini_mime (>= 0.1.1)
marcel (0.3.3) marcel (0.3.3)
mimemagic (~> 0.3.2) mimemagic (~> 0.3.2)
memoist (0.16.2)
method_source (1.0.0) method_source (1.0.0)
mimemagic (0.3.5) mimemagic (0.3.5)
mini_mime (1.0.2) mini_mime (1.0.2)
@ -186,6 +250,7 @@ GEM
omniauth-twitter (1.4.0) omniauth-twitter (1.4.0)
omniauth-oauth (~> 1.1) omniauth-oauth (~> 1.1)
rack rack
os (1.1.0)
pagy (3.8.1) pagy (3.8.1)
parallel (1.19.1) parallel (1.19.1)
parser (2.7.1.3) parser (2.7.1.3)
@ -194,7 +259,7 @@ GEM
popper_js (1.16.0) popper_js (1.16.0)
public_suffix (4.0.5) public_suffix (4.0.5)
puma (3.12.6) puma (3.12.6)
rack (2.2.2) rack (2.2.3)
rack-test (1.1.0) rack-test (1.1.0)
rack (>= 1.0, < 3) rack (>= 1.0, < 3)
rails (5.2.4.3) rails (5.2.4.3)
@ -237,8 +302,13 @@ GEM
redis (4.1.4) redis (4.1.4)
remote_syslog_logger (1.0.4) remote_syslog_logger (1.0.4)
syslog_protocol syslog_protocol
representable (3.0.4)
declarative (< 0.1.0)
declarative-option (< 0.2.0)
uber (< 0.2.0)
request_store (1.5.0) request_store (1.5.0)
rack (>= 1.4) rack (>= 1.4)
retriable (3.1.2)
rexml (3.2.4) rexml (3.2.4)
rspec-core (3.9.2) rspec-core (3.9.2)
rspec-support (~> 3.9.3) rspec-support (~> 3.9.3)
@ -268,6 +338,7 @@ GEM
rubocop-ast (0.0.3) rubocop-ast (0.0.3)
parser (>= 2.7.0.1) parser (>= 2.7.0.1)
ruby-progressbar (1.10.1) ruby-progressbar (1.10.1)
rubyzip (2.3.0)
safe_yaml (1.0.5) safe_yaml (1.0.5)
sassc (2.3.0) sassc (2.3.0)
ffi (~> 1.9) ffi (~> 1.9)
@ -280,6 +351,11 @@ GEM
sequel (5.32.0) sequel (5.32.0)
shoulda-matchers (3.1.3) shoulda-matchers (3.1.3)
activesupport (>= 4.0.0) 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) simplecov (0.16.1)
docile (~> 1.1) docile (~> 1.1)
json (>= 1.8, < 3) json (>= 1.8, < 3)
@ -313,6 +389,7 @@ GEM
thread_safe (~> 0.1) thread_safe (~> 0.1)
tzinfo-data (1.2020.1) tzinfo-data (1.2020.1)
tzinfo (>= 1.0.0) tzinfo (>= 1.0.0)
uber (0.1.0)
uglifier (4.2.0) uglifier (4.2.0)
execjs (>= 0.3.0, < 3) execjs (>= 0.3.0, < 3)
unicode-display_width (1.7.0) unicode-display_width (1.7.0)
@ -335,8 +412,9 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
action-cable-testing action-cable-testing
aws-sdk-s3 (~> 1.75)
bcrypt (~> 3.1.7) bcrypt (~> 3.1.7)
bigbluebutton-api-ruby bigbluebutton-api-ruby!
bn-ldap-authentication (~> 0.1.4) bn-ldap-authentication (~> 0.1.4)
bootsnap (>= 1.1.0) bootsnap (>= 1.1.0)
bootstrap (~> 4.3.1) bootstrap (~> 4.3.1)
@ -348,11 +426,12 @@ DEPENDENCIES
factory_bot_rails factory_bot_rails
faker faker
font-awesome-sass (~> 5.9.0) font-awesome-sass (~> 5.9.0)
google-cloud-storage (~> 1.26)
hiredis hiredis
http_accept_language http_accept_language
i18n-language-mapping (~> 0.1.1) i18n-language-mapping (~> 0.1.1)
jbuilder (~> 2.5) jbuilder (~> 2.5)
jquery-rails (~> 4.3.3) jquery-rails (~> 4.4)
jquery-ui-rails jquery-ui-rails
listen (~> 3.0.5) listen (~> 3.0.5)
lograge 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"){ 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() loadColourSelectors()
} }
}
else if (action == "roles"){ else if (action == "roles"){
// Refreshes the new role modal // Refreshes the new role modal
$("#newRoleButton").click(function(){ $("#newRoleButton").click(function(){
@ -119,19 +123,30 @@ $(document).on('turbolinks:load', function(){
// Change the branding image to the image provided // Change the branding image to the image provided
function changeBrandingImage(path) { function changeBrandingImage(path) {
var url = $("#branding-url").val() var url = $("#branding-url").val()
$.post(path, {value: url}) $.post(path, {value: url, tab: "appearance"})
} }
// Change the Legal URL to the one provided // Change the Legal URL to the one provided
function changeLegalURL(path) { function changeLegalURL(path) {
var url = $("#legal-url").val() var url = $("#legal-url").val()
$.post(path, {value: url}) $.post(path, {value: url, tab: "administration"})
} }
// Change the Privacy Policy URL to the one provided // Change the Privacy Policy URL to the one provided
function changePrivacyPolicyURL(path) { function changePrivacyPolicyURL(path) {
var url = $("#privpolicy-url").val() 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() { function mergeUsers() {
@ -234,13 +249,13 @@ function loadColourSelectors() {
}) })
pickrLighten.on("save", (color, instance) => { 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() location.reload()
}); });
}) })
pickrDarken.on("save", (color, instance) => { 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() location.reload()
}); });
}) })

View File

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

View File

@ -26,9 +26,12 @@ $(document).on('turbolinks:load', function(){
}) })
$("#maintenance-close").click(function(event) { $("#maintenance-close").click(function(event) {
//create a cookie that lasts 1 year //create a cookie that lasts 1 day
var cookieDate = new Date();
cookieDate.setFullYear(cookieDate.getFullYear() + 1); //1 year from now 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() + ";" 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(){ $("#create-room-block").click(function(){
showCreateRoom(this) showCreateRoom(this)
}) })
checkIfAutoJoin()
} }
// Autofocus on the Room Name label when creating a room only // Autofocus on the Room Name label when creating a room only
@ -129,6 +131,27 @@ $(document).on('turbolinks:load', function(){
$("#user-list").append(listItem) $("#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) $("#room_access_code").val(null)
$("#createRoomModal form").attr("action", $("body").data('relative-root')) $("#createRoomModal form").attr("action", $("body").data('relative-root'))
$("#room_mute_on_join").prop("checked", $("#room_mute_on_join").data("default")) $("#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_require_moderator_approval").prop("checked", $("#room_require_moderator_approval").data("default"))
$("#room_anyone_can_start").prop("checked", $("#room_anyone_can_start").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_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 //show all elements & their children with a create-only class
$(".create-only").each(function() { $(".create-only").each(function() {
@ -197,12 +220,12 @@ function showDeleteRoom(target) {
//Update the createRoomModal to show the correct current settings //Update the createRoomModal to show the correct current settings
function updateCurrentSettings(settings_path){ function updateCurrentSettings(settings_path){
// Get current room settings and set checkbox // Get current room settings and set checkbox
$.get(settings_path, function(room_settings) { $.get(settings_path, function(settings) {
var settings = JSON.parse(room_settings)
$("#room_mute_on_join").prop("checked", $("#room_mute_on_join").data("default") || settings.muteOnStart) $("#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_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_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_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") 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() { connected: function() {
console.log("connected"); console.log("connected");
setTimeout(startRefreshTimeout, 120000);
}, },
disconnected: function(data) { disconnected: function(data) {
@ -40,7 +41,7 @@ $(document).on("turbolinks:load", function(){
received: function(data){ received: function(data){
console.log(data); console.log(data);
if(data.action = "started"){ if(data.action == "started"){
request_to_join_meeting(); 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; color: white !important;
} }
.manage-users-tab { #manage-users-nav.nav-tabs .nav-item {
&:hover { margin-bottom: -1px;
cursor: pointer;
}
} }
#merge-account-arrow { #merge-account-arrow {
@ -97,3 +95,7 @@
z-index: 999; z-index: 999;
background: white; background: white;
} }
.admin-tabs {
justify-content: space-around;
}

View File

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

View File

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

View File

@ -84,9 +84,9 @@ class ApplicationController < ActionController::Base
help: I18n.t("errors.maintenance.help"), help: I18n.t("errors.maintenance.help"),
} }
end end
if Rails.configuration.maintenance_window.present? if @settings.get_value("Maintenance Banner").present?
unless cookies[:maintenance_window] == Rails.configuration.maintenance_window unless cookies[:maintenance_window] == @settings.get_value("Maintenance Banner")
flash.now[:maintenance] = Rails.configuration.maintenance_window flash.now[:maintenance] = @settings.get_value("Maintenance Banner")
end end
end end
end end
@ -182,6 +182,18 @@ class ApplicationController < ActionController::Base
end end
helper_method :shared_access_allowed 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 # Returns the page that the logo redirects to when clicked on
def home_page def home_page
return admins_path if current_user.has_role? :super_admin 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. # Creates a meeting on the BigBlueButton server.
def start_session(room, options = {}) def start_session(room, options = {})
create_options = { create_options = {
record: options[:meeting_recorded].to_s, record: options[:record].to_s,
logoutURL: options[:meeting_logout_url] || '', logoutURL: options[:meeting_logout_url] || '',
moderatorPW: room.moderator_pw, moderatorPW: room.moderator_pw,
attendeePW: room.attendee_pw, attendeePW: room.attendee_pw,
@ -77,11 +77,17 @@ module BbbServer
# Send the create request. # Send the create request.
begin begin
meeting = bbb_server.create_meeting(room.name, room.bbb_id, create_options) meeting = if room.presentation.attached?
# Update session info. 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' unless meeting[:messageKey] == 'duplicateWarning'
room.update_attributes(sessions: room.sessions + 1, room.update_attributes(sessions: room.sessions + 1, last_session: DateTime.now)
last_session: DateTime.now)
end end
rescue BigBlueButton::BigBlueButtonException => e rescue BigBlueButton::BigBlueButtonException => e
puts "BigBlueButton failed on create: #{e.key}: #{e.message}" puts "BigBlueButton failed on create: #{e.key}: #{e.message}"

View File

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

View File

@ -27,7 +27,7 @@ class RoomsController < ApplicationController
unless: -> { !Rails.configuration.enable_email_verification } unless: -> { !Rails.configuration.enable_email_verification }
before_action :find_room, except: [:create, :join_specific_room, :cant_create_rooms] 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_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_ownership_or_shared, only: [:remove_shared_access]
before_action :verify_room_owner_verified, only: [:show, :join], before_action :verify_room_owner_verified, only: [:show, :join],
unless: -> { !Rails.configuration.enable_email_verification } unless: -> { !Rails.configuration.enable_email_verification }
@ -171,6 +171,7 @@ class RoomsController < ApplicationController
@room_settings = JSON.parse(@room[:room_settings]) @room_settings = JSON.parse(@room[:room_settings])
opts[:mute_on_start] = room_setting_with_config("muteOnStart") opts[:mute_on_start] = room_setting_with_config("muteOnStart")
opts[:require_moderator_approval] = room_setting_with_config("requireModeratorApproval") opts[:require_moderator_approval] = room_setting_with_config("requireModeratorApproval")
opts[:record] = record_meeting
begin begin
redirect_to join_path(@room, current_user.name, opts, current_user.uid) 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) redirect_back fallback_location: room_path(@room)
end 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 # POST /:room_uid/update_shared_access
def shared_access def shared_access
begin begin
@ -240,7 +280,7 @@ class RoomsController < ApplicationController
# POST /:room_uid/remove_shared_access # POST /:room_uid/remove_shared_access
def remove_shared_access def remove_shared_access
begin 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") flash[:success] = I18n.t("room.remove_shared_access_success")
rescue => e rescue => e
logger.error "Support: Error in removing room shared access: #{e}" logger.error "Support: Error in removing room shared access: #{e}"
@ -262,7 +302,7 @@ class RoomsController < ApplicationController
def room_settings def room_settings
# Respond with JSON object of the room_settings # Respond with JSON object of the room_settings
respond_to do |format| respond_to do |format|
format.json { render body: @room.room_settings.to_json } format.json { render body: @room.room_settings }
end end
end end
@ -291,6 +331,7 @@ class RoomsController < ApplicationController
"requireModeratorApproval": options[:require_moderator_approval] == "1", "requireModeratorApproval": options[:require_moderator_approval] == "1",
"anyoneCanStart": options[:anyone_can_start] == "1", "anyoneCanStart": options[:anyone_can_start] == "1",
"joinModerator": options[:all_join_moderator] == "1", "joinModerator": options[:all_join_moderator] == "1",
"recording": options[:recording] == "1",
} }
room_settings.to_json room_settings.to_json
@ -298,7 +339,8 @@ class RoomsController < ApplicationController
def room_params def room_params
params.require(:room).permit(:name, :auto_join, :mute_on_join, :access_code, 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 end
# Find the room from the uid. # Find the room from the uid.
@ -364,4 +406,18 @@ class RoomsController < ApplicationController
current_user.rooms.length >= limit current_user.rooms.length >= limit
end end
helper_method :room_limit_exceeded 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 end

View File

@ -61,6 +61,14 @@ module AdminsHelper
end end
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 def recording_default_visibility_string
if @settings.get_value("Default Recording Visibility") == "public" if @settings.get_value("Default Recording Visibility") == "public"
I18n.t("recording.visibility.public") I18n.t("recording.visibility.public")
@ -80,6 +88,14 @@ module AdminsHelper
end end
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 def log_level_string
case Rails.logger.level case Rails.logger.level
when 0 when 0
@ -97,6 +113,10 @@ module AdminsHelper
end end
end end
def show_log_dropdown
current_user.has_role?(:super_admin) || !Rails.configuration.loadbalanced_configuration
end
def room_limit_number def room_limit_number
@settings.get_value("Room Limit").to_i @settings.get_value("Room Limit").to_i
end end

View File

@ -117,4 +117,11 @@ module ApplicationHelper
rescue rescue
false false
end 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 end

View File

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

View File

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

View File

@ -28,7 +28,7 @@ class Ability
highest_role = user.role highest_role = user.role
if highest_role.get_permission("can_edit_site_settings") if highest_role.get_permission("can_edit_site_settings")
can [:site_settings, :room_configuration, :update_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 end
if highest_role.get_permission("can_edit_roles") if highest_role.get_permission("can_edit_roles")

View File

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

View File

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

View File

@ -13,6 +13,6 @@
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. # 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) %> <%= translated_role_name(role) %>
</button> </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). # 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 # 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 # 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="form-group mt-n3">
<div class="row"> <nav class="row m-0">
<div class="col-12 tags"> <div class="nav col nav-tabs admin-tabs m-0 p-0" id="manage-users-nav" role="tablist">
<span id="active" class="btn btn-sm tag manage-users-tab <%= 'selected' if @tab == 'active' %>"> <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") %> <%= t("roles.active") %>
</span> </a>
<span id="pending" class="btn btn-sm tag manage-users-tab <%= 'selected' if @tab == 'pending' %>"> <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") %> <%= t("roles.pending") %>
</span> </a>
<span id="denied" class="btn btn-sm tag manage-users-tab <%= 'selected' if @tab == 'denied' %>"> <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") %> <%= t("roles.banned") %>
</span> </a>
<span id="deleted" class="btn btn-sm tag manage-users-tab <%= 'selected' if @tab == 'deleted' %>"> <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") %> <%= t("roles.deleted") %>
</span> </a>
</div>
</div> </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> </div>

View File

@ -98,4 +98,31 @@
</div> </div>
</div> </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> </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) %>"> <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") %> <i class="dropdown-icon fas fa-cog"></i> <%= t("room.settings") %>
</a> </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 %> <% 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) %>"> <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") %> <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/>. # with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
%> %>
<div class="form-group"> <div class="form-group mt-n3">
<div class="row"> <nav class="row m-0">
<div class="col-12"> <div class="nav col nav-tabs admin-tabs m-0 p-0" >
<div class="mb-6 form-group"> <a class="nav-item p-3 nav-link <%= 'active' if @tab == 'appearance' %>" href="?tab=appearance" role="tab" aria-selected="true">
<label class="form-label"><%= t("administrator.site_settings.branding.title") %></label> <i class="fas mr-3 fa-palette"></i>
<label class="form-label text-muted"><%= t("administrator.site_settings.branding.info") %></label> <%= t("administrator.site_settings.tabs.appearance") %>
<div class="input-group"> </a>
<input id="branding-url" type="text" class="form-control" value="<%= logo_image %>"> <a class="nav-item p-3 nav-link <%= 'active' if @tab == 'administration' %>" href="?tab=administration" role="tab" aria-selected="false">
<span class="input-group-append"> <i class="fas mr-3 fa-toolbox"></i>
<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> <%= t("administrator.site_settings.tabs.administration") %>
</span> </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> </nav>
</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"> <% if @tab == "appearance"%>
<%= t("administrator.site_settings.color.regular") %> <%= render "admins/components/site_settings/appearance" %>
</div> <% elsif @tab == "administration"%>
<%= render "admins/components/site_settings/administration" %>
<% else %>
<%= render "admins/components/site_settings/settings" %>
<% end %>
<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>
<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/delete_room_modal" %>
<%= render "shared/modals/create_room_modal" %> <%= render "shared/modals/create_room_modal" %>
<% if preupload_allowed? %>
<%= render "shared/modals/preupload_presentation_modal" %>
<% end %>
<% if shared_access_allowed %> <% if shared_access_allowed %>
<%= render "shared/modals/share_room_modal" %> <%= render "shared/modals/share_room_modal" %>
<% end %> <% end %>

View File

@ -28,13 +28,12 @@
</script> </script>
<% end %> <% end %>
<title><%= t("bigbluebutton") %></title> <title><%= yield(:page_title).present? ? yield(:page_title) : t("bigbluebutton") %></title>
<meta property="og:title" content="<%= t("bigbluebutton", locale: :en) %>" /> <meta property="og:title" content="<%= yield(:page_title).present? ? yield(:page_title) : t("bigbluebutton") %>" />
<meta property="og:type" content="website" /> <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:url" content="<%= request.base_url %>" />
<meta property="og:image" content="<%= logo_image %>" /> <meta property="og:image" content="<%= logo_image %>" />
<meta name="viewport" content= "width=device-width, user-scalable=no"> <meta name="viewport" content= "width=device-width, user-scalable=no">
<%= csrf_meta_tags %> <%= csrf_meta_tags %>
@ -48,6 +47,8 @@
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= favicon_link_tag asset_path('favicon.ico') %>
<!-- Primary color styling --> <!-- Primary color styling -->
<%= stylesheet_link_tag themes_primary_path %> <%= 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) %>"> <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") %> <i class="dropdown-icon fas fa-cog"></i> <%= t("room.settings") %>
</a> </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 %> <% 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) %>"> <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") %> <i class="dropdown-icon fas fa-users"></i> <%= t("room.share") %>

View File

@ -18,19 +18,19 @@
<div class="row pt-9"> <div class="row pt-9">
<div class="col-lg-12 col-sm-12"> <div class="col-lg-12 col-sm-12">
<h4 class="text-left"><%= t("room.invited") %></h4> <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"> <hr class="mt-2 float-left w-25">
</div> </div>
</div> </div>
<div class="row"> <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? %> <% if @room.owner.image.blank? %>
<span class="avatar"><%= @room.owner.name.first %></span> <span class="avatar"><%= @room.owner.name.first %></span>
<% else %> <% else %>
<span class="avatar" style="background-image: url(<%= @room.owner.image %>)"></span> <span class="avatar" style="background-image: url(<%= @room.owner.image %>)"></span>
<% end %> <% 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>
<div class="col-lg-6 col-md-6 col-sm-12"> <div class="col-lg-6 col-md-6 col-sm-12">
@ -40,6 +40,7 @@
</div> </div>
</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") %> <%= render "shared/sessions", recordings: @public_recordings, pagy: @pagy, only_public: true, user_recordings: false, title: t("room.recordings") %>
<% end %> <% end %>

View File

@ -13,6 +13,8 @@
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. # 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] %> <% 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 %> <%= render 'rooms/components/room_event', render_recordings: valid_access_code do %>
<% if room_authentication_required %> <% if room_authentication_required %>
@ -44,11 +46,17 @@
autofocus: true autofocus: true
%> %>
<span class="input-group-append"> <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") %> <%= (!@room_running && @anyone_can_start) ? t("room.start") : t("room.join") %>
</button> </button>
</span> </span>
</div> </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 %> <% end %>
<% end %> <% end %>

View File

@ -24,11 +24,10 @@
<div class="row pt-7 pt-sm-9"> <div class="row pt-7 pt-sm-9">
<div class="col-lg-8 col-sm-12"> <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) %>"> <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 %> <% 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> <a class="disable-click"><i class="fas fa-home align-top home-indicator ml-2"></i></a>
<% else %> <% 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> <a><i id="edit-room" class="fa fa-edit align-top home-indicator ml-2" data-edit-room="<%= @room.uid %>"></i></a>
<% end %> <% end %>
</div> </div>
@ -104,12 +103,19 @@
</div> </div>
</div> </div>
<%= render "shared/sessions", recordings: @recordings, pagy: @pagy, only_public: false, shared_room: @shared_room, user_recordings: false, title: t("room.recordings")%> <% 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/delete_room_modal" %>
<%= render "shared/modals/create_room_modal" %> <%= render "shared/modals/create_room_modal" %>
<% if preupload_allowed? %>
<%= render "shared/modals/preupload_presentation_modal" %>
<% end %>
<% if shared_access_allowed %> <% if shared_access_allowed %>
<%= render "shared/modals/share_room_modal" %> <%= render "shared/modals/share_room_modal" %>
<%= render "shared/modals/remove_access_modal" %> <%= render "shared/modals/remove_access_modal" %>

View File

@ -27,7 +27,7 @@
<% elsif key.eql? "maintenance" %> <% elsif key.eql? "maintenance" %>
<div class="alert alert-info alert-dismissible text-center mb-0"> <div class="alert alert-info alert-dismissible text-center mb-0">
<%= value %> <%= 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> </div>
<% elsif key.eql? "info" %> <% elsif key.eql? "info" %>
<div class="alert alert-info alert-dismissible text-center mb-0"> <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> <i class="fas fa-home pr-1 "></i><span class="d-none d-sm-inline-block"><%= t("header.dropdown.home") %></span>
<% end %> <% 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" : "" %> <% 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 %> <%= 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> <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> <tr>
<td> <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]) %>"> <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] %> <% if recording[:metadata][:name] %>
<span id="recording-text" title="<%= recording[:metadata][:name] %>">
<%= recording[:metadata][:name] %> <%= recording[:metadata][:name] %>
<% else %> <% else %>
<span id="recording-text" title="<%= recording[:name] %>">
<%= recording[:name] %> <%= recording[:name] %>
<% end %> <% end %>
</span> </span>

View File

@ -16,10 +16,11 @@
<tr> <tr>
<td> <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]) %>"> <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] %> <% if recording[:metadata][:name] %>
<span id='recording-text' title="<%= recording[:metadata][:name] %>">
<%= recording[:metadata][:name] %> <%= recording[:metadata][:name] %>
<% else %> <% else %>
<span id='recording-text' title="<%= recording[:name] %>">
<%= recording[:name] %> <%= recording[:name] %>
<% end %> <% end %>
</span> </span>

View File

@ -16,18 +16,10 @@
<div class="row mt-2"> <div class="row mt-2">
<% if search %> <% if search %>
<div class="col-md-6"> <div class="col-md-6">
<p class="subtitle"><%= subtitle %></p> <p class="subtitle"><%= title(subtitle) %></p>
</div> </div>
<div class="col-md-6 mb-4"> <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 id="search-bar" class="d-inline-block float-right">
<div class="input-group"> <div class="input-group">
<input id="search-input" type="text" class="form-control" placeholder="<%= t("settings.search") %>..." value="<%= @search %>"> <input id="search-input" type="text" class="form-control" placeholder="<%= t("settings.search") %>..." value="<%= @search %>">
@ -46,7 +38,7 @@
</div> </div>
<% else %> <% else %>
<div class="col-12"> <div class="col-12">
<p class="subtitle"><%= subtitle %></p> <p class="subtitle"><%= title(subtitle) %></p>
</div> </div>
<% end %> <% end %>
</div> </div>

View File

@ -69,7 +69,6 @@
<span class="custom-switch-indicator float-right cursor-pointer"></span> <span class="custom-switch-indicator float-right cursor-pointer"></span>
</label> </label>
<% end %> <% end %>
<% moderator = room_configuration("Room Configuration All Join Moderator") %> <% moderator = room_configuration("Room Configuration All Join Moderator") %>
<% if moderator != "disabled" %> <% 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" %>"> <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> <span class="custom-switch-indicator float-right cursor-pointer"></span>
</label> </label>
<% end %> <% 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"> <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> <span class="custom-switch-description"><%= t("modal.create_room.auto_join") %></span>
<%= f.check_box :auto_join, class: "custom-switch-input", checked: false %> <%= 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> </div>
<%= button_to "/", method: :delete, id: "remove-shared-confirm", class: "btn btn-danger my-1 btn-del-room" do %> <%= 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") %> <%= t("modal.remove_shared.delete") %>
<% end %> <% end %>

View File

@ -128,6 +128,9 @@ module Greenlight
config.report_issue_url = ENV["REPORT_ISSUE_URL"] 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"] 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 # DEFAULTS
# Default branding image if the user does not specify one # Default branding image if the user does not specify one
@ -157,6 +160,12 @@ module Greenlight
# Allow users to share rooms by default # Allow users to share rooms by default
config.shared_access_default = "true" 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 # Default admin password
config.admin_password_default = ENV['ADMIN_PASSWORD'] || 'administrator' config.admin_password_default = ENV['ADMIN_PASSWORD'] || 'administrator'
end end

View File

@ -61,7 +61,13 @@ Rails.application.configure do
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX # 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) # 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 # Mount Action Cable outside main process or domain
# config.action_cable.mount_path = nil # config.action_cable.mount_path = nil

View File

@ -36,7 +36,7 @@ en:
enabled: Enabled enabled: Enabled
info: Only allow authenticated users to join a room info: Only allow authenticated users to join a room
title: Require Authentication for Rooms 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: branding:
change: Change Image change: Change Image
info: Change the branding image that appears in the top left corner info: Change the branding image that appears in the top left corner
@ -45,9 +45,9 @@ en:
invalid: Invalid URL invalid: Invalid URL
legal: legal:
change: Change URL change: Change URL
info: Change the Legal Link that appears in the bottom of the page info: Change the Terms Link that appears in the bottom of the page
placeholder: Legal URL... placeholder: Terms URL...
title: Legal title: Terms
invalid: Invalid URL invalid: Invalid URL
privpolicy: privpolicy:
change: Change URL change: Change URL
@ -82,6 +82,18 @@ en:
info: Set the default recording visbility for new recordings info: Set the default recording visbility for new recordings
title: Recording Default Visibility title: Recording Default Visibility
warning: This setting will only be applied to rooms that aren't running 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: registration:
info: Change the way that users register to the website info: Change the way that users register to the website
title: Registration Method 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 info: Setting to disabled will remove the button from the Room options dropdown, preventing users from sharing rooms
title: Allow Users to Share Rooms title: Allow Users to Share Rooms
subtitle: Customize Greenlight subtitle: Customize Greenlight
tabs:
appearance: Appearance
administration: Administration
settings: Settings
title: Site Settings title: Site Settings
flash: flash:
approved: User has been successfully approved. 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. info: Allows any user to start the meeting at any time. By default, only the room owner can start the meeting.
all_moderator: all_moderator:
info: Gives all users moderator privileges in BigBlueButton when they join the meeting. 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: options:
disabled: Disabled disabled: Disabled
enabled: Always Enabled enabled: Always Enabled
@ -261,7 +279,7 @@ en:
designs: Custom Designs designs: Custom Designs
authentication: User Authentication authentication: User Authentication
footer: footer:
legal: Legal legal: Terms
privpolicy: Privacy Policy privpolicy: Privacy Policy
powered_by: Powered by %{href}. powered_by: Powered by %{href}.
forgot_password: forgot_password:
@ -393,6 +411,14 @@ en:
or: or or: or
with: Sign in with %{provider} with: Sign in with %{provider}
forgot_password: Forgot Password? 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: rename_recording:
remove_shared: remove_shared:
title: Are you sure you want to remove this room from your room list? 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 require_approval: Require moderator approval before joining
start: Allow any user to start this meeting start: Allow any user to start this meeting
footer_text: Adjustment to your room can be done at anytime. footer_text: Adjustment to your room can be done at anytime.
recording: Allow room to be recorded
rename_room: rename_room:
name_placeholder: Enter a new room name... name_placeholder: Enter a new room name...
share_access: share_access:
@ -501,6 +528,7 @@ en:
user: User user: User
room: room:
access_code_required: Please enter a valid access code to join the 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: Create a Room
create_room_error: There was an error creating the room create_room_error: There was an error creating the room
create_room_success: Room created successfully create_room_success: Room created successfully
@ -510,7 +538,9 @@ en:
fail: Failed to delete room (%{error}) fail: Failed to delete room (%{error})
enter_the_access_code: Enter the room's access code 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. 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 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 invite_participants: Invite Participants
join: Join join: Join
last_session: Last session on %{session} last_session: Last session on %{session}
@ -527,6 +557,10 @@ en:
recent_rooms: Go To a Recently Joined Room recent_rooms: Go To a Recently Joined Room
title: Join a Room title: Join a Room
no_sessions: This room has no sessions, yet! 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 recordings: Room Recordings
room_limit: You have reached the maximum number of rooms allowed 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. 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 patch '/', to: 'rooms#update', as: :update_room
get '/room_settings', to: 'rooms#room_settings' get '/room_settings', to: 'rooms#room_settings'
post '/update_settings', to: 'rooms#update_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 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 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 get '/shared_users', to: 'rooms#shared_users', as: :room_shared_users

View File

@ -7,19 +7,29 @@ local:
root: <%= Rails.root.join("storage") %> root: <%= Rails.root.join("storage") %>
# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
# amazon: amazon:
# service: S3 service: S3
# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
# region: us-east-1 region: <%= ENV['AWS_REGION'] %>
# bucket: your_own_bucket bucket: <%= ENV['AWS_BUCKET'] %>
# Remember not to checkin your GCS keyfile to a repository # Remember not to checkin your GCS keyfile to a repository
# google: google:
# service: GCS service: GCS
# project: your_project project: "<%= ENV['GCS_PROJECT'] %>"
# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> bucket: "<%= ENV['GCS_BUCKET'] %>"
# bucket: your_own_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) # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
# microsoft: # 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. # 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| create_table "features", force: :cascade do |t|
t.integer "setting_id" t.integer "setting_id"

View File

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

View File

@ -24,3 +24,10 @@ location /b/cable {
client_body_timeout 6h; client_body_timeout 6h;
send_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 { .dropdown-item {
color: #6e7687 !important; color: #6e7687 !important;
&:hover { &:hover {

View File

@ -33,4 +33,18 @@ namespace :room do
end end
end 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 end

View File

@ -47,7 +47,7 @@ namespace :user do
user.set_role(u[:role]) user.set_role(u[:role])
puts "Account succesfully created." puts "Account successfully created."
puts "Email: #{u[:email]}" puts "Email: #{u[:email]}"
puts "Password: #{u[:password]}" puts "Password: #{u[:password]}"
puts "Role: #{u[:role]}" 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 # 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 # 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 # 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 # Specify the maximum number of records to be sent to the BigBlueButton API in one call
# Default is set to 25 records # Default is set to 25 records
@ -258,3 +259,24 @@ DB_PASSWORD=password
# invite - For invite only registration # invite - For invite only registration
# approval - For approve/decline registration # approval - For approve/decline registration
DEFAULT_REGISTRATION=open 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) export CD_REF_NAME=$(git branch | grep \* | cut -d ' ' -f2)
fi 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" echo "#### Docker image for $CD_REF_SLUG:$CD_REF_NAME won't be built"
exit 0 exit 0
fi fi

View File

@ -290,12 +290,12 @@ describe AdminsController, type: :controller do
@request.session[:user_id] = @admin.id @request.session[:user_id] = @admin.id
fake_image_url = "example.com" 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") feature = Setting.find_by(provider: "provider1").features.find_by(name: "Branding Image")
expect(feature[:value]).to eq(fake_image_url) 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
end end
@ -307,12 +307,12 @@ describe AdminsController, type: :controller do
@request.session[:user_id] = @admin.id @request.session[:user_id] = @admin.id
fake_url = "example.com" 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") feature = Setting.find_by(provider: "provider1").features.find_by(name: "Legal URL")
expect(feature[:value]).to eq(fake_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
end end
@ -324,12 +324,12 @@ describe AdminsController, type: :controller do
@request.session[:user_id] = @admin.id @request.session[:user_id] = @admin.id
fake_url = "example.com" 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") feature = Setting.find_by(provider: "provider1").features.find_by(name: "Privacy Policy URL")
expect(feature[:value]).to eq(fake_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
end end
@ -346,7 +346,7 @@ describe AdminsController, type: :controller do
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Primary Color") feature = Setting.find_by(provider: "provider1").features.find_by(name: "Primary Color")
expect(feature[:value]).to eq(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 end
it "changes the primary-lighten on the page" do it "changes the primary-lighten on the page" do
@ -356,12 +356,12 @@ describe AdminsController, type: :controller do
@request.session[:user_id] = @admin.id @request.session[:user_id] = @admin.id
primary_color = Faker::Color.hex_color 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") feature = Setting.find_by(provider: "provider1").features.find_by(name: "Primary Color Lighten")
expect(feature[:value]).to eq(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 end
it "changes the primary-darken on the page" do it "changes the primary-darken on the page" do
@ -371,12 +371,12 @@ describe AdminsController, type: :controller do
@request.session[:user_id] = @admin.id @request.session[:user_id] = @admin.id
primary_color = Faker::Color.hex_color 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") feature = Setting.find_by(provider: "provider1").features.find_by(name: "Primary Color Darken")
expect(feature[:value]).to eq(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 end
end end
end end
@ -396,7 +396,7 @@ describe AdminsController, type: :controller do
expect(feature[:value]).to eq(Rails.configuration.registration_methods[:invite]) expect(feature[:value]).to eq(Rails.configuration.registration_methods[:invite])
expect(flash[:success]).to be_present 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 end
it "does not allow the user to change to invite if emails are off" do 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" } post :registration_method, params: { value: "invite" }
expect(flash[:alert]).to be_present 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
end end
@ -425,7 +425,7 @@ describe AdminsController, type: :controller do
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Room Authentication") feature = Setting.find_by(provider: "provider1").features.find_by(name: "Room Authentication")
expect(feature[:value]).to eq("true") 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
end end
@ -441,7 +441,7 @@ describe AdminsController, type: :controller do
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Room Limit") feature = Setting.find_by(provider: "provider1").features.find_by(name: "Room Limit")
expect(feature[:value]).to eq("5") 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
end end
@ -457,7 +457,25 @@ describe AdminsController, type: :controller do
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Default Recording Visibility") feature = Setting.find_by(provider: "provider1").features.find_by(name: "Default Recording Visibility")
expect(feature[:value]).to eq("public") 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
end end
@ -473,7 +491,7 @@ describe AdminsController, type: :controller do
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Shared Access") feature = Setting.find_by(provider: "provider1").features.find_by(name: "Shared Access")
expect(feature[:value]).to eq("false") 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
end end
@ -537,7 +555,7 @@ describe AdminsController, type: :controller do
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Shared Access") feature = Setting.find_by(provider: "provider1").features.find_by(name: "Shared Access")
expect(feature[:value]).to eq("false") 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
it "doesn't allow a user with the incorrect permission to edit site settings" do 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", room_params = { name: name, "mute_on_join": "1",
"require_moderator_approval": "1", "anyone_can_start": "1", "all_join_moderator": "1" } "require_moderator_approval": "1", "anyone_can_start": "1", "all_join_moderator": "1" }
json_room_settings = "{\"muteOnStart\":true,\"requireModeratorApproval\":true," \ json_room_settings = "{\"muteOnStart\":true,\"requireModeratorApproval\":true," \
"\"anyoneCanStart\":true,\"joinModerator\":true}" "\"anyoneCanStart\":true,\"joinModerator\":true,\"recording\":false}"
post :create, params: { room: room_params } 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, @owner.main_room.update_attribute(:room_settings, { "muteOnStart": true, "requireModeratorApproval": true,
"anyoneCanStart": true, "joinModerator": true }.to_json) "anyoneCanStart": true, "joinModerator": true }.to_json)
json_room_settings = "{\"muteOnStart\":true,\"requireModeratorApproval\":true," \ json_room_settings = { "anyoneCanStart" => true,
"\"anyoneCanStart\":true,\"joinModerator\":true}" "joinModerator" => true,
"muteOnStart" => true,
"requireModeratorApproval" => true }
get :room_settings, params: { room_uid: @owner.main_room }, format: :json 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 it "properly updates room name through the room settings modal and redirects to current page" do
@request.session[:user_id] = @user.id @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 } } 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 it "properly updates room settings through the room settings modal and redirects to current page" do
@request.session[:user_id] = @user.id @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," \ 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 } } expect { post :update_settings, params: { room_uid: @secondary_room.uid, room: room_params } }
.to change { @secondary_room.reload.room_settings } .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 } room_params = { "mute_on_join": "1", "name": @secondary_room.name }
formatted_room_params = "{\"muteOnStart\":true,\"requireModeratorApproval\":false," \ 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 } } expect { post :update_settings, params: { room_uid: @secondary_room.uid, room: room_params } }
.to change { @secondary_room.reload.room_settings } .to change { @secondary_room.reload.room_settings }
@ -814,4 +816,107 @@ describe RoomsController, type: :controller do
expect(response).to redirect_to root_path expect(response).to redirect_to root_path
end end
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 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