forked from External/greenlight
GRN2-253: Added the ability to share rooms across multiple users (#912)
* Added ability to share rooms with other users * Fixed testcases
This commit is contained in:
parent
8cbfc3f730
commit
967130e57c
|
@ -34,4 +34,5 @@
|
||||||
//= require jquery-ui/widget
|
//= require jquery-ui/widget
|
||||||
//= require jquery-ui/widgets/sortable
|
//= require jquery-ui/widgets/sortable
|
||||||
//= require pickr.min.js
|
//= require pickr.min.js
|
||||||
|
//= require bootstrap-select.min.js
|
||||||
//= require_tree .
|
//= require_tree .
|
||||||
|
|
|
@ -60,6 +60,69 @@ $(document).on('turbolinks:load', function(){
|
||||||
$(".delete-room").click(function() {
|
$(".delete-room").click(function() {
|
||||||
showDeleteRoom(this)
|
showDeleteRoom(this)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
$('.selectpicker').selectpicker({
|
||||||
|
liveSearchPlaceholder: "Start searching..."
|
||||||
|
});
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -150,3 +213,44 @@ function ResetAccessCode(){
|
||||||
$("#create-room-access-code").text(getLocalizedString("modal.create_room.access_code_placeholder"))
|
$("#create-room-access-code").text(getLocalizedString("modal.create_room.access_code_placeholder"))
|
||||||
$("#room_access_code").val(null)
|
$("#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")
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,14 +36,16 @@
|
||||||
@import "tabler-custom";
|
@import "tabler-custom";
|
||||||
@import "font-awesome-sprockets";
|
@import "font-awesome-sprockets";
|
||||||
@import "font-awesome";
|
@import "font-awesome";
|
||||||
|
@import "monolith.min.scss";
|
||||||
|
@import "bootstrap-select.min.css";
|
||||||
|
|
||||||
@import "utilities/variables";
|
@import "utilities/variables";
|
||||||
@import "admins";
|
@import "admins";
|
||||||
@import "main";
|
@import "main";
|
||||||
@import "rooms";
|
@import "rooms";
|
||||||
@import "sessions";
|
@import "sessions";
|
||||||
@import "monolith.min.scss";
|
|
||||||
@import "utilities/fonts";
|
@import "utilities/fonts";
|
||||||
|
@import "users";
|
||||||
|
|
||||||
* {
|
* {
|
||||||
outline: none !important;
|
outline: none !important;
|
||||||
|
|
|
@ -83,3 +83,20 @@
|
||||||
margin-top: -6rem;
|
margin-top: -6rem;
|
||||||
font-size: 5rem;
|
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;
|
||||||
|
}
|
|
@ -22,3 +22,11 @@
|
||||||
.user-role-tag{
|
.user-role-tag{
|
||||||
color: white !important;
|
color: white !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.shared-user {
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bootstrap-select {
|
||||||
|
border: 1px solid rgba(0, 40, 100, 0.12);
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ class AdminsController < ApplicationController
|
||||||
include Emailer
|
include Emailer
|
||||||
include Recorder
|
include Recorder
|
||||||
include Rolify
|
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]
|
||||||
manage_deleted_users = [:undelete]
|
manage_deleted_users = [:undelete]
|
||||||
|
@ -49,11 +50,7 @@ class AdminsController < ApplicationController
|
||||||
|
|
||||||
# GET /admins/server_recordings
|
# GET /admins/server_recordings
|
||||||
def server_recordings
|
def server_recordings
|
||||||
server_rooms = if Rails.configuration.loadbalanced_configuration
|
server_rooms = rooms_list_for_recordings
|
||||||
Room.includes(:owner).where(users: { provider: @user_domain }).pluck(:bbb_id)
|
|
||||||
else
|
|
||||||
Room.pluck(:bbb_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
@search, @order_column, @order_direction, recs =
|
@search, @order_column, @order_direction, recs =
|
||||||
all_recordings(server_rooms, params.permit(:search, :column, :direction), true, true)
|
all_recordings(server_rooms, params.permit(:search, :column, :direction), true, true)
|
||||||
|
@ -67,13 +64,9 @@ class AdminsController < ApplicationController
|
||||||
@order_column = params[:column] && params[:direction] != "none" ? params[:column] : "created_at"
|
@order_column = params[:column] && params[:direction] != "none" ? params[:column] : "created_at"
|
||||||
@order_direction = params[:direction] && params[:direction] != "none" ? params[:direction] : "DESC"
|
@order_direction = params[:direction] && params[:direction] != "none" ? params[:direction] : "DESC"
|
||||||
|
|
||||||
server_rooms = if Rails.configuration.loadbalanced_configuration
|
server_rooms = server_rooms_list
|
||||||
Room.includes(:owner).where(users: { provider: @user_domain })
|
|
||||||
.admins_search(@search)
|
@user_list = shared_user_list if shared_access_allowed
|
||||||
.admins_order(@order_column, @order_direction)
|
|
||||||
else
|
|
||||||
Room.all.admins_search(@search).admins_order(@order_column, @order_direction)
|
|
||||||
end
|
|
||||||
|
|
||||||
@pagy, @rooms = pagy_array(server_rooms)
|
@pagy, @rooms = pagy_array(server_rooms)
|
||||||
end
|
end
|
||||||
|
|
|
@ -172,6 +172,12 @@ class ApplicationController < ActionController::Base
|
||||||
end
|
end
|
||||||
helper_method :configured_providers
|
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
|
# Parses the url for the user domain
|
||||||
def parse_user_domain(hostname)
|
def parse_user_domain(hostname)
|
||||||
return hostname.split('.').first if Rails.configuration.url_host.empty?
|
return hostname.split('.').first if Rails.configuration.url_host.empty?
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2018 BigBlueButton Inc. and by respective authors (see below).
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it under the
|
||||||
|
# terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
# Foundation; either version 3.0 of the License, or (at your option) any later
|
||||||
|
# version.
|
||||||
|
#
|
||||||
|
# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License along
|
||||||
|
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
module Populator
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
# 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.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.name != "super_admin"
|
||||||
|
end
|
||||||
|
|
||||||
|
initial_list = User.where.not(uid: current_user.uid).with_highest_priority_role(roles_can_appear)
|
||||||
|
|
||||||
|
return initial_list unless Rails.configuration.loadbalanced_configuration
|
||||||
|
initial_list.where(provider: @user_domain)
|
||||||
|
end
|
||||||
|
end
|
|
@ -142,7 +142,7 @@ module Rolify
|
||||||
role_params = params.require(:role).permit(:name)
|
role_params = params.require(:role).permit(:name)
|
||||||
permission_params = params.require(:role).permit(:can_create_rooms, :send_promoted_email,
|
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,
|
:send_demoted_email, :can_edit_site_settings, :can_edit_roles, :can_manage_users,
|
||||||
:can_manage_rooms_recordings, :colour)
|
:can_manage_rooms_recordings, :can_appear_in_share_list, :colour)
|
||||||
|
|
||||||
permission_params.transform_values! do |v|
|
permission_params.transform_values! do |v|
|
||||||
if v == "0"
|
if v == "0"
|
||||||
|
|
|
@ -20,12 +20,15 @@ class RoomsController < ApplicationController
|
||||||
include Pagy::Backend
|
include Pagy::Backend
|
||||||
include Recorder
|
include Recorder
|
||||||
include Joiner
|
include Joiner
|
||||||
|
include Populator
|
||||||
|
|
||||||
before_action :validate_accepted_terms, unless: -> { !Rails.configuration.terms }
|
before_action :validate_accepted_terms, unless: -> { !Rails.configuration.terms }
|
||||||
before_action :validate_verified_email, except: [:show, :join],
|
before_action :validate_verified_email, except: [:show, :join],
|
||||||
unless: -> { !Rails.configuration.enable_email_verification }
|
unless: -> { !Rails.configuration.enable_email_verification }
|
||||||
before_action :find_room, except: [:create, :join_specific_room]
|
before_action :find_room, except: [:create, :join_specific_room]
|
||||||
before_action :verify_room_ownership_or_admin, only: [:start, :update_settings, :destroy]
|
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],
|
before_action :verify_room_owner_verified, only: [:show, :join],
|
||||||
unless: -> { !Rails.configuration.enable_email_verification }
|
unless: -> { !Rails.configuration.enable_email_verification }
|
||||||
before_action :verify_room_owner_valid, only: [:show, :join]
|
before_action :verify_room_owner_valid, only: [:show, :join]
|
||||||
|
@ -61,14 +64,17 @@ class RoomsController < ApplicationController
|
||||||
def show
|
def show
|
||||||
@anyone_can_start = JSON.parse(@room[:room_settings])["anyoneCanStart"]
|
@anyone_can_start = JSON.parse(@room[:room_settings])["anyoneCanStart"]
|
||||||
@room_running = room_running?(@room.bbb_id)
|
@room_running = room_running?(@room.bbb_id)
|
||||||
|
@shared_room = room_shared_with_user
|
||||||
|
|
||||||
# If its the current user's room
|
# 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")
|
if current_user.highest_priority_role.get_permission("can_create_rooms")
|
||||||
# User is allowed to have rooms
|
# User is allowed to have rooms
|
||||||
@search, @order_column, @order_direction, recs =
|
@search, @order_column, @order_direction, recs =
|
||||||
recordings(@room.bbb_id, params.permit(:search, :column, :direction), true)
|
recordings(@room.bbb_id, params.permit(:search, :column, :direction), true)
|
||||||
|
|
||||||
|
@user_list = shared_user_list if shared_access_allowed
|
||||||
|
|
||||||
@pagy, @recordings = pagy_array(recs)
|
@pagy, @recordings = pagy_array(recs)
|
||||||
else
|
else
|
||||||
# Render view for users that cant create rooms
|
# Render view for users that cant create rooms
|
||||||
|
@ -189,6 +195,55 @@ class RoomsController < ApplicationController
|
||||||
redirect_back fallback_location: room_path(@room)
|
redirect_back fallback_location: room_path(@room)
|
||||||
end
|
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/logout
|
# GET /:room_uid/logout
|
||||||
def logout
|
def logout
|
||||||
logger.info "Support: #{current_user.present? ? current_user.email : 'Guest'} has left room #{@room.uid}"
|
logger.info "Support: #{current_user.present? ? current_user.email : 'Guest'} has left room #{@room.uid}"
|
||||||
|
@ -229,11 +284,23 @@ class RoomsController < ApplicationController
|
||||||
@room = Room.find_by!(uid: params[:room_uid])
|
@room = Room.find_by!(uid: params[:room_uid])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# 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
|
# Ensure the user either owns the room or is an admin of the room owner
|
||||||
def verify_room_ownership_or_admin
|
def verify_room_ownership_or_admin
|
||||||
return redirect_to root_path if !@room.owned_by?(current_user) && !current_user&.admin_of?(@room.owner)
|
return redirect_to root_path if !@room.owned_by?(current_user) && !current_user&.admin_of?(@room.owner)
|
||||||
end
|
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
|
def validate_accepted_terms
|
||||||
redirect_to terms_path if current_user && !current_user&.accepted_terms
|
redirect_to terms_path if current_user && !current_user&.accepted_terms
|
||||||
end
|
end
|
||||||
|
@ -259,6 +326,11 @@ class RoomsController < ApplicationController
|
||||||
@settings.get_value("Room Authentication") == "true" && current_user.nil?
|
@settings.get_value("Room Authentication") == "true" && current_user.nil?
|
||||||
end
|
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
|
def room_limit_exceeded
|
||||||
limit = @settings.get_value("Room Limit").to_i
|
limit = @settings.get_value("Room Limit").to_i
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,14 @@ module AdminsHelper
|
||||||
end
|
end
|
||||||
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
|
def recording_default_visibility_string
|
||||||
if @settings.get_value("Default Recording Visibility") == "public"
|
if @settings.get_value("Default Recording Visibility") == "public"
|
||||||
I18n.t("recording.visibility.public")
|
I18n.t("recording.visibility.public")
|
||||||
|
|
|
@ -42,7 +42,7 @@ class Role < ApplicationRecord
|
||||||
Role.create(name: "super_admin", provider: provider, priority: -2, colour: "#cd201f")
|
Role.create(name: "super_admin", provider: provider, priority: -2, colour: "#cd201f")
|
||||||
.update_all_role_permissions(can_create_rooms: true,
|
.update_all_role_permissions(can_create_rooms: true,
|
||||||
send_promoted_email: true, send_demoted_email: true, can_edit_site_settings: 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_appear_in_share_list: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.create_new_role(role_name, provider)
|
def self.create_new_role(role_name, provider)
|
||||||
|
@ -69,6 +69,7 @@ class Role < ApplicationRecord
|
||||||
update_permission("can_edit_roles", permissions[:can_edit_roles].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_users", permissions[:can_manage_users].to_s)
|
||||||
update_permission("can_manage_rooms_recordings", permissions[:can_manage_rooms_recordings].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
|
end
|
||||||
|
|
||||||
# Updates the value of the permission and enables it
|
# Updates the value of the permission and enables it
|
||||||
|
@ -84,9 +85,14 @@ class Role < ApplicationRecord
|
||||||
|
|
||||||
value = if permission[:enabled]
|
value = if permission[:enabled]
|
||||||
permission[:value]
|
permission[:value]
|
||||||
|
else
|
||||||
|
case name
|
||||||
|
when "can_appear_in_share_list"
|
||||||
|
Rails.configuration.shared_access_default.to_s
|
||||||
else
|
else
|
||||||
"false"
|
"false"
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if return_boolean
|
if return_boolean
|
||||||
value == "true"
|
value == "true"
|
||||||
|
|
|
@ -26,6 +26,7 @@ class Room < ApplicationRecord
|
||||||
validates :name, presence: true
|
validates :name, presence: true
|
||||||
|
|
||||||
belongs_to :owner, class_name: 'User', foreign_key: :user_id
|
belongs_to :owner, class_name: 'User', foreign_key: :user_id
|
||||||
|
has_many :shared_access
|
||||||
|
|
||||||
def self.admins_search(string)
|
def self.admins_search(string)
|
||||||
active_database = Rails.configuration.database_configuration[Rails.env]["adapter"]
|
active_database = Rails.configuration.database_configuration[Rails.env]["adapter"]
|
||||||
|
@ -59,6 +60,15 @@ class Room < ApplicationRecord
|
||||||
user.rooms.include?(self)
|
user.rooms.include?(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def shared_users
|
||||||
|
User.where(id: shared_access.pluck(:user_id))
|
||||||
|
end
|
||||||
|
|
||||||
|
def shared_with?(user)
|
||||||
|
return false if user.nil?
|
||||||
|
shared_users.include?(user)
|
||||||
|
end
|
||||||
|
|
||||||
# Determines the invite path for the room.
|
# Determines the invite path for the room.
|
||||||
def invite_path
|
def invite_path
|
||||||
"#{Rails.configuration.relative_url_root}/#{CGI.escape(uid)}"
|
"#{Rails.configuration.relative_url_root}/#{CGI.escape(uid)}"
|
||||||
|
|
|
@ -43,6 +43,8 @@ class Setting < ApplicationRecord
|
||||||
false
|
false
|
||||||
when "Room Limit"
|
when "Room Limit"
|
||||||
Rails.configuration.number_of_rooms_default
|
Rails.configuration.number_of_rooms_default
|
||||||
|
when "Shared Access"
|
||||||
|
Rails.configuration.shared_access_default
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class SharedAccess < ApplicationRecord
|
||||||
|
belongs_to :room
|
||||||
|
end
|
|
@ -29,6 +29,7 @@ class User < ApplicationRecord
|
||||||
before_destroy :destroy_rooms
|
before_destroy :destroy_rooms
|
||||||
|
|
||||||
has_many :rooms
|
has_many :rooms
|
||||||
|
has_many :shared_access
|
||||||
belongs_to :main_room, class_name: 'Room', foreign_key: :room_id, required: false
|
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, -> { includes :role_permissions }, join_table: :users_roles
|
||||||
|
@ -135,6 +136,11 @@ class User < ApplicationRecord
|
||||||
room_list.where.not(last_session: nil).order("last_session desc") + room_list.where(last_session: nil)
|
room_list.where.not(last_session: nil).order("last_session desc") + room_list.where(last_session: nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# 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
|
def name_chunk
|
||||||
charset = ("a".."z").to_a - %w(b i l o s) + ("2".."9").to_a - %w(5 8)
|
charset = ("a".."z").to_a - %w(b i l o s) + ("2".."9").to_a - %w(5 8)
|
||||||
chunk = name.parameterize[0...3]
|
chunk = name.parameterize[0...3]
|
||||||
|
@ -228,11 +234,22 @@ class User < ApplicationRecord
|
||||||
User.where.not(id: with_role(role).pluck(:id))
|
User.where.not(id: with_role(role).pluck(:id))
|
||||||
end
|
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
|
def self.all_users_with_roles
|
||||||
User.joins("INNER JOIN users_roles ON users_roles.user_id = users.id INNER JOIN 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
|
"ON roles.id = users_roles.role_id INNER JOIN role_permissions ON roles.id = role_permissions.role_id").distinct
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.all_users_highest_priority_role
|
||||||
|
User.joins("INNER JOIN (SELECT user_id, role_id, min(roles.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.id = a.role_id " \
|
||||||
|
" INNER JOIN role_permissions ON roles.id = role_permissions.role_id").distinct
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def create_reset_activation_digest(token)
|
def create_reset_activation_digest(token)
|
||||||
|
|
|
@ -73,6 +73,11 @@
|
||||||
<%= 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") %>
|
<%= 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>
|
<span class="custom-switch-indicator float-right"></span>
|
||||||
</label>
|
</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_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") %>">
|
<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>
|
<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") %>
|
<%= 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") %>
|
||||||
|
|
|
@ -53,6 +53,11 @@
|
||||||
<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">
|
||||||
<i class="dropdown-icon fas fa-cog"></i> <%= t("room.settings") %>
|
<i class="dropdown-icon fas fa-cog"></i> <%= t("room.settings") %>
|
||||||
</a>
|
</a>
|
||||||
|
<% if 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 %>
|
||||||
<a href="" data-toggle="modal" data-target="#deleteRoomModal" data-path="<%= room_path(room) %>" data-name="<%= room.name %>" class="delete-room dropdown-item">
|
<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") %>
|
<i class="dropdown-icon far fa-trash-alt"></i> <%= t("delete") %>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -99,6 +99,27 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mb-6 row">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label"><%= t("administrator.site_settings.shared_access.title") %></label>
|
||||||
|
<label class="form-label text-muted"><%= t("administrator.site_settings.shared_access.info") %></label>
|
||||||
|
<div class="dropdown">
|
||||||
|
<button class="btn btn-primary dropdown-toggle" type="button" id="room-auth" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<%= shared_access_string %>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu" aria-labelledby="room-auth">
|
||||||
|
<%= button_to admin_update_settings_path(setting: "Shared Access", value: "true"), class: "dropdown-item" do %>
|
||||||
|
<%= t("administrator.site_settings.authentication.enabled") %>
|
||||||
|
<% end %>
|
||||||
|
<%= button_to admin_update_settings_path(setting: "Shared Access", value: "false"), class: "dropdown-item" do %>
|
||||||
|
<%= t("administrator.site_settings.authentication.disabled") %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="mb-6 row">
|
<div class="mb-6 row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|
|
@ -28,3 +28,6 @@
|
||||||
|
|
||||||
<%= render "shared/modals/delete_room_modal" %>
|
<%= render "shared/modals/delete_room_modal" %>
|
||||||
<%= render "shared/modals/create_room_modal" %>
|
<%= render "shared/modals/create_room_modal" %>
|
||||||
|
<% if shared_access_allowed %>
|
||||||
|
<%= render "shared/modals/share_room_modal" %>
|
||||||
|
<% end %>
|
|
@ -46,19 +46,26 @@
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
|
<% unless room == current_user.main_room %>
|
||||||
<div class="item-action dropdown" data-display="static">
|
<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>
|
<i class="fas fa-ellipsis-v px-4"></i>
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-menu dropdown-menu-right dropdown-menu-md-left">
|
<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">
|
||||||
<i class="dropdown-icon fas fa-cog"></i> <%= t("room.settings") %>
|
<i class="dropdown-icon fas fa-cog"></i> <%= t("room.settings") %>
|
||||||
</a>
|
</a>
|
||||||
|
<% if 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 %>
|
||||||
<a href="" data-toggle="modal" data-target="#deleteRoomModal" data-path="<%= room_path(room) %>" data-name="<%= room.name %>" class="delete-room dropdown-item">
|
<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") %>
|
<i class="dropdown-icon far fa-trash-alt"></i> <%= t("delete") %>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<% end %>
|
||||||
</td>
|
</td>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -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>
|
|
@ -91,6 +91,17 @@
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% 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/shared_room_block", room: room %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<% unless room_limit_exceeded %>
|
<% unless room_limit_exceeded %>
|
||||||
<%= render "rooms/components/create_room_block"%>
|
<%= render "rooms/components/create_room_block"%>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
@ -98,8 +109,13 @@
|
||||||
</div>
|
</div>
|
||||||
</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/delete_room_modal" %>
|
||||||
|
|
||||||
<%= render "shared/modals/create_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 %>
|
|
@ -94,7 +94,7 @@
|
||||||
<% failed_recordings = 0 %>
|
<% failed_recordings = 0 %>
|
||||||
<% recordings.each do |recording| %>
|
<% recordings.each do |recording| %>
|
||||||
<% begin %>
|
<% begin %>
|
||||||
<% if only_public %>
|
<% if only_public || (defined?(shared_room) && shared_room) %>
|
||||||
<%= render "shared/components/public_recording_row", recording: recording %>
|
<%= render "shared/components/public_recording_row", recording: recording %>
|
||||||
<% else %>
|
<% else %>
|
||||||
<%= render "shared/components/recording_row", recording: recording %>
|
<%= render "shared/components/recording_row", recording: recording %>
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -153,6 +153,9 @@ module Greenlight
|
||||||
# Default limit on number of rooms users can create
|
# Default limit on number of rooms users can create
|
||||||
config.number_of_rooms_default = 15
|
config.number_of_rooms_default = 15
|
||||||
|
|
||||||
|
# Allow users to share rooms by default
|
||||||
|
config.shared_access_default = (ENV["SHARED_ACCESS"] == "true").to_s
|
||||||
|
|
||||||
# Default admin password
|
# Default admin password
|
||||||
config.admin_password_default = ENV['ADMIN_PASSWORD'] || 'administrator'
|
config.admin_password_default = ENV['ADMIN_PASSWORD'] || 'administrator'
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,9 @@ en:
|
||||||
rooms:
|
rooms:
|
||||||
info: Limits the number of rooms that a user can have (including Home Room). This setting does not apply to administrators.
|
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
|
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
|
subtitle: Customize Greenlight
|
||||||
title: Site Settings
|
title: Site Settings
|
||||||
flash:
|
flash:
|
||||||
|
@ -342,6 +345,10 @@ en:
|
||||||
with: Sign in with %{provider}
|
with: Sign in with %{provider}
|
||||||
forgot_password: Forgot Password?
|
forgot_password: Forgot Password?
|
||||||
rename_recording:
|
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:
|
room_settings:
|
||||||
title: Room Settings
|
title: Room Settings
|
||||||
update: Update Room
|
update: Update Room
|
||||||
|
@ -353,6 +360,13 @@ en:
|
||||||
footer_text: Adjustment to your room can be done at anytime.
|
footer_text: Adjustment to your room can be done at anytime.
|
||||||
rename_room:
|
rename_room:
|
||||||
name_placeholder: Enter a new room name...
|
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
|
||||||
name_update_success: Room name successfully changed!
|
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.
|
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!
|
omniauth_error: An error occured while authenticating with omniauth. Please try again or contact an administrator!
|
||||||
|
@ -413,6 +427,7 @@ en:
|
||||||
invite:
|
invite:
|
||||||
fail: Your token is either invalid or has expired. If you believe this is a mistake, please contact your administrator.
|
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.
|
no_invite: You do not have an invitation to join. Please contact your administrator to receive one.
|
||||||
|
remove: Remove
|
||||||
rename: Rename
|
rename: Rename
|
||||||
reset_password:
|
reset_password:
|
||||||
subtitle: Reset Password
|
subtitle: Reset Password
|
||||||
|
@ -460,6 +475,12 @@ en:
|
||||||
room_limit_exceeded: You have exceeded the number of rooms allowed. Please delete %{difference} room(s) to access this room.
|
room_limit_exceeded: You have exceeded the number of rooms allowed. Please delete %{difference} room(s) to access this room.
|
||||||
sessions: Sessions
|
sessions: Sessions
|
||||||
settings: Room Settings
|
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
|
start: Start
|
||||||
unavailable: This room is currently unavailable due to the owner's email not being verified.
|
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
|
update_settings_error: There was an error updating the room settings
|
||||||
|
|
|
@ -112,6 +112,9 @@ Rails.application.routes.draw do
|
||||||
post '/', to: 'rooms#join'
|
post '/', to: 'rooms#join'
|
||||||
patch '/', to: 'rooms#update', as: :update_room
|
patch '/', to: 'rooms#update', as: :update_room
|
||||||
post '/update_settings', to: 'rooms#update_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
|
post '/start', to: 'rooms#start', as: :start_room
|
||||||
get '/logout', to: 'rooms#logout', as: :logout_room
|
get '/logout', to: 'rooms#logout', as: :logout_room
|
||||||
post '/login', to: 'rooms#login', as: :login_room
|
post '/login', to: 'rooms#login', as: :login_room
|
||||||
|
|
|
@ -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
|
11
db/schema.rb
11
db/schema.rb
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2019_10_23_172511) do
|
ActiveRecord::Schema.define(version: 2019_11_28_212935) do
|
||||||
|
|
||||||
create_table "features", force: :cascade do |t|
|
create_table "features", force: :cascade do |t|
|
||||||
t.integer "setting_id"
|
t.integer "setting_id"
|
||||||
|
@ -90,6 +90,15 @@ ActiveRecord::Schema.define(version: 2019_10_23_172511) do
|
||||||
t.index ["provider"], name: "index_settings_on_provider"
|
t.index ["provider"], name: "index_settings_on_provider"
|
||||||
end
|
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|
|
create_table "users", force: :cascade do |t|
|
||||||
t.integer "room_id"
|
t.integer "room_id"
|
||||||
t.string "provider"
|
t.string "provider"
|
||||||
|
|
|
@ -91,7 +91,8 @@ a {
|
||||||
opacity: 0.9;
|
opacity: 0.9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:active {
|
&:active, &.active {
|
||||||
|
color: $primary-color !important;
|
||||||
background-color: $primary-color-lighten !important;
|
background-color: $primary-color-lighten !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -345,6 +345,23 @@ describe AdminsController, type: :controller do
|
||||||
end
|
end
|
||||||
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
|
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")
|
allow_any_instance_of(ApplicationController).to receive(:set_user_domain).and_return("provider1")
|
||||||
controller.instance_variable_set(:@user_domain, "provider1")
|
controller.instance_variable_set(:@user_domain, "provider1")
|
||||||
|
@ -375,6 +392,7 @@ describe AdminsController, type: :controller do
|
||||||
expect(@user3.social_uid).to be(nil)
|
expect(@user3.social_uid).to be(nil)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "Roles" do
|
describe "Roles" do
|
||||||
context "GET #roles" do
|
context "GET #roles" do
|
||||||
|
|
|
@ -605,4 +605,122 @@ describe RoomsController, type: :controller do
|
||||||
expect(response).to redirect_to room_path(@user1.main_room)
|
expect(response).to redirect_to room_path(@user1.main_room)
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue