1) Added browse button to select the binary path in the Preferences. Fixes #1561

2) Added support to set the binary path for the different database server versions. Fixes #5370
This commit is contained in:
Akshay Joshi 2021-06-04 17:55:35 +05:30
parent ac8e8961ce
commit 4bc4ca1ba9
26 changed files with 930 additions and 302 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

After

Width:  |  Height:  |  Size: 237 KiB

View File

@ -211,21 +211,23 @@ files.
:align: center
Use the fields on the *Binary paths* panel to specify the path to the directory
that contains the utility programs (pg_dump, pg_restore, and pg_dumpall) for
that contains the utility programs (pg_dump, pg_dumpall, pg_restore and psql) for
monitored databases:
* Use the *EDB Advanced Server Binary Path* field to specify the location of the
EDB Postgres Advanced Server utility programs. If this path is not set,
pgAdmin will attempt to find the utilities in standard locations used by
EnterpriseDB.
* Use the *EDB Advanced Server Binary Path* grid to specify the location of the
EDB Postgres Advanced Server utility programs based on the server version.
If the respective path is not set, then pgAdmin will pick up the path for which
'Set as default' is checked else pgAdmin will attempt to find the utilities in
standard locations used by EnterpriseDB.
* Use the *Greenplum Database Binary Path* field to specify the location of the
Greenplum database utility programs. If this path is not set, pgAdmin will
attempt to find the utilities in standard locations used by Greenplum.
* Use the *PostgreSQL Binary Path* grid to specify the location of the
PostgreSQL utility programs based on the server version. If the respective
path is not set, then pgAdmin will pick up the path for which 'Set as default'
is checked else pgAdmin will attempt to find the utilities in standard
locations used by PostgreSQL.
* Use the *PostgreSQL Binary Path* field to specify the location of the
PostgreSQL utility programs. If this path is not set, pgAdmin will attempt
to find the utilities in standard locations used by PostgreSQL.
**Note:** Use the 'Validate path' button to check the existence of the utility
programs (pg_dump, pg_dumpall, pg_restore and psql) and there respective versions.
.. image:: images/preferences_paths_help.png
:alt: Preferences dialog binary path help section

View File

@ -9,9 +9,11 @@ This release contains a number of bug fixes and new features since the release o
New features
************
| `Issue #1561 <https://redmine.postgresql.org/issues/1561>`_ - Added browse button to select the binary path in the Preferences.
| `Issue #1591 <https://redmine.postgresql.org/issues/1591>`_ - Added Grant Wizard option under Package node.
| `Issue #2341 <https://redmine.postgresql.org/issues/2341>`_ - Added support to launch PSQL for the connected database server.
| `Issue #4064 <https://redmine.postgresql.org/issues/4064>`_ - Added window maximize/restore functionality for properties dialog.
| `Issue #5370 <https://redmine.postgresql.org/issues/5370>`_ - Added support to set the binary path for the different database server versions.
| `Issue #6231 <https://redmine.postgresql.org/issues/6231>`_ - Added OS, Browser, Configuration details in the About dialog.
| `Issue #6395 <https://redmine.postgresql.org/issues/6395>`_ - Added support to rotate the pgadmin log file on the basis of Size and Age.

View File

@ -658,7 +658,12 @@ ENABLE_PSQL = True
# User will able to execute the system level commands through PSQL terminal
# in pgAdmin.
ALLOW_PSQL_SHELL_COMMANDS = False
##########################################################################
# ENABLE_BINARY_PATH_BROWSING setting is used to enable the browse button
# while selecting binary path for the database server in server mode.
# In Desktop mode it is always enabled and setting is of no use.
##########################################################################
ENABLE_BINARY_PATH_BROWSING = False
##########################################################################
# Local config settings
##########################################################################

View File

