diff --git a/app/assets/javascripts/admins.js b/app/assets/javascripts/admins.js
index 13a64baf..53fcfb57 100644
--- a/app/assets/javascripts/admins.js
+++ b/app/assets/javascripts/admins.js
@@ -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("" + userInfo.name + "" + "" + userInfo.email + "" + "" + userInfo.uid + "")
+
+ })
+
+ $("#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("" + userInfo.name + "" + "" + userInfo.email + "" + "" + userInfo.uid + "")
+ }
+ })
}
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')
diff --git a/app/assets/javascripts/room.js b/app/assets/javascripts/room.js
index 4b762e04..79e8652a 100644
--- a/app/assets/javascripts/room.js
+++ b/app/assets/javascripts/room.js
@@ -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');
diff --git a/app/assets/stylesheets/admins.scss b/app/assets/stylesheets/admins.scss
index 2265448d..3e872d74 100644
--- a/app/assets/stylesheets/admins.scss
+++ b/app/assets/stylesheets/admins.scss
@@ -88,4 +88,12 @@
&:hover {
cursor: pointer;
}
+}
+
+#merge-account-arrow {
+ position: absolute;
+ top: 47%;
+ right: 47%;
+ z-index: 999;
+ background: white;
}
\ No newline at end of file
diff --git a/app/controllers/admins_controller.rb b/app/controllers/admins_controller.rb
index 3dc7ba32..37de5067 100644
--- a/app/controllers/admins_controller.rb
+++ b/app/controllers/admins_controller.rb
@@ -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
diff --git a/app/controllers/concerns/populator.rb b/app/controllers/concerns/populator.rb
index 20974a5a..970fe0ee 100644
--- a/app/controllers/concerns/populator.rb
+++ b/app/controllers/concerns/populator.rb
@@ -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)
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 714d5a45..541d6940 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -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")
diff --git a/app/models/room.rb b/app/models/room.rb
index a5bc17a3..b7354694 100644
--- a/app/models/room.rb
+++ b/app/models/room.rb
@@ -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
diff --git a/app/views/admins/components/_users.html.erb b/app/views/admins/components/_users.html.erb
index 74383a07..8d46812e 100644
--- a/app/views/admins/components/_users.html.erb
+++ b/app/views/admins/components/_users.html.erb
@@ -124,6 +124,9 @@
<%= link_to admin_edit_user_path(user_uid: user.uid), class: "dropdown-item" do %>
<%= t("administrator.users.settings.edit") %>
<% end %>
+
<%= button_to admin_ban_path(user_uid: user.uid), class: "dropdown-item", "data-disable": "" do %>
<%= 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" %>
\ No newline at end of file
diff --git a/app/views/shared/modals/_merge_user_modal.html.erb b/app/views/shared/modals/_merge_user_modal.html.erb
new file mode 100644
index 00000000..e5c74bbc
--- /dev/null
+++ b/app/views/shared/modals/_merge_user_modal.html.erb
@@ -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