diff --git a/Gemfile b/Gemfile
index a58166de..5ce666f0 100644
--- a/Gemfile
+++ b/Gemfile
@@ -57,6 +57,7 @@ gem 'bigbluebutton-api-ruby'
# Front-end.
gem 'bootstrap', '~> 4.3.1'
gem 'tabler-rubygem'
+gem 'pagy'
# For detecting the users preferred language.
gem 'http_accept_language'
@@ -70,6 +71,11 @@ gem 'redcarpet'
# For health check endpoint
gem "health_check"
+# For providing user roles
+gem "rolify"
+# For limiting access based on user roles
+gem 'cancancan', '~> 2.0'
+
group :production do
# Use a postgres database in production.
gem 'pg', '~> 0.18'
diff --git a/Gemfile.lock b/Gemfile.lock
index db2fbd1f..88d24127 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -56,6 +56,7 @@ GEM
sassc-rails (>= 2.0.0)
builder (3.2.3)
byebug (10.0.2)
+ cancancan (2.3.0)
coffee-rails (4.2.2)
coffee-script (>= 2.2.0)
railties (>= 4.0.0)
@@ -174,6 +175,7 @@ GEM
omniauth-twitter (1.4.0)
omniauth-oauth (~> 1.1)
rack
+ pagy (2.1.5)
parallel (1.17.0)
parser (2.6.3.0)
ast (~> 2.4.0)
@@ -226,6 +228,7 @@ GEM
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
+ rolify (5.2.0)
rspec-core (3.7.1)
rspec-support (~> 3.7.0)
rspec-expectations (3.7.0)
@@ -336,6 +339,7 @@ DEPENDENCIES
bigbluebutton-api-ruby
bootstrap (~> 4.3.1)
byebug
+ cancancan (~> 2.0)
coffee-rails (~> 4.2)
coveralls
dotenv-rails
@@ -353,6 +357,7 @@ DEPENDENCIES
omniauth-ldap
omniauth-microsoft-office365 (~> 0.0.7)
omniauth-twitter
+ pagy
pg (~> 0.18)
puma (~> 3.0)
rails (~> 5.0.7)
@@ -361,6 +366,7 @@ DEPENDENCIES
redcarpet
redis (~> 3.0)
remote_syslog_logger
+ rolify
rspec-rails (~> 3.7)
rubocop
sass-rails (~> 5.0)
diff --git a/app/assets/javascripts/admins.js b/app/assets/javascripts/admins.js
new file mode 100644
index 00000000..4a117e9c
--- /dev/null
+++ b/app/assets/javascripts/admins.js
@@ -0,0 +1,97 @@
+// 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 .
+
+$(document).on('turbolinks:load', function(){
+ var controller = $("body").data('controller');
+ var action = $("body").data('action');
+
+ // Only run on the admins page.
+ if (controller == "admins" && action == "index") {
+ // show the modal with the correct form action url
+ $(".delete-user").click(function(data){
+ var uid = $(data.target).closest("tr").data("user-uid")
+ $("#delete-confirm").parent().attr("action", "/u/" + uid)
+ })
+
+ // Change the color of the color inputs when the color is changed
+ $(".colorinput-input").change(function(data) {
+ // Get the color from the input
+ var color = $(data.target).val()
+
+ // Update the color in the database and reload the page
+ $.post($("#coloring-path").val(), {color: color}).done(function(data) {
+ location.reload()
+ });
+ });
+
+ // Submit search if the user hits enter
+ $("#search-input").keypress(function(key) {
+ var keyPressed = key.which
+ if (keyPressed == 13) {
+ searchPage()
+ }
+ })
+
+ // Add listeners for sort
+ $("th[data-order]").click(function(data){
+ var header_elem = $(data.target)
+
+ if(header_elem.data('order') === 'asc'){ // asc
+ header_elem.data('order', 'desc');
+ }
+ else if(header_elem.data('order') === 'desc'){ // desc
+ header_elem.data('order', 'none');
+ }
+ else{ // none
+ header_elem.data('order', 'asc');
+ }
+
+ var search = $("#search-input").val()
+ window.location.replace(window.location.pathname + "?page=1&search=" + search + "&column=" + header_elem.data("header") + "&direction="+ header_elem.data('order'))
+ })
+ }
+
+ // Only run on the admins edit user page.
+ if (controller == "admins" && action == "edit_user") {
+ $("#users").click(function(data){
+ var url = $("body").data("relative-root")
+ if (!url.endsWith("/")) {
+ url += "/"
+ }
+ url += "admins"
+
+ window.location.href = url
+ })
+ }
+});
+
+// Change the branding image to the image provided
+function changeBrandingImage(path) {
+ var url = $("#branding-url").val()
+ $.post(path, {url: url})
+}
+
+// Searches the user table for the given string
+function searchPage() {
+ var search = $("#search-input").val()
+
+ window.location.replace(window.location.pathname + "?page=1&search=" + search)
+}
+
+// Clears the search bar
+function clearSearch() {
+ window.location.replace(window.location.pathname + "?page=1")
+}
diff --git a/app/assets/javascripts/room.js b/app/assets/javascripts/room.js
index 93dbd5cc..e229c7d4 100644
--- a/app/assets/javascripts/room.js
+++ b/app/assets/javascripts/room.js
@@ -57,7 +57,7 @@ $(document).on('turbolinks:load', function(){
}
// Display and update all fields related to creating a room in the createRoomModal
- $("#create-room").click(function(){
+ $("#create-room-block").click(function(){
$("#create-room-name").val("")
$("#createRoomModal form").attr("action", $("body").data('relative-root'))
updateDropdown($(".dropdown-item[value='default']"))
diff --git a/app/assets/javascripts/settings.js b/app/assets/javascripts/settings.js
index 42b7418e..bacd22b4 100644
--- a/app/assets/javascripts/settings.js
+++ b/app/assets/javascripts/settings.js
@@ -20,7 +20,7 @@ $(document).on('turbolinks:load', function(){
var action = $("body").data('action');
// Only run on the settings page.
- if ((controller == "users" && action == "edit") || (controller == "users" && action == "update")){
+ if ((controller == "users" && action == "edit") || (controller == "users" && action == "update") || (controller == "admins" && action == "index")){
var settingsButtons = $('.setting-btn');
var settingsViews = $('.setting-view');
diff --git a/app/assets/javascripts/sort.js b/app/assets/javascripts/sort.js
index 09452868..a7903de6 100644
--- a/app/assets/javascripts/sort.js
+++ b/app/assets/javascripts/sort.js
@@ -15,8 +15,10 @@
// with BigBlueButton; if not, see .
$(document).on('turbolinks:load', function(){
- // Check if there is a table on this page
- if ($("table").length) {
+ var controller = $("body").data('controller');
+ var action = $("body").data('action');
+
+ if(controller == "rooms" && action == "show" || controller == "rooms" && action == "update" || controller == "users" && action == "recordings"){
// Choose active header
// (Name, Length or Users)
diff --git a/app/assets/stylesheets/_tabler-custom.scss b/app/assets/stylesheets/_tabler-custom.scss
index 66958746..c87cabeb 100644
--- a/app/assets/stylesheets/_tabler-custom.scss
+++ b/app/assets/stylesheets/_tabler-custom.scss
@@ -31,7 +31,7 @@
@import "tabler/nav";
@import "tabler/button";
-//@import "tabler/alert";
+@import "tabler/alert";
//@import "tabler/close";
//@import "tabler/badge";
@import "tabler/tables";
@@ -68,7 +68,7 @@
//@import "tabler/forms/custom-selectgroup";
@import "tabler/forms/custom-switch";
//@import "tabler/forms/custom-imagecheck";
-//@import "tabler/forms/custom-colorinput";
+@import "tabler/forms/custom-colorinput";
//@import "tabler/timeline";
diff --git a/app/assets/stylesheets/admins.scss b/app/assets/stylesheets/admins.scss
new file mode 100644
index 00000000..3c3db40e
--- /dev/null
+++ b/app/assets/stylesheets/admins.scss
@@ -0,0 +1,32 @@
+// 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 .
+
+#users-table {
+ .user-role:hover {
+ cursor: default;
+ }
+}
+
+#clear-search {
+ z-index: 9;
+ position: absolute;
+ right: 55px;
+ top: 8px;
+
+ &:hover {
+ cursor: pointer;
+ }
+}
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index f883273b..93725e12 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -35,12 +35,17 @@
@import "tabler-custom";
@import "utilities/variables";
+@import "admins";
@import "main";
@import "rooms";
@import "sessions";
@import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,300i,400,400i,500,500i,600,600i,700,700i&subset=latin-ext);
+* {
+ outline: none !important;
+}
+
html, body {
position: relative;
width: 100%;
@@ -77,10 +82,6 @@ a {
width: 100%;
}
-.table-responsive {
- overflow: visible;
-}
-
.background {
background-color: $background-color;
}
@@ -135,3 +136,34 @@ a {
background-color: green !important;
}
}
+
+input:focus {
+ border-color: $primary !important;
+}
+
+.list-group-item-action.active {
+ color: $primary;
+}
+
+.header .header-nav {
+ color: $text-muted !important;
+
+ &:hover {
+ padding-bottom: 21px;
+ border-bottom: 1px solid $primary;
+ }
+
+ &.active {
+ color: $primary !important;
+ padding-bottom: 21px;
+ border-bottom: 1px solid $primary;
+ }
+}
+
+table {
+ thead {
+ th[data-order]:hover {
+ cursor: pointer;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss
index 87fb2c79..dcd6dacd 100755
--- a/app/assets/stylesheets/main.scss
+++ b/app/assets/stylesheets/main.scss
@@ -144,3 +144,7 @@
padding:10px 10px 10px 10px;
}
}
+
+.signin-button {
+ font-size: 16px;
+}
diff --git a/app/assets/stylesheets/rooms.scss b/app/assets/stylesheets/rooms.scss
index 3b90cd1a..e971c0bb 100644
--- a/app/assets/stylesheets/rooms.scss
+++ b/app/assets/stylesheets/rooms.scss
@@ -56,3 +56,12 @@
vertical-align: middle;
padding-top: 12px;
}
+
+#create-room-block {
+ border: 1px dashed lightgray;
+
+ &:hover {
+ cursor: pointer;
+ background-color: rgba(0, 0, 0, 0.04);
+ }
+}
diff --git a/app/assets/stylesheets/utilities/_primary_themes.scss b/app/assets/stylesheets/utilities/_primary_themes.scss
new file mode 100644
index 00000000..33d29a56
--- /dev/null
+++ b/app/assets/stylesheets/utilities/_primary_themes.scss
@@ -0,0 +1,125 @@
+.btn-primary,
+.btn-primary:visited,
+.btn-primary i {
+ background-color: $primary-color !important;
+ border-color: $primary-color !important;
+ color: white !important;
+}
+
+.btn-primary:active,
+.btn-primary:active:focus,
+.btn-primary:active:hover,
+.btn-primary:focus,
+.btn-primary:hover,
+.btn-primary:hover i {
+ background-color: $primary-color-darken !important;
+ border-color: $primary-color-darken !important;
+ color: white !important;
+}
+
+a {
+ color: $primary-color !important;
+}
+
+.oauth-signin {
+ color: white !important;
+
+ &:hover * {
+ color: white !important;
+ }
+}
+
+.btn-outline-primary {
+ border-color: $primary-color !important;
+ color: $primary-color !important;
+
+ &:hover {
+ background: $primary-color !important;
+ color: white !important;
+ }
+
+ &:focus {
+ box-shadow: 0 0 0 2px $primary-color-lighten;
+ }
+}
+
+.header {
+ & .avatar {
+ background-color: $primary-color !important;
+ color: white !important;
+ }
+
+ & a:hover:not(.btn) {
+ color: $primary-color !important;
+ }
+
+ & .header-nav {
+ border-color: $primary-color !important;
+ }
+
+ & .header-nav.active {
+ color: $primary-color !important;
+ }
+}
+
+.dropdown-item {
+ color: #6e7687 !important;
+ &:hover {
+ color: $primary-color !important;
+ }
+ &:active {
+ background-color: $primary-color-lighten !important;
+ }
+}
+
+input:focus, select:focus {
+ box-shadow: 0 0 5px $primary-color !important;
+ border-color: $primary-color !important;
+}
+
+.list-group-item.active {
+ background-color: $primary-color-lighten !important;
+
+ &, .list-group-item.active * {
+ color: $primary-color !important;
+ }
+}
+
+.text-primary {
+ color: $primary-color !important;
+}
+
+.bg-primary {
+ background-color: $primary-color !important;
+}
+
+.btn-danger {
+ color: white !important;
+}
+
+#clear-search {
+ &:hover {
+ color: $primary-color-darken !important;
+ }
+}
+
+.pagination {
+ .page-item {
+ &.active a {
+ color:white !important;
+ background-color: $primary-color !important;
+ }
+
+ & a {
+ border-color: $primary-color !important;
+ }
+
+ & a:hover {
+ background-color: $primary-color-lighten !important;
+ }
+
+ & a:focus {
+ box-shadow: 0 0 3px $primary-color !important;
+ }
+ }
+}
diff --git a/app/controllers/account_activations_controller.rb b/app/controllers/account_activations_controller.rb
index 549253d9..f508b056 100644
--- a/app/controllers/account_activations_controller.rb
+++ b/app/controllers/account_activations_controller.rb
@@ -33,11 +33,11 @@ class AccountActivationsController < ApplicationController
@user.activate
flash[:success] = I18n.t("verify.activated") + " " + I18n.t("verify.signin")
+ redirect_to signin_path
else
flash[:alert] = I18n.t("verify.invalid")
+ redirect_to root_path
end
-
- redirect_to root_url
end
# GET /account_activations/resend
@@ -51,7 +51,7 @@ class AccountActivationsController < ApplicationController
logger.error "Error in email delivery: #{e}"
flash[:alert] = I18n.t(params[:message], default: I18n.t("delivery_error"))
else
- flash[:success] = I18n.t("email_sent")
+ flash[:success] = I18n.t("email_sent", email_type: t("verify.verification"))
end
end
diff --git a/app/controllers/admins_controller.rb b/app/controllers/admins_controller.rb
new file mode 100644
index 00000000..4ea1a188
--- /dev/null
+++ b/app/controllers/admins_controller.rb
@@ -0,0 +1,101 @@
+# frozen_string_literal: true
+
+# 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 .
+
+class AdminsController < ApplicationController
+ include Pagy::Backend
+ authorize_resource class: false
+ before_action :find_user, only: [:edit_user, :promote, :demote, :ban_user, :unban_user]
+ before_action :verify_admin_of_user, only: [:edit_user, :promote, :demote, :ban_user, :unban_user]
+ before_action :find_setting, only: [:branding, :coloring]
+
+ # GET /admins
+ def index
+ @search = params[:search] || ""
+ @order_column = params[:column] && params[:direction] != "none" ? params[:column] : "created_at"
+ @order_direction = params[:direction] && params[:direction] != "none" ? params[:direction] : "DESC"
+ puts @order_direction.to_s
+
+ if Rails.configuration.loadbalanced_configuration
+ @pagy, @users = pagy(User.without_role(:super_admin)
+ .where(provider: user_settings_provider)
+ .where.not(id: current_user.id)
+ .admins_search(@search)
+ .admins_order(@order_column, @order_direction))
+ else
+ @pagy, @users = pagy(User.where.not(id: current_user.id)
+ .admins_search(@search)
+ .admins_order(@order_column, @order_direction))
+ end
+ end
+
+ # GET /admins/edit/:user_uid
+ def edit_user
+ render "admins/index", locals: { setting_id: "account" }
+ end
+
+ # POST /admins/promote/:user_uid
+ def promote
+ @user.add_role :admin
+ redirect_to admins_path, flash: { success: I18n.t("administrator.flash.promoted") }
+ end
+
+ # POST /admins/demote/:user_uid
+ def demote
+ @user.remove_role :admin
+ redirect_to admins_path, flash: { success: I18n.t("administrator.flash.demoted") }
+ end
+
+ # POST /admins/branding
+ def branding
+ @settings.update_value("Branding Image", params[:url])
+ redirect_to admins_path
+ end
+
+ # POST /admins/color
+ def coloring
+ @settings.update_value("Primary Color", params[:color])
+ redirect_to admins_path(setting: "site_settings")
+ end
+
+ # POST /admins/ban/:user_uid
+ def ban_user
+ @user.add_role :denied
+ redirect_to admins_path, flash: { success: I18n.t("administrator.flash.banned") }
+ end
+
+ # POST /admins/unban/:user_uid
+ def unban_user
+ @user.remove_role :denied
+ redirect_to admins_path, flash: { success: I18n.t("administrator.flash.unbanned") }
+ end
+
+ private
+
+ def find_user
+ @user = User.find_by!(uid: params[:user_uid])
+ end
+
+ def find_setting
+ @settings = Setting.find_or_create_by!(provider: user_settings_provider)
+ end
+
+ def verify_admin_of_user
+ redirect_to admins_path,
+ flash: { alert: I18n.t("administrator.flash.unauthorized") } unless current_user.admin_of?(@user)
+ end
+end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 71ab4f1f..dc241760 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -20,10 +20,13 @@ require 'bigbluebutton_api'
class ApplicationController < ActionController::Base
include SessionsHelper
+ include ThemingHelper
before_action :migration_error?
before_action :set_locale
+ before_action :check_admin_password
before_action :set_user_domain
+ before_action :check_if_unbanned
# Force SSL for loadbalancer configurations.
before_action :redirect_to_https
@@ -102,6 +105,21 @@ class ApplicationController < ActionController::Base
}
end
+ # Manually deal with 401 errors
+ rescue_from CanCan::AccessDenied do |_exception|
+ render "errors/not_found"
+ end
+
+ # Checks to make sure that the admin has changed his password from the default
+ def check_admin_password
+ if current_user&.has_role?(:admin) && current_user&.greenlight_account? &&
+ current_user&.authenticate(Rails.configuration.admin_password_default)
+
+ flash.now[:alert] = I18n.t("default_admin",
+ edit_link: edit_user_path(user_uid: current_user.uid) + "?setting=password").html_safe
+ end
+ end
+
def redirect_to_https
if Rails.configuration.loadbalanced_configuration && request.headers["X-Forwarded-Proto"] == "http"
redirect_to protocol: "https://"
@@ -116,4 +134,13 @@ class ApplicationController < ActionController::Base
end
end
helper_method :set_user_domain
+
+ # Checks if the user is banned and logs him out if he is
+ def check_if_unbanned
+ if current_user&.has_role?(:denied)
+ session.delete(:user_id)
+ redirect_to unauthorized_path
+ end
+ end
+ helper_method :check_if_unbanned
end
diff --git a/app/controllers/errors_controller.rb b/app/controllers/errors_controller.rb
index 4b0b4b25..5c388a4e 100644
--- a/app/controllers/errors_controller.rb
+++ b/app/controllers/errors_controller.rb
@@ -28,4 +28,8 @@ class ErrorsController < ApplicationController
def internal_error
render status: 500, formats: :html
end
+
+ def unauthorized
+ render status: 401, formats: :html
+ end
end
diff --git a/app/controllers/main_controller.rb b/app/controllers/main_controller.rb
index 49f8ae81..a6ac81bc 100644
--- a/app/controllers/main_controller.rb
+++ b/app/controllers/main_controller.rb
@@ -17,16 +17,7 @@
# with BigBlueButton; if not, see .
class MainController < ApplicationController
- # before_action :redirect_to_room
-
# GET /
def index
end
-
- private
-
- def redirect_to_room
- # If the user is logged in already, move them along to their room.
- redirect_to room_path(current_user.room) if current_user
- end
end
diff --git a/app/controllers/password_resets_controller.rb b/app/controllers/password_resets_controller.rb
index 4cf87adb..280ef06f 100644
--- a/app/controllers/password_resets_controller.rb
+++ b/app/controllers/password_resets_controller.rb
@@ -30,7 +30,7 @@ class PasswordResetsController < ApplicationController
if @user
@user.create_reset_digest
@user.send_password_reset_email(reset_link)
- flash[:success] = I18n.t("email_sent")
+ flash[:success] = I18n.t("email_sent", email_type: t("reset_password.subtitle"))
redirect_to root_path
else
flash[:alert] = I18n.t("no_user_email_exists")
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index 62c8f613..0dc85d40 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -27,12 +27,18 @@ class SessionsController < ApplicationController
# POST /users/login
def create
- user = User.find_by(email: session_params[:email], provider: @user_domain)
- redirect_to(root_path, alert: I18n.t("invalid_user")) && return unless user
- redirect_to(root_path, alert: I18n.t("invalid_login_method")) && return unless user.greenlight_account?
+ admin = User.find_by(email: session_params[:email])
+ if admin&.has_role? :super_admin
+ user = admin
+ else
+ user = User.find_by(email: session_params[:email], provider: @user_domain)
+ redirect_to(root_path, alert: I18n.t("invalid_user")) && return unless user
+ redirect_to(root_path, alert: I18n.t("invalid_login_method")) && return unless user.greenlight_account?
+ redirect_to(account_activation_path(email: user.email)) && return unless user.activated?
+ end
redirect_to(root_path, alert: I18n.t("invalid_credentials")) && return unless user.try(:authenticate,
session_params[:password])
- redirect_to(account_activation_path(email: user.email)) && return unless user.activated?
+
login(user)
end
diff --git a/app/controllers/themes_controller.rb b/app/controllers/themes_controller.rb
new file mode 100644
index 00000000..812a3aa4
--- /dev/null
+++ b/app/controllers/themes_controller.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+# 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 .
+
+class ThemesController < ApplicationController
+ before_action :provider_settings
+
+ # GET /primary
+ def index
+ color = @settings.get_value("Primary Color") || Rails.configuration.primary_color_default
+ file_name = Rails.root.join('app', 'assets', 'stylesheets', 'utilities', '_primary_themes.scss')
+ @file_contents = File.read(file_name)
+
+ # Include the variables and covert scss file to css
+ @compiled = Sass::Engine.new("$primary-color:#{color};" \
+ "$primary-color-lighten:lighten(#{color}, 40%);" \
+ "$primary-color-darken:darken(#{color}, 10%);" +
+ @file_contents, syntax: :scss).render
+
+ respond_to do |format|
+ format.css { render body: @compiled }
+ end
+ end
+
+ private
+
+ def provider_settings
+ @settings = Setting.find_or_create_by(provider: user_settings_provider)
+ end
+end
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 904ef56d..a7517e01 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -44,11 +44,15 @@ class UsersController < ApplicationController
logger.error "Error in email delivery: #{e}"
flash[:alert] = I18n.t(params[:message], default: I18n.t("delivery_error"))
else
- flash[:success] = I18n.t("email_sent")
+ flash[:success] = I18n.t("email_sent", email_type: t("verify.verification"))
end
redirect_to(root_path)
end
+ # GET /signin
+ def signin
+ end
+
# GET /signup
def new
if Rails.configuration.allow_user_signup
@@ -61,7 +65,7 @@ class UsersController < ApplicationController
# GET /u/:user_uid/edit
def edit
if current_user
- redirect_to current_user.room unless @user == current_user
+ redirect_to current_user.main_room if @user != current_user && !current_user.admin_of?(@user)
else
redirect_to root_path
end
@@ -113,6 +117,16 @@ class UsersController < ApplicationController
if current_user && current_user == @user
@user.destroy
session.delete(:user_id)
+ elsif current_user.admin_of?(@user)
+ begin
+ @user.destroy
+ rescue => e
+ logger.error "Error in user deletion: #{e}"
+ flash[:alert] = I18n.t(params[:message], default: I18n.t("administrator.flash.delete_fail"))
+ else
+ flash[:success] = I18n.t("administrator.flash.delete")
+ end
+ redirect_to(admins_path) && return
end
redirect_to root_path
end
diff --git a/app/helpers/admins_helper.rb b/app/helpers/admins_helper.rb
new file mode 100644
index 00000000..e0aa5c5c
--- /dev/null
+++ b/app/helpers/admins_helper.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+# 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 .
+
+module AdminsHelper
+ include Pagy::Frontend
+end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 440a3c1f..8f96426a 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -95,4 +95,11 @@ module ApplicationHelper
@translations ||= I18n.backend.send(:translations)
@translations[I18n.locale].with_indifferent_access[:javascript] || {}
end
+
+ # Returns the page that the logo redirects to when clicked on
+ def home_page
+ return root_path unless current_user
+ return admins_path if current_user.has_role? :super_admin
+ current_user.main_room
+ end
end
diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb
index 9c76c731..5b25bc5a 100644
--- a/app/helpers/sessions_helper.rb
+++ b/app/helpers/sessions_helper.rb
@@ -31,9 +31,13 @@ module SessionsHelper
# If email verification is disabled, or the user has verified, go to their room
def check_email_verified(user)
- if user.activated?
- # Get the url to redirect the user to
- url = if cookies[:return_to] && ![root_url, signup_url].include?(cookies[:return_to])
+ # Admin users should be redirected to the admin page
+ if user.has_role? :super_admin
+ redirect_to admins_path
+ elsif user.activated?
+ # Dont redirect to any of these urls
+ dont_redirect_to = [root_url, signup_url, unauthorized_url, internal_error_url, not_found_url]
+ url = if cookies[:return_to] && !dont_redirect_to.include?(cookies[:return_to])
cookies[:return_to]
else
user.main_room
diff --git a/app/helpers/theming_helper.rb b/app/helpers/theming_helper.rb
new file mode 100644
index 00000000..58f0def3
--- /dev/null
+++ b/app/helpers/theming_helper.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+# 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 .
+
+module ThemingHelper
+ # Returns the logo based on user's provider
+ def logo_image
+ Setting.find_or_create_by(provider: user_settings_provider)
+ .get_value("Branding Image") || Rails.configuration.branding_image_default
+ end
+
+ # Returns the primary color based on user's provider
+ def user_color
+ Setting.find_or_create_by(provider: user_settings_provider)
+ .get_value("Primary Color") || Rails.configuration.primary_color_default
+ end
+
+ # Returns the user's provider in the settings context
+ def user_settings_provider
+ if Rails.configuration.loadbalanced_configuration && !current_user&.has_role?(:super_admin)
+ current_user.provider
+ elsif Rails.configuration.loadbalanced_configuration
+ @user_domain
+ else
+ "greenlight"
+ end
+ end
+end
diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb
index 0fe7b991..3e0743e9 100644
--- a/app/mailers/application_mailer.rb
+++ b/app/mailers/application_mailer.rb
@@ -17,6 +17,7 @@
# with BigBlueButton; if not, see .
class ApplicationMailer < ActionMailer::Base
+ add_template_helper(ThemingHelper)
default from: 'from@example.com'
layout 'mailer'
end
diff --git a/app/models/ability.rb b/app/models/ability.rb
new file mode 100644
index 00000000..07ec8358
--- /dev/null
+++ b/app/models/ability.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+# 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 .
+
+class Ability
+ include CanCan::Ability
+
+ def initialize(user)
+ if !user
+ cannot :manage, AdminsController
+ elsif user.has_role? :super_admin
+ can :manage, :all
+ elsif user.has_role? :admin
+ can :manage, :all
+ elsif user.has_role? :user
+ cannot :manage, AdminsController
+ end
+ end
+end
diff --git a/app/models/feature.rb b/app/models/feature.rb
new file mode 100644
index 00000000..01c49117
--- /dev/null
+++ b/app/models/feature.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+# 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 .
+
+class Feature < ApplicationRecord
+ belongs_to :setting
+end
diff --git a/app/models/role.rb b/app/models/role.rb
new file mode 100644
index 00000000..856b92c6
--- /dev/null
+++ b/app/models/role.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+# 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 .
+
+class Role < ApplicationRecord
+ has_and_belongs_to_many :users, join_table: :users_roles
+
+ belongs_to :resource,
+ polymorphic: true,
+ optional: true
+
+ validates :resource_type,
+ inclusion: { in: Rolify.resource_types },
+ allow_nil: true
+
+ scopify
+end
diff --git a/app/models/setting.rb b/app/models/setting.rb
new file mode 100644
index 00000000..c0e859e3
--- /dev/null
+++ b/app/models/setting.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+# 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 .
+
+class Setting < ApplicationRecord
+ has_many :features
+
+ # Updates the value of the feature and enables it
+ def update_value(name, value)
+ feature = features.find_or_create_by!(name: name)
+
+ feature.update_attributes(value: value, enabled: true)
+ end
+
+ # Returns the value if enabled or the default if not enabled
+ def get_value(name)
+ feature = features.find_or_create_by!(name: name)
+ if feature[:enabled]
+ feature[:value]
+ else
+ case name
+ when "Branding Image"
+ Rails.configuration.branding_image_default
+ when "Primary Color"
+ Rails.configuration.primary_color_default
+ end
+ end
+ end
+end
diff --git a/app/models/user.rb b/app/models/user.rb
index 7e446f80..de530c94 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -19,11 +19,14 @@
require 'bbb_api'
class User < ApplicationRecord
+ rolify
include ::APIConcern
include ::BbbApi
attr_accessor :reset_token
+ after_create :assign_default_role
after_create :initialize_main_room
+
before_save { email.try(:downcase!) }
before_destroy :destroy_rooms
@@ -33,6 +36,7 @@ class User < ApplicationRecord
validates :name, length: { maximum: 256 }, presence: true
validates :provider, presence: true
+ validate :check_if_email_can_be_blank
validates :email, length: { maximum: 256 }, allow_blank: true,
uniqueness: { case_sensitive: false, scope: :provider },
format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i }
@@ -98,6 +102,17 @@ class User < ApplicationRecord
end
end
+ def self.admins_search(string)
+ search_query = "name LIKE :search OR email LIKE :search OR username LIKE :search" \
+ " OR created_at LIKE :search OR provider LIKE :search"
+ search_param = "%#{string}%"
+ where(search_query, search: search_param)
+ end
+
+ def self.admins_order(column, direction)
+ order("#{column} #{direction}")
+ end
+
def all_recordings
pag_num = Rails.configuration.pagination_number
@@ -199,6 +214,18 @@ class User < ApplicationRecord
create_reset_activation_digest(User.new_token)
end
+ def admin_of?(user)
+ if Rails.configuration.loadbalanced_configuration
+ if has_role? :super_admin
+ id != user.id
+ else
+ (has_role? :admin) && (id != user.id) && (provider == user.provider) && (!user.has_role? :super_admin)
+ end
+ else
+ ((has_role? :admin) || (has_role? :super_admin)) && (id != user.id)
+ end
+ end
+
def self.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
@@ -229,4 +256,19 @@ class User < ApplicationRecord
self.main_room = Room.create!(owner: self, name: I18n.t("home_room"))
save
end
+
+ # Initialize the user to use the default user role
+ def assign_default_role
+ add_role(:user) if roles.blank?
+ end
+
+ def check_if_email_can_be_blank
+ if email.blank?
+ if Rails.configuration.loadbalanced_configuration && greenlight_account?
+ errors.add(:email, I18n.t("errors.messages.blank"))
+ elsif provider == "greenlight"
+ errors.add(:email, I18n.t("errors.messages.blank"))
+ end
+ end
+ end
end
diff --git a/app/views/admins/index.html.erb b/app/views/admins/index.html.erb
new file mode 100644
index 00000000..f89ee3d0
--- /dev/null
+++ b/app/views/admins/index.html.erb
@@ -0,0 +1,42 @@
+<%
+# 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 .
+%>
+
diff --git a/app/views/errors/unauthorized.html.erb b/app/views/errors/unauthorized.html.erb
new file mode 100644
index 00000000..e54591d7
--- /dev/null
+++ b/app/views/errors/unauthorized.html.erb
@@ -0,0 +1,20 @@
+<%
+# 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 .
+%>
+
+