From fb1ef9ac0b1cd7598fce545b656ce23b97e3f1e1 Mon Sep 17 00:00:00 2001 From: Khushboo Vashi Date: Fri, 29 Jun 2018 15:14:37 +0100 Subject: [PATCH] Properly support backups in Directory format. Fixes #3309 --- docs/en_US/release_notes_3_2.rst | 2 +- .../file_manager/static/js/create_dialogue.js | 162 ++++ .../file_manager/static/js/file_manager.js | 704 +----------------- .../misc/file_manager/static/js/helpers.js | 38 + .../file_manager/static/js/select_dialogue.js | 134 ++++ .../misc/file_manager/static/js/utility.js | 16 +- web/pgadmin/static/js/backform.pgadmin.js | 6 + web/pgadmin/tools/backup/__init__.py | 15 +- web/pgadmin/tools/backup/static/js/backup.js | 16 +- .../tests/test_backup_create_job_unit_test.py | 25 + web/pgadmin/tools/restore/__init__.py | 2 +- .../tools/restore/static/js/restore.js | 16 +- .../test_restore_create_job_unit_test.py | 26 + web/regression/feature_utils/pgadmin_page.py | 1 + .../file_manager/file_manager_specs.js | 55 ++ 15 files changed, 504 insertions(+), 714 deletions(-) create mode 100644 web/pgadmin/misc/file_manager/static/js/create_dialogue.js create mode 100644 web/pgadmin/misc/file_manager/static/js/helpers.js create mode 100644 web/pgadmin/misc/file_manager/static/js/select_dialogue.js create mode 100644 web/regression/javascript/file_manager/file_manager_specs.js diff --git a/docs/en_US/release_notes_3_2.rst b/docs/en_US/release_notes_3_2.rst index 74dc4402a..5b87a95b7 100644 --- a/docs/en_US/release_notes_3_2.rst +++ b/docs/en_US/release_notes_3_2.rst @@ -16,4 +16,4 @@ Features Bug fixes ********* -| `Bug #???? `_ - Fix foo! +| `Bug #3309 `_ - Fix Directory format support for backups. diff --git a/web/pgadmin/misc/file_manager/static/js/create_dialogue.js b/web/pgadmin/misc/file_manager/static/js/create_dialogue.js new file mode 100644 index 000000000..8deb72004 --- /dev/null +++ b/web/pgadmin/misc/file_manager/static/js/create_dialogue.js @@ -0,0 +1,162 @@ +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 {removeTransId, set_last_traversed_dir} from './helpers'; + +// Declare the Create mode dialog +module.exports = Alertify.dialog('createModeDlg', function() { + // Dialog property + return { + setup: function() { + return { + buttons: [{ + text: gettext('Create'), + key: 13, + className: 'btn btn-primary fa fa-file file_manager_create file_manager_ok pg-alertify-button disabled', + }, + { + text: gettext('Cancel'), + key: 27, + className: 'btn btn-danger fa fa-times file_manager_create_cancel pg-alertify-button', + }, + ], + focus: { + element: 0, + }, + options: { + closableByDimmer: false, + maximizable: false, + closable: false, + movable: true, + }, + }; + }, + replace_file: function() { + var $yesBtn = $('.replace_file .btn_yes'), + $noBtn = $('.replace_file .btn_no'); + + $('.storage_dialog #uploader .input-path').attr('disabled', true); + $('.file_manager_ok').addClass('disabled'); + $('.replace_file, .fm_dimmer').show(); + + $yesBtn.on('click',() => { + $('.replace_file, .fm_dimmer').hide(); + $yesBtn.off(); + $noBtn.off(); + var newFile = $('.storage_dialog #uploader .input-path').val(); + + pgAdmin.Browser.Events.trigger('pgadmin-storage:finish_btn:create_file', newFile); + $('.file_manager_create_cancel').trigger('click'); + $('.storage_dialog #uploader .input-path').attr('disabled', false); + $('.file_manager_ok').removeClass('disabled'); + }); + + $noBtn.on('click',() => { + $('.replace_file, .fm_dimmer').hide(); + $yesBtn.off(); + $noBtn.off(); + $('.storage_dialog #uploader .input-path').attr('disabled', false); + $('.file_manager_ok').removeClass('disabled'); + }); + }, + is_file_exist: function() { + var full_path = $('.storage_dialog #uploader .input-path').val(), + path = full_path.substr(0, full_path.lastIndexOf('/') + 1), + selected_item = full_path.substr(full_path.lastIndexOf('/') + 1), + is_exist = false; + + var file_data = { + 'path': path, + 'name': selected_item, + 'mode': 'is_file_exist', + }; + + $.ajax({ + type: 'POST', + data: JSON.stringify(file_data), + url: url_for('file_manager.filemanager', { + 'trans_id': this.trans_id, + }), + dataType: 'json', + contentType: 'application/x-download; charset=utf-8', + async: false, + success: function(resp) { + var data = resp.data.result; + if (data['Code'] === 1) { + is_exist = true; + } else { + is_exist = false; + } + }, + }); + return is_exist; + }, + check_permission: function(path) { + var permission = false, + post_data = { + 'path': path, + 'mode': 'permission', + }; + + $.ajax({ + type: 'POST', + data: JSON.stringify(post_data), + url: url_for('file_manager.filemanager', { + 'trans_id': this.trans_id, + }), + dataType: 'json', + contentType: 'application/json; charset=utf-8', + async: false, + success: function(resp) { + var data = resp.data.result; + if (data.Code === 1) { + permission = true; + } else { + $('.file_manager_ok').addClass('disabled'); + Alertify.error(data.Error); + } + }, + error: function() { + $('.file_manager_ok').addClass('disabled'); + Alertify.error(gettext('Error occurred while checking access permission.')); + }, + }); + return permission; + }, + callback: function(closeEvent) { + if (closeEvent.button.text == gettext('Create')) { + var newFile = $('.storage_dialog #uploader .input-path').val(), + file_data = { + 'path': $('.currentpath').val(), + }, + innerbody; + + if (!this.check_permission(newFile)) { + closeEvent.cancel = true; + return; + } + + if (!_.isUndefined(newFile) && newFile !== '' && this.is_file_exist()) { + this.replace_file(); + closeEvent.cancel = true; + } else { + pgAdmin.Browser.Events.trigger('pgadmin-storage:finish_btn:create_file', newFile); + innerbody = $(this.elements.body).find('.storage_content'); + $(innerbody).find('*').off(); + innerbody.remove(); + removeTransId(this.trans_id); + } + + set_last_traversed_dir(file_data, this.trans_id); + } else if (closeEvent.button.text == gettext('Cancel')) { + innerbody = $(this.elements.body).find('.storage_content'); + $(innerbody).find('*').off(); + innerbody.remove(); + removeTransId(this.trans_id); + pgAdmin.Browser.Events.trigger('pgadmin-storage:cancel_btn:create_file'); + } + }, + }; +}, true, 'fileSelectionDlg'); diff --git a/web/pgadmin/misc/file_manager/static/js/file_manager.js b/web/pgadmin/misc/file_manager/static/js/file_manager.js index 11fa2e78d..1dccd79b2 100644 --- a/web/pgadmin/misc/file_manager/static/js/file_manager.js +++ b/web/pgadmin/misc/file_manager/static/js/file_manager.js @@ -1,3 +1,6 @@ +import './select_dialogue'; +import './create_dialogue'; + define('misc.file_manager', [ 'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'sources/pgadmin', 'pgadmin.alertifyjs', @@ -22,708 +25,13 @@ define('misc.file_manager', [ this.initialized = true; - // Send a request to get transaction id - var getTransId = function(configs) { - return $.ajax({ - data: configs, - type: 'POST', - async: false, - url: url_for('file_manager.get_trans_id'), - dataType: 'json', - contentType: 'application/json; charset=utf-8', - }); - }; - - // Function to remove trans id from session - var removeTransId = function(trans_id) { - return $.ajax({ - type: 'GET', - async: false, - url: url_for('file_manager.delete_trans_id', { - 'trans_id': trans_id, - }), - dataType: 'json', - contentType: 'application/json; charset=utf-8', - }); - }; - - var set_last_traversed_dir = function(path, trans_id) { - return $.ajax({ - url: url_for('file_manager.save_last_dir', { - 'trans_id': trans_id, - }), - type: 'POST', - data: JSON.stringify(path), - contentType: 'application/json', - }); - }; - // Declare the Storage dialog - Alertify.dialog('storageManagerDlg', function() { - // Dialog containter - var $container = $('
'), - trans_id; - - /* - * Function: renderStoragePanel - * - * Renders the FileManager in the content div based on the given - * configuration parameters. - */ - var renderStoragePanel = function(params) { - /* - * Clear the existing html in the storage content - */ - var content = $container.find('.storage_content'); - content.empty(); - $.get(url_for('file_manager.index'), function(data) { - content.append(data); - }); - - var transId = getTransId(params); - var t_res; - if (transId.readyState == 4) { - t_res = JSON.parse(transId.responseText); - } - trans_id = t_res.data.fileTransId; - }; - - // Dialog property - return { - main: function(params) { - // Set title and button name - var self = this; - if (_.isUndefined(params['dialog_title'])) { - params['dialog_title'] = 'Storage manager'; - } - this.set('title', params['dialog_title']); - if (_.isUndefined(params['btn_primary'])) { - params['btn_primary'] = 'Select'; - } - this.set('label', params['btn_primary']); - - params = JSON.stringify(params); - $container.find('.storage_content').remove(); - $container.append('
'); - renderStoragePanel(params); - this.elements.dialog.style.minWidth = '630px'; - this.show(); - setTimeout(function() { - $($container.find('.file_manager')).on('enter-key', function() { - $($(self.elements.footer).find('.file_manager_ok')).trigger('click'); - }); - }, 200); - }, - settings: { - label: undefined, - }, - settingUpdated: function(key, oldValue, newValue) { - switch (key) { - case 'message': - this.setMessage(newValue); - break; - case 'label': - if (this.__internal.buttons[0].element) { - this.__internal.buttons[0].element.innerHTML = newValue; - } - break; - default: - break; - } - }, - prepare: function() { - this.__internal.buttons[0].element.disabled = true; - }, - setup: function() { - return { - buttons: [{ - text: gettext('Select'), - className: 'btn btn-primary fa fa-file file_manager_ok pg-alertify-button disabled', - }, - { - text: gettext('Cancel'), - className: 'btn btn-danger fa fa-times pg-alertify-button', - }, - ], - focus: { - element: 0, - }, - options: { - closableByDimmer: false, - - }, - }; - }, - callback: function(closeEvent) { - var innerbody; - if (closeEvent.button.text == gettext('Select')) { - var newFile = $('.storage_dialog #uploader .input-path').val(), - file_data = { - 'path': $('.currentpath').val(), - }; - - pgAdmin.Browser.Events.trigger('pgadmin-storage:finish_btn:storage_dialog', newFile); - - set_last_traversed_dir(file_data, trans_id); - innerbody = $(this.elements.body).find('.storage_content'); - $(innerbody).find('*').off(); - innerbody.remove(); - removeTransId(trans_id); - } else if (closeEvent.button.text == gettext('Cancel')) { - innerbody = $(this.elements.body).find('.storage_content'); - $(innerbody).find('*').off(); - innerbody.remove(); - removeTransId(trans_id); - pgAdmin.Browser.Events.trigger('pgadmin-storage:cancel_btn:storage_dialog'); - } - }, - build: function() { - this.elements.content.appendChild($container.get(0)); - }, - hooks: { - onshow: function() { - $(this.elements.body).addClass('pgadmin-storage-body'); - }, - }, - }; - }); - - // Declare the Selection dialog - Alertify.dialog('fileSelectionDlg', function() { - // Dialog containter - var $container = - $('
'), - trans_id; - - // Send a request to get transaction id - /* - * Function: renderStoragePanel - * - * Renders the FileManager in the content div based on the given - * configuration parameters. - */ - var renderStoragePanel = function(configs) { - /* - * Clear the existing html in the storage content - */ - var content = $container.find('.storage_content'); - content.empty(); - - $.get(url_for('file_manager.index'), function(data) { - content.append(data); - }); - - var transId = getTransId(configs); - var t_res; - if (transId.readyState == 4) { - t_res = JSON.parse(transId.responseText); - } - trans_id = t_res.data.fileTransId; - }; - - // Dialog property - return { - main: function(params) { - // Set title and button name - var self = this; - if (_.isUndefined(params['dialog_title'])) { - params['dialog_title'] = 'Select file'; - } - this.set('title', params['dialog_title']); - if (_.isUndefined(params['btn_primary'])) { - params['btn_primary'] = 'Select'; - } - this.set('label', params['btn_primary']); - - params = JSON.stringify(params); - $container.find('.storage_content').remove(); - $container.append('
'); - renderStoragePanel(params); - this.elements.dialog.style.minWidth = '630px'; - this.show(); - setTimeout(function() { - $($container.find('.file_manager')).on('enter-key', function() { - $($(self.elements.footer).find('.file_manager_ok')).trigger('click'); - }); - }, 200); - }, - settings: { - label: undefined, - }, - settingUpdated: function(key, oldValue, newValue) { - switch (key) { - case 'message': - this.setMessage(newValue); - break; - case 'label': - if (this.__internal.buttons[0].element) { - this.__internal.buttons[0].element.innerHTML = newValue; - } - break; - default: - break; - } - }, - prepare: function() { - this.__internal.buttons[0].element.disabled = true; - }, - setup: function() { - return { - buttons: [{ - text: gettext('Select'), - key: 13, - className: 'btn btn-primary fa fa-file file_manager_ok pg-alertify-button disabled', - }, - { - text: gettext('Cancel'), - key: 27, - className: 'btn btn-danger fa fa-times pg-alertify-button', - }, - ], - focus: { - element: 0, - }, - options: { - closableByDimmer: false, - maximizable: false, - closable: false, - movable: true, - }, - }; - }, - callback: function(closeEvent) { - var innerbody; - - if (closeEvent.button.text == gettext('Select')) { - var newFile = $('.storage_dialog #uploader .input-path').val(), - file_data = { - 'path': $('.currentpath').val(), - }; - - pgAdmin.Browser.Events.trigger('pgadmin-storage:finish_btn:select_file', newFile); - innerbody = $(this.elements.body).find('.storage_content'); - $(innerbody).find('*').off(); - innerbody.remove(); - removeTransId(trans_id); - // Ajax call to store the last directory visited once user press select button - - set_last_traversed_dir(file_data, trans_id); - } else if (closeEvent.button.text == gettext('Cancel')) { - innerbody = $(this.elements.body).find('.storage_content'); - $(innerbody).find('*').off(); - innerbody.remove(); - removeTransId(trans_id); - pgAdmin.Browser.Events.trigger('pgadmin-storage:cancel_btn:select_file'); - } - }, - build: function() { - this.elements.content.appendChild($container.get(0)); - }, - hooks: { - onshow: function() { - $(this.elements.body).addClass('pgadmin-storage-body'); - }, - }, - }; - }); - - // Declare the Folder Selection dialog - Alertify.dialog('folderSelectionDlg', function() { - // Dialog containter - var $container = - $('
'), - trans_id; - - // send a request to get transaction id - /* - * Function: renderStoragePanel - * - * Renders the FileManager in the content div based on the given - * configuration parameters. - */ - var renderStoragePanel = function(params) { - /* - * Clear the existing html in the storage content - */ - var content = $container.find('.storage_content'); - content.empty(); - - $.get(url_for('file_manager.index'), function(data) { - content.append(data); - }); - - var transId = getTransId(params); - var t_res; - if (transId.readyState == 4) { - t_res = JSON.parse(transId.responseText); - } - trans_id = t_res.data.fileTransId; - }; - - // Dialog property - return { - main: function(params) { - var self = this; - // Set title and button name - if (_.isUndefined(params['dialog_title'])) { - params['dialog_title'] = 'Select folder'; - } - this.set('title', params['dialog_title']); - if (_.isUndefined(params['btn_primary'])) { - params['btn_primary'] = 'Select'; - } - this.set('label', params['btn_primary']); - - params = JSON.stringify(params); - $container.find('.storage_content').remove(); - $container.append('
'); - renderStoragePanel(params); - this.elements.dialog.style.minWidth = '630px'; - this.show(); - setTimeout(function() { - $($container.find('.file_manager')).on('enter-key', function() { - $($(self.elements.footer).find('.file_manager_ok')).trigger('click'); - }); - }, 200); - }, - settings: { - label: undefined, - }, - settingUpdated: function(key, oldValue, newValue) { - switch (key) { - case 'message': - this.setMessage(newValue); - break; - case 'label': - if (this.__internal.buttons[0].element) { - this.__internal.buttons[0].element.innerHTML = newValue; - } - break; - default: - break; - } - }, - prepare: function() { - this.__internal.buttons[0].element.disabled = true; - }, - setup: function() { - return { - buttons: [{ - text: gettext('Select'), - key: 13, - className: 'btn btn-primary fa fa-file file_manager_ok pg-alertify-button disabled', - }, - { - text: gettext('Cancel'), - key: 27, - className: 'btn btn-danger fa fa-times pg-alertify-button', - }, - ], - focus: { - element: 0, - }, - options: { - closableByDimmer: false, - maximizable: false, - closable: false, - movable: true, - }, - }; - }, - callback: function(closeEvent) { - var innerbody; - - if (closeEvent.button.text == gettext('Select')) { - var newFile = $('.storage_dialog #uploader .input-path').val(), - file_data = { - 'path': $('.currentpath').val(), - }; - pgAdmin.Browser.Events.trigger('pgadmin-storage:finish_btn:select_folder', newFile); - innerbody = $(this.elements.body).find('.storage_content'); - $(innerbody).find('*').off(); - innerbody.remove(); - removeTransId(trans_id); - // Ajax call to store the last directory visited once user press select button - set_last_traversed_dir(file_data, trans_id); - } else if (closeEvent.button.text == gettext('Cancel')) { - innerbody = $(this.elements.body).find('.storage_content'); - $(innerbody).find('*').off(); - innerbody.remove(); - removeTransId(trans_id); - pgAdmin.Browser.Events.trigger('pgadmin-storage:cancel_btn:select_folder'); - } - }, - build: function() { - this.elements.content.appendChild($container.get(0)); - }, - hooks: { - onshow: function() { - $(this.elements.body).addClass('pgadmin-storage-body'); - }, - }, - }; - }); - - // Declare the Create mode dialog - Alertify.dialog('createModeDlg', function() { - // Dialog containter - var $container = - $('
'), - trans_id; - - /* - * Function: renderStoragePanel - * - * Renders the FileManager in the content div based on the given - * configuration parameters. - */ - var renderStoragePanel = function(params) { - /* - * Clear the existing html in the storage content - */ - var content = $container.find('.storage_content'); - content.empty(); - - $.get(url_for('file_manager.index'), function(data) { - content.append(data); - }); - - var transId = getTransId(params); - var t_res; - if (transId.readyState == 4) { - t_res = JSON.parse(transId.responseText); - } - trans_id = t_res.data.fileTransId; - }; - - // Dialog property - return { - main: function(params) { - var self = this; - - // Set title and button name - if (_.isUndefined(params['dialog_title'])) { - params['dialog_title'] = 'Create file'; - } - this.set('title', params['dialog_title']); - if (_.isUndefined(params['btn_primary'])) { - params['btn_primary'] = 'Create'; - } - this.set('label', params['btn_primary']); - - params = JSON.stringify(params); - $container.find('.storage_content').remove(); - $container.append('
'); - renderStoragePanel(params); - this.elements.dialog.style.minWidth = '630px'; - this.show(); - setTimeout(function() { - $($container.find('.file_manager')).on('enter-key', function() { - $($(self.elements.footer).find('.file_manager_ok')).trigger('click'); - }); - }, 200); - }, - settings: { - label: undefined, - }, - settingUpdated: function(key, oldValue, newValue) { - switch (key) { - case 'message': - this.setMessage(newValue); - break; - case 'label': - if (this.__internal.buttons[0].element) { - this.__internal.buttons[0].element.innerHTML = newValue; - } - break; - default: - break; - } - }, - prepare: function() { - this.__internal.buttons[0].element.disabled = true; - }, - setup: function() { - return { - buttons: [{ - text: gettext('Create'), - key: 13, - className: 'btn btn-primary fa fa-file file_manager_create file_manager_ok pg-alertify-button disabled', - }, - { - text: gettext('Cancel'), - key: 27, - className: 'btn btn-danger fa fa-times file_manager_create_cancel pg-alertify-button', - }, - ], - focus: { - element: 0, - }, - options: { - closableByDimmer: false, - maximizable: false, - closable: false, - movable: true, - }, - }; - }, - replace_file: function() { - var $yesBtn = $('.replace_file .btn_yes'), - $noBtn = $('.replace_file .btn_no'); - - $('.storage_dialog #uploader .input-path').attr('disabled', true); - $('.file_manager_ok').addClass('disabled'); - $('.replace_file, .fm_dimmer').show(); - - $yesBtn.on('click',() => { - $('.replace_file, .fm_dimmer').hide(); - $yesBtn.off(); - $noBtn.off(); - var newFile = $('.storage_dialog #uploader .input-path').val(); - - pgAdmin.Browser.Events.trigger('pgadmin-storage:finish_btn:create_file', newFile); - $('.file_manager_create_cancel').trigger('click'); - $('.storage_dialog #uploader .input-path').attr('disabled', false); - $('.file_manager_ok').removeClass('disabled'); - }); - - $noBtn.on('click',() => { - $('.replace_file, .fm_dimmer').hide(); - $yesBtn.off(); - $noBtn.off(); - $('.storage_dialog #uploader .input-path').attr('disabled', false); - $('.file_manager_ok').removeClass('disabled'); - }); - }, - is_file_exist: function() { - var full_path = $('.storage_dialog #uploader .input-path').val(), - path = full_path.substr(0, full_path.lastIndexOf('/') + 1), - selected_item = full_path.substr(full_path.lastIndexOf('/') + 1), - is_exist = false; - - var file_data = { - 'path': path, - 'name': selected_item, - 'mode': 'is_file_exist', - }; - - $.ajax({ - type: 'POST', - data: JSON.stringify(file_data), - url: url_for('file_manager.filemanager', { - 'trans_id': trans_id, - }), - dataType: 'json', - contentType: 'application/x-download; charset=utf-8', - async: false, - success: function(resp) { - var data = resp.data.result; - if (data['Code'] === 1) { - is_exist = true; - } else { - is_exist = false; - } - }, - }); - return is_exist; - }, - check_permission: function(path) { - var permission = false, - post_data = { - 'path': path, - 'mode': 'permission', - }; - - $.ajax({ - type: 'POST', - data: JSON.stringify(post_data), - url: url_for('file_manager.filemanager', { - 'trans_id': trans_id, - }), - dataType: 'json', - contentType: 'application/json; charset=utf-8', - async: false, - success: function(resp) { - var data = resp.data.result; - if (data.Code === 1) { - permission = true; - } else { - $('.file_manager_ok').addClass('disabled'); - Alertify.error(data.Error); - } - }, - error: function() { - $('.file_manager_ok').addClass('disabled'); - Alertify.error(gettext('Error occurred while checking access permission.')); - }, - }); - return permission; - }, - callback: function(closeEvent) { - if (closeEvent.button.text == gettext('Create')) { - var newFile = $('.storage_dialog #uploader .input-path').val(), - file_data = { - 'path': $('.currentpath').val(), - }, - innerbody; - - if (!this.check_permission(newFile)) { - closeEvent.cancel = true; - return; - } - - if (!_.isUndefined(newFile) && newFile !== '' && this.is_file_exist()) { - this.replace_file(); - closeEvent.cancel = true; - } else { - pgAdmin.Browser.Events.trigger('pgadmin-storage:finish_btn:create_file', newFile); - innerbody = $(this.elements.body).find('.storage_content'); - $(innerbody).find('*').off(); - innerbody.remove(); - removeTransId(trans_id); - } - - set_last_traversed_dir(file_data, trans_id); - } else if (closeEvent.button.text == gettext('Cancel')) { - innerbody = $(this.elements.body).find('.storage_content'); - $(innerbody).find('*').off(); - innerbody.remove(); - removeTransId(trans_id); - pgAdmin.Browser.Events.trigger('pgadmin-storage:cancel_btn:create_file'); - } - }, - build: function() { - this.elements.content.appendChild($container.get(0)); - }, - hooks: { - onshow: function() { - $(this.elements.body).addClass('pgadmin-storage-body'); - }, - }, - }; - }); - }, - show_storage_dlg: function(params) { - Alertify.storageManagerDlg(params).resizeTo('60%', '80%'); - }, - show_file_selection: function(params) { - Alertify.fileSelectionDlg(params).resizeTo('60%', '80%'); - }, - show_folder_selection: function(params) { - Alertify.folderSelectionDlg(params).resizeTo('60%', '80%'); - }, - show_create_dlg: function(params) { - Alertify.createModeDlg(params).resizeTo('60%', '80%'); }, // Call dialogs subject to dialog_type param show_dialog: function(params) { - if (params.dialog_type == 'select_file') { - this.show_file_selection(params); - } else if (params.dialog_type == 'select_folder') { - this.show_folder_selection(params); - } else if (params.dialog_type == 'create_file') { - this.show_create_dlg(params); + if (params.dialog_type == 'create_file') { + Alertify.createModeDlg(params).resizeTo('60%', '80%'); } else { - this.show_storage_dlg(params); + Alertify.fileSelectionDlg(params).resizeTo('60%', '80%'); } }, }; diff --git a/web/pgadmin/misc/file_manager/static/js/helpers.js b/web/pgadmin/misc/file_manager/static/js/helpers.js new file mode 100644 index 000000000..99b1ae42d --- /dev/null +++ b/web/pgadmin/misc/file_manager/static/js/helpers.js @@ -0,0 +1,38 @@ +import url_for from 'sources/url_for'; +import $ from 'jquery'; + +// Send a request to get transaction id +export function getTransId(configs) { + return $.ajax({ + data: configs, + type: 'POST', + async: false, + url: url_for('file_manager.get_trans_id'), + dataType: 'json', + contentType: 'application/json; charset=utf-8', + }); +} + +// Function to remove trans id from session +export function removeTransId(trans_id) { + return $.ajax({ + type: 'GET', + async: false, + url: url_for('file_manager.delete_trans_id', { + 'trans_id': trans_id, + }), + dataType: 'json', + contentType: 'application/json; charset=utf-8', + }); +} + +export function set_last_traversed_dir(path, trans_id) { + return $.ajax({ + url: url_for('file_manager.save_last_dir', { + 'trans_id': trans_id, + }), + type: 'POST', + data: JSON.stringify(path), + contentType: 'application/json', + }); +} diff --git a/web/pgadmin/misc/file_manager/static/js/select_dialogue.js b/web/pgadmin/misc/file_manager/static/js/select_dialogue.js new file mode 100644 index 000000000..5d24d8fb8 --- /dev/null +++ b/web/pgadmin/misc/file_manager/static/js/select_dialogue.js @@ -0,0 +1,134 @@ +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 {getTransId, removeTransId, set_last_traversed_dir} from './helpers'; + +// Declare the Selection dialog +module.exports = Alertify.dialog('fileSelectionDlg', function() { + // Dialog property + return { + main: function(params) { + // Set title and button name + var self = this; + if (_.isUndefined(params['dialog_title'])) { + params['dialog_title'] = 'Select file'; + } + self.dialog_type = params['dialog_type']; + + this.set('title', params['dialog_title']); + if (_.isUndefined(params['btn_primary'])) { + params['btn_primary'] = 'Select'; + } + this.set('label', params['btn_primary']); + + this.params = JSON.stringify(params); + + this.elements.dialog.style.minWidth = '630px'; + this.show(); + + }, + settings: { + label: undefined, + }, + settingUpdated: function(key, oldValue, newValue) { + switch (key) { + case 'message': + this.setMessage(newValue); + break; + case 'label': + if (this.__internal.buttons[0].element) { + this.__internal.buttons[0].element.innerHTML = newValue; + } + break; + default: + break; + } + }, + prepare: function() { + var self = this; + self.$container.find('.storage_content').remove(); + self.$container.append('
'); + + var content = self.$container.find('.storage_content'); + content.empty(); + + $.get(url_for('file_manager.index'), function(data) { + content.append(data); + }); + + var transId = getTransId(self.params); + var t_res; + if (transId.readyState == 4) { + t_res = JSON.parse(transId.responseText); + } + self.trans_id = t_res.data.fileTransId; + + setTimeout(function() { + $(self.$container.find('.file_manager')).on('enter-key', function() { + $($(self.elements.footer).find('.file_manager_ok')).trigger('click'); + }); + }, 200); + self.__internal.buttons[0].element.disabled = true; + }, + setup: function() { + return { + buttons: [{ + text: gettext('Select'), + key: 13, + className: 'btn btn-primary fa fa-file file_manager_ok pg-alertify-button disabled', + }, + { + text: gettext('Cancel'), + key: 27, + className: 'btn btn-danger fa fa-times pg-alertify-button', + }, + ], + focus: { + element: 0, + }, + options: { + closableByDimmer: false, + maximizable: false, + closable: false, + movable: true, + }, + }; + }, + callback: function(closeEvent) { + var innerbody; + + if (closeEvent.button.text == gettext('Select')) { + var newFile = $('.storage_dialog #uploader .input-path').val(), + file_data = { + 'path': $('.currentpath').val(), + }; + + pgAdmin.Browser.Events.trigger('pgadmin-storage:finish_btn:' + this.dialog_type, newFile); + innerbody = $(this.elements.body).find('.storage_content'); + $(innerbody).find('*').off(); + innerbody.remove(); + removeTransId(this.trans_id); + // Ajax call to store the last directory visited once user press select button + + set_last_traversed_dir(file_data, this.trans_id); + } else if (closeEvent.button.text == gettext('Cancel')) { + innerbody = $(this.elements.body).find('.storage_content'); + $(innerbody).find('*').off(); + innerbody.remove(); + removeTransId(this.trans_id); + pgAdmin.Browser.Events.trigger('pgadmin-storage:cancel_btn:' + this.dialog_type); + } + }, + build: function() { + this.$container = $('
'); + this.elements.content.appendChild(this.$container.get(0)); + }, + hooks: { + onshow: function() { + $(this.elements.body).addClass('pgadmin-storage-body'); + }, + }, + }; +}); diff --git a/web/pgadmin/misc/file_manager/static/js/utility.js b/web/pgadmin/misc/file_manager/static/js/utility.js index e5dac84fc..dc787e3f6 100644 --- a/web/pgadmin/misc/file_manager/static/js/utility.js +++ b/web/pgadmin/misc/file_manager/static/js/utility.js @@ -36,7 +36,7 @@ define([ async: false, cache: false, url: url, - dataType: 'jsonp', + dataType: 'json', contentType: 'application/json; charset=utf-8', }); }; @@ -169,7 +169,7 @@ define([ if (!has_capability(data, 'download') || pgAdmin.FileUtils.hideButtons()) { $('.file_manager').find('button.download').hide(); } else { - $('.file_manager').find('button.download').off().on('click',() => { + $('.file_manager').find('button.download').off().on('click', function() { var path; if ($('.fileinfo').data('view') == 'grid') { path = $('.fileinfo li.selected').find('.clip span').attr('data-alt'); @@ -879,7 +879,7 @@ define([ } }); - $('.fileinfo').find('#contents li').on('click',(e) => { + $('.fileinfo').find('#contents li').on('click', function(e) { e.stopPropagation(); var path = decodeURI($(this).find('.clip span').attr('data-alt')), is_protected = $(this).find( @@ -909,6 +909,7 @@ define([ '.file_manager #uploader .filemanager-path-group' ); } + pgAdmin.FileUtils.setUploader(path); } else { if ( has_capability(data_cap, 'select_file') && @@ -952,6 +953,7 @@ define([ '.file_manager #uploader .filemanager-path-group' ); } + pgAdmin.FileUtils.setUploader(path); } else { if (has_capability(data_cap, 'select_file') && is_protected == undefined) { $(this).parent().find('tr.selected').removeClass('selected'); @@ -1229,7 +1231,7 @@ define([ }); // re-render the home view - $('.file_manager .home').on('click',() => { + $('.file_manager .home').on('click', function() { var currentViewMode = $('.fileinfo').data('view'); $('.fileinfo').data('view', currentViewMode); getFolderInfo('/'); @@ -1237,7 +1239,7 @@ define([ }); // Go one directory back - $('.file_manager .level-up').on('click',() => { + $('.file_manager .level-up').on('click', function() { var b = $('.currentpath').val(); // Enable/Disable level up button enab_dis_level_up(); @@ -1395,7 +1397,7 @@ define([ $('.upload').remove(); $('.create').before(' '); - $('#uploader .upload').off().on('click',() => { + $('#uploader .upload').off().on('click', function() { // we create prompt var msg = '
' + '' + @@ -1541,7 +1543,7 @@ define([ $('.storage_dialog #uploader .input-path').attr('data-path', path); // create new folder - $('.create').off().on('click',() => { + $('.create').off().on('click', function() { var foldername = lg.new_folder; var $file_element, $file_element_list, diff --git a/web/pgadmin/static/js/backform.pgadmin.js b/web/pgadmin/static/js/backform.pgadmin.js index c7b984966..f3364c9d0 100644 --- a/web/pgadmin/static/js/backform.pgadmin.js +++ b/web/pgadmin/static/js/backform.pgadmin.js @@ -2269,6 +2269,12 @@ define([ // Introduce a new class to fix the error icon placement on the control this.$el.addClass('pgadmin-file-has-error'); }, + disable_button: function() { + this.$el.find('button.select_item').attr('disabled', 'disabled'); + }, + enable_button: function() { + this.$el.find('button.select_item').removeAttr('disabled'); + }, }); Backform.DatetimepickerControl = diff --git a/web/pgadmin/tools/backup/__init__.py b/web/pgadmin/tools/backup/__init__.py index 682bd4b87..e41530fcd 100644 --- a/web/pgadmin/tools/backup/__init__.py +++ b/web/pgadmin/tools/backup/__init__.py @@ -221,10 +221,11 @@ def script(): ) -def filename_with_file_manager_path(_file): +def filename_with_file_manager_path(_file, create_file=True): """ Args: file: File name returned from client file manager + create_file: Set flag to False when file creation doesn't required Returns: Filename to use for backup with full path taken from preference @@ -237,9 +238,10 @@ def filename_with_file_manager_path(_file): elif not os.path.isabs(_file): _file = os.path.join(document_dir(), _file) - # Touch the file to get the short path of the file on windows. - with open(_file, 'a'): - pass + if create_file: + # Touch the file to get the short path of the file on windows. + with open(_file, 'a'): + pass return fs_short_path(_file) @@ -385,7 +387,10 @@ def create_backup_objects_job(sid): data.pop("ratio") try: - backup_file = filename_with_file_manager_path(data['file']) + if data['format'] == 'directory': + backup_file = filename_with_file_manager_path(data['file'], False) + else: + backup_file = filename_with_file_manager_path(data['file']) except Exception as e: return bad_request(errormsg=str(e)) diff --git a/web/pgadmin/tools/backup/static/js/backup.js b/web/pgadmin/tools/backup/static/js/backup.js index d6fd48c52..79a1c909d 100644 --- a/web/pgadmin/tools/backup/static/js/backup.js +++ b/web/pgadmin/tools/backup/static/js/backup.js @@ -139,9 +139,23 @@ define([ label: gettext('Filename'), type: 'text', disabled: false, - control: Backform.FileControl, + control: Backform.FileControl.extend({ + render: function() { + var attributes = this.model.toJSON(); + if (attributes.format == 'directory') { + this.field.attributes.dialog_type = 'select_folder'; + } + else { + this.field.attributes.dialog_type = 'create_file'; + } + + Backform.InputControl.prototype.render.apply(this, arguments); + return this; + }, + }), dialog_type: 'create_file', supp_types: ['*', 'sql', 'backup'], + deps: ['format'], }, { id: 'format', label: gettext('Format'), diff --git a/web/pgadmin/tools/backup/tests/test_backup_create_job_unit_test.py b/web/pgadmin/tools/backup/tests/test_backup_create_job_unit_test.py index 56dc71fba..dcc4bb5ce 100644 --- a/web/pgadmin/tools/backup/tests/test_backup_create_job_unit_test.py +++ b/web/pgadmin/tools/backup/tests/test_backup_create_job_unit_test.py @@ -52,6 +52,31 @@ class BackupCreateJobTest(BaseTestGenerator): not_expected_cmd_opts=[], expected_exit_code=[0, None] )), + ('When backup object with format directory', + dict( + class_params=dict( + sid=1, + name='test_backup_server', + port=5444, + host='localhost', + database='postgres', + bfile='test_backup', + username='postgres' + ), + params=dict( + file='test_backup_folder', + format='directory', + verbose=True, + blobs=False, + schemas=[], + tables=[], + database='postgres' + ), + url='/backup/job/{0}/object', + expected_cmd_opts=['--verbose', '--format=d'], + not_expected_cmd_opts=[], + expected_exit_code=[0, None] + )), ('When backup the object with option sections to all data', dict( class_params=dict( diff --git a/web/pgadmin/tools/restore/__init__.py b/web/pgadmin/tools/restore/__init__.py index 6321a638d..1e5498592 100644 --- a/web/pgadmin/tools/restore/__init__.py +++ b/web/pgadmin/tools/restore/__init__.py @@ -168,7 +168,7 @@ def filename_with_file_manager_path(_file): elif not os.path.isabs(_file): _file = os.path.join(document_dir(), _file) - if not os.path.isfile(_file): + if not os.path.isfile(_file) and not os.path.exists(_file): return None return fs_short_path(_file) diff --git a/web/pgadmin/tools/restore/static/js/restore.js b/web/pgadmin/tools/restore/static/js/restore.js index aeff6d3d4..ce60c6d40 100644 --- a/web/pgadmin/tools/restore/static/js/restore.js +++ b/web/pgadmin/tools/restore/static/js/restore.js @@ -112,9 +112,23 @@ commonUtils, menuUtils, supportedNodes, restoreDialog label: gettext('Filename'), type: 'text', disabled: false, - control: Backform.FileControl, + control: Backform.FileControl.extend({ + render: function() { + var attributes = this.model.toJSON(); + if (attributes.format == 'directory') { + this.field.attributes.dialog_type = 'select_folder'; + } + else { + this.field.attributes.dialog_type = 'select_file'; + } + + Backform.InputControl.prototype.render.apply(this, arguments); + return this; + }, + }), dialog_type: 'select_file', supp_types: ['*', 'backup', 'sql', 'patch'], + deps: ['format'], }, { id: 'no_of_jobs', label: gettext('Number of jobs'), diff --git a/web/pgadmin/tools/restore/tests/test_restore_create_job_unit_test.py b/web/pgadmin/tools/restore/tests/test_restore_create_job_unit_test.py index d69827ddf..223d51644 100644 --- a/web/pgadmin/tools/restore/tests/test_restore_create_job_unit_test.py +++ b/web/pgadmin/tools/restore/tests/test_restore_create_job_unit_test.py @@ -51,6 +51,32 @@ class RestoreCreateJobTest(BaseTestGenerator): not_expected_cmd_opts=[], expected_exit_code=[0, None] )), + ('When restore object with format directory', + dict( + class_params=dict( + sid=1, + name='test_restore_server', + port=5444, + host='localhost', + database='postgres', + bfile='test_restore', + username='postgres' + ), + params=dict( + file='test_restore_file', + format='directory', + custom=False, + verbose=True, + blobs=False, + schemas=[], + tables=[], + database='postgres' + ), + url='/restore/job/{0}', + expected_cmd_opts=['--verbose', '--format=d'], + not_expected_cmd_opts=[], + expected_exit_code=[0, None] + )), ('When restore object with the sections options', dict( class_params=dict( diff --git a/web/regression/feature_utils/pgadmin_page.py b/web/regression/feature_utils/pgadmin_page.py index eff5f80ef..aacb925e6 100644 --- a/web/regression/feature_utils/pgadmin_page.py +++ b/web/regression/feature_utils/pgadmin_page.py @@ -244,6 +244,7 @@ class PgadminPage: tab = self.find_by_xpath("//*[contains(@class,'wcTabTop')]//" "*[contains(@class,'wcPanelTab') " "and contains(.,'" + tab_name + "')]") + self.click_element(tab) def wait_for_input_field_content(self, field_name, content): diff --git a/web/regression/javascript/file_manager/file_manager_specs.js b/web/regression/javascript/file_manager/file_manager_specs.js new file mode 100644 index 000000000..a2076e5df --- /dev/null +++ b/web/regression/javascript/file_manager/file_manager_specs.js @@ -0,0 +1,55 @@ +///////////////////////////////////////////////////////////// +// +// pgAdmin 4 - PostgreSQL Tools +// +// Copyright (C) 2013 - 2018, The pgAdmin Development Team +// This software is released under the PostgreSQL Licence +// +////////////////////////////////////////////////////////////// + +import pgAdmin from 'sources/pgadmin'; +import Alertify from 'pgadmin.alertifyjs'; +import '../../../pgadmin/misc/file_manager/static/js/file_manager'; +import '../../../pgadmin/misc/file_manager/static/js/select_dialogue.js'; + + +describe('fileSelectDialog', function () { + + let params; + + describe('When dialog is called for select file', () => { + it('Select file dialog', function() { + params = { + 'dialog_title': 'Select file', + 'dialog_type': 'select_file', + }; + + spyOn(Alertify, 'fileSelectionDlg').and.callFake(function() { + this.resizeTo = function() {}; + return this; + }); + + pgAdmin.FileManager.show_dialog(params); + + expect(Alertify.fileSelectionDlg).toHaveBeenCalled(); + }); + }); + + describe('When dialog is called for create file', () => { + it('Select file dialog', function() { + params = { + 'dialog_title': 'Create file', + 'dialog_type': 'create_file', + }; + + spyOn(Alertify, 'createModeDlg').and.callFake(function() { + this.resizeTo = function() {}; + return this; + }); + + pgAdmin.FileManager.show_dialog(params); + + expect(Alertify.createModeDlg).toHaveBeenCalled(); + }); + }); +});