diff --git a/web/pgadmin/browser/server_groups/__init__.py b/web/pgadmin/browser/server_groups/__init__.py
index 476a4e66..56177263 100644
--- a/web/pgadmin/browser/server_groups/__init__.py
+++ b/web/pgadmin/browser/server_groups/__init__.py
@@ -177,6 +177,17 @@ class ServerGroupView(NodeView):
# if server group id is 1 we won't delete it.
sg = groups.first()
+ shared_servers = Server.query.filter_by(servergroup_id=sg.id,
+ shared=True).all()
+ if shared_servers:
+ return make_json_response(
+ status=417,
+ success=0,
+ errormsg=gettext(
+ 'The specified server group cannot be deleted.'
+ )
+ )
+
if sg.id == gid:
return make_json_response(
status=417,
diff --git a/web/pgadmin/static/js/sqleditor/new_connection_dialog_model.js b/web/pgadmin/static/js/sqleditor/new_connection_dialog_model.js
index de1d0f21..4f282da8 100644
--- a/web/pgadmin/static/js/sqleditor/new_connection_dialog_model.js
+++ b/web/pgadmin/static/js/sqleditor/new_connection_dialog_model.js
@@ -100,352 +100,353 @@ export default function newConnectionDialogModel(response, sgid, sid, handler, c
server_name: server_name,
database_name: database_name,
},
- schema: [{
- id: 'server',
- name: 'server',
- label: gettext('Server'),
- type: 'text',
- editable: true,
- disabled: false,
- select2: {
- allowClear: false,
- width: 'style',
- templateResult: formatNode,
- templateSelection: formatNode,
- },
- events: {
- 'focus select': 'clearInvalid',
- 'keydown :input': 'processTab',
- 'select2:select': 'onSelect',
- 'select2:selecting': 'beforeSelect',
- 'select2:clear': 'onChange',
- },
- transform: function(data) {
- let group_template_options = [];
- for (let key in data) {
- if (data.hasOwnProperty(key)) {
- group_template_options.push({'group': key, 'optval': data[key]});
- }
- }
- return group_template_options;
- },
- control: Backform.Select2Control.extend({
- template: _.template([
- '<% if(label == false) {} else {%>',
- ' ',
- '<% }%>',
- '
',
- ' ',
- ' <% if (helpMessage && helpMessage.length) { %>',
- ' <%=helpMessage%>',
- ' <% } %>',
- '
',
- ].join('\n')),
- beforeSelect: function() {
- var selVal = arguments[0].params.args.data.id;
-
- if(this.field.get('connect') && this.$el.find('option[value="'+selVal+'"]').attr('data-connected') !== 'connected') {
- this.field.get('connect').apply(this, [selVal, this.changeIcon.bind(this)]);
- } else {
- $(this.$sel).trigger('change');
- setTimeout(function(){ this.onChange.apply(this); }.bind(this), 200);
+ schema: [
+ {
+ id: 'server',
+ name: 'server',
+ label: gettext('Server'),
+ type: 'text',
+ editable: true,
+ disabled: false,
+ select2: {
+ allowClear: false,
+ width: 'style',
+ templateResult: formatNode,
+ templateSelection: formatNode,
+ },
+ events: {
+ 'focus select': 'clearInvalid',
+ 'keydown :input': 'processTab',
+ 'select2:select': 'onSelect',
+ 'select2:selecting': 'beforeSelect',
+ 'select2:clear': 'onChange',
+ },
+ transform: function(data) {
+ let group_template_options = [];
+ for (let key in data) {
+ if (data.hasOwnProperty(key)) {
+ group_template_options.push({'group': key, 'optval': data[key]});
+ }
}
+ return group_template_options;
},
- changeIcon: function(data) {
- let span = this.$el.find('.select2-selection .select2-selection__rendered span.wcTabIcon'),
- selSpan = this.$el.find('option:selected');
+ control: Backform.Select2Control.extend({
+ template: _.template([
+ '<% if(label == false) {} else {%>',
+ ' ',
+ '<% }%>',
+ '',
+ ' ',
+ ' <% if (helpMessage && helpMessage.length) { %>',
+ ' <%=helpMessage%>',
+ ' <% } %>',
+ '
',
+ ].join('\n')),
+ beforeSelect: function() {
+ var selVal = arguments[0].params.args.data.id;
- if (span.hasClass('icon-server-not-connected') || span.hasClass('icon-shared-server-not-connected')) {
- let icon = (data.icon) ? data.icon : 'icon-pg';
- span.removeClass('icon-server-not-connected');
- span.addClass(icon);
- span.attr('data-connected', 'connected');
+ if(this.field.get('connect') && this.$el.find('option[value="'+selVal+'"]').attr('data-connected') !== 'connected') {
+ this.field.get('connect').apply(this, [selVal, this.changeIcon.bind(this)]);
+ } else {
+ $(this.$sel).trigger('change');
+ setTimeout(function(){ this.onChange.apply(this); }.bind(this), 200);
+ }
+ },
+ changeIcon: function(data) {
+ let span = this.$el.find('.select2-selection .select2-selection__rendered span.wcTabIcon'),
+ selSpan = this.$el.find('option:selected');
- selSpan.data().image = icon;
- selSpan.attr('data-connected', 'connected');
- alertify.connectServer().destroy();
- this.onChange.apply(this);
- }
- else if (span.hasClass('icon-database-not-connected')) {
- let icon = (data.icon) ? data.icon : 'pg-icon-database';
+ if (span.hasClass('icon-server-not-connected') || span.hasClass('icon-shared-server-not-connected')) {
+ let icon = (data.icon) ? data.icon : 'icon-pg';
+ span.removeClass('icon-server-not-connected');
+ span.addClass(icon);
+ span.attr('data-connected', 'connected');
- span.removeClass('icon-database-not-connected');
- span.addClass(icon);
- span.attr('data-connected', 'connected');
+ selSpan.data().image = icon;
+ selSpan.attr('data-connected', 'connected');
+ alertify.connectServer().destroy();
+ this.onChange.apply(this);
+ }
+ else if (span.hasClass('icon-database-not-connected')) {
+ let icon = (data.icon) ? data.icon : 'pg-icon-database';
- selSpan.removeClass('icon-database-not-connected');
- selSpan.data().image = icon;
- selSpan.attr('data-connected', 'connected');
- alertify.connectServer().destroy();
- this.onChange.apply(this);
- }
- },
- connect: function(self) {
- let local_self = self;
+ span.removeClass('icon-database-not-connected');
+ span.addClass(icon);
+ span.attr('data-connected', 'connected');
- if(alertify.connectServer) {
- delete alertify.connectServer;
- }
+ selSpan.removeClass('icon-database-not-connected');
+ selSpan.data().image = icon;
+ selSpan.attr('data-connected', 'connected');
+ alertify.connectServer().destroy();
+ this.onChange.apply(this);
+ }
+ },
+ connect: function(self) {
+ let local_self = self;
- alertify.dialog('connectServer', function factory() {
- return {
- main: function(
- title, message, server_id, submit_password=true, connect_server=null,
- ) {
- this.set('title', title);
- this.message = message;
- this.server_id = server_id;
- this.submit_password = submit_password;
- this.connect_server = connect_server;
- },
- setup:function() {
- return {
- buttons:[{
- text: gettext('Cancel'), className: 'btn btn-secondary fa fa-times pg-alertify-button',
- key: 27,
- },{
- text: gettext('OK'), key: 13, className: 'btn btn-primary fa fa-check pg-alertify-button',
- }],
- focus: {element: '#password', select: true},
- options: {
- modal: 0, resizable: false, maximizable: false, pinnable: false,
- },
- };
- },
- build:function() {
- },
- prepare:function() {
- this.setContent(this.message);
- },
- callback: function(closeEvent) {
- var loadingDiv = $('#show_filter_progress');
- if (closeEvent.button.text == gettext('OK')) {
- if(this.submit_password) {
- var _url = url_for('sqleditor.connect_server', {'sid': this.server_id});
+ if(alertify.connectServer) {
+ delete alertify.connectServer;
+ }
- loadingDiv.removeClass('d-none');
- $.ajax({
- type: 'POST',
- timeout: 30000,
- url: _url,
- data: $('#frmPassword').serialize(),
- })
- .done(function(res) {
+ alertify.dialog('connectServer', function factory() {
+ return {
+ main: function(
+ title, message, server_id, submit_password=true, connect_server=null,
+ ) {
+ this.set('title', title);
+ this.message = message;
+ this.server_id = server_id;
+ this.submit_password = submit_password;
+ this.connect_server = connect_server;
+ },
+ setup:function() {
+ return {
+ buttons:[{
+ text: gettext('Cancel'), className: 'btn btn-secondary fa fa-times pg-alertify-button',
+ key: 27,
+ },{
+ text: gettext('OK'), key: 13, className: 'btn btn-primary fa fa-check pg-alertify-button',
+ }],
+ focus: {element: '#password', select: true},
+ options: {
+ modal: 0, resizable: false, maximizable: false, pinnable: false,
+ },
+ };
+ },
+ build:function() {
+ },
+ prepare:function() {
+ this.setContent(this.message);
+ },
+ callback: function(closeEvent) {
+ var loadingDiv = $('#show_filter_progress');
+ if (closeEvent.button.text == gettext('OK')) {
+ if(this.submit_password) {
+ var _url = url_for('sqleditor.connect_server', {'sid': this.server_id});
- local_self.model.attributes.database = null;
- local_self.changeIcon(res.data);
- local_self.model.attributes.user = null;
- local_self.model.attributes.role = null;
- Backform.Select2Control.prototype.onChange.apply(local_self, arguments);
- Object.keys(response.server_list).forEach(key => {
- response.server_list[key].forEach(option => {
- if (option.value == local_self.getValueFromDOM()) {
- response.server_name = option.label;
- }
+ loadingDiv.removeClass('d-none');
+ $.ajax({
+ type: 'POST',
+ timeout: 30000,
+ url: _url,
+ data: $('#frmPassword').serialize(),
+ })
+ .done(function(res) {
+
+ local_self.model.attributes.database = null;
+ local_self.changeIcon(res.data);
+ local_self.model.attributes.user = null;
+ local_self.model.attributes.role = null;
+ Backform.Select2Control.prototype.onChange.apply(local_self, arguments);
+ Object.keys(response.server_list).forEach(key => {
+ response.server_list[key].forEach(option => {
+ if (option.value == local_self.getValueFromDOM()) {
+ response.server_name = option.label;
+ }
+ });
});
- });
+ loadingDiv.addClass('d-none');
+ alertify.connectServer().destroy();
+ })
+ .fail(function(xhr) {
+ loadingDiv.addClass('d-none');
+ alertify.connectServer().destroy();
+ alertify.connectServer('Connect to server', xhr.responseJSON.result, local_self.getValueFromDOM());
+ });
+ } else {
+ if(Object.keys(this.connect_server).length > 0) {
+ this.connect_server['password'] = $('#password').val();
+ this.connect_server['is_selected'] = false;
+ handler.gridView.on_change_connection(this.connect_server, conn_self, false);
+ loadingDiv = $('#fetching_data');
loadingDiv.addClass('d-none');
- alertify.connectServer().destroy();
- })
- .fail(function(xhr) {
+ } else {
+ response.password = $('#password').val();
loadingDiv.addClass('d-none');
- alertify.connectServer().destroy();
- alertify.connectServer('Connect to server', xhr.responseJSON.result, local_self.getValueFromDOM());
- });
- } else {
- if(Object.keys(this.connect_server).length > 0) {
- this.connect_server['password'] = $('#password').val();
- this.connect_server['is_selected'] = false;
- handler.gridView.on_change_connection(this.connect_server, conn_self, false);
- loadingDiv = $('#fetching_data');
- loadingDiv.addClass('d-none');
- } else {
- response.password = $('#password').val();
- loadingDiv.addClass('d-none');
+ }
}
- }
- } else {
- local_self.model.attributes.database = null;
- local_self.model.attributes.user = null;
- local_self.model.attributes.role = null;
- Backform.Select2Control.prototype.onChange.apply(local_self, arguments);
- loadingDiv.addClass('d-none');
- alertify.connectServer().destroy();
+ } else {
+ local_self.model.attributes.database = null;
+ local_self.model.attributes.user = null;
+ local_self.model.attributes.role = null;
+ Backform.Select2Control.prototype.onChange.apply(local_self, arguments);
+ loadingDiv.addClass('d-none');
+ alertify.connectServer().destroy();
- }
- closeEvent.close = true;
- },
- };
- });
- },
- render: function() {
- let self = this;
- self.connect(self);
- Object.keys(response.server_list).forEach(key => {
- response.server_list[key].forEach(option => {
- if (option.value == parseInt(sid)) {
- response.server_name = option.label;
- }
+ }
+ closeEvent.close = true;
+ },
+ };
});
- });
- var transform = self.field.get('transform') || self.defaults.transform;
- if (transform && _.isFunction(transform)) {
- self.field.set('options', transform.bind(self, response.server_list));
- } else {
- self.field.set('options', response.server_list);
- }
- return Backform.Select2Control.prototype.render.apply(self, arguments);
- },
- onChange: function() {
- this.model.attributes.database = null;
- this.model.attributes.user = null;
- let self = this;
- self.connect(self);
-
- let url = url_for('sqleditor.connect_server', {
- 'sid': self.getValueFromDOM(),
- 'usr': self.model.attributes.user,
- });
- var loadingDiv = $('#show_filter_progress');
- loadingDiv.removeClass('d-none');
- $.ajax({
- url: url,
- type: 'POST',
- headers: {
- 'Cache-Control' : 'no-cache',
- },
- }).done(function () {
- Backform.Select2Control.prototype.onChange.apply(self, arguments);
+ },
+ render: function() {
+ let self = this;
+ self.connect(self);
Object.keys(response.server_list).forEach(key => {
response.server_list[key].forEach(option => {
- if (option.value == self.getValueFromDOM()) {
+ if (option.value == parseInt(sid)) {
response.server_name = option.label;
}
});
});
- loadingDiv.addClass('d-none');
- }).fail(function(xhr){
- loadingDiv.addClass('d-none');
- alertify.connectServer('Connect to server', xhr.responseJSON.result, self.getValueFromDOM());
- });
-
- },
- }),
- },
- {
- id: 'database',
- name: 'database',
- label: gettext('Database'),
- type: 'text',
- editable: true,
- disabled: function(m) {
- let self_local = this;
- if (!_.isUndefined(m.get('server')) && !_.isNull(m.get('server'))
- && m.get('server') !== '') {
- setTimeout(function() {
- if(self_local.options.length) {
- m.set('database', self_local.options[0].value);
+ var transform = self.field.get('transform') || self.defaults.transform;
+ if (transform && _.isFunction(transform)) {
+ self.field.set('options', transform.bind(self, response.server_list));
+ } else {
+ self.field.set('options', response.server_list);
}
- }, 10);
- return false;
- }
+ return Backform.Select2Control.prototype.render.apply(self, arguments);
+ },
+ onChange: function() {
+ this.model.attributes.database = null;
+ this.model.attributes.user = null;
+ let self = this;
+ self.connect(self);
- return true;
- },
- deps: ['server'],
- url: 'sqleditor.get_new_connection_database',
- select2: {
- allowClear: false,
- width: '100%',
- first_empty: true,
- select_first: false,
- },
- extraClasses:['new-connection-dialog-style'],
- control: NewConnectionSelect2Control,
- transform: function(data) {
- response.database_list = data;
- return data;
- },
- },
- {
- id: 'user',
- name: 'user',
- label: gettext('User'),
- type: 'text',
- editable: true,
- deps: ['server'],
- select2: {
- allowClear: false,
- width: '100%',
+ let url = url_for('sqleditor.connect_server', {
+ 'sid': self.getValueFromDOM(),
+ 'usr': self.model.attributes.user,
+ });
+ var loadingDiv = $('#show_filter_progress');
+ loadingDiv.removeClass('d-none');
+ $.ajax({
+ url: url,
+ type: 'POST',
+ headers: {
+ 'Cache-Control' : 'no-cache',
+ },
+ }).done(function () {
+ Backform.Select2Control.prototype.onChange.apply(self, arguments);
+ Object.keys(response.server_list).forEach(key => {
+ response.server_list[key].forEach(option => {
+ if (option.value == self.getValueFromDOM()) {
+ response.server_name = option.label;
+ }
+ });
+ });
+ loadingDiv.addClass('d-none');
+ }).fail(function(xhr){
+ loadingDiv.addClass('d-none');
+ alertify.connectServer('Connect to server', xhr.responseJSON.result, self.getValueFromDOM());
+ });
+
+ },
+ }),
},
- control: NewConnectionSelect2Control,
- url: 'sqleditor.get_new_connection_user',
- disabled: function(m) {
- let self_local = this;
- if (!_.isUndefined(m.get('server')) && !_.isNull(m.get('server'))
+ {
+ id: 'database',
+ name: 'database',
+ label: gettext('Database'),
+ type: 'text',
+ editable: true,
+ disabled: function(m) {
+ let self_local = this;
+ if (!_.isUndefined(m.get('server')) && !_.isNull(m.get('server'))
&& m.get('server') !== '') {
- setTimeout(function() {
- if(self_local.options.length) {
- m.set('user', self_local.options[0].value);
- }
- }, 10);
- return false;
- }
- return true;
+ setTimeout(function() {
+ if(self_local.options.length) {
+ m.set('database', self_local.options[0].value);
+ }
+ }, 10);
+ return false;
+ }
+
+ return true;
+ },
+ deps: ['server'],
+ url: 'sqleditor.get_new_connection_database',
+ select2: {
+ allowClear: false,
+ width: '100%',
+ first_empty: true,
+ select_first: false,
+ },
+ extraClasses:['new-connection-dialog-style'],
+ control: NewConnectionSelect2Control,
+ transform: function(data) {
+ response.database_list = data;
+ return data;
+ },
},
- },{
- id: 'role',
- name: 'role',
- label: gettext('Role'),
- type: 'text',
- editable: true,
- deps: ['server'],
- select2: {
- allowClear: false,
- width: '100%',
- first_empty: true,
+ {
+ id: 'user',
+ name: 'user',
+ label: gettext('User'),
+ type: 'text',
+ editable: true,
+ deps: ['server'],
+ select2: {
+ allowClear: false,
+ width: '100%',
+ },
+ control: NewConnectionSelect2Control,
+ url: 'sqleditor.get_new_connection_user',
+ disabled: function(m) {
+ let self_local = this;
+ if (!_.isUndefined(m.get('server')) && !_.isNull(m.get('server'))
+ && m.get('server') !== '') {
+ setTimeout(function() {
+ if(self_local.options.length) {
+ m.set('user', self_local.options[0].value);
+ }
+ }, 10);
+ return false;
+ }
+ return true;
+ },
+ },{
+ id: 'role',
+ name: 'role',
+ label: gettext('Role'),
+ type: 'text',
+ editable: true,
+ deps: ['server'],
+ select2: {
+ allowClear: false,
+ width: '100%',
+ first_empty: true,
+ },
+ control: NewConnectionSelect2Control,
+ url: 'sqleditor.get_new_connection_role',
+ disabled: false,
},
- control: NewConnectionSelect2Control,
- url: 'sqleditor.get_new_connection_role',
- disabled: false,
- },
],
validate: function() {
let msg = null;
diff --git a/web/pgadmin/tools/user_management/__init__.py b/web/pgadmin/tools/user_management/__init__.py
index ce280a3d..f202f898 100644
--- a/web/pgadmin/tools/user_management/__init__.py
+++ b/web/pgadmin/tools/user_management/__init__.py
@@ -28,7 +28,7 @@ from pgadmin.utils.constants import MIMETYPE_APP_JS, INTERNAL,\
SUPPORTED_AUTH_SOURCES, KERBEROS
from pgadmin.utils.validation_utils import validate_email
from pgadmin.model import db, Role, User, UserPreference, Server, \
- ServerGroup, Process, Setting
+ ServerGroup, Process, Setting, roles_users, SharedServer
# set template path for sql scripts
MODULE_NAME = 'user_management'
@@ -78,7 +78,9 @@ class UserManagementModule(PgAdminModule):
'user_management.update_user', 'user_management.delete_user',
'user_management.create_user', 'user_management.users',
'user_management.user', current_app.login_manager.login_view,
- 'user_management.auth_sources', 'user_management.auth_sources'
+ 'user_management.auth_sources', 'user_management.auth_sources',
+ 'user_management.shared_servers', 'user_management.admin_users',
+ 'user_management.change_owner',
]
@@ -336,6 +338,8 @@ def delete(uid):
abort(404)
try:
+ server_groups = ServerGroup.query.filter_by(user_id=uid).all()
+ sg = [server_group.id for server_group in server_groups]
Setting.query.filter_by(user_id=uid).delete()
@@ -346,6 +350,11 @@ def delete(uid):
ServerGroup.query.filter_by(user_id=uid).delete()
Process.query.filter_by(user_id=uid).delete()
+ # Delete Shared servers for current user.
+ SharedServer.query.filter_by(user_id=uid).delete()
+
+ SharedServer.query.filter(SharedServer.servergroup_id.in_(sg)).delete(
+ synchronize_session=False)
# Finally delete user
db.session.delete(usr)
@@ -361,6 +370,174 @@ def delete(uid):
return internal_server_error(errormsg=str(e))
+@blueprint.route('/change_owner', methods=['POST'], endpoint='change_owner')
+@roles_required('Administrator')
+def change_owner():
+ """
+
+ Returns:
+
+ """
+
+ data = request.form if request.form else json.loads(
+ request.data, encoding='utf-8'
+ )
+ try:
+ old_user_servers = Server.query.filter_by(shared=True, user_id=data[
+ 'old_owner']).all()
+ server_group_ids = [server.servergroup_id for server in
+ old_user_servers]
+ server_groups = ServerGroup.query.filter(
+ ServerGroup.id.in_(server_group_ids)).all()
+
+ new_owner_sg = ServerGroup.query.filter_by(
+ user_id=data['new_owner']).all()
+ old_owner_sg = ServerGroup.query.filter_by(
+ user_id=data['old_owner']).all()
+ sg_data = {sg.name: sg.id for sg in new_owner_sg}
+ old_sg_data = {sg.id: sg.name for sg in old_owner_sg}
+
+ deleted_sg = []
+ # Change server user.
+ for server in old_user_servers:
+ if old_sg_data[server.servergroup_id] in sg_data:
+ sh_servers = SharedServer.query.filter_by(
+ servergroup_id=server.servergroup_id).all()
+ for sh in sh_servers:
+ sh.servergroup_id = sg_data[
+ old_sg_data[server.servergroup_id]]
+ # Update Server user and server group to prevent deleting
+ # shared server associated with deleting user.
+ Server.query.filter_by(
+ servergroup_id=server.servergroup_id, shared=True,
+ user_id=data['old_owner']
+ ).update(
+ {
+ 'servergroup_id': sg_data[old_sg_data[
+ server.servergroup_id]],
+ 'user_id': data['new_owner']
+ }
+ )
+ ServerGroup.query.filter_by(id=server.servergroup_id).delete()
+ deleted_sg.append(server.servergroup_id)
+ else:
+ server.user_id = data['new_owner']
+
+ # Change server group user.
+ for server_group in server_groups:
+ if server_group.id not in deleted_sg:
+ server_group.user_id = data['new_owner']
+
+ db.session.commit()
+ # Delete old owner records.
+ delete(data['old_owner'])
+
+ return make_json_response(
+ success=1,
+ info=_("Owner changed successfully."),
+ data={}
+ )
+ except Exception as e:
+ return internal_server_error(
+ errormsg='Unable to update shared server owner')
+
+
+@blueprint.route(
+ '/shared_servers/', methods=['GET'], endpoint='shared_servers'
+)
+@roles_required('Administrator')
+def get_shared_servers(uid):
+ """
+
+ Args:
+ uid:
+
+ Returns:
+
+ """
+ usr = User.query.get(uid)
+
+ if not usr:
+ abort(404)
+
+ try:
+ shared_servers_count = 0
+ admin_role = Role.query.filter_by(name='Administrator')[0]
+ # Check user has admin role.
+ for role in usr.roles:
+ if role.id == admin_role.id:
+ # get all server created by user.
+ servers = Server.query.filter_by(user_id=usr.id).all()
+ for server in servers:
+ if server.shared:
+ shared_servers_count += 1
+ break
+
+ if shared_servers_count:
+ return make_json_response(
+ success=1,
+ info=_(
+ "{0} Shared servers are associated with this user."
+ "".format(shared_servers_count)
+ ),
+ data={
+ 'shared_servers': shared_servers_count
+ }
+ )
+
+ return make_json_response(
+ success=1,
+ info=_("No shared servers found"),
+ data={'shared_servers': 0}
+ )
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
+
+# @blueprint.route(
+# '/admin_users', methods=['GET'], endpoint='admin_users'
+# )
+@blueprint.route(
+ '/admin_users/', methods=['GET'], endpoint='admin_users'
+)
+@roles_required('Administrator')
+def admin_users(uid=None):
+ """
+
+ Args:
+ uid:
+
+ Returns:
+
+ """
+ admin_role = Role.query.filter_by(name='Administrator')[0]
+
+ admin_users = db.session.query(roles_users).filter_by(
+ role_id=admin_role.id).all()
+
+ if uid:
+ admin_users = [user[0] for user in admin_users if user[0] != uid]
+ else:
+ admin_users = [user[0] for user in admin_users]
+
+ admin_list = User.query.filter(User.id.in_(admin_users)).all()
+
+ user_list = [{'value': admin.id, 'label': admin.username} for admin in
+ admin_list]
+
+ return make_json_response(
+ success=1,
+ info=_("No shared servers found"),
+ data={
+ 'status': 'success',
+ 'msg': 'Admin user list',
+ 'result': {
+ 'data': user_list,
+ }
+ }
+ )
+
+
@blueprint.route('/user/', methods=['PUT'], endpoint='update_user')
@roles_required('Administrator')
def update(uid):
diff --git a/web/pgadmin/tools/user_management/static/js/user_management.js b/web/pgadmin/tools/user_management/static/js/user_management.js
index c3aca881..531c8c59 100644
--- a/web/pgadmin/tools/user_management/static/js/user_management.js
+++ b/web/pgadmin/tools/user_management/static/js/user_management.js
@@ -604,7 +604,223 @@ define([
}),
gridSchema = Backform.generateGridColumnsFromModel(
null, UserModel, 'edit'),
+
+
deleteUserCell = Backgrid.Extension.DeleteCell.extend({
+ changeOwnership: function(res, uid) {
+ let self = this;
+
+ let ownershipSelect2Control = Backform.Select2Control.extend({
+ fetchData: function(){
+ let self = this;
+ let url = self.field.get('url');
+
+ url = url_for(url, {'uid': uid});
+
+ $.ajax({
+ url: url,
+ headers: {
+ 'Cache-Control' : 'no-cache',
+ },
+ }).done(function (res) {
+ var transform = self.field.get('transform');
+ if(res.data.status){
+ let data = res.data.result.data;
+
+ if (transform && _.isFunction(transform)) {
+ self.field.set('options', transform.bind(self, data));
+ } else {
+ self.field.set('options', data);
+ }
+ } else {
+ if (transform && _.isFunction(transform)) {
+ self.field.set('options', transform.bind(self, []));
+ } else {
+ self.field.set('options', []);
+ }
+ }
+ Backform.Select2Control.prototype.render.apply(self, arguments);
+ }).fail(function(e){
+ let msg = '';
+ if(e.status == 404) {
+ msg = 'Unable to find url.';
+ } else {
+ msg = e.responseJSON.errormsg;
+ }
+ alertify.error(msg);
+ });
+ },
+ render: function() {
+ this.fetchData();
+ return Backform.Select2Control.prototype.render.apply(this, arguments);
+ },
+ onChange: function() {
+ Backform.Select2Control.prototype.onChange.apply(this, arguments);
+ },
+ });
+
+ let ownershipModel = pgBrowser.DataModel.extend({
+ schema: [
+ {
+ id: 'note_text_ch_owner',
+ control: Backform.NoteControl,
+ text: 'Select the user that will take ownership of the shared servers created by ' + self.model.get('username') + '. ' + res['data'].shared_servers + ' shared servers are currently owned by this user.',
+ group: gettext('General'),
+ },
+ {
+ id: 'user',
+ name: 'user',
+ label: gettext('User'),
+ type: 'text',
+ editable: true,
+ select2: {
+ allowClear: true,
+ width: '100%',
+ first_empty: true,
+ },
+ control: ownershipSelect2Control,
+ url: 'user_management.admin_users',
+ helpMessage: gettext('Note: If no user is selected, the shared servers will be deleted.'),
+ }],
+ });
+ // Change shared server ownership before deleting the admin user
+ if (!alertify.changeOwnershipDialog) {
+ alertify.dialog('changeOwnershipDialog', function factory() {
+ let $container = $('');
+ return {
+ main: function(message) {
+ this.msg = message;
+ },
+ build: function() {
+ this.elements.content.appendChild($container.get(0));
+ alertify.pgDialogBuild.apply(this);
+ },
+ setup: function(){
+ return {
+ buttons: [
+ {
+ text: gettext('Cancel'),
+ key: 27,
+ className: 'btn btn-secondary fa fa-times pg-alertify-button',
+ 'data-btn-name': 'cancel',
+ }, {
+ text: gettext('OK'),
+ key: 13,
+ className: 'btn btn-primary fa fa-check pg-alertify-button',
+ 'data-btn-name': 'ok',
+ },
+ ],
+ // Set options for dialog
+ options: {
+ title: 'Change ownership',
+ //disable both padding and overflow control.
+ padding: !1,
+ overflow: !1,
+ model: 0,
+ resizable: true,
+ maximizable: false,
+ pinnable: false,
+ closableByDimmer: false,
+ modal: false,
+ autoReset: false,
+ closable: true,
+ },
+ };
+ },
+ prepare: function() {
+ let self = this;
+ $container.html('');
+
+ self.ownershipModel = new ownershipModel();
+ let fields = pgBackform.generateViewSchema(null, self.ownershipModel, 'create', null, null, true, null);
+
+ let view = this.view = new pgBackform.Dialog({
+ el: '',
+ model: self.ownershipModel,
+ schema: fields,
+ });
+ //Render change ownership dialog.
+ $container.append(view.render().$el[0]);
+ },
+ callback: function(e) {
+ if(e.button['data-btn-name'] === 'ok') {
+ e.cancel = true; // Do not close dialog
+ let ownershipModel = this.ownershipModel.toJSON();
+ if (ownershipModel.user == '' || ownershipModel.user == undefined) {
+ alertify.confirm(
+ gettext('Delete user?'),
+ gettext('The shared servers owned by '+ self.model.get('username') +' will be deleted. Do you wish to continue?'),
+ function() {
+
+ self.model.destroy({
+ wait: true,
+ success: function() {
+ alertify.success(gettext('User deleted.'));
+ alertify.changeOwnershipDialog().destroy();
+ alertify.UserManagement().destroy();
+ },
+ error: function() {
+ alertify.error(
+ gettext('Error during deleting user.')
+ );
+ },
+ });
+ alertify.changeOwnershipDialog().destroy();
+ },
+ function() {
+ return true;
+ }
+ );
+ } else {
+ self.changeOwner(ownershipModel.user, uid);
+ }
+ } else {
+ alertify.changeOwnershipDialog().destroy();
+ }
+ },
+ };
+ });
+ }
+ alertify.changeOwnershipDialog('Change ownership').resizeTo(pgBrowser.stdW.md, pgBrowser.stdH.md);
+ },
+ changeOwner: function(user_id, old_user) {
+ $.ajax({
+ url: url_for('user_management.change_owner'),
+ method: 'POST',
+ data:{'new_owner': user_id, 'old_owner': old_user},
+ })
+ .done(function(res) {
+ alertify.changeOwnershipDialog().destroy();
+ alertify.UserManagement().destroy();
+ alertify.success(gettext(res.info));
+ })
+ .fail(function() {
+ alertify.error(gettext('Unable to change owner.'));
+ });
+ },
+ deleteUser: function() {
+ let self = this;
+ alertify.confirm(
+ gettext('Delete user?'),
+ gettext('Are you sure you wish to delete this user?'),
+ function() {
+ self.model.destroy({
+ wait: true,
+ success: function() {
+ alertify.success(gettext('User deleted.'));
+ },
+ error: function() {
+ alertify.error(
+ gettext('Error during deleting user.')
+ );
+ },
+ });
+ },
+ function() {
+ return true;
+ }
+ );
+ },
deleteRow: function(e) {
var self = this;
e.preventDefault();
@@ -629,26 +845,27 @@ define([
if (self.model.isNew()) {
self.model.destroy();
} else {
- alertify.confirm(
- gettext('Delete user?'),
- gettext('Are you sure you wish to delete this user?'),
- function() {
- self.model.destroy({
- wait: true,
- success: function() {
- alertify.success(gettext('User deleted.'));
- },
- error: function() {
- alertify.error(
- gettext('Error during deleting user.')
- );
- },
+ if(self.model.get('role') == 1){
+ $.ajax({
+ url: url_for('user_management.shared_servers', {'uid': self.model.get('id'),
+ }),
+ method: 'GET',
+ async: false,
+ })
+ .done(function(res) {
+ if(res['data'].shared_servers > 0) {
+ self.changeOwnership(res, self.model.get('id'));
+ } else {
+ self.deleteUser();
+ }
+ })
+ .fail(function() {
+ self.deleteUser();
});
- },
- function() {
- return true;
- }
- );
+ } else {
+ self.deleteUser();
+ }
+
}
} else {
alertify.alert(