mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2024-11-21 16:27:39 -06:00
Administer pgAdmin Users and Preferences Using the Command Line Interface (CLI). #2483
This commit is contained in:
parent
a973c9c62c
commit
0d287df6dd
@ -61,7 +61,7 @@ Exporting Servers
|
||||
*****************
|
||||
|
||||
To export the servers defined in an installation, simply invoke ``setup.py`` with
|
||||
the ``--dump-servers`` command line option, followed by the name (and if required,
|
||||
the ``dump-servers`` command line option, followed by the name (and if required,
|
||||
path) to the desired output file. By default, servers owned by the desktop mode
|
||||
user will be dumped (pgadmin4@pgadmin.org by default - see the DESKTOP_USER
|
||||
setting in ``config.py``). This can be overridden with the ``--user`` command
|
||||
@ -73,28 +73,28 @@ For example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
/path/to/python /path/to/setup.py --dump-servers output_file.json
|
||||
/path/to/python /path/to/setup.py dump-servers output_file.json
|
||||
|
||||
# or, to specify a non-default user name:
|
||||
# or, to specify a non-default user name and auth source (the default is Internal):
|
||||
|
||||
/path/to/python /path/to/setup.py --dump-servers output_file.json --user user@example.com
|
||||
/path/to/python /path/to/setup.py dump-servers output_file.json --user user@example.com --auth_source ldap
|
||||
|
||||
# to specify a pgAdmin config DB file:
|
||||
|
||||
/path/to/python /path/to/setup.py --dump-servers output_file.json --sqlite-path /path/to/pgadmin4.db
|
||||
/path/to/python /path/to/setup.py dump-servers output_file.json --sqlite-path /path/to/pgadmin4.db
|
||||
|
||||
To export only certain servers, use the ``--servers`` option and list one or
|
||||
To export only certain servers, use the ``--server`` option and list one or
|
||||
more server IDs. For example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
/path/to/python /path/to/setup.py --dump-servers output_file.json --server 1 2 5
|
||||
/path/to/python /path/to/setup.py dump-servers output_file.json --server 1 --server 2 --server 5
|
||||
|
||||
Importing Servers
|
||||
*****************
|
||||
|
||||
To import the servers defined in a JSON file, simply invoke ``setup.py`` with
|
||||
the ``--load-servers`` command line option, followed by the name (and if required,
|
||||
the ``load-servers`` command line option, followed by the name (and if required,
|
||||
path) of the JSON file containing the server definitions. Servers will be owned
|
||||
by the desktop mode user (pgadmin4@pgadmin.org by default - see the DESKTOP_USER
|
||||
setting in ``config.py``). This can be overridden with the ``--user`` command
|
||||
@ -108,19 +108,19 @@ desktop mode. By default SQLITE_PATH setting in ``config.py`` is taken. For exam
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
/path/to/python /path/to/setup.py --load-servers input_file.json
|
||||
/path/to/python /path/to/setup.py load-servers input_file.json
|
||||
|
||||
# or, to replace the list of servers with the newly imported one:
|
||||
|
||||
/path/to/python /path/to/setup.py --load-servers input_file.json --replace
|
||||
/path/to/python /path/to/setup.py load-servers input_file.json --replace
|
||||
|
||||
# or, to specify a non-default user name to own the new servers:
|
||||
# or, to specify a non-default user name and auth source (the default is Internal) to own the new servers:
|
||||
|
||||
/path/to/python /path/to/setup.py --load-servers input_file.json --user user@example.com
|
||||
/path/to/python /path/to/setup.py load-servers input_file.json --user user@example.com
|
||||
|
||||
# to specify a pgAdmin config DB file:
|
||||
|
||||
/path/to/python /path/to/setup.py --load-servers input_file.json --sqlite-path /path/to/pgadmin4.db
|
||||
/path/to/python /path/to/setup.py load-servers input_file.json --sqlite-path /path/to/pgadmin4.db
|
||||
|
||||
If any Servers are defined with a Server Group that is not already present in
|
||||
the configuration database, the required Group will be created.
|
||||
|
@ -549,3 +549,40 @@ Use the fields on the *Options* panel to specify storage preferences.
|
||||
|
||||
* When the *Show hidden files and folders?* switch is set to *True*, the file
|
||||
manager will display hidden files and folders.
|
||||
|
||||
|
||||
Using 'setup.py' command line script
|
||||
####################################
|
||||
|
||||
.. note:: To manage preferences using ``setup.py`` script, you must use
|
||||
the Python interpreter that is normally used to run pgAdmin to ensure
|
||||
that the required Python packages are available. In most packages, this
|
||||
can be found in the Python Virtual Environment that can be found in the
|
||||
installation directory. When using platform-native packages, the system
|
||||
installation of Python may be the one used by pgAdmin.
|
||||
|
||||
|
||||
Manage Preferences
|
||||
******************
|
||||
|
||||
Get Preferences
|
||||
***************
|
||||
To get all the preferences listed, invoke ``setup.py`` with ``get-prefs`` command line option.
|
||||
You can also get this mapping by hovering the individual preference in the Preference UI dialog.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
/path/to/python /path/to/setup.py get-prefs
|
||||
|
||||
Save Preferences
|
||||
****************
|
||||
To save the preferences, invoke ``setup.py`` with ``set-prefs`` command line option, followed by username,
|
||||
preference_key=value and auth_source. Multiple preference can be given too by a space separated.
|
||||
If auth_source is not given, Internal authentication will be consider by default.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
/path/to/python /path/to/setup.py set-prefs user1@gmail.com sqleditor:editor:comma_first=true
|
||||
|
||||
# to specify an auth_source
|
||||
/path/to/python /path/to/setup.py set-prefs user1@gmail.com sqleditor:editor:comma_first=true --auth-source=ldap
|
||||
|
@ -75,3 +75,142 @@ users, but otherwise have the same capabilities as those with the *User* role.
|
||||
* Click the *Help* button (?) to access online help.
|
||||
* Click the *Close* button to save work. You will be prompted to return to the
|
||||
dialog if your selections cannot be saved.
|
||||
|
||||
|
||||
Using 'setup.py' command line script
|
||||
####################################
|
||||
|
||||
.. note:: To manage users using ``setup.py`` script, you must use
|
||||
the Python interpreter that is normally used to run pgAdmin to ensure
|
||||
that the required Python packages are available. In most packages, this
|
||||
can be found in the Python Virtual Environment that can be found in the
|
||||
installation directory. When using platform-native packages, the system
|
||||
installation of Python may be the one used by pgAdmin.
|
||||
|
||||
When using PIP wheel package to install pgadmin, all the commands can be used
|
||||
without Python interpreter.
|
||||
|
||||
Some of the examples:
|
||||
pgadmin4-cli add-user user1@gmail.com password --role 1
|
||||
pgadmin4-cli get-prefs
|
||||
|
||||
Manage Users
|
||||
*************
|
||||
|
||||
Add User
|
||||
*********
|
||||
|
||||
To add user, invoke ``setup.py`` with ``add-user`` command line option, followed by
|
||||
email and password. role and active will be optional fields.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
/path/to/python /path/to/setup.py add-user user1@gmail.com password
|
||||
|
||||
# to specify a role, admin and non-admin users:
|
||||
|
||||
/path/to/python /path/to/setup.py add-user user1@gmail.com password --admin
|
||||
/path/to/python /path/to/setup.py add-user user1@gmail.com password --nonadmin
|
||||
|
||||
# to specify user's status
|
||||
|
||||
/path/to/python /path/to/setup.py add-user user1@gmail.com password --active
|
||||
/path/to/python /path/to/setup.py add-user user1@gmail.com password --inactive
|
||||
|
||||
Add External User
|
||||
*****************
|
||||
|
||||
To add external authentication user, invoke ``setup.py`` with ``add-external-user`` command line option,
|
||||
followed by email, password and authentication source. email, role and status will be optional fields.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
/path/to/python /path/to/setup.py add-external-user user1@gmail.com ldap
|
||||
|
||||
# to specify an email:
|
||||
|
||||
/path/to/python /path/to/setup.py add-external-user ldapuser ldap --email user1@gmail.com
|
||||
|
||||
# to specify a role, admin and non-admin user:
|
||||
|
||||
/path/to/python /path/to/setup.py add-external-user ldapuser ldap --admin
|
||||
/path/to/python /path/to/setup.py add-external-user ldapuser ldap --nonadmin
|
||||
|
||||
# to specify user's status
|
||||
|
||||
/path/to/python /path/to/setup.py add-external-user user1@gmail.com ldap --active
|
||||
/path/to/python /path/to/setup.py add-external-user user1@gmail.com ldap --inactive
|
||||
|
||||
Update User
|
||||
***********
|
||||
|
||||
To update user, invoke ``setup.py`` with ``update-user`` command line option, followed by
|
||||
email address. password, role and active are updatable fields.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
/path/to/python /path/to/setup.py update-user user1@gmail.com --password new-password
|
||||
|
||||
# to specify a role, admin and non-admin user:
|
||||
|
||||
/path/to/python /path/to/setup.py update-user user1@gmail.com password --role --admin
|
||||
/path/to/python /path/to/setup.py update-user user1@gmail.com password --role --nonadmin
|
||||
|
||||
# to specify user's status
|
||||
|
||||
/path/to/python /path/to/setup.py update-user user1@gmail.com password --active
|
||||
/path/to/python /path/to/setup.py update-user user1@gmail.com password --inactive
|
||||
|
||||
Update External User
|
||||
********************
|
||||
|
||||
To update the external user, invoke ``setup.py`` with ``update-external-user`` command line option,
|
||||
followed by username and auth source. email, password, role and active are updatable fields.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# to change email address:
|
||||
|
||||
/path/to/python /path/to/setup.py update-external-user ldap ldapuser --email newemail@gmail.com
|
||||
|
||||
# to specify a role, admin and non-admin user:
|
||||
|
||||
/path/to/python /path/to/setup.py update-user user1@gmail.com password --role --admin
|
||||
/path/to/python /path/to/setup.py update-user user1@gmail.com password --role --nonadmin
|
||||
|
||||
# to change user's status
|
||||
|
||||
/path/to/python /path/to/setup.py update-user ldap ldapuser --active
|
||||
/path/to/python /path/to/setup.py update-user ldap ldapuser --inactive
|
||||
|
||||
Delete User
|
||||
***********
|
||||
|
||||
To delete the user, invoke ``setup.py`` with ``delete-user`` command line option, followed by
|
||||
username and auth_source. For Internal users, email adress will be used instead of username.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
/path/to/python /path/to/setup.py delete-user user1@gmail.com --auth-source internal
|
||||
/path/to/python /path/to/setup.py delete-user ldapuser --auth-source ldap
|
||||
|
||||
|
||||
Get User
|
||||
********
|
||||
|
||||
To get the user details, invoke ``setup.py`` with ``get-users`` command line option, followed by
|
||||
username/email address.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# to list all the users:
|
||||
/path/to/python /path/to/setup.py get-users
|
||||
|
||||
# to get the user's details:
|
||||
/path/to/python /path/to/setup.py get-users --username user1@gmail.com
|
||||
|
||||
|
||||
Output
|
||||
******
|
||||
|
||||
Each command output can be seen in the json format too by adding --json command line option.
|
@ -70,9 +70,9 @@ if [ ! -f /var/lib/pgadmin/pgadmin4.db ]; then
|
||||
# When running in Desktop mode, no user is created
|
||||
# so we have to import servers anonymously
|
||||
if [ "${PGADMIN_CONFIG_SERVER_MODE}" = "False" ]; then
|
||||
/venv/bin/python3 /pgadmin4/setup.py --load-servers "${PGADMIN_SERVER_JSON_FILE}"
|
||||
/venv/bin/python3 /pgadmin4/setup.py load-servers "${PGADMIN_SERVER_JSON_FILE}"
|
||||
else
|
||||
/venv/bin/python3 /pgadmin4/setup.py --load-servers "${PGADMIN_SERVER_JSON_FILE}" --user "${PGADMIN_DEFAULT_EMAIL}"
|
||||
/venv/bin/python3 /pgadmin4/setup.py load-servers "${PGADMIN_SERVER_JSON_FILE}" --user "${PGADMIN_DEFAULT_EMAIL}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
@ -72,7 +72,7 @@ fi
|
||||
|
||||
# Run setup script first:
|
||||
echo "Creating configuration database..."
|
||||
if ! /usr/pgadmin4/venv/bin/python3 /usr/pgadmin4/web/setup.py;
|
||||
if ! /usr/pgadmin4/venv/bin/python3 /usr/pgadmin4/web/setup.py setup-db;
|
||||
then
|
||||
echo "Error setting up server mode. Please examine the output above."
|
||||
exit 1
|
||||
|
@ -100,7 +100,8 @@ setup(
|
||||
},
|
||||
|
||||
entry_points={
|
||||
'console_scripts': ['pgadmin4=pgadmin4.pgAdmin4:main'],
|
||||
'console_scripts': ['pgadmin4=pgadmin4.pgAdmin4:main',
|
||||
'pgadmin4-cli=pgadmin4.setup:main'],
|
||||
},
|
||||
|
||||
)
|
||||
|
@ -60,3 +60,4 @@ keyring==24.*; python_version > '3.7'
|
||||
keyring==23.*; python_version <= '3.7'
|
||||
Werkzeug==2.3.*; python_version > '3.7'
|
||||
Werkzeug==2.2.3; python_version <= '3.7'
|
||||
typer[all]==0.9.*
|
||||
|
@ -105,7 +105,7 @@ app = create_app()
|
||||
app.config['sessions'] = dict()
|
||||
|
||||
if setup_db_required:
|
||||
setup.setup_db(app)
|
||||
setup.setup_db()
|
||||
|
||||
# Authentication sources
|
||||
if len(config.AUTHENTICATION_SOURCES) > 0:
|
||||
|
@ -216,6 +216,7 @@ def create_app(app_name=None):
|
||||
app.config.from_object(config)
|
||||
app.config.update(dict(PROPAGATE_EXCEPTIONS=True))
|
||||
|
||||
config.SETTINGS_SCHEMA_VERSION = CURRENT_SCHEMA_VERSION
|
||||
##########################################################################
|
||||
# Setup logging and log the application startup
|
||||
##########################################################################
|
||||
|
@ -185,7 +185,7 @@ class ServerGroupView(NodeView):
|
||||
# This matches the behavior of
|
||||
# web/pgadmin/utils/__init.py__#clear_database_servers
|
||||
# called by the setup script when importing and replacing servers:
|
||||
# `python setup.py --load-servers input_file.json --replace`
|
||||
# `python setup.py load-servers input_file.json --replace`
|
||||
sg = groups.first()
|
||||
|
||||
shared_servers = Server.query.filter_by(servergroup_id=gid,
|
||||
|
@ -48,8 +48,8 @@ class PreferencesModule(PgAdminModule):
|
||||
'preferences.index',
|
||||
'preferences.get_by_name',
|
||||
'preferences.get_all',
|
||||
'preferences.get_all_cli',
|
||||
'preferences.update_pref'
|
||||
|
||||
]
|
||||
|
||||
|
||||
@ -181,6 +181,28 @@ def preferences_s():
|
||||
)
|
||||
|
||||
|
||||
@blueprint.route("/get_all_cli", methods=["GET"], endpoint='get_all_cli')
|
||||
def get_all_cli():
|
||||
"""Fetch all preferences for caching."""
|
||||
# Load Preferences
|
||||
pref = Preferences.preferences()
|
||||
res = {}
|
||||
|
||||
for m in pref:
|
||||
if len(m['categories']):
|
||||
for c in m['categories']:
|
||||
for p in c['preferences']:
|
||||
p['module'] = m['name']
|
||||
res["{0}:{1}:{2}".format(m['label'], p['label'], c['label']
|
||||
)] = "{0}:{1}:{2}".format(
|
||||
p['module'],c['name'],p['name'])
|
||||
|
||||
return ajax_response(
|
||||
response=res,
|
||||
status=200
|
||||
)
|
||||
|
||||
|
||||
def get_data():
|
||||
"""
|
||||
Get preferences data.
|
||||
@ -249,6 +271,26 @@ def save():
|
||||
return response
|
||||
|
||||
|
||||
def save_pref(data):
|
||||
"""
|
||||
Save a specific preference.
|
||||
"""
|
||||
|
||||
if data['name'] in ['vw_edt_tab_title_placeholder',
|
||||
'qt_tab_title_placeholder',
|
||||
'debugger_tab_title_placeholder'] \
|
||||
and data['value'].isspace():
|
||||
data['value'] = ''
|
||||
|
||||
res, msg = Preferences.save_cli(
|
||||
data['mid'], data['category_id'], data['id'], data['user_id'],
|
||||
data['value'])
|
||||
|
||||
if not res:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@blueprint.route("/update", methods=["PUT"], endpoint="update_pref")
|
||||
@login_required
|
||||
def update():
|
||||
|
@ -378,6 +378,7 @@ export default function PreferencesComponent({ ...props }) {
|
||||
if(field.visible && _.isNull(firstElement)) {
|
||||
firstElement = field;
|
||||
}
|
||||
field.tooltip = item._parent._metadata.data.name + ':' + item._metadata.data.name + ':' + field.name;
|
||||
});
|
||||
setLoadTree(crypto.getRandomValues(new Uint16Array(1)));
|
||||
initTreeTimeout = setTimeout(() => {
|
||||
@ -598,6 +599,10 @@ export default function PreferencesComponent({ ...props }) {
|
||||
window.open(url_for('help.static', { 'filename': 'preferences.html' }), 'pgadmin_help');
|
||||
};
|
||||
|
||||
const onDialogHelpCli = () => {
|
||||
window.open(url_for('preferences.get_all_cli'), 'pgadmin_help');
|
||||
};
|
||||
|
||||
return (
|
||||
<Box height={'100%'}>
|
||||
<Box className={classes.root}>
|
||||
@ -623,6 +628,7 @@ export default function PreferencesComponent({ ...props }) {
|
||||
<Box className={classes.footer}>
|
||||
<Box>
|
||||
<PgIconButton data-test="dialog-help" onClick={onDialogHelp} icon={<HelpIcon />} title={gettext('Help for this dialog.')} />
|
||||
<PgIconButton data-test="dialog-help-cli" onClick={onDialogHelpCli} icon={<HelpIcon />} title={gettext('Help for this dialog.')} />
|
||||
</Box>
|
||||
<Box className={classes.actionBtn} marginLeft="auto">
|
||||
<DefaultButton className={classes.buttonMargin} onClick={() => { props.closeModal();}} startIcon={<CloseSharpIcon onClick={() => { props.closeModal();}} />}>
|
||||
|
@ -36,13 +36,13 @@ class ImportExportServersTestCase(BaseTestGenerator):
|
||||
|
||||
# Load the servers
|
||||
os.system(
|
||||
"python \"%s\" --load-servers \"%s\" 2> %s" %
|
||||
"python \"%s\" load-servers \"%s\" 2> %s" %
|
||||
(setup, os.path.join(path, "servers.json"), os.devnull)
|
||||
)
|
||||
|
||||
# And dump them again
|
||||
tf = tempfile.NamedTemporaryFile(delete=False)
|
||||
os.system("python \"%s\" --dump-servers \"%s\" 2> %s" %
|
||||
os.system("python \"%s\" dump-servers \"%s\" 2> %s" %
|
||||
(setup, tf.name, os.devnull))
|
||||
|
||||
# Compare the JSON files, ignoring servers that exist in our
|
||||
|
@ -8,7 +8,7 @@
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||
import { Box, makeStyles, Tab, Tabs } from '@material-ui/core';
|
||||
import { Box, makeStyles, Tab, Tabs, Tooltip } from '@material-ui/core';
|
||||
import _ from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import clsx from 'clsx';
|
||||
@ -359,6 +359,10 @@ export default function FormView({
|
||||
]}
|
||||
/>;
|
||||
|
||||
if(field.tooltip) {
|
||||
currentControl = <Tooltip title={field.tooltip} aria-label={field.tooltip}>{currentControl}</Tooltip>;
|
||||
}
|
||||
|
||||
if(field.isFullTab && field.helpMessage) {
|
||||
currentControl = (<React.Fragment key={`coll-${field.id}`}>
|
||||
<FormNote key={`note-${field.id}`} text={field.helpMessage}/>
|
||||
|
@ -212,7 +212,7 @@ const ALLOWED_PROPS_FIELD_COMMON = [
|
||||
'label', 'options', 'optionsLoaded', 'controlProps', 'schema', 'inputRef',
|
||||
'visible', 'autoFocus', 'helpMessage', 'className', 'optionsReloadBasis',
|
||||
'orientation', 'isvalidate', 'fields', 'radioType', 'hideBrowseButton', 'btnName', 'hidden',
|
||||
'withContainer', 'controlGridBasis', 'hasCheckbox', 'treeData'
|
||||
'withContainer', 'controlGridBasis', 'hasCheckbox', 'treeData', 'title'
|
||||
];
|
||||
|
||||
const ALLOWED_PROPS_FIELD_FORM = [
|
||||
|
@ -27,7 +27,7 @@ const useStyles = makeStyles((theme) => ({
|
||||
}
|
||||
}));
|
||||
|
||||
export default function KeyboardShortcuts({ value, onChange, fields }) {
|
||||
export default function KeyboardShortcuts({ value, onChange, fields, title }) {
|
||||
const classes = useStyles();
|
||||
const keyCid = _.uniqueId('c');
|
||||
const keyhelpid = `h${keyCid}`;
|
||||
@ -87,11 +87,11 @@ export default function KeyboardShortcuts({ value, onChange, fields }) {
|
||||
<Typography id={keyLabel}>{element.label}</Typography>
|
||||
</Grid>
|
||||
<Grid item lg={8} md={8} sm={8} xs={12}>
|
||||
<InputText id={keyCid} helpid={keyhelpid} type='text' value={value?.key?.char} controlProps={
|
||||
<InputText id={keyCid} helpid={keyhelpid} value={value?.key?.char} controlProps={
|
||||
{
|
||||
onKeyDown: onKeyDown,
|
||||
}
|
||||
}></InputText>
|
||||
} title={title} />
|
||||
</Grid>
|
||||
</Grid>;
|
||||
} else if (element.name == 'shift') {
|
||||
@ -129,5 +129,6 @@ KeyboardShortcuts.propTypes = {
|
||||
value: PropTypes.object,
|
||||
onChange: PropTypes.func,
|
||||
controlProps: PropTypes.object,
|
||||
fields: PropTypes.array
|
||||
fields: PropTypes.array,
|
||||
title: PropTypes.string
|
||||
};
|
||||
|
@ -552,10 +552,12 @@ def update_user(uid, data):
|
||||
# Username and email can not be changed for internal users
|
||||
if usr.auth_source == INTERNAL:
|
||||
non_editable_params = ('username', 'email')
|
||||
else:
|
||||
non_editable_params = ('username',)
|
||||
|
||||
for f in non_editable_params:
|
||||
if f in data:
|
||||
return False, _("'{0}' is not allowed to modify.").format(f)
|
||||
for f in non_editable_params:
|
||||
if f in data:
|
||||
return False, _("'{0}' is not allowed to modify.").format(f)
|
||||
|
||||
try:
|
||||
new_data = validate_user(data)
|
||||
@ -580,6 +582,7 @@ def delete_user(uid):
|
||||
This function is used to delete the users
|
||||
"""
|
||||
usr = User.query.get(uid)
|
||||
|
||||
if not usr:
|
||||
return False, _("Unable to update user '{0}'").format(uid)
|
||||
|
||||
|
@ -24,7 +24,7 @@ from threading import Lock
|
||||
from .paths import get_storage_directory
|
||||
from .preferences import Preferences
|
||||
from pgadmin.utils.constants import UTILITIES_ARRAY, USER_NOT_FOUND, \
|
||||
MY_STORAGE, ACCESS_DENIED_MESSAGE
|
||||
MY_STORAGE, ACCESS_DENIED_MESSAGE, INTERNAL
|
||||
from pgadmin.utils.ajax import make_json_response
|
||||
from pgadmin.model import db, User, ServerGroup, Server
|
||||
from urllib.parse import unquote
|
||||
@ -439,10 +439,11 @@ def add_value(attr_dict, key, value):
|
||||
|
||||
|
||||
def dump_database_servers(output_file, selected_servers,
|
||||
dump_user=current_user, from_setup=False):
|
||||
dump_user=current_user, from_setup=False,
|
||||
auth_source=INTERNAL):
|
||||
"""Dump the server groups and servers.
|
||||
"""
|
||||
user = _does_user_exist(dump_user, from_setup)
|
||||
user = _does_user_exist(dump_user, from_setup, auth_source)
|
||||
if user is None:
|
||||
return False, USER_NOT_FOUND % dump_user
|
||||
|
||||
@ -456,7 +457,10 @@ def dump_database_servers(output_file, selected_servers,
|
||||
servers = Server.query.filter_by(user_id=user_id).all()
|
||||
server_dict = {}
|
||||
for server in servers:
|
||||
if selected_servers is None or str(server.id) in selected_servers:
|
||||
if selected_servers is None or (
|
||||
isinstance(selected_servers, list) and len(selected_servers) == 0)\
|
||||
or str(server.id) in selected_servers\
|
||||
or server.id in selected_servers:
|
||||
# Get the group name
|
||||
group_name = ServerGroup.query.filter_by(
|
||||
user_id=user_id, id=server.servergroup_id).first().name
|
||||
@ -592,10 +596,11 @@ def validate_json_data(data, is_admin):
|
||||
|
||||
|
||||
def load_database_servers(input_file, selected_servers,
|
||||
load_user=current_user, from_setup=False):
|
||||
load_user=current_user, from_setup=False,
|
||||
auth_source=INTERNAL):
|
||||
"""Load server groups and servers.
|
||||
"""
|
||||
user = _does_user_exist(load_user, from_setup)
|
||||
user = _does_user_exist(load_user, from_setup, auth_source)
|
||||
if user is None:
|
||||
return False, USER_NOT_FOUND % load_user
|
||||
|
||||
@ -745,10 +750,11 @@ def load_database_servers(input_file, selected_servers,
|
||||
return True, msg
|
||||
|
||||
|
||||
def clear_database_servers(load_user=current_user, from_setup=False):
|
||||
def clear_database_servers(load_user=current_user, from_setup=False,
|
||||
auth_source=INTERNAL):
|
||||
"""Clear groups and servers configurations.
|
||||
"""
|
||||
user = _does_user_exist(load_user, from_setup)
|
||||
user = _does_user_exist(load_user, from_setup, auth_source)
|
||||
if user is None:
|
||||
return False
|
||||
|
||||
@ -782,14 +788,16 @@ def clear_database_servers(load_user=current_user, from_setup=False):
|
||||
return False, error_msg
|
||||
|
||||
|
||||
def _does_user_exist(user, from_setup):
|
||||
def _does_user_exist(user, from_setup, auth_source=INTERNAL):
|
||||
"""
|
||||
This function will check user is exist or not. If exist then return
|
||||
"""
|
||||
if isinstance(user, User):
|
||||
user = user.email
|
||||
user = user.username
|
||||
auth_source = user.auth_source
|
||||
|
||||
new_user = User.query.filter_by(email=user).first()
|
||||
new_user = User.query.filter_by(username=user,
|
||||
auth_source=auth_source).first()
|
||||
|
||||
if new_user is None:
|
||||
print(USER_NOT_FOUND % user)
|
||||
|
@ -41,6 +41,7 @@ class _PGCSRFProtect(CSRFProtect):
|
||||
'pgadmin.authenticate.login',
|
||||
'pgadmin.tools.erd.panel',
|
||||
'pgadmin.tools.psql.panel',
|
||||
'pgadmin.preferences.get_all_cli',
|
||||
]
|
||||
|
||||
for exempt in exempt_views:
|
||||
|
@ -594,6 +594,34 @@ class Preferences():
|
||||
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def save_cli(cls, mid, cid, pid, user_id, value):
|
||||
"""
|
||||
save
|
||||
Update the value for the preference in the configuration database.
|
||||
|
||||
:param mid: Module ID
|
||||
:param cid: Category ID
|
||||
:param pid: Preference ID
|
||||
:param value: Value for the options
|
||||
"""
|
||||
|
||||
pref = UserPrefTable.query.filter_by(
|
||||
pid=pid
|
||||
).filter_by(uid=user_id).first()
|
||||
|
||||
value = "{}".format(value)
|
||||
if pref is None:
|
||||
pref = UserPrefTable(
|
||||
uid=user_id, pid=pid, value=value
|
||||
)
|
||||
db.session.add(pref)
|
||||
else:
|
||||
pref.value = value
|
||||
db.session.commit()
|
||||
|
||||
return True, None
|
||||
|
||||
@classmethod
|
||||
def save(cls, mid, cid, pid, value):
|
||||
"""
|
||||
|
@ -55,7 +55,7 @@ describe('KeyboardShortcuts', () => {
|
||||
fields={fields}
|
||||
controlProps={{
|
||||
extraprop: 'test',
|
||||
keyDown: onChange
|
||||
'keydown': onChange
|
||||
}}
|
||||
onChange={onChange}
|
||||
/>);
|
||||
|
@ -23,6 +23,7 @@ import threading
|
||||
import time
|
||||
import unittest
|
||||
import asyncio
|
||||
|
||||
from selenium.webdriver.firefox.options import Options as FirefoxOptions
|
||||
|
||||
if sys.platform == "win32":
|
||||
@ -89,9 +90,6 @@ if pgadmin_credentials and \
|
||||
os.environ['PGADMIN_SETUP_PASSWORD'] = str(pgadmin_credentials[
|
||||
'login_password'])
|
||||
|
||||
# Execute the setup file
|
||||
exec(open("setup.py").read())
|
||||
|
||||
# Get the config database schema version. We store this in pgadmin.model
|
||||
# as it turns out that putting it in the config files isn't a great idea
|
||||
from pgadmin.model import SCHEMA_VERSION
|
||||
@ -110,7 +108,6 @@ config.CONSOLE_LOG_LEVEL = WARNING
|
||||
|
||||
# Create the app
|
||||
from pgAdmin4 import app
|
||||
# app = create_app()
|
||||
app.app_context().push()
|
||||
|
||||
app.PGADMIN_INT_KEY = ''
|
||||
|
551
web/setup.py
551
web/setup.py
@ -10,9 +10,16 @@
|
||||
"""Perform the initial setup of the application, by creating the auth
|
||||
and settings database."""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import typer
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
from rich import box, print
|
||||
import json as jsonlib
|
||||
|
||||
console = Console()
|
||||
app = typer.Typer()
|
||||
|
||||
# We need to include the root directory in sys.path to ensure that we can
|
||||
# find everything we need when running in the standalone runtime.
|
||||
@ -29,69 +36,446 @@ if 'SERVER_MODE' in globals():
|
||||
else:
|
||||
builtins.SERVER_MODE = None
|
||||
|
||||
from pgadmin.model import db, Version, SCHEMA_VERSION as CURRENT_SCHEMA_VERSION
|
||||
from pgadmin.model import db, Version, User,\
|
||||
SCHEMA_VERSION as CURRENT_SCHEMA_VERSION
|
||||
from pgadmin import create_app
|
||||
from pgadmin.utils import clear_database_servers, dump_database_servers,\
|
||||
load_database_servers
|
||||
from pgadmin.setup import db_upgrade, create_app_data_directory
|
||||
from typing import Optional, List
|
||||
from typing_extensions import Annotated
|
||||
from pgadmin.utils.constants import MIMETYPE_APP_JS, INTERNAL, LDAP, OAUTH2,\
|
||||
KERBEROS, WEBSERVER
|
||||
from pgadmin.tools.user_management import create_user, delete_user, update_user
|
||||
from enum import Enum
|
||||
|
||||
app = typer.Typer(pretty_exceptions_show_locals=False)
|
||||
|
||||
|
||||
def dump_servers(args):
|
||||
"""Dump the server groups and servers.
|
||||
class ManageServers:
|
||||
|
||||
Args:
|
||||
args (ArgParser): The parsed command line options
|
||||
"""
|
||||
@app.command()
|
||||
def dump_servers(output_file: str, user: Optional[str] = None,
|
||||
auth_source: Optional[str] = INTERNAL,
|
||||
sqlite_path: Optional[str] = None,
|
||||
server: List[int] = None):
|
||||
"""Dump the server groups and servers. """
|
||||
|
||||
# What user?
|
||||
if args.user is not None:
|
||||
dump_user = args.user
|
||||
else:
|
||||
dump_user = config.DESKTOP_USER
|
||||
# What user?
|
||||
dump_user = user if user is not None else config.DESKTOP_USER
|
||||
|
||||
# And the sqlite path
|
||||
if args.sqlite_path is not None:
|
||||
config.SQLITE_PATH = args.sqlite_path
|
||||
# And the sqlite path
|
||||
if sqlite_path is not None:
|
||||
config.SQLITE_PATH = sqlite_path
|
||||
|
||||
print('----------')
|
||||
print('Dumping servers with:')
|
||||
print('User:', dump_user)
|
||||
print('SQLite pgAdmin config:', config.SQLITE_PATH)
|
||||
print('----------')
|
||||
print('----------')
|
||||
print('Dumping servers with:')
|
||||
print('User:', dump_user)
|
||||
print('SQLite pgAdmin config:', config.SQLITE_PATH)
|
||||
print('----------')
|
||||
|
||||
app = create_app(config.APP_NAME + '-cli')
|
||||
with app.test_request_context():
|
||||
dump_database_servers(args.dump_servers, args.servers, dump_user, True)
|
||||
app = create_app(config.APP_NAME + '-cli')
|
||||
with app.test_request_context():
|
||||
dump_database_servers(output_file, server, dump_user, True,
|
||||
auth_source)
|
||||
|
||||
@app.command()
|
||||
def load_servers(input_file: str, user: Optional[str] = None,
|
||||
auth_source: Optional[str] = INTERNAL,
|
||||
sqlite_path: Optional[str] = None,
|
||||
replace: Optional[bool] = False
|
||||
):
|
||||
|
||||
"""Load server groups and servers."""
|
||||
|
||||
# What user?
|
||||
load_user = user if user is not None else config.DESKTOP_USER
|
||||
|
||||
# And the sqlite path
|
||||
if sqlite_path is not None:
|
||||
config.SQLITE_PATH = sqlite_path
|
||||
|
||||
print('----------')
|
||||
print('Loading servers with:')
|
||||
print('User:', load_user)
|
||||
print('SQLite pgAdmin config:', config.SQLITE_PATH)
|
||||
print('----------')
|
||||
|
||||
app = create_app(config.APP_NAME + '-cli')
|
||||
with app.test_request_context():
|
||||
if replace:
|
||||
clear_database_servers(load_user, True, auth_source)
|
||||
load_database_servers(input_file, None, load_user, True,
|
||||
auth_source)
|
||||
|
||||
|
||||
def load_servers(args):
|
||||
"""Load server groups and servers.
|
||||
|
||||
Args:
|
||||
args (ArgParser): The parsed command line options
|
||||
"""
|
||||
|
||||
# What user?
|
||||
load_user = args.user if args.user is not None else config.DESKTOP_USER
|
||||
|
||||
# And the sqlite path
|
||||
if args.sqlite_path is not None:
|
||||
config.SQLITE_PATH = args.sqlite_path
|
||||
|
||||
print('----------')
|
||||
print('Loading servers with:')
|
||||
print('User:', load_user)
|
||||
print('SQLite pgAdmin config:', config.SQLITE_PATH)
|
||||
print('----------')
|
||||
|
||||
app = create_app(config.APP_NAME + '-cli')
|
||||
with app.test_request_context():
|
||||
load_database_servers(args.load_servers, None, load_user, True)
|
||||
class AuthExtTypes(str, Enum):
|
||||
oauth2 = OAUTH2
|
||||
ldap = LDAP
|
||||
kerberos = KERBEROS
|
||||
webserver = WEBSERVER
|
||||
|
||||
|
||||
def setup_db(app):
|
||||
# Enum class can not be extended
|
||||
class AuthType(str, Enum):
|
||||
oauth2 = OAUTH2
|
||||
ldap = LDAP
|
||||
kerberos = KERBEROS
|
||||
webserver = WEBSERVER
|
||||
internal = INTERNAL
|
||||
|
||||
|
||||
class ManageUsers:
|
||||
|
||||
@app.command()
|
||||
def add_user(email: str, password: str,
|
||||
role: Annotated[Optional[bool], typer.Option(
|
||||
"--admin/--nonadmin")] = False,
|
||||
active: Annotated[Optional[bool],
|
||||
typer.Option("--active/--inactive")] = True,
|
||||
console: Optional[bool] = True,
|
||||
json: Optional[bool] = False
|
||||
):
|
||||
"""Add Internal user. """
|
||||
|
||||
data = {
|
||||
'email': email,
|
||||
'role': 1 if role else 2,
|
||||
'active': active,
|
||||
'auth_source': INTERNAL,
|
||||
'newPassword': password,
|
||||
'confirmPassword': password,
|
||||
}
|
||||
ManageUsers.create_user(data, console, json)
|
||||
|
||||
@app.command()
|
||||
def add_external_user(username: str,
|
||||
auth_source: AuthExtTypes = AuthExtTypes.oauth2,
|
||||
email: Optional[str] = None,
|
||||
role: Annotated[Optional[bool],
|
||||
typer.Option(
|
||||
"--admin/--nonadmin")] = False,
|
||||
active: Annotated[Optional[bool],
|
||||
typer.Option(
|
||||
"--active/--inactive")] = True,
|
||||
console: Optional[bool] = True,
|
||||
json: Optional[bool] = False
|
||||
):
|
||||
"""Add external user, other than Internal like
|
||||
Ldap, Ouath2, Kerberos, Webserver. """
|
||||
|
||||
data = {
|
||||
'username': username,
|
||||
'email': email,
|
||||
'role': 1 if role else 2,
|
||||
'active': active,
|
||||
'auth_source': auth_source
|
||||
}
|
||||
ManageUsers.create_user(data, console, json)
|
||||
|
||||
@app.command()
|
||||
def delete_user(username: str, auth_source: AuthType = AuthType.internal):
|
||||
"""Delete the user. """
|
||||
delete = typer.confirm("Are you sure you want to delete it?")
|
||||
|
||||
if delete:
|
||||
app = create_app(config.APP_NAME + '-cli')
|
||||
with app.test_request_context():
|
||||
uid = ManageUsers.get_user(username=username,
|
||||
auth_source=auth_source)
|
||||
if not uid:
|
||||
print("User not found")
|
||||
else:
|
||||
status, msg = delete_user(uid)
|
||||
if status:
|
||||
print('User deleted successfully.')
|
||||
else:
|
||||
print('Something went wrong. ' + str(msg))
|
||||
|
||||
@app.command()
|
||||
def update_user(email: str,
|
||||
password: Optional[str] = None,
|
||||
role: Annotated[Optional[bool],
|
||||
typer.Option("--admin/--nonadmin"
|
||||
)] = None,
|
||||
active: Annotated[Optional[bool],
|
||||
typer.Option("--active/--inactive"
|
||||
)] = None,
|
||||
console: Optional[bool] = True,
|
||||
json: Optional[bool] = False
|
||||
):
|
||||
"""Update internal user."""
|
||||
|
||||
data = dict()
|
||||
if password:
|
||||
if len(password) < 6:
|
||||
print("Password must be at least 6 characters long.")
|
||||
exit()
|
||||
data['password'] = password
|
||||
|
||||
if role is not None:
|
||||
data['role'] = 1 if role else 2
|
||||
if active is not None:
|
||||
data['active'] = active
|
||||
|
||||
app = create_app(config.APP_NAME + '-cli')
|
||||
with app.test_request_context():
|
||||
uid = ManageUsers.get_user(username=email,
|
||||
auth_source=INTERNAL)
|
||||
if not uid:
|
||||
print("User not found")
|
||||
else:
|
||||
status, msg = update_user(uid, data)
|
||||
if status:
|
||||
_user = ManageUsers.get_users(username=email,
|
||||
auth_source=INTERNAL,
|
||||
console=False)
|
||||
ManageUsers.display_user(_user[0], console, json)
|
||||
else:
|
||||
print('Something went wrong. ' + str(msg))
|
||||
|
||||
@app.command()
|
||||
def get_users(username:Optional[str] = None,
|
||||
auth_source: AuthType = None,
|
||||
console:Optional[bool] = True,
|
||||
json:Optional[bool] = False
|
||||
):
|
||||
"""Get user(s) details."""
|
||||
app = create_app(config.APP_NAME + '-cli')
|
||||
usr = None
|
||||
with app.test_request_context():
|
||||
if username and auth_source:
|
||||
users = User.query.filter_by(username=username,
|
||||
auth_source=auth_source)
|
||||
elif not username and auth_source:
|
||||
users = User.query.filter_by(auth_source=auth_source)
|
||||
elif username and not auth_source:
|
||||
users = User.query.filter_by(username=username)
|
||||
else:
|
||||
users = User.query.all()
|
||||
users_data = []
|
||||
for u in users:
|
||||
_data = {'id': u.id,
|
||||
'username': u.username,
|
||||
'email': u.email,
|
||||
'active': u.active,
|
||||
'role': u.roles[0].id,
|
||||
'auth_source': u.auth_source,
|
||||
'locked': u.locked
|
||||
}
|
||||
users_data.append(_data)
|
||||
if console:
|
||||
ManageUsers.display_user(_data, False, json)
|
||||
if not console:
|
||||
return users_data
|
||||
|
||||
@app.command()
|
||||
def update_external_user(username: str,
|
||||
auth_source: AuthExtTypes = AuthExtTypes.oauth2,
|
||||
email: Optional[str] = None,
|
||||
role: Annotated[Optional[bool],
|
||||
typer.Option("--admin/--nonadmin"
|
||||
)] = None,
|
||||
active: Annotated[
|
||||
Optional[bool],
|
||||
typer.Option("--active/--inactive")] = None,
|
||||
console: Optional[bool] = True,
|
||||
json: Optional[bool] = False
|
||||
):
|
||||
"""Update external users other than Internal like
|
||||
Ldap, Ouath2, Kerberos, Webserver."""
|
||||
|
||||
data = dict()
|
||||
if email:
|
||||
data['email'] = email
|
||||
if role is not None:
|
||||
data['role'] = 1 if role else 2
|
||||
if active is not None:
|
||||
data['active'] = active
|
||||
|
||||
app = create_app(config.APP_NAME + '-cli')
|
||||
with app.test_request_context():
|
||||
uid = ManageUsers.get_user(username=username,
|
||||
auth_source=auth_source)
|
||||
if not uid:
|
||||
print("User not found")
|
||||
else:
|
||||
status, msg = update_user(uid, data)
|
||||
if status:
|
||||
_user = ManageUsers.get_users(username=username,
|
||||
auth_source=auth_source,
|
||||
console=False)
|
||||
ManageUsers.display_user(_user[0], console, json)
|
||||
else:
|
||||
print('Something went wrong. ' + str(msg))
|
||||
|
||||
def create_user(data, console, json):
|
||||
app = create_app(config.APP_NAME + '-cli')
|
||||
with app.test_request_context():
|
||||
username = data['username'] if 'username' in data else\
|
||||
data['email']
|
||||
uid = ManageUsers.get_user(username=username,
|
||||
auth_source=data['auth_source'])
|
||||
if uid:
|
||||
print("User already exists.")
|
||||
exit()
|
||||
|
||||
if 'newPassword' in data and len(data['newPassword']) < 6:
|
||||
print("Password must be at least 6 characters long.")
|
||||
exit()
|
||||
|
||||
status, msg = create_user(data)
|
||||
if status:
|
||||
ManageUsers.display_user(data, console, json)
|
||||
else:
|
||||
print('Something went wrong. ' + str(msg))
|
||||
|
||||
def get_user(username=None, auth_source=INTERNAL):
|
||||
app = create_app(config.APP_NAME + '-cli')
|
||||
usr = None
|
||||
with app.test_request_context():
|
||||
usr = User.query.filter_by(username=username,
|
||||
auth_source=auth_source).first()
|
||||
|
||||
if not usr:
|
||||
return None
|
||||
return usr.id
|
||||
|
||||
def display_user(data, _console, _json):
|
||||
if _json:
|
||||
json_formatted_str = jsonlib.dumps(data, indent=0)
|
||||
console.print(json_formatted_str)
|
||||
else:
|
||||
table = Table(title="User Details", box=box.ASCII)
|
||||
table.add_column("Field", style="green")
|
||||
table.add_column("Value", style="green")
|
||||
|
||||
if 'username' in data:
|
||||
table.add_row("Username", data['username'])
|
||||
if 'email' in data:
|
||||
table.add_row("Email", data['email'])
|
||||
table.add_row("auth_source", data['auth_source'])
|
||||
table.add_row("role",
|
||||
"Admin" if data['role'] and data['role'] != 2 else
|
||||
"Non-admin")
|
||||
table.add_row("active",
|
||||
'True' if data['active'] else 'False')
|
||||
console.print(table)
|
||||
|
||||
|
||||
class ManagePreferences:
|
||||
|
||||
def get_user(username=None, auth_source=INTERNAL):
|
||||
app = create_app(config.APP_NAME + '-cli')
|
||||
usr = None
|
||||
with app.test_request_context():
|
||||
usr = User.query.filter_by(username=username,
|
||||
auth_source=auth_source).first()
|
||||
if not usr:
|
||||
return None
|
||||
return usr.id
|
||||
|
||||
@app.command()
|
||||
def get_prefs(id: Optional[bool] = None, json: Optional[bool] = False):
|
||||
"""Get Preferences List."""
|
||||
app = create_app(config.APP_NAME + '-cli')
|
||||
table = Table(title="Pref Details", box=box.ASCII)
|
||||
table.add_column("Preference", style="green")
|
||||
with app.app_context():
|
||||
from pgadmin.preferences import save_pref
|
||||
from pgadmin.utils.preferences import Preferences
|
||||
from pgadmin.model import db, Preferences as PrefTable, \
|
||||
ModulePreference as ModulePrefTable, \
|
||||
UserPreference as UserPrefTable, \
|
||||
PreferenceCategory as PrefCategoryTbl
|
||||
|
||||
module_prefs = ModulePrefTable.query.all()
|
||||
cat_prefs = PrefCategoryTbl.query.all()
|
||||
prefs = PrefTable.query.all()
|
||||
if id:
|
||||
all_preferences = {}
|
||||
else:
|
||||
all_preferences = []
|
||||
for i in module_prefs:
|
||||
for j in cat_prefs:
|
||||
if i.id == j.mid:
|
||||
for k in prefs:
|
||||
if k.cid == j.id:
|
||||
if id:
|
||||
all_preferences["{0}:{1}:{2}".format(
|
||||
i.name, j.name, k.name)
|
||||
] = "{0}:{1}:{2}".format(i.id, j.id, k.id)
|
||||
else:
|
||||
table.add_row("{0}:{1}:{2}".format(
|
||||
i.name, j.name, k.name))
|
||||
all_preferences.append(
|
||||
"{0}:{1}:{2}".format(
|
||||
i.name, j.name, k.name)
|
||||
)
|
||||
if id:
|
||||
return all_preferences
|
||||
else:
|
||||
if json:
|
||||
json_formatted_str = jsonlib.dumps(
|
||||
{"Preferences": all_preferences},
|
||||
indent=0)
|
||||
console.print(json_formatted_str)
|
||||
else:
|
||||
console.print(table)
|
||||
|
||||
@app.command()
|
||||
def set_prefs(username, pref_options: List[str],
|
||||
auth_source: AuthType = AuthType.internal,
|
||||
json: Optional[bool] = False):
|
||||
"""Set User preferences."""
|
||||
user_id = ManagePreferences.get_user(username, auth_source)
|
||||
app = create_app(config.APP_NAME + '-cli')
|
||||
table = Table(title="Pref Details", box=box.ASCII)
|
||||
table.add_column("Preference", style="green")
|
||||
if not user_id:
|
||||
print("User not found.")
|
||||
return
|
||||
|
||||
prefs = ManagePreferences.get_prefs(True)
|
||||
app = create_app(config.APP_NAME + '-cli')
|
||||
with app.app_context():
|
||||
from pgadmin.preferences import save_pref
|
||||
for opt in pref_options:
|
||||
val = opt.split("=")
|
||||
final_opt = val[0].split(":")
|
||||
val = val[1]
|
||||
f = ":".join(final_opt)
|
||||
if f in prefs:
|
||||
ids = prefs[f].split(":")
|
||||
save_pref({
|
||||
'mid': ids[0],
|
||||
'category_id': ids[1],
|
||||
'id': ids[2],
|
||||
'name': final_opt[2],
|
||||
'user_id': user_id,
|
||||
'value': val})
|
||||
_row = {
|
||||
'mid': ids[0],
|
||||
'category_id': ids[1],
|
||||
'id': ids[2],
|
||||
'name': final_opt[2],
|
||||
'user_id': user_id,
|
||||
'value': val}
|
||||
if json:
|
||||
json_formatted_str = jsonlib.dumps(_row, indent=0)
|
||||
console.print(json_formatted_str)
|
||||
else:
|
||||
table.add_row(jsonlib.dumps(_row))
|
||||
|
||||
if not json:
|
||||
console.print(table)
|
||||
|
||||
|
||||
@app.command()
|
||||
def setup_db():
|
||||
"""Setup the configuration database."""
|
||||
|
||||
app = create_app()
|
||||
create_app_data_directory(config)
|
||||
|
||||
print("pgAdmin 4 - Application Initialisation")
|
||||
@ -148,74 +532,5 @@ def setup_db(app):
|
||||
run_migration_for_sqlite()
|
||||
|
||||
|
||||
def clear_servers():
|
||||
"""Clear groups and servers configurations.
|
||||
|
||||
Args:
|
||||
args (ArgParser): The parsed command line options
|
||||
"""
|
||||
|
||||
# What user?
|
||||
load_user = args.user if args.user is not None else config.DESKTOP_USER
|
||||
|
||||
# And the sqlite path
|
||||
if args.sqlite_path is not None:
|
||||
config.SQLITE_PATH = args.sqlite_path
|
||||
|
||||
app = create_app(config.APP_NAME + '-cli')
|
||||
with app.app_context():
|
||||
clear_database_servers(load_user, True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Configuration settings
|
||||
parser = argparse.ArgumentParser(description='Setup the pgAdmin config DB')
|
||||
|
||||
exp_group = parser.add_argument_group('Dump server config')
|
||||
exp_group.add_argument('--dump-servers', metavar="OUTPUT_FILE",
|
||||
help='Dump the servers in the DB', required=False)
|
||||
exp_group.add_argument('--servers', metavar="SERVERS", nargs='*',
|
||||
help='One or more servers to dump', required=False)
|
||||
|
||||
imp_group = parser.add_argument_group('Load server config')
|
||||
imp_group.add_argument('--load-servers', metavar="INPUT_FILE",
|
||||
help='Load servers into the DB', required=False)
|
||||
imp_group.add_argument('--replace', dest='replace', action='store_true',
|
||||
help='replace server configurations',
|
||||
required=False)
|
||||
|
||||
imp_group.set_defaults(replace=False)
|
||||
# Common args
|
||||
parser.add_argument('--sqlite-path', metavar="PATH",
|
||||
help='Dump/load with the specified pgAdmin config DB'
|
||||
' file. This is particularly helpful when there'
|
||||
' are multiple pgAdmin configurations. It is also'
|
||||
' recommended to use this option when running'
|
||||
' pgAdmin in desktop mode.', required=False)
|
||||
parser.add_argument('--user', metavar="USER_NAME",
|
||||
help='Dump/load servers for the specified username',
|
||||
required=False)
|
||||
|
||||
args, extra = parser.parse_known_args()
|
||||
|
||||
config.SETTINGS_SCHEMA_VERSION = CURRENT_SCHEMA_VERSION
|
||||
if "PGADMIN_TESTING_MODE" in os.environ and \
|
||||
os.environ["PGADMIN_TESTING_MODE"] == "1":
|
||||
config.SQLITE_PATH = config.TEST_SQLITE_PATH
|
||||
|
||||
# What to do?
|
||||
if args.dump_servers is not None:
|
||||
try:
|
||||
dump_servers(args)
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
elif args.load_servers is not None:
|
||||
try:
|
||||
if args.replace:
|
||||
clear_servers()
|
||||
load_servers(args)
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
else:
|
||||
app = create_app()
|
||||
setup_db(app)
|
||||
if __name__ == "__main__":
|
||||
app()
|
||||
|
Loading…
Reference in New Issue
Block a user