Allow user to change the database connection from an open query tool tab. Fixes #3794
parent
228d4bb321
commit
be7bb81a19
Binary file not shown.
After Width: | Height: | Size: 48 KiB |
Binary file not shown.
After Width: | Height: | Size: 45 KiB |
|
@ -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.
|
||||
|
|
|
@ -10,6 +10,7 @@ New features
|
|||
************
|
||||
|
||||
| `Issue #1402 <https://redmine.postgresql.org/issues/1402>`_ - Added Macro support.
|
||||
| `Issue #3794 <https://redmine.postgresql.org/issues/3794>`_ - Allow user to change the database connection from an open query tool tab.
|
||||
| `Issue #5200 <https://redmine.postgresql.org/issues/5200>`_ - Added support to ignore the owner while comparing objects in the Schema Diff tool
|
||||
|
||||
Housekeeping
|
||||
|
|
|
@ -1247,7 +1247,7 @@ class ServerNode(PGChildNodeView):
|
|||
}
|
||||
)
|
||||
|
||||
def connect(self, gid, sid):
|
||||
def connect(self, gid, sid, user_name=None):
|
||||
"""
|
||||
Connect the Server and return the connection object.
|
||||
Verification Process before Connection:
|
||||
|
@ -1368,7 +1368,8 @@ class ServerNode(PGChildNodeView):
|
|||
# not provided, or password has not been saved earlier.
|
||||
if prompt_password or prompt_tunnel_password:
|
||||
return self.get_response_for_password(server, 428, prompt_password,
|
||||
prompt_tunnel_password)
|
||||
prompt_tunnel_password,
|
||||
user=user_name)
|
||||
|
||||
status = True
|
||||
try:
|
||||
|
@ -1802,7 +1803,8 @@ class ServerNode(PGChildNodeView):
|
|||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
def get_response_for_password(self, server, status, prompt_password=False,
|
||||
prompt_tunnel_password=False, errmsg=None):
|
||||
prompt_tunnel_password=False, errmsg=None,
|
||||
user=None):
|
||||
|
||||
if server.use_ssh_tunnel:
|
||||
return make_json_response(
|
||||
|
@ -1829,7 +1831,7 @@ class ServerNode(PGChildNodeView):
|
|||
result=render_template(
|
||||
'servers/password.html',
|
||||
server_label=server.name,
|
||||
username=server.username,
|
||||
username=user if user else server.username,
|
||||
errmsg=errmsg,
|
||||
service=server.service,
|
||||
_=gettext,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -95,6 +95,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"""
|
||||
|
@ -176,6 +185,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."""
|
||||
|
|
|
@ -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 tab_title = '';
|
||||
if(newConnCollectionModel['role']) {
|
||||
tab_title = selected_database_name + '/' + newConnCollectionModel['role'] + '@' + response.server_name;
|
||||
} else {
|
||||
tab_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(tab_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': tab_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;
|
|
@ -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;
|
||||
let url = self.field.get('url');
|
||||
|
||||
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) {
|
||||
let local_self = self;
|
||||
if(!alertify.connectServer){
|
||||
alertify.dialog('connectServer', function factory() {
|
||||
return {
|
||||
main: function(
|
||||
title, message, server_id, submit_password=true
|
||||
) {
|
||||
this.set('title', title);
|
||||
this.message = message;
|
||||
this.server_id = server_id;
|
||||
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('sqleditor.connect_server', {'sid': this.server_id});
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
timeout: 30000,
|
||||
url: _url,
|
||||
data: $('#frmPassword').serialize(),
|
||||
})
|
||||
.done(function() {
|
||||
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);
|
||||
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, local_self.getValueFromDOM());
|
||||
});
|
||||
} else {
|
||||
response.password = $('#password').val();
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
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(),
|
||||
'usr': self.model.attributes.user,
|
||||
});
|
||||
$.ajax({
|
||||
async: false,
|
||||
url: url,
|
||||
type: 'POST',
|
||||
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;
|
||||
}
|
|
@ -92,6 +92,7 @@
|
|||
right: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.pg-prop-status-bar {
|
||||
|
|
|
@ -18,22 +18,23 @@ 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.tools.sqleditor.utils.macros import get_user_macros
|
||||
from pgadmin.utils.constants import MIMETYPE_APP_JS, UNAUTH_REQ
|
||||
|
||||
MODULE_NAME = 'datagrid'
|
||||
|
||||
|
@ -74,7 +75,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):
|
||||
|
@ -324,10 +326,48 @@ 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 _connect(conn, **kwargs):
|
||||
"""
|
||||
Connect the database.
|
||||
:param conn: Connection instance.
|
||||
:param kwargs: user, role and password data from user.
|
||||
:return:
|
||||
"""
|
||||
user = None
|
||||
role = None
|
||||
password = None
|
||||
is_ask_password = False
|
||||
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()
|
||||
|
||||
return status, msg, is_ask_password, user, role, password
|
||||
|
||||
|
||||
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:
|
||||
|
@ -338,24 +378,41 @@ 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)
|
||||
|
||||
if connect:
|
||||
status, msg = conn.connect()
|
||||
status, msg, is_ask_password, user, role, password = _connect(
|
||||
conn, **kwargs)
|
||||
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()
|
||||
|
@ -377,10 +434,77 @@ 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
|
||||
|
||||
|
||||
@blueprint.route(
|
||||
'/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 = 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 make_json_response(
|
||||
data={
|
||||
'connId': str(conn_id),
|
||||
'serverVersion': manager.version,
|
||||
'serverVersion': version,
|
||||
'tran_id': new_trans_id
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -417,8 +417,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">
|
||||
|
@ -481,6 +490,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}},
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
##########################################################################
|
||||
#
|
||||
# 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 pgadmin.utils.exception import ExecuteError
|
||||
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 ExecuteError("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)
|
|
@ -0,0 +1,90 @@
|
|||
##########################################################################
|
||||
#
|
||||
# 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 pgadmin.utils.exception import ExecuteError
|
||||
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 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 ExecuteError("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 ExecuteError("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)
|
|
@ -0,0 +1,78 @@
|
|||
##########################################################################
|
||||
#
|
||||
# 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
|
||||
from pgadmin.utils.exception import ExecuteError
|
||||
|
||||
|
||||
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 ExecuteError("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 ExecuteError("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)
|
|
@ -0,0 +1,121 @@
|
|||
##########################################################################
|
||||
#
|
||||
# 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
|
||||
from pgadmin.utils.exception import ExecuteError
|
||||
|
||||
|
||||
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 ExecuteError("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 ExecuteError("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)
|
|
@ -0,0 +1,92 @@
|
|||
##########################################################################
|
||||
#
|
||||
# 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
|
||||
from pgadmin.utils.exception import ExecuteError
|
||||
|
||||
|
||||
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 ExecuteError("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 ExecuteError("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)
|
|
@ -0,0 +1,109 @@
|
|||
##########################################################################
|
||||
#
|
||||
# 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
|
||||
from pgadmin.utils.exception import ExecuteError
|
||||
|
||||
|
||||
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 ExecuteError("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 ExecuteError("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 ExecuteError("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)
|
|
@ -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
|
|
@ -10,17 +10,15 @@
|
|||
"""A blueprint module implementing the sqleditor frame."""
|
||||
import os
|
||||
import pickle
|
||||
import sys
|
||||
import re
|
||||
|
||||
import simplejson as json
|
||||
from flask import Response, url_for, render_template, session, request, \
|
||||
current_app
|
||||
from flask_babelex import gettext
|
||||
from flask_security import login_required, current_user
|
||||
from urllib.parse import unquote
|
||||
|
||||
import simplejson as json
|
||||
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 pgadmin.misc.file_manager import Filemanager
|
||||
from pgadmin.tools.sqleditor.command import QueryToolCommand
|
||||
from pgadmin.tools.sqleditor.utils.constant_definition import ASYNC_OK, \
|
||||
|
@ -32,11 +30,11 @@ from pgadmin.tools.sqleditor.utils.update_session_grid_transaction import \
|
|||
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, make_response as ajax_response
|
||||
success_return, internal_server_error
|
||||
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,13 +42,16 @@ 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.tools.sqleditor.utils.macros import get_macros,\
|
||||
get_user_macros, set_macros
|
||||
from pgadmin.utils.constants import MIMETYPE_APP_JS, \
|
||||
SERVER_CONNECTION_CLOSED, ERROR_MSG_TRANS_ID_NOT_FOUND, ERROR_FETCHING_DATA
|
||||
from pgadmin.model import Server
|
||||
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry
|
||||
|
||||
MODULE_NAME = 'sqleditor'
|
||||
TRANSACTION_STATUS_CHECK_FAILED = gettext("Transaction status check failed.")
|
||||
_NODES_SQL = 'nodes.sql'
|
||||
|
||||
|
||||
class SqlEditorModule(PgAdminModule):
|
||||
|
@ -114,7 +115,13 @@ class SqlEditorModule(PgAdminModule):
|
|||
'sqleditor.clear_query_history',
|
||||
'sqleditor.get_macro',
|
||||
'sqleditor.get_macros',
|
||||
'sqleditor.set_macros'
|
||||
'sqleditor.set_macros',
|
||||
'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):
|
||||
|
@ -230,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)
|
||||
|
||||
|
@ -376,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)
|
||||
|
@ -686,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,
|
||||
|
@ -759,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 = ''
|
||||
|
@ -813,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 = ''
|
||||
|
@ -866,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
|
||||
|
||||
|
@ -910,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
|
||||
|
||||
|
@ -1052,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
|
||||
|
@ -1088,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
|
||||
|
||||
|
@ -1133,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
|
||||
|
||||
|
@ -1185,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(
|
||||
|
@ -1472,6 +1478,282 @@ def get_filter_data(trans_id):
|
|||
return FilterDialog.get(status, error_msg, conn, trans_obj, session_ob)
|
||||
|
||||
|
||||
@blueprint.route(
|
||||
'/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:
|
||||
return make_json_response(
|
||||
data={
|
||||
'status': False,
|
||||
'msg': ERROR_FETCHING_DATA,
|
||||
'result': {
|
||||
'server_list': []
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@blueprint.route(
|
||||
'/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:
|
||||
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_CONNECTION_CLOSED,
|
||||
'result': {
|
||||
'database_list': [],
|
||||
}
|
||||
}
|
||||
)
|
||||
except Exception:
|
||||
return make_json_response(
|
||||
data={
|
||||
'status': False,
|
||||
'msg': ERROR_FETCHING_DATA,
|
||||
'result': {
|
||||
'database_list': [],
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@blueprint.route(
|
||||
'/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_CONNECTION_CLOSED,
|
||||
'result': {
|
||||
'user_list': [],
|
||||
}
|
||||
}
|
||||
)
|
||||
except Exception:
|
||||
return make_json_response(
|
||||
data={
|
||||
'status': False,
|
||||
'msg': 'Unable to fetch data.',
|
||||
'result': {
|
||||
'user_list': [],
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@blueprint.route(
|
||||
'/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_CONNECTION_CLOSED,
|
||||
'result': {
|
||||
'user_list': [],
|
||||
}
|
||||
}
|
||||
)
|
||||
except Exception:
|
||||
return make_json_response(
|
||||
data={
|
||||
'status': False,
|
||||
'msg': 'Unable to fetch data.',
|
||||
'result': {
|
||||
'user_list': [],
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@blueprint.route(
|
||||
'/connect_server/<int:sid>/<usr>',
|
||||
methods=["POST"],
|
||||
endpoint="connect_server_with_user"
|
||||
)
|
||||
@blueprint.route(
|
||||
'/connect_server/<int:sid>',
|
||||
methods=["POST"],
|
||||
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:
|
||||
user = manager.user
|
||||
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_name=user)
|
||||
|
||||
|
||||
@blueprint.route(
|
||||
'/filter_dialog/<int:trans_id>',
|
||||
methods=["PUT"], endpoint='set_filter_data'
|
||||
|
|
|
@ -315,10 +315,6 @@ input.editor-checkbox:focus {
|
|||
padding: 10px 0px;
|
||||
}
|
||||
|
||||
.editor-title {
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.connection-status-hide {
|
||||
display: none !important;
|
||||
}
|
||||
|
@ -396,7 +392,6 @@ input.editor-checkbox:focus {
|
|||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
|
||||
/* Macros */
|
||||
|
||||
.macro-tab {
|
||||
|
@ -424,3 +419,7 @@ input.editor-checkbox:focus {
|
|||
.macro_dialog .pg-prop-status-bar {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.new-connection-dialog-style {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
|
@ -53,8 +55,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,
|
||||
|
@ -98,6 +100,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
|
||||
|
@ -163,6 +168,35 @@ define('tools.querytool', [
|
|||
'click .btn-macro': 'on_execute_macro',
|
||||
},
|
||||
|
||||
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,
|
||||
|
@ -213,6 +247,7 @@ define('tools.querytool', [
|
|||
|
||||
set_editor_title: function(title) {
|
||||
this.$el.find('.editor-title').text(title);
|
||||
this.render_connection(this.connection_list);
|
||||
},
|
||||
|
||||
// This function is used to render the template.
|
||||
|
@ -696,6 +731,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.
|
||||
|
@ -1607,6 +1644,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;
|
||||
|
@ -2070,6 +2118,83 @@ define('tools.querytool', [
|
|||
queryToolActions.executeMacro(this.handler, macroId);
|
||||
},
|
||||
|
||||
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){});*/
|
||||
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
|
@ -2393,6 +2518,17 @@ define('tools.querytool', [
|
|||
|
||||
$('#btn-conn-status i').removeClass('obtaining-conn');
|
||||
self.gridView.set_editor_title(_.unescape(url_params.title));
|
||||
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);
|
||||
|
@ -2487,6 +2623,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);
|
||||
|
@ -3696,7 +3833,6 @@ define('tools.querytool', [
|
|||
}
|
||||
};
|
||||
},
|
||||
|
||||
// This function will show the filter in the text area.
|
||||
_show_filter: function() {
|
||||
let self = this,
|
||||
|
@ -3711,7 +3847,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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
##########################################################################
|
||||
#
|
||||
# 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. """
|
||||
API_URL = "/sqleditor/new_connection_database/"
|
||||
scenarios = [
|
||||
('New connection dialog',
|
||||
dict(
|
||||
url=API_URL,
|
||||
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=API_URL,
|
||||
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=API_URL,
|
||||
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.content_type = 'html/json'
|
||||
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=self.content_type
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
def runTest(self):
|
||||
if self.is_positive_test:
|
||||
if self.is_server_conn_required:
|
||||
self.server['password'] = self.server['db_password']
|
||||
self.tester.post(
|
||||
'/browser/server/connect/{0}/{1}'.format(
|
||||
utils.SERVER_GROUP,
|
||||
self.sid),
|
||||
data=json.dumps(self.server),
|
||||
content_type=self.content_type
|
||||
)
|
||||
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']
|
||||
self.tester.post(
|
||||
'/browser/server/connect/{0}/{1}'.format(
|
||||
utils.SERVER_GROUP,
|
||||
self.sid),
|
||||
data=json.dumps(self.server),
|
||||
content_type=self.content_type
|
||||
)
|
||||
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)
|
|
@ -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)
|
|
@ -0,0 +1,100 @@
|
|||
##########################################################################
|
||||
#
|
||||
# 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. """
|
||||
API_URL = '/sqleditor/new_connection_user/'
|
||||
scenarios = [
|
||||
('New connection dialog',
|
||||
dict(
|
||||
url=API_URL,
|
||||
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=API_URL,
|
||||
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=API_URL,
|
||||
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.content_type = 'html/json'
|
||||
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=self.content_type
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
def runTest(self):
|
||||
if self.is_positive_test:
|
||||
if self.is_server_conn_required:
|
||||
self.server['password'] = self.server['db_password']
|
||||
self.tester.post(
|
||||
'/browser/server/connect/{0}/{1}'.format(
|
||||
utils.SERVER_GROUP,
|
||||
self.sid),
|
||||
data=json.dumps(self.server),
|
||||
content_type=self.content_type
|
||||
)
|
||||
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']
|
||||
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)
|
|
@ -44,3 +44,5 @@ ERROR_MSG_TRANS_ID_NOT_FOUND = gettext(
|
|||
# Role module constant
|
||||
ERROR_FETCHING_ROLE_INFORMATION = gettext(
|
||||
'Error fetching role information from the database server.')
|
||||
|
||||
ERROR_FETCHING_DATA = gettext('Unable to fetch data.')
|
||||
|
|
|
@ -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
|
||||
|
@ -204,6 +204,45 @@ class Connection(BaseConnection):
|
|||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
def _check_user_password(self, kwargs):
|
||||
"""
|
||||
Check user and password.
|
||||
"""
|
||||
password = None
|
||||
encpass = None
|
||||
is_update_password = True
|
||||
|
||||
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
|
||||
|
||||
return password, encpass, is_update_password
|
||||
|
||||
def _decode_password(self, encpass, manager, password, crypt_key):
|
||||
if encpass:
|
||||
# Fetch Logged in User Details.
|
||||
user = User.query.filter_by(id=current_user.id).first()
|
||||
|
||||
if user is None:
|
||||
return True, self.UNAUTHORIZED_REQUEST, password
|
||||
|
||||
try:
|
||||
password = decrypt(encpass, crypt_key)
|
||||
# password is in bytes, for python3 we need it in string
|
||||
if isinstance(password, bytes):
|
||||
password = password.decode()
|
||||
except Exception as e:
|
||||
manager.stop_ssh_tunnel()
|
||||
current_app.logger.exception(e)
|
||||
return True, \
|
||||
_(
|
||||
"Failed to decrypt the saved password.\nError: {0}"
|
||||
).format(str(e))
|
||||
return False, '', password
|
||||
|
||||
def connect(self, **kwargs):
|
||||
if self.conn:
|
||||
if self.conn.closed:
|
||||
|
@ -212,11 +251,13 @@ class Connection(BaseConnection):
|
|||
return True, None
|
||||
|
||||
pg_conn = None
|
||||
password = None
|
||||
passfile = None
|
||||
manager = self.manager
|
||||
crypt_key_present, crypt_key = get_crypt_key()
|
||||
|
||||
password, encpass, is_update_password = self._check_user_password(
|
||||
kwargs)
|
||||
|
||||
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 ''
|
||||
|
@ -231,38 +272,23 @@ 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()
|
||||
|
||||
if encpass:
|
||||
# Fetch Logged in User Details.
|
||||
user = User.query.filter_by(id=current_user.id).first()
|
||||
|
||||
if user is None:
|
||||
return False, self.UNAUTHORIZED_REQUEST
|
||||
|
||||
try:
|
||||
password = decrypt(encpass, crypt_key)
|
||||
# password is in bytes, for python3 we need it in string
|
||||
if isinstance(password, bytes):
|
||||
password = password.decode()
|
||||
except Exception as e:
|
||||
manager.stop_ssh_tunnel()
|
||||
current_app.logger.exception(e)
|
||||
return False, \
|
||||
_(
|
||||
"Failed to decrypt the saved password.\nError: {0}"
|
||||
).format(str(e))
|
||||
is_error, errmsg, password = self._decode_password(encpass, manager,
|
||||
password, crypt_key)
|
||||
if is_error:
|
||||
return False, errmsg
|
||||
|
||||
# If no password credential is found then connect request might
|
||||
# come from Query tool, ViewData grid, debugger etc tools.
|
||||
|
@ -273,7 +299,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
|
||||
|
@ -342,10 +371,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
|
||||
|
@ -363,7 +392,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:
|
||||
|
@ -371,8 +400,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()
|
||||
|
@ -386,7 +425,7 @@ class Connection(BaseConnection):
|
|||
msg=status
|
||||
)
|
||||
)
|
||||
return False, \
|
||||
return True, \
|
||||
_(
|
||||
"Failed to setup the role with error message:\n{0}"
|
||||
).format(status)
|
||||
|
@ -449,7 +488,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
|
||||
|
||||
|
@ -495,7 +534,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)
|
||||
|
||||
|
@ -503,7 +542,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:
|
||||
|
@ -521,7 +560,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]
|
||||
|
|
Loading…
Reference in New Issue