Hi Dave,
Please find attached rebased patch.
--
*Harshal Dhumal*
*Software Engineer*
EnterpriseDB India: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Sun, Jan 8, 2017 at 4:07 PM, Dave Page <[email protected]> wrote:
> Hi
>
> Can you rebase this please? It no longer applies :-(
>
>
> On Wednesday, December 28, 2016, Harshal Dhumal <
> [email protected]> wrote:
>
>> Hi Dave,
>> Here is updated (V4) patch.
>>
>> Changes: 1] Now can enter both type of slashes ( / and \ ) and all will
>> get replaced with the platform standard.
>> 2] Added unicode support.
>>
>> --
>> *Harshal Dhumal*
>> *Software Engineer*
>>
>> EnterpriseDB India: http://www.enterprisedb.com
>> The Enterprise PostgreSQL Company
>>
>> On Mon, Dec 19, 2016 at 5:16 PM, Dave Page <[email protected]> wrote:
>>
>>> Hi
>>>
>>> On Fri, Dec 16, 2016 at 6:46 PM, Harshal Dhumal
>>> <[email protected]> wrote:
>>> > Hi Dave,
>>> >
>>> > Please find updated patch below for direct file navigation.
>>> > I have covered all of above mentioned case.
>>>
>>> Still not there I'm afraid:
>>>
>>> - On Mac, if I type \Users\dpage, it changes it to /\Users\dpage and
>>> then tells me it doesn't exist. Per the RM, either forward or back
>>> slashes should be acceptable ("The path should accept either / or \ as
>>> separators. Upon successful navigation to the path (after pressing
>>> Return), the slashes should be replaced with the platform standard if
>>> needed.")
>>>
>>> - Unicode handling seems to be completely broken - see the attached
>>> screenshot.
>>>
>>> I haven't tested on Windows yet, and only in Desktop mode on Mac.
>>> Please test on Windows and Mac or Linux with both Python 2 and 3, in
>>> both Server and Desktop modes to ensure that the behaviour meets the
>>> requirements of the ticket with Unicode and non-Unicode paths and
>>> files before resubmitting.
>>>
>>> Thanks.
>>>
>>> --
>>> Dave Page
>>> Blog: http://pgsnake.blogspot.com
>>> Twitter: @pgsnake
>>>
>>> EnterpriseDB UK: http://www.enterprisedb.com
>>> The Enterprise PostgreSQL Company
>>>
>>
>>
>
> --
> Dave Page
> Blog: http://pgsnake.blogspot.com
> Twitter: @pgsnake
>
> EnterpriseDB UK: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company
>
>
diff --git a/web/pgadmin/misc/file_manager/__init__.py b/web/pgadmin/misc/file_manager/__init__.py
index 7040f11..28ec225 100644
--- a/web/pgadmin/misc/file_manager/__init__.py
+++ b/web/pgadmin/misc/file_manager/__init__.py
@@ -16,6 +16,7 @@ import string
import sys
import time
from sys import platform as _platform
+import config
import simplejson as json
from flask import render_template, Response, session, request as req, url_for
@@ -241,6 +242,7 @@ def delete_trans_id(trans_id):
data={'status': True}
)
+
@blueprint.route("/save_last_dir/<int:trans_id>", methods=["POST"])
@login_required
def save_last_directory_visited(trans_id):
@@ -259,12 +261,12 @@ class Filemanager(object):
{
'Error': gettext('No permission to operate on \
specified path.'),
- 'Code': -1
+ 'Code': 0
}
)
self.dir = get_storage_directory()
- if (self.dir is not None and isinstance(self.dir, list)):
+ if self.dir is not None and isinstance(self.dir, list):
self.dir = ""
@staticmethod
@@ -312,25 +314,34 @@ class Filemanager(object):
folders_only = False
title = "Storage Manager"
- # get last visited directory, if not present then traverse in reverse order
- # to find closest parent directory
+ # get last visited directory, if not present then traverse in reverse
+ # order to find closest parent directory
last_dir = blueprint.last_directory_visited.get()
if storage_dir is None:
if last_dir is None:
last_dir = "/"
else:
if last_dir is not None:
- if len(last_dir) > 1 and last_dir.endswith('/'):
+ if len(last_dir) > 1 and \
+ (last_dir.endswith('/') or last_dir.endswith('\\')):
last_dir = last_dir[:-1]
while last_dir:
if os.path.exists(storage_dir + last_dir):
- break;
- index = last_dir.rfind('/')
+ break
+ if _platform == 'win32':
+ index = last_dir.rfind('\\')
+ else:
+ index = last_dir.rfind('/')
last_dir = last_dir[0:index]
if not last_dir:
last_dir = "/"
- if not last_dir.endswith('/'):
- last_dir += "/"
+
+ if _platform == 'win32':
+ if not last_dir.endswith('\\'):
+ last_dir += "\\"
+ else:
+ if not last_dir.endswith('/'):
+ last_dir += "/"
else:
last_dir = "/"
@@ -426,11 +437,11 @@ class Filemanager(object):
bitmask >>= 1
if (drive_name != '' and drive_name is not None and
drive_name in drives):
- return "{0}{1}".format(drive_name, ':/')
+ return u"{0}{1}".format(drive_name, ':')
else:
return drives # return drives if no argument is passed
except Exception:
- return ['C:/']
+ return ['C:']
else:
return '/'
@@ -443,12 +454,24 @@ class Filemanager(object):
path = unquote(path)
if hasattr(str, 'decode'):
path = unquote(path).encode('utf-8').decode('utf-8')
+
+ try:
+ Filemanager.check_access_permission(dir, path)
+ except Exception as e:
+ err_msg = "Error: {0}".format(str(e))
+ files = {
+ 'Code': 0,
+ 'Error': err_msg
+ }
+ return files
+
files = {}
- if (_platform == "win32" and path == '/') and dir is None:
+ if (_platform == "win32" and (path == '/' or path == '\\'))\
+ and dir is None:
drives = Filemanager._get_drives()
for drive in drives:
protected = 0
- path = file_name = "{0}:/".format(drive)
+ path = file_name = u"{0}:".format(drive)
try:
drive_size = getDriveSize(path)
drive_size_in_units = sizeof_fmt(drive_size)
@@ -487,7 +510,7 @@ class Filemanager(object):
system_path = os.path.join(os.path.join(orig_path, f))
# continue if file/folder is hidden
- if (is_folder_hidden(system_path) or f.startswith('.')):
+ if is_folder_hidden(system_path) or f.startswith('.'):
continue
if hasattr(str, 'decode'):
@@ -508,7 +531,7 @@ class Filemanager(object):
if files_only == 'true':
continue
file_extension = str('dir')
- user_path = "{0}/".format(user_path)
+ user_path = u"{0}/".format(user_path)
else:
# filter files based on file_type
if file_type is not None and file_type != "*":
@@ -537,10 +560,62 @@ class Filemanager(object):
err_msg = "Error: {0}".format(e)
files = {
'Code': 0,
- 'err_msg': err_msg
+ 'Error': err_msg
}
return files
+ @staticmethod
+ def check_access_permission(dir, path):
+ if dir is None:
+ dir = ""
+ orig_path = Filemanager.get_abs_path(dir, path)
+
+ # This translates path with relative path notations like ./ and ../ to
+ # absolute path.
+ orig_path = os.path.abspath(orig_path)
+
+ if _platform == 'win32':
+ if dir[-1] == '\\':
+ dir = dir[:-1]
+ else:
+ if dir[-1] == '/':
+ dir = dir[:-1]
+
+ # Do not allow user to access outside his storage dir in server mode.
+ if config.SERVER_MODE is True and not orig_path.startswith(dir):
+ raise Exception(
+ gettext(u"Access denied ({})".format(orig_path)))
+ return True
+
+ @staticmethod
+ def get_abs_path(dir, path):
+
+ if path.startswith('\\\\'):
+ return u"{}".format(path)
+
+ if path == '/' or path == '\\':
+ if _platform == 'win32':
+ if dir.endswith('\\'):
+ return u"{}".format(dir)
+ else:
+ return u"{}{}".format(dir, '\\')
+ else:
+ if dir.endswith('/'):
+ return u"{}".format(dir)
+ else:
+ return u"{}{}".format(dir, '/')
+
+ if dir.endswith('/') or dir.endswith('\\'):
+ if path.startswith('/') or path.startswith('\\'):
+ return u"{}{}".format(dir[:-1], path)
+ else:
+ return u"{}{}".format(dir, path)
+ else:
+ if path.startswith('/') or path.startswith('\\'):
+ return u"{}{}".format(dir, path)
+ else:
+ return u"{}/{}".format(dir, path)
+
def validate_request(self, capability):
"""
It validates the capability with the capabilities
@@ -560,13 +635,35 @@ class Filemanager(object):
if self.dir is None:
self.dir = ""
orig_path = u"{0}{1}".format(self.dir, path)
+
+ try:
+ Filemanager.check_access_permission(self.dir, path)
+ except Exception as e:
+ thefile = {
+ 'Filename': split_path(path)[-1],
+ 'FileType': '',
+ 'Path': path,
+ 'Error': gettext("Error: {0}".format(str(e))),
+ 'Code': 0,
+ 'Info': '',
+ 'Properties': {
+ 'Date Created': '',
+ 'Date Modified': '',
+ 'Width': '',
+ 'Height': '',
+ 'Size': ''
+ }
+ }
+ return thefile
+
user_dir = path
thefile = {
'Filename': split_path(orig_path)[-1],
- 'File Type': '',
+ 'FileType': '',
'Path': user_dir,
'Error': '',
- 'Code': 0,
+ 'Code': 1,
+ 'Info': '',
'Properties': {
'Date Created': '',
'Date Modified': '',
@@ -577,13 +674,16 @@ class Filemanager(object):
}
if not path_exists(orig_path):
- thefile['Error'] = gettext('File does not exist.')
- return (encode_json(thefile), None, 'application/json')
-
- if split_path(user_dir)[-1] == '/':
- thefile['File Type'] = 'Directory'
+ thefile['Error'] = gettext("'{}' file does not exist.".format(
+ split_path(orig_path)[-1]))
+ thefile['Code'] = -1
+ return thefile
+
+ if split_path(user_dir)[-1] == '/'\
+ or os.path.isfile(orig_path) is False:
+ thefile['FileType'] = 'Directory'
else:
- thefile['File Type'] = splitext(user_dir)
+ thefile['FileType'] = splitext(user_dir)
created = time.ctime(os.path.getctime(orig_path))
modified = time.ctime(os.path.getmtime(orig_path))
@@ -601,7 +701,7 @@ class Filemanager(object):
trans_data = Filemanager.get_trasaction_selection(self.trans_id)
dir = self.dir if self.dir is not None else ''
if not dir.endswith('/'):
- dir += '/';
+ dir += '/'
filelist = self.list_filesystem(dir, path, trans_data, file_type)
return filelist
@@ -613,10 +713,21 @@ class Filemanager(object):
if not self.validate_request('rename'):
return {
'Error': gettext('Not allowed'),
- 'Code': 1
+ 'Code': 0
}
dir = self.dir if self.dir is not None else ''
+
+ try:
+ Filemanager.check_access_permission(dir, old)
+ Filemanager.check_access_permission(dir, new)
+ except Exception as e:
+ res = {
+ 'Error': gettext("Error: {0}".format(str(e))),
+ 'Code': 0
+ }
+ return res
+
# check if it's dir
if old[-1] == '/':
old = old[:-1]
@@ -631,7 +742,6 @@ class Filemanager(object):
if not path[-1] == '/':
path += '/'
- # newname = encode_urlpath(new)
newname = new
if hasattr(str, 'decode'):
newname = new.encode('utf-8').decode('utf-8')
@@ -645,8 +755,8 @@ class Filemanager(object):
code = 1
try:
os.rename(oldpath_sys, newpath_sys)
- code = 0
except Exception as e:
+ code = 0
error_msg = "{0} {1}".format(
gettext('There was an error renaming the file:'),
str(e))
@@ -669,23 +779,31 @@ class Filemanager(object):
if not self.validate_request('delete'):
return {
'Error': gettext('Not allowed'),
- 'Code': 1
+ 'Code': 0
}
dir = self.dir if self.dir is not None else ''
path = path.encode('utf-8').decode('utf-8') if hasattr(str, 'decode') else path
orig_path = u"{0}{1}".format(dir, path)
+ try:
+ Filemanager.check_access_permission(dir, path)
+ except Exception as e:
+ res = {
+ 'Error': gettext("Error: {0}".format(str(e))),
+ 'Code': 0
+ }
+ return res
+
err_msg = ''
code = 1
try:
if os.path.isdir(orig_path):
os.rmdir(orig_path)
- code = 0
else:
os.remove(orig_path)
- code = 0
except Exception as e:
+ code = 0
err_msg = "Error: {0}".format(e.strerror)
result = {
@@ -703,7 +821,7 @@ class Filemanager(object):
if not self.validate_request('upload'):
return {
'Error': gettext('Not allowed'),
- 'Code': 1
+ 'Code': 0
}
dir = self.dir if self.dir is not None else ''
@@ -718,14 +836,23 @@ class Filemanager(object):
path = req.form.get('currentpath').encode('utf-8').decode('utf-8')
file_name = file_obj.filename.encode('utf-8').decode('utf-8')
orig_path = u"{0}{1}".format(dir, path)
- newName = u'{0}{1}'.format(orig_path, file_name)
+ newName = u"{0}{1}".format(orig_path, file_name)
with open(newName, 'wb') as f:
f.write(file_obj.read())
- code = 0
except Exception as e:
+ code = 0
err_msg = "Error: {0}".format(e.strerror)
+ try:
+ Filemanager.check_access_permission(dir, path)
+ except Exception as e:
+ res = {
+ 'Error': gettext("Error: {0}".format(str(e))),
+ 'Code': 0
+ }
+ return res
+
result = {
'Path': path,
'Name': newName,
@@ -745,17 +872,21 @@ class Filemanager(object):
name = unquote(name)
path = unquote(path)
if hasattr(str, 'decode'):
- name = unquote(name).encode('utf-8')
- path = unquote(path).encode('utf-8')
+ name = name.encode('utf-8').decode('utf-8')
+ path = path.encode('utf-8').decode('utf-8')
try:
- orig_path = "{0}{1}".format(dir, path)
- newName = '{0}{1}'.format(orig_path, name)
- if os.path.exists(newName):
+ orig_path = u"{0}{1}".format(dir, path)
+ Filemanager.check_access_permission(dir, u"{}{}".format(path, name))
+
+ newName = u"{0}{1}".format(orig_path, name)
+ if not os.path.exists(newName):
code = 0
- else:
- code = 1
except Exception as e:
- err_msg = "Error: {0}".format(e.strerror)
+ code = 0
+ if hasattr(e, 'strerror'):
+ err_msg = "Error: {0}".format(e.strerror)
+ else:
+ err_msg = "Error: {0}".format(str(e))
result = {
'Path': path,
@@ -792,7 +923,7 @@ class Filemanager(object):
if not self.validate_request('create'):
return {
'Error': gettext('Not allowed'),
- 'Code': 1
+ 'Code': 0
}
dir = self.dir if self.dir is not None else ''
@@ -800,6 +931,16 @@ class Filemanager(object):
if hasattr(str, 'decode'):
newName = name.encode('utf-8')
+ try:
+ Filemanager.check_access_permission(dir, u"{}{}".format(
+ path, newName))
+ except Exception as e:
+ res = {
+ 'Error': gettext("Error: {0}".format(str(e))),
+ 'Code': 0
+ }
+ return res
+
if dir != "":
if hasattr(str, 'decode'):
newPath = dir + '/' + path + newName.decode('utf-8') + '/'
@@ -816,15 +957,15 @@ class Filemanager(object):
if not path_exists(newPath):
try:
os.mkdir(newPath)
- code = 0
except Exception as e:
+ code = 0
err_msg = "Error: {0}".format(e.strerror)
else:
newPath, newName = self.getNewName(dir, path, newName)
try:
os.mkdir(newPath)
- code = 0
except Exception as e:
+ code = 0
err_msg = "Error: {0}".format(e.strerror)
result = {
@@ -843,21 +984,42 @@ class Filemanager(object):
if not self.validate_request('download'):
return {
'Error': gettext('Not allowed'),
- 'Code': 1
+ 'Code': 0
}
dir = self.dir if self.dir is not None else ''
+
if hasattr(str, 'decode'):
path = path.encode('utf-8')
orig_path = u"{0}{1}".format(dir, path.decode('utf-8'))
else:
- orig_path = "{0}{1}".format(dir, path)
+ orig_path = u"{0}{1}".format(dir, path)
+
+ try:
+ Filemanager.check_access_permission(dir, u"{}{}".format(
+ path, path))
+ except Exception as e:
+ resp = Response(gettext("Error: {0}".format(str(e))))
+ resp.headers['Content-Disposition'] = 'attachment; filename=' + name
+ return resp
+
name = path.split('/')[-1]
content = open(orig_path, 'rb')
resp = Response(content)
resp.headers['Content-Disposition'] = 'attachment; filename=' + name
return resp
+ def permission(self, path=None, req=None):
+ dir = self.dir if self.dir is not None else ''
+ res = {'Code': 1}
+ try:
+ Filemanager.check_access_permission(dir, path)
+ except Exception as e:
+ err_msg = "Error: {0}".format(str(e))
+ res['Code'] = 0
+ res['Error'] = err_msg
+ return res
+
@blueprint.route("/filemanager/<int:trans_id>/", methods=["GET", "POST"])
@login_required
diff --git a/web/pgadmin/misc/file_manager/static/css/file_manager.css b/web/pgadmin/misc/file_manager/static/css/file_manager.css
index ea502ac..56d9c38 100755
--- a/web/pgadmin/misc/file_manager/static/css/file_manager.css
+++ b/web/pgadmin/misc/file_manager/static/css/file_manager.css
@@ -15,19 +15,17 @@
top: 35px;
}
-#uploader h1 {
+#uploader .input-path {
font-size: 14px;
margin: 0;
- margin-left: 5px;
padding: 0;
display: block;
float: left;
text-align: left;
- line-height:1.9em;
- max-width: 367px;
+ line-height:1.6em;
+ width: calc(100% - 72px);
text-overflow: ellipsis;
overflow: hidden;
- color: #999;
}
#uploader h1 b {
diff --git a/web/pgadmin/misc/file_manager/templates/file_manager/index.html b/web/pgadmin/misc/file_manager/templates/file_manager/index.html
index 197386f..992fe5d 100755
--- a/web/pgadmin/misc/file_manager/templates/file_manager/index.html
+++ b/web/pgadmin/misc/file_manager/templates/file_manager/index.html
@@ -5,13 +5,14 @@
</head>
<body>
<div class="file_manager">
- <form id="uploader" method="post" class='col-xs-12'>
+ <div id="uploader" class='col-xs-12'>
<div class="btn-group filemanager-path-group col-sm-7 col-xs-12" role="group">
<button name="home" type="button" value="Home" title="Home" class="fa fa-home btn home"><span></span>
</button>
<button name="level-up" type="button" title="Back" value="LevelUp" class="btn fa fa-level-up level-up"
disabled><span></span></button>
- <h1 title=''></h1>
+ <input class='input-path' title='' type="text"/>
+
</div>
<div class="btn-group filemanager-btn-group" role="group">
<div class="uploadresponse"></div>
@@ -29,7 +30,7 @@
<button class="ON fa fa-th btn grid" type="button" title="View as grid"><span></span></button>
<button type="button" class="btn fa fa-list list" title="View as Table"><span></span></button>
</div>
- </form>
+ </div>
<div class="fileinfo">
<span class="activity">
<img src="{{ url_for('browser.static', filename='css/aciTree/image/load-root.gif') }}">
diff --git a/web/pgadmin/misc/file_manager/templates/file_manager/js/file_manager.js b/web/pgadmin/misc/file_manager/templates/file_manager/js/file_manager.js
index 412e6c8..8558d3c 100644
--- a/web/pgadmin/misc/file_manager/templates/file_manager/js/file_manager.js
+++ b/web/pgadmin/misc/file_manager/templates/file_manager/js/file_manager.js
@@ -47,9 +47,9 @@ define([
});
};
- var set_last_traversed_dir = function(path, _url) {
+ var set_last_traversed_dir = function(path, trans_id) {
return $.ajax({
- url: _url,
+ url: "{{ url_for('file_manager.index') }}save_last_dir/" + trans_id,
type: 'POST',
data: JSON.stringify(path),
contentType: 'application/json'
@@ -90,6 +90,7 @@ define([
return {
main: function(params) {
// Set title and button name
+ var self = this;
if (_.isUndefined(params['dialog_title'])) {
params['dialog_title'] = 'Storage manager';
}
@@ -105,6 +106,11 @@ define([
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
@@ -142,25 +148,21 @@ define([
},
callback: function(closeEvent) {
if (closeEvent.button.text == "{{ _('Select') }}") {
- if($('.fileinfo').data('view') == 'grid') {
- sel_file = $('.fileinfo').find('#contents li.selected p span').attr('title');
- } else {
- sel_file = $('.fileinfo tbody tr.selected td p span').attr('title');
- }
- var newFile = $('.currentpath').val() + sel_file;
+ var newFile = $('.storage_dialog #uploader .input-path').val(),
+ file_data = {'path': $('.currentpath').val()};
pgAdmin.Browser.Events.trigger('pgadmin-storage:finish_btn:storage_dialog', newFile);
- var _Url = "{{ url_for('file_manager.index') }}" + "save_last_dir/" + trans_id;
- var file_data = {
- 'path': $('.currentpath').val()
- };
- set_last_traversed_dir(file_data, _Url);
+ set_last_traversed_dir(file_data, trans_id);
+ var innerbody = $(this.elements.body).find('.storage_content')
+ $(innerbody).find('*').off();
+ innerbody.remove();
+ removeTransId(trans_id);
} else if (closeEvent.button.text == "{{ _('Cancel') }}") {
- if (removeTransId(trans_id)) {
- this.destroy();
- return;
- }
+ var innerbody = $(this.elements.body).find('.storage_content')
+ $(innerbody).find('*').off();
+ innerbody.remove();
+ removeTransId(trans_id);
}
},
build: function() {
@@ -210,6 +212,7 @@ define([
return {
main: function(params) {
// Set title and button name
+ var self = this;
if (_.isUndefined(params['dialog_title'])) {
params['dialog_title'] = 'Select file';
}
@@ -225,6 +228,11 @@ define([
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
@@ -264,26 +272,22 @@ define([
},
callback: function(closeEvent) {
if (closeEvent.button.text == "{{ _('Select') }}") {
- if($('.fileinfo').data('view') == 'grid') {
- sel_file = $('.fileinfo').find('#contents li.selected p span').attr('title');
- } else {
- sel_file = $('.fileinfo tbody tr.selected td p span').attr('title');
- }
- var newFile = $('.currentpath').val() + sel_file;
+ var newFile = $('.storage_dialog #uploader .input-path').val(),
+ file_data = {'path': $('.currentpath').val()};
pgAdmin.Browser.Events.trigger('pgadmin-storage:finish_btn:select_file', newFile);
+ var 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
- var _Url = "{{ url_for('file_manager.index') }}" + "save_last_dir/" + trans_id;
- var file_data = {
- 'path': $('.currentpath').val()
- };
- set_last_traversed_dir(file_data, _Url);
+
+ set_last_traversed_dir(file_data, trans_id);
} else if (closeEvent.button.text == "{{ _('Cancel') }}") {
- if (removeTransId(trans_id)) {
- this.destroy();
- return;
- }
+ var innerbody = $(this.elements.body).find('.storage_content')
+ $(innerbody).find('*').off();
+ innerbody.remove();
+ removeTransId(trans_id);
}
},
build: function() {
@@ -332,6 +336,7 @@ define([
// Dialog property
return {
main: function(params) {
+ var self = this;
// Set title and button name
if (_.isUndefined(params['dialog_title'])) {
params['dialog_title'] = 'Select folder';
@@ -348,6 +353,11 @@ define([
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
@@ -387,26 +397,20 @@ define([
},
callback: function(closeEvent) {
if (closeEvent.button.text == "{{ _('Select') }}") {
- if($('.fileinfo').data('view') == 'grid') {
- sel_file = $('.fileinfo').find('#contents li.selected p span').attr('title');
- } else {
- sel_file = $('.fileinfo tbody tr.selected td p span').attr('title');
- }
- var newFile = $('.currentpath').val() + sel_file;
-
+ var newFile = $('.storage_dialog #uploader .input-path').val(),
+ file_data = {'path': $('.currentpath').val()};
pgAdmin.Browser.Events.trigger('pgadmin-storage:finish_btn:select_folder', newFile);
+ var 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
- var _Url = "{{ url_for('file_manager.index') }}" + "save_last_dir/" + trans_id;
- var file_data = {
- 'path': $('.currentpath').val()
- };
- set_last_traversed_dir(file_data, _Url);
+ set_last_traversed_dir(file_data, trans_id);
} else if (closeEvent.button.text == "{{ _('Cancel') }}") {
- if (removeTransId(trans_id)) {
- this.destroy();
- return;
- }
+ var innerbody = $(this.elements.body).find('.storage_content')
+ $(innerbody).find('*').off();
+ innerbody.remove();
+ removeTransId(trans_id);
}
},
build: function() {
@@ -454,7 +458,8 @@ define([
// Dialog property
return {
main: function(params) {
- var trans_id;
+ var self = this,
+ trans_id;
// Set title and button name
if (_.isUndefined(params['dialog_title'])) {
params['dialog_title'] = 'Create file';
@@ -471,6 +476,11 @@ define([
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
@@ -512,8 +522,7 @@ define([
$('.replace_file, .fm_dimmer').show();
$('.replace_file .btn_yes').click(function(self) {
$('.replace_file, .fm_dimmer').hide();
- var selected_item = $('.allowed_file_types .create_input input[type="text"]').val(),
- newFile = $('.currentpath').val() + selected_item;
+ 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');
@@ -523,11 +532,13 @@ define([
});
},
is_file_exist: function() {
- var selected_item = $('.allowed_file_types .create_input input[type="text"]').val(),
+ 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': $('.currentpath').val(),
+ 'path': path,
'name': selected_item,
'mode': 'is_file_exist'
};
@@ -541,7 +552,7 @@ define([
async: false,
success: function(resp) {
data = resp.data.result;
- if(data['Code'] === 0) {
+ if(data['Code'] === 1) {
is_exist = true;
} else {
is_exist = false;
@@ -550,30 +561,63 @@ define([
});
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: fileConnector + 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('{{ _('Error occurred while checking access permission.') }}');
+ }
+ });
+ return permission;
+ },
callback: function(closeEvent) {
if (closeEvent.button.text == "{{ _('Create') }}") {
- var selected_item = $('.allowed_file_types .create_input input[type="text"]').val();
- var newFile = $('.currentpath').val() + selected_item;
+ var newFile = $('.storage_dialog #uploader .input-path').val(),
+ file_data = {'path': $('.currentpath').val()};
- if(!_.isUndefined(selected_item) && selected_item !== '' && this.is_file_exist()) {
- this.replace_file();
+ if (!this.check_permission(newFile)) {
closeEvent.cancel = true;
+ return;
}
- else {
+
+ 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);
+ var innerbody = $(this.elements.body).find('.storage_content')
+ $(innerbody).find('*').off();
+ innerbody.remove();
removeTransId(trans_id);
}
- var _Url = "{{ url_for('file_manager.index') }}" + "save_last_dir/" + trans_id;
- var file_data = {
- 'path': $('.currentpath').val()
- };
- set_last_traversed_dir(file_data, _Url);
+ set_last_traversed_dir(file_data, trans_id);
} else if (closeEvent.button.text == "{{ _('Cancel') }}") {
- if (removeTransId(trans_id)) {
- this.destroy();
- return;
- }
+ var innerbody = $(this.elements.body).find('.storage_content')
+ $(innerbody).find('*').off();
+ innerbody.remove();
+ removeTransId(trans_id);
}
},
build: function() {
diff --git a/web/pgadmin/misc/file_manager/templates/file_manager/js/utility.js b/web/pgadmin/misc/file_manager/templates/file_manager/js/utility.js
index b8a2444..cb4faf4 100755
--- a/web/pgadmin/misc/file_manager/templates/file_manager/js/utility.js
+++ b/web/pgadmin/misc/file_manager/templates/file_manager/js/utility.js
@@ -159,37 +159,43 @@ var setUploader = function(path) {
$('.storage_dialog #uploader').find('a').remove();
$('.storage_dialog #uploader').find('b').remove();
- path = decodeURI(path);
-
- var display_string = path,
- file_path = '';
+ if(config.options.platform_type === "win32") {
+ path = path.replace(/\//g, '\\')
+ } else {
+ path = path.replace(/\\/g, '/')
+ }
- // split path
- var split_path = display_string.split('/');
- split_path = split_path.filter(function(e) {return e;});
+ path = decodeURI(path);
- // set empty path if it is windows
- if (config.options.platform_type === "win32" && config.options.show_volumes) {
- file_path = "";
- } else if (split_path.length === 0) {
- file_path = '/';
+ if (config.options.platform_type === "win32") {
+ if (config.options.show_volumes && path == '\\') {
+ $('.storage_dialog #uploader .input-path').val('');
+ } else {
+ $('.storage_dialog #uploader .input-path').val(path);
+ }
+ } else if (!config.options.platform_type === "win32" &&
+ (path == '' || !path.startsWith('/'))) {
+ path = '/' + path;
+ $('.storage_dialog #uploader .input-path').val(path);
} else {
- file_path = '/';
+ $('.storage_dialog #uploader .input-path').val(path);
}
- Object.keys(split_path).forEach(function (i) {
- file_path += split_path[i] + '/';
- });
- $('.storage_dialog #uploader h1').html(file_path);
+ if( path.lastIndexOf('\\') == -1 && path.lastIndexOf('/') == -1) {
+ $('.currentpath').val(path);
+ } else if(path.lastIndexOf('/') > path.lastIndexOf('\\')) {
+ $('.currentpath').val(path.substr(0, path.lastIndexOf('/') + 1));
+ } else {
+ $('.currentpath').val(path.substr(0, path.lastIndexOf('\\') + 1));
+ }
- $('.currentpath').val(path);
enab_dis_level_up();
if ($('.storage_dialog #uploader h1 span').length === 0) {
$('<span>'+lg.current_folder+'</span>').appendTo($('.storage_dialog #uploader h1'));
}
- $('.storage_dialog #uploader h1').attr('title', display_string);
- $('.storage_dialog #uploader h1').attr('data-path', display_string);
+ $('.storage_dialog #uploader .input-path').attr('title', path);
+ $('.storage_dialog #uploader .input-path').attr('data-path', path);
// create new folder
$('.create').unbind().click(function() {
@@ -288,7 +294,7 @@ var setUploader = function(path) {
var d = new Date(); // to prevent IE cache issues
$.getJSON(fileConnector + '?mode=addfolder&path=' + $('.currentpath').val() + '&name=' + foldername, function(resp) {
var result = resp.data.result;
- if (result.Code === 0) {
+ if (result.Code === 1) {
alertify.success(lg.successful_added_folder);
getFolderInfo(result.Parent);
} else {
@@ -382,7 +388,6 @@ var enable_disable_btn = function() {
$('.file_manager').find('button.download').prop('disabled', true);
$('.file_manager').find('button.rename').prop('disabled', true);
if ($grid_file.length > 0) {
- $('.create_input input[type="text"]').val('');
$('.file_manager_ok').addClass('disabled');
}
} else {
@@ -392,14 +397,13 @@ var enable_disable_btn = function() {
$('.file_manager').find('button.download').prop('disabled', true);
$('.file_manager').find('button.rename').prop('disabled', true);
if ($list_file.length > 0) {
- $('.create_input input[type="text"]').val('');
$('.file_manager_ok').addClass('disabled');
}
}
$('.delete_item').hide();
// clear address bar
- $('.file_manager #uploader h1').show();
+ $('.file_manager #uploader .input-path').show();
$('.file_manager #uploader .show_selected_file').remove();
};
@@ -436,7 +440,7 @@ var renameItem = function(data) {
async: false,
success: function(resp) {
var result = resp.data.result;
- if (result.Code === 0) {
+ if (result.Code === 1) {
var newPath = result['New Path'],
newName = result['New Name'],
title = $("#preview h1").attr("title");
@@ -500,7 +504,7 @@ var deleteItem = function(data) {
async: false,
success: function(resp) {
var result = resp.data.result;
- if (result.Code === 0) {
+ if (result.Code === 1) {
isDeleted = true;
if (isDeleted) {
alertify.success(lg.successful_delete);
@@ -548,11 +552,11 @@ var getDetailView = function(path) {
*/
var getFileInfo = function(file) {
// Update location for status, upload, & new folder functions.
- var currentpath = file.substr(0, file.lastIndexOf('/') + 1);
- setUploader(currentpath);
+ setUploader(file);
// Retrieve the data & populate the template.
- var d = new Date(); // to prevent IE cache issues
+ var d = new Date(), // to prevent IE cache issues
+ is_file_valid = false;
var post_data = {
'path': file,
'mode': 'getinfo'
@@ -567,8 +571,8 @@ var getFileInfo = function(file) {
async: false,
success: function(resp) {
var data = resp.data.result;
-
- if (data.Code === 0) {
+ if (data.Code === 1) {
+ $('.file_manager_ok').removeClass('disabled');
var properties = '';
if (
data.Properties.Size || parseInt(data.Properties.Size)==0
@@ -579,18 +583,69 @@ var getFileInfo = function(file) {
}
data.Capabilities = capabilities;
bindToolbar(data);
+ if (data.FileType == 'Directory') {
+ // Enable/Disable level up button
+ enab_dis_level_up();
+ $('.file_manager_ok').addClass('disabled');
+
+ $('.file_manager button.delete, .file_manager button.rename').attr('disabled', 'disabled');
+ $('.file_manager button.download').attr('disabled', 'disabled');
+
+ if (file.charAt(file.length - 1) != '/' && file.charAt(file.length - 1) != '\\') {
+ file += '/';
+ }
+ getFolderInfo(file);
+ } else {
+ is_file_valid = true;
+ }
} else {
+ $('.file_manager_ok').addClass('disabled');
alertify.error(data.Error);
}
}
});
+ return is_file_valid;
};
+var checkPermission = function(path) {
+ var permission = false,
+ post_data = {
+ 'path': path,
+ 'mode': 'permission'
+ };
+
+ $.ajax({
+ type: 'POST',
+ data: JSON.stringify(post_data),
+ url: fileConnector,
+ 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('{{ _('Error occurred while checking access permission.') }}');
+ }
+ });
+ return permission;
+};
+
+
+
/*
* Retrieves data for all items within the given folder and
* creates a list view.
*/
var getFolderInfo = function(path, file_type) {
+ $('.storage_dialog #uploader .input-path').prop('disabled', true);
if (!file_type) {
file_type = '';
}
@@ -640,16 +695,16 @@ var getFolderInfo = function(path, file_type) {
contentType: "application/json; charset=utf-8",
async: false,
success: function(resp) {
+ $('.storage_dialog #uploader .input-path').prop('disabled', false);
var result = '',
data = resp.data.result;
// hide activity indicator
$('.fileinfo').find('span.activity').hide();
if (data.Code === 0) {
- alertify.error(data.err_msg);
+ alertify.error(data.Error);
return;
}
-
// generate HTML for files/folder and render into container
if (!_.isEmpty(data)) {
if ($('.fileinfo').data('view') == 'grid') {
@@ -951,7 +1006,6 @@ var getFolderInfo = function(path, file_type) {
var old_name = decodeURI($(this).siblings('span').attr('title')),
newvalue = old_name.substring(0, old_name.indexOf('.')),
last = getFileExtension(old_name);
-
if (old_name.indexOf('.') == 0) {
last = '';
}
@@ -997,24 +1051,19 @@ var getFolderInfo = function(path, file_type) {
// Get into folder on dblclick
$('.fileinfo').find('#contents li').dblclick(function(e) {
e.stopPropagation();
-
// Enable/Disable level up button
enab_dis_level_up();
var path = decodeURI($(this).find('span').attr('data-alt'));
- if (path.lastIndexOf("/") == path.length - 1) {
+ if (path.lastIndexOf("/") == path.length - 1 || path.lastIndexOf("\\") == path.length - 1) {
$('.file_manager_ok').addClass('disabled');
- var $create_input = $('.create_input input[type="text"]');
-
$('.file_manager button.delete, .file_manager button.rename').attr('disabled', 'disabled');
$('.file_manager button.download').attr('disabled', 'disabled');
getFolderInfo(path);
- if ($create_input.length != 0 && $create_input.val() != '') {
- $('.file_manager_ok').removeClass('disabled');
- }
+
} else {
getFileInfo(path);
}
@@ -1028,7 +1077,7 @@ var getFolderInfo = function(path, file_type) {
'.clip span.fm_lock_icon'
).attr('data-protected');
- if (path.lastIndexOf('/') == path.length - 1) {
+ if (path.lastIndexOf('/') == path.length - 1 || path.lastIndexOf('\\') == path.length - 1) {
if (
has_capability(data_cap, 'select_folder') &&
is_protected == undefined
@@ -1044,7 +1093,7 @@ var getFolderInfo = function(path, file_type) {
'disabled', 'disabled'
);
// set selected folder name in breadcrums
- $('.file_manager #uploader h1').hide();
+ $('.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'
@@ -1065,13 +1114,6 @@ var getFolderInfo = function(path, file_type) {
$('.file_manager #uploader .show_selected_file').remove();
}
- if (
- config.options.dialog_type == 'create_file' &&
- is_protected == undefined
- ) {
- $('.create_input input[type="text"]').val(decodeURI(file_name));
- $('.file_manager_ok, .file_manager_create').removeClass('disabled');
- }
getFileInfo(path);
}
});
@@ -1086,7 +1128,7 @@ var getFolderInfo = function(path, file_type) {
'i.tbl_lock_icon'
).attr('data-protected');
- if (path.lastIndexOf('/') == path.length - 1) {
+ if (path.lastIndexOf('/') == path.length - 1 || path.lastIndexOf('\\') == path.length - 1) {
if (has_capability(data_cap, 'select_folder') && is_protected == undefined) {
$(this).parent().find('tr.selected').removeClass('selected');
$('td:first-child', this).parent().addClass('selected');
@@ -1095,7 +1137,7 @@ var getFolderInfo = function(path, file_type) {
$('.file_manager button.delete, .file_manager button.rename').removeAttr('disabled');
// set selected folder name in breadcrums
- $('.file_manager #uploader h1').hide();
+ $('.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'
@@ -1105,33 +1147,24 @@ var getFolderInfo = function(path, file_type) {
if (has_capability(data_cap, 'select_file') && is_protected == undefined) {
$(this).parent().find('tr.selected').removeClass('selected');
$('td:first-child', this).parent().addClass('selected');
- $('.file_manager_ok').removeClass('disabled');
$('.file_manager button.delete, .file_manager button.download, .file_manager button.rename').removeAttr(
'disabled'
);
// set selected folder name in breadcrums
$('.file_manager #uploader .show_selected_file').remove();
}
- if (
- config.options.dialog_type == 'create_file' &&
- is_protected == undefined
- ) {
- $('.create_input input[type="text"]').val(file_name);
- $('.file_manager_ok, .file_manager_create').removeClass('disabled');
- }
+
getFileInfo(path);
}
});
$('.fileinfo table#contents tbody tr').on('dblclick', function(e) {
e.stopPropagation();
-
// Enable/Disable level up button
enab_dis_level_up();
-
var path = $('td:first-child', this).attr('title');
- if (path.lastIndexOf('/') == path.length - 1) {
+ if (path.lastIndexOf('/') == path.length - 1 || path.lastIndexOf('\\') == path.length - 1) {
$('.file_manager_ok').removeClass('disabled');
$('.file_manager button.download').attr('disabled', 'disabled');
$('.file_manager button.delete, .file_manager button.rename').attr('disabled', 'disabled');
@@ -1142,13 +1175,17 @@ var getFolderInfo = function(path, file_type) {
});
}
+ input_object.set_cap(data_cap);
+ },
+ error: function() {
+ $('.storage_dialog #uploader .input-path').prop('disabled', false);
}
});
};
// Enable/Disable level up button
var enab_dis_level_up = function() {
- $('.file_manager #uploader h1').show();
+ $('.file_manager #uploader .input-path').show();
$('.show_selected_file').remove();
setTimeout(function() {
@@ -1203,6 +1240,7 @@ var fileRoot = config.options.fileRoot,
* Get localized messages from file
* through culture var or from URL
*/
+
var lg = [],
enjs = '{{ url_for("file_manager.index") }}' + "en.js",
lgf = loadData(enjs);
@@ -1260,39 +1298,26 @@ if (
});
}
-if (config.options.dialog_type == 'create_file') {
- var create_file_html = '<div class="create_input">'+
- '<span>Filename:</span>'+
- '<input type="text" name="new_filename" class="fm_create_input form-control" />'+
- '</div>';
-
- $('.create_mode_dlg').find('.allowed_file_types').prepend(create_file_html);
- $('.create_input input[type="text"]').on('keypress, keydown', function() {
- var input_text_len = $(this).val().length;
- if (input_text_len > 0 ) {
- $('.file_manager_ok').removeClass('disabled');
- } else {
- $('.file_manager_ok').addClass('disabled');
- }
- });
-}
-
/*---------------------------------------------------------
Item Actions - Object events
---------------------------------------------------------*/
// switch to folder view
$('.file_manager .fileinfo').on('click', function(e) {
+ $('.file_manager #uploader .input-path').val($('.currentpath').val())
enable_disable_btn();
});
// refresh current directory
$('.file_manager .refresh').on('click', function(e) {
enable_disable_btn();
- var curr_path = $('.currentpath').val(),
- path = curr_path.substring(
- 0, curr_path.lastIndexOf("/")
- ) + "/";
+ var curr_path = $('.currentpath').val();
+ $('.file_manager #uploader .input-path').val(curr_path);
+ if(curr_path.endsWith("/")) {
+ var path = curr_path.substring(0, curr_path.lastIndexOf("/")) + "/";
+ } else {
+ var path = curr_path.substring(0, curr_path.lastIndexOf("\\")) + "\\";
+ }
getFolderInfo(path);
});
@@ -1345,12 +1370,20 @@ $('.file_manager .home').click(function() {
// Go one directory back
$(".file_manager .level-up").click(function() {
var b = $('.currentpath').val();
-
// Enable/Disable level up button
enab_dis_level_up();
+ if (b.endsWith('\\') || b.endsWith('/')) {
+ b = b.substring(0, b.length - 1)
+ }
+
if (b != '/') {
- parent = b.substring(0, b.slice(0, -1).lastIndexOf("/")) + "/";
+ if(b.lastIndexOf('/') > b.lastIndexOf('\\')) {
+ var parent = b.substring(0, b.slice(0, -1).lastIndexOf("/")) + "/";
+ } else {
+ var parent = b.substring(0, b.slice(0, -1).lastIndexOf("\\")) + "\\";
+ }
+
var d = $(".fileinfo").data("view");
$(".fileinfo").data("view", d);
getFolderInfo(parent);
@@ -1376,12 +1409,110 @@ $('.file_manager .list').click(function() {
// Provide initial values for upload form, status, etc.
setUploader(fileRoot);
-$('#uploader').attr('action', fileConnector);
-
var data = {
'Capabilities': capabilities
};
+function InputObject() {
+ this.init= function(cap) {
+ var self = this,
+ check_obj = function(path, check) {
+
+ var path = decodeURI(path);
+
+ if (path.lastIndexOf('/') == path.length - 1 || path.lastIndexOf('\\') == path.length - 1) {
+ if (
+ has_capability(self.data_cap, 'select_folder')
+ ) {
+ $('.file_manager_ok').removeClass('disabled');
+ $('.file_manager button.delete, .file_manager button.rename').removeAttr(
+ 'disabled', 'disabled'
+ );
+ $('.file_manager button.download').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'
+ );
+ } else {
+ $('.file_manager_ok').addClass('disabled');
+ if(check) {
+ // Enable/Disable level up button
+ enab_dis_level_up();
+
+ $('.file_manager button.delete, .file_manager button.rename').attr('disabled', 'disabled');
+ $('.file_manager button.download').attr('disabled', 'disabled');
+ getFolderInfo(path);
+ }
+ }
+ } else {
+ if (
+ has_capability(self.data_cap, 'select_file')
+ ) {
+ $('.file_manager_ok').removeClass('disabled');
+ $('.file_manager button.delete, .file_manager button.download, .file_manager button.rename').removeAttr(
+ 'disabled'
+ );
+ // set selected folder name in breadcrums
+ $('.file_manager #uploader .show_selected_file').remove();
+ }
+
+ if(check) {
+ if (config.options.dialog_type == 'create_file') {
+ var status = checkPermission(path)
+ if (status) {
+ $('.file_manager').trigger('enter-key');
+ }
+ } else if(config.options.dialog_type == 'select_file') {
+ var file_status = getFileInfo(path);
+ if (file_status) {
+ $('.file_manager').trigger('enter-key');
+ }
+ }
+ }
+ }
+ };
+
+ self.data_cap = cap;
+
+ $('.storage_dialog #uploader .input-path').keyup(function(e) {
+ if(e.keyCode == 13) {
+ e.stopPropagation();
+ var path = $(this).val();
+ if(path == '') {
+ path = '/';
+ }
+
+ if(config.options.platform_type === "win32") {
+ path = path.replace(/\//g, '\\')
+ } else {
+ path = path.replace(/\\/g, '/')
+ if (!path.startsWith('/')) {
+ path = '/' + path;
+ }
+ }
+
+ $(this).val(path);
+ setTimeout(function() {
+ check_obj(path, true);
+ });
+
+ return;
+ }
+ check_obj($(this).val(), false);
+ });
+ }
+ this.set_cap = function(cap) {
+ this.data_cap = cap;
+ }
+}
+
+var input_object = new InputObject()
+input_object.init(data);
+
// Upload file
if (has_capability(data, 'upload')) {
Dropzone.autoDiscover = false;
@@ -1463,7 +1594,7 @@ if (has_capability(data, 'upload')) {
var data = response.data.result,
$this = $(file.previewTemplate);
- if (data.Code == 0) {
+ if (data.Code == 1) {
setTimeout(function() {
$this.find(".dz-upload").addClass("success");
}, 1000);
diff --git a/web/pgadmin/tools/sqleditor/__init__.py b/web/pgadmin/tools/sqleditor/__init__.py
index d0af418..f1efeb8 100644
--- a/web/pgadmin/tools/sqleditor/__init__.py
+++ b/web/pgadmin/tools/sqleditor/__init__.py
@@ -8,8 +8,6 @@
##########################################################################
"""A blueprint module implementing the sqleditor frame."""
-MODULE_NAME = 'sqleditor'
-
import simplejson as json
import os
import pickle
@@ -26,7 +24,9 @@ from pgadmin.utils.ajax import make_json_response, bad_request, \
from pgadmin.utils.driver import get_driver
from pgadmin.utils.sqlautocomplete.autocomplete import SQLAutoComplete
-from config import PG_DEFAULT_DRIVER
+from config import PG_DEFAULT_DRIVER, SERVER_MODE
+
+MODULE_NAME = 'sqleditor'
# import unquote from urlib for python2.x and python3.x
try:
@@ -1203,7 +1203,7 @@ def load_file():
# generate full path of file
file_path = os.path.join(
storage_manager_path,
- file_path.lstrip('/')
+ file_path.lstrip('/').lstrip('\\')
)
file_data = None
@@ -1271,9 +1271,19 @@ def save_file():
if storage_manager_path is not None:
file_path = os.path.join(
storage_manager_path,
- file_path.lstrip('/')
+ file_path.lstrip('/').lstrip('\\')
)
+ try:
+ # Do not allow user to access outside his storage dir in server mode.
+ if SERVER_MODE is True:
+ orig_path = os.path.abspath(file_path)
+ if not orig_path.startswith(storage_manager_path):
+ raise Exception(
+ gettext("Access denied ({})".format(orig_path)))
+ except Exception as e:
+ return internal_server_error(errormsg=str(e))
+
if hasattr(str, 'decode'):
file_content = file_data['file_content']
else:
@@ -1281,7 +1291,7 @@ def save_file():
# write to file
try:
- with open(file_path, 'wb') as output_file:
+ with open(file_path, 'wb+') as output_file:
if hasattr(str, 'decode'):
output_file.write(file_content.encode('utf-8'))
else:
--
Sent via pgadmin-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgadmin-hackers