Merge pull request #555 from bigbluebutton/alpha-2.1.1

Alpha 2.1.1
This commit is contained in:
Jesus Federico 2019-05-24 11:49:59 -04:00 committed by GitHub
commit 98395328b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
67 changed files with 2055 additions and 181 deletions

2
.gitignore vendored
View File

@ -35,6 +35,8 @@ env
# IDEs # IDEs
.idea .idea
.idea/** .idea/**
.vscode
.vscode/**
config/terms.md config/terms.md
coverage* coverage*

View File

@ -41,6 +41,10 @@ Style/MixinUsage:
Style/SymbolArray: Style/SymbolArray:
Enabled: false Enabled: false
# Don't use begin blocks when they are not needed.
Style/RedundantBegin:
Enabled: false
# Use `%`-literal delimiters consistently # Use `%`-literal delimiters consistently
Style/PercentLiteralDelimiters: Style/PercentLiteralDelimiters:
Enabled: false Enabled: false

View File

@ -31,32 +31,58 @@ $(document).on('turbolinks:load', function(){
$("#delete-confirm").parent().attr("action", url) $("#delete-confirm").parent().attr("action", url)
}) })
$('.colorinput').ColorPicker({ //clear the role filter if user clicks on the x
onHide: function (colpkr) { $(".clear-role").click(function(data) {
var colour = $("#user-colour").val(); search = new URL(location.href).searchParams.get('search')
// Update the color in the database and reload the page url = window.location.pathname + "?page=1"
$.post($("#coloring-path").val(), {color: colour}).done(function(data) {
location.reload() if (search) {
}); url += "&search=" + search
}, }
onSubmit: function(hsb, hex, rgb, el) { window.location.replace(url);
$.post($("#coloring-path").val(), {color: '#' + hex}).done(function(data) { })
location.reload()
}); /* COLOR SELECTORS */
},
$('#colorinput-regular').ColorPicker({
onBeforeShow: function () { onBeforeShow: function () {
var colour = $("#user-colour").val(); var colour = rgb2hex($("#colorinput-regular").css("background-color"))
$(this).ColorPickerSetColor(colour); $(this).ColorPickerSetColor(colour);
}, },
onSubmit: function(_hsb, hex, _rgb, _el) {
$.post($("#coloring-path-regular").val(), {color: '#' + hex}).done(function(data) {
location.reload()
});
},
});
onChange: function (hsb, hex, rgb) { $('#colorinput-lighten').ColorPicker({
$('.colorinput span').css('backgroundColor', '#' + hex); onBeforeShow: function () {
$("#user-colour").val('#' + hex); var colour = rgb2hex($("#colorinput-lighten").css("background-color"))
}
$(this).ColorPickerSetColor(colour);
},
onSubmit: function(_hsb, hex, _rgb, _el) {
$.post($("#coloring-path-lighten").val(), {color: '#' + hex}).done(function(data) {
location.reload()
});
},
});
$('#colorinput-darken').ColorPicker({
onBeforeShow: function () {
var colour = rgb2hex($("#colorinput-darken").css("background-color"))
$(this).ColorPickerSetColor(colour);
},
onSubmit: function(_hsb, hex, _rgb, _el) {
$.post($("#coloring-path-darken").val(), {color: '#' + hex}).done(function(data) {
location.reload()
});
},
}); });
} }
@ -79,3 +105,25 @@ function changeBrandingImage(path) {
var url = $("#branding-url").val() var url = $("#branding-url").val()
$.post(path, {url: url}) $.post(path, {url: url})
} }
// Filters by role
function filterRole(role) {
search = new URL(location.href).searchParams.get('search')
url = window.location.pathname + "?page=1" + "&role=" + role
if (search) {
url += "&search=" + search
}
window.location.replace(url);
}
function rgb2hex(rgb) {
rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
function hex(x) {
return ("0" + parseInt(x).toString(16)).slice(-2);
}
return "#" + hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
}

View File

@ -17,7 +17,8 @@
$(document).on('turbolinks:load', function(){ $(document).on('turbolinks:load', function(){
// Stores the current url when the user clicks the sign in button // Stores the current url when the user clicks the sign in button
$(".sign-in-button").click(function(){ $(".sign-in-button").click(function(){
document.cookie ="return_to=" + window.location.href var url = [location.protocol, '//', location.host, location.pathname].join('');
document.cookie ="return_to=" + url
}) })
// Checks to see if the user provided an image url and displays it if they did // Checks to see if the user provided an image url and displays it if they did

View File

@ -77,10 +77,19 @@ function searchPage() {
var controller = $("body").data('controller'); var controller = $("body").data('controller');
var action = $("body").data('action'); var action = $("body").data('action');
// Check if the user filtered by role
role = new URL(location.href).searchParams.get('role')
url = window.location.pathname + "?page=1&search=" + search
if (role) {
url += "&role=" + role
}
if(controller === "rooms" && action === "show"){ if(controller === "rooms" && action === "show"){
window.location.replace(window.location.pathname + "?page=1&search=" + search + "#recordings-table"); window.location.replace(url + "#recordings-table");
} else{ } else{
window.location.replace(window.location.pathname + "?page=1&search=" + search); window.location.replace(url);
} }
} }
@ -90,9 +99,17 @@ function clearSearch() {
var controller = $("body").data('controller'); var controller = $("body").data('controller');
var action = $("body").data('action'); var action = $("body").data('action');
role = new URL(location.href).searchParams.get('role')
url = window.location.pathname + "?page=1"
if (role) {
url += "&role=" + role
}
if(controller === "rooms" && action === "show"){ if(controller === "rooms" && action === "show"){
window.location.replace(window.location.pathname + "?page=1" + "#recordings-table"); window.location.replace(url + "#recordings-table");
} else{ } else{
window.location.replace(window.location.pathname + "?page=1"); window.location.replace(url);
} }
} }

View File

@ -59,7 +59,7 @@
@import "tabler/stamp"; @import "tabler/stamp";
//@import "tabler/chat"; //@import "tabler/chat";
//@import "tabler/example"; //@import "tabler/example";
//@import "tabler/tag"; @import "tabler/tag";
//@import "tabler/syntax"; //@import "tabler/syntax";
//@import "tabler/infobox"; //@import "tabler/infobox";
//@import "tabler/carousel"; //@import "tabler/carousel";

View File

@ -15,8 +15,8 @@
// with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. // with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
#users-table { #users-table {
.user-role:hover { .user-role {
cursor: default; color: white !important;
} }
} }
@ -31,6 +31,14 @@
} }
} }
.tag i {
color: white !important;
}
#branding-image{ #branding-image{
z-index: auto; z-index: auto;
} }
.authentication-required{
padding-top: 2px;
}

View File

@ -1,3 +1,9 @@
.btn {
&:focus {
box-shadow: 0 0 0 2px $primary-color-lighten;
}
}
.btn-primary, .btn-primary,
.btn-primary:visited, .btn-primary:visited,
.btn-primary i { .btn-primary i {
@ -9,7 +15,6 @@
.btn-primary:active, .btn-primary:active,
.btn-primary:active:focus, .btn-primary:active:focus,
.btn-primary:active:hover, .btn-primary:active:hover,
.btn-primary:focus,
.btn-primary:hover, .btn-primary:hover,
.btn-primary:hover i { .btn-primary:hover i {
background-color: $primary-color-darken !important; background-color: $primary-color-darken !important;
@ -17,6 +22,19 @@
color: white !important; color: white !important;
} }
.btn-primary:focus {
background-color: $primary-color-darken !important;
border-color: $primary-color-darken !important;
color: white !important;
box-shadow: 0 0 0 2px $primary-color-lighten !important;
}
.custom-checkbox .custom-control-input:checked ~ .custom-control-label::before{
background-color: $primary-color !important;
border-color: $primary-color !important;
color: white !important;
}
a { a {
color: $primary-color !important; color: $primary-color !important;
} }
@ -39,7 +57,7 @@ a {
} }
&:focus { &:focus {
box-shadow: 0 0 0 2px $primary-color-lighten; box-shadow: 0 0 0 2px $primary-color-lighten !important;
} }
} }
@ -91,6 +109,7 @@ input:focus, select:focus {
.bg-primary { .bg-primary {
background-color: $primary-color !important; background-color: $primary-color !important;
color: white !important;
} }
.btn-danger { .btn-danger {
@ -123,3 +142,21 @@ input:focus, select:focus {
} }
} }
} }
.primary-regular {
background-color: $primary-color !important;
border-color: $primary-color !important;
color: white !important;
}
.primary-lighten {
background-color: $primary-color-lighten !important;
border-color: $primary-color-lighten !important;
color: $primary-color !important;
}
.primary-darken {
background-color: $primary-color-darken !important;
border-color: $primary-color-darken !important;
color: white !important;
}

View File

@ -32,6 +32,10 @@ class AccountActivationsController < ApplicationController
if @user && !@user.activated? && @user.authenticated?(:activation, params[:token]) if @user && !@user.activated? && @user.authenticated?(:activation, params[:token])
@user.activate @user.activate
# Redirect user to root with account pending flash if account is still pending
return redirect_to root_path,
flash: { success: I18n.t("registration.approval.signup") } if @user.has_role?(:pending)
flash[:success] = I18n.t("verify.activated") + " " + I18n.t("verify.signin") flash[:success] = I18n.t("verify.activated") + " " + I18n.t("verify.signin")
redirect_to signin_path redirect_to signin_path
else else

View File

