Merge pull request #971 from bigbluebutton/v2.5-alpha

Release v2.5
This commit is contained in:
Fred Dixon 2020-03-02 11:48:17 -05:00 committed by GitHub
commit 2af1f7242f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
82 changed files with 2148 additions and 361 deletions

View File

@ -13,6 +13,7 @@ tmp
/db/**/*.sqlite3
/db/**/*.sqlite3-journal
/db/production
/db/production-postgres
public/assets
public/b
coverage/

1
.gitignore vendored
View File

@ -19,6 +19,7 @@ vendor/bundle
# Ignore production paths.
/db/production
/db/production-postgres
# Ignore all logfiles and tempfiles.
/log/*

View File

@ -1,34 +1,58 @@
FROM ruby:2.5
FROM ruby:2.5.1-alpine AS base
# Install app dependencies.
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev curl
ADD https://dl.yarnpkg.com/debian/pubkey.gpg /tmp/yarn-pubkey.gpg
RUN apt-key add /tmp/yarn-pubkey.gpg && rm /tmp/yarn-pubkey.gpg && \
echo 'deb http://dl.yarnpkg.com/debian/ stable main' > /etc/apt/sources.list.d/yarn.list && \
curl -sL https://deb.nodesource.com/setup_10.x | bash - && \
apt-get update && apt-get install -y nodejs yarn
# Set an environment variable for the install location.
ENV RAILS_ROOT /usr/src/app
# Set a variable for the install location.
ARG RAILS_ROOT=/usr/src/app
# Set Rails environment.
ENV RAILS_ENV production
ENV BUNDLE_APP_CONFIG="$RAILS_ROOT/.bundle"
# Make the directory and set as working.
RUN mkdir -p $RAILS_ROOT
WORKDIR $RAILS_ROOT
# Set Rails environment.
ENV RAILS_ENV production
ARG BUILD_PACKAGES="build-base curl-dev git"
ARG DEV_PACKAGES="postgresql-dev sqlite-libs sqlite-dev yaml-dev zlib-dev nodejs yarn"
ARG RUBY_PACKAGES="tzdata"
# Install app dependencies.
RUN apk update \
&& apk upgrade \
&& apk add --update --no-cache $BUILD_PACKAGES $DEV_PACKAGES $RUBY_PACKAGES
COPY Gemfile* ./
RUN bundle install --without development test --deployment --clean
COPY Gemfile Gemfile.lock $RAILS_ROOT/
RUN bundle config --global frozen 1 \
&& bundle install --deployment --without development:test:assets -j4 --path=vendor/bundle \
&& rm -rf vendor/bundle/ruby/2.5.0/cache/*.gem \
&& find vendor/bundle/ruby/2.5.0/gems/ -name "*.c" -delete \
&& find vendor/bundle/ruby/2.5.0/gems/ -name "*.o" -delete
# Adding project files.
COPY . .
# Precompile assets
RUN SECRET_KEY_BASE="$(bundle exec rake secret)" bundle exec rake assets:clean
RUN SECRET_KEY_BASE="$(bundle exec rake secret)" bundle exec rake assets:precompile
# Remove folders not needed in resulting image
RUN rm -rf tmp/cache spec
############### Build step done ###############
FROM ruby:2.5.1-alpine
# Set a variable for the install location.
ARG RAILS_ROOT=/usr/src/app
ARG PACKAGES="tzdata curl postgresql-client sqlite-libs yarn nodejs bash"
ENV RAILS_ENV=production
ENV BUNDLE_APP_CONFIG="$RAILS_ROOT/.bundle"
WORKDIR $RAILS_ROOT
RUN apk update \
&& apk upgrade \
&& apk add --update --no-cache $PACKAGES
COPY --from=base $RAILS_ROOT $RAILS_ROOT
# Expose port 80.
EXPOSE 80

View File

@ -23,7 +23,7 @@ gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.2'
# See https://github.com/rails/execjs#readme for more supported runtimes
gem 'mini_racer', platforms: :ruby
# gem 'mini_racer', platforms: :ruby
# Use jquery as the JavaScript library
gem 'jquery-rails', '~> 4.3.3'
@ -77,6 +77,7 @@ gem 'cancancan', '~> 2.0'
group :production do
# Use a postgres database in production.
gem 'pg', '~> 0.18'
gem 'sequel'
# For a better logging library in production
gem "lograge"
@ -121,7 +122,7 @@ end
gem 'remote_syslog_logger'
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
gem 'tzinfo-data'
gem 'coveralls', require: false

View File

@ -153,7 +153,6 @@ GEM
railties (>= 3.2.16)
json (2.2.0)
jwt (2.2.1)
libv8 (7.3.492.27.1)
listen (3.0.8)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
@ -173,8 +172,6 @@ GEM
mimemagic (0.3.3)
mini_mime (1.0.2)
mini_portile2 (2.4.0)
mini_racer (0.2.6)
libv8 (>= 6.9.411)
minitest (5.11.3)
msgpack (1.3.0)
multi_json (1.13.1)
@ -295,6 +292,7 @@ GEM
sprockets (> 3.0)
sprockets-rails
tilt
sequel (5.29.0)
shoulda-matchers (3.1.3)
activesupport (>= 4.0.0)
simplecov (0.16.1)
@ -326,6 +324,8 @@ GEM
turbolinks-source (5.2.0)
tzinfo (1.2.5)
thread_safe (~> 0.1)
tzinfo-data (1.2019.3)
tzinfo (>= 1.0.0)
uglifier (4.1.20)
execjs (>= 0.3.0, < 3)
unicode-display_width (1.6.0)
@ -369,7 +369,6 @@ DEPENDENCIES
jquery-ui-rails
listen (~> 3.0.5)
lograge
mini_racer
net-ldap
omniauth
omniauth-bn-launcher!
@ -389,6 +388,7 @@ DEPENDENCIES
rspec-rails (~> 3.7)
rubocop
sassc-rails
sequel
shoulda-matchers (~> 3.1)
spring
spring-watcher-listen (~> 2.0.0)

View File

@ -41,6 +41,49 @@ $(document).on('turbolinks:load', function(){
updateTabParams(this.id)
})
$('.selectpicker').selectpicker({
liveSearchPlaceholder: getLocalizedString('javascript.search.start')
});
// Fixes turbolinks issue with bootstrap select
$(window).trigger('load.bs.select.data-api');
// Display merge accounts modal with correct info
$(".merge-user").click(function() {
// Update the path of save button
$("#merge-save-access").attr("data-path", $(this).data("path"))
let userInfo = $(this).data("info")
$("#merge-to").html("<span>" + userInfo.name + "</span>" + "<span class='text-muted d-block'>" + userInfo.email + "</span>" + "<span class='text-muted d-block'>" + userInfo.uid + "</span>")
})
$("#mergeUserModal").on("show.bs.modal", function() {
$(".selectpicker").selectpicker('val','')
})
$(".bootstrap-select").on("click", function() {
$(".bs-searchbox").siblings().hide()
})
$(".bs-searchbox input").on("input", function() {
if ($(".bs-searchbox input").val() == '' || $(".bs-searchbox input").val().length < 3) {
$(".bs-searchbox").siblings().hide()
} else {
$(".bs-searchbox").siblings().show()
}
})
// User selects an option from the Room Access dropdown
$(".bootstrap-select").on("changed.bs.select", function(){
// Get the uid of the selected user
let user = $(".selectpicker").selectpicker('val')
if (user != "") {
userInfo = JSON.parse(user)
$("#merge-from").html("<span>" + userInfo.name + "</span>" + "<span class='text-muted d-block'>" + userInfo.email + "</span>" + "<span id='from-uid' class='text-muted d-block'>" + userInfo.uid + "</span>")
}
})
}
else if(action == "site_settings"){
loadColourSelectors()
@ -79,6 +122,11 @@ function changeBrandingImage(path) {
$.post(path, {value: url})
}
function mergeUsers() {
let userToMerge = $("#from-uid").text()
$.post($("#merge-save-access").data("path"), {merge: userToMerge})
}
// Filters by role
function filterRole(role) {
var search = new URL(location.href).searchParams.get('search')

View File

@ -34,4 +34,5 @@
//= require jquery-ui/widget
//= require jquery-ui/widgets/sortable
//= require pickr.min.js
//= require bootstrap-select.min.js
//= require_tree .

View File

@ -49,7 +49,16 @@ $(document).on('turbolinks:load', function(){
$("#create-room-block").click(function(){
showCreateRoom(this)
})
}
// Autofocus on the Room Name label when creating a room only
$('#createRoomModal').on('shown.bs.modal', function (){
if ($(".create-only").css("display") == "block"){
$('#create-room-name').focus()
}
})
if (controller == "rooms" && action == "show" || controller == "admins" && action == "server_rooms"){
// Display and update all fields related to creating a room in the createRoomModal
$(".update-room").click(function(){
showUpdateRoom(this)
@ -58,6 +67,69 @@ $(document).on('turbolinks:load', function(){
$(".delete-room").click(function() {
showDeleteRoom(this)
})
$('.selectpicker').selectpicker({
liveSearchPlaceholder: getLocalizedString('javascript.search.start')
});
// Fixes turbolinks issue with bootstrap select
$(window).trigger('load.bs.select.data-api');
$(".share-room").click(function() {
// Update the path of save button
$("#save-access").attr("data-path", $(this).data("path"))
// Get list of users shared with and display them
displaySharedUsers($(this).data("users-path"))
})
$("#shareRoomModal").on("show.bs.modal", function() {
$(".selectpicker").selectpicker('val','')
})
$(".bootstrap-select").on("click", function() {
$(".bs-searchbox").siblings().hide()
})
$(".bs-searchbox input").on("input", function() {
if ($(".bs-searchbox input").val() == '' || $(".bs-searchbox input").val().length < 3) {
$(".bs-searchbox").siblings().hide()
} else {
$(".bs-searchbox").siblings().show()
}
})
$(".remove-share-room").click(function() {
$("#remove-shared-confirm").parent().attr("action", $(this).data("path"))
})
// User selects an option from the Room Access dropdown
$(".bootstrap-select").on("changed.bs.select", function(){
// Get the uid of the selected user
let uid = $(".selectpicker").selectpicker('val')
// If the value was changed to blank, ignore it
if (uid == "") return
let currentListItems = $("#user-list li").toArray().map(user => $(user).data("uid"))
// Check to make sure that the user is not already there
if (!currentListItems.includes(uid)) {
// Create the faded list item and display it
let option = $("option[value='" + uid + "']")
let listItem = document.createElement("li")
listItem.setAttribute('class', 'list-group-item text-left not-saved add-access');
listItem.setAttribute("data-uid", uid)
let spanItem = "<span class='avatar float-left mr-2'>" + option.text().charAt(0) + "</span> <span class='shared-user'>" +
option.text() + " <span class='text-muted'>" + option.data("subtext") + "</span></span>" +
"<span class='text-primary float-right shared-user cursor-pointer' onclick='removeSharedUser(this)'><i class='fas fa-times'></i></span>"
listItem.innerHTML = spanItem
$("#user-list").append(listItem)
}
})
}
});
@ -88,9 +160,10 @@ function showCreateRoom(target) {
function showUpdateRoom(target) {
var modal = $(target)
var room_block_uid = modal.closest("#room-block").data("room-uid")
$("#create-room-name").val(modal.closest("tbody").find("#room-name h4").text())
$("#createRoomModal form").attr("action", room_block_uid + "/update_settings")
var update_path = modal.closest("#room-block").data("path")
var settings_path = modal.data("settings-path")
$("#create-room-name").val(modal.closest("#room-block").find("#room-name-text").text())
$("#createRoomModal form").attr("action", update_path)
//show all elements & their children with a update-only class
$(".update-only").each(function() {
@ -104,7 +177,7 @@ function showUpdateRoom(target) {
if($(this).children().length > 0) { $(this).children().attr('style',"display:none !important") }
})
updateCurrentSettings(modal.closest("#room-block").data("room-settings"))
updateCurrentSettings(settings_path)
var accessCode = modal.closest("#room-block").data("room-access-code")
@ -123,12 +196,15 @@ function showDeleteRoom(target) {
}
//Update the createRoomModal to show the correct current settings
function updateCurrentSettings(settings){
//set checkbox
$("#room_mute_on_join").prop("checked", settings.muteOnStart)
$("#room_require_moderator_approval").prop("checked", settings.requireModeratorApproval)
$("#room_anyone_can_start").prop("checked", settings.anyoneCanStart)
$("#room_all_join_moderator").prop("checked", settings.joinModerator)
function updateCurrentSettings(settings_path){
// Get current room settings and set checkbox
$.get(settings_path, function(room_settings) {
var settings = JSON.parse(room_settings)
$("#room_mute_on_join").prop("checked", settings.muteOnStart)
$("#room_require_moderator_approval").prop("checked", settings.requireModeratorApproval)
$("#room_anyone_can_start").prop("checked", settings.anyoneCanStart)
$("#room_all_join_moderator").prop("checked", settings.joinModerator)
})
}
function generateAccessCode(){
@ -148,3 +224,44 @@ function ResetAccessCode(){
$("#create-room-access-code").text(getLocalizedString("modal.create_room.access_code_placeholder"))
$("#room_access_code").val(null)
}
function saveAccessChanges() {
let listItemsToAdd = $("#user-list li:not(.remove-shared)").toArray().map(user => $(user).data("uid"))
$.post($("#save-access").data("path"), {add: listItemsToAdd})
}
// Get list of users shared with and display them
function displaySharedUsers(path) {
$.get(path, function(users) {
// Create list element and add to user list
var user_list_html = ""
users.forEach(function(user) {
user_list_html += "<li class='list-group-item text-left' data-uid='" + user.uid + "'>"
if (user.image) {
user_list_html += "<img id='user-image' class='avatar float-left mr-2' src='" + user.image + "'></img>"
} else {
user_list_html += "<span class='avatar float-left mr-2'>" + user.name.charAt(0) + "</span>"
}
user_list_html += "<span class='shared-user'>" + user.name + "<span class='text-muted ml-1'>" + user.uid + "</span></span>"
user_list_html += "<span class='text-primary float-right shared-user cursor-pointer' onclick='removeSharedUser(this)'><i class='fas fa-times'></i></span>"
user_list_html += "</li>"
})
$("#user-list").html(user_list_html)
});
}
// Removes the user from the list of shared users
function removeSharedUser(target) {
let parentLI = target.closest("li")
if (parentLI.classList.contains("not-saved")) {
parentLI.parentNode.removeChild(parentLI)
} else {
parentLI.removeChild(target)
parentLI.classList.add("remove-shared")
}
}

View File

@ -23,7 +23,8 @@ $(document).on('turbolinks:load', function(){
(controller == "rooms" && action == "update") ||
(controller == "rooms" && action == "join") ||
(controller == "users" && action == "recordings") ||
(controller == "admins" && action == "server_recordings")) {
(controller == "admins" && action == "server_recordings") ||
(controller == "admins" && action == "server_rooms")) {
// Submit search if the user hits enter
$("#search-input").keypress(function(key) {
if (key.which == 13) {

View File

@ -52,15 +52,12 @@ $(document).on('turbolinks:load', function(){
// Modify the ui for the tables
var configure_order = function(header_elem){
if(header_elem.data('order') === 'asc'){ // asc
header_elem.text(header_elem.data("header") + " ↓");
header_elem.data('order', 'desc');
}
else if(header_elem.data('order') === 'desc'){ // desc
header_elem.text(header_elem.data("header"));
header_elem.data('order', 'none');
}
else{ // none
header_elem.text(header_elem.data("header") + " ↑");
header_elem.data('order', 'asc');
}
}

View File

@ -88,4 +88,12 @@
&:hover {
cursor: pointer;
}
}
#merge-account-arrow {
position: absolute;
top: 47%;
right: 47%;
z-index: 999;
background: white;
}

View File

@ -36,14 +36,16 @@
@import "tabler-custom";
@import "font-awesome-sprockets";
@import "font-awesome";
@import "monolith.min.scss";
@import "bootstrap-select.min";
@import "utilities/variables";
@import "admins";
@import "main";
@import "rooms";
@import "sessions";
@import "monolith.min.scss";
@import "utilities/fonts";
@import "users";
* {
outline: none !important;

View File

@ -83,3 +83,20 @@
margin-top: -6rem;
font-size: 5rem;
}
.bootstrap-select .dropdown-menu li.active small.text-muted{
color: #9aa0ac !important
}
.not-saved {
color: grey;
background: rgba(0, 40, 100, 0.12);
}
.dropdown-menu.show {
min-height: 0px !important;
}
.remove-shared {
text-decoration: line-through;
}

View File

@ -21,4 +21,12 @@
.user-role-tag{
color: white !important;
}
.shared-user {
line-height: 30px;
}
.bootstrap-select {
border: 1px solid rgba(0, 40, 100, 0.12);
}

View File

@ -18,11 +18,6 @@
class WaitingChannel < ApplicationCable::Channel
def subscribed
Rails.logger.info "subscribed [#{params[:useruid]}:#{params[:roomuid]}]"
stream_from "#{params[:roomuid]}_waiting_channel"
end
def unsubscribed
Rails.logger.info "unsubscribed [#{params[:useruid]}:#{params[:roomuid]}]"
end
end

View File

@ -51,6 +51,7 @@ class AccountActivationsController < ApplicationController
flash[:alert] = I18n.t("verify.already_verified")
else
# Resend
@user.create_activation_token
send_activation_email(@user)
end
@ -60,14 +61,10 @@ class AccountActivationsController < ApplicationController
private
def find_user
@user = User.find_by!(email: params[:email], provider: @user_domain)
@user = User.find_by!(activation_digest: User.digest(params[:token]), provider: @user_domain)
end
def ensure_unauthenticated
redirect_to current_user.main_room if current_user
end
def email_params
params.require(:email).permit(:email, :token)
end
end

View File

@ -22,8 +22,9 @@ class AdminsController < ApplicationController
include Emailer
include Recorder
include Rolify
include Populator
manage_users = [:edit_user, :promote, :demote, :ban_user, :unban_user, :approve, :reset]
manage_users = [:edit_user, :promote, :demote, :ban_user, :unban_user, :approve, :reset, :merge_user]
manage_deleted_users = [:undelete]
authorize_resource class: false
before_action :find_user, only: manage_users
@ -40,7 +41,9 @@ class AdminsController < ApplicationController
@role = params[:role] ? Role.find_by(name: params[:role], provider: @user_domain) : nil
@tab = params[:tab] || "active"
@pagy, @users = pagy(user_list)
@user_list = merge_user_list
@pagy, @users = pagy(manage_users_list)
end
# GET /admins/site_settings
@ -49,11 +52,7 @@ class AdminsController < ApplicationController
# GET /admins/server_recordings
def server_recordings
server_rooms = if Rails.configuration.loadbalanced_configuration
Room.includes(:owner).where(users: { provider: @user_domain }).pluck(:bbb_id)
else
Room.pluck(:bbb_id)
end
server_rooms = rooms_list_for_recordings
@search, @order_column, @order_direction, recs =
all_recordings(server_rooms, params.permit(:search, :column, :direction), true, true)
@ -61,24 +60,40 @@ class AdminsController < ApplicationController
@pagy, @recordings = pagy_array(recs)
end
# GET /admins/rooms
def server_rooms
@search = params[:search] || ""
@order_column = params[:column] && params[:direction] != "none" ? params[:column] : "created_at"
@order_direction = params[:direction] && params[:direction] != "none" ? params[:direction] : "DESC"
@running_room_bbb_ids = all_running_meetings[:meetings].pluck(:meetingID)
@user_list = shared_user_list if shared_access_allowed
@pagy, @rooms = pagy_array(server_rooms_list)
end
# MANAGE USERS
# GET /admins/edit/:user_uid
def edit_user
session[:prev_url] = request.referer if request.referer.present?
end
# POST /admins/ban/:user_uid
def ban_user
@user.roles = []
@user.add_role :denied
redirect_to admins_path, flash: { success: I18n.t("administrator.flash.banned") }
redirect_back fallback_location: admins_path, flash: { success: I18n.t("administrator.flash.banned") }
end
# POST /admins/unban/:user_uid
def unban_user
@user.remove_role :denied
@user.add_role :user
redirect_to admins_path, flash: { success: I18n.t("administrator.flash.unbanned") }
redirect_back fallback_location: admins_path, flash: { success: I18n.t("administrator.flash.unbanned") }
end
# POST /admins/approve/:user_uid
@ -87,7 +102,7 @@ class AdminsController < ApplicationController
send_user_approved_email(@user)
redirect_to admins_path, flash: { success: I18n.t("administrator.flash.approved") }
redirect_back fallback_location: admins_path, flash: { success: I18n.t("administrator.flash.approved") }
end
# POST /admins/approve/:user_uid
@ -96,7 +111,7 @@ class AdminsController < ApplicationController
@user.undelete!
@user.rooms.deleted.each(&:undelete!)
redirect_to admins_path, flash: { success: I18n.t("administrator.flash.restored") }
redirect_back fallback_location: admins_path, flash: { success: I18n.t("administrator.flash.restored") }
end
# POST /admins/invite
@ -118,8 +133,54 @@ class AdminsController < ApplicationController
send_password_reset_email(@user)
redirect_to admins_path, flash: { success: I18n.t("administrator.flash.reset_password") }
if session[:prev_url].present?
redirect_path = session[:prev_url]
session.delete(:prev_url)
else
redirect_path = admins_path
end
redirect_to redirect_path, flash: { success: I18n.t("administrator.flash.reset_password") }
end
# POST /admins/merge/:user_uid
def merge_user
begin
# Get uid of user that will be merged into the other account
uid_to_merge = params[:merge]
logger.info "#{current_user.uid} is attempting to merge #{uid_to_merge} into #{@user.uid}"
# Check to make sure the 2 users are unique
raise "Can not merge the user into themself" if uid_to_merge == @user.uid
# Find user to merge
user_to_merge = User.find_by(uid: uid_to_merge)
# Move over user's rooms
user_to_merge.rooms.each do |room|
room.owner = @user
room.name = "(#{I18n.t('merged')}) #{room.name}"
room.save!
end
# Reload user to update merge rooms
user_to_merge.reload
# Delete merged user
user_to_merge.destroy(true)
rescue => e
logger.info "Failed to merge #{uid_to_merge} into #{@user.uid}: #{e}"
flash[:alert] = I18n.t("administrator.flash.merge_fail")
else
logger.info "#{current_user.uid} successfully merged #{uid_to_merge} into #{@user.uid}"
flash[:success] = I18n.t("administrator.flash.merge_success")
end
redirect_back fallback_location: admins_path
end
# SITE SETTINGS
# POST /admins/update_settings
@ -158,6 +219,13 @@ class AdminsController < ApplicationController
end
end
# POST /admins/clear_auth
def clear_auth
User.include_deleted.where(provider: @user_domain).update_all(social_uid: nil)
redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") }
end
# POST /admins/clear_cache
def clear_cache
Rails.cache.delete("#{@user_domain}/getUser")
@ -166,6 +234,13 @@ class AdminsController < ApplicationController
redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") }
end
# POST /admins/log_level
def log_level
Rails.logger.level = params[:value].to_i
redirect_to admin_site_settings_path, flash: { success: I18n.t("administrator.flash.settings") }
end
# ROLES
# GET /admins/roles
@ -224,11 +299,11 @@ class AdminsController < ApplicationController
private
def find_user
@user = User.where(uid: params[:user_uid]).includes(:roles).first
@user = User.find_by(uid: params[:user_uid])
end
def find_deleted_user
@user = User.deleted.where(uid: params[:user_uid]).includes(:roles).first
@user = User.deleted.find_by(uid: params[:user_uid])
end
# Verifies that admin is an administrator of the user in the action
@ -237,37 +312,6 @@ class AdminsController < ApplicationController
flash: { alert: I18n.t("administrator.flash.unauthorized") } unless current_user.admin_of?(@user)
end
# Gets the list of users based on your configuration
def user_list
current_role = @role
initial_user = case @tab
when "active"
User.without_role(:pending).without_role(:denied)
when "deleted"
User.deleted
else
User
end
current_role = Role.find_by(name: @tab, provider: @user_domain) if @tab == "pending" || @tab == "denied"
initial_list = if current_user.has_role? :super_admin
initial_user.where.not(id: current_user.id)
else
initial_user.without_role(:super_admin).where.not(id: current_user.id)
end
if Rails.configuration.loadbalanced_configuration
initial_list.where(provider: @user_domain)
.admins_search(@search, current_role)
.admins_order(@order_column, @order_direction)
else
initial_list.admins_search(@search, current_role)
.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)

View File

@ -29,7 +29,7 @@ class ApplicationController < ActionController::Base
# Retrieves the current user.
def current_user
@current_user ||= User.where(id: session[:user_id]).includes(:roles).first
@current_user ||= User.includes(:roles, :main_room).find_by(id: session[:user_id])
if Rails.configuration.loadbalanced_configuration
if @current_user && !@current_user.has_role?(:super_admin) &&
@ -67,7 +67,7 @@ class ApplicationController < ActionController::Base
# Sets the settinfs variable
def set_user_settings
@settings = Setting.find_or_create_by(provider: @user_domain)
@settings = Setting.includes(:features).find_or_create_by(provider: @user_domain)
end
# Redirects the user to a Maintenance page if turned on
@ -172,6 +172,12 @@ class ApplicationController < ActionController::Base
end
helper_method :configured_providers
# Indicates whether users are allowed to share rooms
def shared_access_allowed
@settings.get_value("Shared Access") == "true"
end
helper_method :shared_access_allowed
# Parses the url for the user domain
def parse_user_domain(hostname)
return hostname.split('.').first if Rails.configuration.url_host.empty?
@ -194,7 +200,23 @@ class ApplicationController < ActionController::Base
# Manually deal with 401 errors
rescue_from CanCan::AccessDenied do |_exception|
render "errors/greenlight_error"
if current_user
render "errors/greenlight_error"
else
# Store the current url as a cookie to redirect to after sigining in
cookies[:return_to] = request.url
# Get the correct signin path
path = if allow_greenlight_accounts?
signin_path
elsif Rails.configuration.loadbalanced_configuration
omniauth_login_url(:bn_launcher)
else
signin_path
end
redirect_to path
end
end
private
@ -214,6 +236,7 @@ class ApplicationController < ActionController::Base
logger.error "Error in retrieve provider info: #{e}"
# Use the default site settings
@user_domain = "greenlight"
@settings = Setting.find_or_create_by(provider: @user_domain)
if e.message.eql? "No user with that id exists"
render "errors/greenlight_error", locals: { message: I18n.t("errors.not_found.user_not_found.message"),

View File

@ -68,6 +68,18 @@ module Authenticator
session.delete(:user_id) if current_user
end
# Check if the user is using local accounts
def auth_changed_to_local?(user)
Rails.configuration.loadbalanced_configuration && user.social_uid.present? && allow_greenlight_accounts?
end
# Check if the user exists under the same email with no social uid and that social accounts are allowed
def auth_changed_to_social?(email)
Rails.configuration.loadbalanced_configuration &&
User.exists?(email: email, provider: @user_domain, social_uid: nil) &&
!allow_greenlight_accounts?
end
private
# Migrates all of the twitter users rooms to the new account

View File

@ -29,6 +29,11 @@ module BbbServer
bbb_server.is_meeting_running?(bbb_id)
end
# Returns a list of all running meetings
def all_running_meetings
bbb_server.get_meetings
end
def get_recordings(meeting_id)
bbb_server.get_recordings(meetingID: meeting_id)
end

View File

@ -101,7 +101,8 @@ module Emailer
return unless Rails.configuration.enable_email_verification
admin_emails = admin_emails()
UserMailer.approval_user_signup(user, admins_url, admin_emails, @settings).deliver_now unless admin_emails.empty?
UserMailer.approval_user_signup(user, admins_url(tab: "pending"),
admin_emails, @settings).deliver_now unless admin_emails.empty?
rescue => e
logger.error "Support: Error in email delivery: #{e}"
flash[:alert] = I18n.t(params[:message], default: I18n.t("delivery_error"))
@ -124,7 +125,7 @@ module Emailer
# Returns the link the user needs to click to verify their account
def user_verification_link(user)
edit_account_activation_url(token: user.activation_token, email: user.email)
edit_account_activation_url(token: user.activation_token)
end
def admin_emails
@ -139,7 +140,7 @@ module Emailer
end
def reset_link(user)
edit_password_reset_url(user.reset_token, email: user.email)
edit_password_reset_url(user.reset_token)
end
def invitation_link(token)

View File

@ -0,0 +1,96 @@
# 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 Populator
extend ActiveSupport::Concern
# Returns a list of users that are in the same context of the current user
def manage_users_list
current_role = @role
initial_user = case @tab
when "active"
User.includes(:roles).without_role(:pending).without_role(:denied)
when "deleted"
User.includes(:roles).deleted
else
User.includes(:roles)
end
current_role = Role.find_by(name: @tab, provider: @user_domain) if @tab == "pending" || @tab == "denied"
initial_list = if current_user.has_role? :super_admin
initial_user.where.not(id: current_user.id)
else
initial_user.without_role(:super_admin).where.not(id: current_user.id)
end
if Rails.configuration.loadbalanced_configuration
initial_list.where(provider: @user_domain)
.admins_search(@search, current_role)
.admins_order(@order_column, @order_direction)
else
initial_list.admins_search(@search, current_role)
.admins_order(@order_column, @order_direction)
end
end
# Returns a list of rooms that are in the same context of the current user
def server_rooms_list
if Rails.configuration.loadbalanced_configuration
Room.includes(:owner).where(users: { provider: @user_domain })
.admins_search(@search)
.admins_order(@order_column, @order_direction)
else
Room.includes(:owner).all.admins_search(@search).admins_order(@order_column, @order_direction)
end
end
# Returns list of rooms needed to get the recordings on the server
def rooms_list_for_recordings
if Rails.configuration.loadbalanced_configuration
Room.includes(:owner).where(users: { provider: @user_domain }).pluck(:bbb_id)
else
Room.pluck(:bbb_id)
end
end
# Returns a list of users that are in the same context of the current user
def shared_user_list
roles_can_appear = []
Role.where(provider: @user_domain).each do |role|
roles_can_appear << role.name if role.get_permission("can_appear_in_share_list") && role.priority >= 0
end
initial_list = User.where.not(uid: current_user.uid)
.without_role(:pending)
.without_role(:denied)
.with_highest_priority_role(roles_can_appear)
return initial_list unless Rails.configuration.loadbalanced_configuration
initial_list.where(provider: @user_domain)
end
# Returns a list of users that can merged into another user
def merge_user_list
initial_list = User.where.not(uid: current_user.uid).without_role(:super_admin)
return initial_list unless Rails.configuration.loadbalanced_configuration
initial_list.where(provider: @user_domain)
end
end

View File

@ -119,17 +119,32 @@ module Rolify
return false if role.priority <= current_user_role.priority || role.provider != @user_domain
end
# Update the roles priority including the user role
top_priority = 0
# Get the priority of the current user's role and start with 1 higher
new_priority = [current_user_role.priority, 0].max + 1
role_to_update.each_with_index do |id, index|
new_priority = index + [current_user_role.priority, 0].max + 1
top_priority = new_priority
Role.where(id: id).update_all(priority: new_priority)
begin
# Save the old priorities incase something fails
old_priority = Role.where(id: role_to_update).select(:id, :priority).index_by(&:id)
# Set all the priorities to nil to avoid unique column issues
Role.where(id: role_to_update).update_all(priority: nil)
# Starting at the starting priority, increase by 1 every time
role_to_update.each_with_index do |id, index|
Role.find(id).update_attribute(:priority, new_priority + index)
end
true
rescue => e
# Reset to old prorities
role_to_update.each_with_index do |id, _index|
Role.find(id).update_attribute(:priority, old_priority[id.to_i].priority)
end
logger.error "#{current_user} failed to update role priorities: #{e}"
false
end
user_role.priority = top_priority + 1
user_role.save!
end
# Update Permissions
@ -141,7 +156,8 @@ module Rolify
role_params = params.require(:role).permit(:name)
permission_params = params.require(:role).permit(:can_create_rooms, :send_promoted_email,
:send_demoted_email, :can_edit_site_settings, :can_edit_roles, :can_manage_users, :colour)
:send_demoted_email, :can_edit_site_settings, :can_edit_roles, :can_manage_users,
:can_manage_rooms_recordings, :can_appear_in_share_list, :colour)
permission_params.transform_values! do |v|
if v == "0"

View File

@ -56,6 +56,8 @@ class PasswordResetsController < ApplicationController
# Password does not match password confirmation
flash.now[:alert] = I18n.t("password_different_notice")
elsif @user.update_attributes(user_params)
# Clear the user's social uid if they are switching from a social to a local account
@user.update_attribute(:social_uid, nil) if @user.social_uid.present?
# Successfully reset password
return redirect_to root_path, flash: { success: I18n.t("password_reset_success") }
end
@ -66,7 +68,7 @@ class PasswordResetsController < ApplicationController
private
def find_user
@user = User.find_by(email: params[:email])
@user = User.find_by(reset_digest: User.digest(params[:id]), provider: @user_domain)
end
def user_params

View File

@ -20,14 +20,18 @@ class RoomsController < ApplicationController
include Pagy::Backend
include Recorder
include Joiner
include Populator
before_action :validate_accepted_terms, unless: -> { !Rails.configuration.terms }
before_action :validate_verified_email, except: [:show, :join],
unless: -> { !Rails.configuration.enable_email_verification }
before_action :find_room, except: [:create, :join_specific_room]
before_action :verify_room_ownership, only: [:destroy, :start, :update_settings]
before_action :verify_room_ownership_or_admin_or_shared, only: [:start, :shared_access]
before_action :verify_room_ownership_or_admin, only: [:update_settings, :destroy]
before_action :verify_room_ownership_or_shared, only: [:remove_shared_access]
before_action :verify_room_owner_verified, only: [:show, :join],
unless: -> { !Rails.configuration.enable_email_verification }
before_action :verify_room_owner_valid, only: [:show, :join]
before_action :verify_user_not_admin, only: [:show]
# POST /
@ -60,14 +64,17 @@ class RoomsController < ApplicationController
def show
@anyone_can_start = JSON.parse(@room[:room_settings])["anyoneCanStart"]
@room_running = room_running?(@room.bbb_id)
@shared_room = room_shared_with_user
# If its the current user's room
if current_user && @room.owned_by?(current_user)
if current_user && (@room.owned_by?(current_user) || @shared_room)
if current_user.highest_priority_role.get_permission("can_create_rooms")
# User is allowed to have rooms
@search, @order_column, @order_direction, recs =
recordings(@room.bbb_id, params.permit(:search, :column, :direction), true)
@user_list = shared_user_list if shared_access_allowed
@pagy, @recordings = pagy_array(recs)
else
# Render view for users that cant create rooms
@ -112,10 +119,21 @@ class RoomsController < ApplicationController
# DELETE /:room_uid
def destroy
# Don't delete the users home room.
@room.destroy if @room.owned_by?(current_user) && @room != current_user.main_room
begin
# Don't delete the users home room.
raise I18n.t("room.delete.home_room") if @room == @room.owner.main_room
@room.destroy
rescue => e
flash[:alert] = I18n.t("room.delete.fail", error: e)
else
flash[:success] = I18n.t("room.delete.success")
end
redirect_to current_user.main_room
# Redirect to home room if the redirect_back location is the deleted room
return redirect_to @current_user.main_room if request.referer == room_url(@room)
# Redirect to the location that the user deleted the room from
redirect_back fallback_location: current_user.main_room
end
# POST /room/join
@ -162,7 +180,6 @@ class RoomsController < ApplicationController
begin
options = params[:room].nil? ? params : params[:room]
raise "Room name can't be blank" if options[:name].blank?
raise "Unauthorized Request" if !@room.owned_by?(current_user) || @room == current_user.main_room
# Update the rooms values
room_settings_string = create_room_settings_string(options)
@ -179,7 +196,64 @@ class RoomsController < ApplicationController
flash[:alert] = I18n.t("room.update_settings_error")
end
redirect_to room_path
redirect_back fallback_location: room_path(@room)
end
# POST /:room_uid/update_shared_access
def shared_access
begin
current_list = @room.shared_users.pluck(:id)
new_list = User.where(uid: params[:add]).pluck(:id)
# Get the list of users that used to be in the list but were removed
users_to_remove = current_list - new_list
# Get the list of users that are in the new list but not in the current list
users_to_add = new_list - current_list
# Remove users that are removed
SharedAccess.where(room_id: @room.id, user_id: users_to_remove).delete_all unless users_to_remove.empty?
# Add users that are added
users_to_add.each do |id|
SharedAccess.create(room_id: @room.id, user_id: id)
end
flash[:success] = I18n.t("room.shared_access_success")
rescue => e
logger.error "Support: Error in updating room shared access: #{e}"
flash[:alert] = I18n.t("room.shared_access_error")
end
redirect_back fallback_location: room_path
end
# POST /:room_uid/remove_shared_access
def remove_shared_access
begin
SharedAccess.find_by!(room_id: @room.id, user_id: params[:user_id]).destroy
flash[:success] = I18n.t("room.remove_shared_access_success")
rescue => e
logger.error "Support: Error in removing room shared access: #{e}"
flash[:alert] = I18n.t("room.remove_shared_access_error")
end
redirect_to current_user.main_room
end
# GET /:room_uid/shared_users
def shared_users
# Respond with JSON object of users that have access to the room
respond_to do |format|
format.json { render body: @room.shared_users.to_json }
end
end
# GET /:room_uid/room_settings
def room_settings
# Respond with JSON object of the room_settings
respond_to do |format|
format.json { render body: @room.room_settings.to_json }
end
end
# GET /:room_uid/logout
@ -219,12 +293,24 @@ class RoomsController < ApplicationController
# Find the room from the uid.
def find_room
@room = Room.find_by!(uid: params[:room_uid])
@room = Room.includes(:owner).find_by!(uid: params[:room_uid])
end
# Ensure the user is logged into the room they are accessing.
def verify_room_ownership
return redirect_to root_path unless @room.owned_by?(current_user)
# Ensure the user either owns the room or is an admin of the room owner or the room is shared with him
def verify_room_ownership_or_admin_or_shared
return redirect_to root_path unless @room.owned_by?(current_user) ||
room_shared_with_user ||
current_user&.admin_of?(@room.owner)
end
# Ensure the user either owns the room or is an admin of the room owner
def verify_room_ownership_or_admin
return redirect_to root_path if !@room.owned_by?(current_user) && !current_user&.admin_of?(@room.owner)
end
# Ensure the user owns the room or is allowed to start it
def verify_room_ownership_or_shared
return redirect_to root_path unless @room.owned_by?(current_user) || room_shared_with_user
end
def validate_accepted_terms
@ -236,10 +322,12 @@ class RoomsController < ApplicationController
end
def verify_room_owner_verified
unless @room.owner.activated?
flash[:alert] = t("room.unavailable")
redirect_to root_path
end
redirect_to root_path, alert: t("room.unavailable") unless @room.owner.activated?
end
# Check to make sure the room owner is not pending or banned
def verify_room_owner_valid
redirect_to root_path, alert: t("room.owner_banned") if @room.owner.has_role?(:pending) || @room.owner.has_role?(:denied)
end
def verify_user_not_admin
@ -250,6 +338,11 @@ class RoomsController < ApplicationController
@settings.get_value("Room Authentication") == "true" && current_user.nil?
end
# Checks if the room is shared with the user and room sharing is enabled
def room_shared_with_user
shared_access_allowed ? @room.shared_with?(current_user) : false
end
def room_limit_exceeded
limit = @settings.get_value("Room Limit").to_i

View File

@ -74,6 +74,10 @@ class SessionsController < ApplicationController
# Check user with that email exists
return redirect_to(signin_path, alert: I18n.t("invalid_credentials")) unless user
# Check if authenticators have switched
return switch_account_to_local(user) if !is_super_admin && auth_changed_to_local?(user)
# Check correct password was entered
return redirect_to(signin_path, alert: I18n.t("invalid_credentials")) unless user.try(:authenticate,
session_params[:password])
@ -84,7 +88,10 @@ class SessionsController < ApplicationController
# Check that the user is a Greenlight account
return redirect_to(root_path, alert: I18n.t("invalid_login_method")) unless user.greenlight_account?
# Check that the user has verified their account
return redirect_to(account_activation_path(email: user.email)) unless user.activated?
unless user.activated?
user.create_activation_token
return redirect_to(account_activation_path(token: user.activation_token))
end
end
login(user)
@ -199,6 +206,9 @@ class SessionsController < ApplicationController
# 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
# Switch the user to a social account if they exist under the same email with no social uid
switch_account_to_social if !@user_exists && auth_changed_to_social?(@auth['info']['email'])
user = User.from_omniauth(@auth)
logger.info "Support: Auth user #{user.email} is attempting to login."
@ -225,4 +235,28 @@ class SessionsController < ApplicationController
end
end
end
# Send the user a password reset email to allow them to set their password
def switch_account_to_local(user)
logger.info "Switching social account to local account for #{user.uid}"
# Send the user a reset password email
user.create_reset_digest
send_password_reset_email(user)
# Overwrite the flash with a more descriptive message if successful
flash[:success] = I18n.t("reset_password.auth_change") if flash[:success].present?
redirect_to signin_path
end
# Set the user's social id to the new id being passed
def switch_account_to_social
user = User.find_by(email: @auth['info']['email'], provider: @user_domain, social_uid: nil)
logger.info "Switching account to social account for #{user.uid}"
# Set the user's social id to the one being returned from auth
user.update_attribute(:social_uid, @auth['uid'])
end
end

View File

@ -26,7 +26,7 @@ class ThemesController < ApplicationController
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('lib', 'assets', '_primary_themes.scss')
@file_contents = File.read(file_name)
# Include the variables and covert scss file to css

View File

@ -58,6 +58,8 @@ class UsersController < ApplicationController
# Sign in automatically if email verification is disabled or if user is already verified.
login(@user) && return if !Rails.configuration.enable_email_verification || @user.email_verified
@user.create_activation_token
send_activation_email(@user)
redirect_to root_path
@ -80,7 +82,14 @@ class UsersController < ApplicationController
# PATCH /u/:user_uid/edit
def update
profile = params[:setting] == "password" ? change_password_path(@user) : edit_user_path(@user)
redirect_path = current_user.admin_of?(@user) ? admins_path : profile
if session[:prev_url].present?
path = session[:prev_url]
session.delete(:prev_url)
else
path = admins_path
end
redirect_path = current_user.admin_of?(@user) ? path : profile
if params[:setting] == "password"
# Update the users password.
@ -123,12 +132,13 @@ class UsersController < ApplicationController
# DELETE /u/:user_uid
def destroy
# Include deleted users in the check
admin_path = request.referer.present? ? request.referer : admins_path
@user = User.include_deleted.find_by(uid: params[:user_uid])
logger.info "Support: #{current_user.email} is deleting #{@user.email}."
self_delete = current_user == @user
redirect_url = self_delete ? root_path : admins_path
redirect_url = self_delete ? root_path : admin_path
begin
if current_user && (self_delete || current_user.admin_of?(@user))
@ -183,7 +193,7 @@ class UsersController < ApplicationController
private
def find_user
@user = User.where(uid: params[:user_uid]).includes(:roles).first
@user = User.find_by(uid: params[:user_uid])
end
# Verify that GreenLight is configured to allow user signup.

View File

@ -37,6 +37,14 @@ module AdminsHelper
end
end
def shared_access_string
if @settings.get_value("Shared Access") == "true"
I18n.t("administrator.site_settings.authentication.enabled")
else
I18n.t("administrator.site_settings.authentication.disabled")
end
end
def recording_default_visibility_string
if @settings.get_value("Default Recording Visibility") == "public"
I18n.t("recording.visibility.public")
@ -56,6 +64,23 @@ module AdminsHelper
end
end
def log_level_string
case Rails.logger.level
when 0
t("administrator.site_settings.log_level.debug")
when 1
t("administrator.site_settings.log_level.info")
when 2
t("administrator.site_settings.log_level.warn")
when 3
t("administrator.site_settings.log_level.error")
when 4
t("administrator.site_settings.log_level.fatal")
when 5
t("administrator.site_settings.log_level.unknown")
end
end
def room_limit_number
@settings.get_value("Room Limit").to_i
end
@ -63,4 +88,9 @@ module AdminsHelper
def edit_disabled
@edit_disabled ||= @selected_role.priority <= current_user.highest_priority_role.priority
end
# Get the room status to display in the Server Rooms table
def room_is_running(id)
@running_room_bbb_ids.include?(id)
end
end

View File

@ -57,7 +57,6 @@ module ApplicationHelper
# Returns the page that the logo redirects to when clicked on
def home_page
return root_path unless current_user
return admins_path if current_user.has_role? :super_admin
current_user.main_room
end

View File

@ -24,18 +24,13 @@ module RecordingsHelper
# Helper for converting BigBlueButton dates into a nice length string.
def recording_length(playbacks)
# Stats format currently doesn't support length.
valid_playbacks = playbacks.reject { |p| p[:type] == "statistics" }
return "0 min" if valid_playbacks.empty?
len = valid_playbacks.first[:length]
if len > 60
"#{(len / 60).to_i} h #{len % 60} min"
elsif len.zero?
"< 1 min"
else
"#{len} min"
# Looping through playbacks array and returning first non-zero length value
playbacks.each do |playback|
length = playback[:length]
return recording_length_string(length) unless length.zero?
end
# Return '< 1 min' if length values are zero
"< 1 min"
end
# Prevents single images from erroring when not passed as an array.
@ -51,4 +46,15 @@ module RecordingsHelper
def recording_thumbnails?
Rails.configuration.recording_thumbnails
end
private
# Returns length of the recording as a string
def recording_length_string(len)
if len > 60
"#{(len / 60).to_i} h #{len % 60} min"
else
"#{len} min"
end
end
end

View File

@ -27,7 +27,7 @@ class Ability
else
highest_role = user.highest_priority_role
if highest_role.get_permission("can_edit_site_settings")
can [:index, :site_settings, :server_recordings, :update_settings, :coloring, :registration_method], :admin
can [:index, :site_settings, :update_settings, :coloring, :registration_method], :admin
end
if highest_role.get_permission("can_edit_roles")
@ -36,11 +36,13 @@ class Ability
if highest_role.get_permission("can_manage_users")
can [:index, :roles, :edit_user, :promote, :demote, :ban_user, :unban_user,
:approve, :invite, :reset, :undelete], :admin
:approve, :invite, :reset, :undelete, :merge_user], :admin
end
can [:index, :server_recordings, :server_rooms], :admin if highest_role.get_permission("can_manage_rooms_recordings")
if !highest_role.get_permission("can_edit_site_settings") && !highest_role.get_permission("can_edit_roles") &&
!highest_role.get_permission("can_manage_users")
!highest_role.get_permission("can_manage_users") && !highest_role.get_permission("can_manage_rooms_recordings")
cannot :manage, AdminsController
end
end

View File

@ -48,6 +48,9 @@ module AuthValues
case auth['provider']
when :twitter
auth['info']['image'].gsub("http", "https").gsub("_normal", "")
when :ldap
return auth['info']['image'] if auth['info']['image']&.starts_with?("http")
""
else
auth['info']['image']
end

View File

@ -20,7 +20,7 @@ class Role < ApplicationRecord
has_and_belongs_to_many :users, join_table: :users_roles
has_many :role_permissions
default_scope { order(:priority) }
default_scope { includes(:role_permissions).order(:priority) }
scope :by_priority, -> { order(:priority) }
scope :editable_roles, ->(provider) { where(provider: provider).where.not(name: %w[super_admin denied pending]) }
@ -35,14 +35,14 @@ class Role < ApplicationRecord
.update_all_role_permissions(can_create_rooms: true)
Role.create(name: "admin", provider: provider, priority: 0, colour: "#f1c40f")
.update_all_role_permissions(can_create_rooms: true, send_promoted_email: true,
send_demoted_email: true, can_edit_site_settings: true,
send_demoted_email: true, can_edit_site_settings: true, can_manage_rooms_recordings: true,
can_edit_roles: true, can_manage_users: true)
Role.create(name: "pending", provider: provider, priority: -1, colour: "#17a2b8").update_all_role_permissions
Role.create(name: "denied", provider: provider, priority: -1, colour: "#343a40").update_all_role_permissions
Role.create(name: "super_admin", provider: provider, priority: -2, colour: "#cd201f")
Role.create(name: "denied", provider: provider, priority: -2, colour: "#343a40").update_all_role_permissions
Role.create(name: "super_admin", provider: provider, priority: -3, colour: "#cd201f")
.update_all_role_permissions(can_create_rooms: true,
send_promoted_email: true, send_demoted_email: true, can_edit_site_settings: true,
can_edit_roles: true, can_manage_users: true)
can_edit_roles: true, can_manage_users: true, can_manage_rooms_recordings: true)
end
def self.create_new_role(role_name, provider)
@ -55,8 +55,8 @@ class Role < ApplicationRecord
role.priority = user_role.priority
user_role.priority += 1
role.save!
user_role.save!
role.save!
role
end
@ -68,10 +68,15 @@ class Role < ApplicationRecord
update_permission("can_edit_site_settings", permissions[:can_edit_site_settings].to_s)
update_permission("can_edit_roles", permissions[:can_edit_roles].to_s)
update_permission("can_manage_users", permissions[:can_manage_users].to_s)
update_permission("can_manage_rooms_recordings", permissions[:can_manage_rooms_recordings].to_s)
update_permission("can_appear_in_share_list", permissions[:can_appear_in_share_list].to_s)
end
# Updates the value of the permission and enables it
def update_permission(name, value)
# Dont update if it is not explicitly set to a value
return unless value.present?
permission = role_permissions.find_or_create_by!(name: name)
permission.update_attributes(value: value, enabled: true)
@ -79,18 +84,36 @@ class Role < ApplicationRecord
# Returns the value if enabled or the default if not enabled
def get_permission(name, return_boolean = true)
permission = role_permissions.find_or_create_by!(name: name)
value = nil
value = if permission[:enabled]
permission[:value]
else
"false"
role_permissions.each do |permission|
next if permission.name != name
value = if permission.enabled
permission.value
else
default_value(name)
end
end
# Create the role_permissions since it doesn't exist
role_permissions.create(name: name) if value.nil?
if return_boolean
value == "true"
else
value
end
end
private
def default_value(name)
case name
when "can_appear_in_share_list"
Rails.configuration.shared_access_default.to_s
else
"false"
end
end
end

View File

@ -26,11 +26,46 @@ class Room < ApplicationRecord
validates :name, presence: true
belongs_to :owner, class_name: 'User', foreign_key: :user_id
has_many :shared_access
def self.admins_search(string)
active_database = Rails.configuration.database_configuration[Rails.env]["adapter"]
# Postgres requires created_at to be cast to a string
created_at_query = if active_database == "postgresql"
"created_at::text"
else
"created_at"
end
search_query = "rooms.name LIKE :search OR rooms.uid LIKE :search OR users.email LIKE :search" \
" OR users.#{created_at_query} LIKE :search"
search_param = "%#{string}%"
where(search_query, search: search_param)
end
def self.admins_order(column, direction)
# Include the owner of the table
table = joins(:owner)
return table.order(Arel.sql("rooms.#{column} #{direction}")) if table.column_names.include?(column) || column == "users.name"
table
end
# Determines if a user owns a room.
def owned_by?(user)
user_id == user&.id
end
def shared_users
User.where(id: shared_access.pluck(:user_id))
end
def shared_with?(user)
return false if user.nil?
user.rooms.include?(self)
shared_users.include?(user)
end
# Determines the invite path for the room.

View File

@ -28,22 +28,36 @@ class Setting < ApplicationRecord
# Returns the value if enabled or the default if not enabled
def get_value(name)
feature = features.find_or_create_by!(name: name)
if feature[:enabled]
feature[:value]
else
case name
when "Branding Image"
Rails.configuration.branding_image_default
when "Primary Color"
Rails.configuration.primary_color_default
when "Registration Method"
Rails.configuration.registration_method_default
when "Room Authentication"
false
when "Room Limit"
Rails.configuration.number_of_rooms_default
end
# Return feature value if already exists
features.each do |feature|
next if feature.name != name
return feature.value if feature.enabled
return default_value(name)
end
# Create the feature since it doesn't exist
features.create(name: name)
default_value(name)
end
private
def default_value(name)
# return default value
case name
when "Branding Image"
Rails.configuration.branding_image_default
when "Primary Color"
Rails.configuration.primary_color_default
when "Registration Method"
Rails.configuration.registration_method_default
when "Room Authentication"
false
when "Room Limit"
Rails.configuration.number_of_rooms_default
when "Shared Access"
Rails.configuration.shared_access_default
end
end
end

View File

@ -0,0 +1,5 @@
# frozen_string_literal: true
class SharedAccess < ApplicationRecord
belongs_to :room
end

View File

@ -21,7 +21,7 @@ require 'bbb_api'
class User < ApplicationRecord
include Deleteable
attr_accessor :reset_token
attr_accessor :reset_token, :activation_token
after_create :setup_user
before_save { email.try(:downcase!) }
@ -29,9 +29,10 @@ class User < ApplicationRecord
before_destroy :destroy_rooms
has_many :rooms
has_many :shared_access
belongs_to :main_room, class_name: 'Room', foreign_key: :room_id, required: false
has_and_belongs_to_many :roles, -> { includes :role_permissions }, join_table: :users_roles
has_and_belongs_to_many :roles, join_table: :users_roles
validates :name, length: { maximum: 256 }, presence: true
validates :provider, presence: true
@ -102,6 +103,11 @@ class User < ApplicationRecord
order(Arel.sql("#{column} #{direction}"))
end
# Returns a list of rooms ordered by last session
def ordered_rooms
[main_room] + rooms.where.not(id: main_room.id).order("last_session desc")
end
# Activates an account and initialize a users main room
def activate
update_attributes(email_verified: true, activated_at: Time.zone.now)
@ -121,7 +127,7 @@ class User < ApplicationRecord
def authenticated?(attribute, token)
digest = send("#{attribute}_digest")
return false if digest.nil?
BCrypt::Password.new(digest).is_password?(token)
digest == Digest::SHA256.base64digest(token)
end
# Return true if password reset link expires
@ -129,10 +135,9 @@ class User < ApplicationRecord
reset_sent_at < 2.hours.ago
end
# Retrives a list of all a users rooms that are not the main room, sorted by last session date.
def secondary_rooms
room_list = rooms.where.not(uid: main_room.uid)
room_list.where.not(last_session: nil).order("last_session desc") + room_list.where(last_session: nil)
# Retrieves a list of rooms that are shared with the user
def shared_rooms
Room.where(id: shared_access.pluck(:room_id))
end
def name_chunk
@ -153,9 +158,9 @@ class User < ApplicationRecord
social_uid.nil?
end
def activation_token
# Create the token.
create_reset_activation_digest(User.new_token)
def create_activation_token
self.activation_token = User.new_token
update_attributes(activation_digest: User.digest(activation_token))
end
def admin_of?(user)
@ -172,8 +177,7 @@ class User < ApplicationRecord
end
def self.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
Digest::SHA256.base64digest(string)
end
# Returns a random token.
@ -183,7 +187,7 @@ class User < ApplicationRecord
# role functions
def highest_priority_role
roles.by_priority.first
roles.min_by(&:priority)
end
def add_role(role)
@ -217,7 +221,11 @@ class User < ApplicationRecord
# rubocop:disable Naming/PredicateName
def has_role?(role)
# rubocop:enable Naming/PredicateName
roles.exists?(name: role)
roles.each do |single_role|
return true if single_role.name.eql? role.to_s
end
false
end
def self.with_role(role)
@ -228,19 +236,24 @@ class User < ApplicationRecord
User.where.not(id: with_role(role).pluck(:id))
end
def self.with_highest_priority_role(role)
User.all_users_highest_priority_role.where(roles: { name: role })
end
def self.all_users_with_roles
User.joins("INNER JOIN users_roles ON users_roles.user_id = users.id INNER JOIN roles " \
"ON roles.id = users_roles.role_id INNER JOIN role_permissions ON roles.id = role_permissions.role_id").distinct
end
private
def create_reset_activation_digest(token)
# Create the digest and persist it.
update_attribute(:activation_digest, User.digest(token))
token
def self.all_users_highest_priority_role
User.joins("INNER JOIN (SELECT user_id, min(roles.priority) as role_priority FROM users_roles " \
"INNER JOIN roles ON users_roles.role_id = roles.id GROUP BY user_id) as a ON " \
"a.user_id = users.id INNER JOIN roles ON roles.priority = a.role_priority " \
" INNER JOIN role_permissions ON roles.id = role_permissions.role_id").distinct
end
private
# Destory a users rooms when they are removed.
def destroy_rooms
rooms.destroy_all

View File

@ -22,7 +22,7 @@
<div class="card-body">
<p><%= t("verify.not_verified") %></p>
<div class="btn-list text-right pt-8">
<%= button_to t("verify.resend"), resend_email_path, params: { email: params['email'], email_verified: false }, class: "btn btn-primary btn-space" %>
<%= button_to t("verify.resend"), resend_email_path, params: { token: params['token'], email_verified: false }, class: "btn btn-primary btn-space", "data-disable": "" %>
</div>
</div>
</div>

View File

@ -21,17 +21,22 @@
<span class="icon mr-3"><i class="fas fa-users"></i></span><%= t("administrator.users.title") %>
<% end %>
<% end %>
<% if highest_role.get_permission("can_edit_site_settings") || highest_role.name == "super_admin" %>
<%= link_to admin_recordings_path, class: "list-group-item list-group-item-action dropdown-item #{"active" if active_page == "server_recordings"}" do %>
<span class="icon mr-4"><i class="fas fa-video"></i></i></span><%= t("administrator.recordings.title") %>
<% if highest_role.get_permission("can_manage_rooms_recordings") || highest_role.name == "super_admin" %>
<%= link_to admin_rooms_path, class: "list-group-item list-group-item-action dropdown-item #{"active" if active_page == "server_rooms"}" do %>
<span class="icon mr-4"><i class="fas fa-binoculars"></i></span><%= t("administrator.rooms.title") %>
<% end %>
<%= link_to admin_recordings_path, class: "list-group-item list-group-item-action dropdown-item #{"active" if active_page == "server_recordings"}" do %>
<span class="icon mr-4"><i class="fas fa-video"></i></span><%= t("administrator.recordings.title") %>
<% end %>
<% end %>
<% if highest_role.get_permission("can_edit_site_settings") || highest_role.name == "super_admin" %>
<%= link_to admin_site_settings_path, class: "list-group-item list-group-item-action dropdown-item #{"active" if active_page == "site_settings"}" do %>
<span class="icon mr-4"><i class="fas fa-cogs"></i></span><%= t("administrator.site_settings.title") %>
<% end %>
<% end %>
<% if highest_role.get_permission("can_edit_roles") || highest_role.name == "super_admin" %>
<%= link_to admin_roles_path, class: "list-group-item list-group-item-action dropdown-item #{"active" if active_page == "roles"}" do %>
<span class="icon mr-4"><i class="fas fa-user-tag"></i></i></span><%= t("administrator.roles.title") %>
<span class="icon mr-4"><i class="fas fa-user-tag"></i></span><%= t("administrator.roles.title") %>
<% end %>
<% end %>
</div>

View File

@ -53,14 +53,14 @@
<%= f.check_box :can_create_rooms, checked: @selected_role.get_permission("can_create_rooms"), class: "custom-switch-input", disabled: edit_disabled || !current_role.get_permission("can_create_rooms") %>
<span class="custom-switch-indicator float-right"></span>
</label>
<label class="custom-switch pl-0 mt-3 mb-3 w-100 text-left d-inline-block <%="form-disable" if !current_role.get_permission("send_promoted_email") %>">
<span class="ml-0 custom-switch-description"><%= t("administrator.roles.promote_email")%></span>
<%= f.check_box :send_promoted_email, checked: @selected_role.get_permission("send_promoted_email"), class: "custom-switch-input", disabled: edit_disabled || !current_role.get_permission("send_promoted_email") %>
<label class="custom-switch pl-0 mt-3 mb-3 w-100 text-left d-inline-block <%="form-disable" if !current_role.get_permission("can_manage_users") %>">
<span class="ml-0 custom-switch-description"><%= t("administrator.roles.manage_users")%></span>
<%= f.check_box :can_manage_users, checked: @selected_role.get_permission("can_manage_users"), class: "custom-switch-input", disabled: edit_disabled || !current_role.get_permission("can_manage_users") %>
<span class="custom-switch-indicator float-right"></span>
</label>
<label class="custom-switch pl-0 mt-3 mb-3 w-100 text-left d-inline-block <%="form-disable" if !current_role.get_permission("send_demoted_email") %>">
<span class="ml-0 custom-switch-description"><%= t("administrator.roles.demote_email")%></span>
<%= f.check_box :send_demoted_email, checked: @selected_role.get_permission("send_demoted_email"), class: "custom-switch-input", disabled: edit_disabled || !current_role.get_permission("send_demoted_email") %>
<label class="custom-switch pl-0 mt-3 mb-3 w-100 text-left d-inline-block <%="form-disable" if !current_role.get_permission("can_manage_rooms_recordings") %>">
<span class="ml-0 custom-switch-description"><%= t("administrator.roles.manage_rooms_recordings")%></span>
<%= f.check_box :can_manage_rooms_recordings, checked: @selected_role.get_permission("can_manage_rooms_recordings"), class: "custom-switch-input", disabled: edit_disabled || !current_role.get_permission("can_manage_rooms_recordings") %>
<span class="custom-switch-indicator float-right"></span>
</label>
<label class="custom-switch pl-0 mt-3 mb-3 w-100 text-left d-inline-block <%="form-disable" if !current_role.get_permission("can_edit_site_settings") %>">
@ -73,9 +73,19 @@
<%= f.check_box :can_edit_roles, checked: @selected_role.get_permission("can_edit_roles"), class: "custom-switch-input", disabled: edit_disabled || !current_role.get_permission("can_edit_roles") %>
<span class="custom-switch-indicator float-right"></span>
</label>
<label class="custom-switch pl-0 mt-3 mb-3 w-100 text-left d-inline-block <%="form-disable" if !current_role.get_permission("can_manage_users") %>">
<span class="ml-0 custom-switch-description"><%= t("administrator.roles.manage_users")%></span>
<%= f.check_box :can_manage_users, checked: @selected_role.get_permission("can_manage_users"), class: "custom-switch-input", disabled: edit_disabled || !current_role.get_permission("can_manage_users") %>
<label class="custom-switch pl-0 mt-3 mb-3 w-100 text-left d-inline-block <%="form-disable" if !current_role.get_permission("can_appear_in_share_list") %>">
<span class="ml-0 custom-switch-description"><%= t("administrator.roles.appear_in_share_list")%></span>
<%= f.check_box :can_appear_in_share_list, checked: @selected_role.get_permission("can_appear_in_share_list"), class: "custom-switch-input", disabled: edit_disabled || !current_role.get_permission("can_appear_in_share_list") %>
<span class="custom-switch-indicator float-right"></span>
</label>
<label class="custom-switch pl-0 mt-3 mb-3 w-100 text-left d-inline-block <%="form-disable" if !current_role.get_permission("send_promoted_email") %>">
<span class="ml-0 custom-switch-description"><%= t("administrator.roles.promote_email")%></span>
<%= f.check_box :send_promoted_email, checked: @selected_role.get_permission("send_promoted_email"), class: "custom-switch-input", disabled: edit_disabled || !current_role.get_permission("send_promoted_email") %>
<span class="custom-switch-indicator float-right"></span>
</label>
<label class="custom-switch pl-0 mt-3 mb-3 w-100 text-left d-inline-block <%="form-disable" if !current_role.get_permission("send_demoted_email") %>">
<span class="ml-0 custom-switch-description"><%= t("administrator.roles.demote_email")%></span>
<%= f.check_box :send_demoted_email, checked: @selected_role.get_permission("send_demoted_email"), class: "custom-switch-input", disabled: edit_disabled || !current_role.get_permission("send_demoted_email") %>
<span class="custom-switch-indicator float-right"></span>
</label>

View File

@ -0,0 +1,65 @@
<%
# 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="row">
<div class="col-12">
<div class="table-responsive">
<table id="rooms-table" class="table table-hover table-outline table-vcenter text-nowrap card-table">
<thead>
<tr>
<th data-header="name" data-order="<%= @order_column == "name" ? @order_direction : "none" %>">
<%= t("administrator.users.table.name") %>
<% if @order_column == "name" && @order_direction == "desc" %>
<% elsif @order_column == "name" && @order_direction == "asc" %>
<% end %>
</th>
<th data-header="users.name" data-order="<%= @order_column == "users.name" ? @order_direction : "none" %>">
<%= t("room.owner") %>
<% if @order_column == "users.name" && @order_direction == "desc" %>
<% elsif @order_column == "users.name" && @order_direction == "asc" %>
<% end %>
</th>
<th data-header="uid" data-order="<%= @order_column == "uid" ? @order_direction : "none" %>">
<%= t("administrator.rooms.table.id") %>
<% if @order_column == "uid" && @order_direction == "desc" %>
<% elsif @order_column == "uid" && @order_direction == "asc" %>
<% end %>
</th>
<th>
<%= t("administrator.rooms.table.status") %>
</th>
<th class="text-center"><i class="icon-settings"></i></th>
</tr>
</thead>
<tbody id="rooms-table">
<% @rooms.each do |room| %>
<%= render "admins/components/server_room_row", room: room %>
<% end %>
</tbody>
</table>
<% if !@rooms.empty?%>
<div class="float-right mr-4 mt-4">
<%== pagy_bootstrap_nav(@pagy) %>
</div>
<% end %>
</div>
</div>
</div>

View File

@ -46,10 +46,10 @@
<button class="btn btn-sm btn-secondary dropdown-toggle" data-toggle="dropdown"><i class="dropdown-icon fas fa-link px-2"></i> <%= t("recording.visibility.unlisted") %></button>
<% end %>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<%= button_to update_recording_path(meetingID: recording[:meetingID], record_id: recording[:recordID], state: "public"), class: "dropdown-item" do %>
<%= button_to update_recording_path(meetingID: recording[:meetingID], record_id: recording[:recordID], state: "public"), class: "dropdown-item", "data-disable": "" do %>
<i class="dropdown-icon fas fa-globe"></i> <%= t("recording.visibility.public") %>
<% end %>
<%= button_to update_recording_path(meetingID: recording[:meetingID], record_id: recording[:recordID], state: "unlisted"), class: "dropdown-item" do %>
<%= button_to update_recording_path(meetingID: recording[:meetingID], record_id: recording[:recordID], state: "unlisted"), class: "dropdown-item", "data-disable": "" do %>
<i class="dropdown-icon fas fa-link"></i> <%= t("recording.visibility.unlisted") %>
<% end %>
</div>
@ -73,7 +73,7 @@
<a class="dropdown-item email-link" data-pres-link="<%= recording_links %>"><i class="dropdown-icon far fa-envelope"></i> <%= t("recording.email") %></a>
<div class="dropdown-divider"></div>
<% end %>
<%= button_to delete_recording_path(meetingID: recording[:meetingID], record_id: recording[:recordID]), method: :delete, class: "dropdown-item" do %>
<%= button_to delete_recording_path(meetingID: recording[:meetingID], record_id: recording[:recordID]), method: :delete, class: "dropdown-item", "data-disable": "" do %>
<i class="dropdown-icon far fa-trash-alt"></i> <%= t("delete") %>
<% end %>
</div>

View File

@ -0,0 +1,72 @@
<%
# 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/>.
%>
<tr id="room-block" data-path="<%= update_settings_path(room) %>" data-room-settings=<%= room.room_settings %> data-room-access-code="<%= room.access_code %>">
<td>
<div id="room-title" class="form-inline edit_hover_class">
<% if room.id == room.owner.room_id %>
<i class="fas fa-home pr-1"></i>
<% end %>
<text id="room-name-text">
<%= room.name %>
</text>
</div>
<div class="small text-muted">
<%= [t("administrator.users.table.created"), ": ", room.created_at].join %>
</div>
</td>
<td class="text-left">
<%= room.owner.name %>
</td>
<td class="text-left">
<%= room.uid %>
</td>
<td class="text-left">
<% running = room_is_running(room.bbb_id) %>
<% if running %>
<%= t("administrator.rooms.running") %>
<% else %>
<%= t("administrator.rooms.not_running") %>
<% end %>
</td>
<td class="text-center">
<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-right">
<%= link_to room_path(room), class: "dropdown-item" do %>
<i class="dropdown-icon far fa-eye"></i> <%= t("administrator.rooms.view") %>
<% end %>
<%= button_to start_room_path(room), class: "dropdown-item", "data-disable": "" do %>
<i class="dropdown-icon fas fa-door-open"></i> <%= running ? t("room.join") : t("room.start") %>
<% end %>
<a href="" data-toggle="modal" data-target="#createRoomModal" class="update-room dropdown-item">
<i class="dropdown-icon fas fa-cog"></i> <%= t("room.settings") %>
</a>
<% if shared_access_allowed %>
<a href="" data-toggle="modal" data-target="#shareRoomModal" class="share-room dropdown-item" data-path="<%= room_shared_access_path(room) %>" data-users-path="<%= room_shared_users_path(room) %>">
<i class="dropdown-icon fas fa-users"></i> <%= t("room.share") %>
</a>
<% end %>
<% if room.id != room.owner.room_id %>
<a href="" data-toggle="modal" data-target="#deleteRoomModal" data-path="<%= room_path(room) %>" data-name="<%= room.name %>" class="delete-room dropdown-item">
<i class="dropdown-icon far fa-trash-alt"></i> <%= t("delete") %>
</a>
<% end %>
</div>
</div>
</td>
</tr>

View File

@ -64,13 +64,13 @@
<%= registration_method_string %>
</button>
<div class="dropdown-menu" aria-labelledby="registrationMethods">
<%= button_to admin_change_registration_path(value: "open"), class: "dropdown-item" do %>
<%= button_to admin_change_registration_path(value: "open"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.registration.methods.open") %>
<% end %>
<%= button_to admin_change_registration_path(value: "invite"), class: "dropdown-item" do %>
<%= button_to admin_change_registration_path(value: "invite"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.registration.methods.invite") %>
<% end %>
<%= button_to admin_change_registration_path(value: "approval"), class: "dropdown-item" do %>
<%= button_to admin_change_registration_path(value: "approval"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.registration.methods.approval") %>
<% end %>
</div>
@ -88,10 +88,10 @@
<%= room_authentication_string %>
</button>
<div class="dropdown-menu" aria-labelledby="room-auth">
<%= button_to admin_update_settings_path(setting: "Room Authentication", value: "true"), class: "dropdown-item" do %>
<%= button_to admin_update_settings_path(setting: "Room Authentication", value: "true"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.authentication.enabled") %>
<% end %>
<%= button_to admin_update_settings_path(setting: "Room Authentication", value: "false"), class: "dropdown-item" do %>
<%= button_to admin_update_settings_path(setting: "Room Authentication", value: "false"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.authentication.disabled") %>
<% end %>
</div>
@ -99,7 +99,28 @@
</div>
</div>
</div>
<div class="mb-6 row">
<div class="mb-6 row">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.shared_access.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.shared_access.info") %></label>
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" id="room-auth" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<%= shared_access_string %>
</button>
<div class="dropdown-menu" aria-labelledby="room-auth">
<%= button_to admin_update_settings_path(setting: "Shared Access", value: "true"), class: "dropdown-item" do %>
<%= t("administrator.site_settings.authentication.enabled") %>
<% end %>
<%= button_to admin_update_settings_path(setting: "Shared Access", value: "false"), class: "dropdown-item" do %>
<%= t("administrator.site_settings.authentication.disabled") %>
<% end %>
</div>
</div>
</div>
</div>
</div>
<div class="mb-6 row">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.recording_visibility.title") %></label>
@ -109,10 +130,10 @@
<%= recording_default_visibility_string %>
</button>
<div class="dropdown-menu" aria-labelledby="room-auth">
<%= button_to admin_update_settings_path(setting: "Default Recording Visibility", value: "public"), class: "dropdown-item" do %>
<%= button_to admin_update_settings_path(setting: "Default Recording Visibility", value: "public"), class: "dropdown-item", "data-disable": "" do %>
<%= t("recording.visibility.public") %>
<% end %>
<%= button_to admin_update_settings_path(setting: "Default Recording Visibility", value: "private"), class: "dropdown-item" do %>
<%= button_to admin_update_settings_path(setting: "Default Recording Visibility", value: "private"), class: "dropdown-item", "data-disable": "" do %>
<%= t("recording.visibility.unlisted") %>
<% end %>
</div>
@ -128,25 +149,25 @@
<div class="row gutters-xs">
<div class="col-auto">
<label class="colorinput">
<%= button_to admin_update_settings_path(setting: "Room Limit", value: 1), class: "colorinput-input" do %><% end %>
<%= button_to admin_update_settings_path(setting: "Room Limit", value: 1), class: "colorinput-input", "data-disable": "" do %><% end %>
<span class="colorinput-color <%= room_limit_number == 1 ? "btn-primary" : "btn-outline-primary" %>">1</span>
</label>
</div>
<div class="col-auto">
<label class="colorinput">
<%= button_to admin_update_settings_path(setting: "Room Limit", value: 5), class: "colorinput-input" do %><% end %>
<%= button_to admin_update_settings_path(setting: "Room Limit", value: 5), class: "colorinput-input", "data-disable": "" do %><% end %>
<span class="colorinput-color <%= room_limit_number == 5 ? "btn-primary" : "btn-outline-primary" %>">5</span>
</label>
</div>
<div class="col-auto">
<label class="colorinput">
<%= button_to admin_update_settings_path(setting: "Room Limit", value: 10), class: "colorinput-input" do %><% end %>
<%= button_to admin_update_settings_path(setting: "Room Limit", value: 10), class: "colorinput-input", "data-disable": "" do %><% end %>
<span class="colorinput-color <%= room_limit_number == 10 ? "btn-primary" : "btn-outline-primary" %>">10</span>
</label>
</div>
<div class="col-auto">
<label class="colorinput">
<%= button_to admin_update_settings_path(setting: "Room Limit", value: 15), class: "colorinput-input" do %><% end %>
<%= button_to admin_update_settings_path(setting: "Room Limit", value: 15), class: "colorinput-input", "data-disable": "" do %><% end %>
<span class="colorinput-color <%= room_limit_number == 15 ? "btn-primary" : "btn-outline-primary" %>">15+</span>
</label>
</div>
@ -155,12 +176,55 @@
</div>
</div>
<% if current_user.has_role? :super_admin%>
<hr>
<div class="row">
<div class="col-12">
<div class="mb-6 form-group">
<label class="form-label"><%= t("administrator.site_settings.cache.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.cache.info") %></label>
<%= button_to t("administrator.site_settings.cache.button"), admin_clear_cache_path, class: "btn btn-primary" %>
<%= button_to t("administrator.site_settings.cache.button"), admin_clear_cache_path, class: "btn btn-primary", "data-disable": "" %>
</div>
</div>
</div>
<div class="mb-4 row">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.clear_auth.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.clear_auth.info") %></label>
<%= button_to t("administrator.site_settings.clear_auth.button"), admin_clear_auth_path, class: "btn btn-primary" %>
</div>
</div>
</div>
<div class="mb-4 row">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.log_level.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.log_level.information") %></label>
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" id="room-auth" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<%= log_level_string %>
</button>
<div class="dropdown-menu" aria-labelledby="room-auth">
<%= button_to admin_log_level_path(value: 0), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.log_level.debug") %>
<% end %>
<%= button_to admin_log_level_path(value: 1), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.log_level.info") %>
<% end %>
<%= button_to admin_log_level_path(value: 2), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.log_level.warn") %>
<% end %>
<%= button_to admin_log_level_path(value: 3), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.log_level.error") %>
<% end %>
<%= button_to admin_log_level_path(value: 4), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.log_level.fatal") %>
<% end %>
<%= button_to admin_log_level_path(value: 5), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.log_level.unknown") %>
<% end %>
</div>
</div>
</div>
</div>
</div>

View File

@ -100,31 +100,34 @@
</a>
<div class="dropdown-menu dropdown-menu">
<% if user.deleted? %>
<%= button_to admin_undelete_path(user_uid: user.uid), class: "dropdown-item" do %>
<%= button_to admin_undelete_path(user_uid: user.uid), class: "dropdown-item", "data-disable": "" do %>
<i class="dropdown-icon fas fa-recycle"></i> <%= t("administrator.users.settings.undelete") %>
<% end %>
<button class="delete-user dropdown-item" data-path="<%= delete_user_path(user_uid: user.uid, permanent: "true") %>" data-toggle="modal" data-target="#deleteAccountModal">
<i class="dropdown-icon fas fa-skull-crossbones"></i> <%= t("administrator.users.settings.perm_delete") %>
</button>
<% elsif roles.include?("denied") %>
<%= button_to admin_unban_path(user_uid: user.uid), class: "dropdown-item" do %>
<%= button_to admin_unban_path(user_uid: user.uid), class: "dropdown-item", "data-disable": "" do %>
<i class="dropdown-icon fas fa-lock-open"></i> <%= t("administrator.users.settings.unban") %>
<% end %>
<button class= "delete-user dropdown-item" data-path="<%= delete_user_path(user_uid: user.uid) %>" data-delete="temp-delete" data-toggle="modal" data-target="#deleteAccountModal">
<i class="dropdown-icon fas fa-user-minus"></i> <%= t("administrator.users.settings.delete") %>
</button>
<% elsif roles.include?("pending") %>
<%= button_to admin_approve_path(user_uid: user.uid), class: "dropdown-item" do %>
<%= button_to admin_approve_path(user_uid: user.uid), class: "dropdown-item", "data-disable": "" 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 %>
<%= button_to admin_ban_path(user_uid: user.uid), class: "dropdown-item", "data-disable": "" do %>
<i class="dropdown-icon far fa-times-circle"></i> <%= t("administrator.users.settings.decline") %>
<% end %>
<% else %>
<%= link_to admin_edit_user_path(user_uid: user.uid), class: "dropdown-item" do %>
<i class="dropdown-icon fas fa-user-edit"></i> <%= t("administrator.users.settings.edit") %>
<% end %>
<%= button_to admin_ban_path(user_uid: user.uid), class: "dropdown-item" do %>
<button class= "merge-user dropdown-item" data-path="<%= merge_user_path(user_uid: user.uid) %>" data-info="<%= user.slice(:name, :email, :uid).to_json %>" data-toggle="modal" data-target="#mergeUserModal">
<i class="dropdown-icon fas fa-user-friends"></i> <%= t("administrator.users.settings.merge") %>
</button>
<%= button_to admin_ban_path(user_uid: user.uid), class: "dropdown-item", "data-disable": "" do %>
<i class="dropdown-icon fas fa-lock"></i> <%= t("administrator.users.settings.ban") %>
<% end %>
<button class= "delete-user dropdown-item" data-path="<%= delete_user_path(user_uid: user.uid) %>" data-delete="temp-delete" data-toggle="modal" data-target="#deleteAccountModal">
@ -157,3 +160,4 @@
<%= render "shared/modals/invite_user_modal" %>
<%= render "shared/modals/delete_account_modal", delete_location: relative_root %>
<%= render "shared/modals/merge_user_modal" %>

View File

@ -0,0 +1,33 @@
<%
# 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 pt-6">
<%= render "shared/components/subtitle", subtitle: t("administrator.title"), search: false %>
<div class="row">
<div class="col-lg-3 mb-4">
<%= render "admins/components/menu_buttons" %>
</div>
<div id="server_recordings" class="col-lg-9">
<%= render "admins/components/setting_view", setting_id: "rooms", setting_title: t("administrator.rooms.title"), search: true %>
</div>
</div>
</div>
<%= render "shared/modals/delete_room_modal" %>
<%= render "shared/modals/create_room_modal" %>
<% if shared_access_allowed %>
<%= render "shared/modals/share_room_modal" %>
<% end %>

View File

@ -13,7 +13,7 @@
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
%>
<div id="<%= if room == current_user.main_room then 'home_room_block' else 'room-block' end %>" data-room-uid="<%= room.uid %>" data-room-settings=<%= room.room_settings %> data-room-access-code="<%= room.access_code %>" class="card">
<div id="room-block" data-path="<%= update_settings_path(room) %>" data-room-access-code="<%= room.access_code %>" class="card">
<div class="card-body p-1">
<table class="table table-hover table-vcenter text-wrap table-no-border">
<tbody class="no-border-top">
@ -28,11 +28,7 @@
</td>
<td>
<div id="room-name">
<% if room == current_user.main_room %>
<h4 contenteditable="false" class="m-0 force-text-normal" ><%= t("home_room") %></h4>
<% else %>
<h4 contenteditable="false" class="m-0 force-text-normal" ><%= room.name %></h4>
<% end %>
<h4 id="room-name-text" contenteditable="false" class="m-0 force-text-normal" ><%= room.name %></h4>
</div>
<div id="room-name-editable" style="display: none">
<input id="room-name-editable-input" class="form-control input-sm w-100 h-4" value="<%= room.name %>">
@ -45,20 +41,27 @@
<% end %>
</div>
</td>
<td class="text-right">
<td class="text-right">
<div class="item-action dropdown" data-display="static">
<a href="javascript:void(0)" data-toggle="dropdown" data-display="static" class="icon <%= 'invisible' if room == current_user.main_room %>">
<a href="javascript:void(0)" data-toggle="dropdown" data-display="static" class="icon">
<i class="fas fa-ellipsis-v px-4"></i>
</a>
<div class="dropdown-menu dropdown-menu-right dropdown-menu-md-left">
<a href="" data-toggle="modal" data-target="#createRoomModal" class="update-room dropdown-item">
<a href="" data-toggle="modal" data-target="#createRoomModal" class="update-room dropdown-item" data-settings-path="<%= room_settings_path(room) %>">
<i class="dropdown-icon fas fa-cog"></i> <%= t("room.settings") %>
</a>
<a href="" data-toggle="modal" data-target="#deleteRoomModal" data-path="<%= room_path(room) %>" data-name="<%= room.name %>" class="delete-room dropdown-item">
<i class="dropdown-icon far fa-trash-alt"></i> <%= t("delete") %>
</a>
<% if shared_access_allowed %>
<a href="" data-toggle="modal" data-target="#shareRoomModal" class="share-room dropdown-item" data-path="<%= room_shared_access_path(room) %>" data-users-path="<%= room_shared_users_path(room) %>">
<i class="dropdown-icon fas fa-users"></i> <%= t("room.share") %>
</a>
<% end %>
<% unless room == current_user.main_room %>
<a href="" data-toggle="modal" data-target="#deleteRoomModal" data-path="<%= room_path(room) %>" data-name="<%= room.name %>" class="delete-room dropdown-item">
<i class="dropdown-icon far fa-trash-alt"></i> <%= t("delete") %>
</a>
<% end %>
</div>
</div>
</div>
</td>
</tbody>
</table>

View File

@ -24,7 +24,7 @@
</div>
<div class="row">
<div class="col-lg-6 col-md-8 col-sm-12 form-inline mb-5 align-top">
<div class="col-lg-6 col-md-6 col-sm-12 form-inline mb-5 align-top">
<% if @room.owner.image.blank? %>
<span class="avatar"><%= @room.owner.name.first %></span>
<% else %>
@ -33,7 +33,7 @@
<h5 class="font-weight-normal ml-4 mt-3"><%= @room.owner.name %> (<%= t("room.owner") %>)</h5>
</div>
<div class="col-lg-6 col-md-4 col-sm-12">
<div class="col-lg-6 col-md-6 col-sm-12">
<%= yield %>
</div>
</div>

View File

@ -0,0 +1,48 @@
<%
# 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 id="room-block" data-room-uid="<%= room.uid %>" data-room-settings=<%= room.room_settings %> data-room-access-code="<%= room.access_code %>" class="card">
<div class="card-body p-1">
<table class="table table-hover table-vcenter text-wrap table-no-border">
<tbody class="no-border-top">
<td>
<span class="stamp stamp-md bg-primary">
<i class="fas fa-share-alt"></i>
</span>
</td>
<td>
<div id="room-name">
<h4 contenteditable="false" class="m-0 force-text-normal" ><%= room.name %></h4>
</div>
<div class="small text-muted text-break">
<%= t("room.shared_by", email: room.owner.name) %>
</div>
</td>
<td class="text-right">
<div class="item-action dropdown" data-display="static">
<a href="javascript:void(0)" data-toggle="dropdown" data-display="static" class="icon">
<i class="fas fa-ellipsis-v px-4"></i>
</a>
<div class="dropdown-menu dropdown-menu-right dropdown-menu-md-left">
<a href="" data-toggle="modal" data-target="#removeAccessModal" class="remove-share-room dropdown-item" data-path="<%= room_remove_shared_access_path(room) %>">
<i class="dropdown-icon far fa-trash-alt"></i> <%= t("remove") %>
</a>
</div>
</div>
</td>
</tbody>
</table>
</div>
</div>

View File

@ -31,7 +31,7 @@
<% end %>
<% else %>
<%= form_for room_path(@room), method: :post do |f| %>
<div class="input-group join-input">
<div class="input-group">
<%= f.hidden_field(:search, :value => params[:search])%>
<%= f.hidden_field(:column, :value => params[:column])%>
<%= f.hidden_field(:direction, :value => params[:direction])%>
@ -43,7 +43,11 @@
readonly: !current_user.nil?,
autofocus: true
%>
<%= f.submit (!@room_running && @anyone_can_start)? t("room.start") : t("room.join"), class: "btn btn-primary btn-sm col-sm-3 form-control join-form" %>
<span class="input-group-append">
<button type="submit" class="btn btn-primary btn-sm px-7 form-control join-form">
<%= (!@room_running && @anyone_can_start) ? t("room.start") : t("room.join") %>
</button>
</span>
</div>
<% end %>
<% end %>

View File

@ -25,7 +25,7 @@
<div class="col-lg-8 col-sm-12">
<div id="room-title" class="display-3 form-inline <%= 'edit_hover_class' if current_user.main_room != @room %>" data-path="<%= update_settings_path(@room) %>">
<% if current_user.main_room == @room %>
<h1 contenteditable=false id="user-text" class="display-3 text-left mb-3 font-weight-400"><%= t("home_room") %></h1>
<h1 contenteditable=false id="user-text" class="display-3 text-left mb-3 font-weight-400"><%= @room.name %></h1>
<a class="disable-click"><i class="fas fa-home align-top home-indicator ml-2"></i></a>
<% else %>
<h1 contenteditable=false id="user-text" class="display-3 text-left mb-3 font-weight-400"><%= @room.name %></h1>
@ -47,7 +47,7 @@
<div class="col-lg-5 col-md-12">
<div class="row">
<div class="col-sm-6">
<a href="#" id="copy" class="btn btn-primary btn-block mt-2">
<a id="copy" class="btn btn-primary btn-block mt-2">
<i class="fas fa-copy"></i>
<%= t("copy") %>
</a>
@ -67,30 +67,34 @@
</div>
<div class="offset-lg-1 col-lg-3 col-sm-12 force-bottom mt-5">
<% if @room_running %>
<%= button_to t("room.join"), room_path(@room), class: "btn btn-primary btn-block px-7 start-button float-right" %>
<%= button_to t("room.join"), room_path(@room), class: "btn btn-primary btn-block px-7 start-button float-right", "data-disable": "" %>
<% else %>
<% unless exceeds_limit %>
<%= button_to t("room.start"), start_room_path(@room), class: "btn btn-primary btn-block px-7 start-button float-right" %>
<%= button_to t("room.start"), start_room_path(@room), class: "btn btn-primary btn-block px-7 start-button float-right", "data-disable": "" %>
<% end %>
<% end %>
</div>
</div>
<div id="room_block_container" class="row pt-7 pb-5">
<% if current_user.rooms.length > 1 %>
<% current_user.ordered_rooms.each do |room| %>
<div class="col-lg-4 col-md-6 col-sm-12">
<%= link_to current_user.main_room do %>
<%= render "rooms/components/room_block", room: current_user.main_room %>
<%= link_to room do %>
<%= render "rooms/components/room_block", room: room %>
<% end %>
</div>
<% current_user.secondary_rooms.each do |room| %>
<% end %>
<% if shared_access_allowed %>
<% current_user.shared_rooms.each do |room| %>
<div class="col-lg-4 col-md-6 col-sm-12">
<%= link_to room do %>
<%= render "rooms/components/room_block", room: room %>
<%= render "rooms/components/shared_room_block", room: room %>
<% end %>
</div>
<% end %>
<% end %>
<% unless room_limit_exceeded %>
<%= render "rooms/components/create_room_block"%>
<% end %>
@ -98,8 +102,13 @@
</div>
</div>
<%= render "shared/sessions", recordings: @recordings, pagy: @pagy, only_public: false, user_recordings: false, title: t("room.recordings")%>
<%= render "shared/sessions", recordings: @recordings, pagy: @pagy, only_public: false, shared_room: @shared_room, user_recordings: false, title: t("room.recordings")%>
<%= render "shared/modals/delete_room_modal" %>
<%= render "shared/modals/create_room_modal" %>
<% if shared_access_allowed %>
<%= render "shared/modals/share_room_modal" %>
<%= render "shared/modals/remove_access_modal" %>
<% end %>

View File

@ -63,6 +63,10 @@
<%= link_to admins_path, class: "dropdown-item" do %>
<i class="dropdown-icon fas fa-user-tie mr-3"></i><%= t("header.dropdown.account_settings") %>
<% end %>
<% elsif highest_role.get_permission("can_manage_rooms_recordings")%>
<%= link_to admin_rooms_path, class: "dropdown-item" do %>
<i class="dropdown-icon fas fa-user-tie mr-3"></i><%= t("header.dropdown.account_settings") %>
<% end %>
<% elsif highest_role.get_permission("can_edit_site_settings") %>
<%= link_to admin_site_settings_path, class: "dropdown-item" do %>
<i class="dropdown-icon fas fa-user-tie mr-3"></i><%= t("header.dropdown.account_settings") %>

View File

@ -94,7 +94,7 @@
<% failed_recordings = 0 %>
<% recordings.each do |recording| %>
<% begin %>
<% if only_public %>
<% if only_public || (defined?(shared_room) && shared_room) %>
<%= render "shared/components/public_recording_row", recording: recording %>
<% else %>
<%= render "shared/components/recording_row", recording: recording %>

View File

@ -53,10 +53,10 @@
<button class="btn btn-sm btn-secondary dropdown-toggle" data-toggle="dropdown"><i class="dropdown-icon fas fa-link px-2"></i> <%= t("recording.visibility.unlisted") %></button>
<% end %>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<%= button_to update_recording_path(meetingID: recording[:meetingID], record_id: recording[:recordID], state: "public"), class: "dropdown-item" do %>
<%= button_to update_recording_path(meetingID: recording[:meetingID], record_id: recording[:recordID], state: "public"), class: "dropdown-item", "data-disable": "" do %>
<i class="dropdown-icon fas fa-globe"></i> <%= t("recording.visibility.public") %>
<% end %>
<%= button_to update_recording_path(meetingID: recording[:meetingID], record_id: recording[:recordID], state: "unlisted"), class: "dropdown-item" do %>
<%= button_to update_recording_path(meetingID: recording[:meetingID], record_id: recording[:recordID], state: "unlisted"), class: "dropdown-item", "data-disable": "" do %>
<i class="dropdown-icon fas fa-link"></i> <%= t("recording.visibility.unlisted") %>
<% end %>
</div>
@ -80,7 +80,7 @@
<a class="dropdown-item email-link" data-pres-link="<%= recording_links %>"><i class="dropdown-icon far fa-envelope"></i> <%= t("recording.email") %></a>
<div class="dropdown-divider"></div>
<% end %>
<%= button_to delete_recording_path(meetingID: recording[:meetingID], record_id: recording[:recordID]), method: :delete, class: "dropdown-item" do %>
<%= button_to delete_recording_path(meetingID: recording[:meetingID], record_id: recording[:recordID]), method: :delete, class: "dropdown-item", "data-disable": "" do %>
<i class="dropdown-icon far fa-trash-alt"></i> <%= t("delete") %>
<% end %>
</div>

View File

@ -26,7 +26,7 @@
<%= t("modal.delete_account.keep") %>
</button>
<%= button_to delete_location, method: :delete, id: "delete-confirm", class: "btn btn-danger my-1 btn-del-room", disabled:"" do %>
<%= button_to delete_location, method: :delete, id: "delete-confirm", class: "btn btn-danger my-1 btn-del-room", disabled:"", "data-disable": "" do %>
<%= t("modal.delete_account.delete") %>
<% end %>

View File

@ -26,7 +26,7 @@
<%= t("modal.delete_room.keep") %>
</button>
<%= button_to "/", method: :delete, id: "delete-confirm", class: "btn btn-danger my-1 btn-del-room" do %>
<%= button_to "/", method: :delete, id: "delete-confirm", class: "btn btn-danger my-1 btn-del-room", "data-disable": "" do %>
<%= t("modal.delete_room.delete") %>
<% end %>

View File

@ -0,0 +1,51 @@
<%
# 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="mergeUserModal" 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.merge_user.title") %></h3>
</div>
<select class="selectpicker" title="<%= t("modal.share_access.select") %>" data-live-search="true" data-virtual-scroll="true" >
<% @user_list.each do |user| %>
<option value="<%= { uid: user.uid, email: user.email, name: user.name }.to_json %>" data-subtext="<%= user.email %>" ><%= user.name %></option>
<% end %>
</select>
<div class="mt-5 text-left row">
<div class="list-group-item col-6 text-center">
<label class="form-label text-primary"><%= t("modal.merge_user.from") %></label>
<div id="merge-from"></div>
</div>
<i id="merge-account-arrow" class="fas fa-2x fa-arrow-circle-right text-primary"></i>
<div class="list-group-item col-6 text-center">
<label class="form-label text-primary"><%= t("modal.merge_user.to") %></label>
<div id="merge-to"></div>
</div>
</div>
<div class="mt-6">
<button id="merge-save-access" class="btn btn-primary btn-block" onclick="mergeUsers()" ><%= t("modal.merge_user.save") %></button>
<button class="btn btn-secondary text-primary btn-block" onclick="$('#mergeUserModal').modal('hide')"><%= t("modal.merge_user.cancel") %></button>
</div>
</div>
<div class="card-footer">
<p><%= t("modal.merge_user.footer") %></p>
</div>
</div>
</div>
</div>
</div>

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 class="modal fade" id="removeAccessModal" 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.remove_shared.title")%></h3>
</div>
<%= button_to "/", method: :delete, id: "remove-shared-confirm", class: "btn btn-danger my-1 btn-del-room" do %>
<%= hidden_field_tag :user_id, current_user.id %>
<%= t("modal.remove_shared.delete") %>
<% end %>
</div>
<div class="card-footer">
<p id="delete-footer">
<%= t("modal.remove_shared.warning").html_safe %>
</p>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,45 @@
<%
# 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="shareRoomModal" 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.share_access.title") %></h3>
</div>
<select class="selectpicker" title="<%= t("modal.share_access.select") %>" data-live-search="true" data-virtual-scroll="true" >
<% @user_list.each do |user| %>
<option value="<%= user.uid %>" data-subtext="<%= user.uid %>" ><%= user.name %></option>
<% end %>
</select>
<div class="mt-5 text-left">
<label class="form-label"><%= t("modal.share_access.list") %></label>
<ul id="user-list" class="list-group">
</ul>
</div>
<div class="mt-6">
<button id="save-access" class="btn btn-primary btn-block" onclick="saveAccessChanges()" ><%= t("modal.share_access.save") %></button>
<button class="btn btn-secondary text-primary btn-block" onclick="$('#shareRoomModal').modal('hide')"><%= t("modal.share_access.cancel_changes") %></button>
</div>
</div>
<div class="card-footer">
<p><%= t("modal.share_access.footer") %></p>
</div>
</div>
</div>
</div>
</div>

View File

@ -25,7 +25,7 @@
</div>
<% if Rails.configuration.terms && current_user && !current_user.accepted_terms %>
<div class="btn-list text-right pt-8">
<%= button_to t("terms.accept_existing"), terms_path, params: { accept: true }, class: "btn btn-primary btn-space" %>
<%= button_to t("terms.accept_existing"), terms_path, params: { accept: true }, class: "btn btn-primary btn-space", "data-disable": "" %>
</div>
<% end %>
</form>

View File

@ -153,13 +153,10 @@ module Greenlight
# Default limit on number of rooms users can create
config.number_of_rooms_default = 15
# Allow users to share rooms by default
config.shared_access_default = "true"
# Default admin password
config.admin_password_default = ENV['ADMIN_PASSWORD'] || 'administrator'
config.action_cable.log_tags = [
->(request) { request.session['user_id'] || "no-account" },
:action_cable,
->(request) { request.uuid }
]
end
end

View File

@ -110,7 +110,9 @@ Rails.application.configure do
# Use Lograge for logging
config.lograge.enabled = true
config.lograge.ignore_actions = ["HealthCheckController#all", "ThemesController#index"]
config.lograge.ignore_actions = ["HealthCheckController#all", "ThemesController#index",
"ApplicationCable::Connection#connect", "WaitingChannel#subscribe",
"ApplicationCable::Connection#disconnect", "WaitingChannel#unsubscribe"]
config.lograge.custom_options = lambda do |event|
# capture some specific timing values you are interested in

View File

@ -13,4 +13,8 @@ Rails.application.config.assets.version = '1.0'
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in the app/assets
# folder are already added.
Rails.application.config.assets.precompile += %w(pickr.min.js monolith.min.scss)
Rails.application.config.assets.precompile += %w(_primary_theme.scss
pickr.min.js
monolith.min.scss
bootstrap-select.min.js
bootstrap-select.min.css)

View File

@ -46,12 +46,25 @@ en:
info: Clears the stored provider cache which forces a new request for the updated info
title: Clear Provider Cache
button: Clear Cache
clear_auth:
info: Clears the current authenticator for users allowing them to sign back in using a different authentication method
title: Clear Current Authenticator
button: Clear Auth
color:
info: Changing the Regular Color will change both Lighten and Darken. Lighten and Darken can then be changed individually
title: Primary Color
regular: Regular
lighten: Lighten
darken: Darken
log_level:
title: Log Level
information: Change the Log Level for the entire deployment
debug: Debug
info: Info
warn: Warn
error: Error
fatal: Fatal
unknown: Unknown
recording_visibility:
info: Set the default recording visbility for new recordings
title: Recording Default Visibility
@ -66,6 +79,9 @@ en:
rooms:
info: Limits the number of rooms that a user can have (including Home Room). This setting does not apply to administrators.
title: Number of Rooms per User
shared_access:
info: Setting to disabled will remove the button from the Room options dropdown, preventing users from sharing rooms
title: Allow Users to Share Rooms
subtitle: Customize Greenlight
title: Site Settings
flash:
@ -77,6 +93,8 @@ en:
demoted: User has been successfully demoted
invite: Invite successfully sent to %{email}
invite_email_verification: Emails must be enabled in order to use this method. Please contact your system administrator.
merge_fail: There was an issue merging the user accounts. Please check the users selected and try again
merge_success: User accounts merged successfully
perm_deleted: User has been permanently deleted
promoted: User has been successfully promoted
registration_method_updated: Registration method successfully updated
@ -88,11 +106,13 @@ en:
title: Server Recordings
no_recordings: This server has no recordings.
roles:
appear_in_share_list: Include users with this role in the dropdown for sharing rooms
can_create_rooms: Can create rooms
delete: Delete the role
invalid_create: There was a problem creating a new role. Please check the role values and try again
invalid_order: There was a problem updating the priority of the role. Please check the values and try again
invalid_update: There was a problem updating the permissions of the role. Please check the values and try again
manage_rooms_recordings: Allow users with this role to manage server rooms and recordings
name: Role Name
new_role: Create a new role
role_has_users: This role is assigned to %{user_count} accounts. Please remove all accounts from this role before deleting it.
@ -106,6 +126,14 @@ en:
colour:
title: Role Colour
info: Set the colour that will be associated with the role
rooms:
title: Server Rooms
table:
id: ID
not_running: Not Running
running: Running
status: Status
view: View
title: Organization Settings
users:
invite: Invite User
@ -228,6 +256,8 @@ en:
body: 'To view the recording, follow the link below:'
autogenerated: 'This e-mail is auto-generated by BigBlueButton.'
footer: 'BigBlueButton is an open source web conferencing system. For more information on BigBlueButton, see https://bigbluebutton.org/.'
search:
start: Start searching...
landing:
about: "%{href} is a simple front-end for your BigBlueButton open-source web conferencing server. You can create your own rooms to host sessions, or join others using a short and convenient link."
welcome: Welcome to BigBlueButton.
@ -291,6 +321,7 @@ en:
maintenance:
window_alert: Maintenance window scheduled for %{date}
max_concurrent: The maximum number of concurrent sessions allowed has been reached!
merged: Merged
modal:
create_role:
create: Create a new Role
@ -329,6 +360,10 @@ en:
with: Sign in with %{provider}
forgot_password: Forgot Password?
rename_recording:
remove_shared:
title: Are you sure you want to remove this room from your room list?
delete: I'm sure, remove this room.
warning: You will <b>not</b> be able to access this room anymore.
room_settings:
title: Room Settings
update: Update Room
@ -340,6 +375,20 @@ en:
footer_text: Adjustment to your room can be done at anytime.
rename_room:
name_placeholder: Enter a new room name...
share_access:
footer: Sharing a room with a user allows them to start the room and view the room's recordings
list: Shared With
title: Share Room Access
save: Save Changes
cancel_changes: Cancel Changes
select: Select User
merge_user:
cancel: Cancel
from: Account to be Merged
title: Merge User Accounts
to: Primary Account
save: Merge
footer: The rooms of the account to be merged will be transfered over to the Primary Account's room list and then the account will be deleted.
name_update_success: Room name successfully changed!
no_user_email_exists: There is no existing user with the email specified. Please make sure you typed it correctly.
omniauth_error: An error occured while authenticating with omniauth. Please try again or contact an administrator!
@ -400,12 +449,14 @@ en:
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.
remove: Remove
rename: Rename
reset_password:
subtitle: Reset Password
password: New Password
confirm: New Password Confirmation
update: Update Password
auth_change: The authentication method has changed. Please check your email to set your password.
roles:
active: Active
admin: Admin
@ -418,6 +469,10 @@ en:
create_room: Create a Room
create_room_error: There was an error creating the room
create_room_success: Room created successfully
delete:
home_room: Can't delete user's Home Room
success: Room deleted successfully
fail: Failed to delete room (%{error})
enter_the_access_code: Enter the room's access code
invalid_provider: You have entered an invalid url. Please check the url and try again.
invited: You have been invited to join
@ -426,6 +481,7 @@ en:
last_session: Last session on %{session}
login: Enter
owner: Owner
owner_banned: This room is currently unavailable
no_room:
description: Enter the room url or the room id for the room you want to join.
edit_profile: Edit User Profile
@ -441,6 +497,12 @@ en:
room_limit_exceeded: You have exceeded the number of rooms allowed. Please delete %{difference} room(s) to access this room.
sessions: Sessions
settings: Room Settings
share: Manage Access
shared_by: Shared by %{email}
remove_shared_access_success: Successfully removed shared room from your room list
remove_shared_access_error: There was an error removing the shared room from your list
shared_access_success: Room shared successfully
shared_access_error: There was an error sharing the room
start: Start
unavailable: This room is currently unavailable due to the owner's email not being verified.
update_settings_error: There was an error updating the room settings

View File

@ -38,6 +38,7 @@ Rails.application.routes.draw do
scope '/admins' do
# Panel Tabs
get '/rooms', to: 'admins#server_rooms', as: :admin_rooms
get '/recordings', to: 'admins#server_recordings', as: :admin_recordings
get '/site_settings', to: 'admins#site_settings', as: :admin_site_settings
get '/roles', to: 'admins#roles', as: :admin_roles
@ -49,11 +50,14 @@ Rails.application.routes.draw do
post '/approve/:user_uid', to: 'admins#approve', as: :admin_approve
get '/reset', to: 'admins#reset', as: :admin_reset
post '/undelete', to: 'admins#undelete', as: :admin_undelete
post '/merge/:user_uid', to: 'admins#merge_user', as: :merge_user
# Site Settings
post '/update_settings', to: 'admins#update_settings', as: :admin_update_settings
post '/registration_method', to: 'admins#registration_method', as: :admin_change_registration
post '/coloring', to: 'admins#coloring', as: :admin_coloring
post '/clear_cache', to: 'admins#clear_cache', as: :admin_clear_cache
post '/clear_auth', to: 'admins#clear_auth', as: :admin_clear_auth
post '/log_level', to: 'admins#log_level', as: :admin_log_level
# Roles
post '/role', to: 'admins#new_role', as: :admin_new_role
patch 'roles/order', to: 'admins#change_role_order', as: :admin_roles_order
@ -109,7 +113,11 @@ Rails.application.routes.draw do
scope '/:room_uid' do
post '/', to: 'rooms#join'
patch '/', to: 'rooms#update', as: :update_room
get '/room_settings', to: 'rooms#room_settings'
post '/update_settings', to: 'rooms#update_settings'
post '/update_shared_access', to: 'rooms#shared_access', as: :room_shared_access
delete '/remove_shared_access', to: 'rooms#remove_shared_access', as: :room_remove_shared_access
get '/shared_users', to: 'rooms#shared_users', as: :room_shared_users
post '/start', to: 'rooms#start', as: :start_room
get '/logout', to: 'rooms#logout', as: :logout_room
post '/login', to: 'rooms#login', as: :login_room

View File

@ -0,0 +1,28 @@
# frozen_string_literal: true
class MigrationProduct < ActiveRecord::Base
self.table_name = :roles
end
class SubMigrationProduct < ActiveRecord::Base
self.table_name = :role_permissions
end
class AddManageRoomRecordingsToPermissions < ActiveRecord::Migration[5.2]
def change
reversible do |dir|
dir.up do
MigrationProduct.all.each do |role|
SubMigrationProduct.create(role_id: role.id, name: "can_manage_rooms_recordings",
value: SubMigrationProduct.find_by(role_id: role.id, name: "can_manage_users").value, enabled: true)
end
end
dir.down do
MigrationProduct.all.each do |role|
SubMigrationProduct.find_by(role_id: role.id, name: "can_manage_rooms_recordings").destroy
end
end
end
end
end

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
class CreateSharedAccesses < ActiveRecord::Migration[5.2]
def change
create_table :shared_accesses do |t|
t.belongs_to :room, foreign_key: true
t.references :user, foreign_key: true
t.timestamps
end
end
end

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
class MigrationProduct < ActiveRecord::Base
self.table_name = :roles
end
class ChangeRolePriorityToUnique < ActiveRecord::Migration[5.2]
def change
reversible do |dir|
dir.up do
MigrationProduct.where("priority < 0").where.not(name: "pending").each do |role|
role.decrement!(:priority)
end
add_index MigrationProduct, [:priority, :provider], unique: true
end
dir.down do
remove_index MigrationProduct, [:priority, :provider]
MigrationProduct.where("priority < 0").where.not(name: "pending").each do |role|
role.increment!(:priority)
end
end
end
end
end

View File

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2019_08_28_153347) do
ActiveRecord::Schema.define(version: 2020_01_30_144841) do
create_table "features", force: :cascade do |t|
t.integer "setting_id"
@ -58,6 +58,7 @@ ActiveRecord::Schema.define(version: 2019_08_28_153347) do
t.datetime "updated_at", null: false
t.index ["name", "provider"], name: "index_roles_on_name_and_provider", unique: true
t.index ["name"], name: "index_roles_on_name"
t.index ["priority", "provider"], name: "index_roles_on_priority_and_provider", unique: true
end
create_table "rooms", force: :cascade do |t|
@ -90,6 +91,15 @@ ActiveRecord::Schema.define(version: 2019_08_28_153347) do
t.index ["provider"], name: "index_settings_on_provider"
end
create_table "shared_accesses", force: :cascade do |t|
t.integer "room_id"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["room_id"], name: "index_shared_accesses_on_room_id"
t.index ["user_id"], name: "index_shared_accesses_on_user_id"
end
create_table "users", force: :cascade do |t|
t.integer "room_id"
t.string "provider"

View File

@ -18,19 +18,18 @@ services:
volumes:
- ./log:/usr/src/app/log
# When using sqlite3 as the database
- ./db/production:/usr/src/app/db/production
# - ./db/production:/usr/src/app/db/production
# When using postgresql as the database
# links:
# - db
# db:
# image: postgres:9.5
# restart: on-failure
# ports:
# - 127.0.0.1:5432:5432
# volumes:
# - ./db/production:/var/lib/postgresql/data
# environment:
# - PGHOST=postgres
# - PGDATABASE=postgres
# - PGUSER=postgres
# - PGPASSWORD=password
links:
- db
db:
image: postgres:9.5
restart: on-failure
ports:
- 127.0.0.1:5432:5432
volumes:
- ./db/production:/var/lib/postgresql/data
environment:
- POSTGRES_DB=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password

View File

@ -91,7 +91,8 @@ a {
opacity: 0.9;
}
}
&:active {
&:active, &.active {
color: $primary-color !important;
background-color: $primary-color-lighten !important;
}
}

View File

@ -215,11 +215,11 @@ REPORT_ISSUE_URL=https://github.com/bigbluebutton/greenlight/issues/new
#
# For deployments based on the docker-compose script also included, the HOST should be set with the Docker container id.
#
# DB_ADAPTER=postgresql
# DB_HOST=db
# DB_NAME=greenlight_production
# DB_USERNAME=postgres
# DB_PASSWORD=password
DB_ADAPTER=postgresql
DB_HOST=db
DB_NAME=greenlight_production
DB_USERNAME=postgres
DB_PASSWORD=password
# Specify the default registration to be used by Greenlight until an administrator sets the
# registration method

View File

@ -27,7 +27,7 @@ describe AccountActivationsController, type: :controller do
user = create(:user, provider: "greenlight")
@request.session[:user_id] = user.id
get :show, params: { email: user.email }
get :show, params: { uid: user.uid }
expect(response).to redirect_to(user.main_room)
end
@ -35,7 +35,8 @@ describe AccountActivationsController, type: :controller do
it "renders the verify view if the user is not signed in and is not verified" do
user = create(:user, email_verified: false, provider: "greenlight")
get :show, params: { email: user.email }
user.create_activation_token
get :show, params: { token: user.activation_token }
expect(response).to render_template(:show)
end
@ -45,7 +46,8 @@ describe AccountActivationsController, type: :controller do
it "activates a user if they have the correct activation token" do
@user = create(:user, email_verified: false, provider: "greenlight")
get :edit, params: { email: @user.email, token: @user.activation_token }
@user.create_activation_token
get :edit, params: { token: @user.activation_token }
@user.reload
expect(@user.email_verified).to eq(true)
@ -53,22 +55,17 @@ describe AccountActivationsController, type: :controller do
expect(response).to redirect_to(signin_path)
end
it "does not activate a user if they have the correct activation token" do
it "should not find user when given fake activation token" do
@user = create(:user, email_verified: false, provider: "greenlight")
get :edit, params: { email: @user.email, token: "fake_token" }
@user.reload
expect(@user.email_verified).to eq(false)
expect(flash[:alert]).to be_present
expect(response).to redirect_to(root_path)
expect { get :edit, params: { token: "fake_token" } }.to raise_error(ActiveRecord::RecordNotFound)
end
it "does not allow the user to click the verify link again" do
@user = create(:user, provider: "greenlight")
get :edit, params: { email: @user.email, token: @user.activation_token }
@user.create_activation_token
get :edit, params: { token: @user.activation_token }
expect(flash[:alert]).to be_present
expect(response).to redirect_to(root_path)
end
@ -78,7 +75,8 @@ describe AccountActivationsController, type: :controller do
@user.add_role :pending
get :edit, params: { email: @user.email, token: @user.activation_token }
@user.create_activation_token
get :edit, params: { token: @user.activation_token }
expect(flash[:success]).to be_present
expect(response).to redirect_to(root_path)
@ -89,7 +87,8 @@ describe AccountActivationsController, type: :controller do
it "resends the email to the current user if the resend button is clicked" do
user = create(:user, email_verified: false, provider: "greenlight")
expect { get :resend, params: { email: user.email } }.to change { ActionMailer::Base.deliveries.count }.by(1)
user.create_activation_token
expect { get :resend, params: { token: user.activation_token } }.to change { ActionMailer::Base.deliveries.count }.by(1)
expect(flash[:success]).to be_present
expect(response).to redirect_to(root_path)
end
@ -97,7 +96,8 @@ describe AccountActivationsController, type: :controller do
it "redirects a verified user to the root path" do
user = create(:user, provider: "greenlight")
get :resend, params: { email: user.email }
user.create_activation_token
get :resend, params: { token: user.activation_token }
expect(flash[:alert]).to be_present
expect(response).to redirect_to(root_path)

View File

@ -67,6 +67,8 @@ describe AdminsController, type: :controller do
post :ban_user, params: { user_uid: @user.uid }
@user.reload
expect(@user.has_role?(:denied)).to eq(true)
expect(flash[:success]).to be_present
expect(response).to redirect_to(admins_path)
@ -82,6 +84,8 @@ describe AdminsController, type: :controller do
post :unban_user, params: { user_uid: @user.uid }
@user.reload
expect(@user.has_role?(:denied)).to eq(false)
expect(flash[:success]).to be_present
expect(response).to redirect_to(admins_path)
@ -153,6 +157,8 @@ describe AdminsController, type: :controller do
post :approve, params: { user_uid: @user.uid }
@user.reload
expect(@user.has_role?(:pending)).to eq(false)
expect(flash[:success]).to be_present
expect(response).to redirect_to(admins_path)
@ -197,6 +203,42 @@ describe AdminsController, type: :controller do
expect(response).to redirect_to(admins_path)
end
end
context "POST #merge_user" do
it "merges the users room to the primary account and deletes the old user" do
@request.session[:user_id] = @admin.id
@user2 = create(:user)
room1 = create(:room, owner: @user2)
room2 = create(:room, owner: @user2)
room3 = @user2.main_room
post :merge_user, params: { user_uid: @user.uid, merge: @user2.uid }
room1.reload
room2.reload
room3.reload
expect(User.exists?(uid: @user2.uid)).to be false
expect(room1.name).to start_with("(Merged)")
expect(room2.name).to start_with("(Merged)")
expect(room3.name).to start_with("(Merged)")
expect(room1.owner).to eq(@user)
expect(room2.owner).to eq(@user)
expect(room3.owner).to eq(@user)
expect(flash[:success]).to be_present
expect(response).to redirect_to(admins_path)
end
it "does not merge if trying to merge the same user into themself" do
@request.session[:user_id] = @admin.id
post :merge_user, params: { user_uid: @user.uid, merge: @user.uid }
expect(flash[:alert]).to be_present
expect(response).to redirect_to(admins_path)
end
end
end
describe "User Design" do
@ -344,6 +386,66 @@ describe AdminsController, type: :controller do
expect(response).to redirect_to(admin_site_settings_path)
end
end
context "POST #shared_access" do
it "changes the shared access 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 :update_settings, params: { setting: "Shared Access", value: "false" }
feature = Setting.find_by(provider: "provider1").features.find_by(name: "Shared Access")
expect(feature[:value]).to eq("false")
expect(response).to redirect_to(admin_site_settings_path)
end
end
context "POST #clear_auth" do
it "clears all users social uids if clear auth button is clicked" do
allow_any_instance_of(ApplicationController).to receive(:set_user_domain).and_return("provider1")
controller.instance_variable_set(:@user_domain, "provider1")
@request.session[:user_id] = @admin.id
@admin.add_role :super_admin
@admin.update_attribute(:provider, "greenlight")
@user2 = create(:user, provider: "provider1")
@user3 = create(:user, provider: "provider1")
@user.update_attribute(:social_uid, Faker::Internet.password)
@user2.update_attribute(:social_uid, Faker::Internet.password)
@user3.update_attribute(:social_uid, Faker::Internet.password)
expect(@user.social_uid).not_to be(nil)
expect(@user2.social_uid).not_to be(nil)
expect(@user3.social_uid).not_to be(nil)
post :clear_auth
@user.reload
@user2.reload
@user3.reload
expect(@user.social_uid).to be(nil)
expect(@user2.social_uid).to be(nil)
expect(@user3.social_uid).to be(nil)
end
end
context "POST #log_level" do
it "changes the log level" do
@request.session[:user_id] = @admin.id
@admin.add_role :super_admin
expect(Rails.logger.level).to eq(0)
post :log_level, params: { value: 2 }
expect(Rails.logger.level).to eq(2)
end
end
end
describe "Roles" do
@ -413,6 +515,7 @@ describe AdminsController, type: :controller do
context "PATCH #change_role_order" do
before do
Role.create_default_roles("provider1")
@user.roles.delete(Role.find_by(name: "user", provider: "greenlight"))
end
it "should fail if user attempts to change the order of the admin or user roles" do
@ -428,35 +531,9 @@ describe AdminsController, type: :controller do
end
it "should fail if a user attempts to edit a role with a higher priority than their own" do
Role.create(name: "test1", priority: 1, provider: "greenlight")
new_role2 = Role.create(name: "test2", priority: 2, provider: "greenlight")
new_role3 = Role.create_new_role("test3", "provider1")
new_role2 = Role.create_new_role("test2", "provider1")
new_role2.update_permission("can_edit_roles", "true")
new_role3 = Role.create(name: "test3", priority: 3, provider: "greenlight")
user_role = Role.find_by(name: "user", provider: "greenlight")
user_role.priority = 4
user_role.save!
@user.roles << new_role2
@user.save!
@request.session[:user_id] = @user.id
patch :change_role_order, params: { role: [new_role3.id, new_role2.id] }
expect(flash[:alert]).to eq(I18n.t("administrator.roles.invalid_order"))
expect(response).to redirect_to admin_roles_path
end
it "should fail if a user attempts to edit a role with a higher priority than their own" do
Role.create(name: "test1", priority: 1, provider: "greenlight")
new_role2 = Role.create(name: "test2", priority: 2, provider: "greenlight")
new_role2.update_permission("can_edit_roles", "true")
new_role3 = Role.create(name: "test3", priority: 3, provider: "greenlight")
user_role = Role.find_by(name: "user", provider: "greenlight")
user_role.priority = 4
user_role.save!
@user.roles << new_role2
@user.save!
@ -470,10 +547,11 @@ describe AdminsController, type: :controller do
end
it "should update the role order" do
user_role = Role.find_by(name: "user", provider: "provider1")
user_role.update_attribute(:priority, 4)
new_role1 = Role.create(name: "test1", priority: 1, provider: "provider1")
new_role2 = Role.create(name: "test2", priority: 2, provider: "provider1")
new_role3 = Role.create(name: "test3", priority: 3, provider: "provider1")
user_role = Role.find_by(name: "user", provider: "provider1")
@request.session[:user_id] = @admin.id
@ -494,16 +572,15 @@ describe AdminsController, type: :controller do
context 'POST #update_role' do
before do
Role.create_default_roles("provider1")
@user.roles.delete(Role.find_by(name: "user", provider: "greenlight"))
end
it "should fail to update a role with a lower priority than the user" do
user_role = Role.find_by(name: "user", provider: "provider1")
user_role.update_attribute(:priority, 3)
new_role1 = Role.create(name: "test1", priority: 1, provider: "provider1")
new_role2 = Role.create(name: "test2", priority: 2, provider: "provider1")
new_role2.update_permission("can_edit_roles", "true")
user_role = Role.find_by(name: "user", provider: "greenlight")
user_role.priority = 3
user_role.save!
@user.roles << new_role2
@user.save!
@ -517,7 +594,7 @@ describe AdminsController, type: :controller do
end
it "should fail to update if there is a duplicate name" do
new_role = Role.create(name: "test2", priority: 1, provider: "provider1")
new_role = Role.create(name: "test2", priority: 2, provider: "provider1")
new_role.update_permission("can_edit_roles", "true")
@request.session[:user_id] = @admin.id
@ -529,7 +606,7 @@ describe AdminsController, type: :controller do
end
it "should update role permisions" do
new_role = Role.create(name: "test2", priority: 1, provider: "provider1")
new_role = Role.create(name: "test2", priority: 2, provider: "provider1")
new_role.update_permission("can_edit_roles", "true")
@request.session[:user_id] = @admin.id
@ -574,7 +651,7 @@ describe AdminsController, type: :controller do
end
it "should successfully delete the role" do
new_role = Role.create(name: "test2", priority: 1, provider: "provider1")
new_role = Role.create(name: "test2", priority: 2, provider: "provider1")
new_role.update_permission("can_edit_roles", "true")
@request.session[:user_id] = @admin.id

View File

@ -115,19 +115,15 @@ describe PasswordResetsController, type: :controller do
end
it "updates attributes if the password update is a success" do
user = create(:user)
token = "reset_token"
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
user.reset_digest = BCrypt::Password.create(token, cost: cost)
user = create(:user, provider: "greenlight")
user.create_reset_digest
old_digest = user.password_digest
allow(controller).to receive(:valid_user).and_return(nil)
allow(controller).to receive(:check_expiration).and_return(nil)
controller.instance_variable_set(:@user, user)
params = {
id: token,
email: user.email,
id: user.reset_token,
user: {
password: :password,
password_confirmation: :password,
@ -135,6 +131,10 @@ describe PasswordResetsController, type: :controller do
}
patch :update, params: params
user.reload
expect(old_digest.eql?(user.password_digest)).to be false
expect(response).to redirect_to(root_path)
end
end

View File

@ -137,6 +137,24 @@ describe RoomsController, type: :controller do
expect(flash[:alert]).to be_present
expect(response).to redirect_to(root_path)
end
it "redirects to root if owner is pending" do
@request.session[:user_id] = @owner.id
@owner.add_role :pending
get :show, params: { room_uid: @owner.main_room, search: :none }
expect(response).to redirect_to(root_path)
end
it "redirects to root if owner is banned" do
@request.session[:user_id] = @owner.id
@owner.add_role :denied
get :show, params: { room_uid: @owner.main_room, search: :none }
expect(response).to redirect_to(root_path)
end
end
describe "POST #create" do
@ -155,13 +173,27 @@ describe RoomsController, type: :controller do
post :create, params: { room: room_params }
r = @owner.secondary_rooms.last
r = @owner.rooms.last
expect(r.name).to eql(name)
expect(r.owner).to eql(@owner)
expect(r.room_settings).to eql(json_room_settings)
expect(response).to redirect_to(r)
end
it "should respond with JSON object of the room_settings" do
@request.session[:user_id] = @owner.id
@owner.main_room.update_attribute(:room_settings, { "muteOnStart": true, "requireModeratorApproval": true,
"anyoneCanStart": true, "joinModerator": true }.to_json)
json_room_settings = "{\"muteOnStart\":true,\"requireModeratorApproval\":true," \
"\"anyoneCanStart\":true,\"joinModerator\":true}"
get :room_settings, params: { room_uid: @owner.main_room }, format: :json
expect(JSON.parse(response.body)).to eql(json_room_settings)
end
it "should redirect to root if not logged in" do
expect do
name = Faker::Games::Pokemon.name
@ -214,7 +246,6 @@ describe RoomsController, type: :controller do
it "should use join name if user is not logged in and meeting running" do
allow_any_instance_of(BigBlueButton::BigBlueButtonApi).to receive(:is_meeting_running?).and_return(true)
post :join, params: { room_uid: @room, join_name: "Join Name" }
expect(response).to redirect_to(join_path(@owner.main_room, "Join Name", {}))
@ -310,6 +341,24 @@ describe RoomsController, type: :controller do
expect(flash[:alert]).to be_present
expect(response).to redirect_to(root_path)
end
it "redirects to root if owner is pending" do
@request.session[:user_id] = @owner.id
@owner.add_role :pending
post :join, params: { room_uid: @room }
expect(response).to redirect_to(root_path)
end
it "redirects to root if owner is banned" do
@request.session[:user_id] = @owner.id
@owner.add_role :denied
post :join, params: { room_uid: @room }
expect(response).to redirect_to(root_path)
end
end
describe "DELETE #destroy" do
@ -342,6 +391,45 @@ describe RoomsController, type: :controller do
delete :destroy, params: { room_uid: @user.main_room }
end.to change { Room.count }.by(0)
end
it "allows admin to delete room" do
@admin = create(:user)
@admin.add_role :admin
@request.session[:user_id] = @admin.id
expect do
delete :destroy, params: { room_uid: @secondary_room }
end.to change { Room.count }.by(-1)
expect(response).to redirect_to(@admin.main_room)
end
it "does not allow admin to delete a users home room" do
@admin = create(:user)
@admin.add_role :admin
@request.session[:user_id] = @admin.id
expect do
delete :destroy, params: { room_uid: @user.main_room }
end.to change { Room.count }.by(0)
expect(flash[:alert]).to be_present
expect(response).to redirect_to(@admin.main_room)
end
it "does not allow an admin from a different context to delete room" do
allow_any_instance_of(User).to receive(:admin_of?).and_return(false)
@admin = create(:user)
@admin.add_role :admin
@request.session[:user_id] = @admin.id
expect do
delete :destroy, params: { room_uid: @secondary_room }
end.to change { Room.count }.by(0)
expect(response).to redirect_to(root_path)
end
end
describe "POST #start" do
@ -374,6 +462,27 @@ describe RoomsController, type: :controller do
expect(response).to redirect_to(root_path)
end
it "redirects to join path if admin" do
@admin = create(:user)
@admin.add_role :admin
@request.session[:user_id] = @admin.id
post :start, params: { room_uid: @user.main_room }
expect(response).to redirect_to(join_path(@user.main_room, @admin.name, { user_is_moderator: true }, @admin.uid))
end
it "redirects to root path if not admin of current user" do
allow_any_instance_of(User).to receive(:admin_of?).and_return(false)
@admin = create(:user)
@admin.add_role :admin
@request.session[:user_id] = @admin.id
post :start, params: { room_uid: @user.main_room }
expect(response).to redirect_to(root_path)
end
end
describe "POST #update_settings" do
@ -413,6 +522,35 @@ describe RoomsController, type: :controller do
expect(response).to redirect_to(@secondary_room)
end
it "allows admin to update room settings" do
@admin = create(:user)
@admin.add_role :admin
@request.session[:user_id] = @admin.id
room_params = { "mute_on_join": "1", "name": @secondary_room.name }
formatted_room_params = "{\"muteOnStart\":true,\"requireModeratorApproval\":false," \
"\"anyoneCanStart\":false,\"joinModerator\":false}" # JSON string format
expect { post :update_settings, params: { room_uid: @secondary_room.uid, room: room_params } }
.to change { @secondary_room.reload.room_settings }
.from(@secondary_room.room_settings).to(formatted_room_params)
expect(response).to redirect_to(@secondary_room)
end
it "does not allow admins from a different context to update room settings" do
allow_any_instance_of(User).to receive(:admin_of?).and_return(false)
@admin = create(:user)
@admin.add_role :admin
@request.session[:user_id] = @admin.id
room_params = { "mute_on_join": "1", "name": @secondary_room.name }
expect { post :update_settings, params: { room_uid: @secondary_room.uid, room: room_params } }
.not_to change { @secondary_room.reload.room_settings }
expect(response).to redirect_to(root_path)
end
end
describe "GET #logout" do
@ -480,4 +618,122 @@ describe RoomsController, type: :controller do
expect(response).to redirect_to room_path(@user1.main_room)
end
end
describe "POST #shared_access" do
before do
@user = create(:user)
@room = create(:room, owner: @user)
@user1 = create(:user)
allow(Rails.configuration).to receive(:shared_access_default).and_return("true")
end
it "shares a room with another user" do
@request.session[:user_id] = @user.id
post :shared_access, params: { room_uid: @room.uid, add: [@user1.uid] }
expect(SharedAccess.exists?(room_id: @room.id, user_id: @user1.id)).to be true
expect(flash[:success]).to be_present
expect(response).to redirect_to room_path(@room)
end
it "allows a user to view a shared room and start it" do
@request.session[:user_id] = @user.id
post :shared_access, params: { room_uid: @room.uid, add: [@user1.uid] }
allow(controller).to receive(:current_user).and_return(@user1)
get :show, params: { room_uid: @room.uid }
expect(response).to render_template(:show)
end
it "unshares a room from the user if they are removed from the list" do
SharedAccess.create(room_id: @room.id, user_id: @user1.id)
expect(SharedAccess.exists?(room_id: @room.id, user_id: @user1.id)).to be true
@request.session[:user_id] = @user.id
post :shared_access, params: { room_uid: @room.uid, add: [] }
expect(SharedAccess.exists?(room_id: @room.id, user_id: @user1.id)).to be false
expect(flash[:success]).to be_present
expect(response).to redirect_to room_path(@room)
end
it "doesn't allow a user to share a room they don't own" do
@request.session[:user_id] = @user1.id
post :shared_access, params: { room_uid: @room.uid, add: [@user1.uid] }
expect(SharedAccess.exists?(room_id: @room.id, user_id: @user1.id)).to be false
expect(response).to redirect_to root_path
end
it "disables shared room functionality if the site setting is disabled" do
allow_any_instance_of(Setting).to receive(:get_value).and_return("false")
@request.session[:user_id] = @user.id
post :shared_access, params: { room_uid: @room.uid, add: [@user1.uid] }
expect(SharedAccess.exists?(room_id: @room.id, user_id: @user1.id)).to be true
allow(controller).to receive(:current_user).and_return(@user1)
get :show, params: { room_uid: @room.uid }
expect(response).to render_template(:join)
end
it "allows admins to update room access" do
@admin = create(:user)
@admin.add_role :admin
@request.session[:user_id] = @admin.id
post :shared_access, params: { room_uid: @room.uid, add: [@user1.uid] }
expect(SharedAccess.exists?(room_id: @room.id, user_id: @user1.id)).to be true
expect(flash[:success]).to be_present
expect(response).to redirect_to room_path(@room)
end
it "redirects to root path if not admin of current user" do
allow_any_instance_of(User).to receive(:admin_of?).and_return(false)
@admin = create(:user)
@admin.add_role :admin
@request.session[:user_id] = @admin.id
post :shared_access, params: { room_uid: @room.uid, add: [] }
expect(response).to redirect_to(root_path)
end
end
describe "POST #remove_shared_access" do
before do
@user = create(:user)
@room = create(:room, owner: @user)
@user1 = create(:user)
allow(Rails.configuration).to receive(:shared_access_default).and_return("true")
end
it "unshares a room from the user if they click the remove button" do
SharedAccess.create(room_id: @room.id, user_id: @user1.id)
expect(SharedAccess.exists?(room_id: @room.id, user_id: @user1.id)).to be true
@request.session[:user_id] = @user1.id
post :remove_shared_access, params: { room_uid: @room.uid, user_id: @user1.id }
expect(SharedAccess.exists?(room_id: @room.id, user_id: @user1.id)).to be false
expect(flash[:success]).to be_present
expect(response).to redirect_to @user1.main_room
end
it "doesn't allow some random user to change share access" do
@user2 = create(:user)
SharedAccess.create(room_id: @room.id, user_id: @user1.id)
expect(SharedAccess.exists?(room_id: @room.id, user_id: @user1.id)).to be true
@request.session[:user_id] = @user2.id
post :remove_shared_access, params: { room_uid: @room.uid, user_id: @user1.id }
expect(SharedAccess.exists?(room_id: @room.id, user_id: @user1.id)).to be true
expect(response).to redirect_to root_path
end
end
end

View File

@ -88,7 +88,11 @@ describe SessionsController, type: :controller do
end
describe "POST #create" 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)
allow_any_instance_of(SessionsController).to receive(:auth_changed_to_local?).and_return(false)
end
before(:each) do
@user1 = create(:user, provider: 'greenlight', password: 'example', password_confirmation: 'example')
@user2 = create(:user, password: 'example', password_confirmation: "example")
@ -139,7 +143,8 @@ describe SessionsController, type: :controller do
}
expect(@request.session[:user_id]).to be_nil
expect(response).to redirect_to(account_activation_path(email: @user3.email))
# Expect to redirect to activation path since token is not known here
expect(response.location.start_with?(account_activation_url(token: ""))).to be true
end
it "should not login user if account is deleted" do
@ -251,6 +256,22 @@ describe SessionsController, type: :controller do
expect(@user1.rooms.find { |r| r.name == "Old Home Room" }).to_not be_nil
expect(@user1.rooms.find { |r| r.name == "Test" }).to_not be_nil
end
it "sends the user a reset password email if the authentication method is changing to local" do
allow_any_instance_of(SessionsController).to receive(:auth_changed_to_local?).and_return(true)
email = Faker::Internet.email
create(:user, email: email, provider: "greenlight", social_uid: "google-user")
expect {
post :create, params: {
session: {
email: email,
password: 'example',
},
}
}.to change { ActionMailer::Base.deliveries.count }.by(1)
end
end
describe "GET/POST #omniauth" do
@ -428,6 +449,66 @@ describe SessionsController, type: :controller do
expect(response).to redirect_to(root_path)
end
it "switches a social account to a different social account if the authentication method changed" do
request.env["omniauth.auth"] = OmniAuth.config.mock_auth[:bn_launcher]
get :omniauth, params: { provider: 'bn_launcher' }
u = User.find_by(social_uid: "bn-launcher-user")
u.social_uid = nil
users_old_uid = u.uid
u.save!
new_user = OmniAuth::AuthHash.new(
provider: "bn_launcher",
uid: "bn-launcher-user-new",
info: {
email: "user@google.com",
name: "Office User",
nickname: "googleuser",
image: "touch.png",
customer: 'customer1',
}
)
allow_any_instance_of(SessionsController).to receive(:auth_changed_to_social?).and_return(true)
allow_any_instance_of(ApplicationController).to receive(:set_user_domain).and_return("customer1")
controller.instance_variable_set(:@user_domain, "customer1")
request.env["omniauth.auth"] = new_user
get :omniauth, params: { provider: 'bn_launcher' }
new_u = User.find_by(social_uid: "bn-launcher-user-new")
expect(users_old_uid).to eq(new_u.uid)
end
it "switches a local account to a different social account if the authentication method changed" do
email = Faker::Internet.email
user = create(:user, email: email, provider: "customer1")
users_old_uid = user.uid
new_user = OmniAuth::AuthHash.new(
provider: "bn_launcher",
uid: "bn-launcher-user-new",
info: {
email: email,
name: "Office User",
nickname: "googleuser",
image: "touch.png",
customer: 'customer1',
}
)
allow_any_instance_of(SessionsController).to receive(:auth_changed_to_social?).and_return(true)
allow_any_instance_of(ApplicationController).to receive(:set_user_domain).and_return("customer1")
controller.instance_variable_set(:@user_domain, "customer1")
request.env["omniauth.auth"] = new_user
get :omniauth, params: { provider: 'bn_launcher' }
new_u = User.find_by(social_uid: "bn-launcher-user-new")
expect(users_old_uid).to eq(new_u.uid)
end
end
describe "POST #ldap" do
@ -452,6 +533,51 @@ describe SessionsController, type: :controller do
expect(@request.session[:user_id]).to eql(u.id)
end
it "should defaults the users image to blank if actual image is provided" do
entry = Net::LDAP::Entry.new("cn=Test User,ou=people,dc=planetexpress,dc=com")
entry[:cn] = "Test User"
entry[:givenName] = "Test"
entry[:sn] = "User"
entry[:mail] = "test@example.com"
entry[:jpegPhoto] = "\FF\F8" # Pretend image
allow_any_instance_of(Net::LDAP).to receive(:bind_as).and_return([entry])
post :ldap, params: {
session: {
user: "test",
password: 'password',
},
}
u = User.last
expect(u.provider).to eql("ldap")
expect(u.image).to eql("")
expect(@request.session[:user_id]).to eql(u.id)
end
it "uses the users image if a url is provided" do
image = Faker::Internet.url
entry = Net::LDAP::Entry.new("cn=Test User,ou=people,dc=planetexpress,dc=com")
entry[:cn] = "Test User"
entry[:givenName] = "Test"
entry[:sn] = "User"
entry[:mail] = "test@example.com"
entry[:jpegPhoto] = image
allow_any_instance_of(Net::LDAP).to receive(:bind_as).and_return([entry])
post :ldap, params: {
session: {
user: "test",
password: 'password',
},
}
u = User.last
expect(u.provider).to eql("ldap")
expect(u.image).to eql(image)
expect(@request.session[:user_id]).to eql(u.id)
end
it "should redirect to signin on invalid credentials" do
allow_any_instance_of(Net::LDAP).to receive(:bind_as).and_return(false)

View File

@ -312,7 +312,7 @@ describe UsersController, type: :controller do
user_role.save!
tmp_role = Role.create(name: "test", priority: -2, provider: "greenlight")
tmp_role = Role.create(name: "test", priority: -4, provider: "greenlight")
params = random_valid_user_params
patch :update, params: params.merge!(user_uid: user, user: { role_ids: tmp_role.id.to_s })
@ -354,14 +354,16 @@ describe UsersController, type: :controller do
@request.session[:user_id] = admin.id
tmp_role1 = Role.create(name: "test1", priority: 1, provider: "greenlight")
tmp_role1 = Role.create(name: "test1", priority: 2, provider: "greenlight")
tmp_role1.update_permission("send_promoted_email", "true")
tmp_role2 = Role.create(name: "test2", priority: 2, provider: "greenlight")
tmp_role2 = Role.create(name: "test2", priority: 3, provider: "greenlight")
params = random_valid_user_params
params = params.merge!(user_uid: user, user: { role_ids: "#{tmp_role1.id} #{tmp_role2.id}" })
expect { patch :update, params: params }.to change { ActionMailer::Base.deliveries.count }.by(1)
user.reload
expect(user.roles.count).to eq(2)
expect(user.highest_priority_role.name).to eq("test1")
expect(response).to redirect_to(admins_path)
@ -375,7 +377,7 @@ describe UsersController, type: :controller do
admin.add_role :admin
tmp_role1 = Role.create(name: "test1", priority: 1, provider: "greenlight")
tmp_role1 = Role.create(name: "test1", priority: 2, provider: "greenlight")
tmp_role1.update_permission("send_demoted_email", "true")
user.roles << tmp_role1
user.save!

View File

@ -112,6 +112,28 @@ describe User, type: :model do
end
end
context '#ordered_rooms' do
it 'correctly orders the users rooms' do
user = create(:user)
room1 = create(:room, owner: user)
room2 = create(:room, owner: user)
room3 = create(:room, owner: user)
room4 = create(:room, owner: user)
room4.update_attributes(sessions: 1, last_session: "2020-02-24 19:52:57")
room3.update_attributes(sessions: 1, last_session: "2020-01-25 19:52:57")
room2.update_attributes(sessions: 1, last_session: "2019-09-05 19:52:57")
room1.update_attributes(sessions: 1, last_session: "2015-02-24 19:52:57")
rooms = user.ordered_rooms
expect(rooms[0]).to eq(user.main_room)
expect(rooms[1]).to eq(room4)
expect(rooms[2]).to eq(room3)
expect(rooms[3]).to eq(room2)
expect(rooms[4]).to eq(room1)
end
end
context 'password reset' do
it 'creates token and respective reset digest' do
user = create(:user)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long