2016-05-12 13:34:28 -05:00
|
|
|
##########################################################################
|
|
|
|
#
|
|
|
|
# pgAdmin 4 - PostgreSQL Tools
|
|
|
|
#
|
2024-01-01 02:43:48 -06:00
|
|
|
# Copyright (C) 2013 - 2024, The pgAdmin Development Team
|
2016-05-12 13:34:28 -05:00
|
|
|
# This software is released under the PostgreSQL Licence
|
|
|
|
#
|
|
|
|
#########################################################################
|
|
|
|
|
|
|
|
"""This file contains functions fetching different utility paths."""
|
|
|
|
|
|
|
|
import os
|
2023-03-14 08:10:53 -05:00
|
|
|
|
2019-03-22 04:36:13 -05:00
|
|
|
from flask import current_app, url_for
|
2022-01-09 03:17:32 -06:00
|
|
|
from flask_security import current_user
|
2020-08-07 02:07:00 -05:00
|
|
|
from werkzeug.exceptions import InternalServerError
|
2023-03-06 05:33:47 -06:00
|
|
|
from pgadmin.utils.constants import MY_STORAGE
|
2023-03-14 07:51:18 -05:00
|
|
|
from pgadmin.model import User
|
|
|
|
|
2023-06-12 08:14:31 -05:00
|
|
|
PGADMIN_PATH = '~/.pgadmin/'
|
|
|
|
|
2023-03-14 07:51:18 -05:00
|
|
|
|
|
|
|
def preprocess_username(un):
|
|
|
|
ret_un = un
|
|
|
|
if len(ret_un) == 0 or ret_un[0].isdigit():
|
|
|
|
ret_un = 'pga_user_' + un
|
|
|
|
|
|
|
|
ret_un = ret_un.replace('@', '_') \
|
|
|
|
.replace('/', 'slash') \
|
|
|
|
.replace('\\', 'slash')
|
|
|
|
|
|
|
|
return ret_un
|
2016-06-21 08:12:14 -05:00
|
|
|
|
2016-05-12 13:34:28 -05:00
|
|
|
|
2023-03-06 05:33:47 -06:00
|
|
|
def get_storage_directory(user=current_user, shared_storage=''):
|
2023-03-14 08:10:53 -05:00
|
|
|
# Don't move this import statement to the top of the file,
|
|
|
|
# it throws circular import error.
|
|
|
|
import config
|
2016-05-12 13:34:28 -05:00
|
|
|
if config.SERVER_MODE is not True:
|
2016-06-17 12:19:51 -05:00
|
|
|
return None
|
2016-05-12 13:34:28 -05:00
|
|
|
|
2023-03-06 05:33:47 -06:00
|
|
|
is_shared_storage = False
|
|
|
|
if shared_storage != MY_STORAGE and shared_storage:
|
|
|
|
is_shared_storage = True
|
2023-06-12 08:14:31 -05:00
|
|
|
selected_dir = [sdir for sdir in config.SHARED_STORAGE if
|
|
|
|
sdir['name'] == shared_storage]
|
2023-03-06 05:33:47 -06:00
|
|
|
storage_dir = None
|
2023-06-12 08:14:31 -05:00
|
|
|
if len(selected_dir) > 0:
|
|
|
|
the_dir = selected_dir[0]['path']
|
2023-03-06 05:33:47 -06:00
|
|
|
storage_dir = the_dir
|
|
|
|
else:
|
|
|
|
storage_dir = getattr(
|
|
|
|
config, 'STORAGE_DIR',
|
|
|
|
os.path.join(
|
|
|
|
os.path.realpath(
|
2023-06-12 08:14:31 -05:00
|
|
|
os.path.expanduser(PGADMIN_PATH)
|
2023-03-06 05:33:47 -06:00
|
|
|
), 'storage'
|
|
|
|
)
|
2016-05-12 13:34:28 -05:00
|
|
|
)
|
2016-05-13 14:18:11 -05:00
|
|
|
|
|
|
|
if storage_dir is None:
|
2016-06-17 12:19:51 -05:00
|
|
|
return None
|
2016-05-13 14:18:11 -05:00
|
|
|
|
2023-03-14 07:51:18 -05:00
|
|
|
username = preprocess_username(user.username.split('@')[0])
|
2016-05-12 13:34:28 -05:00
|
|
|
|
2019-03-22 04:36:13 -05:00
|
|
|
# Figure out the old-style storage directory name
|
|
|
|
old_storage_dir = os.path.join(
|
2018-01-31 07:58:55 -06:00
|
|
|
storage_dir.decode('utf-8') if hasattr(storage_dir, 'decode')
|
|
|
|
else storage_dir,
|
Resolved quite a few file-system encoding/decoding related cases.
In order to resolve the non-ascii characters in path (in user directory,
storage path, etc) on windows, we have converted the path into the
short-path, so that - we don't need to deal with the encoding issues
(specially with Python 2).
We've resolved majority of the issues with this patch.
We still need couple issues to resolve after this in the same area.
TODO
* Add better support for non-ascii characters in the database name on
windows with Python 3
* Improve the messages created after the background processes by
different modules (such as Backup, Restore, Import/Export, etc.),
which does not show short-paths, and xml representable characters for
non-ascii characters, when found in the database objects, and the file
PATH.
Fixes #2174, #1797, #2166, #1940
Initial patch by: Surinder Kumar
Reviewed by: Murtuza Zabuawala
2017-03-07 04:00:57 -06:00
|
|
|
username
|
|
|
|
)
|
2016-05-12 13:34:28 -05:00
|
|
|
|
2023-03-14 07:51:18 -05:00
|
|
|
username = preprocess_username(user.username)
|
2020-09-11 09:25:19 -05:00
|
|
|
|
2023-03-06 05:33:47 -06:00
|
|
|
if is_shared_storage:
|
|
|
|
# Figure out the new style storage directory name
|
|
|
|
storage_dir = os.path.join(
|
|
|
|
storage_dir.decode('utf-8') if hasattr(storage_dir, 'decode')
|
|
|
|
else storage_dir
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
# Figure out the new style storage directory name
|
|
|
|
storage_dir = os.path.join(
|
|
|
|
storage_dir.decode('utf-8') if hasattr(storage_dir, 'decode')
|
|
|
|
else storage_dir,
|
|
|
|
username
|
|
|
|
)
|
2019-03-22 04:36:13 -05:00
|
|
|
|
|
|
|
# Rename an old-style storage directory, if the new style doesn't exist
|
|
|
|
if os.path.exists(old_storage_dir) and not os.path.exists(storage_dir):
|
|
|
|
current_app.logger.warning(
|
|
|
|
'Renaming storage directory %s to %s.',
|
|
|
|
old_storage_dir, storage_dir
|
|
|
|
)
|
|
|
|
os.rename(old_storage_dir, storage_dir)
|
|
|
|
|
2016-05-12 13:34:28 -05:00
|
|
|
if not os.path.exists(storage_dir):
|
|
|
|
os.makedirs(storage_dir, int('700', 8))
|
|
|
|
|
|
|
|
return storage_dir
|
|
|
|
|
|
|
|
|
2022-09-09 08:06:51 -05:00
|
|
|
def init_app():
|
2023-03-14 08:10:53 -05:00
|
|
|
# Don't move this import statement to the top of the file,
|
|
|
|
# it throws circular import error.
|
|
|
|
import config
|
2016-05-12 13:34:28 -05:00
|
|
|
if config.SERVER_MODE is not True:
|
|
|
|
return None
|
|
|
|
|
|
|
|
storage_dir = getattr(
|
|
|
|
config, 'STORAGE_DIR',
|
|
|
|
os.path.join(
|
|
|
|
os.path.realpath(
|
2023-06-12 08:14:31 -05:00
|
|
|
os.path.expanduser(PGADMIN_PATH)
|
2016-05-12 13:34:28 -05:00
|
|
|
), 'storage'
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2016-05-13 14:18:11 -05:00
|
|
|
if storage_dir and not os.path.isdir(storage_dir):
|
2016-05-12 13:34:28 -05:00
|
|
|
if os.path.exists(storage_dir):
|
2020-08-07 02:07:00 -05:00
|
|
|
raise InternalServerError(
|
2018-01-31 07:58:55 -06:00
|
|
|
'The path specified for the storage directory is not a '
|
|
|
|
'directory.'
|
2016-05-12 13:34:28 -05:00
|
|
|
)
|
|
|
|
os.makedirs(storage_dir, int('700', 8))
|
|
|
|
|
2016-06-10 11:06:22 -05:00
|
|
|
if storage_dir and not os.access(storage_dir, os.W_OK | os.R_OK):
|
2020-08-07 02:07:00 -05:00
|
|
|
raise InternalServerError(
|
2018-01-31 07:58:55 -06:00
|
|
|
'The user does not have permission to read and write to the '
|
|
|
|
'specified storage directory.'
|
2016-05-12 13:34:28 -05:00
|
|
|
)
|
2018-03-19 12:09:19 -05:00
|
|
|
|
|
|
|
|
|
|
|
def get_cookie_path():
|
|
|
|
cookie_root_path = '/'
|
|
|
|
pgadmin_root_path = url_for('browser.index')
|
|
|
|
if pgadmin_root_path != '/browser/':
|
|
|
|
cookie_root_path = pgadmin_root_path.replace(
|
|
|
|
'/browser/', ''
|
|
|
|
)
|
|
|
|
return cookie_root_path
|
2023-03-14 07:51:18 -05:00
|
|
|
|
|
|
|
|
|
|
|
def create_users_storage_directory():
|
|
|
|
"""
|
|
|
|
This function is used to iterate through all the users and
|
|
|
|
create users directory if not already created.
|
|
|
|
"""
|
2023-03-14 08:10:53 -05:00
|
|
|
# Don't move this import statement to the top of the file,
|
|
|
|
# it throws circular import error.
|
|
|
|
import config
|
2023-03-14 07:51:18 -05:00
|
|
|
if not config.SERVER_MODE:
|
|
|
|
return None
|
|
|
|
|
|
|
|
users = User.query.all()
|
|
|
|
|
|
|
|
for usr in users:
|
|
|
|
username = preprocess_username(usr.username)
|
|
|
|
|
|
|
|
storage_dir = getattr(
|
|
|
|
config, 'STORAGE_DIR',
|
|
|
|
os.path.join(
|
|
|
|
os.path.realpath(
|
2023-06-12 08:14:31 -05:00
|
|
|
os.path.expanduser(PGADMIN_PATH)
|
2023-03-14 07:51:18 -05:00
|
|
|
), 'storage'
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
if storage_dir is None:
|
|
|
|
return None
|
|
|
|
|
|
|
|
storage_dir = os.path.join(
|
|
|
|
storage_dir.decode('utf-8') if hasattr(storage_dir, 'decode')
|
|
|
|
else storage_dir, username
|
|
|
|
)
|
|
|
|
|
|
|
|
if not os.path.exists(storage_dir):
|
|
|
|
os.makedirs(storage_dir, int('700', 8))
|