@ -18,30 +18,30 @@
class AdminsController < ApplicationController class AdminsController < ApplicationController
include Pagy::Backend include Pagy::Backend
include Themer
include Emailer
manage_users = [:edit_user, :promote, :demote, :ban_user, :unban_user, :approve]
site_settings = [:branding, :coloring, :coloring_lighten, :coloring_darken,
:registration_method, :room_authentication]
authorize_resource class: false authorize_resource class: false
before_action :find_user, only: [:edit_user, :promote, :demote, :ban_user, :unban_user] before_action :find_user, only: manage_users
before_action :verify_admin_of_user, only: [:edit_user, :promote, :demote, :ban_user, :unban_user] before_action :verify_admin_of_user, only: manage_users
before_action :find_setting, only: [:branding, :coloring] before_action :find_setting, only: site_settings
# GET /admins # GET /admins
def index def index
@search = params[:search] || "" @search = params[:search] || ""
@order_column = params[:column] && params[:direction] != "none" ? params[:column] : "created_at" @order_column = params[:column] && params[:direction] != "none" ? params[:column] : "created_at"
@order_direction = params[:direction] && params[:direction] != "none" ? params[:direction] : "DESC" @order_direction = params[:direction] && params[:direction] != "none" ? params[:direction] : "DESC"
@role = params[:role] || ""
if Rails.configuration.loadbalanced_configuration @pagy, @users = pagy(user_list)
@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 end
# MANAGE USERS
# GET /admins/edit/:user_uid # GET /admins/edit/:user_uid
def edit_user def edit_user
render "admins/index", locals: { setting_id: "account" } render "admins/index", locals: { setting_id: "account" }
@ -50,29 +50,24 @@ class AdminsController < ApplicationController
# POST /admins/promote/:user_uid # POST /admins/promote/:user_uid
def promote def promote
@user.add_role :admin @user.add_role :admin
send_user_promoted_email(@user)
redirect_to admins_path, flash: { success: I18n.t("administrator.flash.promoted") } redirect_to admins_path, flash: { success: I18n.t("administrator.flash.promoted") }
end end
# POST /admins/demote/:user_uid # POST /admins/demote/:user_uid
def demote def demote
@user.remove_role :admin @user.remove_role :admin
send_user_demoted_email(@user)
redirect_to admins_path, flash: { success: I18n.t("administrator.flash.demoted") } redirect_to admins_path, flash: { success: I18n.t("administrator.flash.demoted") }
end 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 # POST /admins/ban/:user_uid
def ban_user def ban_user
@user.roles = []
@user.add_role :denied @user.add_role :denied
redirect_to admins_path, flash: { success: I18n.t("administrator.flash.banned") } redirect_to admins_path, flash: { success: I18n.t("administrator.flash.banned") }
end end
@ -80,9 +75,84 @@ class AdminsController < ApplicationController
# POST /admins/unban/:user_uid # POST /admins/unban/:user_uid
def unban_user def unban_user
@user.remove_role :denied @user.remove_role :denied
@user.add_role :user
redirect_to admins_path, flash: { success: I18n.t("administrator.flash.unbanned") } redirect_to admins_path, flash: { success: I18n.t("administrator.flash.unbanned") }
end end
# POST /admins/approve/:user_uid
def approve
@user.remove_role :pending
send_user_approved_email(@user)
redirect_to admins_path, flash: { success: I18n.t("administrator.flash.approved") }
end
# POST /admins/invite
def invite
email = params[:invite_user][:email]
begin
invitation = create_or_update_invite(email)
send_invitation_email(current_user.name, email, invitation.invite_token)
rescue => e
logger.error "Error in email delivery: #{e}"
flash[:alert] = I18n.t(params[:message], default: I18n.t("delivery_error"))
else
flash[:success] = I18n.t("administrator.flash.invite", email: email)
end
redirect_to admins_path
end
# SITE SETTINGS
# POST /admins/branding
def branding
@settings.update_value("Branding Image", params[:url])
redirect_to admins_path, flash: { success: I18n.t("administrator.flash.settings.image") }
end
# POST /admins/color
def coloring
@settings.update_value("Primary Color", params[:color])
@settings.update_value("Primary Color Lighten", color_lighten(params[:color]))
@settings.update_value("Primary Color Darken", color_darken(params[:color]))
redirect_to admins_path, flash: { success: I18n.t("administrator.flash.settings") }
end
def coloring_lighten
@settings.update_value("Primary Color Lighten", params[:color])
redirect_to admins_path, flash: { success: I18n.t("administrator.flash.settings") }
end
def coloring_darken
@settings.update_value("Primary Color Darken", params[:color])
redirect_to admins_path, flash: { success: I18n.t("administrator.flash.settings") }
end
# POST /admins/room_authentication
def room_authentication
@settings.update_value("Room Authentication", params[:value])
redirect_to admins_path, flash: { success: I18n.t("administrator.flash.settings") }
end
# POST /admins/registration_method/:method
def registration_method
new_method = Rails.configuration.registration_methods[params[:method].to_sym]
# Only allow change to Join by Invitation if user has emails enabled
if !Rails.configuration.enable_email_verification && new_method == Rails.configuration.registration_methods[:invite]
redirect_to admins_path,
flash: { alert: I18n.t("administrator.flash.invite_email_verification") }
else
@settings.update_value("Registration Method", new_method)
redirect_to admins_path,
flash: { success: I18n.t("administrator.flash.registration_method_updated") }
end
end
private private
def find_user def find_user
@ -97,4 +167,38 @@ class AdminsController < ApplicationController
redirect_to admins_path, redirect_to admins_path,
flash: { alert: I18n.t("administrator.flash.unauthorized") } unless current_user.admin_of?(@user) flash: { alert: I18n.t("administrator.flash.unauthorized") } unless current_user.admin_of?(@user)
end end
# Gets the list of users based on your configuration
def user_list
list = if @role.present?
User.with_role(@role.to_sym).where.not(id: current_user.id)
else
User.where.not(id: current_user.id)
end
if Rails.configuration.loadbalanced_configuration
list.where(provider: user_settings_provider)
.admins_search(@search)
.admins_order(@order_column, @order_direction)
else
list.admins_search(@search)
.admins_order(@order_column, @order_direction)
end
end
# Creates the invite if it doesn't exist, or updates the updated_at time if it does
def create_or_update_invite(email)
invite = Invitation.find_by(email: email, provider: @user_domain)
# Invite already exists
if invite.present?
# Updates updated_at to now
invite.touch
else
# Creates invite
invite = Invitation.create(email: email, provider: @user_domain)
end
invite
end
end end

View File

@ -19,6 +19,7 @@
require 'bigbluebutton_api' require 'bigbluebutton_api'
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
include ApplicationHelper
include SessionsHelper include SessionsHelper
include ThemingHelper include ThemingHelper
@ -26,7 +27,10 @@ class ApplicationController < ActionController::Base
before_action :set_locale before_action :set_locale
before_action :check_admin_password before_action :check_admin_password
before_action :set_user_domain before_action :set_user_domain
before_action :check_if_unbanned before_action :check_user_role
# Manually handle BigBlueButton errors
rescue_from BigBlueButton::BigBlueButtonException, with: :handle_bigbluebutton_error
# Force SSL for loadbalancer configurations. # Force SSL for loadbalancer configurations.
before_action :redirect_to_https before_action :redirect_to_https
@ -84,7 +88,7 @@ class ApplicationController < ActionController::Base
helper_method :recording_thumbnails? helper_method :recording_thumbnails?
def allow_greenlight_users? def allow_greenlight_users?
Rails.configuration.greenlight_accounts allow_greenlight_accounts?
end end
helper_method :allow_greenlight_users? helper_method :allow_greenlight_users?
@ -136,11 +140,19 @@ class ApplicationController < ActionController::Base
helper_method :set_user_domain helper_method :set_user_domain
# Checks if the user is banned and logs him out if he is # Checks if the user is banned and logs him out if he is
def check_if_unbanned def check_user_role
if current_user&.has_role?(:denied) if current_user&.has_role? :denied
session.delete(:user_id) session.delete(:user_id)
redirect_to unauthorized_path redirect_to root_path, flash: { alert: I18n.t("registration.banned.fail") }
elsif current_user&.has_role? :pending
session.delete(:user_id)
redirect_to root_path, flash: { alert: I18n.t("registration.approval.fail") }
end end
end end
helper_method :check_if_unbanned helper_method :check_user_role
# Manually Handle BigBlueButton errors
def handle_bigbluebutton_error
render "errors/bigbluebutton_error"
end
end end

View File

@ -21,22 +21,85 @@ module Emailer
# Sends account activation email. # Sends account activation email.
def send_activation_email(user) def send_activation_email(user)
return unless Rails.configuration.enable_email_verification
@user = user @user = user
UserMailer.verify_email(@user, user_verification_link, logo_image, user_color).deliver UserMailer.verify_email(@user, user_verification_link, logo_image, user_color).deliver
end end
# Sends password reset email. # Sends password reset email.
def send_password_reset_email(user) def send_password_reset_email(user)
return unless Rails.configuration.enable_email_verification
@user = user @user = user
UserMailer.password_reset(@user, reset_link, logo_image, user_color).deliver_now UserMailer.password_reset(@user, reset_link, logo_image, user_color).deliver_now
end end
def send_user_promoted_email(user)
return unless Rails.configuration.enable_email_verification
UserMailer.user_promoted(user, root_url, logo_image, user_color).deliver_now
end
def send_user_demoted_email(user)
return unless Rails.configuration.enable_email_verification
UserMailer.user_demoted(user, root_url, logo_image, user_color).deliver_now
end
# Sends inivitation to join
def send_invitation_email(name, email, token)
return unless Rails.configuration.enable_email_verification
@token = token
UserMailer.invite_email(name, email, invitation_link, logo_image, user_color).deliver_now
end
def send_user_approved_email(user)
return unless Rails.configuration.enable_email_verification
UserMailer.approve_user(user, root_url, logo_image, user_color).deliver_now
end
def send_approval_user_signup_email(user)
return unless Rails.configuration.enable_email_verification
UserMailer.approval_user_signup(user, admins_url, logo_image, user_color, admin_emails).deliver_now
end
def send_invite_user_signup_email(user)
return unless Rails.configuration.enable_email_verification
UserMailer.invite_user_signup(user, admins_url, logo_image, user_color, admin_emails).deliver_now
end
private
# Returns the link the user needs to click to verify their account # Returns the link the user needs to click to verify their account
def user_verification_link def user_verification_link
request.base_url + edit_account_activation_path(token: @user.activation_token, email: @user.email) edit_account_activation_url(token: @user.activation_token, email: @user.email)
end
def admin_emails
admins = User.with_role(:admin)
if Rails.configuration.loadbalanced_configuration
admins = admins.without_role(:super_admin)
.where(provider: user_settings_provider)
end
admins.collect(&:email).join(",")
end end
def reset_link def reset_link
request.base_url + edit_password_reset_path(@user.reset_token, email: @user.email) edit_password_reset_url(@user.reset_token, email: @user.email)
end
def invitation_link
if allow_greenlight_users?
signup_url(invite_token: @token)
else
root_url(invite_token: @token)
end
end end
end end

View File

@ -0,0 +1,54 @@
# 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 <http://www.gnu.org/licenses/>.
module Registrar
extend ActiveSupport::Concern
def registration_method
Setting.find_or_create_by!(provider: user_settings_provider).get_value("Registration Method")
end
def open_registration
registration_method == Rails.configuration.registration_methods[:open]
end
def approval_registration
registration_method == Rails.configuration.registration_methods[:approval]
end
def invite_registration
registration_method == Rails.configuration.registration_methods[:invite]
end
# Returns a hash containing whether the user has been invited and if they
# signed up with the same email that they were invited with
def check_user_invited(email, token, domain)
return { present: true, verified: false } unless invite_registration
return { present: false, verified: false } if token.nil?
invite = Invitation.valid.find_by(invite_token: token, provider: domain)
if invite.present?
# Check if they used the same email to sign up
same_email = email.casecmp(invite.email).zero?
invite.destroy
{ present: true, verified: same_email }
else
{ present: false, verified: false }
end
end
end

View File

@ -0,0 +1,47 @@
# 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 <http://www.gnu.org/licenses/>.
module Themer
extend ActiveSupport::Concern
# Lightens a color by 40%
def color_lighten(color)
# Uses the built in Sass Engine to lighten the color
dummy_scss = "h1 { color: $lighten; }"
compiled = Sass::Engine.new("$lighten:lighten(#{color}, 40%);" + dummy_scss, syntax: :scss).render
string_locater = 'color: '
color_start = compiled.index(string_locater) + string_locater.length
compiled[color_start..color_start + 6]
end
# Darkens a color by 10%
def color_darken(color)
# Uses the built in Sass Engine to darken the color
dummy_scss = "h1 { color: $darken; }"
compiled = Sass::Engine.new("$darken:darken(#{color}, 10%);" + dummy_scss, syntax: :scss).render
string_locater = 'color: '
color_start = compiled.index(string_locater) + string_locater.length
compiled[color_start..color_start + 6]
end
end

View File

@ -17,7 +17,10 @@
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. # with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
class MainController < ApplicationController class MainController < ApplicationController
include Registrar
# GET / # GET /
def index def index
# Store invite token
session[:invite_token] = params[:invite_token] if params[:invite_token] && invite_registration
end end
end end

