Added PSQL tool support for the Windows platform.
Fixed following issues: 1. If the database name contains escape characters then PSQL unable to connect. 2. If the user terminates the connection by typing the 'exit' command, PSQL will show the connection termination msg. Fixes #2341pull/51/head
parent
5a086a9173
commit
9f12747d9b
|
@ -37,6 +37,7 @@ ldap3==2.*
|
||||||
Flask-BabelEx==0.*
|
Flask-BabelEx==0.*
|
||||||
gssapi==1.6.*
|
gssapi==1.6.*
|
||||||
flask-socketio>=5.0.1
|
flask-socketio>=5.0.1
|
||||||
eventlet==0.30.2
|
eventlet==0.31.0
|
||||||
httpagentparser==1.9.*
|
httpagentparser==1.9.*
|
||||||
user-agents==2.2.0
|
user-agents==2.2.0
|
||||||
|
pywinpty==1.1.1; sys_platform=="win32"
|
||||||
|
|
|
@ -506,61 +506,38 @@ def register_browser_preferences(self):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if sys.platform != 'win32':
|
self.open_in_new_tab = self.preference.register(
|
||||||
self.open_in_new_tab = self.preference.register(
|
'tab_settings', 'new_browser_tab_open',
|
||||||
'tab_settings', 'new_browser_tab_open',
|
gettext("Open in new browser tab"), 'select2', None,
|
||||||
gettext("Open in new browser tab"), 'select2', None,
|
category_label=PREF_LABEL_OPTIONS,
|
||||||
category_label=PREF_LABEL_OPTIONS,
|
options=[{'label': gettext('Query Tool'), 'value': 'qt'},
|
||||||
options=[{'label': gettext('Query Tool'), 'value': 'qt'},
|
{'label': gettext('Debugger'), 'value': 'debugger'},
|
||||||
{'label': gettext('Debugger'), 'value': 'debugger'},
|
{'label': gettext('Schema Diff'), 'value': 'schema_diff'},
|
||||||
{'label': gettext('Schema Diff'), 'value': 'schema_diff'},
|
{'label': gettext('ERD Tool'), 'value': 'erd_tool'},
|
||||||
{'label': gettext('ERD Tool'), 'value': 'erd_tool'},
|
{'label': gettext('PSQL Tool'), 'value': 'psql_tool'}],
|
||||||
{'label': gettext('PSQL Tool'), 'value': 'psql_tool'}],
|
help_str=gettext(
|
||||||
help_str=gettext(
|
'Select Query Tool, Debugger, Schema Diff, ERD Tool '
|
||||||
'Select Query Tool, Debugger, Schema Diff, ERD Tool '
|
'or PSQL Tool from the drop-down to set '
|
||||||
'or PSQL Tool from the drop-down to set '
|
'open in new browser tab for that particular module.'
|
||||||
'open in new browser tab for that particular module.'
|
),
|
||||||
),
|
select2={
|
||||||
select2={
|
'multiple': True, 'allowClear': False,
|
||||||
'multiple': True, 'allowClear': False,
|
'tags': True, 'first_empty': False,
|
||||||
'tags': True, 'first_empty': False,
|
'selectOnClose': False, 'emptyOptions': True,
|
||||||
'selectOnClose': False, 'emptyOptions': True,
|
'tokenSeparators': [','],
|
||||||
'tokenSeparators': [','],
|
'placeholder': gettext('Select open new tab...')
|
||||||
'placeholder': gettext('Select open new tab...')
|
}
|
||||||
}
|
)
|
||||||
)
|
|
||||||
|
|
||||||
self.psql_tab_title = self.preference.register(
|
self.psql_tab_title = self.preference.register(
|
||||||
'tab_settings', 'psql_tab_title_placeholder',
|
'tab_settings', 'psql_tab_title_placeholder',
|
||||||
gettext("PSQL tool tab title"),
|
gettext("PSQL tool tab title"),
|
||||||
'text', '%DATABASE%/%USERNAME%@%SERVER%',
|
'text', '%DATABASE%/%USERNAME%@%SERVER%',
|
||||||
category_label=PREF_LABEL_DISPLAY,
|
category_label=PREF_LABEL_DISPLAY,
|
||||||
help_str=gettext(
|
help_str=gettext(
|
||||||
'Supported placeholders are %DATABASE%, %USERNAME%, '
|
'Supported placeholders are %DATABASE%, %USERNAME%, '
|
||||||
'and %SERVER%. Users can provide any string with or without'
|
'and %SERVER%. Users can provide any string with or without'
|
||||||
' placeholders of their choice. The blank title will be revert'
|
' placeholders of their choice. The blank title will be revert'
|
||||||
' back to the default title with placeholders.'
|
' back to the default title with placeholders.'
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self.open_in_new_tab = self.preference.register(
|
|
||||||
'tab_settings', 'new_browser_tab_open',
|
|
||||||
gettext("Open in new browser tab"), 'select2', None,
|
|
||||||
category_label=PREF_LABEL_OPTIONS,
|
|
||||||
options=[{'label': gettext('Query Tool'), 'value': 'qt'},
|
|
||||||
{'label': gettext('Debugger'), 'value': 'debugger'},
|
|
||||||
{'label': gettext('Schema Diff'), 'value': 'schema_diff'},
|
|
||||||
{'label': gettext('ERD Tool'), 'value': 'erd_tool'}],
|
|
||||||
help_str=gettext(
|
|
||||||
'Select Query Tool, Debugger, Schema Diff, ERD Tool '
|
|
||||||
'or PSQL Tool from the drop-down to set '
|
|
||||||
'open in new browser tab for that particular module.'
|
|
||||||
),
|
|
||||||
select2={
|
|
||||||
'multiple': True, 'allowClear': False,
|
|
||||||
'tags': True, 'first_empty': False,
|
|
||||||
'selectOnClose': False, 'emptyOptions': True,
|
|
||||||
'tokenSeparators': [','],
|
|
||||||
'placeholder': gettext('Select open new tab...')
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
|
@ -66,7 +66,7 @@ define([
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
// show psql tool same as query tool.
|
// show psql tool same as query tool.
|
||||||
if(pgAdmin['enable_psql'] && pgAdmin['platform'] != 'win32') {
|
if(pgAdmin['enable_psql']) {
|
||||||
pgAdmin.Browser.add_menus([{
|
pgAdmin.Browser.add_menus([{
|
||||||
name: 'show_psql_tool', node: this.type, module: this,
|
name: 'show_psql_tool', node: this.type, module: this,
|
||||||
applies: ['context'], callback: 'show_psql_tool',
|
applies: ['context'], callback: 'show_psql_tool',
|
||||||
|
|
|
@ -210,7 +210,7 @@ define('pgadmin.browser.node', [
|
||||||
icon: 'fa fa-search', enable: enable,
|
icon: 'fa fa-search', enable: enable,
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
if(pgAdmin['enable_psql'] && pgAdmin['platform'] != 'win32') {
|
if(pgAdmin['enable_psql']) {
|
||||||
// show psql tool same as query tool.
|
// show psql tool same as query tool.
|
||||||
pgAdmin.Browser.add_menus([{
|
pgAdmin.Browser.add_menus([{
|
||||||
name: 'show_psql_tool', node: this.type, module: this,
|
name: 'show_psql_tool', node: this.type, module: this,
|
||||||
|
|
|
@ -59,7 +59,7 @@ let _defaultToolBarButtons = [
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
if(pgAdmin['enable_psql'] && pgAdmin['platform'] != 'win32') {
|
if(pgAdmin['enable_psql']) {
|
||||||
_defaultToolBarButtons.unshift({
|
_defaultToolBarButtons.unshift({
|
||||||
label: gettext('PSQL Tool'),
|
label: gettext('PSQL Tool'),
|
||||||
ariaLabel: gettext('PSQL Tool'),
|
ariaLabel: gettext('PSQL Tool'),
|
||||||
|
@ -119,7 +119,7 @@ export function initializeToolbar(panel, wcDocker) {
|
||||||
pgAdmin.DataGrid.show_filtered_row({mnuid: 4}, pgAdmin.Browser.tree.selected());
|
pgAdmin.DataGrid.show_filtered_row({mnuid: 4}, pgAdmin.Browser.tree.selected());
|
||||||
else if ('name' in data && data.name === gettext('Search objects'))
|
else if ('name' in data && data.name === gettext('Search objects'))
|
||||||
pgAdmin.SearchObjects.show_search_objects('', pgAdmin.Browser.tree.selected());
|
pgAdmin.SearchObjects.show_search_objects('', pgAdmin.Browser.tree.selected());
|
||||||
else if ('name' in data && data.name === gettext('PSQL Tool') && pgAdmin['platform'] != 'win32'){
|
else if ('name' in data && data.name === gettext('PSQL Tool')){
|
||||||
var input = {},
|
var input = {},
|
||||||
t = pgAdmin.Browser.tree,
|
t = pgAdmin.Browser.tree,
|
||||||
i = input.item || t.selected(),
|
i = input.item || t.selected(),
|
||||||
|
|
|
@ -63,7 +63,8 @@ def underscore_unescape(text):
|
||||||
""": '"',
|
""": '"',
|
||||||
"`": '`',
|
"`": '`',
|
||||||
"'": "'",
|
"'": "'",
|
||||||
"'": "'"
|
"'": "'",
|
||||||
|
""": '"'
|
||||||
}
|
}
|
||||||
|
|
||||||
# always replace & first
|
# always replace & first
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import select
|
import select
|
||||||
|
@ -20,7 +19,9 @@ from pgadmin.utils.driver import get_driver
|
||||||
from ... import socketio as sio
|
from ... import socketio as sio
|
||||||
from pgadmin.utils import get_complete_file_path
|
from pgadmin.utils import get_complete_file_path
|
||||||
|
|
||||||
if _platform != 'win32':
|
if _platform == 'win32':
|
||||||
|
from winpty import PtyProcess
|
||||||
|
else:
|
||||||
import fcntl
|
import fcntl
|
||||||
import termios
|
import termios
|
||||||
import pty
|
import pty
|
||||||
|
@ -101,8 +102,8 @@ def panel(trans_id):
|
||||||
|
|
||||||
return render_template('editor_template.html',
|
return render_template('editor_template.html',
|
||||||
sid=params['sid'],
|
sid=params['sid'],
|
||||||
db=underscore_unescape(params['db']) if params[
|
db=underscore_unescape(
|
||||||
'db'] else 'postgres',
|
o_db_name) if o_db_name else 'postgres',
|
||||||
server_type=params['server_type'],
|
server_type=params['server_type'],
|
||||||
is_enable=config.ENABLE_PSQL,
|
is_enable=config.ENABLE_PSQL,
|
||||||
title=underscore_unescape(params['title']),
|
title=underscore_unescape(params['title']),
|
||||||
|
@ -120,8 +121,13 @@ def set_term_size(fd, row, col, xpix=0, ypix=0):
|
||||||
:param xpix:
|
:param xpix:
|
||||||
:param ypix:
|
:param ypix:
|
||||||
"""
|
"""
|
||||||
term_size = struct.pack('HHHH', row, col, xpix, ypix)
|
if _platform == 'win32':
|
||||||
fcntl.ioctl(fd, termios.TIOCSWINSZ, term_size)
|
app.config['sessions'][request.sid].setwinsize(row, col)
|
||||||
|
# data = {'key_name': 'Enter', 'input': '\n'}
|
||||||
|
# socket_input(data)
|
||||||
|
else:
|
||||||
|
term_size = struct.pack('HHHH', row, col, xpix, ypix)
|
||||||
|
fcntl.ioctl(fd, termios.TIOCSWINSZ, term_size)
|
||||||
|
|
||||||
|
|
||||||
@sio.on('connect', namespace='/pty')
|
@sio.on('connect', namespace='/pty')
|
||||||
|
@ -216,6 +222,19 @@ def read_terminal_data(parent, data_ready, max_read_bytes, sid):
|
||||||
session_last_cmd[request.sid]['invalid_cmd'] = False
|
session_last_cmd[request.sid]['invalid_cmd'] = False
|
||||||
|
|
||||||
|
|
||||||
|
def read_stdout(process, sid, max_read_bytes, win_emit_output=True):
|
||||||
|
(data_ready, _, _) = select.select([process.fd], [], [], 0)
|
||||||
|
if process.fd in data_ready:
|
||||||
|
output = process.read(max_read_bytes)
|
||||||
|
if win_emit_output:
|
||||||
|
sio.emit('pty-output',
|
||||||
|
{'result': output,
|
||||||
|
'error': False},
|
||||||
|
namespace='/pty', room=sid)
|
||||||
|
|
||||||
|
sio.sleep(0)
|
||||||
|
|
||||||
|
|
||||||
@sio.on('start_process', namespace='/pty')
|
@sio.on('start_process', namespace='/pty')
|
||||||
def start_process(data):
|
def start_process(data):
|
||||||
"""
|
"""
|
||||||
|
@ -227,8 +246,24 @@ def start_process(data):
|
||||||
def read_and_forward_pty_output(sid, data):
|
def read_and_forward_pty_output(sid, data):
|
||||||
|
|
||||||
max_read_bytes = 1024 * 20
|
max_read_bytes = 1024 * 20
|
||||||
|
import time
|
||||||
|
if _platform == 'win32':
|
||||||
|
|
||||||
|
os.environ['PYWINPTY_BACKEND'] = '1'
|
||||||
|
process = PtyProcess.spawn('cmd.exe')
|
||||||
|
|
||||||
|
process.write(r'"{0}" "{1}" 2>>&1'.format(connection_data[0],
|
||||||
|
connection_data[1]))
|
||||||
|
process.write("\r\n")
|
||||||
|
app.config['sessions'][request.sid] = process
|
||||||
|
pdata[request.sid] = process
|
||||||
|
set_term_size(process, 50, 50)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
read_stdout(process, sid, max_read_bytes,
|
||||||
|
win_emit_output=True)
|
||||||
|
else:
|
||||||
|
|
||||||
if _platform != 'win32':
|
|
||||||
p, parent, fd = create_pty_terminal(connection_data)
|
p, parent, fd = create_pty_terminal(connection_data)
|
||||||
|
|
||||||
while p and p.poll() is None:
|
while p and p.poll() is None:
|
||||||
|
@ -248,12 +283,6 @@ def start_process(data):
|
||||||
timeout)
|
timeout)
|
||||||
|
|
||||||
read_terminal_data(parent, data_ready, max_read_bytes, sid)
|
read_terminal_data(parent, data_ready, max_read_bytes, sid)
|
||||||
else:
|
|
||||||
sio.emit(
|
|
||||||
'conn_error',
|
|
||||||
{
|
|
||||||
'error': 'PSQL tool not supported.',
|
|
||||||
}, namespace='/pty', room=request.sid)
|
|
||||||
|
|
||||||
# Check user is authenticated and PSQL is enabled in config.
|
# Check user is authenticated and PSQL is enabled in config.
|
||||||
if current_user.is_authenticated and config.ENABLE_PSQL:
|
if current_user.is_authenticated and config.ENABLE_PSQL:
|
||||||
|
@ -342,14 +371,14 @@ def get_connection_str(psql_utility, db, manager):
|
||||||
:param db: database name to connect specific db.
|
:param db: database name to connect specific db.
|
||||||
:return: connection attribute list for PSQL connection.
|
:return: connection attribute list for PSQL connection.
|
||||||
"""
|
"""
|
||||||
conn_attr = get_conn_str(manager, db)
|
conn_attr = get_conn_str_win(manager, db)
|
||||||
conn_attr_list = list()
|
conn_attr_list = list()
|
||||||
conn_attr_list.append(psql_utility)
|
conn_attr_list.append(psql_utility)
|
||||||
conn_attr_list.append(conn_attr)
|
conn_attr_list.append(conn_attr)
|
||||||
return conn_attr_list
|
return conn_attr_list
|
||||||
|
|
||||||
|
|
||||||
def get_conn_str(manager, db):
|
def get_conn_str_win(manager, db):
|
||||||
"""
|
"""
|
||||||
Get connection attributes for psql connection.
|
Get connection attributes for psql connection.
|
||||||
:param manager:
|
:param manager:
|
||||||
|
@ -357,46 +386,48 @@ def get_conn_str(manager, db):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
manager.export_password_env('PGPASSWORD')
|
manager.export_password_env('PGPASSWORD')
|
||||||
|
db = db.replace('"', '\\"')
|
||||||
|
db = db.replace("'", "\\'")
|
||||||
conn_attr =\
|
conn_attr =\
|
||||||
'host={0} port={1} dbname={2} user={3} sslmode={4} ' \
|
'host=\'{0}\' port=\'{1}\' dbname=\'{2}\' user=\'{3}\' ' \
|
||||||
'sslcompression={5} ' \
|
'sslmode=\'{4}\' sslcompression=\'{5}\' ' \
|
||||||
''.format(
|
''.format(
|
||||||
manager.local_bind_host if manager.use_ssh_tunnel else
|
manager.local_bind_host if manager.use_ssh_tunnel else
|
||||||
manager.host,
|
manager.host,
|
||||||
manager.local_bind_port if manager.use_ssh_tunnel else
|
manager.local_bind_port if manager.use_ssh_tunnel else
|
||||||
manager.port,
|
manager.port,
|
||||||
underscore_unescape(db) if db != '' else 'postgres',
|
db if db != '' else 'postgres',
|
||||||
underscore_unescape(manager.user) if manager.user else 'postgres',
|
underscore_unescape(manager.user) if manager.user else 'postgres',
|
||||||
manager.ssl_mode,
|
manager.ssl_mode,
|
||||||
True if manager.sslcompression else False,
|
True if manager.sslcompression else False,
|
||||||
)
|
)
|
||||||
|
|
||||||
if manager.hostaddr:
|
if manager.hostaddr:
|
||||||
conn_attr = " {0} hostaddr={1}".format(conn_attr, manager.hostaddr)
|
conn_attr = " {0} hostaddr='{1}'".format(conn_attr, manager.hostaddr)
|
||||||
|
|
||||||
if manager.passfile:
|
if manager.passfile:
|
||||||
conn_attr = " {0} passfile={1}".format(conn_attr,
|
conn_attr = " {0} passfile='{1}'".format(conn_attr,
|
||||||
get_complete_file_path(
|
get_complete_file_path(
|
||||||
manager.passfile))
|
manager.passfile))
|
||||||
|
|
||||||
if get_complete_file_path(manager.sslcert):
|
if get_complete_file_path(manager.sslcert):
|
||||||
conn_attr = " {0} sslcert={1}".format(
|
conn_attr = " {0} sslcert='{1}'".format(
|
||||||
conn_attr, get_complete_file_path(manager.sslcert))
|
conn_attr, get_complete_file_path(manager.sslcert))
|
||||||
|
|
||||||
if get_complete_file_path(manager.sslkey):
|
if get_complete_file_path(manager.sslkey):
|
||||||
conn_attr = " {0} sslkey={1}".format(
|
conn_attr = " {0} sslkey='{1}'".format(
|
||||||
conn_attr, get_complete_file_path(manager.sslkey))
|
conn_attr, get_complete_file_path(manager.sslkey))
|
||||||
|
|
||||||
if get_complete_file_path(manager.sslrootcert):
|
if get_complete_file_path(manager.sslrootcert):
|
||||||
conn_attr = " {0} sslrootcert={1}".format(
|
conn_attr = " {0} sslrootcert='{1}'".format(
|
||||||
conn_attr, get_complete_file_path(manager.sslrootcert))
|
conn_attr, get_complete_file_path(manager.sslrootcert))
|
||||||
|
|
||||||
if get_complete_file_path(manager.sslcrl):
|
if get_complete_file_path(manager.sslcrl):
|
||||||
conn_attr = " {0} sslcrl={1}".format(
|
conn_attr = " {0} sslcrl='{1}'".format(
|
||||||
conn_attr, get_complete_file_path(manager.sslcrl))
|
conn_attr, get_complete_file_path(manager.sslcrl))
|
||||||
|
|
||||||
if manager.service:
|
if manager.service:
|
||||||
conn_attr = " {0} service={1}".format(
|
conn_attr = " {0} service='{1}'".format(
|
||||||
conn_attr, get_complete_file_path(manager.service))
|
conn_attr, get_complete_file_path(manager.service))
|
||||||
|
|
||||||
return conn_attr
|
return conn_attr
|
||||||
|
@ -433,12 +464,27 @@ def invalid_cmd():
|
||||||
:rtype:
|
:rtype:
|
||||||
"""
|
"""
|
||||||
session_last_cmd[request.sid]['invalid_cmd'] = True
|
session_last_cmd[request.sid]['invalid_cmd'] = True
|
||||||
for i in range(len(session_input[request.sid])):
|
if _platform == 'win32':
|
||||||
os.write(app.config['sessions'][request.sid],
|
for i in range(len(session_input[request.sid])):
|
||||||
'\b \b'.encode())
|
app.config['sessions'][request.sid].write('\b \b')
|
||||||
|
app.config['sessions'][request.sid].write('\r\n')
|
||||||
|
|
||||||
os.write(app.config['sessions'][request.sid],
|
sio.emit(
|
||||||
'\n'.encode())
|
'pty-output',
|
||||||
|
{
|
||||||
|
'result': gettext(
|
||||||
|
"ERROR: Shell commands are disabled "
|
||||||
|
"in psql for security\r\n"),
|
||||||
|
'error': True
|
||||||
|
},
|
||||||
|
namespace='/pty', room=request.sid)
|
||||||
|
else:
|
||||||
|
for i in range(len(session_input[request.sid])):
|
||||||
|
os.write(app.config['sessions'][request.sid],
|
||||||
|
'\b \b'.encode())
|
||||||
|
|
||||||
|
os.write(app.config['sessions'][request.sid],
|
||||||
|
'\n'.encode())
|
||||||
session_input[request.sid] = ''
|
session_input[request.sid] = ''
|
||||||
|
|
||||||
|
|
||||||
|
@ -464,18 +510,36 @@ def check_valid_cmd(user_input):
|
||||||
|
|
||||||
if stop_execution:
|
if stop_execution:
|
||||||
session_last_cmd[request.sid]['invalid_cmd'] = True
|
session_last_cmd[request.sid]['invalid_cmd'] = True
|
||||||
|
if _platform == 'win32':
|
||||||
|
# Remove already added command from terminal.
|
||||||
|
for i in range(len(user_input)):
|
||||||
|
app.config['sessions'][request.sid].write('\b \b')
|
||||||
|
app.config['sessions'][request.sid].write('\n')
|
||||||
|
|
||||||
# Remove already added command from terminal.
|
sio.emit(
|
||||||
for i in range(len(user_input)):
|
'pty-output',
|
||||||
|
{
|
||||||
|
'result': gettext(
|
||||||
|
"ERROR: Shell commands are disabled "
|
||||||
|
"in psql for security\r\n"),
|
||||||
|
'error': True
|
||||||
|
},
|
||||||
|
namespace='/pty', room=request.sid)
|
||||||
|
else:
|
||||||
|
# Remove already added command from terminal.
|
||||||
|
for i in range(len(user_input)):
|
||||||
|
os.write(app.config['sessions'][request.sid],
|
||||||
|
'\b \b'.encode())
|
||||||
|
# Add Enter event to execute the command.
|
||||||
os.write(app.config['sessions'][request.sid],
|
os.write(app.config['sessions'][request.sid],
|
||||||
'\b \b'.encode())
|
'\n'.encode())
|
||||||
# Add Enter event to execute the command.
|
|
||||||
os.write(app.config['sessions'][request.sid],
|
|
||||||
'\n'.encode())
|
|
||||||
else:
|
else:
|
||||||
session_last_cmd[request.sid]['invalid_cmd'] = False
|
session_last_cmd[request.sid]['invalid_cmd'] = False
|
||||||
os.write(app.config['sessions'][request.sid],
|
if _platform == 'win32':
|
||||||
'\n'.encode())
|
app.config['sessions'][request.sid].write('\n')
|
||||||
|
else:
|
||||||
|
os.write(app.config['sessions'][request.sid],
|
||||||
|
'\n'.encode())
|
||||||
|
|
||||||
|
|
||||||
def enter_key_press(data):
|
def enter_key_press(data):
|
||||||
|
@ -501,8 +565,8 @@ def enter_key_press(data):
|
||||||
not config.ALLOW_PSQL_SHELL_COMMANDS and\
|
not config.ALLOW_PSQL_SHELL_COMMANDS and\
|
||||||
not session_last_cmd[request.sid]['is_new_connection']:
|
not session_last_cmd[request.sid]['is_new_connection']:
|
||||||
check_valid_cmd(user_input)
|
check_valid_cmd(user_input)
|
||||||
elif user_input == '\q' or user_input == 'q\\q' or \
|
elif user_input == '\q' or user_input == 'q\\q' or user_input in ['exit',
|
||||||
user_input in ['exit', 'exit;']:
|
'exit;']:
|
||||||
# If user enter \q to terminate the PSQL, emit the msg to
|
# If user enter \q to terminate the PSQL, emit the msg to
|
||||||
# notify user connection is terminated.
|
# notify user connection is terminated.
|
||||||
sio.emit('pty-output',
|
sio.emit('pty-output',
|
||||||
|
@ -514,12 +578,20 @@ def enter_key_press(data):
|
||||||
'error': True},
|
'error': True},
|
||||||
namespace='/pty', room=request.sid)
|
namespace='/pty', room=request.sid)
|
||||||
|
|
||||||
os.write(app.config['sessions'][request.sid],
|
if _platform == 'win32':
|
||||||
'\n'.encode())
|
app.config['sessions'][request.sid].write('\n')
|
||||||
|
del app.config['sessions'][request.sid]
|
||||||
|
else:
|
||||||
|
os.write(app.config['sessions'][request.sid],
|
||||||
|
'\n'.encode())
|
||||||
|
|
||||||
else:
|
else:
|
||||||
os.write(app.config['sessions'][request.sid],
|
if _platform == 'win32':
|
||||||
data['input'].encode())
|
app.config['sessions'][request.sid].write(
|
||||||
|
"{0}".format(data['input']))
|
||||||
|
else:
|
||||||
|
os.write(app.config['sessions'][request.sid],
|
||||||
|
data['input'].encode())
|
||||||
session_input[request.sid] = ''
|
session_input[request.sid] = ''
|
||||||
session_last_cmd[request.sid]['is_new_connection'] = False
|
session_last_cmd[request.sid]['is_new_connection'] = False
|
||||||
|
|
||||||
|
@ -619,9 +691,13 @@ def other_key_press(data):
|
||||||
session_input[request.sid] = data['input']
|
session_input[request.sid] = data['input']
|
||||||
session_input_cursor[request.sid] += 1
|
session_input_cursor[request.sid] += 1
|
||||||
|
|
||||||
# Write user input to terminal parent fd.
|
if _platform == 'win32':
|
||||||
os.write(app.config['sessions'][request.sid],
|
app.config['sessions'][request.sid].write(
|
||||||
data['input'].encode())
|
"{0}".format(data['input']))
|
||||||
|
else:
|
||||||
|
# Write user input to terminal parent fd.
|
||||||
|
os.write(app.config['sessions'][request.sid],
|
||||||
|
data['input'].encode())
|
||||||
|
|
||||||
|
|
||||||
@sio.on('socket_input', namespace='/pty')
|
@sio.on('socket_input', namespace='/pty')
|
||||||
|
@ -697,11 +773,17 @@ def server_disconnect(data):
|
||||||
|
|
||||||
|
|
||||||
def disconnect_socket():
|
def disconnect_socket():
|
||||||
os.write(app.config['sessions'][request.sid], '\q\n'.encode())
|
if _platform == 'win32':
|
||||||
sio.sleep(1)
|
if request.sid in app.config['sessions']:
|
||||||
os.close(app.config['sessions'][request.sid])
|
process = app.config['sessions'][request.sid]
|
||||||
os.close(cdata[request.sid])
|
process.terminate()
|
||||||
del app.config['sessions'][request.sid]
|
del app.config['sessions'][request.sid]
|
||||||
|
else:
|
||||||
|
os.write(app.config['sessions'][request.sid], '\q\n'.encode())
|
||||||
|
sio.sleep(1)
|
||||||
|
os.close(app.config['sessions'][request.sid])
|
||||||
|
os.close(cdata[request.sid])
|
||||||
|
del app.config['sessions'][request.sid]
|
||||||
|
|
||||||
|
|
||||||
def _get_database(sid, did):
|
def _get_database(sid, did):
|
||||||
|
|
|
@ -55,7 +55,7 @@ export function initialize(gettext, url_for, $, _, pgAdmin, csrfToken, Browser)
|
||||||
}];
|
}];
|
||||||
|
|
||||||
this.enable_psql_tool = pgAdmin['enable_psql'];
|
this.enable_psql_tool = pgAdmin['enable_psql'];
|
||||||
if(pgAdmin['enable_psql'] && pgAdmin['platform'] != 'win32') {
|
if(pgAdmin['enable_psql']) {
|
||||||
pgBrowser.add_menus(menus);
|
pgBrowser.add_menus(menus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,11 +156,12 @@ export function initialize(gettext, url_for, $, _, pgAdmin, csrfToken, Browser)
|
||||||
var tab_title_placeholder = pgBrowser.get_preferences_for_module('browser').psql_tab_title_placeholder;
|
var tab_title_placeholder = pgBrowser.get_preferences_for_module('browser').psql_tab_title_placeholder;
|
||||||
panelTitle = generateTitle(tab_title_placeholder, title_data);
|
panelTitle = generateTitle(tab_title_placeholder, title_data);
|
||||||
|
|
||||||
const [panelUrl, panelCloseUrl] = this.getPanelUrls(transId, panelTitle, parentData, gen);
|
const [panelUrl, panelCloseUrl, db_label] = this.getPanelUrls(transId, panelTitle, parentData, gen);
|
||||||
|
|
||||||
let psqlToolForm = `
|
let psqlToolForm = `
|
||||||
<form id="psqlToolForm" action="${panelUrl}" method="post">
|
<form id="psqlToolForm" action="${panelUrl}" method="post">
|
||||||
<input id="title" name="title" hidden />
|
<input id="title" name="title" hidden />
|
||||||
|
<input id='db' value='${db_label}' hidden />
|
||||||
<input name="close_url" value="${panelCloseUrl}" hidden />
|
<input name="close_url" value="${panelCloseUrl}" hidden />
|
||||||
</form>
|
</form>
|
||||||
<script>
|
<script>
|
||||||
|
@ -228,9 +229,11 @@ export function initialize(gettext, url_for, $, _, pgAdmin, csrfToken, Browser)
|
||||||
+`&did=${parentData.database._id}`
|
+`&did=${parentData.database._id}`
|
||||||
+`&server_type=${parentData.server.server_type}`
|
+`&server_type=${parentData.server.server_type}`
|
||||||
+ `&theme=${theme}`;
|
+ `&theme=${theme}`;
|
||||||
|
let db_label = '';
|
||||||
if(parentData.database && parentData.database._id) {
|
if(parentData.database && parentData.database._id) {
|
||||||
let db_label = parentData.database._label.replace('\\', '\\\\');
|
db_label = _.escape(parentData.database._label.replace('\\', '\\\\'));
|
||||||
|
db_label = db_label.replace('\'', '\'');
|
||||||
|
db_label = db_label.replace('"', '\"');
|
||||||
openUrl += `&db=${db_label}`;
|
openUrl += `&db=${db_label}`;
|
||||||
} else {
|
} else {
|
||||||
openUrl += `&db=${''}`;
|
openUrl += `&db=${''}`;
|
||||||
|
@ -239,7 +242,7 @@ export function initialize(gettext, url_for, $, _, pgAdmin, csrfToken, Browser)
|
||||||
let closeUrl = url_for('psql.close', {
|
let closeUrl = url_for('psql.close', {
|
||||||
trans_id: transId,
|
trans_id: transId,
|
||||||
});
|
});
|
||||||
return [openUrl, closeUrl];
|
return [openUrl, closeUrl, db_label];
|
||||||
},
|
},
|
||||||
psql_terminal: function() {
|
psql_terminal: function() {
|
||||||
// theme colors
|
// theme colors
|
||||||
|
@ -375,4 +378,3 @@ export function initialize(gettext, url_for, $, _, pgAdmin, csrfToken, Browser)
|
||||||
|
|
||||||
return pgBrowser.psql;
|
return pgBrowser.psql;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,41 +23,36 @@
|
||||||
require(
|
require(
|
||||||
['sources/generated/psql_tool'],
|
['sources/generated/psql_tool'],
|
||||||
function(pgBrowser) {
|
function(pgBrowser) {
|
||||||
if (self.pgAdmin['platform'] != 'win32') {
|
const term = self.pgAdmin.Browser.psql.psql_terminal();
|
||||||
const term = self.pgAdmin.Browser.psql.psql_terminal();
|
<!--Addon for fitAddon, webLinkAddon, SearchAddon -->
|
||||||
<!--Addon for fitAddon, webLinkAddon, SearchAddon -->
|
const fitAddon = self.pgAdmin.Browser.psql.psql_Addon(term);
|
||||||
const fitAddon = self.pgAdmin.Browser.psql.psql_Addon(term);
|
<!-- Update the theme for terminal as per pgAdmin 4 theme.-->
|
||||||
<!-- Update the theme for terminal as per pgAdmin 4 theme.-->
|
self.pgAdmin.Browser.psql.set_theme(term);
|
||||||
self.pgAdmin.Browser.psql.set_theme(term);
|
<!-- Open the terminal -->
|
||||||
<!-- Open the terminal -->
|
term.open(document.getElementById('psql-terminal'));
|
||||||
term.open(document.getElementById('psql-terminal'));
|
<!-- Socket-->
|
||||||
<!-- Socket-->
|
const socket = self.pgAdmin.Browser.psql.psql_socket();
|
||||||
const socket = self.pgAdmin.Browser.psql.psql_socket();
|
self.pgAdmin.Browser.psql.psql_socket_io(socket, '{{is_enable}}', '{{sid}}', '{{db | replace("'", "\'")| replace('"', '\"') | replace('\\', '\\\\')}}', '{{server_type}}', fitAddon, term);
|
||||||
self.pgAdmin.Browser.psql.psql_socket_io(socket, '{{is_enable}}', '{{sid}}', '{{db}}', '{{server_type}}', fitAddon, term);
|
self.pgAdmin.Browser.psql.psql_terminal_io(term, socket);
|
||||||
self.pgAdmin.Browser.psql.psql_terminal_io(term, socket);
|
self.pgAdmin.Browser.psql.check_db_name_change('{{db}}', '{{o_db_name}}');
|
||||||
self.pgAdmin.Browser.psql.check_db_name_change('{{db}}', '{{o_db_name}}');
|
|
||||||
|
|
||||||
<!-- Resize the terminal -->
|
<!-- Resize the terminal -->
|
||||||
function fitToscreen(){
|
function fitToscreen(){
|
||||||
fitAddon.fit()
|
fitAddon.fit()
|
||||||
socket.emit("resize", {"cols": term.cols, "rows": term.rows})
|
socket.emit("resize", {"cols": term.cols, "rows": term.rows})
|
||||||
}
|
|
||||||
|
|
||||||
function debounce(func, wait_ms) {
|
|
||||||
let timeout
|
|
||||||
return function(...args) {
|
|
||||||
const context = this
|
|
||||||
clearTimeout(timeout)
|
|
||||||
timeout = setTimeout(() => func.apply(context, args), wait_ms)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const wait_ms = 50;;
|
|
||||||
window.onresize = debounce(fitToscreen, wait_ms)
|
|
||||||
} else {
|
|
||||||
document.getElementById('psql-terminal').innterHTML = 'PSQL not supported'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function debounce(func, wait_ms) {
|
||||||
|
let timeout
|
||||||
|
return function(...args) {
|
||||||
|
const context = this
|
||||||
|
clearTimeout(timeout)
|
||||||
|
timeout = setTimeout(() => func.apply(context, args), wait_ms)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const wait_ms = 50;;
|
||||||
|
window.onresize = debounce(fitToscreen, wait_ms)
|
||||||
|
|
||||||
});
|
});
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -769,6 +769,10 @@ def configure_preferences(default_binary_path=None):
|
||||||
set_default_binary_path(
|
set_default_binary_path(
|
||||||
default_binary_path[server], bin_paths, server)
|
default_binary_path[server], bin_paths, server)
|
||||||
|
|
||||||
|
bin_paths_server_based = json.dumps(bin_paths['pg_bin_paths'])
|
||||||
|
if server == 'ppas':
|
||||||
|
bin_paths_server_based = json.dumps(bin_paths['as_bin_paths'])
|
||||||
|
|
||||||
pref_bin_path = paths_pref.preference('{0}_bin_dir'.format(server))
|
pref_bin_path = paths_pref.preference('{0}_bin_dir'.format(server))
|
||||||
user_pref = cur.execute(
|
user_pref = cur.execute(
|
||||||
'SELECT pid, uid FROM user_preferences '
|
'SELECT pid, uid FROM user_preferences '
|
||||||
|
@ -779,15 +783,10 @@ def configure_preferences(default_binary_path=None):
|
||||||
if user_pref_data:
|
if user_pref_data:
|
||||||
cur.execute(
|
cur.execute(
|
||||||
'UPDATE user_preferences SET value = ? WHERE pid = ?',
|
'UPDATE user_preferences SET value = ? WHERE pid = ?',
|
||||||
(pref_bin_path.default, pref_bin_path.pid)
|
(bin_paths_server_based, pref_bin_path.pid)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if server == 'ppas':
|
params = (pref_bin_path.pid, 1, bin_paths_server_based)
|
||||||
params = (pref_bin_path.pid, 1,
|
|
||||||
json.dumps(bin_paths['as_bin_paths']))
|
|
||||||
else:
|
|
||||||
params = (pref_bin_path.pid, 1,
|
|
||||||
json.dumps(bin_paths['pg_bin_paths']))
|
|
||||||
cur.execute(
|
cur.execute(
|
||||||
insert_preferences_query, params
|
insert_preferences_query, params
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue