mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Added support for the infrastructure for on demand access/create the
server connection. The BaseDriver and BaseConnection are two abstract classes, which allows us to replace the existing driver with the currently used. The current implementation supports to connect the PostgreSQL and Postgres Plus Advanced Server using the psycopg2 driver.
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
.icon-{{node_type}} {
|
||||
background-image: url('{{ url_for('NODE-%s.static' % node_type, filename='img/%s.png' % node_type )}}') !important;
|
||||
background-repeat: no-repeat;
|
||||
align-content: center;
|
||||
vertical-align: middle;
|
||||
height: 1.3em;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
.icon-server {
|
||||
background-image: url('{{ url_for('NODE-server.static', filename='img/server.png') }}') !important;
|
||||
border-radius: 10px
|
||||
}
|
||||
|
||||
.icon-server-not-connected {
|
||||
background-image: url('{{ url_for('NODE-server.static', filename='img/serverbad.png') }}') !important;
|
||||
border-radius: 10px
|
||||
}
|
||||
|
||||
.icon-server-connecting {
|
||||
background-image: url('{{ url_for('browser.static', filename='css/aciTree/image/load-node.gif')}}') !important;
|
||||
background-repeat: no-repeat;
|
||||
align-content: center;
|
||||
vertical-align: middle;
|
||||
height: 1.3em;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<form name="frmPassword" id="frmPassword" style="height: 100%; width: 100%" onsubmit="return false;">
|
||||
<div>{% if errmsg %}
|
||||
<div class="highlight has-error">
|
||||
<div class='control-label'>{{ errmsg }}</div>
|
||||
</div>{% endif %}
|
||||
<div><b>{{ _('Please enter the password for the user \'{0}\' to connect the server - "{1}"').format(username, server_label) }}</b></div>
|
||||
<div style="padding: 5px; height: 1px;"></div>
|
||||
<div style="width: 100%">
|
||||
<span style="width: 25%;display: inline-table;">Password</span>
|
||||
<span style="width: 73%;display: inline-block;">
|
||||
<input style="width:100%" id="password" class="form-control" name="password" type="password">
|
||||
</span>
|
||||
<span style="margin-left: 25%; padding-top: 15px;width: 45%;display: inline-block;">
|
||||
<input id="save_password" name="save_password" type="checkbox"> Save Password
|
||||
</span>
|
||||
</div>
|
||||
<div style="padding: 5px; height: 1px;"></div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -1,6 +1,6 @@
|
||||
define(
|
||||
['jquery', 'underscore', 'pgadmin', 'pgadmin.browser', 'alertify'],
|
||||
function($, _, pgAdmin, pgBrowser, alertify) {
|
||||
['jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', 'alertify'],
|
||||
function($, _, S, pgAdmin, pgBrowser, alertify) {
|
||||
|
||||
if (!pgBrowser.Nodes['server']) {
|
||||
pgAdmin.Browser.Nodes['server'] = pgAdmin.Browser.Node.extend({
|
||||
@@ -29,76 +29,99 @@ function($, _, pgAdmin, pgBrowser, alertify) {
|
||||
name: 'drop_server', node: 'server', module: this,
|
||||
applies: ['object', 'context'], callback: 'delete_obj',
|
||||
category: 'drop', priority: 3, label: '{{ _('Drop Server...') }}',
|
||||
icon: 'fa fa-trash'
|
||||
icon: 'fa fa-trash', enable: 'is_not_connected'
|
||||
},{
|
||||
name: 'connect_server', node: 'server', module: this,
|
||||
applies: ['object', 'context'], callback: 'connect_server',
|
||||
category: 'connect', priority: 4, label: '{{ _('Connect Server...') }}',
|
||||
icon: 'fa fa-link', enable : 'is_not_connected'
|
||||
},
|
||||
{
|
||||
name: 'disconnect_server', node: 'server', module: this,
|
||||
applies: ['object', 'context'], callback: 'disconnect_server',
|
||||
category: 'drop', priority: 5, label: '{{ _('Disconnect Server...') }}',
|
||||
icon: 'fa fa-chain-broken', enable : 'is_connected'
|
||||
}]);
|
||||
},
|
||||
is_not_connected: function(node) {
|
||||
return (node && node.connected != true);
|
||||
},
|
||||
is_connected: function(node) {
|
||||
return (node && node.connected == true);
|
||||
},
|
||||
callbacks: {
|
||||
// Add a server
|
||||
create_server: function (item) {
|
||||
var alert = alertify.prompt(
|
||||
'{{ _('Create a server') }}',
|
||||
'{{ _('Enter a name for the new server') }}',
|
||||
'',
|
||||
function(evt, value) {
|
||||
var d = tree.itemData(item);
|
||||
if (d._type != 'server-group') {
|
||||
d = tree.itemData(tree.parent(item));
|
||||
}
|
||||
$.post(
|
||||
"{{ url_for('browser.index') }}server/obj/" + d.refid + '/' + d.id + '/',
|
||||
{ name: value }
|
||||
)
|
||||
.done(function(data) {
|
||||
if (data.success == 0) {
|
||||
report_error(data.errormsg, data.info);
|
||||
} else {
|
||||
var item = {
|
||||
id: data.data.id,
|
||||
label: data.data.name,
|
||||
inode: true,
|
||||
open: false,
|
||||
icon: 'icon-server-not-connected'
|
||||
}
|
||||
tree.append(null, {
|
||||
itemData: item
|
||||
});
|
||||
/* Connect the server */
|
||||
connect_server: function(args){
|
||||
var input = args || {};
|
||||
obj = this,
|
||||
t = pgBrowser.tree,
|
||||
i = input.item || t.selected(),
|
||||
d = i && i.length == 1 ? t.itemData(i) : undefined;
|
||||
|
||||
if (!d)
|
||||
return false;
|
||||
|
||||
connect_to_server(obj, d, t, i);
|
||||
return false;
|
||||
},
|
||||
/* Disconnect the server */
|
||||
disconnect_server: function(args) {
|
||||
var input = args || {};
|
||||
obj = this,
|
||||
t = pgBrowser.tree,
|
||||
i = input.item || t.selected(),
|
||||
d = i && i.length == 1 ? t.itemData(i) : undefined;
|
||||
|
||||
if (!d)
|
||||
return false;
|
||||
|
||||
alertify.confirm(
|
||||
'{{ _('Disconnect the server') }}',
|
||||
S('{{ _('Are you sure you want to disconnect the server - %%s ?') }}').sprintf(d.label).value(),
|
||||
function(evt) {
|
||||
$.ajax({
|
||||
url: obj.generate_url('connect', d, true),
|
||||
type:'DELETE',
|
||||
success: function(res) {
|
||||
if (res.success == 1) {
|
||||
alertify.success("{{ _('" + res.info + "') }}");
|
||||
t.removeIcon(i);
|
||||
d.connected = false;
|
||||
d.icon = 'icon-server-not-connected';
|
||||
t.addIcon(i, {icon: d.icon});
|
||||
t.unload(i);
|
||||
t.setInode(i);
|
||||
}
|
||||
});
|
||||
},
|
||||
null
|
||||
);
|
||||
alert.show();
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
try {
|
||||
var err = $.parseJSON(xhr.responseText);
|
||||
if (err.success == 0) {
|
||||
msg = S('{{ _(' + err.errormsg + ')}}').value();
|
||||
alertify.error("{{ _('" + err.errormsg + "') }}");
|
||||
}
|
||||
} catch (e) {}
|
||||
t.unload(i);
|
||||
}
|
||||
});
|
||||
},
|
||||
function(evt) {
|
||||
return true;
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
/* Connect the server (if not connected), before opening this node */
|
||||
beforeopen: function(o) {
|
||||
o.browser.tree.removeIcon(o.item);
|
||||
if (o.data.connected) {
|
||||
o.browser.tree.addIcon(o.item, {icon: 'icon-server-connected'});
|
||||
} else {
|
||||
o.browser.tree.addIcon(o.item, {icon: 'icon-server-not-connected'});
|
||||
}
|
||||
var data = o.data;
|
||||
|
||||
if(!data || data._type != 'server') {
|
||||
return false;
|
||||
}
|
||||
|
||||
o.browser.tree.addIcon(o.item, {icon: data.icon});
|
||||
if (!data.connected) {
|
||||
alertify.confirm(
|
||||
'{{ _('Connect to server') }}',
|
||||
'{{ _('Do you want to connect the server?') }}',
|
||||
function(evt) {
|
||||
$.post(
|
||||
"{{ url_for('browser.index') }}server/connect/" + data.refid + '/'
|
||||
).done(function(data) {
|
||||
if (data.success == 0) {
|
||||
report_error(data.errormsg, data.info);
|
||||
}
|
||||
}).fail(function() {});
|
||||
return true;
|
||||
},
|
||||
function(evt) {
|
||||
return true;
|
||||
}
|
||||
);
|
||||
connect_to_server(this, data, o.browser.tree, o.item);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -107,40 +130,61 @@ function($, _, pgAdmin, pgBrowser, alertify) {
|
||||
model: pgAdmin.Browser.Node.Model.extend({
|
||||
defaults: {
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
sslmode: 'prefer'
|
||||
name: null,
|
||||
sslmode: 'prefer',
|
||||
host: null,
|
||||
port: 5432,
|
||||
db: null,
|
||||
username: null,
|
||||
role: null
|
||||
},
|
||||
schema: [{
|
||||
id: 'id', label: 'ID', type: 'int', group: null,
|
||||
id: 'id', label: '{{ _('ID') }}', type: 'int', group: null,
|
||||
mode: ['properties']
|
||||
},{
|
||||
id: 'name', label:'Name', type: 'text', group: null,
|
||||
id: 'name', label:'{{ _('Name') }}', type: 'text', group: null,
|
||||
mode: ['properties', 'edit', 'create']
|
||||
},{
|
||||
id: 'connected', label:'Connected', type: 'text', group: null,
|
||||
id: 'connected', label:'{{ _('Connected') }}', type: 'text', group: null,
|
||||
mode: ['properties']
|
||||
},{
|
||||
id: 'version', label:'Version', type: 'text', group: null,
|
||||
id: 'version', label:'{{ _('Version') }}', type: 'text', group: null,
|
||||
mode: ['properties'], show: 'isConnected'
|
||||
},{
|
||||
id: 'comment', label:'Comments:', type: 'multiline', group: null,
|
||||
mode: ['properties', 'edit', 'create'], disable: 'notEditMode'
|
||||
id: 'comment', label:'{{ _('Comments:') }}', type: 'multiline', group: null,
|
||||
mode: ['properties', 'edit', 'create'], disabled: 'notEditMode'
|
||||
},{
|
||||
id: 'host', label:'Host Name/Address', type: 'text', group: "Connection",
|
||||
mode: ['properties', 'edit', 'create']
|
||||
id: 'host', label:'{{ _('Host Name/Address') }}', type: 'text', group: "Connection",
|
||||
mode: ['properties', 'edit', 'create'], disabled: 'isConnected'
|
||||
},{
|
||||
id: 'port', label:'Port', type: 'int', group: "Connection",
|
||||
mode: ['properties', 'edit', 'create']
|
||||
id: 'port', label:'{{ _('Port') }}', type: 'int', group: "Connection",
|
||||
mode: ['properties', 'edit', 'create'], disabled: 'isConnected'
|
||||
},{
|
||||
id: 'db', label:'Maintenance Database', type: 'text', group: "Connection",
|
||||
mode: ['properties', 'edit', 'create']
|
||||
id: 'db', label:'{{ _('Maintenance Database') }}', type: 'text', group: "Connection",
|
||||
mode: ['properties', 'edit', 'create'], disabled: 'isConnected'
|
||||
},{
|
||||
id: 'username', label:'User Name', type: 'text', group: "Connection",
|
||||
mode: ['properties', 'edit', 'create']
|
||||
id: 'username', label:'{{ _('User Name') }}', type: 'text', group: "Connection",
|
||||
mode: ['properties', 'edit', 'create'], disabled: 'isConnected'
|
||||
},{
|
||||
id: 'sslmode', label:'SSL Mode', type: 'options', group: "Connection",
|
||||
mode: ['properties', 'edit', 'create'],
|
||||
'options': [{label:'Allow', value:'allow'}, {label: 'Prefer', value:'prefer'}, {label: 'Require', value: 'require'}, {label: 'Disable', value:'disable'}, {label:'Verify-CA', value: 'verify-ca'}, {label:'Verify-Full', value:'verify-full'}]
|
||||
id: 'role', label:'{{ _('Role') }}', type: 'text', group: "Connection",
|
||||
mode: ['properties', 'edit', 'create'], disabled: 'isConnected'
|
||||
},{
|
||||
id: 'sslmode', label:'{{ _('SSL Mode') }}', type: 'options', group: "Connection",
|
||||
mode: ['properties', 'edit', 'create'], disabled: 'isConnected',
|
||||
'options': [
|
||||
{label: 'Allow', value: 'allow'},
|
||||
{label: 'Prefer', value: 'prefer'},
|
||||
{label: 'Require', value: 'require'},
|
||||
{label: 'Disable', value: 'disable'},
|
||||
{label: 'Verify-CA', value: 'verify-ca'},
|
||||
{label: 'Verify-Full', value: 'verify-full'}
|
||||
]
|
||||
},{
|
||||
id: 'server_type', label: '{{ _('Server Type') }}', type: 'options',
|
||||
mode: ['properties'], show: 'isConnected',
|
||||
'options': [{% set cnt = 1 %}{% for server_type in server_types %}{% if cnt != 1 %},{% endif %}
|
||||
{label: '{{ server_type.description }}', value: '{{ server_type.type}}'}{% set cnt = cnt + 1 %}{% endfor %}
|
||||
]
|
||||
}],
|
||||
validate: function(attrs, options) {
|
||||
if (!this.isNew() && 'id' in this.changed) {
|
||||
@@ -151,13 +195,145 @@ function($, _, pgAdmin, pgBrowser, alertify) {
|
||||
}
|
||||
return null;
|
||||
},
|
||||
isConnected: function(mode) {
|
||||
return mode == 'properties' && this.get('connected');
|
||||
isConnected: function(model) {
|
||||
return model.get('connected');
|
||||
}
|
||||
})
|
||||
});
|
||||
function connect_to_server(obj, data, tree, item) {
|
||||
var onFailure = function(xhr, status, error, _model, _data, _tree, _item) {
|
||||
|
||||
tree.setInode(_item);
|
||||
tree.addIcon(_item, {icon: 'icon-server-not-connected'});
|
||||
|
||||
alertify.pgNotifier('error', xhr, error, function(msg) {
|
||||
setTimeout(function() {
|
||||
alertify.dlgServerPass(
|
||||
'{{ _('Connect to Server') }}',
|
||||
msg, _model, _data, _tree, _item
|
||||
).resizeTo();
|
||||
}, 100);
|
||||
});
|
||||
},
|
||||
onSuccess = function(res, model, data, tree, item) {
|
||||
tree.deselect(item);
|
||||
tree.setInode(item);
|
||||
|
||||
if (res && res.data) {
|
||||
if(typeof res.data.connected == 'boolean') {
|
||||
data.connected = res.data.connected;
|
||||
}
|
||||
if (typeof res.data.icon == 'string') {
|
||||
tree.removeIcon(item);
|
||||
data.icon = res.data.icon;
|
||||
tree.addIcon(item, {icon: data.icon});
|
||||
}
|
||||
|
||||
alertify.success(res.info);
|
||||
setTimeout(function() {tree.select(item);}, 10);
|
||||
setTimeout(function() {tree.open(item);}, 100);
|
||||
}
|
||||
};
|
||||
|
||||
// Ask Password and send it back to the connect server
|
||||
if (!alertify.dlgServerPass) {
|
||||
alertify.dialog('dlgServerPass', function factory() {
|
||||
return {
|
||||
main: function(title, message, model, data, tree, item) {
|
||||
this.set('title', title);
|
||||
this.message = message;
|
||||
this.tree = tree;
|
||||
this.nodeData = data;
|
||||
this.nodeItem = item;
|
||||
this.nodeModel = model;
|
||||
},
|
||||
setup:function() {
|
||||
return {
|
||||
buttons:[
|
||||
{
|
||||
text: "{{ _('OK') }}", key: 13, className: "btn btn-primary"
|
||||
},
|
||||
{
|
||||
text: "{{ _('Cancel') }}", className: "btn btn-danger"
|
||||
}
|
||||
],
|
||||
focus: { element: '#password', select: true },
|
||||
options: {
|
||||
modal: 0, resizable: false, maximizable: false, pinnable: false
|
||||
}
|
||||
};
|
||||
},
|
||||
build:function() {},
|
||||
prepare:function() {
|
||||
this.setContent(this.message);
|
||||
},
|
||||
callback: function(closeEvent) {
|
||||
var _sdata = this.nodeData,
|
||||
_tree = this.tree,
|
||||
_item = this.nodeItem,
|
||||
_model = this.nodeModel;
|
||||
|
||||
if (closeEvent.button.text == "{{ _('OK') }}") {
|
||||
|
||||
var _url = _model.generate_url('connect', _sdata, true);
|
||||
|
||||
_tree.setLeaf(_item);
|
||||
_tree.removeIcon(_item);
|
||||
_tree.addIcon(_item, {icon: 'icon-server-connecting'});
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
timeout: 30000,
|
||||
url: _url,
|
||||
data: $('#frmPassword').serialize(),
|
||||
success: function(res) {
|
||||
return onSuccess(
|
||||
res, _model, _sdata, _tree, _item
|
||||
);
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
return onFailure(
|
||||
xhr, status, error, _model, _sdata, _tree, _item
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
_tree.setInode(_item);
|
||||
_tree.removeIcon(_item);
|
||||
_tree.addIcon(_item, {icon: 'icon-server-not-connected'});
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
alertify.confirm(
|
||||
'{{ _('Connect to server') }}',
|
||||
'{{ _('Do you want to connect the server?') }}',
|
||||
function(evt) {
|
||||
url = obj.generate_url("connect", data, true);
|
||||
$.post(url)
|
||||
.done(
|
||||
function(res) {
|
||||
if (res.success == 1) {
|
||||
return onSuccess(res, obj, data, tree, item);
|
||||
}
|
||||
})
|
||||
.fail(
|
||||
function(xhr, status, error) {
|
||||
return onFailure(xhr, status, error, obj, data, tree, item);
|
||||
});
|
||||
},
|
||||
notEditMode: function(mode) {
|
||||
return mode != 'edit';
|
||||
}})
|
||||
});
|
||||
function() {});
|
||||
}
|
||||
/* Send PING to indicate that session is alive */
|
||||
function server_status(server_id)
|
||||
{
|
||||
url = "/ping";
|
||||
$.post(url)
|
||||
.done(function(data) { return true})
|
||||
.fail(function(xhr, status, error) { return false})
|
||||
}
|
||||
}
|
||||
|
||||
return pgBrowser.Nodes['server'];
|
||||
|
||||
Reference in New Issue
Block a user