@ -11,10 +11,11 @@ define('pgadmin.node.mview', [
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
'sources/pgadmin', 'pgadmin.alertifyjs', 'pgadmin.browser',
'pgadmin.backform', 'pgadmin.node.schema.dir/child',
'pgadmin.node.schema.dir/schema_child_tree_node', 'pgadmin.browser.server.privilege',
'pgadmin.node.schema.dir/schema_child_tree_node', 'sources/utils',
'pgadmin.browser.server.privilege',
], function(
gettext, url_for, $, _, pgAdmin, Alertify, pgBrowser, Backform,
schemaChild, schemaChildTreeNode
schemaChild, schemaChildTreeNode, commonUtils
) {
/**
@ -316,25 +317,7 @@ define('pgadmin.node.mview', [
return;
}
var module = 'paths',
preference_name = 'pg_bin_dir',
msg = gettext('Please configure the PostgreSQL Binary Path in the Preferences dialog.');
if ((server_data.type && server_data.type == 'ppas') ||
server_data.server_type == 'ppas') {
preference_name = 'ppas_bin_dir';
msg = gettext('Please configure the EDB Advanced Server Binary Path in the Preferences dialog.');
}
var preference = pgBrowser.get_preference(module, preference_name);
if (preference) {
if (!preference.value) {
Alertify.alert(gettext('Configuration required'), msg);
return;
}
} else {
Alertify.alert(gettext('Failed to load preference %s of module %s', preference_name, module));
if (!commonUtils.hasBinariesConfiguration(pgBrowser, server_data, this.alertify)) {
return;
}

View File

@ -9,14 +9,13 @@
import os
import sys
import json
from flask import render_template
from flask_babelex import gettext as _
from pgadmin.utils.preferences import Preferences
from werkzeug.exceptions import InternalServerError
import config
class ServerType(object):
"""
@ -61,14 +60,18 @@ class ServerType(object):
for key in cls.registry:
st = cls.registry[key]
default_path = config.DEFAULT_BINARY_PATHS.get(st.stype, "")
st.utility_path = paths.register(
'bin_paths', st.stype + '_bin_dir',
st.UTILITY_PATH_LABEL,
'text', default_path, category_label=_('Binary paths'),
help_str=st.UTILITY_PATH_HELP
)
if key == 'pg':
st.utility_path = paths.register(
'bin_paths', 'pg_bin_dir',
_("PostgreSQL Binary Path"), 'selectFile', None,
category_label=_('Binary paths')
)
elif key == 'ppas':
st.utility_path = paths.register(
'bin_paths', 'ppas_bin_dir',
_("EDB Advanced Server Binary Path"), 'selectFile', None,
category_label=_('Binary paths')
)
@property
def priority(self):
@ -120,7 +123,8 @@ class ServerType(object):
operation
)
)
bin_path = self.utility_path.get()
bin_path = self.get_utility_path(sversion)
if "$DIR" in bin_path:
# When running as an WSGI application, we will not find the
# '__file__' attribute for the '__main__' module.
@ -138,6 +142,26 @@ class ServerType(object):
(res if os.name != 'nt' else (res + '.exe'))
))
def get_utility_path(self, sverison):
"""
This function is used to get the utility path set by the user in
preferences for the specific server version, if not set then check
for any default path is set.
"""
default_path = None
bin_path_json = json.loads(self.utility_path.get())
# iterate through all the path and return appropriate value
for bin_path in bin_path_json:
if int(bin_path['version']) <= sverison < \
int(bin_path['next_major_version']) and \
bin_path['binaryPath'] is not None:
return bin_path['binaryPath']
if bin_path['isDefault']:
default_path = bin_path['binaryPath']
return default_path
# Default Server Type
ServerType('pg', _("PostgreSQL"), -1)

View File

@ -57,6 +57,9 @@ define('pgadmin.browser.utils',
pgAdmin['allow_psql_shell_commands'] = '{{ current_app.config.get('ALLOW_PSQL_SHELL_COMMANDS') }}' == 'True';
pgAdmin['platform'] = '{{platform}}';
/* GET Binary Path Browse config */
pgAdmin['enable_binary_path_browsing'] = '{{ current_app.config.get('ENABLE_BINARY_PATH_BROWSING') }}' == 'True';
// Define list of nodes on which Query tool option doesn't appears
var unsupported_nodes = pgAdmin.unsupported_nodes = [
'server_group', 'server', 'coll-tablespace', 'tablespace',

View File

@ -17,8 +17,11 @@ from pgadmin.utils.csrf import pgCSRFProtect
from pgadmin.utils.session import cleanup_session_files
from pgadmin.misc.themes import get_all_themes
from pgadmin.utils.constants import MIMETYPE_APP_JS
from pgadmin.utils.ajax import precondition_required, make_json_response
import config
from werkzeug.exceptions import InternalServerError
import subprocess
import os
import json
MODULE_NAME = 'misc'
@ -98,7 +101,8 @@ class MiscModule(PgAdminModule):
Returns:
list: a list of url endpoints exposed to the client.
"""
return ['misc.ping', 'misc.index', 'misc.cleanup']
return ['misc.ping', 'misc.index', 'misc.cleanup',
'misc.validate_binary_path']
# Initialise the module
@ -165,3 +169,48 @@ def shutdown():
return 'SHUTDOWN'
else:
return ''
##########################################################################
# A special URL used to validate the binary path
##########################################################################
@blueprint.route("/validate_binary_path",
endpoint="validate_binary_path",
methods=["POST"])
def validate_binary_path():
"""
This function is used to validate the specified utilities path by
running the utilities with there versions.
"""
data = None
if hasattr(request.data, 'decode'):
data = request.data.decode('utf-8')
if data != '':
data = json.loads(data)
version_str = ''
if 'utility_path' in data and data['utility_path'] is not None:
for utility in ['pg_dump', 'pg_dumpall', 'pg_restore', 'psql']:
full_path = os.path.abspath(
os.path.join(data['utility_path'],
(utility if os.name != 'nt' else
(utility + '.exe'))))
try:
result = subprocess.Popen([full_path, '--version'],
stdout=subprocess.PIPE)
except FileNotFoundError:
version_str += "<b>" + utility + ":</b> " + \
"not found on the specified binary path.<br/>"
continue
# Replace the name of the utility from the result to avoid
# duplicate name.
result_str = \
result.stdout.read().decode("utf-8").replace(utility, '')
version_str += "<b>" + utility + ":</b> " + result_str + "<br/>"
else:
return precondition_required(gettext('Invalid binary path.'))
return make_json_response(data=gettext(version_str), status=200)

View File

@ -1573,7 +1573,6 @@ define([
);
$('.file_manager button.rename').attr('disabled', 'disabled');
// set selected folder name in breadcrums
$('.file_manager #uploader .input-path').hide();
$('.file_manager #uploader .show_selected_file').remove();
$('<span class="show_selected_file">' + path + '</span>').appendTo(
'.file_manager #uploader .filemanager-path-group'

View File

@ -307,6 +307,8 @@ define('pgadmin.preferences', [
return 'keyboardShortcut';
case 'radioModern':
return 'radioModern';
case 'selectFile':
return 'binary-paths-grid';
default:
if (console && console.warn) {
// Warning for developer only.
@ -476,7 +478,7 @@ define('pgadmin.preferences', [
overflow: !1,
title: gettext('Preferences'),
closableByDimmer: false,
modal: false,
modal: true,
pinnable: false,
},
};

View File

@ -79,66 +79,6 @@ export class Dialog {
return serverInformation;
}
retrieveAncestorOfTypeDatabase(item) {
let databaseInfo = null;
let aciTreeItem = item || this.pgBrowser.treeMenu.selected();
let treeNode = this.pgBrowser.treeMenu.findNodeByDomElement(aciTreeItem);
if (treeNode) {
if(treeNode.getData()._type === 'database') {
databaseInfo = treeNode.getData();
} else {
let nodeData = null;
treeNode.ancestorNode(
(node) => {
nodeData = node.getData();
if(nodeData._type === 'database') {
databaseInfo = nodeData;
return true;
}
return false;
}
);
}
}
if (databaseInfo === null) {
this.alertify.alert(
gettext(this.errorAlertTitle),
gettext('Please select a database or its child node from the browser.')
);
}
return databaseInfo;
}
hasBinariesConfiguration(serverInformation) {
const module = 'paths';
let preference_name = 'pg_bin_dir';
let msg = gettext('Please configure the PostgreSQL Binary Path in the Preferences dialog.');
if ((serverInformation.type && serverInformation.type === 'ppas') ||
serverInformation.server_type === 'ppas') {
preference_name = 'ppas_bin_dir';
msg = gettext('Please configure the EDB Advanced Server Binary Path in the Preferences dialog.');
}
const preference = this.pgBrowser.get_preference(module, preference_name);
if (preference) {
if (!preference.value) {
this.alertify.alert(gettext('Configuration required'), msg);
return false;
}
} else {
this.alertify.alert(
gettext(this.errorAlertTitle),
gettext('Failed to load preference %s of module %s', preference_name, module)
);
return false;
}
return true;
}
dialogName() {
return undefined;
}

View File

@ -1115,6 +1115,120 @@ define([
};
};
Backform.BinaryPathsGridControl = Backform.Control.extend({
initialize: function() {
Backform.Control.prototype.initialize.apply(this, arguments);
var BinaryPathModel = Backbone.Model.extend({
idAttribute: 'serverType',
defaults: {
serverType: undefined,
binaryPath: undefined,
isDefault: false
},
});
this.gridColumns = [{
name: 'isDefault',
label: 'Set as default',
sortable: false,
cell: Backgrid.RadioCell,
cellHeaderClasses: 'width_percent_10',
headerCell: Backgrid.Extension.CustomHeaderCell,
deps: ['binaryPath'],
editable: function(m) {
if (!_.isUndefined(m.get('binaryPath')) && !_.isNull(m.get('binaryPath')) && m.get('binaryPath') !== '') {
return true;
} else if (!_.isUndefined(m.get('isDefault')) && !_.isNull(m.get('isDefault'))){
setTimeout(function() {
m.set('isDefault', false);
}, 10);
}
return false;
}
}, {
name: 'serverType',
label: 'Database Server',
editable: false,
cell: 'string',
cellHeaderClasses: 'width_percent_20',
headerCell: Backgrid.Extension.CustomHeaderCell,
}, {
name: 'binaryPath',
label: 'Binary Path',
sortable: false,
cell: Backgrid.Extension.SelectFileCell,
dialog_type: 'select_folder',
dialog_title: gettext('Select Folder'),
placeholder: gettext('Select binary path ...'),
browse_btn_label: gettext('Select path'),
check_btn_label: gettext('Validate utilities'),
browse_btn_visible: pgAdmin.server_mode === 'False' ? true : pgAdmin.enable_binary_path_browsing ? true : false
}];
var BinPathCollection = this.BinPathCollection = new (Backbone.Collection.extend({
model: BinaryPathModel
}))(null);
let bin_value = JSON.parse(this.model.get(this.field.get('name')));
if (this.field.get('label').indexOf('EDB') >= 0) {
let as_bin_paths = _.extend([
{'version': '90600', 'next_major_version': '100000', 'serverType': gettext('EDB Advanced Server 9.6'), 'binaryPath': null, 'isDefault': false},
{'version': '100000', 'next_major_version': '110000', 'serverType': gettext('EDB Advanced Server 10'), 'binaryPath': null, 'isDefault': false},
{'version': '110000', 'next_major_version': '120000', 'serverType': gettext('EDB Advanced Server 11'), 'binaryPath': null, 'isDefault': false},
{'version': '120000', 'next_major_version': '130000', 'serverType': gettext('EDB Advanced Server 12'), 'binaryPath': null, 'isDefault': false},
{'version': '130000', 'next_major_version': '140000', 'serverType': gettext('EDB Advanced Server 13'), 'binaryPath': null, 'isDefault': false},
], bin_value);
this.BinPathCollection.add(as_bin_paths);
} else {
let pg_bin_paths = _.extend([
{'version': '90600', 'next_major_version': '100000', 'serverType': gettext('PostgreSQL 9.6'), 'binaryPath': null, 'isDefault': false},
{'version': '100000', 'next_major_version': '110000', 'serverType': gettext('PostgreSQL 10'), 'binaryPath': null, 'isDefault': false},
{'version': '110000', 'next_major_version': '120000', 'serverType': gettext('PostgreSQL 11'), 'binaryPath': null, 'isDefault': false},
{'version': '120000', 'next_major_version': '130000', 'serverType': gettext('PostgreSQL 12'), 'binaryPath': null, 'isDefault': false},
{'version': '130000', 'next_major_version': '140000', 'serverType': gettext('PostgreSQL 13'), 'binaryPath': null, 'isDefault': false}
], bin_value);
this.BinPathCollection.add(pg_bin_paths);
}
this.listenTo(BinPathCollection, 'change', this.binPathCollectionChanged);
},
render: function() {
var self = this,
gridHeader = ['<div class=\'subnode-header\'>',
' <span class=\'control-label pg-el-sm-12\'>' + gettext(this.field.get('label')) + '</span>',
'</div>',
].join('\n'),
gridBody = $('<div class=\'pgadmin-control-group backgrid form-group pg-el-12 object subnode\'></div>').append(gridHeader);
self.grid = new Backgrid.Grid({
columns: self.gridColumns,
collection: self.BinPathCollection,
className: 'backgrid table presentation table-bordered table-noouter-border table-hover',
});
this.$el.empty();
this.$el.append(gridBody.append(self.grid.render().$el));
this.$el.append(['<span class="pg-el-sm-12 form-text text-muted help-block">' +
gettext(' Enter the directory in which the psql, pg_dump, pg_dumpall, and pg_restore' +
' utilities can be found for the corresponding database server version.' +
' The default path will be used for server versions that do not have a' +
'path specified.') + '</span>'].join('\n'));
return this;
},
binPathCollectionChanged: function() {
let bin_value = JSON.stringify(this.BinPathCollection.toJSON());
this.model.set(this.field.get('name'), bin_value, {
silent: false
});
}
});
Backform.UniqueColCollectionControl = Backform.Control.extend({
initialize: function() {
Backform.Control.prototype.initialize.apply(this, arguments);

View File

@ -10,10 +10,10 @@
define([
'sources/gettext', 'underscore', 'jquery', 'backbone', 'backform', 'backgrid', 'alertify',
'moment', 'bignumber', 'codemirror', 'sources/utils', 'sources/keyboard_shortcuts', 'sources/select2/configure_show_on_scroll',
'sources/window', 'bootstrap.datetimepicker', 'backgrid.filter', 'bootstrap.toggle',
'sources/window', 'sources/url_for', 'bootstrap.datetimepicker', 'backgrid.filter', 'bootstrap.toggle',
], function(
gettext, _, $, Backbone, Backform, Backgrid, Alertify, moment, BigNumber, CodeMirror,
commonUtils, keyboardShortcuts, configure_show_on_scroll, pgWindow
commonUtils, keyboardShortcuts, configure_show_on_scroll, pgWindow, url_for
) {
/*
* Add mechanism in backgrid to render different types of cells in
@ -2154,7 +2154,7 @@ define([
var editable = Backgrid.callByNeed(column.editable(), column, model);
var align_center = column.get('align_center') || false;
let checked = this.formatter.fromRaw(model.get(column.get('name')), model);
let id = `column.get('name')_${_.uniqueId()}`;
let id = `${column.get('name')}_${_.uniqueId()}`;
this.$el.empty();
this.$el.append(
@ -2249,6 +2249,187 @@ define([
},
});
return Backgrid;
Backgrid.RadioCell = Backgrid.BooleanCell.extend({
className: 'radio-cell',
initialize: function() {
Backgrid.BooleanCell.prototype.initialize.apply(this, arguments);
Backgrid.Extension.DependentCell.prototype.initialize.apply(this, arguments);
},
dependentChanged: function() {
return this.render();
},
enterEditMode: function() {
this.$el.addClass('editor');
$(this.$el.find('input[type=radio]')).trigger('focus');
},
exitEditMode: function() {
this.$el.removeClass('editor');
},
events: {
'change input': 'onChange',
'blur input': 'exitEditMode',
},
onChange: function(e) {
var model = this.model,
column = this.column,
val = this.formatter.toRaw(this.$input.prop('checked'), model);
this.enterEditMode();
_.each(this.model.collection.models, function(sub_model) {
sub_model.set(column.get('name'), false);
sub_model.trigger('backgrid:edited', sub_model, column, new Backgrid.Command(e));
});
// on bootstrap change we also need to change model's value
model.set(column.get('name'), val);
model.trigger('backgrid:edited', model, column, new Backgrid.Command(e));
},
render: function () {
this.$el.empty();
var model = this.model, column = this.column;
var editable = Backgrid.callByNeed(column.editable(), column, model);
let checked = this.formatter.fromRaw(model.get(column.get('name')), model);
let id = `${column.get('name')}_${_.uniqueId()}`;
this.$el.empty();
this.$el.append(
$(`<div style="text-align: center">
<input tabindex="0" type="radio" id="${id}" ${!editable?'disabled':''} ${checked?'checked':''}/>
</div>`)
);
this.$input = this.$el.find('input');
this.delegateEvents();
return this;
},
});
Backgrid.Extension.SelectFileCell = Backgrid.Cell.extend({
/** @property */
className: 'file-cell',
defaults: {
supported_types: ['*'],
dialog_type: 'select_file',
dialog_title: gettext('Select file'),
type: 'text',
value: '',
placeholder: gettext('Select file...'),
disabled: false,
browse_btn_label: gettext('Select file'),
check_btn_label: gettext('Validate file'),
browse_btn_visible: true,
validate_btn_visible: true,
},
initialize: function() {
Backgrid.Cell.prototype.initialize.apply(this, arguments);
this.data = _.extend(this.defaults, this.column.toJSON());
},
template: _.template([
'<div class="input-group">',
'<input type="<%=type%>" id="<%=cId%>" class="form-control" value="<%-value%>" placeholder="<%-placeholder%>" <%=disabled ? "disabled" : ""%> />',
'<% if (browse_btn_visible) { %>',
'<div class="input-group-append">',
'<button class="btn btn-primary-icon fa fa-ellipsis-h select_item" <%=disabled ? "disabled" : ""%> aria-hidden="true" aria-label=<%=browse_btn_label%> title=<%=browse_btn_label%>></button>',
'</div>',
'<% } %>',
'<% if (validate_btn_visible) { %>',
'<div class="input-group-append">',
'<button class="btn btn-primary-icon fa fa-clipboard-check validate_item" <%=disabled ? "disabled" : ""%> <%=(value=="" || value==null) ? "disabled" : ""%> aria-hidden="true" aria-label=<%=check_btn_label%> title=<%=check_btn_label%>></button>',
'</div>',
'<% } %>',
'</div>',
].join('\n')),
events: {
'change input': 'onChange',
'click .select_item': 'onSelect',
'click .validate_item': 'onValidate',
},
render: function() {
this.$el.empty();
this.data = _.extend(this.data, {value: this.model.get(this.column.get('name'))});
// Adding unique id
this.data['cId'] = _.uniqueId('pgC_');
this.$el.append(this.template(this.data));
this.$input = this.$el.find('input');
this.delegateEvents();
return this;
},
onChange: function() {
var model = this.model,
column = this.column,
val = this.formatter.toRaw(this.$input.prop('value'), model);
model.set(column.get('name'), val);
},
onSelect: function() {
let self = this;
var params = {
supported_types: self.data.supported_types,
dialog_type: self.data.dialog_type,
dialog_title: self.data.dialog_title
};
pgAdmin.FileManager.init();
pgAdmin.FileManager.show_dialog(params);
// Listen click events of Storage Manager dialog buttons
this.listen_file_dlg_events();
},
storage_dlg_hander: function(value) {
var attrArr = this.column.get('name').split('.'),
name = attrArr.shift();
this.remove_file_dlg_event_listeners();
// Set selected value into the model
this.model.set(name, decodeURI(value));
},
storage_close_dlg_hander: function() {
this.remove_file_dlg_event_listeners();
},
listen_file_dlg_events: function() {
pgAdmin.Browser.Events.on('pgadmin-storage:finish_btn:' + this.data.dialog_type, this.storage_dlg_hander, this);
pgAdmin.Browser.Events.on('pgadmin-storage:cancel_btn:' + this.data.dialog_type, this.storage_close_dlg_hander, this);
},
remove_file_dlg_event_listeners: function() {
pgAdmin.Browser.Events.off('pgadmin-storage:finish_btn:' + this.data.dialog_type, this.storage_dlg_hander, this);
pgAdmin.Browser.Events.off('pgadmin-storage:cancel_btn:' + this.data.dialog_type, this.storage_close_dlg_hander, this);
},
onValidate: function() {
var model = this.model,
val = this.formatter.toRaw(this.$input.prop('value'), model);
if (_.isNull(val) || val.trim() === '') {
Alertify.alert(gettext('Validate Path'), gettext('Path should not be empty.'));
}
$.ajax({
url: url_for('misc.validate_binary_path'),
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({
'utility_path': val,
}),
})
.done(function(res) {
Alertify.alert(gettext('Validate binary path'), gettext(res.data));
})
.fail(function(xhr, error) {
Alertify.pgNotifier(error, xhr, gettext('Failed to validate binary path.'));
});
},
});
return Backgrid;
});

View File

@ -0,0 +1,90 @@
//////////////////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////////////////
import gettext from 'sources/gettext';
export function retrieveAncestorOfTypeServer(pgBrowser, item, errorAlertTitle, alertify) {
let serverInformation = null;
let aciTreeItem = item || pgBrowser.treeMenu.selected();
let treeNode = pgBrowser.treeMenu.findNodeByDomElement(aciTreeItem);
if (treeNode) {
let nodeData;
let databaseNode = treeNode.ancestorNode(
(node) => {
nodeData = node.getData();
return (nodeData._type === 'database');
}
);
let isServerNode = (node) => {
nodeData = node.getData();
return nodeData._type === 'server';
};
if (databaseNode !== null) {
if (nodeData._label.indexOf('=') >= 0) {
alertify.alert(
gettext(errorAlertTitle),
gettext(
'Databases with = symbols in the name cannot be backed up or restored using this utility.'
)
);
} else {
if (databaseNode.anyParent(isServerNode))
serverInformation = nodeData;
}
} else {
if (treeNode.anyFamilyMember(isServerNode))
serverInformation = nodeData;
}
}
if (serverInformation === null) {
alertify.alert(
gettext(errorAlertTitle),
gettext('Please select server or child node from the browser tree.')
);
}
return serverInformation;
}
export function retrieveAncestorOfTypeDatabase(pgBrowser, item, errorAlertTitle, alertify) {
let databaseInfo = null;
let aciTreeItem = item || pgBrowser.treeMenu.selected();
let treeNode = pgBrowser.treeMenu.findNodeByDomElement(aciTreeItem);
if (treeNode) {
if(treeNode.getData()._type === 'database') {
databaseInfo = treeNode.getData();
} else {
let nodeData = null;
treeNode.ancestorNode(
(node) => {
nodeData = node.getData();
if(nodeData._type === 'database') {
databaseInfo = nodeData;
return true;
}
return false;
}
);
}
}
if (databaseInfo === null) {
alertify.alert(
gettext(errorAlertTitle),
gettext('Please select a database or its child node from the browser.')
);
}
return databaseInfo;
}

View File

@ -10,7 +10,7 @@
import _ from 'underscore';
import { getTreeNodeHierarchyFromIdentifier } from 'sources/tree/pgadmin_tree_node';
import $ from 'jquery';
import gettext from 'sources/gettext';
export function parseShortcutValue(obj) {
var shortcut = '';
@ -360,3 +360,51 @@ export function CSVToArray( strData, strDelimiter, quoteChar){
// Return the parsed data.
return arrData;
}
export function hasBinariesConfiguration(pgBrowser, serverInformation, alertify) {
const module = 'paths';
let preference_name = 'pg_bin_dir';
let msg = gettext('Please configure the PostgreSQL Binary Path in the Preferences dialog.');
if ((serverInformation.type && serverInformation.type === 'ppas') ||
serverInformation.server_type === 'ppas') {
preference_name = 'ppas_bin_dir';
msg = gettext('Please configure the EDB Advanced Server Binary Path in the Preferences dialog.');
}
const preference = pgBrowser.get_preference(module, preference_name);
if (preference) {
if (_.isUndefined(preference.value) || !checkBinaryPathExists(preference.value, serverInformation.version)) {
alertify.alert(gettext('Configuration required'), msg);
return false;
}
} else {
alertify.alert(
gettext('Preferences Error'),
gettext('Failed to load preference %s of module %s', preference_name, module)
);
return false;
}
return true;
}
function checkBinaryPathExists(binaryPathArray, selectedServerVersion) {
let foundDefaultPath = false,
serverSpecificPathExist = false,
binPathArray = JSON.parse(binaryPathArray);
_.each(binPathArray, function(binPath) {
if (selectedServerVersion >= binPath.version && selectedServerVersion < binPath.next_major_version) {
if (!_.isUndefined(binPath.binaryPath) && !_.isNull(binPath.binaryPath) && binPath.binaryPath.trim() !== '')
serverSpecificPathExist = true;
}
// Check for default path
if (binPath.isDefault) {
foundDefaultPath = true;
}
});
return (serverSpecificPathExist | foundDefaultPath);
}

View File

@ -12,6 +12,8 @@ import Backform from '../../../../static/js/backform.pgadmin';
import {Dialog} from '../../../../static/js/alertify/dialog';
import url_for from 'sources/url_for';
import axios from 'axios/index';
import {retrieveAncestorOfTypeServer} from 'sources/tree/tree_utils';
import {hasBinariesConfiguration} from 'sources/utils';
export class BackupDialog extends Dialog {
constructor(pgBrowser, $, alertify, BackupModel, backform = Backform) {
@ -29,13 +31,13 @@ export class BackupDialog extends Dialog {
}
draw(action, aciTreeItem, params, width=0, height=0) {
const serverInformation = this.retrieveAncestorOfTypeServer(aciTreeItem);
const serverInformation = retrieveAncestorOfTypeServer(this.pgBrowser, aciTreeItem, gettext('Backup Error'), this.alertify);
if (!serverInformation) {
return;
}
if (!this.hasBinariesConfiguration(serverInformation)) {
if (!hasBinariesConfiguration(this.pgBrowser, serverInformation, this.alertify)) {
return;
}

View File

@ -444,25 +444,7 @@ define([
return;
}
var module = 'paths',
preference_name = 'pg_bin_dir',
msg = gettext('Please configure the PostgreSQL Binary Path in the Preferences dialog.');
if ((server_data.type && server_data.type == 'ppas') ||
server_data.server_type == 'ppas') {
preference_name = 'ppas_bin_dir';
msg = gettext('Please configure the EDB Advanced Server Binary Path in the Preferences dialog.');
}
var preference = pgBrowser.get_preference(module, preference_name);
if (preference) {
if (!preference.value) {
Alertify.alert(gettext('Configuration required'), msg);
return;
}
} else {
Alertify.alert(gettext('Failed to load preference %s of module %s', preference_name, module));
if (!commonUtils.hasBinariesConfiguration(pgBrowser, server_data, Alertify)) {
return;
}

View File

@ -221,25 +221,7 @@ define([
return;
}
var module = 'paths',
preference_name = 'pg_bin_dir',
msg = gettext('Please configure the PostgreSQL Binary Path in the Preferences dialog.');
if ((server_data.type && server_data.type == 'ppas') ||
server_data.server_type == 'ppas') {
preference_name = 'ppas_bin_dir';
msg = gettext('Please configure the EDB Advanced Server Binary Path in the Preferences dialog.');
}
var preference = pgBrowser.get_preference(module, preference_name);
if (preference) {
if (!preference.value) {
Alertify.alert(gettext('Configuration required'), msg);
return;
}
} else {
Alertify.alert(gettext('Failed to load preference %s of module %s', preference_name, module));
if (!commonUtils.hasBinariesConfiguration(pgBrowser, server_data, Alertify)) {
return;
}

View File

@ -15,7 +15,8 @@ import Alertify from 'pgadmin.alertifyjs';
import {enable} from 'pgadmin.browser.toolbar';
import clipboard from 'sources/selection/clipboard';
import 'wcdocker';
import {getRandomInt} from 'sources/utils';
import {getRandomInt, hasBinariesConfiguration} from 'sources/utils';
import {retrieveAncestorOfTypeServer} from 'sources/tree/tree_utils';
import pgWindow from 'sources/window';
import {getTreeNodeHierarchyFromIdentifier} from 'sources/tree/pgadmin_tree_node';
@ -114,74 +115,12 @@ export function initialize(gettext, url_for, $, _, pgAdmin, csrfToken, Browser)
enable(gettext('PSQL Tool'), isEnabled);
return isEnabled;
},
retrieveAncestorOfTypeServer: function(item) {
let serverInformation = null;
// let aciTreeItem = item || pgBrowser.treeMenu.selected();
let treeNode = pgBrowser.treeMenu.findNodeByDomElement(item);
if (treeNode) {
let nodeData;
let databaseNode = treeNode.ancestorNode(
(node) => {
nodeData = node.getData();
return (nodeData._type === 'database');
}
);
let isServerNode = (node) => {
nodeData = node.getData();
return nodeData._type === 'server';
};
if (databaseNode !== null) {
if (nodeData._label.indexOf('=') >= 0) {
this.alertify.alert(
gettext(this.errorAlertTitle),
gettext(
'Databases with = symbols in the name cannot be backed up or restored using this utility.'
)
);
} else {
if (databaseNode.anyParent(isServerNode))
serverInformation = nodeData;
}
} else {
if (treeNode.anyFamilyMember(isServerNode))
serverInformation = nodeData;
}
}
if (serverInformation === null) {
this.alertify.alert(
gettext(this.errorAlertTitle),
gettext('Please select server or child node from the browser tree.')
);
}
return serverInformation;
},
psql_tool: function(data, aciTreeIdentifier, gen=false) {
const module = 'paths';
let preference_name = 'pg_bin_dir';
let msg = gettext('Please configure the PostgreSQL Binary Path in the Preferences dialog.');
const serverInformation = this.retrieveAncestorOfTypeServer(aciTreeIdentifier);
const serverInformation = retrieveAncestorOfTypeServer(pgBrowser, aciTreeIdentifier, gettext('PSQL Error'), Alertify);
if (!hasBinariesConfiguration(pgBrowser, serverInformation, Alertify)) {
return;
}
if ((serverInformation.type && serverInformation.type === 'ppas') ||
serverInformation.server_type === 'ppas') {
preference_name = 'ppas_bin_dir';
msg = gettext('Please configure the EDB Advanced Server Binary Path in the Preferences dialog.');
}
const preference = pgBrowser.get_preference(module, preference_name);
if (preference) {
if (!preference.value) {
Alertify.alert(gettext('Configuration required'), msg);
return false;
}
} else {
Alertify.alert(
gettext(this.errorAlertTitle),
gettext('Failed to load preference %s of module %s', preference_name, module)
);
return false;
}
const node = pgBrowser.treeMenu.findNodeByDomElement(aciTreeIdentifier);
if (node === undefined || !node.getData()) {
Alertify.alert(

View File

@ -12,6 +12,8 @@ import Backform from '../../../../static/js/backform.pgadmin';
import {Dialog} from '../../../../static/js/alertify/dialog';
import url_for from 'sources/url_for';
import axios from 'axios/index';
import {retrieveAncestorOfTypeServer} from 'sources/tree/tree_utils';
import {hasBinariesConfiguration} from 'sources/utils';
export class RestoreDialog extends Dialog {
constructor(pgBrowser, $, alertify, RestoreModel, backform = Backform) {
@ -27,14 +29,12 @@ export class RestoreDialog extends Dialog {
}
draw(action, aciTreeItem, width, height) {
const serverInformation = this.retrieveAncestorOfTypeServer(aciTreeItem);
const serverInformation = retrieveAncestorOfTypeServer(this.pgBrowser, aciTreeItem, gettext('Restore Error'), this.alertify);
if (!serverInformation) {
return;
}
if (!this.hasBinariesConfiguration(serverInformation)) {
if (!hasBinariesConfiguration(this.pgBrowser, serverInformation, this.alertify)) {
return;
}

View File

@ -10,6 +10,7 @@
import gettext from 'sources/gettext';
import {Dialog} from 'sources/alertify/dialog';
import {getPanelTitle} from 'tools/datagrid/static/js/datagrid_panel_title';
import {retrieveAncestorOfTypeDatabase} from 'sources/tree/tree_utils';
export default class SearchObjectsDialog extends Dialog {
constructor(pgBrowser, $, alertify, BackupModel, backform = null) {
@ -24,7 +25,7 @@ export default class SearchObjectsDialog extends Dialog {
}
draw(action, aciTreeItem, params, width=0, height=0) {
let dbInfo = this.retrieveAncestorOfTypeDatabase(aciTreeItem);
let dbInfo = retrieveAncestorOfTypeDatabase(this.pgBrowser, aciTreeItem, gettext('Search Objects Error'), this.alertify);
if (!dbInfo) {
return;
}

View File

@ -437,7 +437,7 @@ class Preferences(object):
assert _type in (
'boolean', 'integer', 'numeric', 'date', 'datetime',
'options', 'multiline', 'switch', 'node', 'text', 'radioModern',
'keyboardshortcut', 'select2'
'keyboardshortcut', 'select2', 'selectFile',
), "Type cannot be found in the defined list!"
(cat['preferences'])[name] = res = _Preference(

View File

@ -68,6 +68,9 @@ describe('BackupDialog', () => {
data: {
_id: 10,
_type: 'server',
label: 'some-tree-label',
server_type: 'pg',
version: 100000,
},
children: [
{
@ -88,14 +91,34 @@ describe('BackupDialog', () => {
},
],
},
{
id: 'serverTreeNodeWrongPath',
data: {
_id: 12,
_type: 'server',
label: 'some-tree-label',
server_type: 'pg',
version: 90600,
},
},
{
id: 'ppasServer',
data: {
_id: 13,
_type: 'server',
label: 'some-tree-label',
server_type: 'ppas',
children: [
{id: 'someNodeUnderneathPPASServer'},
],
version: 130000,
},
},
{
id: 'ppasServerTreeNodeWrongPath',
data: {
_id: 14,
_type: 'server',
label: 'some-tree-label',
server_type: 'ppas',
version: 90600,
},
},
],
@ -148,52 +171,42 @@ describe('BackupDialog', () => {
pgBrowser.get_preference.and.returnValue(undefined);
});
context('server is a ppas server', () => {
it('display an alert with "Backup Error"', () => {
backupDialog.draw(null, [{id: 'some_database'}], null);
context('server is a PostgreSQL server', () => {
it('display an alert with "Preferences Error"', () => {
backupDialog.draw(null, [{id: 'serverTreeNode'}], null);
expect(alertifySpy.alert).toHaveBeenCalledWith(
'Backup Error',
'Preferences Error',
'Failed to load preference pg_bin_dir of module paths'
);
});
});
context('server is not a ppas server', () => {
it('display an alert with "Backup Error"', () => {
context('server is a EPAS server', () => {
it('display an alert with "Preferences Error"', () => {
backupDialog.draw(null, [{id: 'ppasServer'}], null);
expect(alertifySpy.alert).toHaveBeenCalledWith(
'Backup Error',
'Preferences Error',
'Failed to load preference ppas_bin_dir of module paths'
);
});
});
});
context('preference can be found', () => {
context('preference can be found for PostgreSQL Server', () => {
context('binary folder is not configured', () => {
beforeEach(() => {
pgBrowser.get_preference.and.returnValue({});
pgBrowser.get_preference.and.returnValue({value: '[{\"serverType\":\"PostgreSQL 9.6\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"90600\",\"next_major_version\":\"100000\"},{\"serverType\":\"PostgreSQL 10\",\"binaryPath\":\"/Library/PostgreSQL/10/bin\",\"isDefault\":false,\"version\":\"100000\",\"next_major_version\":\"110000\"},{\"serverType\":\"PostgreSQL 11\",\"binaryPath\":\"/Library/PostgreSQL/11/bin\",\"isDefault\":false,\"version\":\"110000\",\"next_major_version\":\"120000\"},{\"serverType\":\"PostgreSQL 12\",\"binaryPath\":\"/Library/PostgreSQL/12/bin\",\"isDefault\":false,\"version\":\"120000\",\"next_major_version\":\"130000\"},{\"serverType\":\"PostgreSQL 13\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"130000\",\"next_major_version\":\"140000\"}]'});
});
context('server is a ppas server', () => {
context('server is a PostgreSQL server', () => {
it('display an alert with "Configuration required"', () => {
backupDialog.draw(null, [{id: 'serverTreeNode'}], null);
backupDialog.draw(null, [{id: 'serverTreeNodeWrongPath'}], null);
expect(alertifySpy.alert).toHaveBeenCalledWith(
'Configuration required',
'Please configure the PostgreSQL Binary Path in the Preferences dialog.'
);
});
});
context('server is not a ppas server', () => {
it('display an alert with "Configuration required"', () => {
backupDialog.draw(null, [{id: 'ppasServer'}], null);
expect(alertifySpy.alert).toHaveBeenCalledWith(
'Configuration required',
'Please configure the EDB Advanced Server Binary Path in the Preferences dialog.'
);
});
});
});
context('binary folder is configured', () => {
@ -202,12 +215,12 @@ describe('BackupDialog', () => {
backupDialogResizeToSpy = jasmine.createSpyObj('backupDialogResizeToSpy', ['resizeTo']);
alertifySpy['backup_objects'].and
.returnValue(backupDialogResizeToSpy);
pgBrowser.get_preference.and.returnValue({value: '/some/path'});
pgBrowser.get_preference.and.returnValue({value: '[{\"serverType\":\"PostgreSQL 9.6\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"90600\",\"next_major_version\":\"100000\"},{\"serverType\":\"PostgreSQL 10\",\"binaryPath\":\"/Library/PostgreSQL/10/bin\",\"isDefault\":true,\"version\":\"100000\",\"next_major_version\":\"110000\"},{\"serverType\":\"PostgreSQL 11\",\"binaryPath\":\"/Library/PostgreSQL/11/bin\",\"isDefault\":false,\"version\":\"110000\",\"next_major_version\":\"120000\"},{\"serverType\":\"PostgreSQL 12\",\"binaryPath\":\"/Library/PostgreSQL/12/bin\",\"isDefault\":false,\"version\":\"120000\",\"next_major_version\":\"130000\"},{\"serverType\":\"PostgreSQL 13\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"130000\",\"next_major_version\":\"140000\"}]'});
spyOn(backupDialog, 'url_for_utility_exists').and.returnValue('/backup/utility_exists/10/objects');
networkMock.onGet('/backup/utility_exists/10/objects').reply(200, {'success': 1});
});
it('displays the dialog', (done) => {
it('displays the dialog when binary path is for correct server version', (done) => {
backupDialog.draw(null, [{id: 'serverTreeNode'}], null, pgBrowser.stdW.md, pgBrowser.stdH.md);
setTimeout(() => {
expect(alertifySpy['backup_objects']).toHaveBeenCalledWith(true);
@ -216,6 +229,15 @@ describe('BackupDialog', () => {
}, 0);
});
it('displays the dialog when default binary path is specified', (done) => {
backupDialog.draw(null, [{id: 'serverTreeNodeWrongPath'}], null, pgBrowser.stdW.md, pgBrowser.stdH.md);
setTimeout(() => {
expect(alertifySpy['backup_objects']).toHaveBeenCalledWith(true);
expect(backupDialogResizeToSpy.resizeTo).toHaveBeenCalledWith(pgBrowser.stdW.md, pgBrowser.stdH.md);
done();
}, 0);
});
context('database label contain "="', () => {
it('should create alert dialog with backup error', (done) => {
backupDialog.draw(null, [{id: 'database_with_equal_in_name'}], null);
@ -228,6 +250,54 @@ describe('BackupDialog', () => {
});
});
});
context('preference can be found for EPAS server', () => {
context('binary folder is not configured', () => {
beforeEach(() => {
pgBrowser.get_preference.and.returnValue({value: '[{\"serverType\":\"EDB Advanced Server 9.6\",\"binaryPath\":\"\",\"isDefault\":false,\"version\":\"90600\",\"next_major_version\":\"100000\"},{\"serverType\":\"EDB Advanced Server 10\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"100000\",\"next_major_version\":\"110000\"},{\"serverType\":\"EDB Advanced Server 11\",\"binaryPath\":\"/Library/EPAS/11/bin/\",\"isDefault\":false,\"version\":\"110000\",\"next_major_version\":\"120000\"},{\"serverType\":\"EDB Advanced Server 12\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"120000\",\"next_major_version\":\"130000\"},{\"serverType\":\"EDB Advanced Server 13\",\"binaryPath\":\"/Library/EPAS/13/bin/\",\"isDefault\":false,\"version\":\"130000\",\"next_major_version\":\"140000\"}]'});
});
context('server is a EPAS server', () => {
it('display an alert with "Configuration required"', () => {
backupDialog.draw(null, [{id: 'ppasServerTreeNodeWrongPath'}], null);
expect(alertifySpy.alert).toHaveBeenCalledWith(
'Configuration required',
'Please configure the EDB Advanced Server Binary Path in the Preferences dialog.'
);
});
});
});
context('binary folder is configured', () => {
let backupDialogResizeToSpy;
beforeEach(() => {
backupDialogResizeToSpy = jasmine.createSpyObj('backupDialogResizeToSpy', ['resizeTo']);
alertifySpy['backup_objects'].and
.returnValue(backupDialogResizeToSpy);
pgBrowser.get_preference.and.returnValue({value: '[{\"serverType\":\"EDB Advanced Server 9.6\",\"binaryPath\":\"\",\"isDefault\":false,\"version\":\"90600\",\"next_major_version\":\"100000\"},{\"serverType\":\"EDB Advanced Server 10\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"100000\",\"next_major_version\":\"110000\"},{\"serverType\":\"EDB Advanced Server 11\",\"binaryPath\":\"/Library/EPAS/11/bin/\",\"isDefault\":false,\"version\":\"110000\",\"next_major_version\":\"120000\"},{\"serverType\":\"EDB Advanced Server 12\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"120000\",\"next_major_version\":\"130000\"},{\"serverType\":\"EDB Advanced Server 13\",\"binaryPath\":\"/Library/EPAS/13/bin/\",\"isDefault\":true,\"version\":\"130000\",\"next_major_version\":\"140000\"}]'});
spyOn(backupDialog, 'url_for_utility_exists').and.returnValue('/backup/utility_exists/10/objects');
networkMock.onGet('/backup/utility_exists/10/objects').reply(200, {'success': 1});
});
it('displays the dialog when binary path is for correct server version', (done) => {
backupDialog.draw(null, [{id: 'ppasServer'}], null, pgBrowser.stdW.md, pgBrowser.stdH.md);
setTimeout(() => {
expect(alertifySpy['backup_objects']).toHaveBeenCalledWith(true);
expect(backupDialogResizeToSpy.resizeTo).toHaveBeenCalledWith(pgBrowser.stdW.md, pgBrowser.stdH.md);
done();
}, 0);
});
it('displays the dialog when default binary path is specified', (done) => {
backupDialog.draw(null, [{id: 'ppasServerTreeNodeWrongPath'}], null, pgBrowser.stdW.md, pgBrowser.stdH.md);
setTimeout(() => {
expect(alertifySpy['backup_objects']).toHaveBeenCalledWith(true);
expect(backupDialogResizeToSpy.resizeTo).toHaveBeenCalledWith(pgBrowser.stdW.md, pgBrowser.stdH.md);
done();
}, 0);
});
});
});
});
});
});

View File

@ -21,8 +21,8 @@ describe('GlobalServerBackupDialog', () => {
let backupModelSpy;
let rootNode;
let serverTreeNode;
let ppasServerTreeNode;
let serverTreeNode, serverTreeNodeWrongPath;
let ppasServerTreeNode, ppasServerTreeNodeWrongPath;
beforeEach(() => {
pgBrowser = {
@ -51,12 +51,26 @@ describe('GlobalServerBackupDialog', () => {
serverTreeNode = pgBrowser.treeMenu.addNewNode('level1.1', {
_type: 'server',
_id: 10,
server_type: 'pg',
version: 100000,
}, undefined, ['level1']);
ppasServerTreeNode = pgBrowser.treeMenu.addNewNode('level1.2', {
serverTreeNodeWrongPath = pgBrowser.treeMenu.addNewNode('level1.2', {
_type: 'server',
_id: 11,
server_type: 'pg',
version: 90600,
}, undefined, ['level1']);
ppasServerTreeNode = pgBrowser.treeMenu.addNewNode('level1.3', {
_type: 'server',
server_type: 'ppas',
version: 130000,
}, undefined, ['level1']);
pgBrowser.treeMenu.addNewNode('level3', {}, undefined, ['level1', 'level1.2']);
ppasServerTreeNodeWrongPath = pgBrowser.treeMenu.addNewNode('level1.4', {
_type: 'server',
server_type: 'ppas',
version: 90600,
}, undefined, ['level1']);
pgBrowser.treeMenu.addNewNode('level3', {}, undefined, ['level1', 'level1.2', 'level1.3', 'level1.4']);
pgBrowser.treeMenu.addNewNode('level3.1', undefined, undefined, ['level1', 'level1.2', 'level3']);
});
@ -73,6 +87,7 @@ describe('GlobalServerBackupDialog', () => {
alertifySpy,
backupModelSpy
);
pgBrowser.get_preference = jasmine.createSpy('get_preferences');
});
@ -103,46 +118,113 @@ describe('GlobalServerBackupDialog', () => {
pgBrowser.get_preference.and.returnValue(undefined);
});
context('server is a ppas server', () => {
it('display an alert with "Backup Error"', () => {
context('server is a PostgreSQL server', () => {
it('display an alert with "Preferences Error"', () => {
backupDialog.draw(null, [serverTreeNode], null);
expect(alertifySpy.alert).toHaveBeenCalledWith(
'Backup Error',
'Preferences Error',
'Failed to load preference pg_bin_dir of module paths'
);
});
});
context('server is not a ppas server', () => {
it('display an alert with "Backup Error"', () => {
context('server is a EPAS server', () => {
it('display an alert with "Preferences Error"', () => {
backupDialog.draw(null, [ppasServerTreeNode], null);
expect(alertifySpy.alert).toHaveBeenCalledWith(
'Backup Error',
'Preferences Error',
'Failed to load preference ppas_bin_dir of module paths'
);
});
});
});
context('preference can be found', () => {
context('preference can be found for PostgreSQL Server', () => {
context('binary folder is not configured', () => {
beforeEach(() => {
pgBrowser.get_preference.and.returnValue({});
pgBrowser.get_preference.and.returnValue({value: '[{\"serverType\":\"PostgreSQL 9.6\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"90600\",\"next_major_version\":\"100000\"},{\"serverType\":\"PostgreSQL 10\",\"binaryPath\":\"/Library/PostgreSQL/10/bin\",\"isDefault\":false,\"version\":\"100000\",\"next_major_version\":\"110000\"},{\"serverType\":\"PostgreSQL 11\",\"binaryPath\":\"/Library/PostgreSQL/11/bin\",\"isDefault\":false,\"version\":\"110000\",\"next_major_version\":\"120000\"},{\"serverType\":\"PostgreSQL 12\",\"binaryPath\":\"/Library/PostgreSQL/12/bin\",\"isDefault\":false,\"version\":\"120000\",\"next_major_version\":\"130000\"},{\"serverType\":\"PostgreSQL 13\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"130000\",\"next_major_version\":\"140000\"}]'});
});
context('server is a ppas server', () => {
context('server is a PostgreSQL server', () => {
it('display an alert with "Configuration required"', () => {
backupDialog.draw(null, [serverTreeNode], null);
backupDialog.draw(null, [serverTreeNodeWrongPath], null);
expect(alertifySpy.alert).toHaveBeenCalledWith(
'Configuration required',
'Please configure the PostgreSQL Binary Path in the Preferences dialog.'
);
});
});
});
context('server is not a ppas server', () => {
context('binary folder is configured', () => {
let globalResizeToSpy;
let serverResizeToSpy;
beforeEach(() => {
globalResizeToSpy = jasmine.createSpyObj('globals', ['resizeTo']);
alertifySpy['BackupDialog_globals'].and
.returnValue(globalResizeToSpy);
serverResizeToSpy = jasmine.createSpyObj('server', ['resizeTo']);
alertifySpy['BackupDialog_server'].and
.returnValue(serverResizeToSpy);
pgBrowser.get_preference.and.returnValue({value: '[{\"serverType\":\"PostgreSQL 9.6\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"90600\",\"next_major_version\":\"100000\"},{\"serverType\":\"PostgreSQL 10\",\"binaryPath\":\"/Library/PostgreSQL/10/bin\",\"isDefault\":true,\"version\":\"100000\",\"next_major_version\":\"110000\"},{\"serverType\":\"PostgreSQL 11\",\"binaryPath\":\"/Library/PostgreSQL/11/bin\",\"isDefault\":false,\"version\":\"110000\",\"next_major_version\":\"120000\"},{\"serverType\":\"PostgreSQL 12\",\"binaryPath\":\"/Library/PostgreSQL/12/bin\",\"isDefault\":false,\"version\":\"120000\",\"next_major_version\":\"130000\"},{\"serverType\":\"PostgreSQL 13\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"130000\",\"next_major_version\":\"140000\"}]'});
spyOn(backupDialog, 'url_for_utility_exists').and.returnValue('/backup/utility_exists/10/servers');
networkMock.onGet('/backup/utility_exists/10/servers').reply(200, {'success': 1});
});
context('dialog for global backup ', () => {
it('displays the dialog when binary path is for correct server version', (done) => {
backupDialog.draw(null, [serverTreeNode], {globals: true}, pgBrowser.stdW.md, pgBrowser.stdH.md);
setTimeout(() => {
expect(alertifySpy['BackupDialog_globals']).toHaveBeenCalledWith(true);
expect(globalResizeToSpy.resizeTo).toHaveBeenCalledWith(pgBrowser.stdW.md, pgBrowser.stdH.md);
done();
}, 0);
});
});
context('dialog for server backup', () => {
it('displays the dialog when binary path is for correct server version', (done) => {
backupDialog.draw(null, [serverTreeNode], {server: true}, pgBrowser.stdW.md, pgBrowser.stdH.md);
setTimeout(() => {
expect(alertifySpy['BackupDialog_server']).toHaveBeenCalledWith(true);
expect(serverResizeToSpy.resizeTo).toHaveBeenCalledWith(pgBrowser.stdW.md, pgBrowser.stdH.md);
done();
}, 0);
});
});
context('dialog for global backup ', () => {
it('displays the dialog when default binary path is specified', (done) => {
backupDialog.draw(null, [serverTreeNodeWrongPath], {globals: true}, pgBrowser.stdW.md, pgBrowser.stdH.md);
setTimeout(() => {
expect(alertifySpy['BackupDialog_globals']).toHaveBeenCalledWith(true);
expect(globalResizeToSpy.resizeTo).toHaveBeenCalledWith(pgBrowser.stdW.md, pgBrowser.stdH.md);
done();
}, 0);
});
});
context('dialog for server backup', () => {
it('displays the dialog when default binary path is specified', (done) => {
backupDialog.draw(null, [serverTreeNodeWrongPath], {server: true}, pgBrowser.stdW.md, pgBrowser.stdH.md);
setTimeout(() => {
expect(alertifySpy['BackupDialog_server']).toHaveBeenCalledWith(true);
expect(serverResizeToSpy.resizeTo).toHaveBeenCalledWith(pgBrowser.stdW.md, pgBrowser.stdH.md);
done();
}, 0);
});
});
});
});
context('preference can be found for EPAS Server', () => {
context('binary folder is not configured', () => {
beforeEach(() => {
pgBrowser.get_preference.and.returnValue({value: '[{\"serverType\":\"EDB Advanced Server 9.6\",\"binaryPath\":\"\",\"isDefault\":false,\"version\":\"90600\",\"next_major_version\":\"100000\"},{\"serverType\":\"EDB Advanced Server 10\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"100000\",\"next_major_version\":\"110000\"},{\"serverType\":\"EDB Advanced Server 11\",\"binaryPath\":\"/Library/EPAS/11/bin/\",\"isDefault\":false,\"version\":\"110000\",\"next_major_version\":\"120000\"},{\"serverType\":\"EDB Advanced Server 12\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"120000\",\"next_major_version\":\"130000\"},{\"serverType\":\"EDB Advanced Server 13\",\"binaryPath\":\"/Library/EPAS/13/bin/\",\"isDefault\":false,\"version\":\"130000\",\"next_major_version\":\"140000\"}]'});
});
context('server is a EPAS server', () => {
it('display an alert with "Configuration required"', () => {
backupDialog.draw(null, [ppasServerTreeNode], null);
backupDialog.draw(null, [ppasServerTreeNodeWrongPath], null);
expect(alertifySpy.alert).toHaveBeenCalledWith(
'Configuration required',
'Please configure the EDB Advanced Server Binary Path in the Preferences dialog.'
@ -161,14 +243,14 @@ describe('GlobalServerBackupDialog', () => {
serverResizeToSpy = jasmine.createSpyObj('server', ['resizeTo']);
alertifySpy['BackupDialog_server'].and
.returnValue(serverResizeToSpy);
pgBrowser.get_preference.and.returnValue({value: '/some/path'});
pgBrowser.get_preference.and.returnValue({value: '[{\"serverType\":\"EDB Advanced Server 9.6\",\"binaryPath\":\"\",\"isDefault\":false,\"version\":\"90600\",\"next_major_version\":\"100000\"},{\"serverType\":\"EDB Advanced Server 10\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"100000\",\"next_major_version\":\"110000\"},{\"serverType\":\"EDB Advanced Server 11\",\"binaryPath\":\"/Library/EPAS/11/bin/\",\"isDefault\":false,\"version\":\"110000\",\"next_major_version\":\"120000\"},{\"serverType\":\"EDB Advanced Server 12\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"120000\",\"next_major_version\":\"130000\"},{\"serverType\":\"EDB Advanced Server 13\",\"binaryPath\":\"/Library/EPAS/13/bin/\",\"isDefault\":true,\"version\":\"130000\",\"next_major_version\":\"140000\"}]'});
spyOn(backupDialog, 'url_for_utility_exists').and.returnValue('/backup/utility_exists/10/servers');
networkMock.onGet('/backup/utility_exists/10/servers').reply(200, {'success': 1});
});
context('dialog for global backup', () => {
it('displays the dialog', (done) => {
backupDialog.draw(null, [serverTreeNode], {globals: true}, pgBrowser.stdW.md, pgBrowser.stdH.md);
context('dialog for global backup ', () => {
it('displays the dialog when binary path is for correct server version', (done) => {
backupDialog.draw(null, [ppasServerTreeNode], {globals: true}, pgBrowser.stdW.md, pgBrowser.stdH.md);
setTimeout(() => {
expect(alertifySpy['BackupDialog_globals']).toHaveBeenCalledWith(true);
expect(globalResizeToSpy.resizeTo).toHaveBeenCalledWith(pgBrowser.stdW.md, pgBrowser.stdH.md);
@ -178,8 +260,30 @@ describe('GlobalServerBackupDialog', () => {
});
context('dialog for server backup', () => {
it('displays the dialog', (done) => {
backupDialog.draw(null, [serverTreeNode], {server: true}, pgBrowser.stdW.md, pgBrowser.stdH.md);
it('displays the dialog when binary path is for correct server version', (done) => {
backupDialog.draw(null, [ppasServerTreeNode], {server: true}, pgBrowser.stdW.md, pgBrowser.stdH.md);
setTimeout(() => {
expect(alertifySpy['BackupDialog_server']).toHaveBeenCalledWith(true);
expect(serverResizeToSpy.resizeTo).toHaveBeenCalledWith(pgBrowser.stdW.md, pgBrowser.stdH.md);
done();
}, 0);
});
});
context('dialog for global backup ', () => {
it('displays the dialog when default binary path is specified', (done) => {
backupDialog.draw(null, [ppasServerTreeNodeWrongPath], {globals: true}, pgBrowser.stdW.md, pgBrowser.stdH.md);
setTimeout(() => {
expect(alertifySpy['BackupDialog_globals']).toHaveBeenCalledWith(true);
expect(globalResizeToSpy.resizeTo).toHaveBeenCalledWith(pgBrowser.stdW.md, pgBrowser.stdH.md);
done();
}, 0);
});
});
context('dialog for server backup', () => {
it('displays the dialog when default binary path is specified', (done) => {
backupDialog.draw(null, [ppasServerTreeNodeWrongPath], {server: true}, pgBrowser.stdW.md, pgBrowser.stdH.md);
setTimeout(() => {
expect(alertifySpy['BackupDialog_server']).toHaveBeenCalledWith(true);
expect(serverResizeToSpy.resizeTo).toHaveBeenCalledWith(pgBrowser.stdW.md, pgBrowser.stdH.md);

View File

@ -56,6 +56,8 @@ describe('RestoreDialog', () => {
_id: 10,
_type: 'server',
label: 'some-tree-label',
server_type: 'pg',
version: 100000,
},
children: [
{
@ -76,14 +78,34 @@ describe('RestoreDialog', () => {
},
],
},
{
id: 'serverTreeNodeWrongPath',
data: {
_id: 12,
_type: 'server',
label: 'some-tree-label',
server_type: 'pg',
version: 90600,
},
},
{
id: 'ppasServer',
data: {
_id: 13,
_type: 'server',
label: 'some-tree-label',
server_type: 'ppas',
children: [
{id: 'someNodeUnderneathPPASServer'},
],
version: 130000,
},
},
{
id: 'ppasServerTreeNodeWrongPath',
data: {
_id: 14,
_type: 'server',
label: 'some-tree-label',
server_type: 'ppas',
version: 90600,
},
},
],
@ -136,52 +158,42 @@ describe('RestoreDialog', () => {
pgBrowser.get_preference.and.returnValue(undefined);
});
context('server is a ppas server', () => {
it('display an alert with "Restore Error"', () => {
context('server is a PostgreSQL server', () => {
it('display an alert with "Preferences Error"', () => {
restoreDialog.draw(null, [{id: 'serverTreeNode'}], null);
expect(alertifySpy.alert).toHaveBeenCalledWith(
'Restore Error',
'Preferences Error',
'Failed to load preference pg_bin_dir of module paths'
);
});
});
context('server is not a ppas server', () => {
it('display an alert with "Restore Error"', () => {
context('server is a EPAS server', () => {
it('display an alert with "Preferences Error"', () => {
restoreDialog.draw(null, [{id: 'ppasServer'}], null);
expect(alertifySpy.alert).toHaveBeenCalledWith(
'Restore Error',
'Preferences Error',
'Failed to load preference ppas_bin_dir of module paths'
);
});
});
});
context('preference can be found', () => {
context('preference can be found for PostgreSQL Server', () => {
context('binary folder is not configured', () => {
beforeEach(() => {
pgBrowser.get_preference.and.returnValue({});
pgBrowser.get_preference.and.returnValue({value: '[{\"serverType\":\"PostgreSQL 9.6\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"90600\",\"next_major_version\":\"100000\"},{\"serverType\":\"PostgreSQL 10\",\"binaryPath\":\"/Library/PostgreSQL/10/bin\",\"isDefault\":false,\"version\":\"100000\",\"next_major_version\":\"110000\"},{\"serverType\":\"PostgreSQL 11\",\"binaryPath\":\"/Library/PostgreSQL/11/bin\",\"isDefault\":false,\"version\":\"110000\",\"next_major_version\":\"120000\"},{\"serverType\":\"PostgreSQL 12\",\"binaryPath\":\"/Library/PostgreSQL/12/bin\",\"isDefault\":false,\"version\":\"120000\",\"next_major_version\":\"130000\"},{\"serverType\":\"PostgreSQL 13\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"130000\",\"next_major_version\":\"140000\"}]'});
});
context('server is a ppas server', () => {
context('server is a PostgreSQL server', () => {
it('display an alert with "Configuration required"', () => {
restoreDialog.draw(null, [{id: 'serverTreeNode'}], null);
restoreDialog.draw(null, [{id: 'serverTreeNodeWrongPath'}], null);
expect(alertifySpy.alert).toHaveBeenCalledWith(
'Configuration required',
'Please configure the PostgreSQL Binary Path in the Preferences dialog.'
);
});
});
context('server is not a ppas server', () => {
it('display an alert with "Configuration required"', () => {
restoreDialog.draw(null, [{id: 'ppasServer'}], null);
expect(alertifySpy.alert).toHaveBeenCalledWith(
'Configuration required',
'Please configure the EDB Advanced Server Binary Path in the Preferences dialog.'
);
});
});
});
context('binary folder is configured', () => {
@ -190,13 +202,13 @@ describe('RestoreDialog', () => {
spy = jasmine.createSpyObj('globals', ['resizeTo']);
alertifySpy['pg_restore'].and
.returnValue(spy);
pgBrowser.get_preference.and.returnValue({value: '/some/path'});
pgBrowser.Nodes.server.label = 'some-server-label';
pgBrowser.get_preference.and.returnValue({value: '[{\"serverType\":\"PostgreSQL 9.6\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"90600\",\"next_major_version\":\"100000\"},{\"serverType\":\"PostgreSQL 10\",\"binaryPath\":\"/Library/PostgreSQL/10/bin\",\"isDefault\":true,\"version\":\"100000\",\"next_major_version\":\"110000\"},{\"serverType\":\"PostgreSQL 11\",\"binaryPath\":\"/Library/PostgreSQL/11/bin\",\"isDefault\":false,\"version\":\"110000\",\"next_major_version\":\"120000\"},{\"serverType\":\"PostgreSQL 12\",\"binaryPath\":\"/Library/PostgreSQL/12/bin\",\"isDefault\":false,\"version\":\"120000\",\"next_major_version\":\"130000\"},{\"serverType\":\"PostgreSQL 13\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"130000\",\"next_major_version\":\"140000\"}]'});
spyOn(restoreDialog, 'url_for_utility_exists').and.returnValue('/restore/utility_exists/10/objects');
networkMock.onGet('/restore/utility_exists/10/objects').reply(200, {'success': 1});
});
it('displays the dialog', (done) => {
it('displays the dialog when binary path is for correct server version', (done) => {
restoreDialog.draw(null, [{id: 'serverTreeNode'}], pgBrowser.stdW.md, pgBrowser.stdH.md);
setTimeout(() => {
expect(alertifySpy['pg_restore']).toHaveBeenCalledWith(
@ -206,6 +218,28 @@ describe('RestoreDialog', () => {
_id: 10,
_type: 'server',
label: 'some-tree-label',
server_type: 'pg',
version: 100000,
},
pgBrowser.Nodes.server
);
expect(spy.resizeTo).toHaveBeenCalledWith(pgBrowser.stdW.md, pgBrowser.stdH.md);
done();
}, 0);
});
it('displays the dialog when default binary path is specified', (done) => {
restoreDialog.draw(null, [{id: 'serverTreeNodeWrongPath'}], pgBrowser.stdW.md, pgBrowser.stdH.md);
setTimeout(() => {
expect(alertifySpy['pg_restore']).toHaveBeenCalledWith(
'Restore (some-server-label: some-tree-label)',
[{id: 'serverTreeNodeWrongPath'}],
{
_id: 12,
_type: 'server',
label: 'some-tree-label',
server_type: 'pg',
version: 90600,
},
pgBrowser.Nodes.server
);
@ -226,6 +260,77 @@ describe('RestoreDialog', () => {
});
});
});
context('preference can be found for EPAS server', () => {
context('binary folder is not configured', () => {
beforeEach(() => {
pgBrowser.get_preference.and.returnValue({value: '[{\"serverType\":\"EDB Advanced Server 9.6\",\"binaryPath\":\"\",\"isDefault\":false,\"version\":\"90600\",\"next_major_version\":\"100000\"},{\"serverType\":\"EDB Advanced Server 10\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"100000\",\"next_major_version\":\"110000\"},{\"serverType\":\"EDB Advanced Server 11\",\"binaryPath\":\"/Library/EPAS/11/bin/\",\"isDefault\":false,\"version\":\"110000\",\"next_major_version\":\"120000\"},{\"serverType\":\"EDB Advanced Server 12\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"120000\",\"next_major_version\":\"130000\"},{\"serverType\":\"EDB Advanced Server 13\",\"binaryPath\":\"/Library/EPAS/13/bin/\",\"isDefault\":false,\"version\":\"130000\",\"next_major_version\":\"140000\"}]'});
});
context('server is a EPAS server', () => {
it('display an alert with "Configuration required"', () => {
restoreDialog.draw(null, [{id: 'ppasServerTreeNodeWrongPath'}], null);
expect(alertifySpy.alert).toHaveBeenCalledWith(
'Configuration required',
'Please configure the EDB Advanced Server Binary Path in the Preferences dialog.'
);
});
});
});
context('binary folder is configured', () => {
let spy;
beforeEach(() => {
spy = jasmine.createSpyObj('globals', ['resizeTo']);
alertifySpy['pg_restore'].and
.returnValue(spy);
pgBrowser.Nodes.server.label = 'some-server-label';
pgBrowser.get_preference.and.returnValue({value: '[{\"serverType\":\"EDB Advanced Server 9.6\",\"binaryPath\":\"\",\"isDefault\":false,\"version\":\"90600\",\"next_major_version\":\"100000\"},{\"serverType\":\"EDB Advanced Server 10\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"100000\",\"next_major_version\":\"110000\"},{\"serverType\":\"EDB Advanced Server 11\",\"binaryPath\":\"/Library/EPAS/11/bin/\",\"isDefault\":false,\"version\":\"110000\",\"next_major_version\":\"120000\"},{\"serverType\":\"EDB Advanced Server 12\",\"binaryPath\":null,\"isDefault\":false,\"version\":\"120000\",\"next_major_version\":\"130000\"},{\"serverType\":\"EDB Advanced Server 13\",\"binaryPath\":\"/Library/EPAS/13/bin/\",\"isDefault\":true,\"version\":\"130000\",\"next_major_version\":\"140000\"}]'});
spyOn(restoreDialog, 'url_for_utility_exists').and.returnValue('/restore/utility_exists/10/objects');
networkMock.onGet('/restore/utility_exists/10/objects').reply(200, {'success': 1});
});
it('displays the dialog when binary path is for correct server version', (done) => {
restoreDialog.draw(null, [{id: 'ppasServer'}], pgBrowser.stdW.md, pgBrowser.stdH.md);
setTimeout(() => {
expect(alertifySpy['pg_restore']).toHaveBeenCalledWith(
'Restore (some-server-label: some-tree-label)',
[{id: 'ppasServer'}],
{
_id: 13,
_type: 'server',
label: 'some-tree-label',
server_type: 'ppas',
version: 130000,
},
pgBrowser.Nodes.server
);
expect(spy.resizeTo).toHaveBeenCalledWith(pgBrowser.stdW.md, pgBrowser.stdH.md);
done();
}, 0);
});
it('displays the dialog when default binary path is specified', (done) => {
restoreDialog.draw(null, [{id: 'ppasServerTreeNodeWrongPath'}], pgBrowser.stdW.md, pgBrowser.stdH.md);
setTimeout(() => {
expect(alertifySpy['pg_restore']).toHaveBeenCalledWith(
'Restore (some-server-label: some-tree-label)',
[{id: 'ppasServerTreeNodeWrongPath'}],
{
_id: 14,
_type: 'server',
label: 'some-tree-label',
server_type: 'ppas',
version: 90600,
},
pgBrowser.Nodes.server
);
expect(spy.resizeTo).toHaveBeenCalledWith(pgBrowser.stdW.md, pgBrowser.stdH.md);
done();
}, 0);
});
});
});
});
});
});

View File

@ -10,6 +10,7 @@ import SearchObjectsDialog from 'tools/search_objects/static/js/search_objects_d
import {TreeFake} from '../tree/tree_fake';
import MockAdapter from 'axios-mock-adapter';
import axios from 'axios/index';
import gettext from 'sources/gettext';
const context = describe;
@ -141,11 +142,11 @@ describe('SearchObjectsDialog', () => {
expect(alertifySpy['search_objects']).not.toHaveBeenCalled();
});
it('display an alert with a Backup Error', () => {
it('display an alert with a Search object Error', () => {
soDialog.draw(null, [{id: 'serverTreeNode'}], null);
expect(alertifySpy.alert).toHaveBeenCalledWith(
'Search Objects Error',
'Please select a database or its child node from the browser.'
gettext('Search Objects Error'),
gettext('Please select a database or its child node from the browser.')
);
});
});