View File

@ -98,6 +98,9 @@ class RoomsController < ApplicationController
# POST /:room_uid # POST /:room_uid
def join def join
return redirect_to root_path,
flash: { alert: I18n.t("administrator.site_settings.authentication.user-info") } if auth_required
opts = default_meeting_options opts = default_meeting_options
unless @room.owned_by?(current_user) unless @room.owned_by?(current_user)
# Assign join name if passed. # Assign join name if passed.
@ -271,4 +274,9 @@ class RoomsController < ApplicationController
def verify_user_not_admin def verify_user_not_admin
redirect_to admins_path if current_user && current_user&.has_role?(:super_admin) redirect_to admins_path if current_user && current_user&.has_role?(:super_admin)
end end
def auth_required
Setting.find_or_create_by!(provider: user_settings_provider).get_value("Room Authentication") == "true" &&
current_user.nil?
end
end end

View File

@ -17,6 +17,9 @@
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. # with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
class SessionsController < ApplicationController class SessionsController < ApplicationController
include Registrar
include Emailer
skip_before_action :verify_authenticity_token, only: [:omniauth, :fail] skip_before_action :verify_authenticity_token, only: [:omniauth, :fail]
# GET /users/logout # GET /users/logout
@ -32,11 +35,11 @@ class SessionsController < ApplicationController
user = admin user = admin
else else
user = User.find_by(email: session_params[:email], provider: @user_domain) 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(signin_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(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? redirect_to(account_activation_path(email: user.email)) && return unless user.activated?
end end
redirect_to(root_path, alert: I18n.t("invalid_credentials")) && return unless user.try(:authenticate, redirect_to(signin_path, alert: I18n.t("invalid_credentials")) && return unless user.try(:authenticate,
session_params[:password]) session_params[:password])
login(user) login(user)
@ -44,11 +47,33 @@ class SessionsController < ApplicationController
# GET/POST /auth/:provider/callback # GET/POST /auth/:provider/callback
def omniauth def omniauth
user = User.from_omniauth(request.env['omniauth.auth']) begin
login(user) @auth = request.env['omniauth.auth']
rescue => e @user_exists = check_user_exists
logger.error "Error authenticating via omniauth: #{e}"
omniauth_fail # If using invitation registration method, make sure user is invited
return redirect_to root_path, flash: { alert: I18n.t("registration.invite.no_invite") } unless passes_invite_reqs
user = User.from_omniauth(@auth)
# Add pending role if approval method and is a new user
if approval_registration && !@user_exists
user.add_role :pending
# Inform admins that a user signed up if emails are turned on
send_approval_user_signup_email(user) if Rails.configuration.enable_email_verification
return redirect_to root_path, flash: { success: I18n.t("registration.approval.signup") }
end
send_invite_user_signup_email(user) if Rails.configuration.enable_email_verification &&
invite_registration && !@user_exists
login(user)
rescue => e
logger.error "Error authenticating via omniauth: #{e}"
omniauth_fail
end
end end
# POST /auth/failure # POST /auth/failure
@ -61,4 +86,17 @@ class SessionsController < ApplicationController
def session_params def session_params
params.require(:session).permit(:email, :password) params.require(:session).permit(:email, :password)
end end
def check_user_exists
provider = @auth['provider'] == "bn_launcher" ? @auth['info']['customer'] : @auth['provider']
User.exists?(social_uid: @auth['uid'], provider: provider)
end
# Check if the user already exists, if not then check for invitation
def passes_invite_reqs
return true if @user_exists
invitation = check_user_invited("", session[:invite_token], @user_domain)
invitation[:present]
end
end end

View File

@ -22,13 +22,16 @@ class ThemesController < ApplicationController
# GET /primary # GET /primary
def index def index
color = @settings.get_value("Primary Color") || Rails.configuration.primary_color_default color = @settings.get_value("Primary Color") || Rails.configuration.primary_color_default
lighten_color = @settings.get_value("Primary Color Lighten") || Rails.configuration.primary_color_lighten_default
darken_color = @settings.get_value("Primary Color Darken") || Rails.configuration.primary_color_darken_default
file_name = Rails.root.join('app', 'assets', 'stylesheets', 'utilities', '_primary_themes.scss') file_name = Rails.root.join('app', 'assets', 'stylesheets', 'utilities', '_primary_themes.scss')
@file_contents = File.read(file_name) @file_contents = File.read(file_name)
# Include the variables and covert scss file to css # Include the variables and covert scss file to css
@compiled = Sass::Engine.new("$primary-color:#{color};" \ @compiled = Sass::Engine.new("$primary-color:#{color};" \
"$primary-color-lighten:lighten(#{color}, 40%);" \ "$primary-color-lighten:#{lighten_color};" \
"$primary-color-darken:darken(#{color}, 10%);" + "$primary-color-darken:#{darken_color};" +
@file_contents, syntax: :scss).render @file_contents, syntax: :scss).render
respond_to do |format| respond_to do |format|

View File

@ -20,6 +20,7 @@ class UsersController < ApplicationController
include RecordingsHelper include RecordingsHelper
include Pagy::Backend include Pagy::Backend
include Emailer include Emailer
include Registrar
before_action :find_user, only: [:edit, :update, :destroy] before_action :find_user, only: [:edit, :update, :destroy]
before_action :ensure_unauthenticated, only: [:new, :create] before_action :ensure_unauthenticated, only: [:new, :create]
@ -32,29 +33,31 @@ class UsersController < ApplicationController
@user = User.new(user_params) @user = User.new(user_params)
@user.provider = @user_domain @user.provider = @user_domain
# Add validation errors to model if they exist # User or recpatcha is not valid
valid_user = @user.valid? render(:new) && return unless valid_user_or_captcha
valid_captcha = Rails.configuration.recaptcha_enabled ? verify_recaptcha(model: @user) : true
if valid_user && valid_captcha # Redirect to root if user token is either invalid or expired
@user.save return redirect_to root_path, flash: { alert: I18n.t("registration.invite.fail") } unless passes_invite_reqs
else
render(:new) && return # User has passed all validations required
@user.save
# Set user to pending and redirect if Approval Registration is set
if approval_registration
@user.add_role :pending
return redirect_to root_path,
flash: { success: I18n.t("registration.approval.signup") } unless Rails.configuration.enable_email_verification
end end
# Sign in automatically if email verification is disabled. send_registration_email if Rails.configuration.enable_email_verification
login(@user) && return unless Rails.configuration.enable_email_verification
# Start email verification and redirect to root. # Sign in automatically if email verification is disabled or if user is already verified.
begin login(@user) && return if !Rails.configuration.enable_email_verification || @user.email_verified
send_activation_email(@user)
rescue => e send_verification
logger.error "Error in email delivery: #{e}"
flash[:alert] = I18n.t(params[:message], default: I18n.t("delivery_error")) redirect_to root_path
else
flash[:success] = I18n.t("email_sent", email_type: t("verify.verification"))
end
redirect_to(root_path)
end end
# GET /signin # GET /signin
@ -63,11 +66,16 @@ class UsersController < ApplicationController
# GET /signup # GET /signup
def new def new
if Rails.configuration.allow_user_signup return redirect_to root_path unless Rails.configuration.allow_user_signup
@user = User.new
else # Check if the user needs to be invited
redirect_to root_path if invite_registration
redirect_to root_path, flash: { alert: I18n.t("registration.invite.no_invite") } unless params[:invite_token]
session[:invite_token] = params[:invite_token]
end end
@user = User.new
end end
# GET /u/:user_uid/edit # GET /u/:user_uid/edit
@ -174,4 +182,47 @@ class UsersController < ApplicationController
params.require(:user).permit(:name, :email, :image, :password, :password_confirmation, params.require(:user).permit(:name, :email, :image, :password, :password_confirmation,
:new_password, :provider, :accepted_terms, :language) :new_password, :provider, :accepted_terms, :language)
end end
def send_verification
# Start email verification and redirect to root.
begin
send_activation_email(@user)
rescue => e
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", email_type: t("verify.verification"))
end
end
def send_registration_email
begin
if invite_registration
send_invite_user_signup_email(@user)
elsif approval_registration
send_approval_user_signup_email(@user)
end
rescue => e
logger.error "Error in email delivery: #{e}"
flash[:alert] = I18n.t(params[:message], default: I18n.t("delivery_error"))
end
end
# Add validation errors to model if they exist
def valid_user_or_captcha
valid_user = @user.valid?
valid_captcha = Rails.configuration.recaptcha_enabled ? verify_recaptcha(model: @user) : true
valid_user && valid_captcha
end
# Checks if the user passes the requirements to be invited
def passes_invite_reqs
# check if user needs to be invited and IS invited
invitation = check_user_invited(@user.email, session[:invite_token], @user_domain)
@user.email_verified = true if invitation[:verified]
invitation[:present]
end
end end

View File

@ -18,4 +18,39 @@
module AdminsHelper module AdminsHelper
include Pagy::Frontend include Pagy::Frontend
def display_invite
current_page?(admins_path) && invite_registration
end
def registration_method
Setting.find_or_create_by!(provider: user_settings_provider).get_value("Registration Method")
end
def invite_registration
registration_method == Rails.configuration.registration_methods[:invite]
end
def approval_registration
registration_method == Rails.configuration.registration_methods[:approval]
end
def room_authentication_string
if Setting.find_or_create_by!(provider: user_settings_provider).get_value("Room Authentication") == "true"
I18n.t("administrator.site_settings.authentication.enabled")
else
I18n.t("administrator.site_settings.authentication.disabled")
end
end
def registration_method_string
case registration_method
when Rails.configuration.registration_methods[:open]
I18n.t("administrator.site_settings.registration.methods.open")
when Rails.configuration.registration_methods[:invite]
I18n.t("administrator.site_settings.registration.methods.invite")
when Rails.configuration.registration_methods[:approval]
I18n.t("administrator.site_settings.registration.methods.approval")
end
end
end end

View File

@ -22,4 +22,9 @@ module RoomsHelper
def google_calendar_path def google_calendar_path
"http://calendar.google.com/calendar/r/eventedit?text=#{@room.name}&location=#{request.base_url + request.fullpath}" "http://calendar.google.com/calendar/r/eventedit?text=#{@room.name}&location=#{request.base_url + request.fullpath}"
end end
def room_authentication_required
Setting.find_or_create_by!(provider: user_settings_provider).get_value("Room Authentication") == "true" &&
current_user.nil?
end
end end

View File

@ -34,4 +34,55 @@ class UserMailer < ApplicationMailer
@color = color @color = color
mail to: user.email, subject: t('reset_password.subtitle') mail to: user.email, subject: t('reset_password.subtitle')
end end
def user_promoted(user, url, image, color)
@url = url
@admin_url = url + "admins"
@image = image
@color = color
mail to: user.email, subject: t('mailer.user.promoted.subtitle')
end
def user_demoted(user, url, image, color)
@url = url
@root_url = url
@image = image
@color = color
mail to: user.email, subject: t('mailer.user.demoted.subtitle')
end
def invite_email(name, email, url, image, color)
@name = name
@email = email
@url = url
@image = image
@color = color
mail to: email, subject: t('mailer.user.invite.subject')
end
def approve_user(user, url, image, color)
@user = user
@url = url
@image = image
@color = color
mail to: user.email, subject: t('mailer.user.approve.subject')
end
def approval_user_signup(user, url, image, color, admin_emails)
@user = user
@url = url
@image = image
@color = color
mail to: admin_emails, subject: t('mailer.user.approve.signup.subject')
end
def invite_user_signup(user, url, image, color, admin_emails)
@user = user
@url = url
@image = image
@color = color
mail to: admin_emails, subject: t('mailer.user.invite.signup.subject')
end
end end

23
app/models/invitation.rb Normal file
View File

@ -0,0 +1,23 @@
# 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 <http://www.gnu.org/licenses/>.
class Invitation < ApplicationRecord
has_secure_token :invite_token
scope :valid, -> { where(updated_at: (Time.now - 48.hours)..Time.now) }
end

View File

@ -37,6 +37,10 @@ class Setting < ApplicationRecord
Rails.configuration.branding_image_default Rails.configuration.branding_image_default
when "Primary Color" when "Primary Color"
Rails.configuration.primary_color_default Rails.configuration.primary_color_default
when "Registration Method"
Rails.configuration.registration_method_default
when "Room Authentication"
false
end end
end end
end end

View File

@ -111,8 +111,8 @@ class User < ApplicationRecord
"created_at" "created_at"
end end
search_query = "name LIKE :search OR email LIKE :search OR username LIKE :search" \ search_query = "users.name LIKE :search OR email LIKE :search OR username LIKE :search" \
" OR #{created_at_query} LIKE :search OR provider LIKE :search" " OR users.#{created_at_query} LIKE :search OR provider LIKE :search"
search_param = "%#{string}%" search_param = "%#{string}%"
where(search_query, search: search_param) where(search_query, search: search_param)
end end

View File

@ -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 <http://www.gnu.org/licenses/>.
%>
<div class="container text-center pt-9">
<div class="display-1 text-muted mb-5"><%= I18n.t("errors.bigbluebutton.title") %></div>
<h1 class="h2 mb-3"><%= I18n.t("errors.bigbluebutton.message") %></h1>
<p class="h4 text-muted font-weight-normal mb-7"><%= I18n.t("errors.bigbluebutton.help", doc_link: "http://docs.bigbluebutton.org/greenlight/gl-install.html#setting-bigbluebutton-credentials").html_safe %></p>
</div>

View File

@ -15,6 +15,6 @@
<div class="container text-center pt-9"> <div class="container text-center pt-9">
<div class="display-1 text-muted mb-5">401</div> <div class="display-1 text-muted mb-5">401</div>
<h1 class="h2 mb-3"><%= t("errors.unauthorized.message") %></h1> <h1 class="h2 mb-3"><%= I18n.t("errors.unauthorized.message") %></h1>
<p class="h4 text-muted font-weight-normal mb-7"><%= t("errors.unauthorized.help") %></p> <p class="h4 text-muted font-weight-normal mb-7"><%= I18n.t("errors.unauthorized.help") %></p>
</div> </div>

View File

@ -14,18 +14,22 @@
%> %>
<%= render 'shared/room_event' do %> <%= render 'shared/room_event' do %>
<%= form_for room_path(@room), method: :post do |f| %> <% if room_authentication_required %>
<div class="input-group join-input"> <h2><%= t("administrator.site_settings.authentication.user-info") %></h2>
<%= f.hidden_field(:search, :value => params[:search])%> <% else %>
<%= f.hidden_field(:column, :value => params[:column])%> <%= form_for room_path(@room), method: :post do |f| %>
<%= f.hidden_field(:direction, :value => params[:direction])%> <div class="input-group join-input">
<%= f.text_field :join_name, <%= f.hidden_field(:search, :value => params[:search])%>
required: true, <%= f.hidden_field(:column, :value => params[:column])%>
class: "form-control join-form", <%= f.hidden_field(:direction, :value => params[:direction])%>
placeholder: t("enter_your_name"), <%= f.text_field :join_name,
value: "#{@name}", required: true,
readonly: !current_user.nil? %> class: "form-control join-form",
<%= f.submit t("room.join"), class: "btn btn-primary btn-sm col-sm-3 form-control join-form" %> placeholder: t("enter_your_name"),
</div> value: "#{@name}",
readonly: !current_user.nil? %>
<%= f.submit t("room.join"), class: "btn btn-primary btn-sm col-sm-3 form-control join-form" %>
</div>
<% end %>
<% end %> <% end %>
<% end %> <% end %>

View File

@ -16,7 +16,7 @@
<div class="form-group"> <div class="form-group">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="mb-7 form-group"> <div class="mb-6 form-group">
<label class="form-label"><%= t("administrator.site_settings.branding.title") %></label> <label class="form-label"><%= t("administrator.site_settings.branding.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.branding.info") %></label> <label class="form-label text-muted"><%= t("administrator.site_settings.branding.info") %></label>
<div class="input-group"> <div class="input-group">
@ -26,22 +26,77 @@
</span> </span>
</div> </div>
</div> </div>
</div>
<div class="form-group"> </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"><%= t("administrator.site_settings.color.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.color.info") %></label> <label class="form-label text-muted"><%= t("administrator.site_settings.color.info") %></label>
<div class="row gutters-xs"> <div class="color-inputs">
<div class="col-auto"> <input id="coloring-path-regular" type="hidden" value="<%= admin_coloring_path%>">
<input id="coloring-path" value="<%= admin_coloring_path %>" hidden> <input id="coloring-path-lighten" type="hidden" value="<%= admin_coloring_lighten_path%>">
<input id="user-colour" value="<%= user_color %>" hidden/> <input id="coloring-path-darken" type="hidden" value="<%= admin_coloring_darken_path%>">
<div class="colorinput">
<span class="colorinput-color" style="background: <%= user_color %>;"> <div id="colorinput-regular" class="btn primary-regular mr-3">
<i class="p-1 fas fa-paint-brush"></i> <%= t("administrator.site_settings.color.regular") %>
</span> </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>
</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("open"), class: "dropdown-item" do %>
<%= t("administrator.site_settings.registration.methods.open") %>
<% end %>
<%= button_to admin_change_registration_path("invite"), class: "dropdown-item" do %>
<%= t("administrator.site_settings.registration.methods.invite") %>
<% end %>
<%= button_to admin_change_registration_path("approval"), class: "dropdown-item" do %>
<%= t("administrator.site_settings.registration.methods.approval") %>
<% 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.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_room_authentication_path(value: "true"), class: "dropdown-item" do %>
<%= t("administrator.site_settings.authentication.enabled") %>
<% end %>
<%= button_to admin_room_authentication_path(value: "false"), class: "dropdown-item" do %>
<%= t("administrator.site_settings.authentication.disabled") %>
<% end %>
</div>
</div>
</div>
</div>
</div>
</div> </div>

View File

@ -13,6 +13,10 @@
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. # with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
%> %>
<% if @role.present? %>
<%= render "shared/components/admins_tags" %>
<% end %>
<div class="form-group"> <div class="form-group">
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
@ -68,27 +72,25 @@
<td><%= user.email && user.email != "" ? user.email : user.username%></td> <td><%= user.email && user.email != "" ? user.email : user.username%></td>
<td><%= user.provider %></td> <td><%= user.provider %></td>
<td class="text-center"> <td class="text-center">
<% roles = user.roles().pluck(:name) %> <% roles = user.roles().pluck(:name) %>
<% if roles.include?("denied")%> <%= render "shared/components/admins_role", roles: roles %>
<div class="user-role btn btn-sm btn-gray-dark">
<%= t("roles.banned") %>
</div>
<% elsif roles.include?("super_admin") %>
<div class="user-role btn btn-sm btn-red">
<%= t("roles.super_admin") %>
</div>
<% elsif roles.include?("admin") %>
<div class="user-role btn btn-sm btn-yellow">
<%= t("roles.administrator") %>
</div>
<% else %>
<div class="user-role btn btn-sm btn-gray">
<%= t("roles.user") %>
</div>
<% end %>
</td> </td>
<td> <td>
<% unless roles.include?("super_admin") %> <% if roles.include?("pending") %>
<div class="item-action dropdown">
<a href="javascript:void(0)" data-toggle="dropdown" class="icon">
<i class="fas fa-ellipsis-v px-4"></i>
</a>
<div class="dropdown-menu dropdown-menu">
<%= button_to admin_approve_path(user_uid: user.uid), class: "dropdown-item" do %>
<i class="dropdown-icon far fa-check-circle"></i> <%= t("administrator.users.settings.approve") %>
<% end %>
<%= button_to admin_ban_path(user_uid: user.uid), class: "dropdown-item" do %>
<i class="dropdown-icon far fa-times-circle"></i> <%= t("administrator.users.settings.decline") %>
<% end %>
</div>
</div>
<% elsif !roles.include?("super_admin") %>
<div class="item-action dropdown"> <div class="item-action dropdown">
<a href="javascript:void(0)" data-toggle="dropdown" class="icon"> <a href="javascript:void(0)" data-toggle="dropdown" class="icon">
<i class="fas fa-ellipsis-v px-4"></i> <i class="fas fa-ellipsis-v px-4"></i>
@ -142,3 +144,5 @@
</div> </div>
</div> </div>
</div> </div>
<%= render "shared/modals/invite_user_modal" %>

View File

@ -0,0 +1,36 @@
<%
# 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/>.
%>
<% if roles.include?("denied")%>
<button class="user-role btn btn-sm btn-gray-dark" onclick="filterRole('denied')">
<%= t("roles.banned") %>
</button>
<% elsif roles.include?("pending") %>
<button class="user-role btn btn-sm btn-cyan" onclick="filterRole('pending')">
<%= t("roles.pending") %>
</button>
<% elsif roles.include?("super_admin") %>
<button class="user-role btn btn-sm btn-red" onclick="filterRole('super_admin')">
<%= t("roles.super_admin") %>
</button>
<% elsif roles.include?("admin") %>
<button class="user-role btn btn-sm btn-yellow" onclick="filterRole('admin')">
<%= t("roles.administrator") %>
</button>
<% else %>
<button class="user-role btn btn-sm btn-gray" onclick="filterRole('user')">
<%= t("roles.user") %>
</button>
<% end %>

View File

@ -0,0 +1,57 @@
<%
# 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">
<div class="col-12 tags">
<% if @role == "denied"%>
<span class="tag tag-gray-dark">
<%= t("roles.banned") %>
<a class="tag-addon clear-role">
<i class="fas fa-times"></i>
</a>
</span>
<% elsif @role == "pending" %>
<span class="tag tag-cyan">
<%= t("roles.pending") %>
<a class="tag-addon clear-role">
<i class="fas fa-times"></i>
</a>
</span>
<% elsif @role == "super_admin" %>
<span class="tag tag-red">
<%= t("roles.super_admin") %>
<a class="tag-addon clear-role">
<i class="fas fa-times"></i>
</a>
</span>
<% elsif @role == "admin" %>
<span class="tag tag-yellow">
<%= t("roles.administrator") %>
<a class="tag-addon clear-role">
<i class="fas fa-times"></i>
</a>
</span>
<% else %>
<span class="tag tag-gray">
<%= t("roles.user") %>
<a class="tag-addon clear-role">
<i class="fas fa-times"></i>
</a>
</span>
<% end %>
</div>
</div>
</div>

View File

@ -14,12 +14,20 @@
%> %>
<div class="row mt-2"> <div class="row mt-2">
<div class="col-8"> <div class="col-4">
<p class="subtitle"><%= subtitle %></p> <p class="subtitle"><%= subtitle %></p>
</div> </div>
<% if search %> <% if search %>
<div class="col-4"> <div class="col-8">
<div id="search-bar"> <% if display_invite %>
<div id="invite-user" class="d-inline-block float-right ml-3">
<%= link_to "#inviteModal", :class => "btn btn-primary", "data-toggle": "modal" do %>
<%= t("administrator.users.invite") %> <i class="fas fa-paper-plane ml-1"></i>
<% end %>
</div>
<% end %>
<div id="search-bar" class="d-inline-block float-right">
<div class="input-group"> <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 %>">
<% unless @search.blank? %> <% unless @search.blank? %>
@ -28,7 +36,7 @@
</span> </span>
<% end %> <% end %>
<span class="input-group-append"> <span class="input-group-append">
<button class="btn btn-primary" type="button" onclick="searchPage()"> <button class="btn btn-outline-primary" type="button" onclick="searchPage()">
<i class="fas fa-search"></i> <i class="fas fa-search"></i>
</button> </button>
</span> </span>

View File

@ -0,0 +1,44 @@
<%
# 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="inviteModal" 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-6">
<div class="card-title">
<h3><%= t("modal.invite_user.title") %></h3>
</div>
<%= form_for(:invite_user, url: invite_user_path) do |f| %>
<div class="input-icon mb-2">
<span class="input-icon-addon">
<i class="fas fa-envelope"></i>
</span>
<%= f.text_field :email, class: "form-control", value: "", placeholder: t("modal.invite_user.email_placeholder"), autocomplete: :off %>
<div class="invalid-feedback text-left"><%= t("modal.invite_user.not_blank") %></div>
</div>
<div class="mt-4">
<%= f.submit t("modal.invite_user.send"), class:"btn btn-primary btn-block" %>
</div>
<% end %>
</div>
<div class="card-footer">
<p><%= t("modal.invite_user.footer") %></p>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,43 @@
<%
# 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 style="text-align:center; font-family:'Source Sans Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif">
<div style="display:inline-block; background-color:#F5F7FB; border:1px solid #d3d3d3; padding: 25px 70px">
<%= image_tag(@image, height: '70') %>
<h1 style="margin-bottom:30px">
<%= t('mailer.user.approve.signup.subject') %>
</h1>
<p>
<%= t('mailer.user.approve.signup.info') %>
</p>
<p>
<%= t('mailer.user.approve.signup.username', name: @user.name, email: @user.email) %>
</p>
<p style="margin-bottom:35px;">
<%= t('mailer.user.approve.signup.more-info') %>
</p>
<a style="background: <%= @color %>;color: #ffffff; padding: 10px 15px; box-shadow: 0 2px 4px 0 rgba(0,0,0,.25);border: 1px solid transparent;text-decoration:none;" href="<%= @url %>">
<%= t('mailer.user.approve.signup.admins_link') %>
</a>
</div>
</div>

View File

@ -0,0 +1,27 @@
<%
# 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/>.
%>
<%= t('mailer.user.approve.signup.subject') %>
<%= t('mailer.user.approve.signup.info') %>
<%= t('mailer.user.approve.signup.username', name: @user.name, email: @user.email) %>
<%= t('mailer.user.approve.signup.more-info') %>
<%= @url %>

View File

@ -0,0 +1,43 @@
<%
# 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 style="text-align:center; font-family:'Source Sans Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif">
<div style="display:inline-block; background-color:#F5F7FB; border:1px solid #d3d3d3; padding: 25px 70px">
<%= image_tag(@image, height: '70') %>
<h1 style="margin-bottom:30px">
<%= t('mailer.user.approve.subject') %>
</h1>
<p>
<%= t('mailer.user.approve.info') %>
</p>
<p>
<%= t('mailer.user.approve.username', email: @user.email) %>
</p>
<p style="margin-bottom:35px;">
<%= t('mailer.user.approve.signin') %>
</p>
<a style="background: <%= @color %>;color: #ffffff; padding: 10px 15px; box-shadow: 0 2px 4px 0 rgba(0,0,0,.25);border: 1px solid transparent;text-decoration:none;" href="<%= @url %>">
<%= t('mailer.user.approve.signin_link') %>
</a>
</div>
</div>

View File

@ -0,0 +1,27 @@
<%
# 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/>.
%>
<%= t('mailer.user.approve.subject') %>
<%= t('mailer.user.approve.info') %>
<%= t('mailer.user.approve.username', email: @user.email) %>
<%= t('mailer.user.approve.signin') %>
<%= @url %>

View File

@ -0,0 +1,43 @@
<%
# 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 style="text-align:center; font-family:'Source Sans Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif">
<div style="display:inline-block; background-color:#F5F7FB; border:1px solid #d3d3d3; padding: 25px 70px">
<%= image_tag(@image, height: '70') %>
<h1 style="margin-bottom:30px">
<%= t('mailer.user.invite.subject') %>
</h1>
<p>
<%= t('mailer.user.invite.info', name: @name) %>
</p>
<p>
<%= t('mailer.user.invite.username', email: @email) %>
</p>
<p style="margin-bottom:35px;">
<%= t('mailer.user.invite.signup') %>
</p>
<a style="background: <%= @color %>;color: #ffffff; padding: 10px 15px; box-shadow: 0 2px 4px 0 rgba(0,0,0,.25);border: 1px solid transparent;text-decoration:none;" href="<%= @url %>">
<%= t('mailer.user.invite.signup_link') %>
</a>
</div>
</div>

View File

@ -0,0 +1,27 @@
<%
# 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/>.
%>
<%= t('mailer.user.invite.subject') %>
<%= t('mailer.user.invite.info', name: @name) %>
<%= t('mailer.user.invite.username', email: @email) %>
<%= t('mailer.user.invite.signup') %>
<%= @url %>

View File

@ -0,0 +1,39 @@
<%
# 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 style="text-align:center; font-family:'Source Sans Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif">
<div style="display:inline-block; background-color:#F5F7FB; border:1px solid #d3d3d3; padding: 25px 70px">
<%= image_tag(@image, height: '70') %>
<h1 style="margin-bottom:30px">
<%= t('mailer.user.invite.signup.subject') %>
</h1>
<p>
<%= t('mailer.user.invite.signup.info') %>
</p>
<p style="margin-bottom:35px;">
<%= t('mailer.user.invite.signup.username', name: @user.name, email: @user.email) %>
</p>
<a style="background: <%= @color %>;color: #ffffff; padding: 10px 15px; box-shadow: 0 2px 4px 0 rgba(0,0,0,.25);border: 1px solid transparent;text-decoration:none;" href="<%= @url %>">
<%= t('mailer.user.invite.signup.admins_link') %>
</a>
</div>
</div>

View File

@ -0,0 +1,25 @@
<%
# 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/>.
%>
<%= t('mailer.user.invite.signup.subject') %>
<%= t('mailer.user.invite.signup.info') %>
<%= t('mailer.user.invite.signup.username', name: @user.name, email: @user.email) %>
<%= @url %>

View File

@ -0,0 +1,39 @@
<%
# 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 style="text-align:center; font-family:'Source Sans Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif">
<div style="display:inline-block; background-color:#F5F7FB; border:1px solid #d3d3d3; padding: 25px 70px; width: 50%">
<%= image_tag(@image, height: '70') %>
<h1 style="margin-bottom:30px">
<%= t('mailer.user.demoted.subtitle') %>
</h1>
<p>
<%= t('mailer.user.demoted.info', url: @url) %>
</p>
<p style="margin-bottom:45px;">
<%= t('mailer.user.demoted.more-info') %>
</p>
<a style="background: <%= @color %>;color: #ffffff; padding: 10px 15px; box-shadow: 0 2px 4px 0 rgba(0,0,0,.25);border: 1px solid transparent;text-decoration:none;" href="<%= @root_url %>">
<%= t('mailer.user.demoted.root_link') %>
</a>
</div>
</div>

View File

@ -0,0 +1,26 @@
<%
# 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/>.
%>
<%= t('mailer.user.demoted.subtitle') %>
<%= t('mailer.user.demoted.info', url: @url) %>
<%= t('mailer.user.demoted.more-info') %>
<%= @root_url %>

View File

@ -0,0 +1,39 @@
<%
# 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 style="text-align:center; font-family:'Source Sans Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif">
<div style="display:inline-block; background-color:#F5F7FB; border:1px solid #d3d3d3; padding: 25px 70px; width: 50%">
<%= image_tag(@image, height: '70') %>
<h1 style="margin-bottom:30px">
<%= t('mailer.user.promoted.subtitle') %>
</h1>
<p>
<%= t('mailer.user.promoted.info', url: @url) %>
</p>
<p style="margin-bottom:45px;">
<%= t('mailer.user.promoted.more-info') %>
</p>
<a style="background: <%= @color %>;color: #ffffff; padding: 10px 15px; box-shadow: 0 2px 4px 0 rgba(0,0,0,.25);border: 1px solid transparent;text-decoration:none;" href="<%= @admin_url %>">
<%= t('mailer.user.promoted.admins_link') %>
</a>
</div>
</div>

View File

@ -0,0 +1,26 @@
<%
# 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/>.
%>
<%= t('mailer.user.promoted.subtitle') %>
<%= t('mailer.user.promoted.info', url: @url) %>
<%= t('mailer.user.promoted.more-info') %>
<%= @admin_url %>

View File

@ -52,8 +52,17 @@ module Greenlight
config.bigbluebutton_secret_default = "8cd8ef52e8e101574e400365b55e11a6" config.bigbluebutton_secret_default = "8cd8ef52e8e101574e400365b55e11a6"
# Use standalone BigBlueButton server. # Use standalone BigBlueButton server.
config.bigbluebutton_endpoint = ENV["BIGBLUEBUTTON_ENDPOINT"] || config.bigbluebutton_endpoint_default config.bigbluebutton_endpoint = if ENV["BIGBLUEBUTTON_ENDPOINT"].present?
config.bigbluebutton_secret = ENV["BIGBLUEBUTTON_SECRET"] || config.bigbluebutton_secret_default ENV["BIGBLUEBUTTON_ENDPOINT"]
else
config.bigbluebutton_endpoint_default
end
config.bigbluebutton_secret = if ENV["BIGBLUEBUTTON_SECRET"].present?
ENV["BIGBLUEBUTTON_SECRET"]
else
config.bigbluebutton_secret_default
end
# Fix endpoint format if required. # Fix endpoint format if required.
config.bigbluebutton_endpoint += "/" unless config.bigbluebutton_endpoint.ends_with?('/') config.bigbluebutton_endpoint += "/" unless config.bigbluebutton_endpoint.ends_with?('/')
@ -96,22 +105,36 @@ module Greenlight
# The maximum number of rooms included in one bbbapi call # The maximum number of rooms included in one bbbapi call
config.pagination_number = ENV['PAGINATION_NUMBER'].to_i.zero? ? 25 : ENV['PAGINATION_NUMBER'].to_i config.pagination_number = ENV['PAGINATION_NUMBER'].to_i.zero? ? 25 : ENV['PAGINATION_NUMBER'].to_i
# Default branding image if the user does not specify one
config.branding_image_default = "https://raw.githubusercontent.com/bigbluebutton/greenlight/master/app/assets/images/logo_with_text.png"
# Default primary color if the user does not specify one
config.primary_color_default = "#467fcf"
# Default admin password
config.admin_password_default = ENV['ADMIN_PASSWORD'] || 'administrator'
# Number of rows to display per page # Number of rows to display per page
config.pagination_rows = ENV['NUMBER_OF_ROWS'].to_i.zero? ? 10 : ENV['NUMBER_OF_ROWS'].to_i config.pagination_rows = ENV['NUMBER_OF_ROWS'].to_i.zero? ? 25 : ENV['NUMBER_OF_ROWS'].to_i
# Whether the user has defined the variables required for recaptcha # Whether the user has defined the variables required for recaptcha
config.recaptcha_enabled = ENV['RECAPTCHA_SITE_KEY'].present? && ENV['RECAPTCHA_SECRET_KEY'].present? config.recaptcha_enabled = ENV['RECAPTCHA_SITE_KEY'].present? && ENV['RECAPTCHA_SECRET_KEY'].present?
# Show/hide "Add to Google Calendar" button in the room page # Show/hide "Add to Google Calendar" button in the room page
config.enable_google_calendar_button = (ENV['ENABLE_GOOGLE_CALENDAR_BUTTON'] == "true") config.enable_google_calendar_button = (ENV['ENABLE_GOOGLE_CALENDAR_BUTTON'] == "true")
# Enum containing the different possible registration methods
config.registration_methods = { open: "0", invite: "1", approval: "2" }
# DEFAULTS
# Default branding image if the user does not specify one
config.branding_image_default = "https://raw.githubusercontent.com/bigbluebutton/greenlight/master/app/assets/images/logo_with_text.png"
# Default primary color if the user does not specify one
config.primary_color_default = "#467fcf"
# Default primary color lighten if the user does not specify one
config.primary_color_lighten_default = "#e8eff9"
# Default primary color darken if the user does not specify one
config.primary_color_darken_default = "#316cbe"
# Default registration method if the user does not specify one
config.registration_method_default = config.registration_methods[:open]
# Default admin password
config.admin_password_default = ENV['ADMIN_PASSWORD'] || 'administrator'
end end
end end

View File

@ -23,26 +23,48 @@ en:
accepted_terms: "Terms and Conditions" accepted_terms: "Terms and Conditions"
administrator: administrator:
site_settings: site_settings:
authentication:
disabled: Disabled
enabled: Enabled
info: Only allow authenticated users to join a room
title: Require Authentication for Rooms
user-info: You must sign in to Greenlight to join this room
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
placeholder: Image Url... placeholder: Image Url...
title: Branding Image title: Branding Image
color: color:
info: Change the primary color used across the website info: Changing the Regular Color will change both Lighten and Darken. Lighten and Darken can then be changed individually
title: Primary Color title: Primary Color
regular: Regular
lighten: Lighten
Darken: Darken
registration:
info: Change the way that users register to the website
title: Registration Method
methods:
approval: Approve/Decline
invite: Join by Invitation
open: Open Registration
subtitle: Customize Greenlight subtitle: Customize Greenlight
title: Site Settings title: Site Settings
flash: flash:
approved: User has been successfully approved.
banned: User has been successfully banned. banned: User has been successfully banned.
unbanned: User has been successfully unbanned. unbanned: User has been successfully unbanned.
delete: User deleted successfully delete: User deleted successfully
delete_fail: Failed to delete user delete_fail: Failed to delete user
demoted: User has been successfully demoted demoted: User has been successfully demoted
invite: Invite successfully sent to %{email}
invite_email_verification: ALLOW_MAIL_NOTIFICATIONS must be set to true in order to use this method
promoted: User has been successfully promoted promoted: User has been successfully promoted
registration_method_updated: Registration method successfully updated
settings: Site Settings successfully changed
unauthorized: You are not authorized to perform actions on this user unauthorized: You are not authorized to perform actions on this user
title: Organization Settings title: Organization Settings
users: users:
invite: Invite User
edit: edit:
title: Edit User Details title: Edit User Details
settings: settings:
@ -79,6 +101,10 @@ en:
email_sent: Your %{email_type} email has been sent! (Please check your Spam folder if you haven't received it) email_sent: Your %{email_type} email has been sent! (Please check your Spam folder if you haven't received it)
enter_your_name: Enter your name! enter_your_name: Enter your name!
errors: errors:
bigbluebutton:
help: Please make sure the proper steps have been taken. <a href="%{doc_link}">Learn more</a>
message: Invalid BigBlueButton Endpoint and Secret
title: Server Error
internal: internal:
message: Oh no! Looks like something went wrong on our end. message: Oh no! Looks like something went wrong on our end.
help: The error has been logged, we'll take a look! help: The error has been logged, we'll take a look!
@ -157,6 +183,34 @@ en:
login_title: Sign in to your account login_title: Sign in to your account
mailer: mailer:
user: user:
approve:
info: Your account has been approved.
signin: To access your personal rooms, click the button below and sign in.
signin_link: Sign In
signup:
info: A new user has signed up to use Greenlight.
more-info: To allow this user to access Greenlight you must approve their account in organization settings.
admins_link: Visit the Organization Page
subject: New Greenlight User Sign Up
username: The user signed up with the name %{name} and the email %{email}.
subject: Account Approved
username: Your username is %{email}.
demoted:
info: You are no longer an administrator on %{url}.
more-info: You now have the same privileges as a regular user and will no longer be able to access any of the Administrator settings.
root_link: Visit the Organization Page
subtitle: Administrator Rights Rescinded
invite:
info: You have been invited to your own personal space by %{name}
signup: To signup using your email, click the button below and follow the steps.
signup_link: Sign Up
signup:
info: A user that was invited has signed up to use Greenlight.
admins_link: Visit the Organization Page
subject: New Greenlight User Sign Up
username: The user signed up with the name %{name} and the email %{email}.
subject: Invitation to join BigBlueButton
username: Your username is %{email}.
password_reset: password_reset:
title: 'Password reset' title: 'Password reset'
welcome: It seems like you forgot your password for %{bigbluebutton} welcome: It seems like you forgot your password for %{bigbluebutton}
@ -164,6 +218,11 @@ en:
reset_link: Reset Password reset_link: Reset Password
expire: This link will expire in two hours. expire: This link will expire in two hours.
ignore: You can safely ignore this email if you did not request a password reset. ignore: You can safely ignore this email if you did not request a password reset.
promoted:
admins_link: Visit the Organization Page
info: You are now an administrator on %{url}.
more-info: As an administrator, you can manage users, their role and configure your site settings by changing the logo and brand colour.
subtitle: Administrator Rights Granted
verify_email: verify_email:
welcome: Welcome to your personal space, %{name}! welcome: Welcome to your personal space, %{name}!
success: Leveraging %{bigbluebutton}, you can create your own rooms to host sessions and collaborate with others. success: Leveraging %{bigbluebutton}, you can create your own rooms to host sessions and collaborate with others.
@ -191,6 +250,11 @@ en:
delete: I'm sure, delete this room. delete: I'm sure, delete this room.
keep: On second thought, I'll keep it. keep: On second thought, I'll keep it.
warning: You will <b>not</b> be able to recover this room or any of its %{recordings_num} associated recordings. warning: You will <b>not</b> be able to recover this room or any of its %{recordings_num} associated recordings.
invite_user:
email_placeholder: Enter the user's email
footer: The user will receive an email with instructions on how to sign up
send: Send Invite
title: Invite User
login: login:
or: or or: or
with: Sign in with %{provider} with: Sign in with %{provider}
@ -246,6 +310,15 @@ en:
unlisted: Unlisted unlisted: Unlisted
format: format:
presentation: Presentation presentation: Presentation
registration:
approval:
fail: Your account has not been approved yet. If multiples days have passed since you signed up, please contact your administrator.
signup: Your account was successfully created. It has been sent to an administrator for approval.
banned:
fail: You do not have access to this application. If you believe this is a mistake, please contact your administrator.
invite:
fail: Your token is either invalid or has expired. If you believe this is a mistake, please contact your administrator.
no_invite: You do not have an invitation to join. Please contact your administrator to receive one.
rename: Rename rename: Rename
reset_password: reset_password:
subtitle: Reset Password subtitle: Reset Password
@ -255,6 +328,7 @@ en:
roles: roles:
administrator: Administrator administrator: Administrator
banned: Banned banned: Banned
pending: Pending
super_admin: Super Admin super_admin: Super Admin
user: User user: User
room: room:

View File

@ -39,12 +39,18 @@ Rails.application.routes.draw do
scope '/admins' do scope '/admins' do
post '/branding', to: 'admins#branding', as: :admin_branding post '/branding', to: 'admins#branding', as: :admin_branding
post '/coloring', to: 'admins#coloring', as: :admin_coloring post '/coloring', to: 'admins#coloring', as: :admin_coloring
post '/room_authentication', to: 'admins#room_authentication', as: :admin_room_authentication
post '/coloring_lighten', to: 'admins#coloring_lighten', as: :admin_coloring_lighten
post '/coloring_darken', to: 'admins#coloring_darken', as: :admin_coloring_darken
post '/signup', to: 'admins#signup', as: :admin_signup post '/signup', to: 'admins#signup', as: :admin_signup
get '/edit/:user_uid', to: 'admins#edit_user', as: :admin_edit_user get '/edit/:user_uid', to: 'admins#edit_user', as: :admin_edit_user
post '/promote/:user_uid', to: 'admins#promote', as: :admin_promote post '/promote/:user_uid', to: 'admins#promote', as: :admin_promote
post '/demote/:user_uid', to: 'admins#demote', as: :admin_demote post '/demote/:user_uid', to: 'admins#demote', as: :admin_demote
post '/ban/:user_uid', to: 'admins#ban_user', as: :admin_ban post '/ban/:user_uid', to: 'admins#ban_user', as: :admin_ban
post '/unban/:user_uid', to: 'admins#unban_user', as: :admin_unban post '/unban/:user_uid', to: 'admins#unban_user', as: :admin_unban
post '/invite', to: 'admins#invite', as: :invite_user
post '/registration_method/:method', to: 'admins#registration_method', as: :admin_change_registration
post '/approve/:user_uid', to: 'admins#approve', as: :admin_approve
end end
scope '/themes' do scope '/themes' do

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
class CreateInvitations < ActiveRecord::Migration[5.0]
def change
create_table :invitations do |t|
t.string "email", null: false
t.string "provider", null: false
t.string "invite_token"
t.timestamps
end
end
end

View File

@ -0,0 +1,23 @@
# 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 <http://www.gnu.org/licenses/>.
class AddIndexToSettings < ActiveRecord::Migration[5.0]
def change
add_index :settings, :provider
end
end

View File

@ -0,0 +1,23 @@
# 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 <http://www.gnu.org/licenses/>.
class AddIndexToFeatures < ActiveRecord::Migration[5.0]
def change
add_index :features, :name
end
end

View File

@ -0,0 +1,25 @@
# 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 <http://www.gnu.org/licenses/>.
class AddIndexToUsers < ActiveRecord::Migration[5.0]
def change
add_index :users, :email
add_index :users, :provider
add_index :users, :created_at
end
end

View File

@ -0,0 +1,24 @@
# 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 <http://www.gnu.org/licenses/>.
class AddIndexToInvitations < ActiveRecord::Migration[5.0]
def change
add_index :invitations, :invite_token
add_index :invitations, :provider
end
end

View File

@ -10,7 +10,7 @@
# #
# 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: 20190326144939) do ActiveRecord::Schema.define(version: 20190522195242) do
create_table "features", force: :cascade do |t| create_table "features", force: :cascade do |t|
t.integer "setting_id" t.integer "setting_id"
@ -19,9 +19,20 @@ ActiveRecord::Schema.define(version: 20190326144939) do
t.boolean "enabled", default: false t.boolean "enabled", default: false
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.index ["name"], name: "index_features_on_name"
t.index ["setting_id"], name: "index_features_on_setting_id" t.index ["setting_id"], name: "index_features_on_setting_id"
end end
create_table "invitations", force: :cascade do |t|
t.string "email", null: false
t.string "provider", null: false
t.string "invite_token"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["invite_token"], name: "index_invitations_on_invite_token"
t.index ["provider"], name: "index_invitations_on_provider"
end
create_table "roles", force: :cascade do |t| create_table "roles", force: :cascade do |t|
t.string "name" t.string "name"
t.string "resource_type" t.string "resource_type"
@ -57,6 +68,7 @@ ActiveRecord::Schema.define(version: 20190326144939) do
t.string "provider", null: false t.string "provider", null: false
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.index ["provider"], name: "index_settings_on_provider"
end end
create_table "users", force: :cascade do |t| create_table "users", force: :cascade do |t|
@ -78,7 +90,10 @@ ActiveRecord::Schema.define(version: 20190326144939) do
t.datetime "reset_sent_at" t.datetime "reset_sent_at"
t.string "activation_digest" t.string "activation_digest"
t.datetime "activated_at" t.datetime "activated_at"
t.index ["created_at"], name: "index_users_on_created_at"
t.index ["email"], name: "index_users_on_email"
t.index ["password_digest"], name: "index_users_on_password_digest", unique: true t.index ["password_digest"], name: "index_users_on_password_digest", unique: true
t.index ["provider"], name: "index_users_on_provider"
t.index ["room_id"], name: "index_users_on_room_id" t.index ["room_id"], name: "index_users_on_room_id"
end end

View File

@ -16,15 +16,17 @@ namespace :conf do
end end
passed passed
endpoint = fix_endpoint_format(ENV['BIGBLUEBUTTON_ENDPOINT'])
# Tries to establish a connection to the BBB server from Greenlight # Tries to establish a connection to the BBB server from Greenlight
print "Checking Connection" print "Checking Connection"
test_request(ENV['BIGBLUEBUTTON_ENDPOINT']) test_request(endpoint)
passed passed
# Tests the checksum on the getMeetings api call # Tests the checksum on the getMeetings api call
print "Checking Secret" print "Checking Secret"
checksum = Digest::SHA1.hexdigest("getMeetings#{ENV['BIGBLUEBUTTON_SECRET']}") checksum = Digest::SHA1.hexdigest("getMeetings#{ENV['BIGBLUEBUTTON_SECRET']}")
test_request("#{ENV['BIGBLUEBUTTON_ENDPOINT']}getMeetings?checksum=#{checksum}") test_request("#{endpoint}getMeetings?checksum=#{checksum}")
passed passed
if ENV['ALLOW_MAIL_NOTIFICATIONS'] == 'true' if ENV['ALLOW_MAIL_NOTIFICATIONS'] == 'true'
@ -61,6 +63,15 @@ rescue => e
failed("Error connecting to BigBlueButton server - #{e}") failed("Error connecting to BigBlueButton server - #{e}")
end end
def fix_endpoint_format(url)
# Fix endpoint format if required.
url += "/" unless url.ends_with?('/')
url += "api/" if url.ends_with?('bigbluebutton/')
url += "bigbluebutton/api/" unless url.ends_with?('bigbluebutton/api/')
url
end
def failed(msg) def failed(msg)
print(": Failed\n#{msg}\n") print(": Failed\n#{msg}\n")
exit exit

View File

@ -136,8 +136,8 @@ ROOM_FEATURES=default-client,mute-on-join
PAGINATION_NUMBER=25 PAGINATION_NUMBER=25
# Specify the maximum number of rows that should be displayed per page for a paginated table # Specify the maximum number of rows that should be displayed per page for a paginated table
# Default is set to 10 rows # Default is set to 25 rows
NUMBER_OF_ROWS=10 NUMBER_OF_ROWS=25
# Specify if you want to display the Google Calendar button # Specify if you want to display the Google Calendar button
# ENABLE_GOOGLE_CALENDAR_BUTTON=true|false # ENABLE_GOOGLE_CALENDAR_BUTTON=true|false

View File

@ -72,6 +72,17 @@ describe AccountActivationsController, type: :controller do
expect(flash[:alert]).to be_present expect(flash[:alert]).to be_present
expect(response).to redirect_to(root_path) expect(response).to redirect_to(root_path)
end end
it "redirects a pending user to root with a flash" do
@user = create(:user, email_verified: false, provider: "greenlight")
@user.add_role :pending
get :edit, params: { email: @user.email, token: @user.activation_token }
expect(flash[:success]).to be_present
expect(response).to redirect_to(root_path)
end
end end
describe "GET #resend" do describe "GET #resend" do

View File

@ -26,6 +26,10 @@ describe AdminsController, type: :controller do
end end
describe "User Roles" do describe "User Roles" do
before do
allow(Rails.configuration).to receive(:enable_email_verification).and_return(true)
end
context "GET #index" do context "GET #index" do
it "renders a 404 if a user tries to acccess it" do it "renders a 404 if a user tries to acccess it" do
@request.session[:user_id] = @user.id @request.session[:user_id] = @user.id
@ -64,6 +68,14 @@ describe AdminsController, type: :controller do
expect(flash[:success]).to be_present expect(flash[:success]).to be_present
expect(response).to redirect_to(admins_path) expect(response).to redirect_to(admins_path)
end end
it "sends an email to the user being promoted" do
@request.session[:user_id] = @admin.id
params = { user_uid: @user.uid }
expect { post :promote, params: params }.to change { ActionMailer::Base.deliveries.count }.by(1)
end
end end
context "POST #demote" do context "POST #demote" do
@ -79,6 +91,16 @@ describe AdminsController, type: :controller do
expect(flash[:success]).to be_present expect(flash[:success]).to be_present
expect(response).to redirect_to(admins_path) expect(response).to redirect_to(admins_path)
end end
it "sends an email to the user being demoted" do
@request.session[:user_id] = @admin.id
@user.add_role :admin
params = { user_uid: @user.uid }
expect { post :demote, params: params }.to change { ActionMailer::Base.deliveries.count }.by(1)
end
end end
context "POST #ban" do context "POST #ban" do
@ -109,6 +131,56 @@ describe AdminsController, type: :controller do
expect(response).to redirect_to(admins_path) expect(response).to redirect_to(admins_path)
end end
end end
context "POST #invite" do
before do
allow(Rails.configuration).to receive(:loadbalanced_configuration).and_return(true)
allow_any_instance_of(ApplicationController).to receive(:allow_greenlight_users?).and_return(true)
allow_any_instance_of(User).to receive(:greenlight_account?).and_return(true)
end
it "invites a user" do
@request.session[:user_id] = @admin.id
email = Faker::Internet.email
post :invite, params: { invite_user: { email: email } }
invite = Invitation.find_by(email: email, provider: "greenlight")
expect(invite.present?).to eq(true)
expect(flash[:success]).to be_present
expect(response).to redirect_to(admins_path)
end
it "sends an invitation email" do
@request.session[:user_id] = @admin.id
email = Faker::Internet.email
params = { invite_user: { email: email } }
expect { post :invite, params: params }.to change { ActionMailer::Base.deliveries.count }.by(1)
end
end
context "POST #approve" do
it "approves a pending user" do
@request.session[:user_id] = @admin.id
@user.add_role :pending
post :approve, params: { user_uid: @user.uid }
expect(@user.has_role?(:pending)).to eq(false)
expect(flash[:success]).to be_present
expect(response).to redirect_to(admins_path)
end
it "sends the user an email telling them theyre approved" do
@request.session[:user_id] = @admin.id
@user.add_role :pending
params = { user_uid: @user.uid }
expect { post :approve, params: params }.to change { ActionMailer::Base.deliveries.count }.by(1)
end
end
end end
describe "User Design" do describe "User Design" do
@ -135,14 +207,91 @@ describe AdminsController, type: :controller do
allow_any_instance_of(User).to receive(:greenlight_account?).and_return(true) allow_any_instance_of(User).to receive(:greenlight_account?).and_return(true)
@request.session[:user_id] = @admin.id @request.session[:user_id] = @admin.id
primary_color = "#000000" primary_color = Faker::Color.hex_color
post :coloring, params: { color: primary_color } post :coloring, params: { color: primary_color }
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(admins_path(setting: "site_settings")) expect(response).to redirect_to(admins_path)
end
it "changes the primary-lighten on the page" 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
primary_color = Faker::Color.hex_color
post :coloring_lighten, params: { color: primary_color }
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Primary Color Lighten")
expect(feature[:value]).to eq(primary_color)
expect(response).to redirect_to(admins_path)
end
it "changes the primary-darken on the page" 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
primary_color = Faker::Color.hex_color
post :coloring_darken, params: { color: primary_color }
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Primary Color Darken")
expect(feature[:value]).to eq(primary_color)
expect(response).to redirect_to(admins_path)
end
end
context "POST #registration_method" do
it "changes the registration method for the given context" do
allow(Rails.configuration).to receive(:enable_email_verification).and_return(true)
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
post :registration_method, params: { method: "invite" }
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Registration Method")
expect(feature[:value]).to eq(Rails.configuration.registration_methods[:invite])
expect(flash[:success]).to be_present
expect(response).to redirect_to(admins_path)
end
it "does not allow the user to change to invite if emails are off" do
allow(Rails.configuration).to receive(:enable_email_verification).and_return(false)
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
post :registration_method, params: { method: "invite" }
expect(flash[:alert]).to be_present
expect(response).to redirect_to(admins_path)
end
end
context "POST #room_authentication" do
it "changes the room authentication required setting" 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
post :room_authentication, params: { value: "true" }
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Room Authentication")
expect(feature[:value]).to eq("true")
expect(response).to redirect_to(admins_path)
end end
end end
end end

View File

@ -24,22 +24,47 @@ end
describe ApplicationController do describe ApplicationController do
controller do controller do
before_action :check_if_unbanned
def index def index
head :ok head :ok
end end
def error
raise BigBlueButton::BigBlueButtonException
end
end end
context "roles" do context "roles" do
it "redirects a banned user to a 401 and logs them out" do before do
@user = create(:user) @user = create(:user)
end
it "redirects a banned user to a 401 and logs them out" do
@user.add_role :denied @user.add_role :denied
@request.session[:user_id] = @user.id @request.session[:user_id] = @user.id
get :index get :index
expect(@request.session[:user_id]).to be_nil expect(@request.session[:user_id]).to be_nil
expect(response).to redirect_to(unauthorized_path) expect(flash[:alert]).to be_present
expect(response).to redirect_to(root_path)
end
it "redirects a pending user to a 401 and logs them out" do
@user.add_role :pending
@request.session[:user_id] = @user.id
get :index
expect(@request.session[:user_id]).to be_nil
expect(flash[:alert]).to be_present
expect(response).to redirect_to(root_path)
end
end
context "errors" do
it "renders a BigBlueButton error if a BigBlueButtonException occurrs" do
routes.draw { get "error" => "anonymous#error" }
get :error
expect(response).to render_template("errors/bigbluebutton_error")
end end
end end
end end

View File

@ -84,7 +84,7 @@ describe RoomsController, type: :controller do
end end
it "sets the join name to cookie[:greenlight_name] if it exists" do it "sets the join name to cookie[:greenlight_name] if it exists" do
name = Faker::Pokemon.name name = Faker::Games::Pokemon.name
@request.cookies[:greenlight_name] = name @request.cookies[:greenlight_name] = name
get :show, params: { room_uid: @owner.main_room } get :show, params: { room_uid: @owner.main_room }
@ -115,7 +115,7 @@ describe RoomsController, type: :controller do
it "should create room with name and correct settings" do it "should create room with name and correct settings" do
@request.session[:user_id] = @owner.id @request.session[:user_id] = @owner.id
name = Faker::Pokemon.name name = Faker::Games::Pokemon.name
room_params = { name: name, "client": "html5", "mute_on_join": "1" } room_params = { name: name, "client": "html5", "mute_on_join": "1" }
json_room_settings = "{\"muteOnStart\":true,\"joinViaHtml5\":true}" json_room_settings = "{\"muteOnStart\":true,\"joinViaHtml5\":true}"
@ -131,7 +131,7 @@ describe RoomsController, type: :controller do
it "it should redirect to root if not logged in" do it "it should redirect to root if not logged in" do
expect do expect do
name = Faker::Pokemon.name name = Faker::Games::Pokemon.name
post :create, params: { room: { name: name } } post :create, params: { room: { name: name } }
end.to change { Room.count }.by(0) end.to change { Room.count }.by(0)
@ -206,6 +206,15 @@ describe RoomsController, type: :controller do
expect(flash[:alert]).to be_present expect(flash[:alert]).to be_present
expect(response).to redirect_to(root_path) expect(response).to redirect_to(root_path)
end end
it "should not allow the user to join if the user isn't signed in and room authentication is required" do
allow_any_instance_of(Setting).to receive(:get_value).and_return("true")
post :join, params: { room_uid: @room }
expect(flash[:alert]).to be_present
expect(response).to redirect_to(root_path)
end
end end
describe "DELETE #destroy" do describe "DELETE #destroy" do
@ -280,7 +289,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::Pokemon.name name = Faker::Games::Pokemon.name
room_params = { room_uid: @secondary_room.uid, room: { "name": name } } room_params = { room_uid: @secondary_room.uid, room: { "name": name } }

View File

@ -223,6 +223,36 @@ describe SessionsController, type: :controller do
expect(response).to redirect_to(root_path) expect(response).to redirect_to(root_path)
end end
context 'registration notification emails' do
before do
allow(Rails.configuration).to receive(:enable_email_verification).and_return(true)
@user = create(:user, provider: "greenlight")
@admin = create(:user, provider: "greenlight", email: "test@example.com")
@admin.add_role :admin
end
it "should notify admin on new user signup with approve/reject registration" do
allow_any_instance_of(Registrar).to receive(:approval_registration).and_return(true)
request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:bn_launcher]
expect { get :omniauth, params: { provider: 'bn_launcher' } }
.to change { ActionMailer::Base.deliveries.count }.by(1)
end
it "should notify admin on new user signup with invite registration" do
allow_any_instance_of(Registrar).to receive(:invite_registration).and_return(true)
invite = Invitation.create(email: "user@google.com", provider: "greenlight")
@request.session[:invite_token] = invite.invite_token
request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:bn_launcher]
expect { get :omniauth, params: { provider: 'bn_launcher' } }
.to change { ActionMailer::Base.deliveries.count }.by(1)
end
end
end end
it "should not create session without omniauth env set for bn_launcher" do it "should not create session without omniauth env set for bn_launcher" do

