forked from External/greenlight
GRN2-260: Added the ability to merge user accounts (#938)
* Added the ability to merge user accounts * Styling fixes
This commit is contained in:
@ -41,6 +41,49 @@ $(document).on('turbolinks:load', function(){
|
||||
|
||||
updateTabParams(this.id)
|
||||
})
|
||||
|
||||
$('.selectpicker').selectpicker({
|
||||
liveSearchPlaceholder: getLocalizedString('javascript.search.start')
|
||||
});
|
||||
// Fixes turbolinks issue with bootstrap select
|
||||
$(window).trigger('load.bs.select.data-api');
|
||||
|
||||
// Display merge accounts modal with correct info
|
||||
$(".merge-user").click(function() {
|
||||
// Update the path of save button
|
||||
$("#merge-save-access").attr("data-path", $(this).data("path"))
|
||||
|
||||
let userInfo = $(this).data("info")
|
||||
|
||||
$("#merge-to").html("<span>" + userInfo.name + "</span>" + "<span class='text-muted d-block'>" + userInfo.email + "</span>" + "<span class='text-muted d-block'>" + userInfo.uid + "</span>")
|
||||
|
||||
})
|
||||
|
||||
$("#mergeUserModal").on("show.bs.modal", function() {
|
||||
$(".selectpicker").selectpicker('val','')
|
||||
})
|
||||
|
||||
$(".bootstrap-select").on("click", function() {
|
||||
$(".bs-searchbox").siblings().hide()
|
||||
})
|
||||
|
||||
$(".bs-searchbox input").on("input", function() {
|
||||
if ($(".bs-searchbox input").val() == '' || $(".bs-searchbox input").val().length < 3) {
|
||||
$(".bs-searchbox").siblings().hide()
|
||||
} else {
|
||||
$(".bs-searchbox").siblings().show()
|
||||
}
|
||||
})
|
||||
|
||||
// User selects an option from the Room Access dropdown
|
||||
$(".bootstrap-select").on("changed.bs.select", function(){
|
||||
// Get the uid of the selected user
|
||||
let user = $(".selectpicker").selectpicker('val')
|
||||
if (user != "") {
|
||||
userInfo = JSON.parse(user)
|
||||
$("#merge-from").html("<span>" + userInfo.name + "</span>" + "<span class='text-muted d-block'>" + userInfo.email + "</span>" + "<span id='from-uid' class='text-muted d-block'>" + userInfo.uid + "</span>")
|
||||
}
|
||||
})
|
||||
}
|
||||
else if(action == "site_settings"){
|
||||
loadColourSelectors()
|
||||
@ -79,6 +122,11 @@ function changeBrandingImage(path) {
|
||||
$.post(path, {value: url})
|
||||
}
|
||||
|
||||
function mergeUsers() {
|
||||
let userToMerge = $("#from-uid").text()
|
||||
$.post($("#merge-save-access").data("path"), {merge: userToMerge})
|
||||
}
|
||||
|
||||
// Filters by role
|
||||
function filterRole(role) {
|
||||
var search = new URL(location.href).searchParams.get('search')
|
||||
|
@ -69,7 +69,7 @@ $(document).on('turbolinks:load', function(){
|
||||
})
|
||||
|
||||
$('.selectpicker').selectpicker({
|
||||
liveSearchPlaceholder: "Start searching..."
|
||||
liveSearchPlaceholder: getLocalizedString('javascript.search.start')
|
||||
});
|
||||
// Fixes turbolinks issue with bootstrap select
|
||||
$(window).trigger('load.bs.select.data-api');
|
||||
|
@ -88,4 +88,12 @@
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
#merge-account-arrow {
|
||||
position: absolute;
|
||||
top: 47%;
|
||||
right: 47%;
|
||||
z-index: 999;
|
||||
background: white;
|
||||
}
|
@ -24,7 +24,7 @@ class AdminsController < ApplicationController
|
||||
include Rolify
|
||||
include Populator
|
||||
|
||||
manage_users = [:edit_user, :promote, :demote, :ban_user, :unban_user, :approve, :reset]
|
||||
manage_users = [:edit_user, :promote, :demote, :ban_user, :unban_user, :approve, :reset, :merge_user]
|
||||
manage_deleted_users = [:undelete]
|
||||
authorize_resource class: false
|
||||
before_action :find_user, only: manage_users
|
||||
@ -41,6 +41,8 @@ class AdminsController < ApplicationController
|
||||
@role = params[:role] ? Role.find_by(name: params[:role], provider: @user_domain) : nil
|
||||
@tab = params[:tab] || "active"
|
||||
|
||||
@user_list = merge_user_list
|
||||
|
||||
@pagy, @users = pagy(manage_users_list)
|
||||
end
|
||||
|
||||
@ -140,6 +142,45 @@ class AdminsController < ApplicationController
|
||||
|
||||
redirect_to redirect_path, flash: { success: I18n.t("administrator.flash.reset_password") }
|
||||
end
|
||||
|
||||
# POST /admins/merge/:user_uid
|
||||
def merge_user
|
||||
begin
|
||||
# Get uid of user that will be merged into the other account
|
||||
uid_to_merge = params[:merge]
|
||||
logger.info "#{current_user.uid} is attempting to merge #{uid_to_merge} into #{@user.uid}"
|
||||
|
||||
# Check to make sure the 2 users are unique
|
||||
raise "Can not merge the user into themself" if uid_to_merge == @user.uid
|
||||
|
||||
# Find user to merge
|
||||
user_to_merge = User.find_by(uid: uid_to_merge)
|
||||
|
||||
# Move over user's rooms
|
||||
user_to_merge.rooms.each do |room|
|
||||
room.owner = @user
|
||||
|
||||
room.name = "(#{I18n.t('merged')}) #{room.name}"
|
||||
|
||||
room.save!
|
||||
end
|
||||
|
||||
# Reload user to update merge rooms
|
||||
user_to_merge.reload
|
||||
|
||||
# Delete merged user
|
||||
user_to_merge.destroy(true)
|
||||
rescue => e
|
||||
logger.info "Failed to merge #{uid_to_merge} into #{@user.uid}: #{e}"
|
||||
flash[:alert] = I18n.t("administrator.flash.merge_fail")
|
||||
else
|
||||
logger.info "#{current_user.uid} successfully merged #{uid_to_merge} into #{@user.uid}"
|
||||
flash[:success] = I18n.t("administrator.flash.merge_success")
|
||||
end
|
||||
|
||||
redirect_to admins_path
|
||||
end
|
||||
|
||||
# SITE SETTINGS
|
||||
|
||||
# POST /admins/update_settings
|
||||
|
@ -77,7 +77,18 @@ module Populator
|
||||
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)
|
||||
initial_list = User.where.not(uid: current_user.uid)
|
||||
.without_role(:pending)
|
||||
.without_role(:denied)
|
||||
.with_highest_priority_role(roles_can_appear)
|
||||
|
||||
return initial_list unless Rails.configuration.loadbalanced_configuration
|
||||
initial_list.where(provider: @user_domain)
|
||||
end
|
||||
|
||||
# Returns a list of users that can merged into another user
|
||||
def merge_user_list
|
||||
initial_list = User.where.not(uid: current_user.uid).without_role(:super_admin)
|
||||
|
||||
return initial_list unless Rails.configuration.loadbalanced_configuration
|
||||
initial_list.where(provider: @user_domain)
|
||||
|
@ -36,7 +36,7 @@ class Ability
|
||||
|
||||
if highest_role.get_permission("can_manage_users")
|
||||
can [:index, :roles, :edit_user, :promote, :demote, :ban_user, :unban_user,
|
||||
:approve, :invite, :reset, :undelete], :admin
|
||||
:approve, :invite, :reset, :undelete, :merge_user], :admin
|
||||
end
|
||||
|
||||
can [:index, :server_recordings, :server_rooms], :admin if highest_role.get_permission("can_manage_rooms_recordings")
|
||||
|
@ -60,6 +60,11 @@ class Room < ApplicationRecord
|
||||
user.rooms.include?(self)
|
||||
end
|
||||
|
||||
# Determines whether room is a home room
|
||||
def home_room?
|
||||
owner.main_room == self
|
||||
end
|
||||
|
||||
def shared_users
|
||||
User.where(id: shared_access.pluck(:user_id))
|
||||
end
|
||||
|
@ -124,6 +124,9 @@
|
||||
<%= link_to admin_edit_user_path(user_uid: user.uid), class: "dropdown-item" do %>
|
||||
<i class="dropdown-icon fas fa-user-edit"></i> <%= t("administrator.users.settings.edit") %>
|
||||
<% end %>
|
||||
<button class= "merge-user dropdown-item" data-path="<%= merge_user_path(user_uid: user.uid) %>" data-info="<%= user.slice(:name, :email, :uid).to_json %>" data-toggle="modal" data-target="#mergeUserModal">
|
||||
<i class="dropdown-icon fas fa-user-friends"></i> <%= t("administrator.users.settings.merge") %>
|
||||
</button>
|
||||
<%= button_to admin_ban_path(user_uid: user.uid), class: "dropdown-item", "data-disable": "" do %>
|
||||
<i class="dropdown-icon fas fa-lock"></i> <%= t("administrator.users.settings.ban") %>
|
||||
<% end %>
|
||||
@ -157,3 +160,4 @@
|
||||
|
||||
<%= render "shared/modals/invite_user_modal" %>
|
||||
<%= render "shared/modals/delete_account_modal", delete_location: relative_root %>
|
||||
<%= render "shared/modals/merge_user_modal" %>
|
51
app/views/shared/modals/_merge_user_modal.html.erb
Normal file
51
app/views/shared/modals/_merge_user_modal.html.erb
Normal file
@ -0,0 +1,51 @@
|
||||
<%
|
||||
# BigBlueButton open source conferencing system - http://www.bigbluebutton.org/.
|
||||
# Copyright (c) 2018 BigBlueButton Inc. and by respective authors (see below).
|
||||
# This program is free software; you can redistribute it and/or modify it under the
|
||||
# terms of the GNU Lesser General Public License as published by the Free Software
|
||||
# Foundation; either version 3.0 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
# You should have received a copy of the GNU Lesser General Public License along
|
||||
# with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
|
||||
%>
|
||||
|
||||
<div class="modal fade" id="mergeUserModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content text-center">
|
||||
<div class="modal-body">
|
||||
<div class="card-body p-6">
|
||||
<div class="card-title">
|
||||
<h3><%= t("modal.merge_user.title") %></h3>
|
||||
</div>
|
||||
<select class="selectpicker" title="<%= t("modal.share_access.select") %>" data-live-search="true" data-virtual-scroll="true" >
|
||||
<% @user_list.each do |user| %>
|
||||
<option value="<%= { uid: user.uid, email: user.email, name: user.name }.to_json %>" data-subtext="<%= user.email %>" ><%= user.name %></option>
|
||||
<% end %>
|
||||
</select>
|
||||
<div class="mt-5 text-left row">
|
||||
<div class="list-group-item col-6 text-center">
|
||||
<label class="form-label text-primary"><%= t("modal.merge_user.from") %></label>
|
||||
<div id="merge-from"></div>
|
||||
</div>
|
||||
<i id="merge-account-arrow" class="fas fa-2x fa-arrow-circle-right text-primary"></i>
|
||||
<div class="list-group-item col-6 text-center">
|
||||
<label class="form-label text-primary"><%= t("modal.merge_user.to") %></label>
|
||||
<div id="merge-to"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-6">
|
||||
<button id="merge-save-access" class="btn btn-primary btn-block" onclick="mergeUsers()" ><%= t("modal.merge_user.save") %></button>
|
||||
<button class="btn btn-secondary text-primary btn-block" onclick="$('#mergeUserModal').modal('hide')"><%= t("modal.merge_user.cancel") %></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<p><%= t("modal.merge_user.footer") %></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -21,7 +21,7 @@
|
||||
<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" >
|
||||
<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 %>
|
||||
|
Reference in New Issue
Block a user