Add optional moderator codes (#2413)

* add column for moderator code

* add interface for moderator access code

* add support for write and update moderator access

* check if correct moderator_code in session

* move access code form into own component

* add support for moderator access code

* add support for moderator access code

* add copy code button for moderator code

* freeze all the things

* add tests for moderator access code

* add helpfer for moderator_access setting

* add setting for moderator access code

* show setting for moderator access code

* add checks for moderator code setting

* use method from room controller for moderator password check

* add tests for login with moderator access code

* add check for moderator code setting

* check if moderator codes are enabled in settings

* only display form for moderator code if enabled in settings

* add newline at end of file

* make check for moderator code available as helper

* align style of join button and access code button

* add localization for moderator codes

* add field for moderator codes

* add field for moderator access code to rooms

* fixes for rubocop

* fix LineLenghts for rubocop

* fix double space

Co-authored-by: Ahmad Farhat <ahmad.af.farhat@gmail.com>
This commit is contained in:
zechmeister 2021-03-14 19:24:30 +01:00 committed by GitHub
parent 4cd41f5aa8
commit 9dc59b1211
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 447 additions and 174 deletions

View File

@ -184,17 +184,19 @@ function copyInvite() {
} }
} }
function copyAccess() { function copyAccess(target) {
$('#copy-code').attr("type", "text") input = target ? $("#copy-" + target + "-code") : $("#copy-code")
$('#copy-code').select() input.attr("type", "text")
input.select()
if (document.execCommand("copy")) { if (document.execCommand("copy")) {
$('#copy-code').attr("type", "hidden") input.attr("type", "hidden")
copy = $("#copy-access") copy = target ? $("#copy-" + target + "-access") : $("#copy-access")
copy.addClass('btn-success'); copy.addClass('btn-success');
copy.html("<i class='fas fa-check mr-1'></i>" + getLocalizedString("copied")) copy.html("<i class='fas fa-check mr-1'></i>" + getLocalizedString("copied"))
setTimeout(function(){ setTimeout(function(){
copy.removeClass('btn-success'); copy.removeClass('btn-success');
copy.html("<i class='fas fa-copy mr-1'></i>" + getLocalizedString("room.copy_access")) originalString = target ? getLocalizedString("room.copy_" + target + "_access") : getLocalizedString("room.copy_access")
copy.html("<i class='fas fa-copy mr-1'></i>" + originalString)
}, 1000) }, 1000)
} }
} }
@ -202,7 +204,9 @@ function copyAccess() {
function showCreateRoom(target) { function showCreateRoom(target) {
$("#create-room-name").val("") $("#create-room-name").val("")
$("#create-room-access-code").text(getLocalizedString("modal.create_room.access_code_placeholder")) $("#create-room-access-code").text(getLocalizedString("modal.create_room.access_code_placeholder"))
$("#create-room-moderator-access-code").text(getLocalizedString("modal.create_room.moderator_access_code_placeholder"))
$("#room_access_code").val(null) $("#room_access_code").val(null)
$("#room_moderator_access_code").val(null)
$("#createRoomModal form").attr("action", $("body").data('relative-root')) $("#createRoomModal form").attr("action", $("body").data('relative-root'))
$("#room_mute_on_join").prop("checked", $("#room_mute_on_join").data("default")) $("#room_mute_on_join").prop("checked", $("#room_mute_on_join").data("default"))
@ -254,6 +258,16 @@ function showUpdateRoom(target) {
$("#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)
} }
var moderatorAccessCode = modal.closest(".room-block").data("room-moderator-access-code")
if(moderatorAccessCode){
$("#create-room-moderator-access-code").text(getLocalizedString("modal.create_room.moderator_access_code") + ": " + moderatorAccessCode)
$("#room_moderator_access_code").val(moderatorAccessCode)
} else {
$("#create-room-moderator-access-code").text(getLocalizedString("modal.create_room.moderator_access_code_placeholder"))
$("#room_moderator_access_code").val(null)
}
} }
function showDeleteRoom(target) { function showDeleteRoom(target) {
@ -291,6 +305,24 @@ function ResetAccessCode(){
$("#room_access_code").val(null) $("#room_access_code").val(null)
} }
function generateModeratorAccessCode(){
const accessCodeLength = 6
var validCharacters = "abcdefghijklmopqrstuvwxyz"
var accessCode = ""
for( var i = 0; i < accessCodeLength; i++){
accessCode += validCharacters.charAt(Math.floor(Math.random() * validCharacters.length));
}
$("#create-room-moderator-access-code").text(getLocalizedString("modal.create_room.moderator_access_code") + ": " + accessCode)
$("#room_moderator_access_code").val(accessCode)
}
function ResetModeratorAccessCode(){
$("#create-room-moderator-access-code").text(getLocalizedString("modal.create_room.moderator_access_code_placeholder"))
$("#room_moderator_access_code").val(null)
}
function saveAccessChanges() { function saveAccessChanges() {
let listItemsToAdd = $("#user-list li:not(.remove-shared)").toArray().map(user => $(user).data("uid")) let listItemsToAdd = $("#user-list li:not(.remove-shared)").toArray().map(user => $(user).data("uid"))

View File

@ -32,8 +32,8 @@
font-size: 20px !important; font-size: 20px !important;
} }
.join-input { .moderator-code-label {
height: 48px; margin-top: 150px !important;
} }
.home-indicator { .home-indicator {

View File

@ -186,6 +186,12 @@ class ApplicationController < ActionController::Base
end end
helper_method :recording_consent_required? helper_method :recording_consent_required?
# Indicates whether users are allowed to add moderator access codes to rooms
def moderator_code_allowed?
@settings.get_value("Moderator Access Codes") == "true"
end
helper_method :moderator_code_allowed?
# Returns a list of allowed file types # Returns a list of allowed file types
def allowed_file_types def allowed_file_types
Rails.configuration.allowed_file_types Rails.configuration.allowed_file_types

View File

@ -50,10 +50,11 @@ module Joiner
def join_room(opts) def join_room(opts)
@room_settings = JSON.parse(@room[:room_settings]) @room_settings = JSON.parse(@room[:room_settings])
if room_running?(@room.bbb_id) || @room.owned_by?(current_user) || room_setting_with_config("anyoneCanStart") moderator_privileges = @room.owned_by?(current_user) || valid_moderator_access_code(session[:moderator_access_code])
if room_running?(@room.bbb_id) || room_setting_with_config("anyoneCanStart") || moderator_privileges
# Determine if the user needs to join as a moderator. # Determine if the user needs to join as a moderator.
opts[:user_is_moderator] = @room.owned_by?(current_user) || room_setting_with_config("joinModerator") || @shared_room opts[:user_is_moderator] = room_setting_with_config("joinModerator") || @shared_room || moderator_privileges
opts[:record] = record_meeting opts[:record] = record_meeting
opts[:require_moderator_approval] = room_setting_with_config("requireModeratorApproval") opts[:require_moderator_approval] = room_setting_with_config("requireModeratorApproval")
opts[:mute_on_start] = room_setting_with_config("muteOnStart") opts[:mute_on_start] = room_setting_with_config("muteOnStart")

View File

@ -44,7 +44,9 @@ class RoomsController < ApplicationController
return redirect_to current_user.main_room, flash: { alert: I18n.t("room.room_limit") } if room_limit_exceeded return redirect_to current_user.main_room, flash: { alert: I18n.t("room.room_limit") } if room_limit_exceeded
# Create room # Create room
@room = Room.new(name: room_params[:name], access_code: room_params[:access_code]) @room = Room.new(name: room_params[:name],
access_code: room_params[:access_code],
moderator_access_code: room_params[:moderator_access_code])
@room.owner = current_user @room.owner = current_user
@room.room_settings = create_room_settings_string(room_params) @room.room_settings = create_room_settings_string(room_params)
@ -109,8 +111,9 @@ class RoomsController < ApplicationController
@shared_room = room_shared_with_user @shared_room = room_shared_with_user
unless @room.owned_by?(current_user) || @shared_room unless @room.owned_by?(current_user) || @shared_room
# Don't allow users to join unless they have a valid access code or the room doesn't have an access code # Don't allow users to join unless they have a valid access code or the room doesn't have an access codes
if @room.access_code && !@room.access_code.empty? && @room.access_code != session[:access_code] valid_access_code = !@room.access_code.present? || @room.access_code == session[:access_code]
if !valid_access_code && !valid_moderator_access_code(session[:moderator_access_code])
return redirect_to room_path(room_uid: params[:room_uid]), flash: { alert: I18n.t("room.access_code_required") } return redirect_to room_path(room_uid: params[:room_uid]), flash: { alert: I18n.t("room.access_code_required") }
end end
@ -203,7 +206,8 @@ class RoomsController < ApplicationController
@room.update_attributes( @room.update_attributes(
name: options[:name], name: options[:name],
room_settings: room_settings_string, room_settings: room_settings_string,
access_code: options[:access_code] access_code: options[:access_code],
moderator_access_code: options[:moderator_access_code]
) )
flash[:success] = I18n.t("room.update_settings_success") flash[:success] = I18n.t("room.update_settings_success")
@ -321,9 +325,16 @@ class RoomsController < ApplicationController
# POST /:room_uid/login # POST /:room_uid/login
def login def login
# use same form for access_code and moderator_access_code
if valid_moderator_access_code(room_params[:access_code])
session[:moderator_access_code] = room_params[:access_code]
else
session[:access_code] = room_params[:access_code] session[:access_code] = room_params[:access_code]
end
flash[:alert] = I18n.t("room.access_code_required") if session[:access_code] != @room.access_code if session[:access_code] != @room.access_code && !valid_moderator_access_code(session[:moderator_access_code])
flash[:alert] = I18n.t("room.access_code_required")
end
redirect_to room_path(@room.uid) redirect_to room_path(@room.uid)
end end
@ -345,7 +356,7 @@ class RoomsController < ApplicationController
def room_params def room_params
params.require(:room).permit(:name, :auto_join, :mute_on_join, :access_code, params.require(:room).permit(:name, :auto_join, :mute_on_join, :access_code,
:require_moderator_approval, :anyone_can_start, :all_join_moderator, :require_moderator_approval, :anyone_can_start, :all_join_moderator,
:recording, :presentation) :recording, :presentation, :moderator_access_code)
end end
# Find the room from the uid. # Find the room from the uid.
@ -412,6 +423,11 @@ class RoomsController < ApplicationController
end end
helper_method :room_limit_exceeded helper_method :room_limit_exceeded
def valid_moderator_access_code(code)
code == @room.moderator_access_code && !@room.moderator_access_code.blank? && moderator_code_allowed?
end
helper_method :valid_moderator_access_code
def record_meeting def record_meeting
# If the require consent setting is checked, then check the room setting, else, set to true # If the require consent setting is checked, then check the room setting, else, set to true
if recording_consent_required? if recording_consent_required?

View File

@ -89,6 +89,14 @@ module AdminsHelper
end end
end end
def moderator_codes_string
if @settings.get_value("Moderator Access Codes") == "true"
I18n.t("administrator.site_settings.moderator_codes.enabled")
else
I18n.t("administrator.site_settings.moderator_codes.disabled")
end
end
def log_level_string def log_level_string
case Rails.logger.level case Rails.logger.level
when 0 when 0

View File

@ -66,6 +66,8 @@ class Setting < ApplicationRecord
Rails.configuration.shared_access_default Rails.configuration.shared_access_default
when "Preupload Presentation" when "Preupload Presentation"
Rails.configuration.preupload_presentation_default Rails.configuration.preupload_presentation_default
when "Moderator Access Codes"
Rails.configuration.moderator_codes_default
when "Room Configuration Mute On Join" when "Room Configuration Mute On Join"
room_config_setting("mute-on-join") room_config_setting("mute-on-join")
when "Room Configuration Require Moderator" when "Room Configuration Require Moderator"

View File

@ -143,6 +143,27 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row mb-2">
<div class="col-12">
<div class="form-group">
<label class="form-label"><%= t("administrator.site_settings.moderator_codes.title") %></label>
<label class="form-label text-muted"><%= t("administrator.site_settings.moderator_codes.info") %></label>
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<%= moderator_codes_string %>
</button>
<div class="dropdown-menu" aria-labelledby="room-auth">
<%= button_to admin_update_settings_path(setting: "Moderator Access Codes", value: "true"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.moderator_codes.enabled") %>
<% end %>
<%= button_to admin_update_settings_path(setting: "Moderator Access Codes", value: "false"), class: "dropdown-item", "data-disable": "" do %>
<%= t("administrator.site_settings.moderator_codes.disabled") %>
<% end %>
</div>
</div>
</div>
</div>
</div>
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<div class="form-group"> <div class="form-group">

View File

@ -0,0 +1,29 @@
<%
# 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/>.
%>
<%= form_for :room, url: login_room_path(@room.uid) do |f| %>
<div class="input-group join-input">
<%= f.text_field :access_code,
required: true,
class: "form-control join-form",
placeholder: access_code_type == 'moderator' ? t("room.enter_the_moderator_access_code") : t("room.enter_the_access_code"),
value: "" ,
autofocus: true,
maxlength: 26 %>
<span class="input-group-append">
<%= f.button t("room.login"), type: :submit, class: "btn btn-primary btn-sm px-7 form-control join-form" %>
</span>
</div>
<% end %>

View File

@ -13,7 +13,7 @@
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. # with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
%> %>
<div data-path="<%= update_settings_path(room) %>" data-room-access-code="<%= room.access_code %>" class="card room-block"> <div data-path="<%= update_settings_path(room) %>" data-room-access-code="<%= room.access_code %>" data-room-moderator-access-code="<%= room.moderator_access_code %>" class="card room-block">
<div class="card-body p-1"> <div class="card-body p-1">
<table class="table table-hover table-vcenter text-wrap table-no-border"> <table class="table table-hover table-vcenter text-wrap table-no-border">
<tbody class="no-border-top"> <tbody class="no-border-top">

View File

@ -15,23 +15,15 @@
<% content_for(:page_desc) { t("room.invitation_description", name: @room.name) } %> <% content_for(:page_desc) { t("room.invitation_description", name: @room.name) } %>
<% valid_access_code = @room.access_code.nil? || @room.access_code.empty? || @room.access_code == session[:access_code] %> <% access_code_set = @room.access_code.present? %>
<%= render 'rooms/components/room_event', render_recordings: valid_access_code do %> <% valid_access_code = access_code_set && @room.access_code == session[:access_code] %>
<% moderator_access_code_set = @room.moderator_access_code.present? && moderator_code_allowed? %>
<% valid_moderator_access_code = valid_moderator_access_code(session[:moderator_access_code]) %>
<%= render 'rooms/components/room_event', render_recordings: valid_access_code || valid_moderator_access_code do %>
<% if room_authentication_required %> <% if room_authentication_required %>
<h2><%= t("administrator.site_settings.authentication.user-info") %></h2> <h2><%= t("administrator.site_settings.authentication.user-info") %></h2>
<% elsif !valid_access_code %> <% elsif valid_moderator_access_code || valid_access_code || !access_code_set %>
<%= form_for :room, url: login_room_path(@room.uid) do |f| %>
<div class="input-group join-input">
<%= f.text_field :access_code,
required: true,
class: "form-control join-form",
placeholder: t("room.enter_the_access_code"),
value: "" ,
autofocus: true %>
<%= f.submit t("room.login"), class: "btn btn-primary btn-sm col-sm-3 form-control join-form" %>
</div>
<% end %>
<% else %>
<%= form_for room_path(@room), method: :post do |f| %> <%= form_for room_path(@room), method: :post do |f| %>
<div class="input-group"> <div class="input-group">
<%= f.hidden_field(:search, :value => params[:search])%> <%= f.hidden_field(:search, :value => params[:search])%>
@ -59,5 +51,12 @@
</label> </label>
<% end %> <% end %>
<% end %> <% end %>
<% if moderator_access_code_set && !valid_moderator_access_code %>
<!-- <hr class="mt-2 float-right w-100 moderator-code-hr"> -->
<label class="moderator-code-label form-label"><%= t("room.optional_moderator_access_code") %></label>
<%= render "rooms/components/enter_access_code_form", access_code_type: 'moderator' %>
<% end %>
<% else %>
<%= render "rooms/components/enter_access_code_form", access_code_type: 'standard_access' %>
<% end %> <% end %>
<% end %> <% end %>

View File

@ -51,7 +51,7 @@
<%= t("copy") %> <%= t("copy") %>
</button> </button>
</div> </div>
<div class="col-sm-6 pl-0 mt-2"> <div class="btn-group-vertical col-sm-6 pl-0 mt-2">
<% if @room.access_code.present? %> <% if @room.access_code.present? %>
<input id="copy-code" value="<%= @room.access_code %>" type="hidden"> <input id="copy-code" value="<%= @room.access_code %>" type="hidden">
<button id="copy-access" class="btn btn-secondary btn-block" onclick="copyAccess()"> <button id="copy-access" class="btn btn-secondary btn-block" onclick="copyAccess()">
@ -59,6 +59,13 @@
<%= t("room.copy_access") %> <%= t("room.copy_access") %>
</button> </button>
<% end %> <% end %>
<% if moderator_code_allowed? && @room.moderator_access_code.present? %>
<input id="copy-moderator-code" value="<%= @room.moderator_access_code %>" type="hidden">
<button id="copy-moderator-access" class="btn btn-secondary btn-block" onclick="copyAccess('moderator')">
<i class="fas fa-copy mr-1"></i>
<%= t("room.copy_moderator_access") %>
</button>
<% end %>
<% if Rails.configuration.enable_google_calendar_button %> <% if Rails.configuration.enable_google_calendar_button %>
<a href="<%= google_calendar_path %>" target="__blank" id="schedule" class="btn btn-primary btn-block mt-2"> <a href="<%= google_calendar_path %>" target="__blank" id="schedule" class="btn btn-primary btn-block mt-2">
<i class="fas fa-calendar-plus"></i> <i class="fas fa-calendar-plus"></i>

View File

@ -43,6 +43,19 @@
</span> </span>
</div> </div>
<% if moderator_code_allowed? %>
<div class="input-icon mb-2">
<span onclick="generateModeratorAccessCode()" class="input-icon-addon allow-icon-click cursor-pointer">
<i class="fas fa-dice"></i>
</span>
<%= f.label :moderator_access_code, t("modal.create_room.moderator_access_code_placeholder"), id: "create-room-moderator-access-code", class: "form-control" %>
<%= f.hidden_field :moderator_access_code %>
<span onclick="ResetModeratorAccessCode()" class="input-icon-addon allow-icon-click cursor-pointer">
<i class="far fa-trash-alt"></i>
</span>
</div>
<% end %>
<% mute = room_configuration("Room Configuration Mute On Join") %> <% mute = room_configuration("Room Configuration Mute On Join") %>
<% if mute != "disabled" %> <% if mute != "disabled" %>
<label class="custom-switch pl-0 mt-3 mb-3 w-100 text-left d-inline-block <%= "enabled-setting" if mute == "enabled" %>"> <label class="custom-switch pl-0 mt-3 mb-3 w-100 text-left d-inline-block <%= "enabled-setting" if mute == "enabled" %>">

View File

@ -175,6 +175,9 @@ module Greenlight
# Don't allow users to preupload presentations by default # Don't allow users to preupload presentations by default
config.preupload_presentation_default = "false" config.preupload_presentation_default = "false"
# Don't show option to generate moderator access codes
config.moderator_codes_default = "false"
# Default admin password # Default admin password
config.admin_password_default = ENV['ADMIN_PASSWORD'] || 'administrator' config.admin_password_default = ENV['ADMIN_PASSWORD'] || 'administrator'
end end

View File

@ -105,6 +105,11 @@ de_DE:
approval: Zulassen/Ablehnen approval: Zulassen/Ablehnen
invite: Teilnahme durch Einladung invite: Teilnahme durch Einladung
open: Offene Registrierung open: Offene Registrierung
moderator_codes:
info: "Mit gültigen Moderatorencodes können Nutzerinnen einem Raum als Moderator beitreten, ohne sich vorher einen Account anzulegen und einzeln Zugriff zu erhalten. Die Einstellung kann für jeden Raum seperat getätigt werden."
title: Ermöglicht die Erstellung von Moderatorencodes
enabled: Aktiviert
disabled: Deaktiviert
rooms: rooms:
info: "Limitiert die Anzahl der Räume, die Nutzer einrichten können (inklusive des Startraums). Diese Einstellung wirkt sich nicht auf Administratoren aus." info: "Limitiert die Anzahl der Räume, die Nutzer einrichten können (inklusive des Startraums). Diese Einstellung wirkt sich nicht auf Administratoren aus."
title: Anzahl der Räume pro Nutzer title: Anzahl der Räume pro Nutzer
@ -390,7 +395,9 @@ de_DE:
title: Neue Rolle erstellen title: Neue Rolle erstellen
create_room: create_room:
access_code: Zugangscode access_code: Zugangscode
moderator_access_code: Moderatorencode
access_code_placeholder: Generieren eines optionalen Raumzugangscodes access_code_placeholder: Generieren eines optionalen Raumzugangscodes
moderator_access_code_placeholder: Generieren eines optionalen Moderatorencodes
auto_join: Automatisch dem Raum beitreten auto_join: Automatisch dem Raum beitreten
create: Raum erstellen create: Raum erstellen
free_delete: Sie können den Raum jederzeit wieder löschen. free_delete: Sie können den Raum jederzeit wieder löschen.
@ -543,6 +550,7 @@ de_DE:
access_code_required: "Bitte geben Sie einen gültigen Zugangscode ein, um den Raum zu betreten" access_code_required: "Bitte geben Sie einen gültigen Zugangscode ein, um den Raum zu betreten"
add_presentation: Präsentation hinzufügen add_presentation: Präsentation hinzufügen
copy_access: Zugangscode kopieren copy_access: Zugangscode kopieren
copy_moderator_access: Moderatorcode kopieren
create_room: Raum erstellen create_room: Raum erstellen
create_room_error: Bei der Erstellung des Raums ist ein Fehler aufgetreten create_room_error: Bei der Erstellung des Raums ist ein Fehler aufgetreten
create_room_success: Raum erfolgreich erstellt create_room_success: Raum erfolgreich erstellt
@ -551,6 +559,8 @@ de_DE:
success: Raum erfolgreich gelöscht success: Raum erfolgreich gelöscht
fail: "Raum konnte nicht gelöscht werden (%{error})" fail: "Raum konnte nicht gelöscht werden (%{error})"
enter_the_access_code: Raumzugangscode bitte eingeben enter_the_access_code: Raumzugangscode bitte eingeben
enter_the_moderator_access_code: "Moderatorencode bitte eingeben!"
optional_moderator_access_code: "Optionaler Moderatorencode:"
invalid_provider: "Sie haben eine ungültige URL eingegeben, bitte überprüfen Sie die URL und versuchen Sie es erneut." invalid_provider: "Sie haben eine ungültige URL eingegeben, bitte überprüfen Sie die URL und versuchen Sie es erneut."
invitation_description: "Sie wurden zu %{name} über BigBlueButton zur Teilnahme eingeladen. Um beizutreten, klicken Sie auf den obigen Link und geben Sie Ihren Namen ein." invitation_description: "Sie wurden zu %{name} über BigBlueButton zur Teilnahme eingeladen. Um beizutreten, klicken Sie auf den obigen Link und geben Sie Ihren Namen ein."
invited: Sie wurden zur Teilnahme eingeladen invited: Sie wurden zur Teilnahme eingeladen

View File

@ -111,6 +111,11 @@ en:
shared_access: shared_access:
info: Setting to disabled will remove the button from the Room options dropdown, preventing users from sharing rooms info: Setting to disabled will remove the button from the Room options dropdown, preventing users from sharing rooms
title: Allow Users to Share Rooms title: Allow Users to Share Rooms
moderator_codes:
info: "With valid moderator codes, users can join a room as a moderator without having to create an account and receive access individually. The setting can be made separately for each room."
title: Enables the generation of moderator codes
enabled: Enabled
disabled: Disabled
subtitle: Customize Greenlight subtitle: Customize Greenlight
tabs: tabs:
appearance: Appearance appearance: Appearance
@ -391,7 +396,9 @@ en:
title: Create New Role title: Create New Role
create_room: create_room:
access_code: Access Code access_code: Access Code
moderator_access_code: Moderator Code
access_code_placeholder: Generate an optional room access code access_code_placeholder: Generate an optional room access code
moderator_access_code_placeholder: Generate an optional code for moderators
auto_join: Automatically join me into the room auto_join: Automatically join me into the room
create: Create Room create: Create Room
free_delete: You will be free to delete this room at any time. free_delete: You will be free to delete this room at any time.
@ -544,6 +551,7 @@ en:
access_code_required: Please enter a valid access code to join the room access_code_required: Please enter a valid access code to join the room
add_presentation: Add Presentation add_presentation: Add Presentation
copy_access: Copy Access Code copy_access: Copy Access Code
copy_moderator_access: Copy Moderator Code
create_room: Create a Room create_room: Create a Room
create_room_error: There was an error creating the room create_room_error: There was an error creating the room
create_room_success: Room created successfully create_room_success: Room created successfully
@ -552,6 +560,8 @@ en:
success: Room deleted successfully success: Room deleted successfully
fail: Failed to delete room (%{error}) fail: Failed to delete room (%{error})
enter_the_access_code: Enter the room's access code enter_the_access_code: Enter the room's access code
enter_the_moderator_access_code: Enter the room's moderator code!
optional_moderator_access_code: "Optional Moderator Code:"
invalid_provider: You have entered an invalid url. Please check the url and try again. invalid_provider: You have entered an invalid url. Please check the url and try again.
invitation_description: You have been invited to join %{name} using BigBlueButton. To join, click the link above and enter your name. invitation_description: You have been invited to join %{name} using BigBlueButton. To join, click the link above and enter your name.
invited: You have been invited to join invited: You have been invited to join

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddModeratorAccessCodeToRooms < ActiveRecord::Migration[5.2]
def change
add_column :rooms, :moderator_access_code, :string, null: true, default: nil
end
end

View File

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2020_12_14_232153) do ActiveRecord::Schema.define(version: 2021_01_08_032132) do
create_table "active_storage_attachments", force: :cascade do |t| create_table "active_storage_attachments", force: :cascade do |t|
t.string "name", null: false t.string "name", null: false
@ -96,6 +96,7 @@ ActiveRecord::Schema.define(version: 2020_12_14_232153) do
t.string "attendee_pw" t.string "attendee_pw"
t.string "access_code" t.string "access_code"
t.boolean "deleted", default: false, null: false t.boolean "deleted", default: false, null: false
t.string "moderator_access_code"
t.index ["bbb_id"], name: "index_rooms_on_bbb_id" t.index ["bbb_id"], name: "index_rooms_on_bbb_id"
t.index ["deleted"], name: "index_rooms_on_deleted" t.index ["deleted"], name: "index_rooms_on_deleted"
t.index ["last_session"], name: "index_rooms_on_last_session" t.index ["last_session"], name: "index_rooms_on_last_session"

View File

@ -273,6 +273,21 @@ describe RoomsController, type: :controller do
expect(response).to redirect_to(join_path(@owner.main_room, "Join Name", {}, response.cookies["guest_id"])) expect(response).to redirect_to(join_path(@owner.main_room, "Join Name", {}, response.cookies["guest_id"]))
end end
it "should use join name if user is not logged in and meeting running and moderator access code is enabled and set" do
allow_any_instance_of(BigBlueButton::BigBlueButtonApi).to receive(:is_meeting_running?).and_return(true)
allow_any_instance_of(Setting).to receive(:get_value).and_call_original
allow_any_instance_of(Setting).to receive(:get_value).with("Moderator Access Codes").and_return("true")
room = Room.new(name: "test", moderator_access_code: "abcdef")
room.room_settings = "{ }"
room.owner = @owner
room.save
post :join, params: { room_uid: room, join_name: "Join Name" }, session: { moderator_access_code: "abcdef" }
expect(response).to redirect_to(join_path(room, "Join Name", { user_is_moderator: true }, response.cookies["guest_id"]))
end
it "should render wait if meeting isn't running" do it "should render wait if meeting isn't running" do
allow_any_instance_of(BigBlueButton::BigBlueButtonApi).to receive(:is_meeting_running?).and_return(false) allow_any_instance_of(BigBlueButton::BigBlueButtonApi).to receive(:is_meeting_running?).and_return(false)
@ -398,6 +413,62 @@ describe RoomsController, type: :controller do
expect(response).to redirect_to room_path(protected_room.uid) expect(response).to redirect_to room_path(protected_room.uid)
end end
it "should join the room as moderator if the user has the moderator_access code (and regular access code is not set)" do
allow_any_instance_of(BigBlueButton::BigBlueButtonApi).to receive(:is_meeting_running?).and_return(true)
allow_any_instance_of(Setting).to receive(:get_value).and_call_original
allow_any_instance_of(Setting).to receive(:get_value).with("Moderator Access Codes").and_return("true")
room = Room.new(name: "test", moderator_access_code: "abcdef")
room.room_settings = "{ }"
room.owner = @owner
room.save
post :join, params: { room_uid: room, join_name: "Join Name" }, session: { moderator_access_code: "abcdef" }
expect(response).to redirect_to(join_path(room, "Join Name", { user_is_moderator: true }, response.cookies["guest_id"]))
end
it "should join the room as moderator if the user has the moderator_access code (and regular access code is set)" do
allow_any_instance_of(BigBlueButton::BigBlueButtonApi).to receive(:is_meeting_running?).and_return(true)
allow_any_instance_of(Setting).to receive(:get_value).and_call_original
allow_any_instance_of(Setting).to receive(:get_value).with("Moderator Access Codes").and_return("true")
room = Room.new(name: "test", access_code: "123456", moderator_access_code: "abcdef")
room.room_settings = "{ }"
room.owner = @owner
room.save
post :join, params: { room_uid: room, join_name: "Join Name" }, session: { moderator_access_code: "abcdef" }
expect(response).to redirect_to(join_path(room, "Join Name", { user_is_moderator: true }, response.cookies["guest_id"]))
end
it "should redirect to login if a wrong moderator access code is supplied" do
allow_any_instance_of(BigBlueButton::BigBlueButtonApi).to receive(:is_meeting_running?).and_return(true)
room = Room.new(name: "test", access_code: "123456", moderator_access_code: "abcdef")
room.room_settings = "{ }"
room.owner = @owner
room.save
post :join, params: { room_uid: room, join_name: "Join Name" }, session: { moderator_access_code: "abcdee" }
expect(response).to redirect_to room_path(room.uid)
end
it "should redirect to login if a 'empty' moderator access code is supplied and moderator code is not set" do
allow_any_instance_of(BigBlueButton::BigBlueButtonApi).to receive(:is_meeting_running?).and_return(true)
room = Room.new(name: "test", access_code: "123456")
room.room_settings = "{ }"
room.owner = @owner
room.save
post :join, params: { room_uid: room, join_name: "Join Name" }, session: { moderator_access_code: nil }
expect(response).to redirect_to room_path(room.uid)
end
it "should join owner as moderator if meeting running" do it "should join owner as moderator if meeting running" do
allow_any_instance_of(BigBlueButton::BigBlueButtonApi).to receive(:is_meeting_running?).and_return(true) allow_any_instance_of(BigBlueButton::BigBlueButtonApi).to receive(:is_meeting_running?).and_return(true)
@ -671,12 +742,49 @@ describe RoomsController, type: :controller do
expect(flash[:alert]).to be_nil expect(flash[:alert]).to be_nil
end end
it "should redirect to show with valid moderator_access_code as regular access_code" do
allow_any_instance_of(Setting).to receive(:get_value).and_call_original
allow_any_instance_of(Setting).to receive(:get_value).with("Moderator Access Codes").and_return("true")
@room.moderator_access_code = "abcdef"
@room.save
post :login, params: { room_uid: @room.uid, room: { access_code: "abcdef" } }
expect(response).to redirect_to room_path(@room.uid)
expect(flash[:alert]).to be_nil
expect(session[:moderator_access_code]).to eq("abcdef")
end
it "should redirect to show with and notify user of invalid access code" do it "should redirect to show with and notify user of invalid access code" do
post :login, params: { room_uid: @room.uid, room: { access_code: "123455" } } post :login, params: { room_uid: @room.uid, room: { access_code: "123455" } }
expect(response).to redirect_to room_path(@room.uid) expect(response).to redirect_to room_path(@room.uid)
expect(flash[:alert]).to eq(I18n.t("room.access_code_required")) expect(flash[:alert]).to eq(I18n.t("room.access_code_required"))
end end
it "should redirect to show and notify user of invalid moderator access code" do
@room.moderator_access_code = "abcdef"
@room.save
post :login, params: { room_uid: @room.uid, room: { moderator_access_code: "abcdee" } }
expect(response).to redirect_to room_path(@room.uid)
expect(flash[:alert]).to eq(I18n.t("room.access_code_required"))
end
it "it should redirect to show with valid moderator access code and disabled moderator codes setting" do
allow_any_instance_of(Setting).to receive(:get_value).and_call_original
allow_any_instance_of(Setting).to receive(:get_value).with("Moderator Access Codes").and_return("false")
@room.moderator_access_code = "abcdef"
@room.save
post :join, params: { room_uid: @room, join_name: "Join Name" }, session: { moderator_access_code: "abcdef" }
expect(response).to redirect_to room_path(@room.uid)
expect(flash[:alert]).to eq(I18n.t("room.access_code_required"))
end
end end
describe "POST join_specific_room" do describe "POST join_specific_room" do