View File

@ -169,7 +169,9 @@ describe UsersController, type: :controller do
end end
context "allow email verification" do context "allow email verification" do
before { allow(Rails.configuration).to receive(:enable_email_verification).and_return(true) } before do
allow(Rails.configuration).to receive(:enable_email_verification).and_return(true)
end
it "should raise if there there is a delivery failure" do it "should raise if there there is a delivery failure" do
params = random_valid_user_params params = random_valid_user_params
@ -179,6 +181,113 @@ describe UsersController, type: :controller do
raise :anyerror raise :anyerror
end.to raise_error { :anyerror } end.to raise_error { :anyerror }
end end
context "enable invite registration" do
before do
allow_any_instance_of(Registrar).to receive(:invite_registration).and_return(true)
allow(Rails.configuration).to receive(:allow_user_signup).and_return(true)
@user = create(:user, provider: "greenlight")
@admin = create(:user, provider: "greenlight", email: "test@example.com")
@admin.add_role :admin
end
it "should notify admins that user signed up" do
params = random_valid_user_params
invite = Invitation.create(email: params[:user][:email], provider: "greenlight")
@request.session[:invite_token] = invite.invite_token
expect { post :create, params: params }.to change { ActionMailer::Base.deliveries.count }.by(1)
end
it "rejects the user if they are not invited" do
get :new
expect(flash[:alert]).to be_present
expect(response).to redirect_to(root_path)
end
it "allows the user to signup if they are invited" do
allow(Rails.configuration).to receive(:enable_email_verification).and_return(false)
params = random_valid_user_params
invite = Invitation.create(email: params[:user][:name], provider: "greenlight")
@request.session[:invite_token] = invite.invite_token
post :create, params: params
u = User.find_by(name: params[:user][:name], email: params[:user][:email])
expect(response).to redirect_to(u.main_room)
end
it "verifies the user if they sign up with the email they receieved the invite with" do
allow(Rails.configuration).to receive(:enable_email_verification).and_return(true)
params = random_valid_user_params
invite = Invitation.create(email: params[:user][:email], provider: "greenlight")
@request.session[:invite_token] = invite.invite_token
post :create, params: params
u = User.find_by(name: params[:user][:name], email: params[:user][:email])
expect(response).to redirect_to(u.main_room)
end
it "asks the user to verify if they signup with a different email" do
allow(Rails.configuration).to receive(:enable_email_verification).and_return(true)
params = random_valid_user_params
invite = Invitation.create(email: Faker::Internet.email, provider: "greenlight")
@request.session[:invite_token] = invite.invite_token
post :create, params: params
expect(User.exists?(name: params[:user][:name], email: params[:user][:email])).to eq(true)
expect(flash[:success]).to be_present
expect(response).to redirect_to(root_path)
end
end
context "enable approval registration" do
before do
allow_any_instance_of(Registrar).to receive(:approval_registration).and_return(true)
allow(Rails.configuration).to receive(:allow_user_signup).and_return(true)
@user = create(:user, provider: "greenlight")
@admin = create(:user, provider: "greenlight", email: "test@example.com")
@admin.add_role :admin
end
it "allows any user to sign up" do
allow(Rails.configuration).to receive(:enable_email_verification).and_return(false)
params = random_valid_user_params
post :create, params: params
expect(User.exists?(name: params[:user][:name], email: params[:user][:email])).to eq(true)
expect(flash[:success]).to be_present
expect(response).to redirect_to(root_path)
end
it "sets the user to pending on sign up" do
allow(Rails.configuration).to receive(:enable_email_verification).and_return(false)
params = random_valid_user_params
post :create, params: params
u = User.find_by(name: params[:user][:name], email: params[:user][:email])
expect(u.has_role?(:pending)).to eq(true)
end
it "notifies admins that a user signed up" do
allow(Rails.configuration).to receive(:enable_email_verification).and_return(true)
params = random_valid_user_params
expect { post :create, params: params }.to change { ActionMailer::Base.deliveries.count }.by(2)
end
end
end end
it "redirects to main room if already authenticated" do it "redirects to main room if already authenticated" do

