public inbox for [email protected]
help / color / mirror / Atom feedFrom: Nikhil Mohite <[email protected]>
To: Akshay Joshi <[email protected]>
Cc: pgadmin-hackers <[email protected]>
Subject: Re: [pgAdmin][RM3794]:Allow User to Change Database Connection from an Open Query Tool Tab
Date: Mon, 28 Sep 2020 11:20:11 +0530
Message-ID: <CAOBg0AOHJT4wUC3AXjHV2aorF8_OpP3erah8yhyi2eKwn6F_Sg@mail.gmail.com> (raw)
In-Reply-To: <CANxoLDdUj_RKgQWFE6F7noEJbDz+P_3-njnn2mf10TSa0V9wdw@mail.gmail.com>
References: <CAOBg0AM=b7hfJjTJAXu=wGkKHEsV_zoZpSO-QU6Z-G9p2wVF0w@mail.gmail.com>
<CANxoLDdUj_RKgQWFE6F7noEJbDz+P_3-njnn2mf10TSa0V9wdw@mail.gmail.com>
Hi Akshay,
I have resolved all the review comments and also updated the test cases as
per the new implementation.
PFA updated patch.
On Mon, Sep 21, 2020 at 5:24 PM Akshay Joshi <[email protected]>
wrote:
> Hi Nikhil
>
> Following are the initial review comments:
>
> - Open View/Edit data on any table and click on the same database
> connection and then click on the Execute button. Got "get_primary_keys()
> takes 1 positional argument but 2 were given" error.
> - In my opinion, we should hide the option to change the database
> connection for View/Edit Data.
> - If the user clicks on the same database connection multiple times
> then no need to change the backend connection and transaction id. Add
> validation at the backend, no action required in this case.
> - The role option is missing from the "connect to server" dialog.
> - The Password field should not be there on the "connect to server"
> dialog. Sometimes we saved the password so asking a password every time is
> not correct. Check the pgAdmin 3 behavior.
>
> Code review still remains.
>
> On Thu, Sep 17, 2020 at 4:15 PM Nikhil Mohite <
> [email protected]> wrote:
>
>> Hi Team,
>>
>> Regarding RM-3794 <https://redmine.postgresql.org/issues/3794; allow
>> the user to change the database connection from an open query tool:
>> I have implemented the feature and also added documentation for it.
>>
>> PFA patch.
>>
>> --
>> *Thanks & Regards,*
>> *Nikhil Mohite*
>> *Software Engineer.*
>> *EDB Postgres* <https://www.enterprisedb.com/;
>> *Mob.No: +91-7798364578.*
>>
>
>
> --
> *Thanks & Regards*
> *Akshay Joshi*
> *pgAdmin Hacker | Sr. Software Architect*
> *EDB Postgres <http://edbpostgres.com>*
>
> *Mobile: +91 976-788-8246*
>
Attachments:
[application/octet-stream] RM_3794_V2.patch (220.0K, 3-RM_3794_V2.patch)
download | inline diff:
diff --git a/docs/en_US/images/new_connection_dialog.png b/docs/en_US/images/new_connection_dialog.png
new file mode 100644
index 0000000000000000000000000000000000000000..8cf7ae6aa750360ae7710af61bf8e89f9d520284
GIT binary patch
literal 49691
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	%0^c>O%*OkVmcSQwgzI6WP2m3$pEbze=t&
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
NIVmN{VsYb-{|8bOF{}Up
literal 0
HcmV?d00001
diff --git a/docs/en_US/images/new_connection_options.png b/docs/en_US/images/new_connection_options.png
new file mode 100644
index 0000000000000000000000000000000000000000..7ca94374baf0eb9a8a0e49cbd9d4d426895ff9d0
GIT binary patch
literal 45739
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
literal 0
HcmV?d00001
diff --git a/docs/en_US/query_tool.rst b/docs/en_US/query_tool.rst
index 83933f0..80f27a5 100644
--- a/docs/en_US/query_tool.rst
+++ b/docs/en_US/query_tool.rst
@@ -300,3 +300,24 @@ transaction status by clicking on the status icon in the Query Tool:
.. image:: images/query_tool_connection_status.png
:alt: Query tool connection and transaction statuses
:align: center
+
+Change connection
+*****************
+
+User can connect to another server or database from existing open session of query tool.
+
+* Click on the connection link next to connection status.
+* Now click on the *<New Connection>* option from the dropdown.
+
+.. image:: images/new_connection_options.png
+ :alt: Query tool connection options
+ :align: center
+
+* Now select server, database, user, and role to connect and click OK.
+
+.. image:: images/new_connection_dialog.png
+ :alt: Query tool connection dialog
+ :align: center
+
+* A newly created connection will now get listed in the options.
+* To connect, select the newly created connection from the dropdown list.
diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/utils.py b/web/pgadmin/browser/server_groups/servers/roles/tests/utils.py
index 3a7ee58..028ee64 100644
--- a/web/pgadmin/browser/server_groups/servers/roles/tests/utils.py
+++ b/web/pgadmin/browser/server_groups/servers/roles/tests/utils.py
@@ -152,3 +152,38 @@ def delete_role(connection, role_names):
exception = "Error while deleting role: %s: line:%s %s" % (
file_name, sys.exc_traceback.tb_lineno, exception)
print(exception, file=sys.stderr)
+
+
+def create_role_with_password(server, role_name, role_password):
+ """
+ This function create the role.
+ :param server:
+ :param role_name:
+ :param role_password:
+ :return:
+ """
+ try:
+ connection = utils.get_db_connection(server['db'],
+ server['username'],
+ server['db_password'],
+ server['host'],
+ server['port'],
+ server['sslmode'])
+ pg_cursor = connection.cursor()
+ pg_cursor.execute(
+ "CREATE ROLE %s LOGIN PASSWORD '%s'" % (role_name, role_password))
+ connection.commit()
+ # Get 'oid' from newly created tablespace
+ pg_cursor.execute(
+ "SELECT pr.oid from pg_catalog.pg_roles pr WHERE pr.rolname='%s'" %
+ role_name)
+ oid = pg_cursor.fetchone()
+ role_id = ''
+ if oid:
+ role_id = oid[0]
+ connection.close()
+ return role_id
+ except Exception as exception:
+ exception = "Error while deleting role: %s: line:%s %s" % (
+ file_name, sys.exc_traceback.tb_lineno, exception)
+ print(exception, file=sys.stderr)
diff --git a/web/pgadmin/model/__init__.py b/web/pgadmin/model/__init__.py
index b33adc0..d24a350 100644
--- a/web/pgadmin/model/__init__.py
+++ b/web/pgadmin/model/__init__.py
@@ -94,6 +94,15 @@ class ServerGroup(db.Model):
name = db.Column(db.String(128), nullable=False)
__table_args__ = (db.UniqueConstraint('user_id', 'name'),)
+ @property
+ def serialize(self):
+ """Return object data in easily serializable format"""
+ return {
+ 'id': self.id,
+ 'user_id': self.user_id,
+ 'name': self.name,
+ }
+
class Server(db.Model):
"""Define a registered Postgres server"""
@@ -175,6 +184,44 @@ class Server(db.Model):
tunnel_password = db.Column(db.String(64), nullable=True)
shared = db.Column(db.Boolean(), nullable=False)
+ @property
+ def serialize(self):
+ """Return object data in easily serializable format"""
+ return {
+ "id": self.id,
+ "user_id": self.user_id,
+ "servergroup_id": self.servergroup_id,
+ "name": self.name,
+ "host": self.host,
+ "hostaddr": self.hostaddr,
+ "port": self.port,
+ "maintenance_db": self.maintenance_db,
+ "username": self.username,
+ "password": self.password,
+ "save_password": self.save_password,
+ "role": self.role,
+ "ssl_mode": self.ssl_mode,
+ "comment": self.comment,
+ "discovery_id": self.discovery_id,
+ "db_res": self.db_res,
+ "passfile": self.passfile,
+ "sslcert": self.sslcert,
+ "sslkey": self.sslkey,
+ "sslrootcert": self.sslrootcert,
+ "sslcrl": self.sslcrl,
+ "sslcompression": self.sslcompression,
+ "bgcolor": self.bgcolor,
+ "fgcolor": self.fgcolor,
+ "service": self.service,
+ "connect_timeout": self.connect_timeout,
+ "use_ssh_tunnel": self.use_ssh_tunnel,
+ "tunnel_host": self.tunnel_host,
+ "tunnel_port": self.tunnel_port,
+ "tunnel_authentication": self.tunnel_authentication,
+ "tunnel_identity_file": self.tunnel_identity_file,
+ "tunnel_password": self.tunnel_password
+ }
+
class ModulePreference(db.Model):
"""Define a preferences table for any modules."""
diff --git a/web/pgadmin/static/js/sqleditor/new_connection_dialog.js b/web/pgadmin/static/js/sqleditor/new_connection_dialog.js
new file mode 100644
index 0000000..dc1c064
--- /dev/null
+++ b/web/pgadmin/static/js/sqleditor/new_connection_dialog.js
@@ -0,0 +1,262 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2020, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import gettext from 'sources/gettext';
+import url_for from 'sources/url_for';
+import $ from 'jquery';
+import Alertify from 'pgadmin.alertifyjs';
+import pgAdmin from 'sources/pgadmin';
+import Backform from 'pgadmin.backform';
+import newConnectionDialogModel from 'sources/sqleditor/new_connection_dialog_model';
+
+
+let NewConnectionDialog = {
+ 'dialog': function(handler, reconnect) {
+ let url = url_for('sqleditor.get_new_connection_data', {
+ 'sid': handler.url_params.sid,
+ 'sgid': handler.url_params.sgid,
+ });
+
+ if(reconnect) {
+ url += '?connect=1';
+ }
+
+ let title = gettext('Connect to server');
+
+ $.ajax({
+ url: url,
+ headers: {
+ 'Cache-Control' : 'no-cache',
+ },
+ }).done(function (res) {
+ let response = res.data.result;
+ response.database_list = [];
+ response.user_list = [];
+ if (Alertify.newConnectionDialog) {
+ delete Alertify.newConnectionDialog;
+ }
+
+ // Create Dialog
+ Alertify.dialog('newConnectionDialog', function factory() {
+ let $container = $('<div class=\'new-connection-dialog\'></div>');
+ 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: '',
+ key: 112,
+ className: 'btn btn-primary-icon pull-left fa fa-question pg-alertify-icon-button',
+ attrs: {
+ name: 'dialog_help',
+ type: 'button',
+ label: gettext('Help'),
+ 'aria-label': gettext('Help'),
+ url: url_for('help.static', {
+ 'filename': 'query_tool.html',
+ }),
+ },
+ },
+ {
+ 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: title,
+ //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('');
+ // Disable Ok button
+ this.__internal.buttons[2].element.disabled = true;
+
+ // Status bar
+ this.statusBar = $(
+ '<div class=\'pg-prop-status-bar pg-el-xs-12 d-none\'>' +
+ ' <div class="error-in-footer"> ' +
+ ' <div class="d-flex px-2 py-1"> ' +
+ ' <div class="pr-2"> ' +
+ ' <i class="fa fa-exclamation-triangle text-danger" aria-hidden="true"></i> ' +
+ ' </div> ' +
+ ' <div class="alert-text" role="alert"></div> ' +
+ ' </div> ' +
+ ' </div> ' +
+ '</div>').appendTo($container);
+
+ // To show progress on filter Saving/Updating on AJAX
+ this.showNewConnectionProgress = $(
+ `<div id="show_filter_progress" class="pg-sp-container sql-editor-busy-fetching d-none">
+ <div class="pg-sp-content">
+ <div class="row"><div class="col-12 pg-sp-icon sql-editor-busy-icon"></div></div>
+ <div class="row"><div class="col-12 pg-sp-text sql-editor-busy-text">` + gettext('Loading data...') + `</div></div>
+ </div>
+ </div>`
+ ).appendTo($container);
+ $(
+ self.showNewConnectionProgress[0]
+ ).removeClass('d-none');
+
+ self.newConnCollectionModel = newConnectionDialogModel(response, handler.url_params.sgid, handler.url_params.sid);
+ let fields = Backform.generateViewSchema(null, self.newConnCollectionModel, 'create', null, null, true);
+
+ let view = this.view = new Backform.Dialog({
+ el: '<div></div>',
+ model: self.newConnCollectionModel,
+ schema: fields,
+ });
+
+ $(this.elements.body.childNodes[0]).addClass(
+ 'alertify_tools_dialog_properties obj_properties'
+ );
+
+ $container.append(view.render().$el);
+
+ // Enable/disable save button and show/hide statusbar based on session
+ view.listenTo(view.model, 'pgadmin-session:start', function() {
+ view.listenTo(view.model, 'pgadmin-session:invalid', function(msg) {
+ self.statusBar.removeClass('d-none');
+ $(self.statusBar.find('.alert-text')).html(msg);
+ // Disable Okay button
+ self.__internal.buttons[2].element.disabled = true;
+ });
+
+ view.listenTo(view.model, 'pgadmin-session:valid', function() {
+ self.statusBar.addClass('d-none');
+ $(self.statusBar.find('.alert-text')).html('');
+ // Enable Okay button
+ self.__internal.buttons[2].element.disabled = false;
+ });
+ });
+
+ view.listenTo(view.model, 'pgadmin-session:stop', function() {
+ view.stopListening(view.model, 'pgadmin-session:invalid');
+ view.stopListening(view.model, 'pgadmin-session:valid');
+ });
+
+ // Starts monitoring changes to model
+ view.model.startNewSession();
+
+ // Hide Progress ...
+ $(
+ self.showNewConnectionProgress[0]
+ ).addClass('d-none');
+ },
+ callback: function(e) {
+ let self = this;
+ if (e.button.element.name == 'dialog_help') {
+ e.cancel = true;
+ pgAdmin.Browser.showHelp(e.button.element.name, e.button.element.getAttribute('url'),
+ null, null);
+ return;
+ } else if (e.button['data-btn-name'] === 'ok') {
+ e.cancel = true; // Do not close dialog
+ let newConnCollectionModel = this.newConnCollectionModel.toJSON();
+
+ let selected_database_name = null;
+ response.database_list.forEach(function(data){
+ if(newConnCollectionModel['database'] == data['value']) {
+ selected_database_name = data['label'];
+ return false;
+ }
+ });
+ let title = '';
+ if(newConnCollectionModel['role']) {
+ title = selected_database_name + '/' + newConnCollectionModel['role'] + '@' + response.server_name;
+ } else {
+ title = selected_database_name + '/' + newConnCollectionModel['user'] + '@' + response.server_name;
+ newConnCollectionModel['role'] = null;
+ }
+
+ let is_create_connection = true;
+
+ handler.gridView.connection_list.forEach(function(connection_data){
+ if(parseInt(connection_data['server']) == newConnCollectionModel['server']
+ && parseInt(connection_data['database']) == newConnCollectionModel['database']
+ && connection_data['user'] == newConnCollectionModel['user'] && connection_data['role'] == newConnCollectionModel['role']) {
+ is_create_connection = false;
+ // break for loop by return false.
+ return false;
+ }
+
+ if(title == connection_data['title']) {
+ is_create_connection = false;
+ return false;
+ }
+ });
+ if(!is_create_connection) {
+ let errmsg = 'Connection with this configuration already present.';
+ Alertify.info(errmsg);
+ }else {
+ let connection_details = {
+ 'server_group': handler.gridView.handler.url_params.sgid,
+ 'server': newConnCollectionModel['server'],
+ 'database': newConnCollectionModel['database'],
+ 'title': title,
+ 'user': newConnCollectionModel['user'],
+ 'role': newConnCollectionModel['role'],
+ 'password': response.password,
+ };
+ handler.gridView.on_change_connection(connection_details, self);
+ }
+ } else {
+ self.close();
+ }
+ },
+ };
+ });
+ setTimeout(function(){
+ Alertify.newConnectionDialog('Connect to server.').resizeTo(pgAdmin.Browser.stdW.md,pgAdmin.Browser.stdH.md);
+ }, 500);
+ }).fail(function(error) {
+ Alertify.alert().setting({
+ 'title': gettext('Connection lost'),
+ 'label':gettext('Ok'),
+ 'message': gettext('Connection to the server has been lost.'),
+ 'onok': function(){
+ alert(error);
+ //Close the window after connection is lost
+ window.close();
+ },
+ }).show();
+ });
+
+ },
+
+};
+
+module.exports = NewConnectionDialog;
diff --git a/web/pgadmin/static/js/sqleditor/new_connection_dialog_model.js b/web/pgadmin/static/js/sqleditor/new_connection_dialog_model.js
new file mode 100644
index 0000000..1cba6e6
--- /dev/null
+++ b/web/pgadmin/static/js/sqleditor/new_connection_dialog_model.js
@@ -0,0 +1,339 @@
+/////////////////////////////////////////////////////////////
+//
+// pgAdmin 4 - PostgreSQL Tools
+//
+// Copyright (C) 2013 - 2020, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+//////////////////////////////////////////////////////////////
+
+import gettext from 'sources/gettext';
+import _ from 'underscore';
+import $ from 'jquery';
+import pgAdmin from 'sources/pgadmin';
+import Backform from 'pgadmin.backform';
+import url_for from 'sources/url_for';
+import alertify from 'pgadmin.alertifyjs';
+
+export default function newConnectionDialogModel(response, sgid, sid) {
+
+ let server_name = '';
+ let database_name = '';
+
+ let NewConnectionSelect2Control = Backform.Select2Control.extend({
+ fetchData: function(){
+ let self = this;
+ url = self.field.get('url');
+
+ let url = url_for(url, {
+ 'sid': self.model.attributes.server,
+ 'sgid': sgid,
+ });
+
+ $.ajax({
+ async: false,
+ 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', []);
+ }
+ //alertify.error(res.data.msg);
+ }
+ }).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 newConnectionModel = pgAdmin.Browser.DataModel.extend({
+ idAttribute: 'name',
+ defaults: {
+ server: parseInt(sid),
+ database: null,
+ user: null,
+ password: null,
+ 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,
+ },
+ control: Backform.Select2Control.extend({
+ connect: function(self) {
+ /*if (alertify.connectServer) {
+ delete alertify.connectServer;
+ }*/
+ if(!alertify.connectServer){
+ alertify.dialog('connectServer', function factory() {
+ return {
+ main: function(
+ title, message, sid, submit_password=true
+ ) {
+ this.set('title', title);
+ this.message = message;
+ this.server_id = sid;
+ this.submit_password = submit_password;
+ },
+ 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) {
+
+ if (closeEvent.button.text == gettext('OK')) {
+ if(this.submit_password) {
+ var _url = url_for('schema_diff.connect_server', {'sid': this.server_id});
+
+ $.ajax({
+ type: 'POST',
+ timeout: 30000,
+ url: _url,
+ data: $('#frmPassword').serialize(),
+ })
+ .done(function() {
+ self.model.attributes.database = null;
+ self.model.attributes.user = null;
+ self.model.attributes.role = null;
+ Backform.Select2Control.prototype.onChange.apply(self, arguments);
+ response.server_list.forEach(function(obj){
+ if(obj.id==self.model.changed.server) {
+ response.server_name = obj.name;
+ }
+ });
+ })
+ .fail(function(xhr) {
+ alertify.connectServer('Connect to server', xhr.responseJSON.result, self.getValueFromDOM());
+ });
+ } else {
+ response.password = $('#password').val();
+ }
+ } else {
+ self.model.attributes.database = null;
+ self.model.attributes.user = null;
+ self.model.attributes.role = null;
+ Backform.Select2Control.prototype.onChange.apply(self, arguments);
+ }
+ closeEvent.close = true;
+ },
+ };
+ });
+ }
+ },
+ render: function() {
+ let self = this;
+ self.connect(self);
+ 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(),
+ });
+ $.ajax({
+ async: false,
+ url: url,
+ headers: {
+ 'Cache-Control' : 'no-cache',
+ },
+ }).done(function () {
+ Backform.Select2Control.prototype.onChange.apply(self, arguments);
+ response.server_list.forEach(function(obj){
+ if(obj.id==self.model.changed.server) {
+ response.server_name = obj.name;
+ }
+ });
+ }).fail(function(xhr){
+ alertify.connectServer('Connect to server', xhr.responseJSON.result, self.getValueFromDOM());
+ });
+
+ },
+ }),
+ options: function() {
+ return _.map(response.server_list, (obj) => {
+ if (obj.id == parseInt(sid))
+ response.server_name = obj.name;
+
+ return {
+ value: obj.id,
+ label: obj.name,
+ };
+ });
+ },
+ },
+ {
+ 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);
+ }
+ }, 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: '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,
+ },
+ /*{
+ id: 'password',
+ name: 'password',
+ label: gettext('Password'tools/sqleditor/__init__.py),
+ type: 'password',
+ editable: true,
+ disabled: true,
+ deps: ['user'],
+ control: Backform.InputControl.extend({
+ render: function() {
+ let self = this;
+ self.model.attributes.password = null;
+ Backform.InputControl.prototype.render.apply(self, arguments);
+ return self;
+ },
+ onChange: function() {
+ let self = this;
+ Backform.InputControl.prototype.onChange.apply(self, arguments);
+ },
+ }),
+ },*/
+ ],
+ validate: function() {
+ let msg = null;
+ this.errorModel.clear();
+ if(_.isUndefined(this.get('database')) || _.isNull(this.get('database'))){
+ msg = gettext('Please select database');
+ this.errorModel.set('database', msg);
+ return msg;
+ } else if(_.isUndefined(this.get('database')) || _.isUndefined(this.get('user'))|| _.isNull(this.get('user'))) {
+ msg = gettext('Please select user');
+ this.errorModel.set('user', msg);
+ return msg;
+ }
+ /*else if((this.attributes.password == '' || _.isUndefined(this.get('password')) || _.isNull(this.get('password')))) {
+ msg = gettext('Please enter password');
+ this.errorModel.set('password', msg);
+ return msg;
+ }*/
+ return null;
+ },
+ });
+
+ let model = new newConnectionModel();
+ return model;
+}
diff --git a/web/pgadmin/static/scss/_alert.scss b/web/pgadmin/static/scss/_alert.scss
index dac552b..836f0af 100644
--- a/web/pgadmin/static/scss/_alert.scss
+++ b/web/pgadmin/static/scss/_alert.scss
@@ -92,6 +92,7 @@
right: 0;
left: 0;
bottom: 0;
+ z-index: 1;
}
.pg-prop-status-bar {
diff --git a/web/pgadmin/tools/datagrid/__init__.py b/web/pgadmin/tools/datagrid/__init__.py
index f5fc78c..07459be 100644
--- a/web/pgadmin/tools/datagrid/__init__.py
+++ b/web/pgadmin/tools/datagrid/__init__.py
@@ -18,21 +18,22 @@ from flask import Response, url_for, session, request, make_response
from werkzeug.useragents import UserAgent
from flask import current_app as app, render_template
from flask_babelex import gettext
-from flask_security import login_required
+from flask_security import login_required, current_user
from pgadmin.tools.sqleditor.command import ObjectRegistry, SQLFilter
+from pgadmin.tools.sqleditor import check_transaction_status
from pgadmin.utils import PgAdminModule
from pgadmin.utils.ajax import make_json_response, bad_request, \
- internal_server_error
+ internal_server_error, unauthorized
from config import PG_DEFAULT_DRIVER
-from pgadmin.model import Server
+from pgadmin.model import Server, User
from pgadmin.utils.driver import get_driver
from pgadmin.utils.exception import ConnectionLost, SSHTunnelConnectionLost
from pgadmin.utils.preferences import Preferences
from pgadmin.settings import get_setting
from pgadmin.browser.utils import underscore_unescape
from pgadmin.utils.exception import ObjectGone
-from pgadmin.utils.constants import MIMETYPE_APP_JS
+from pgadmin.utils.constants import MIMETYPE_APP_JS, UNAUTH_REQ
MODULE_NAME = 'datagrid'
@@ -73,7 +74,8 @@ class DataGridModule(PgAdminModule):
'datagrid.filter_validate',
'datagrid.filter',
'datagrid.panel',
- 'datagrid.close'
+ 'datagrid.close',
+ 'datagrid.update_query_tool_connection'
]
def on_logout(self, user):
@@ -320,10 +322,23 @@ def initialize_query_tool(trans_id, sgid, sid, did=None):
req_args['recreate'] == '1'):
connect = False
+ is_error, errmsg, conn_id, version = _init_query_tool(trans_id, connect,
+ sgid, sid, did)
+ if is_error:
+ return errmsg
+
+ return make_json_response(
+ data={
+ 'connId': str(conn_id),
+ 'serverVersion': version,
+ }
+ )
+
+
+def _init_query_tool(trans_id, connect, sgid, sid, did, **kwargs):
# Create asynchronous connection using random connection id.
conn_id = str(random.randint(1, 9999999))
- # Use Maintenance database OID
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
if did is None:
@@ -334,24 +349,53 @@ def initialize_query_tool(trans_id, sgid, sid, did=None):
)
except Exception as e:
app.logger.error(e)
- return internal_server_error(errormsg=str(e))
+ return True, internal_server_error(errormsg=str(e)), '', ''
try:
conn = manager.connection(did=did, conn_id=conn_id,
auto_reconnect=False,
use_binary_placeholder=True,
array_to_string=True)
+ is_ask_password = False
if connect:
- status, msg = conn.connect()
+ user = None
+ role = None
+ password = None
+
+ if 'user' in kwargs and 'role' in kwargs:
+ user = kwargs['user']
+ role = kwargs['role'] if kwargs['role'] else None
+ password = kwargs['password'] if kwargs['password'] else None
+ is_ask_password = True
+ if user:
+ status, msg = conn.connect(user=user, role=role,
+ password=password)
+ else:
+ status, msg = conn.connect()
if not status:
app.logger.error(msg)
- return internal_server_error(errormsg=str(msg))
+ if is_ask_password:
+ server = Server.query.filter_by(id=sid).first()
+ return True, make_json_response(
+ success=0,
+ status=428,
+ result=render_template(
+ 'servers/password.html',
+ server_label=server.name,
+ username=user,
+ errmsg=msg,
+ _=gettext,
+ )
+ ), '', ''
+ else:
+ return True, internal_server_error(
+ errormsg=str(msg)), '', ''
except (ConnectionLost, SSHTunnelConnectionLost) as e:
app.logger.error(e)
raise
except Exception as e:
app.logger.error(e)
- return internal_server_error(errormsg=str(e))
+ return True, internal_server_error(errormsg=str(e)), '', ''
if 'gridData' not in session:
sql_grid_data = dict()
@@ -373,10 +417,80 @@ def initialize_query_tool(trans_id, sgid, sid, did=None):
# Store the grid dictionary into the session variable
session['gridData'] = sql_grid_data
+ return False, '', conn_id, manager.version
+
+
[email protected](
+ '/initialize/query_tool/update_connection/<int:trans_id>/'
+ '<int:sgid>/<int:sid>/<int:did>',
+ methods=["POST"], endpoint='update_query_tool_connection'
+)
+def update_query_tool_connection(trans_id, sgid, sid, did):
+ # Remove transaction Id.
+ with query_tool_close_session_lock:
+ data = dict()
+ if request.data:
+ data = json.loads(request.data, encoding='utf-8')
+
+ if 'gridData' not in session:
+ return make_json_response(data={'status': True})
+
+ grid_data = session['gridData']
+
+ # Return from the function if transaction id not found
+ if str(trans_id) not in grid_data:
+ return make_json_response(data={'status': True})
+
+ connect = True
+
+ req_args = request.args
+ if ('recreate' in req_args and
+ req_args['recreate'] == '1'):
+ connect = False
+
+ new_trans_id = str(random.randint(1, 9999999))
+ kwargs = {
+ 'user': data['user'],
+ 'role': data['role'],
+ 'password': data['password'] if 'password' in data else None
+ }
+
+ is_error, errmsg, conn_id, version = _init_query_tool(
+ new_trans_id, connect, sgid, sid, did, **kwargs)
+
+ if is_error:
+ return errmsg
+ else:
+ try:
+ # Check the transaction and connection status
+ status, error_msg, conn, trans_obj, session_obj = \
+ check_transaction_status(trans_id)
+
+ status, error_msg, new_conn, new_trans_obj, new_session_obj = \
+ check_transaction_status(new_trans_id)
+
+ new_session_obj['primary_keys'] = session_obj[
+ 'primary_keys'] if 'primary_keys' in session_obj else None
+ new_session_obj['columns_info'] = session_obj[
+ 'columns_info'] if 'columns_info' in session_obj else None
+ new_session_obj['client_primary_key'] = session_obj[
+ 'client_primary_key'] if 'client_primary_key'\
+ in session_obj else None
+
+ close_query_tool_session(trans_id)
+ # Remove the information of unique transaction id from the
+ # session variable.
+ grid_data.pop(str(trans_id), None)
+ session['gridData'] = grid_data
+ except Exception as e:
+ app.logger.error(e)
+ # return internal_server_error(errormsg=str(e))
+
return make_json_response(
data={
'connId': str(conn_id),
- 'serverVersion': manager.version,
+ 'serverVersion': version,
+ 'tran_id': new_trans_id
}
)
diff --git a/web/pgadmin/tools/datagrid/templates/datagrid/index.html b/web/pgadmin/tools/datagrid/templates/datagrid/index.html
index 097a42e..16a209f 100644
--- a/web/pgadmin/tools/datagrid/templates/datagrid/index.html
+++ b/web/pgadmin/tools/datagrid/templates/datagrid/index.html
@@ -392,8 +392,17 @@
title="" role="img">
</i>
</div>
- <div class="editor-title"
- style="background-color: {% if fgcolor %}{{ bgcolor or '#FFFFFF' }}{% endif %}; color: {% if fgcolor %}{{ fgcolor }}{% endif %};"> </div>
+ <div class="connection-info btn-group mr-1" role="group" aria-label="">
+ <div class="editor-title" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"
+ style="background-color: {% if fgcolor %}{{ bgcolor or '#FFFFFF' }}{% endif %}; color: {% if fgcolor %}{{ fgcolor }}{% endif %};">
+ </div>
+ <span class="conn-info-dd dropdown-toggle dropdown-toggle-split"
+ data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
+ <ul class="dropdown-menu" id="connections-list">
+ </ul>
+ </div>
+
+
</div>
<div id="editor-panel" tabindex="0">
<div id="fetching_data" class="pg-sp-container sql-editor-busy-fetching">
@@ -456,6 +465,7 @@ require(['sources/generated/browser_nodes', 'sources/generated/codemirror', 'sou
var script_type_url = '';
{% endif %}
// Start the query tool.
+
sqlEditorController.start(
{{ uniqueId }},
{{ url_params|safe}},
diff --git a/web/pgadmin/tools/datagrid/tests/__init__.py b/web/pgadmin/tools/datagrid/tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/web/pgadmin/tools/datagrid/tests/datagrid_test_data.json b/web/pgadmin/tools/datagrid/tests/datagrid_test_data.json
new file mode 100644
index 0000000..0075f35
--- /dev/null
+++ b/web/pgadmin/tools/datagrid/tests/datagrid_test_data.json
@@ -0,0 +1,134 @@
+{
+ "data_grid_init_query_tool": [
+ {
+ "name": "Datagrid init query tool",
+ "url": "/datagrid/initialize/query_tool/",
+ "is_positive_test": true,
+ "mocking_required": false,
+ "test_data": {},
+ "mock_data": {},
+ "expected_data": {
+ "status_code": 200
+ }
+ }
+ ],
+ "data_grid_query_tool_close": [
+ {
+ "name": "Datagrid query tool close",
+ "url": "/datagrid/close/",
+ "is_positive_test": true,
+ "mocking_required": false,
+ "test_data": {},
+ "mock_data": {},
+ "expected_data": {
+ "status_code": 200
+ }
+ }
+ ],
+ "data_grid_validate_filter": [
+ {
+ "name": "Datagrid validate filter",
+ "url": "/datagrid/filter/validate/",
+ "is_positive_test": true,
+ "mocking_required": false,
+ "test_data": "id = 1",
+ "mock_data": {},
+ "expected_data": {
+ "status_code": 200
+ }
+ },
+ {
+ "name": "Datagrid validate filter",
+ "url": "/datagrid/filter/validate/",
+ "is_positive_test": false,
+ "mocking_required": true,
+ "test_data": "id = 1",
+ "mock_data": {
+ "function_name": "pgadmin.utils.driver.psycopg2.connection.Connection.execute_scalar",
+ "return_value": "(False, 'Mocked Internal Server Error while validate filter')"
+ },
+ "expected_data": {
+ "status_code": 200
+ }
+ }
+ ],
+ "data_grid_update_connection": [
+ {
+ "name": "Datagrid update connection positive",
+ "url": "/datagrid/initialize/query_tool/update_connection/",
+ "is_positive_test": true,
+ "mocking_required": false,
+ "is_create_role": false,
+ "test_data": {},
+ "mock_data": {},
+ "expected_data": {
+ "status_code": 200
+ }
+ },
+ {
+ "name": "Datagrid update connection with new user",
+ "url": "/datagrid/initialize/query_tool/update_connection/",
+ "is_positive_test": true,
+ "mocking_required": false,
+ "is_create_role": true,
+ "test_data": {},
+ "mock_data": {},
+ "expected_data": {
+ "status_code": 200
+ }
+ }
+ ],
+ "data_grid_panel": [
+ {
+ "name": "Datagrid Panel",
+ "url": "/datagrid/panel/",
+ "is_positive_test": true,
+ "mocking_required": false,
+ "test_data": {},
+ "mock_data": {
+ },
+ "expected_data": {
+ "status_code": 200
+ }
+ }
+ ],
+ "data_grid_initialize": [
+ {
+ "name": "Datagrid Initialize",
+ "url": "/datagrid/initialize/datagrid/",
+ "is_positive_test": true,
+ "mocking_required": false,
+ "test_data": "id=1",
+ "mock_data": {
+
+ },
+ "expected_data": {
+ "status_code": 200
+ }
+ },{
+ "name": "Datagrid Initialize",
+ "url": "/datagrid/initialize/datagrid/",
+ "is_positive_test": true,
+ "mocking_required": false,
+ "test_data": null,
+ "mock_data": {},
+ "expected_data": {
+ "status_code": 200
+ }
+ },
+ {
+ "name": "Datagrid Initialize",
+ "url": "/datagrid/initialize/datagrid/",
+ "is_positive_test": false,
+ "mocking_required": true,
+ "test_data": "id=1",
+ "mock_data": {
+ "function_name": "pgadmin.utils.driver.psycopg2.connection.Connection.execute_dict",
+ "return_value": "(False, 'Mocked Internal Server Error while initialize datagrid.')"
+ },
+ "expected_data": {
+ "status_code": 500
+ }
+ }
+ ]
+}
diff --git a/web/pgadmin/tools/datagrid/tests/test_data_grid_init_query_tool.py b/web/pgadmin/tools/datagrid/tests/test_data_grid_init_query_tool.py
new file mode 100644
index 0000000..6ecf5de
--- /dev/null
+++ b/web/pgadmin/tools/datagrid/tests/test_data_grid_init_query_tool.py
@@ -0,0 +1,72 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+
+import json
+import uuid
+import random
+
+from unittest.mock import patch
+from pgadmin.browser.server_groups.servers.databases.tests import utils as \
+ database_utils
+
+from pgadmin.utils.route import BaseTestGenerator
+from regression import parent_node_dict
+from regression.python_test_utils import test_utils as utils
+from regression.test_setup import config_data
+from . import utils as data_grid_utils
+
+
+class DatagridInitQueryToolTestCase(BaseTestGenerator):
+ """
+ This will init query-tool connection.
+ """
+
+ scenarios = utils.generate_scenarios(
+ 'data_grid_init_query_tool',
+ data_grid_utils.test_cases
+ )
+
+ def setUp(self):
+ self.database_info = parent_node_dict["database"][-1]
+ self.db_name = self.database_info["db_name"]
+ self.did = self.database_info["db_id"]
+ self.sid = parent_node_dict["server"][-1]["server_id"]
+ self.sgid = config_data['server_group']
+
+ db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
+ self.sid, self.did)
+
+ self.trans_id = str(random.randint(1, 9999999))
+
+ if not db_con['data']["connected"]:
+ raise Exception("Could not connect to database to add a table.")
+
+ def init_query_tool(self):
+ response = self.tester.post(
+ self.url + str(self.trans_id) + '/' + str(self.sgid) + '/' + str(
+ self.sid) + '/' + str(self.did),
+ content_type='html/json'
+ )
+ return response
+
+ def runTest(self):
+ """ This function will init query tool connection."""
+
+ if self.is_positive_test:
+ response = self.init_query_tool()
+ actual_response_code = response.status_code
+ expected_response_code = self.expected_data['status_code']
+
+ self.assertEqual(actual_response_code, expected_response_code)
+
+ def tearDown(self):
+ """This function disconnect database."""
+ database_utils.disconnect_database(self, self.sid,
+ self.did)
diff --git a/web/pgadmin/tools/datagrid/tests/test_data_grid_panel.py b/web/pgadmin/tools/datagrid/tests/test_data_grid_panel.py
new file mode 100644
index 0000000..ae8ec10
--- /dev/null
+++ b/web/pgadmin/tools/datagrid/tests/test_data_grid_panel.py
@@ -0,0 +1,93 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+
+import json
+import uuid
+import random
+
+from unittest.mock import patch
+from pgadmin.browser.server_groups.servers.databases.tests import utils as \
+ database_utils
+
+from pgadmin.utils.route import BaseTestGenerator
+from regression import parent_node_dict
+from regression.python_test_utils import test_utils as utils
+from regression.test_setup import config_data
+from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
+ utils as schema_utils
+from pgadmin.browser.server_groups.servers.databases.schemas.tables.tests \
+ import utils as tables_utils
+from . import utils as data_grid_utils
+
+
+class DatagridPanelTestCase(BaseTestGenerator):
+ """
+ This will data grid panel.
+ """
+
+ scenarios = utils.generate_scenarios(
+ 'data_grid_panel',
+ data_grid_utils.test_cases
+ )
+
+ def setUp(self):
+ self.database_info = parent_node_dict["database"][-1]
+ self.db_name = self.database_info["db_name"]
+ self.did = self.database_info["db_id"]
+ self.sid = parent_node_dict["server"][-1]["server_id"]
+ self.sgid = config_data['server_group']
+
+ db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
+ self.sid, self.did)
+ if not db_con['data']["connected"]:
+ raise Exception("Could not connect to database to add a table.")
+
+ self.trans_id = str(random.randint(1, 9999999))
+ qt_init = data_grid_utils._init_query_tool(self, self.trans_id,
+ self.sgid, self.sid,
+ self.did)
+
+ if not qt_init['success']:
+ raise Exception("Could not initialize querty tool.")
+
+ def panel(self):
+ query_param = \
+ '?is_query_tool={0}&sgid={1}&sid={2}&server_type={3}' \
+ '&did={4}&title={5}'.format(True, self.sgid, self.sid,
+ self.server_information['type'],
+ self.did, 'Query panel')
+
+ response = self.tester.post(
+ self.url + str(self.trans_id) + query_param,
+ data=json.dumps(self.test_data),
+ content_type='html/json'
+ )
+ return response
+
+ def runTest(self):
+ """ This function will update query tool connection."""
+
+ if self.is_positive_test:
+ response = self.panel()
+ actual_response_code = response.status_code
+ expected_response_code = self.expected_data['status_code']
+ else:
+ with patch(self.mock_data["function_name"],
+ return_value=eval(self.mock_data["return_value"])):
+ response = self.panel()
+ actual_response_code = response.status_code
+ expected_response_code = self.expected_data['status_code']
+
+ self.assertEqual(actual_response_code, expected_response_code)
+
+ def tearDown(self):
+ """This function disconnect database."""
+ database_utils.disconnect_database(self, self.sid,
+ self.did)
diff --git a/web/pgadmin/tools/datagrid/tests/test_data_grid_query_tool_close.py b/web/pgadmin/tools/datagrid/tests/test_data_grid_query_tool_close.py
new file mode 100644
index 0000000..822c2e1
--- /dev/null
+++ b/web/pgadmin/tools/datagrid/tests/test_data_grid_query_tool_close.py
@@ -0,0 +1,77 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+
+import json
+import uuid
+import random
+
+from unittest.mock import patch
+from pgadmin.browser.server_groups.servers.databases.tests import utils as \
+ database_utils
+
+from pgadmin.utils.route import BaseTestGenerator
+from regression import parent_node_dict
+from regression.python_test_utils import test_utils as utils
+from regression.test_setup import config_data
+from . import utils as data_grid_utils
+
+
+class DatagridQueryToolCloseTestCase(BaseTestGenerator):
+ """
+ This will close query-tool connection.
+ """
+
+ scenarios = utils.generate_scenarios(
+ 'data_grid_query_tool_close',
+ data_grid_utils.test_cases
+ )
+
+ def setUp(self):
+ self.database_info = parent_node_dict["database"][-1]
+ self.db_name = self.database_info["db_name"]
+ self.did = self.database_info["db_id"]
+ self.sid = parent_node_dict["server"][-1]["server_id"]
+ self.sgid = config_data['server_group']
+
+ db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
+ self.sid, self.did)
+
+ if not db_con['data']["connected"]:
+ raise Exception("Could not connect to database to add a table.")
+
+ self.trans_id = str(random.randint(1, 9999999))
+ qt_init = data_grid_utils._init_query_tool(self, self.trans_id,
+ self.sgid, self.sid,
+ self.did)
+
+ if not qt_init['success']:
+ raise Exception("Could not initialize querty tool.")
+
+ def close_connection(self):
+ response = self.tester.delete(
+ self.url + str(self.trans_id),
+ content_type='html/json'
+ )
+ return response
+
+ def runTest(self):
+ """ This function will update query tool connection."""
+
+ if self.is_positive_test:
+ response = self.close_connection()
+ actual_response_code = response.status_code
+ expected_response_code = self.expected_data['status_code']
+
+ self.assertEqual(actual_response_code, expected_response_code)
+
+ def tearDown(self):
+ """This function disconnect database."""
+ database_utils.disconnect_database(self, self.sid,
+ self.did)
diff --git a/web/pgadmin/tools/datagrid/tests/test_data_grid_update_connection.py b/web/pgadmin/tools/datagrid/tests/test_data_grid_update_connection.py
new file mode 100644
index 0000000..5d2b14a
--- /dev/null
+++ b/web/pgadmin/tools/datagrid/tests/test_data_grid_update_connection.py
@@ -0,0 +1,120 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+
+import json
+import uuid
+import random
+
+from unittest.mock import patch
+from pgadmin.browser.server_groups.servers.databases.tests import utils as \
+ database_utils
+
+from pgadmin.utils.route import BaseTestGenerator
+from regression import parent_node_dict
+from regression.python_test_utils import test_utils as utils
+from regression.test_setup import config_data
+from pgadmin.browser.server_groups.servers.roles.tests import \
+ utils as roles_utils
+from . import utils as data_grid_utils
+
+
+class DatagridUpdateConnectionTestCase(BaseTestGenerator):
+ """
+ This will update query-tool connection.
+ """
+
+ scenarios = utils.generate_scenarios(
+ 'data_grid_update_connection',
+ data_grid_utils.test_cases
+ )
+
+ def setUp(self):
+ self.database_info = parent_node_dict["database"][-1]
+ self.db_name = self.database_info["db_name"]
+ self.did = self.database_info["db_id"]
+ self.sid = parent_node_dict["server"][-1]["server_id"]
+ self.sgid = config_data['server_group']
+
+ db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
+ self.sid, self.did)
+
+ self.trans_id = str(random.randint(1, 9999999))
+ self.roles = None
+
+ if self.is_create_role:
+ data = roles_utils.get_role_data(self.server['db_password'])
+ self.role_name = data['rolname']
+ self.role_password = data['rolpassword']
+ roles_utils.create_role_with_password(
+ self.server, self.role_name, self.role_password)
+
+ if not self.is_positive_test or self.is_create_role:
+ qt_init = data_grid_utils._init_query_tool(self, self.trans_id,
+ self.sgid, self.sid,
+ self.did)
+
+ if not qt_init['success']:
+ raise Exception("Could not initialize querty tool.")
+
+ self.test_data = {
+ "database": self.did,
+ "server": self.sid,
+ }
+
+ if self.server_information['type'] == 'ppas':
+ self.test_data['password'] = 'enterprisedb'
+ self.test_data['user'] = 'enterprisedb'
+ else:
+ self.test_data['password'] = 'postgres'
+ self.test_data['user'] = 'postgres'
+
+ if not db_con['data']["connected"]:
+ raise Exception("Could not connect to database to add a table.")
+
+ def update_connection(self, user_data=None):
+ if user_data:
+ response = self.tester.post(
+ self.url + str(self.trans_id) + '/' + str(self.sgid) +
+ '/' + str(self.sid) + '/' + str(self.did),
+ data=json.dumps(user_data),
+ content_type='html/json'
+ )
+ else:
+ response = self.tester.post(
+ self.url + str(self.trans_id) + '/' + str(self.sgid) + '/' +
+ str(self.sid) + '/' + str(self.did),
+ data=json.dumps(self.test_data),
+ content_type='html/json'
+ )
+ return response
+
+ def runTest(self):
+ """ This function will update query tool connection."""
+
+ if self.is_positive_test:
+ user_data = dict()
+ if self.is_create_role:
+ user_data['user'] = self.role_name
+ user_data['password'] = self.role_password
+ user_data['role'] = None
+ response = self.update_connection(user_data=user_data)
+ actual_response_code = response.status_code
+ expected_response_code = self.expected_data['status_code']
+ else:
+ response = self.update_connection()
+ actual_response_code = response.status_code
+ expected_response_code = self.expected_data['status_code']
+
+ self.assertEqual(actual_response_code, expected_response_code)
+
+ def tearDown(self):
+ """This function disconnect database."""
+ database_utils.disconnect_database(self, self.sid,
+ self.did)
diff --git a/web/pgadmin/tools/datagrid/tests/test_data_grid_validate_filter.py b/web/pgadmin/tools/datagrid/tests/test_data_grid_validate_filter.py
new file mode 100644
index 0000000..0aba5d8
--- /dev/null
+++ b/web/pgadmin/tools/datagrid/tests/test_data_grid_validate_filter.py
@@ -0,0 +1,91 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+
+import json
+import uuid
+import random
+
+from unittest.mock import patch
+from pgadmin.browser.server_groups.servers.databases.tests import utils as \
+ database_utils
+
+from pgadmin.utils.route import BaseTestGenerator
+from regression import parent_node_dict
+from regression.python_test_utils import test_utils as utils
+from regression.test_setup import config_data
+from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
+ utils as schema_utils
+from pgadmin.browser.server_groups.servers.databases.schemas.tables.tests \
+ import utils as tables_utils
+from . import utils as data_grid_utils
+
+
+class DatagridValidateFilterTestCase(BaseTestGenerator):
+ """
+ This will validate filter connection.
+ """
+
+ scenarios = utils.generate_scenarios(
+ 'data_grid_validate_filter',
+ data_grid_utils.test_cases
+ )
+
+ def setUp(self):
+ self.database_info = parent_node_dict["database"][-1]
+ self.db_name = self.database_info["db_name"]
+ self.did = self.database_info["db_id"]
+ self.sid = parent_node_dict["server"][-1]["server_id"]
+ self.sgid = config_data['server_group']
+
+ db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
+ self.sid, self.did)
+ if not db_con['data']["connected"]:
+ raise Exception("Could not connect to database to add a table.")
+ self.schema_id = parent_node_dict['schema'][-1]["schema_id"]
+ self.schema_name = parent_node_dict['schema'][-1]["schema_name"]
+ schema_response = schema_utils.verify_schemas(self.server,
+ self.db_name,
+ self.schema_name)
+ if not schema_response:
+ raise Exception("Could not find the schema to add a table.")
+ self.table_name = "table_for_wizard%s" % (str(uuid.uuid4())[1:8])
+ self.table_id = tables_utils.create_table(self.server, self.db_name,
+ self.schema_name,
+ self.table_name)
+
+ def validate_filter(self):
+ response = self.tester.post(
+ self.url + str(self.sid) + '/' + str(self.did) + '/' +
+ str(self.table_id),
+ data=json.dumps(self.test_data),
+ content_type='html/json'
+ )
+ return response
+
+ def runTest(self):
+ """ This function will update query tool connection."""
+
+ if self.is_positive_test:
+ response = self.validate_filter()
+ actual_response_code = response.status_code
+ expected_response_code = self.expected_data['status_code']
+ else:
+ with patch(self.mock_data["function_name"],
+ return_value=eval(self.mock_data["return_value"])):
+ response = self.validate_filter()
+ actual_response_code = response.status_code
+ expected_response_code = self.expected_data['status_code']
+
+ self.assertEqual(actual_response_code, expected_response_code)
+
+ def tearDown(self):
+ """This function disconnect database."""
+ database_utils.disconnect_database(self, self.sid,
+ self.did)
diff --git a/web/pgadmin/tools/datagrid/tests/test_initialize_data_grid.py b/web/pgadmin/tools/datagrid/tests/test_initialize_data_grid.py
new file mode 100644
index 0000000..130a1d6
--- /dev/null
+++ b/web/pgadmin/tools/datagrid/tests/test_initialize_data_grid.py
@@ -0,0 +1,108 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+
+import json
+import uuid
+import random
+
+from unittest.mock import patch
+from pgadmin.browser.server_groups.servers.databases.tests import utils as \
+ database_utils
+
+from pgadmin.utils.route import BaseTestGenerator
+from regression import parent_node_dict
+from regression.python_test_utils import test_utils as utils
+from regression.test_setup import config_data
+from pgadmin.browser.server_groups.servers.databases.schemas.tests import \
+ utils as schema_utils
+from pgadmin.browser.server_groups.servers.databases.schemas.tables.tests \
+ import utils as tables_utils
+from . import utils as data_grid_utils
+
+
+class DatagridInitializeTestCase(BaseTestGenerator):
+ """
+ This will Initialize datagrid
+ """
+
+ scenarios = utils.generate_scenarios(
+ 'data_grid_initialize',
+ data_grid_utils.test_cases
+ )
+
+ def setUp(self):
+ self.database_info = parent_node_dict["database"][-1]
+ self.db_name = self.database_info["db_name"]
+ self.did = self.database_info["db_id"]
+ self.sid = parent_node_dict["server"][-1]["server_id"]
+ self.sgid = config_data['server_group']
+
+ db_con = database_utils.connect_database(self, utils.SERVER_GROUP,
+ self.sid, self.did)
+ if not db_con['data']["connected"]:
+ raise Exception("Could not connect to database to add a table.")
+
+ self.schema_id = parent_node_dict['schema'][-1]["schema_id"]
+ self.schema_name = parent_node_dict['schema'][-1]["schema_name"]
+ schema_response = schema_utils.verify_schemas(self.server,
+ self.db_name,
+ self.schema_name)
+ if not schema_response:
+ raise Exception("Could not find the schema to add a table.")
+ self.table_name = "table_for_wizard%s" % (str(uuid.uuid4())[1:8])
+ self.table_id = tables_utils.create_table(self.server, self.db_name,
+ self.schema_name,
+ self.table_name)
+ self.trans_id = str(random.randint(1, 9999999))
+ qt_init = data_grid_utils._init_query_tool(self, self.trans_id,
+ self.sgid, self.sid,
+ self.did)
+
+ if not qt_init['success']:
+ raise Exception("Could not initialize query tool.")
+
+ def initialize_datagrid(self):
+ if self.test_data:
+ response = self.tester.post(
+ self.url + str(self.trans_id) + '/4/table/' +
+ str(self.sgid) + '/' + str(self.sid) + '/' +
+ str(self.did) + '/' + str(self.table_id),
+ data=json.dumps(self.test_data),
+ content_type='html/json'
+ )
+ else:
+ response = self.tester.post(
+ self.url + str(self.trans_id) + '/4/table/' +
+ str(self.sgid) + '/' + str(self.sid) + '/' +
+ str(self.did) + '/' + str(self.table_id),
+ content_type='html/json'
+ )
+ return response
+
+ def runTest(self):
+ """ This function will update query tool connection."""
+
+ if self.is_positive_test:
+ response = self.initialize_datagrid()
+ actual_response_code = response.status_code
+ expected_response_code = self.expected_data['status_code']
+ else:
+ with patch(self.mock_data["function_name"],
+ return_value=eval(self.mock_data["return_value"])):
+ response = self.initialize_datagrid()
+ actual_response_code = response.status_code
+ expected_response_code = self.expected_data['status_code']
+
+ self.assertEqual(actual_response_code, expected_response_code)
+
+ def tearDown(self):
+ """This function disconnect database."""
+ database_utils.disconnect_database(self, self.sid,
+ self.did)
diff --git a/web/pgadmin/tools/datagrid/tests/utils.py b/web/pgadmin/tools/datagrid/tests/utils.py
new file mode 100644
index 0000000..c3d4bb5
--- /dev/null
+++ b/web/pgadmin/tools/datagrid/tests/utils.py
@@ -0,0 +1,33 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+import os
+import json
+
+file_name = os.path.basename(__file__)
+CURRENT_PATH = os.path.dirname(os.path.realpath(__file__))
+with open(CURRENT_PATH + "/datagrid_test_data.json") as data_file:
+ test_cases = json.load(data_file)
+
+
+def _init_query_tool(self, trans_id, server_group, server_id, db_id):
+ QUERY_TOOL_INIT_URL = '/datagrid/initialize/query_tool'
+
+ qt_init = self.tester.post(
+ '{0}/{1}/{2}/{3}/{4}'.format(
+ QUERY_TOOL_INIT_URL,
+ trans_id,
+ server_group,
+ server_id,
+ db_id
+ ),
+ follow_redirects=True
+ )
+ assert qt_init.status_code == 200
+ qt_init = json.loads(qt_init.data.decode('utf-8'))
+ return qt_init
diff --git a/web/pgadmin/tools/sqleditor/__init__.py b/web/pgadmin/tools/sqleditor/__init__.py
index c62bc7c..a02f6b9 100644
--- a/web/pgadmin/tools/sqleditor/__init__.py
+++ b/web/pgadmin/tools/sqleditor/__init__.py
@@ -10,33 +10,38 @@
"""A blueprint module implementing the sqleditor frame."""
import os
import pickle
-import sys
import re
+from urllib.parse import unquote
import simplejson as json
-from flask import Response, url_for, render_template, session, request, \
- current_app
+from config import PG_DEFAULT_DRIVER, ON_DEMAND_RECORD_COUNT
+from flask import Response, url_for, render_template, session, current_app
+from flask import request, jsonify
from flask_babelex import gettext
from flask_security import login_required, current_user
-from urllib.parse import unquote
-
-from config import PG_DEFAULT_DRIVER, ON_DEMAND_RECORD_COUNT
from pgadmin.misc.file_manager import Filemanager
from pgadmin.tools.sqleditor.command import QueryToolCommand
from pgadmin.tools.sqleditor.utils.constant_definition import ASYNC_OK, \
ASYNC_EXECUTION_ABORTED, \
CONNECTION_STATUS_MESSAGE_MAPPING, TX_STATUS_INERROR
+from pgadmin.tools.sqleditor.utils.filter_dialog import FilterDialog
+from pgadmin.tools.sqleditor.utils.query_history import QueryHistory
+from pgadmin.tools.sqleditor.utils.query_tool_fs_utils import \
+ read_file_generator
+from pgadmin.tools.sqleditor.utils.query_tool_preferences import \
+ register_query_tool_preferences
from pgadmin.tools.sqleditor.utils.start_running_query import StartRunningQuery
from pgadmin.tools.sqleditor.utils.update_session_grid_transaction import \
update_session_grid_transaction
from pgadmin.utils import PgAdminModule
from pgadmin.utils import get_storage_directory
from pgadmin.utils.ajax import make_json_response, bad_request, \
- success_return, internal_server_error
+ internal_server_error
+from pgadmin.utils.constants import MIMETYPE_APP_JS
from pgadmin.utils.driver import get_driver
-from pgadmin.utils.menu import MenuItem
-from pgadmin.utils.exception import ConnectionLost, SSHTunnelConnectionLost,\
+from pgadmin.utils.exception import ConnectionLost, SSHTunnelConnectionLost, \
CryptKeyMissing
+from pgadmin.utils.menu import MenuItem
from pgadmin.utils.sqlautocomplete.autocomplete import SQLAutoComplete
from pgadmin.tools.sqleditor.utils.query_tool_preferences import \
register_query_tool_preferences
@@ -44,8 +49,10 @@ from pgadmin.tools.sqleditor.utils.query_tool_fs_utils import \
read_file_generator
from pgadmin.tools.sqleditor.utils.filter_dialog import FilterDialog
from pgadmin.tools.sqleditor.utils.query_history import QueryHistory
-from pgadmin.utils.constants import MIMETYPE_APP_JS, SERVER_CONNECTION_CLOSED,\
- ERROR_MSG_TRANS_ID_NOT_FOUND
+from pgadmin.utils.constants import MIMETYPE_APP_JS, \
+ SERVER_CONNECTION_CLOSED, ERROR_MSG_TRANS_ID_NOT_FOUND
+from pgadmin.model import Server
+from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
MODULE_NAME = 'sqleditor'
@@ -109,6 +116,12 @@ class SqlEditorModule(PgAdminModule):
'sqleditor.get_query_history',
'sqleditor.add_query_history',
'sqleditor.clear_query_history',
+ 'sqleditor.get_new_connection_data',
+ 'sqleditor.get_new_connection_database',
+ 'sqleditor.get_new_connection_user',
+ 'sqleditor.get_new_connection_role',
+ 'sqleditor.connect_server',
+ 'sqleditor.connect_server_with_user',
]
def register_preferences(self):
@@ -224,7 +237,7 @@ def start_view_data(trans_id):
)
if status and conn is not None and \
- trans_obj is not None and session_obj is not None:
+ trans_obj is not None and session_obj is not None:
# set fetched row count to 0 as we are executing query again.
trans_obj.update_fetched_row_cnt(0)
@@ -370,7 +383,7 @@ def poll(trans_id):
if isinstance(trans_obj, QueryToolCommand):
trans_status = conn.transaction_status()
if trans_status == TX_STATUS_INERROR and \
- trans_obj.auto_rollback:
+ trans_obj.auto_rollback:
conn.execute_void("ROLLBACK;")
st, result = conn.async_fetchmany_2darray(ON_DEMAND_RECORD_COUNT)
@@ -680,13 +693,12 @@ def save(trans_id):
status=404)
if status and conn is not None and \
- trans_obj is not None and session_obj is not None:
+ trans_obj is not None and session_obj is not None:
# If there is no primary key found then return from the function.
if ('primary_keys' not in session_obj or
- len(session_obj['primary_keys']) <= 0 or
- len(changed_data) <= 0) and \
- 'has_oids' not in session_obj:
+ len(session_obj['primary_keys']) <= 0 or
+ len(changed_data) <= 0) and 'has_oids' not in session_obj:
return make_json_response(
data={
'status': False,
@@ -753,7 +765,7 @@ def append_filter_inclusive(trans_id):
status=404)
if status and conn is not None and \
- trans_obj is not None and session_obj is not None:
+ trans_obj is not None and session_obj is not None:
res = None
filter_sql = ''
@@ -807,7 +819,7 @@ def append_filter_exclusive(trans_id):
info='DATAGRID_TRANSACTION_REQUIRED',
status=404)
if status and conn is not None and \
- trans_obj is not None and session_obj is not None:
+ trans_obj is not None and session_obj is not None:
res = None
filter_sql = ''
@@ -860,7 +872,7 @@ def remove_filter(trans_id):
status=404)
if status and conn is not None and \
- trans_obj is not None and session_obj is not None:
+ trans_obj is not None and session_obj is not None:
res = None
@@ -904,7 +916,7 @@ def set_limit(trans_id):
status=404)
if status and conn is not None and \
- trans_obj is not None and session_obj is not None:
+ trans_obj is not None and session_obj is not None:
res = None
@@ -1046,7 +1058,7 @@ def get_object_name(trans_id):
status=404)
if status and conn is not None and \
- trans_obj is not None and session_obj is not None:
+ trans_obj is not None and session_obj is not None:
res = trans_obj.object_name
else:
status = False
@@ -1082,7 +1094,7 @@ def set_auto_commit(trans_id):
status=404)
if status and conn is not None and \
- trans_obj is not None and session_obj is not None:
+ trans_obj is not None and session_obj is not None:
res = None
@@ -1127,7 +1139,7 @@ def set_auto_rollback(trans_id):
status=404)
if status and conn is not None and \
- trans_obj is not None and session_obj is not None:
+ trans_obj is not None and session_obj is not None:
res = None
@@ -1179,7 +1191,7 @@ def auto_complete(trans_id):
status=404)
if status and conn is not None and \
- trans_obj is not None and session_obj is not None:
+ trans_obj is not None and session_obj is not None:
# Create object of SQLAutoComplete class and pass connection object
auto_complete_obj = SQLAutoComplete(
@@ -1465,6 +1477,284 @@ def get_filter_data(trans_id):
return FilterDialog.get(status, error_msg, conn, trans_obj, session_ob)
[email protected](
+ '/new_connection_dialog/<int:sgid>/<int:sid>',
+ methods=["GET"], endpoint='get_new_connection_data'
+)
+@login_required
+def get_new_connection_data(sgid, sid=None):
+ """
+ This method is used to get required data for get new connection.
+ :extract_sql_from_network_parameters,
+ """
+ try:
+ # if sid and not did:
+ servers = Server.query.all()
+ server_list = [
+ {'name': server.serialize['name'], "id": server.serialize['id']}
+ for server in servers]
+
+ msg = "Success"
+ return make_json_response(
+ data={
+ 'status': True,
+ 'msg': msg,
+ 'result': {
+ 'server_list': server_list
+ }
+ }
+ )
+
+ except Exception as e:
+ return make_json_response(
+ data={
+ 'status': False,
+ 'msg': 'Unable to fetch data.',
+ 'result': {
+ 'server_list': []
+ }
+ }
+ )
+
+
[email protected](
+ '/new_connection_database/<int:sgid>/<int:sid>',
+ methods=["GET"], endpoint='get_new_connection_database'
+)
+@login_required
+def get_new_connection_database(sgid, sid=None):
+ """
+ This method is used to get required data for get new connection.
+ :extract_sql_from_network_parameters,
+ """
+ try:
+ database_list = []
+ from pgadmin.utils.driver import get_driver
+ manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
+ conn = manager.connection()
+ if conn.connected():
+ is_connected = True
+ else:
+ # connection = conn.connect()
+ is_connected = False
+ if is_connected:
+ if sid:
+ template_path = 'databases/sql/#{0}#'.format(manager.version)
+ last_system_oid = 0
+ server_node_res = manager
+
+ db_disp_res = None
+ params = None
+ if server_node_res and server_node_res.db_res:
+ db_disp_res = ", ".join(
+ ['%s'] * len(server_node_res.db_res.split(','))
+ )
+ params = tuple(server_node_res.db_res.split(','))
+ sql = render_template(
+ "/".join([template_path, 'nodes.sql']),
+ last_system_oid=last_system_oid,
+ db_restrictions=db_disp_res
+ )
+ status, databases = conn.execute_dict(sql, params)
+ database_list = [
+ {'label': database['name'], 'value': database['did']} for
+ database in databases['rows']]
+ else:
+ status = False
+
+ msg = "Success"
+ return make_json_response(
+ data={
+ 'status': status,
+ 'msg': msg,
+ 'result': {
+ 'data': database_list,
+ }
+ }
+ )
+ else:
+ return make_json_response(
+ data={
+ 'status': False,
+ 'msg': 'Server not connected, '
+ 'Please connect with server and try again.',
+ 'result': {
+ 'database_list': [],
+ }
+ }
+ )
+ except Exception as e:
+ return make_json_response(
+ data={
+ 'status': False,
+ 'msg': 'Unable to fetch data.',
+ 'result': {
+ 'database_list': [],
+ }
+ }
+ )
+
+
[email protected](
+ '/new_connection_user/<int:sgid>/<int:sid>',
+ methods=["GET"], endpoint='get_new_connection_user'
+)
+@login_required
+def get_new_connection_user(sgid, sid=None):
+ """
+ This method is used to get required data for get new connection.
+ :extract_sql_from_network_parameters,
+ """
+ try:
+ from pgadmin.utils.driver import get_driver
+ manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
+ conn = manager.connection()
+ user_list = []
+ if conn.connected():
+ is_connected = True
+ else:
+ is_connected = False
+ if is_connected:
+ if sid:
+ sql_path = 'roles/sql/#{0}#'.format(manager.version)
+ status, users = conn.execute_2darray(
+ render_template(sql_path + 'nodes.sql')
+ )
+ user_list = [
+ {'value': user['rolname'], 'label': user['rolname']} for
+ user in users['rows'] if user['rolcanlogin']]
+ else:
+ status = False
+
+ msg = "Success"
+ return make_json_response(
+ data={
+ 'status': status,
+ 'msg': msg,
+ 'result': {
+ 'data': user_list,
+ }
+ }
+ )
+ else:
+ return make_json_response(
+ data={
+ 'status': False,
+ 'msg': 'Server not connected, '
+ 'Please connect with server and try again.',
+ 'result': {
+ 'user_list': [],
+ }
+ }
+ )
+ except Exception as e:
+ return make_json_response(
+ data={
+ 'status': False,
+ 'msg': 'Unable to fetch data.',
+ 'result': {
+ 'user_list': [],
+ }
+ }
+ )
+
+
[email protected](
+ '/new_connection_role/<int:sgid>/<int:sid>',
+ methods=["GET"], endpoint='get_new_connection_role'
+)
+@login_required
+def get_new_connection_role(sgid, sid=None):
+ """
+ This method is used to get required data for get new connection.
+ :extract_sql_from_network_parameters,
+ """
+ try:
+ from pgadmin.utils.driver import get_driver
+ manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
+ conn = manager.connection()
+ role_list = []
+ if conn.connected():
+ is_connected = True
+ else:
+ is_connected = False
+ if is_connected:
+ if sid:
+ sql_path = 'roles/sql/#{0}#'.format(manager.version)
+ status, roles = conn.execute_2darray(
+ render_template(sql_path + 'nodes.sql')
+ )
+ role_list = [
+ {'value': role['rolname'], 'label': role['rolname']} for
+ role in roles['rows']]
+ else:
+ status = False
+
+ msg = "Success"
+ return make_json_response(
+ data={
+ 'status': status,
+ 'msg': msg,
+ 'result': {
+ 'data': role_list,
+ }
+ }
+ )
+ else:
+ return make_json_response(
+ data={
+ 'status': False,
+ 'msg': 'Server not connected, '
+ 'Please connect with server and try again.',
+ 'result': {
+ 'user_list': [],
+ }
+ }
+ )
+ except Exception as e:
+ return make_json_response(
+ data={
+ 'status': False,
+ 'msg': 'Unable to fetch data.',
+ 'result': {
+ 'user_list': [],
+ }
+ }
+ )
+
+
[email protected](
+ '/connect_server/<int:sid>/<usr>',
+ methods=["GET"],
+ endpoint="connect_server_with_user"
+)
[email protected](
+ '/connect_server/<int:sid>',
+ methods=["GET"],
+ endpoint="connect_server"
+)
+@login_required
+def connect_server(sid, usr=None):
+ # Check if server is already connected then no need to reconnect again.
+ server = Server.query.filter_by(id=sid).first()
+ driver = get_driver(PG_DEFAULT_DRIVER)
+ manager = driver.connection_manager(sid)
+ conn = manager.connection()
+ user = None
+ if usr and manager.user != usr:
+ user = usr
+ else:
+ if conn.connected():
+ return make_json_response(
+ success=1,
+ info=gettext("Server connected."),
+ data={}
+ )
+
+ view = SchemaDiffRegistry.get_node_view('server')
+ return view.connect(server.servergroup_id, sid, user=user)
+
+
@blueprint.route(
'/filter_dialog/<int:trans_id>',
methods=["PUT"], endpoint='set_filter_data'
diff --git a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
index 00543ff..b8c2d2e 100644
--- a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
+++ b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css
@@ -315,10 +315,6 @@ input.editor-checkbox:focus {
padding: 10px 0px;
}
-.editor-title {
- width:100%;
-}
-
.connection-status-hide {
display: none !important;
}
@@ -395,3 +391,7 @@ input.editor-checkbox:focus {
.hide-vertical-scrollbar {
overflow-y: hidden;
}
+
+.new-connection-dialog-style {
+ width: 100% !important;
+}
diff --git a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
index ddd9ad7..9389db5 100644
--- a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
+++ b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
@@ -14,6 +14,7 @@ define('tools.querytool', [
'jqueryui.position', 'underscore', 'pgadmin.alertifyjs',
'sources/pgadmin', 'backbone', 'bundled_codemirror', 'sources/utils',
'pgadmin.misc.explain',
+ 'pgadmin.user_management.current_user',
'sources/selection/grid_selector',
'sources/selection/active_cell_capture',
'sources/selection/clipboard',
@@ -26,6 +27,7 @@ define('tools.querytool', [
'sources/sqleditor/execute_query',
'sources/sqleditor/query_tool_http_error_handler',
'sources/sqleditor/filter_dialog',
+ 'sources/sqleditor/new_connection_dialog',
'sources/sqleditor/geometry_viewer',
'sources/sqleditor/history/history_collection.js',
'sources/sqleditor/history/query_history',
@@ -52,8 +54,8 @@ define('tools.querytool', [
'pgadmin.tools.user_management',
], function(
gettext, url_for, $, jqueryui, jqueryui_position, _, alertify, pgAdmin, Backbone, codemirror, pgadminUtils,
- pgExplain, GridSelector, ActiveCellCapture, clipboard, copyData, RangeSelectionHelper, handleQueryOutputKeyboardEvent,
- XCellSelectionModel, setStagedRows, SqlEditorUtils, ExecuteQuery, httpErrorHandler, FilterHandler,
+ pgExplain, current_user, GridSelector, ActiveCellCapture, clipboard, copyData, RangeSelectionHelper, handleQueryOutputKeyboardEvent,
+ XCellSelectionModel, setStagedRows, SqlEditorUtils, ExecuteQuery, httpErrorHandler, FilterHandler, newConnectionHandler,
GeometryViewer, historyColl, queryHist, querySources,
keyboardShortcuts, queryToolActions, queryToolNotifications, Datagrid,
modifyAnimation, calculateQueryRunTime, callRenderAfterPoll, queryToolPref, queryTxnStatus, csrfToken, panelTitleFunc,
@@ -89,6 +91,9 @@ define('tools.querytool', [
this.layout = opts.layout;
this.set_server_version(opts.server_ver);
this.trigger('pgadmin-sqleditor:view:initialised');
+ this.connection_list = [
+ {'server_group': null,'server': null, 'database': null, 'user': null, 'role': null, 'title': '<New Connection>'},
+ ];
},
// Bind all the events
@@ -151,6 +156,35 @@ define('tools.querytool', [
'click #btn-rollback': 'on_rollback_transaction',
},
+ render_connection: function(data_list) {
+ if(this.handler.is_query_tool) {
+ var dropdownElement = document.getElementById('connections-list');
+ dropdownElement.innerHTML = '';
+ data_list.forEach((option, index) => {
+ $('#connections-list').append('<li class="connection-list-item" data-index='+ index +'><a class="dropdown-item" href="#" tabindex="0">'+ option.title +'</a></li>');
+
+ });
+ var self = this;
+ $('.connection-list-item').click(function() {
+ self.get_connection_data(this);
+ });
+ } else {
+ $('.conn-info-dd').hide();
+ $('.editor-title').css({pointerEvents: 'none'});
+ }
+ },
+
+ get_connection_data: function(event){
+ var index = $(event).attr('data-index');
+ var connection_details = this.connection_list[index];
+ if(connection_details.server_group) {
+ this.on_change_connection(connection_details);
+ } else {
+ this.on_new_connection();
+ }
+
+ },
+
reflectPreferences: function() {
let self = this,
browser = pgWindow.default.pgAdmin.Browser,
@@ -199,8 +233,15 @@ define('tools.querytool', [
});
},
- set_editor_title: function(title) {
- this.$el.find('.editor-title').text(title);
+ set_editor_title: function(title, is_connected) {
+ if(is_connected) {
+ this.$el.find('.editor-title').text(title);
+ this.render_connection(this.connection_list);
+ } else {
+ this.$el.find('.editor-title').text(title);
+ this.render_connection(this.connection_list);
+ }
+
},
// This function is used to render the template.
@@ -684,6 +725,8 @@ define('tools.querytool', [
pgBrowser.register_to_activity_listener(document, ()=>{
alertify.alert(gettext('Timeout'), gettext('Your session has timed out due to inactivity. Please close the window and login again.'));
});
+
+ self.render_connection(self.connection_list);
},
/* Regarding SlickGrid usage in render_grid function.
@@ -1595,6 +1638,17 @@ define('tools.querytool', [
);
},
+ on_new_connection: function() {
+ var self = this;
+
+ // Trigger the show_filter signal to the SqlEditorController class
+ self.handler.trigger(
+ 'pgadmin-sqleditor:button:show_new_connection',
+ self,
+ self.handler
+ );
+ },
+
// Callback function for include filter button click.
on_include_filter: function(ev) {
var self = this;
@@ -2038,6 +2092,83 @@ define('tools.querytool', [
queryToolActions.executeRollback(this.handler);
},
+ on_change_connection: function(connection_details, ref) {
+ let title = this.$el.find('.editor-title').html();
+ if(connection_details['title'] != title) {
+ var self = this;
+ $.ajax({
+ async: false,
+ url: url_for('datagrid.update_query_tool_connection', {
+ 'trans_id': self.transId,
+ 'sgid': connection_details['server_group'],
+ 'sid': connection_details['server'],
+ 'did': connection_details['database'],
+ }),
+ method: 'POST',
+ contentType: 'application/json',
+ data: JSON.stringify(connection_details),
+ })
+ .done(function(res) {
+ if(res.success) {
+ self.transId = res.data.tran_id;
+ self.handler.transId = res.data.tran_id;
+ self.handler.url_params = {
+ 'did': connection_details['database'],
+ 'is_query_tool': self.handler.url_params.is_query_tool,
+ 'server_type': self.handler.url_params.server_type,
+ 'sgid': connection_details['server_group'],
+ 'sid': connection_details['server'],
+ 'title': connection_details['title'],
+ };
+ self.set_editor_title(self.handler.url_params.title);
+ self.handler.setTitle(self.handler.url_params.title);
+ alertify.success('connected successfully');
+ if(ref){
+ let connection_data = {
+ 'server_group': self.handler.url_params.sgid,
+ 'server': connection_details['server'],
+ 'database': connection_details['database'],
+ 'user': connection_details['user'],
+ 'title': connection_details['title'],
+ 'role': connection_details['role'],
+ 'password': connection_details['password'],
+ 'is_allow_new_connection': true,
+ };
+ self.connection_list.unshift(connection_data);
+ self.render_connection(self.connection_list);
+ ref.close();
+ }
+ }
+ return true;
+ })
+ .fail(function(xhr) {
+ if(xhr.status == 428) {
+ alertify.connectServer('Connect to server', xhr.responseJSON.result, connection_details['server'], false);
+ } else {
+ alertify.error(xhr.responseJSON['errormsg']);
+ }
+ /*let url = url_for('sqleditor.connect_server_with_user', {
+ 'sid': newConnCollectionModel['server'],
+ 'usr': newConnCollectionModel['user']
+ });
+ $.ajax({
+ async: false,
+ url: url,
+ headers: {
+ 'Cache-Control' : 'no-cache',
+ },
+ }).done(function () {
+ Backform.Select2Control.prototype.onChange.apply(self, arguments);
+ response.server_list.forEach(function(obj){
+ if(obj.id==self.model.changed.server) {
+ response.server_name = obj.name;
+ }
+ });
+ }).fail(function(xhr){});*/
+
+ });
+ }
+ },
});
/* Defining controller class for data grid, which actually
@@ -2357,7 +2488,18 @@ define('tools.querytool', [
});
$('#btn-conn-status i').removeClass('obtaining-conn');
- self.gridView.set_editor_title(_.unescape(url_params.title));
+ self.gridView.set_editor_title(_.unescape(url_params.title), true);
+ let connection_data = {
+ 'server_group': self.gridView.handler.url_params.sgid,
+ 'server': self.gridView.handler.url_params.sid,
+ 'database': self.gridView.handler.url_params.did,
+ 'user': null,
+ 'role': null,
+ 'title': _.unescape(url_params.title),
+ 'is_allow_new_connection': false,
+ };
+ self.gridView.connection_list.unshift(connection_data);
+ self.gridView.render_connection(self.gridView.connection_list);
};
pgBrowser.Events.on('pgadmin:query_tool:connected:' + transId, afterConn);
@@ -2452,6 +2594,7 @@ define('tools.querytool', [
self.on('pgadmin-sqleditor:button:save_file', self._save_file, self);
self.on('pgadmin-sqleditor:button:deleterow', self._delete, self);
self.on('pgadmin-sqleditor:button:show_filter', self._show_filter, self);
+ self.on('pgadmin-sqleditor:button:show_new_connection', self._show_new_connection, self);
self.on('pgadmin-sqleditor:button:include_filter', self._include_filter, self);
self.on('pgadmin-sqleditor:button:exclude_filter', self._exclude_filter, self);
self.on('pgadmin-sqleditor:button:remove_filter', self._remove_filter, self);
@@ -3622,7 +3765,6 @@ define('tools.querytool', [
}
};
},
-
// This function will show the filter in the text area.
_show_filter: function() {
let self = this,
@@ -3637,7 +3779,19 @@ define('tools.querytool', [
}
FilterHandler.dialog(self, reconnect);
},
+ // This function will show the new connection.
+ _show_new_connection: function() {
+ let self = this,
+ reconnect = false;
+ /* When server is disconnected and connected, connection is lost,
+ * To reconnect pass true
+ */
+ if (arguments.length > 0 && arguments[arguments.length - 1] == 'connect') {
+ reconnect = true;
+ }
+ newConnectionHandler.dialog(self, reconnect);
+ },
// This function will include the filter by selection.
_include_filter: function() {
var self = this,
diff --git a/web/pgadmin/tools/sqleditor/static/scss/_sqleditor.scss b/web/pgadmin/tools/sqleditor/static/scss/_sqleditor.scss
index fd1e5d3..53f2449 100644
--- a/web/pgadmin/tools/sqleditor/static/scss/_sqleditor.scss
+++ b/web/pgadmin/tools/sqleditor/static/scss/_sqleditor.scss
@@ -30,6 +30,19 @@
color: $sql-title-fg;
}
+.connection-info {
+ background: $sql-title-bg;
+ color: $sql-title-fg;
+ width:100%;
+ display: inherit;
+}
+
+.conn-info-dd {
+ padding-top: 0.3em;
+ padding-left: 0.2em;
+ cursor: pointer;
+}
+
#editor-panel {
z-index: 0;
diff --git a/web/pgadmin/tools/sqleditor/tests/test_new_connection_database.py b/web/pgadmin/tools/sqleditor/tests/test_new_connection_database.py
new file mode 100644
index 0000000..20fe3e3
--- /dev/null
+++ b/web/pgadmin/tools/sqleditor/tests/test_new_connection_database.py
@@ -0,0 +1,98 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+import json
+from pgadmin.utils.route import BaseTestGenerator
+from regression import parent_node_dict
+from regression.test_setup import config_data
+from regression.python_test_utils import test_utils as utils
+
+
+class TestNewConnectionDatabase(BaseTestGenerator):
+ """ This class will test new connection database. """
+ scenarios = [
+ ('New connection dialog',
+ dict(
+ url="/sqleditor/new_connection_database/",
+ is_positive_test=True,
+ mocking_required=False,
+ is_server_conn_required=False,
+ test_data={},
+ mock_data={},
+ expected_data={
+ "status_code": 200
+ }
+ )),
+ ('New connection dialog connect server',
+ dict(
+ url="/sqleditor/new_connection_database/",
+ is_positive_test=True,
+ mocking_required=False,
+ is_server_conn_required=True,
+ test_data={},
+ mock_data={},
+ expected_data={
+ "status_code": 200
+ }
+ )),
+ ('New connection dialog negative',
+ dict(
+ url="/sqleditor/new_connection_database/",
+ is_positive_test=False,
+ mocking_required=False,
+ is_server_conn_required=True,
+ test_data={},
+ mock_data={},
+ expected_data={
+ "status_code": 200
+ }
+ )),
+ ]
+
+ def setUp(self):
+ self.sid = parent_node_dict["server"][-1]["server_id"]
+ self.sgid = config_data['server_group']
+
+ def get_database(self):
+ response = self.tester.get(
+ self.url + str(self.sgid) + '/' + str(self.sid),
+ content_type='html/json'
+ )
+
+ return response
+
+ def runTest(self):
+ if self.is_positive_test:
+ if self.is_server_conn_required:
+ self.server['password'] = self.server['db_password']
+ server_response = self.tester.post(
+ '/browser/server/connect/{0}/{1}'.format(
+ utils.SERVER_GROUP,
+ self.sid),
+ data=json.dumps(self.server),
+ content_type='html/json'
+ )
+ response = self.get_database()
+ actual_response_code = response.status_code
+ expected_response_code = self.expected_data['status_code']
+ else:
+ if self.is_server_conn_required:
+ self.server['password'] = self.server['db_password']
+ server_response = self.tester.post(
+ '/browser/server/connect/{0}/{1}'.format(
+ utils.SERVER_GROUP,
+ self.sid),
+ data=json.dumps(self.server),
+ content_type='html/json'
+ )
+ self.sid = 0
+ response = self.get_database()
+ actual_response_code = response.status_code
+ expected_response_code = self.expected_data['status_code']
+ self.assertEqual(actual_response_code, expected_response_code)
diff --git a/web/pgadmin/tools/sqleditor/tests/test_new_connection_dialog.py b/web/pgadmin/tools/sqleditor/tests/test_new_connection_dialog.py
new file mode 100644
index 0000000..75a47ef
--- /dev/null
+++ b/web/pgadmin/tools/sqleditor/tests/test_new_connection_dialog.py
@@ -0,0 +1,50 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+import json
+from pgadmin.utils.route import BaseTestGenerator
+from regression import parent_node_dict
+from regression.test_setup import config_data
+from regression.python_test_utils import test_utils as utils
+
+
+class TestNewConnectionDialog(BaseTestGenerator):
+ """ This class will test new connection dialog. """
+ scenarios = [
+ ('New connection dialog',
+ dict(
+ url="/sqleditor/new_connection_dialog/",
+ is_positive_test=True,
+ mocking_required=False,
+ is_connect_server=False,
+ test_data={},
+ mock_data={},
+ expected_data={
+ "status_code": 200
+ }
+ )),
+ ]
+
+ def setUp(self):
+ self.sid = parent_node_dict["server"][-1]["server_id"]
+ self.sgid = config_data['server_group']
+
+ def new_connection(self):
+ response = self.tester.get(
+ self.url + str(self.sgid) + '/' + str(self.sgid),
+ content_type='html/json'
+ )
+
+ return response
+
+ def runTest(self):
+ if self.is_positive_test:
+ response = self.new_connection()
+ actual_response_code = response.status_code
+ expected_response_code = self.expected_data['status_code']
+ self.assertEqual(actual_response_code, expected_response_code)
diff --git a/web/pgadmin/tools/sqleditor/tests/test_new_connection_user.py b/web/pgadmin/tools/sqleditor/tests/test_new_connection_user.py
new file mode 100644
index 0000000..7b6c12e
--- /dev/null
+++ b/web/pgadmin/tools/sqleditor/tests/test_new_connection_user.py
@@ -0,0 +1,98 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+import json
+from pgadmin.utils.route import BaseTestGenerator
+from regression import parent_node_dict
+from regression.test_setup import config_data
+from regression.python_test_utils import test_utils as utils
+
+
+class TestNewConnectionUser(BaseTestGenerator):
+ """ This class will test new connection user. """
+ scenarios = [
+ ('New connection dialog',
+ dict(
+ url="/sqleditor/new_connection_user/",
+ is_positive_test=True,
+ mocking_required=False,
+ is_server_conn_required=False,
+ test_data={},
+ mock_data={},
+ expected_data={
+ "status_code": 200
+ }
+ )),
+ ('New connection dialog connect server',
+ dict(
+ url="/sqleditor/new_connection_user/",
+ is_positive_test=True,
+ mocking_required=False,
+ is_server_conn_required=True,
+ test_data={},
+ mock_data={},
+ expected_data={
+ "status_code": 200
+ }
+ )),
+ ('New connection dialog negative',
+ dict(
+ url="/sqleditor/new_connection_user/",
+ is_positive_test=False,
+ mocking_required=False,
+ is_server_conn_required=True,
+ test_data={},
+ mock_data={},
+ expected_data={
+ "status_code": 200
+ }
+ )),
+ ]
+
+ def setUp(self):
+ self.sid = parent_node_dict["server"][-1]["server_id"]
+ self.sgid = config_data['server_group']
+
+ def get_use(self):
+ response = self.tester.get(
+ self.url + str(self.sgid) + '/' + str(self.sid),
+ content_type='html/json'
+ )
+
+ return response
+
+ def runTest(self):
+ if self.is_positive_test:
+ if self.is_server_conn_required:
+ self.server['password'] = self.server['db_password']
+ server_response = self.tester.post(
+ '/browser/server/connect/{0}/{1}'.format(
+ utils.SERVER_GROUP,
+ self.sid),
+ data=json.dumps(self.server),
+ content_type='html/json'
+ )
+ response = self.get_use()
+ actual_response_code = response.status_code
+ expected_response_code = self.expected_data['status_code']
+ else:
+ if self.is_server_conn_required:
+ self.server['password'] = self.server['db_password']
+ server_response = self.tester.post(
+ '/browser/server/connect/{0}/{1}'.format(
+ utils.SERVER_GROUP,
+ self.sid),
+ data=json.dumps(self.server),
+ content_type='html/json'
+ )
+ self.sid = 0
+ response = self.get_use()
+ actual_response_code = response.status_code
+ expected_response_code = self.expected_data['status_code']
+ self.assertEqual(actual_response_code, expected_response_code)
diff --git a/web/pgadmin/utils/driver/psycopg2/connection.py b/web/pgadmin/utils/driver/psycopg2/connection.py
index 9cb65bc..83c2c17 100644
--- a/web/pgadmin/utils/driver/psycopg2/connection.py
+++ b/web/pgadmin/utils/driver/psycopg2/connection.py
@@ -21,7 +21,7 @@ import psycopg2
from flask import g, current_app
from flask_babelex import gettext
from flask_security import current_user
-from pgadmin.utils.crypto import decrypt
+from pgadmin.utils.crypto import decrypt, encrypt
from psycopg2.extensions import encodings
import config
@@ -211,8 +211,17 @@ class Connection(BaseConnection):
password = None
passfile = None
manager = self.manager
+ encpass = None
+ is_update_password = True
+ crypt_key_present, crypt_key = get_crypt_key()
+
+ if 'user' in kwargs and kwargs['password']:
+ password = kwargs['password']
+ kwargs.pop('password')
+ is_update_password = False
+ else:
+ encpass = kwargs['password'] if 'password' in kwargs else None
- encpass = kwargs['password'] if 'password' in kwargs else None
passfile = kwargs['passfile'] if 'passfile' in kwargs else None
tunnel_password = kwargs['tunnel_password'] if 'tunnel_password' in \
kwargs else ''
@@ -227,16 +236,16 @@ class Connection(BaseConnection):
if manager.use_ssh_tunnel == 1:
manager.check_ssh_tunnel_alive()
- if encpass is None:
- encpass = self.password or getattr(manager, 'password', None)
+ if is_update_password:
+ if encpass is None:
+ encpass = self.password or getattr(manager, 'password', None)
- self.password = encpass
+ self.password = encpass
# Reset the existing connection password
if self.reconnecting is not False:
self.password = None
- crypt_key_present, crypt_key = get_crypt_key()
if not crypt_key_present:
raise CryptKeyMissing()
@@ -269,7 +278,10 @@ class Connection(BaseConnection):
try:
database = self.db
- user = manager.user
+ if 'user' in kwargs and kwargs['user']:
+ user = kwargs['user']
+ else:
+ user = manager.user
conn_id = self.conn_id
import os
@@ -338,10 +350,10 @@ class Connection(BaseConnection):
self.wasConnected = False
raise e
- if status:
+ if status and is_update_password:
manager._update_password(encpass)
else:
- if not self.reconnecting:
+ if not self.reconnecting and is_update_password:
self.wasConnected = False
return status, msg
@@ -359,7 +371,7 @@ class Connection(BaseConnection):
else:
self.conn.autocommit = True
- def _set_role(self, manager, cur, conn_id):
+ def _set_role(self, manager, cur, conn_id, **kwargs):
"""
Set role
:param manager:
@@ -367,8 +379,18 @@ class Connection(BaseConnection):
:param conn_id:
:return:
"""
- if manager.role:
- status = self._execute(cur, "SET ROLE TO %s", [manager.role])
+ is_set_role = False
+ role = None
+
+ if 'role' in kwargs and kwargs['role']:
+ is_set_role = True
+ role = kwargs['role']
+ elif manager.role:
+ is_set_role = True
+ role = manager.role
+
+ if is_set_role:
+ status = self._execute(cur, "SET ROLE TO %s", [role])
if status is not None:
self.conn.close()
@@ -382,7 +404,7 @@ class Connection(BaseConnection):
msg=status
)
)
- return False, \
+ return True, \
_(
"Failed to setup the role with error message:\n{0}"
).format(status)
@@ -445,7 +467,7 @@ class Connection(BaseConnection):
return False, status
- is_error, errmsg = self._set_role(manager, cur, conn_id)
+ is_error, errmsg = self._set_role(manager, cur, conn_id, **kwargs)
if is_error:
return False, errmsg
@@ -491,7 +513,7 @@ WHERE db.datname = current_database()""")
if len(manager.db_info) == 1:
manager.did = res['did']
- self._set_user_info(cur, manager)
+ self._set_user_info(cur, manager, **kwargs)
self._set_server_type_and_password(kwargs, manager)
@@ -499,7 +521,7 @@ WHERE db.datname = current_database()""")
return True, None
- def _set_user_info(self, cur, manager):
+ def _set_user_info(self, cur, manager, **kwargs):
"""
Set user info.
:param cur:
@@ -517,7 +539,7 @@ WHERE db.datname = current_database()""")
WHERE
rolname = current_user""")
- if status is None:
+ if status is None and 'user' not in kwargs:
manager.user_info = dict()
if cur.rowcount > 0:
manager.user_info = cur.fetchmany(1)[0]
view thread (18+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected], [email protected]
Subject: Re: [pgAdmin][RM3794]:Allow User to Change Database Connection from an Open Query Tool Tab
In-Reply-To: <CAOBg0AOHJT4wUC3AXjHV2aorF8_OpP3erah8yhyi2eKwn6F_Sg@mail.gmail.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox