GRN2-176: Create a role editor that allows admins to specify what permissions each role has (#709)

* Add roles editor

* Add colour selection ability to roles

* Add ability to assign roles to users in the UI

* Remove rolify and replace it with our own custom roles implemenation

* - Fix all existing roles functionality
- Fix super admins

* Fix bugs with new customers not have default roles

* Add can't create room setting

* Code improvements

* Fix migration

* Add tests for new methods

* Translate reserved role names

* Pull roles from saml/ldap

* Fix rspec

* Fix scrutinizer issues

* Fix email promoted/demoted tests

* Apply comments

* Redirect directly to the main room

* Add comments
This commit is contained in:
shawn-higgins1
2019-07-31 11:53:32 -04:00
committed by Jesus Federico
parent 02b342b157
commit 4fc1714db8
56 changed files with 1713 additions and 328 deletions

View File

@ -14,13 +14,24 @@
%>
<div class="list-group list-group-transparent mb-0">
<%= link_to admins_path, class: "list-group-item list-group-item-action dropdown-item #{"active" if active_page == "index"}" do %>
<span class="icon mr-3"><i class="fas fa-users"></i></span><%= t("administrator.users.title") %>
<% highest_role = current_user.highest_priority_role %>
<% highest_role.name %>
<% if highest_role.can_manage_users || highest_role.name == "super_admin" %>
<%= link_to admins_path, class: "list-group-item list-group-item-action dropdown-item #{"active" if active_page == "index"}" do %>
<span class="icon mr-3"><i class="fas fa-users"></i></span><%= t("administrator.users.title") %>
<% end %>
<% end %>
<%= link_to admin_site_settings_path, class: "list-group-item list-group-item-action dropdown-item #{"active" if active_page == "site_settings"}" do %>
<span class="icon mr-4"><i class="fas fa-cogs"></i></span><%= t("administrator.site_settings.title") %>
<% if highest_role.can_edit_site_settings || highest_role.name == "super_admin" %>
<%= link_to admin_recordings_path, class: "list-group-item list-group-item-action dropdown-item #{"active" if active_page == "server_recordings"}" do %>
<span class="icon mr-4"><i class="fas fa-video"></i></i></span><%= t("administrator.recordings.title") %>
<% end %>
<%= link_to admin_site_settings_path, class: "list-group-item list-group-item-action dropdown-item #{"active" if active_page == "site_settings"}" do %>
<span class="icon mr-4"><i class="fas fa-cogs"></i></span><%= t("administrator.site_settings.title") %>
<% end %>
<% end %>
<%= link_to admin_recordings_path, class: "list-group-item list-group-item-action dropdown-item #{"active" if active_page == "server_recordings"}" do %>
<span class="icon mr-4"><i class="fas fa-video"></i></i></span><%= t("administrator.recordings.title") %>
<% if highest_role.can_edit_roles || highest_role.name == "super_admin" %>
<%= link_to admin_roles_path, class: "list-group-item list-group-item-action dropdown-item #{"active" if active_page == "roles"}" do %>
<span class="icon mr-4"><i class="fas fa-user-tag"></i></i></span><%= t("administrator.roles.title") %>
<% end %>
<% end %>
</div>

View File

@ -0,0 +1,94 @@
<%
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
# Copyright (c) 2018 BigBlueButton Inc. and by respective authors (see below).
# This program is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free Software
# Foundation; either version 3.0 of the License, or (at your option) any later
# version.
#
# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License along
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
%>
<div class="container">
<div class="row">
<div class="col-lg-3 mb-4">
<div class="list-group list-group-transparent mb-0">
<div id="rolesSelect" data-url="<%= admin_roles_order_path %>">
<% @roles.each do |role| %>
<%= link_to admin_roles_path(selected_role: role.id),
class: "#{"sort-disabled" if role.name == "user" || role.name == "admin" || role.priority <= current_user.highest_priority_role.priority } dropdown-item list-group-item list-group-item-action #{"active" if @selected_role.id == role.id}",
id: dom_id(role) do %>
<%= translated_role_name(role) %>
<% end %>
<% end %>
</div>
<%= link_to "#", id: "newRoleButton", class: "list-group-item list-group-item-action", "data-toggle" => "modal", "data-target" => '#createRoleModal' do %>
<span class="icon mr-4"><i class="fas fa-plus-circle"></i></span><%= t("administrator.roles.new_role") %>
<% end %>
</div>
</div>
<div class="col-lg-9 <%="form-disable" if edit_disabled %>">
<%= form_for(@selected_role, url: admin_update_role_path(@selected_role.id), method: :post) do |f| %>
<%= f.label t('administrator.roles.name'), class: "form-label" %>
<%= f.text_field :name, class: 'form-control mb-3', value: translated_role_name(@selected_role), readonly: edit_disabled || @selected_role.name == "user" || @selected_role.name == "admin", required: true %>
<%= f.hidden_field :colour, id: "role-colour", value: role_colour(@selected_role) %>
<div class="form-group">
<label class="form-label"><%= t("administrator.roles.colour.title") %></label>
<label class="form-label text-muted"><%= t("administrator.roles.colour.info") %></label>
<div class="color-inputs">
<div id="role-colorinput-regular" class="btn role-colour-picker" data-disabled="<%= edit_disabled %>" data-colour="<%= role_colour(@selected_role) %>">
<%= t("administrator.site_settings.color.regular") %>
</div>
</div>
</div>
<label class="custom-switch pl-0 mt-3 mb-3 w-100 text-left d-inline-block">
<span class="ml-0 custom-switch-description"><%= t("administrator.roles.can_create_rooms")%></span>
<%= f.check_box :can_create_rooms, class: "custom-switch-input", disabled: edit_disabled %>
<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">
<span class="ml-0 custom-switch-description"><%= t("administrator.roles.promote_email")%></span>
<%= f.check_box :send_promoted_email, class: "custom-switch-input", disabled: edit_disabled %>
<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">
<span class="ml-0 custom-switch-description"><%= t("administrator.roles.demote_email")%></span>
<%= f.check_box :send_demoted_email, class: "custom-switch-input", disabled: edit_disabled %>
<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">
<span class="ml-0 custom-switch-description"><%= t("administrator.roles.edit_site_settings")%></span>
<%= f.check_box :can_edit_site_settings, class: "custom-switch-input", disabled: edit_disabled %>
<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">
<span class="ml-0 custom-switch-description"><%= t("administrator.roles.edit_roles")%></span>
<%= f.check_box :can_edit_roles, class: "custom-switch-input", disabled: edit_disabled %>
<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">
<span class="ml-0 custom-switch-description"><%= t("administrator.roles.manage_users")%></span>
<%= f.check_box :can_manage_users, class: "custom-switch-input", disabled: edit_disabled %>
<span class="custom-switch-indicator float-right"></span>
</label>
<div class="mt-4">
<%= f.submit t("update"), class: "btn btn-primary float-right ml-2 mb-2", disabled: edit_disabled %>
<% if @selected_role.name != "user" && @selected_role.name != "admin" && !edit_disabled %>
<%= link_to admin_delete_role_path(@selected_role.id), method: :delete, class: "float-right btn btn-danger" do %>
<%= t("administrator.roles.delete") %>
<% end %>
<% end %>
</div>
<% end %>
</div>
</div>
</div>
<%= render "shared/modals/create_role_modal" %>

View File

@ -28,7 +28,7 @@
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
%>
<% if @role.present? %>
<% unless @role.nil? %>
<%= render "shared/components/admins_tags" %>
<% end %>
@ -88,7 +88,7 @@
<td><%= user.provider %></td>
<td class="text-center">
<% roles = user.roles().pluck(:name) %>
<%= render "shared/components/admins_role", roles: roles %>
<%= render "shared/components/admins_role", role: user.highest_priority_role %>
</td>
<td>
<% if roles.include?("pending") %>
@ -122,16 +122,6 @@
<button class= "delete-user dropdown-item" data-toggle="modal" data-target="#deleteAccountModal">
<i class="dropdown-icon fas fa-user-minus"></i> <%= t("administrator.users.settings.delete") %>
</button>
<% if roles.include?("admin") %>
<%= button_to admin_demote_path(user_uid: user.uid), class: "dropdown-item" do %>
<i class="dropdown-icon fas fa-level-down-alt"></i> <%= t("administrator.users.settings.demote") %>
<% end %>
<% elsif roles.include?("user") %>
<%= button_to admin_promote_path(user_uid: user.uid), class: "dropdown-item" do %>
<i class="dropdown-icon fas fa-level-up-alt"></i> <%= t("administrator.users.settings.promote") %>
<% end %>
<% end %>
<%= button_to admin_ban_path(user_uid: user.uid), class: "dropdown-item" do %>
<i class="dropdown-icon fas fa-lock"></i> <%= t("administrator.users.settings.ban") %>
<% end %>

View File

@ -0,0 +1,27 @@
<%
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
# Copyright (c) 2018 BigBlueButton Inc. and by respective authors (see below).
# This program is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free Software
# Foundation; either version 3.0 of the License, or (at your option) any later
# version.
#
# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License along
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
%>
<div class="container pt-6">
<%= render "shared/components/subtitle", subtitle: t("administrator.title"), search: false %>
<div class="row">
<div class="col-lg-3 mb-4">
<%= render "admins/components/menu_buttons" %>
</div>
<div class="col-lg-9">
<%= render "admins/components/setting_view", setting_id: "roles", setting_title: t("administrator.roles.title"), search: false %>
</div>
</div>
</div>

View File

@ -0,0 +1,44 @@
<%
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
# Copyright (c) 2018 BigBlueButton Inc. and by respective authors (see below).
# This program is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free Software
# Foundation; either version 3.0 of the License, or (at your option) any later
# version.
#
# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License along
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
%>
<div id="cant-create-room-wrapper" class="background h-100 cant-create-room-wrapper">
<div class="container h-100">
<div class="row h-100 align-items-center">
<div class="offset-3 col-6 offset-3">
<div class="card">
<div class="card-status bg-primary"></div>
<div class="card-header">
<h3 class="card-title"><%= t("room.no_room.title") %></h3>
</div>
<div class="card-body">
<%= form_for(:join_room, url: join_room_path) do |f| %>
<div class="input-icon mb-2">
<span class="input-icon-addon">
<i class="fas fa-link"></i>
</span>
<%= f.text_field :url, class: "form-control", value: "", placeholder: t("room.no_room.placeholder"), required: "" %>
</div>
<div class="mt-4">
<%= f.submit t("room.join"), class:"btn btn-primary btn-block" %>
</div>
<% end %>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -23,7 +23,7 @@
<div class="d-flex ml-auto">
<% if current_user %>
<% if current_user.has_cached_role? :super_admin %>
<% if current_user.has_role? :super_admin %>
<% admins_page = params[:controller] == "admins" && params[:action] == "index" ? "active" : "" %>
<%= link_to admins_path, class: "px-3 mx-1 mt-1 header-nav #{admins_page}" do %>
<i class="fas fa-home pr-1 "></i> <%= t("header.dropdown.home") %>
@ -34,9 +34,11 @@
<i class="fas fa-home pr-1 "></i> <%= t("header.dropdown.home") %>
<% end %>
<% all_rec_page = params[:controller] == "users" && params[:action] == "recordings" ? "active" : "" %>
<%= link_to get_user_recordings_path(current_user), class: "px-3 mx-1 mt-1 header-nav #{all_rec_page}" do %>
<i class="fas fa-video pr-1"></i> <%= t("header.all_recordings") %>
<% if current_user.highest_priority_role.can_create_rooms %>
<% all_rec_page = params[:controller] == "users" && params[:action] == "recordings" ? "active" : "" %>
<%= link_to get_user_recordings_path(current_user), class: "px-3 mx-1 mt-1 header-nav #{all_rec_page}" do %>
<i class="fas fa-video pr-1"></i> <%= t("header.all_recordings") %>
<% end %>
<% end %>
<% end %>
@ -56,10 +58,19 @@
<%= link_to edit_user_path(current_user), class: "dropdown-item" do %>
<i class="dropdown-icon fas fa-id-card mr-3"></i><%= t("header.dropdown.settings") %>
<% end %>
<% if current_user.has_cached_role? :admin %>
<% highest_role = current_user.highest_priority_role %>
<% if highest_role.can_manage_users || highest_role.name == "super_admin" %>
<%= link_to admins_path, class: "dropdown-item" do %>
<i class="dropdown-icon fas fa-user-tie mr-3"></i><%= t("header.dropdown.account_settings") %>
<% end %>
<% elsif highest_role.can_edit_site_settings %>
<%= link_to admin_site_settings_path, class: "dropdown-item" do %>
<i class="dropdown-icon fas fa-user-tie mr-3"></i><%= t("header.dropdown.account_settings") %>
<% end %>
<% elsif highest_role.can_edit_roles%>
<%= link_to admin_roles_path, class: "dropdown-item" do %>
<i class="dropdown-icon fas fa-user-tie mr-3"></i><%= t("header.dropdown.account_settings") %>
<% end %>
<% end %>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="http://docs.bigbluebutton.org/install/greenlight-v2.html" target="_blank">

View File

@ -13,24 +13,6 @@
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
%>
<% if roles.include?("denied")%>
<button class="user-role btn btn-sm btn-gray-dark" onclick="filterRole('denied')">
<%= t("roles.banned") %>
</button>
<% elsif roles.include?("pending") %>
<button class="user-role btn btn-sm btn-cyan" onclick="filterRole('pending')">
<%= t("roles.pending") %>
</button>
<% elsif roles.include?("super_admin") %>
<button class="user-role btn btn-sm btn-red" onclick="filterRole('super_admin')">
<%= t("roles.super_admin") %>
</button>
<% elsif roles.include?("admin") %>
<button class="user-role btn btn-sm btn-yellow" onclick="filterRole('admin')">
<%= t("roles.administrator") %>
</button>
<% else %>
<button class="user-role btn btn-sm btn-gray" onclick="filterRole('user')">
<%= t("roles.user") %>
</button>
<% end %>
<button style="<%= "background-color: #{role_colour(role)};border-color: #{role_colour(role)}" %>" class="user-role btn btn-sm" onclick="filterRole('<%= role.name %>')">
<%= translated_role_name(role) %>
</button>

View File

@ -16,42 +16,12 @@
<div class="form-group">
<div class="row">
<div class="col-12 tags">
<% if @role == "denied"%>
<span class="tag tag-gray-dark">
<%= t("roles.banned") %>
<a class="tag-addon clear-role">
<i class="fas fa-times"></i>
</a>
</span>
<% elsif @role == "pending" %>
<span class="tag tag-cyan">
<%= t("roles.pending") %>
<a class="tag-addon clear-role">
<i class="fas fa-times"></i>
</a>
</span>
<% elsif @role == "super_admin" %>
<span class="tag tag-red">
<%= t("roles.super_admin") %>
<a class="tag-addon clear-role">
<i class="fas fa-times"></i>
</a>
</span>
<% elsif @role == "admin" %>
<span class="tag tag-yellow">
<%= t("roles.administrator") %>
<a class="tag-addon clear-role">
<i class="fas fa-times"></i>
</a>
</span>
<% else %>
<span class="tag tag-gray">
<%= t("roles.user") %>
<a class="tag-addon clear-role">
<i class="fas fa-times"></i>
</a>
</span>
<% end %>
<span style="<%= "background-color: #{role_colour(@role)};border-color: #{role_colour(@role)};" %>" class="tag custom-role-tag">
<%= translated_role_name(@role) %>
<a class="tag-addon clear-role">
<i class="fas fa-times"></i>
</a>
</span>
</div>
</div>
</div>

View File

@ -0,0 +1,44 @@
<%
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
# Copyright (c) 2018 BigBlueButton Inc. and by respective authors (see below).
# This program is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free Software
# Foundation; either version 3.0 of the License, or (at your option) any later
# version.
#
# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License along
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
%>
<div class="modal fade" id="createRoleModal" 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.create_role.title") %></h3>
</div>
<%= form_for(:role, url: admin_new_role_path) do |f| %>
<div class="input-icon mb-2">
<span class="input-icon-addon">
<i class="fas fa-user-tag"></i>
</span>
<%= f.text_field :name, id: "createRoleName", class: "form-control text-center", placeholder: t("modal.create_role.name_placeholder"), autocomplete: :off, required: true %>
<div class="invalid-feedback text-left"><%= t("modal.create_role.not_blank") %></div>
</div>
<div class="mt-4">
<%= f.submit t("modal.create_role.create"), class: "btn btn-primary btn-block" %>
</div>
<% end %>
</div>
<div class="card-footer">
<p><%= t("modal.create_role.footer_text") %></p>
</div>
</div>
</div>
</div>
</div>

View File

@ -38,6 +38,28 @@
<%= f.label t("settings.account.language"), class: "form-label" %>
<%= f.select :language, language_options, {}, { class: "form-control custom-select" } %>
<% current_user_role = current_user.highest_priority_role %>
<br>
<br>
<%= f.label t("settings.account.roles"), class: "form-label" %>
<div id="role-tag-container" class="tags mb-1">
<% @user.roles.by_priority.each do |role| %>
<span id="<%= "user-role-tag_#{role.id}" %>" style="<%= "background-color: #{role_colour(role)};border-color: #{role_colour(role)};" %>" class="tag user-role-tag">
<%= translated_role_name(role) %>
<% if (current_user_role.can_edit_roles || current_user_role.name == "super_admin") && (role.priority > current_user_role.priority || current_user_role.name == "admin") %>
<a data-role-id="<%= role.id %>" class="tag-addon clear-role">
<i data-role-id="<%= role.id %>" class="fas fa-times"></i>
</a>
<% end %>
</span>
<% end %>
</div>
<% if current_user_role.can_edit_roles || current_user_role.name == "super_admin" %>
<% provider = Rails.configuration.loadbalanced_configuration ? current_user.provider : "greenlight" %>
<%= f.select :roles, Role.editable_roles(@user_domain).map{|role| [translated_role_name(role), role.id, {'data-colour' => role_colour(role)}]}.unshift(["", nil, {'data-colour' => nil}]), {disabled: disabled_roles(@user)}, { class: "form-control custom-select", id: "role-select-dropdown" } %>
<% end %>
<%= f.hidden_field :role_ids, id: "user_role_ids", value: @user.roles.by_priority.pluck(:id) %>
<%= f.label t("settings.account.image"), class: "form-label mt-5" %>
<div class="row">
<div class="col-2">

View File

@ -21,11 +21,11 @@
<%= image_tag(@image, height: '70') %>
<h1 style="margin-bottom:30px">
<%= t('mailer.user.demoted.subtitle') %>
<%= t('mailer.user.demoted.subtitle', role: @role) %>
</h1>
<p>
<%= t('mailer.user.demoted.info', url: @url) %>
<%= t('mailer.user.demoted.info', url: @url, role: @role) %>
</p>
<p style="margin-bottom:45px;">

View File

@ -17,9 +17,9 @@
%>
<%= t('mailer.user.demoted.subtitle') %>
<%= t('mailer.user.demoted.subtitle', role: @role) %>
<%= t('mailer.user.demoted.info', url: @url) %>
<%= t('mailer.user.demoted.info', url: @url, role: @role) %>
<%= t('mailer.user.demoted.more-info') %>

View File

@ -21,15 +21,15 @@
<%= image_tag(@image, height: '70') %>
<h1 style="margin-bottom:30px">
<%= t('mailer.user.promoted.subtitle') %>
<%= t('mailer.user.promoted.subtitle', role: @role) %>
</h1>
<p>
<%= t('mailer.user.promoted.info', url: @url) %>
<%= t('mailer.user.promoted.info', url: @url, role: @role) %>
</p>
<p style="margin-bottom:45px;">
<%= t('mailer.user.promoted.more-info') %>
<%= t('mailer.user.promoted.more-info', url: @url) %>
</p>
<a style="background: <%= @color %>;color: #ffffff; padding: 10px 15px; box-shadow: 0 2px 4px 0 rgba(0,0,0,.25);border: 1px solid transparent;text-decoration:none;" href="<%= @admin_url %>">

View File

@ -17,10 +17,10 @@
%>
<%= t('mailer.user.promoted.subtitle') %>
<%= t('mailer.user.promoted.subtitle', role: @role) %>
<%= t('mailer.user.promoted.info', url: @url) %>
<%= t('mailer.user.promoted.info', url: @url, role: @role) %>
<%= t('mailer.user.promoted.more-info') %>
<%= t('mailer.user.promoted.more-info', url: @url) %>
<%= @admin_url %>