View File

@ -32,7 +32,7 @@ FactoryBot.define do
end end
factory :room do factory :room do
name { Faker::Pokemon.name } name { Faker::Games::Pokemon.name }
owner { create(:user) } owner { create(:user) }
end end
end end

View File

@ -1,13 +1,18 @@
# frozen_string_literal: true # frozen_string_literal: true
class UserMailerPreview < ActionMailer::Preview class UserMailerPreview < ActionMailer::Preview
def initialize
@logo = "https://raw.githubusercontent.com/bigbluebutton/greenlight/master/app/assets/images/logo_with_text.png"
@color = "#467fcf"
end
# Preview this email at # Preview this email at
# http://localhost:3000/rails/mailers/user_mailer/password_reset # http://localhost:3000/rails/mailers/user_mailer/password_reset
def password_reset def password_reset
user = User.first user = User.first
user.reset_token = User.new_token user.reset_token = User.new_token
url = "http://example.com" + "/password_resets/" + user.reset_token + "/edit?email=" + user.email url = "http://example.com" + "/password_resets/" + user.reset_token + "/edit?email=" + user.email
UserMailer.password_reset(user, url) UserMailer.password_reset(user, url, @logo, @color)
end end
# Preview this email at # Preview this email at
@ -15,6 +20,52 @@ class UserMailerPreview < ActionMailer::Preview
def verify_email def verify_email
user = User.first user = User.first
url = "http://example.com" + "/u/verify/confirm/" + user.uid url = "http://example.com" + "/u/verify/confirm/" + user.uid
UserMailer.verify_email(user, url) UserMailer.verify_email(user, url, @logo, @color)
end
# Preview this email at
# http://localhost:3000/rails/mailers/user_mailer/invite_email
def invite_email
UserMailer.invite_email("Example User", "from@example.com", "http://example.com/signup", @logo, @color)
end
# Preview this email at
# http://localhost:3000/rails/mailers/user_mailer/approve_user
def approve_user
user = User.first
UserMailer.approve_user(user, "http://example.com/", @logo, @color)
end
# Preview this email at
# http://localhost:3000/rails/mailers/user_mailer/approval_user_signup
def approval_user_signup
user = User.first
UserMailer.approval_user_signup(user, "http://example.com/", @logo, @color, "test@example.com")
end
# Preview this email at
# http://localhost:3000/rails/mailers/user_mailer/invite_user_signup
def invite_user_signup
user = User.first
UserMailer.invite_user_signup(user, "http://example.com/", @logo, @color, "test@example.com")
end
# http://localhost:3000/rails/mailers/user_mailer/user_promoted
def user_promoted
user = User.first
url = "http://example.com"
logo_image = "https://raw.githubusercontent.com/bigbluebutton/greenlight/master/app/assets/images/logo_with_text.png"
user_color = "#467fcf"
UserMailer.user_promoted(user, url, logo_image, user_color)
end
# Preview this email at
# http://localhost:3000/rails/mailers/user_mailer/user_demoted
def user_demoted
user = User.first
url = "http://example.com"
logo_image = "https://raw.githubusercontent.com/bigbluebutton/greenlight/master/app/assets/images/logo_with_text.png"
user_color = "#467fcf"
UserMailer.user_demoted(user, url, logo_image, user_color)
end end
end end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 984 B

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -74,13 +74,13 @@
position: absolute; position: absolute;
font-size: 10px; font-size: 10px;
font-family: Arial, Helvetica, sans-serif; font-family: Arial, Helvetica, sans-serif;
color: #898989; color: white;
top: 4px; top: 4px;
right: 11px; right: 11px;
text-align: right; text-align: right;
margin: 0; margin: 0;
padding: 0; padding: 0;
height: 11px; height: 14px;
} }
.colorpicker_hex { .colorpicker_hex {
position: absolute; position: absolute;