Significantly improve connection loss detection and handling in the query tool. Fixes #2815

This commit is contained in:
Harshal Dhumal
2018-02-01 14:29:18 +01:00
committed by Dave Page
parent c3ddb7df38
commit e0da9c5a0c
15 changed files with 1648 additions and 807 deletions

View File

@@ -17,7 +17,6 @@ import random
from flask import Response, url_for, session, request, make_response
from werkzeug.useragents import UserAgent
from flask import current_app as app
from flask_babel import gettext
from flask_security import login_required
from pgadmin.tools.sqleditor.command import *
from pgadmin.utils import PgAdminModule
@@ -27,6 +26,8 @@ from pgadmin.utils.ajax import make_json_response, bad_request, \
from config import PG_DEFAULT_DRIVER
from pgadmin.utils.preferences import Preferences
from pgadmin.model import Server
from pgadmin.utils.driver import get_driver
from pgadmin.utils.exception import ConnectionLost
class DataGridModule(PgAdminModule):
@@ -93,13 +94,13 @@ def show_filter():
@blueprint.route(
'/initialize/datagrid/<int:cmd_type>/<obj_type>/<int:sid>/<int:did>/'
'<int:obj_id>',
'/initialize/datagrid/<int:cmd_type>/<obj_type>/<int:sgid>/<int:sid>/'
'<int:did>/<int:obj_id>',
methods=["PUT", "POST"],
endpoint="initialize_datagrid"
)
@login_required
def initialize_datagrid(cmd_type, obj_type, sid, did, obj_id):
def initialize_datagrid(cmd_type, obj_type, sgid, sid, did, obj_id):
"""
This method is responsible for creating an asynchronous connection.
After creating the connection it will instantiate and initialize
@@ -110,7 +111,7 @@ def initialize_datagrid(cmd_type, obj_type, sid, did, obj_id):
cmd_type: Contains value for which menu item is clicked.
obj_type: Contains type of selected object for which data grid to
be render
sgid: Server group Id
sid: Server Id
did: Database Id
obj_id: Id of currently selected object
@@ -125,15 +126,27 @@ def initialize_datagrid(cmd_type, obj_type, sid, did, obj_id):
conn_id = str(random.randint(1, 9999999))
try:
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
# default_conn is same connection which is created when user connect to
# database from tree
default_conn = manager.connection(did=did)
conn = manager.connection(did=did, conn_id=conn_id,
auto_reconnect=False,
use_binary_placeholder=True,
array_to_string=True)
except ConnectionLost as e:
raise
except Exception as e:
app.logger.error(e)
return internal_server_error(errormsg=str(e))
# Connect the Server
status, msg = default_conn.connect()
if not status:
app.logger.error(msg)
return internal_server_error(errormsg=str(msg))
status, msg = conn.connect()
if not status:
app.logger.error(msg)
return internal_server_error(errormsg=str(msg))
try:
@@ -143,11 +156,12 @@ def initialize_datagrid(cmd_type, obj_type, sid, did, obj_id):
# Get the object as per the object type
command_obj = ObjectRegistry.get_object(
obj_type, conn_id=conn_id, sid=sid,
obj_type, conn_id=conn_id, sgid=sgid, sid=sid,
did=did, obj_id=obj_id, cmd_type=cmd_type,
sql_filter=filter_sql
)
except Exception as e:
app.logger.error(e)
return internal_server_error(errormsg=str(e))
# Create a unique id for the transaction
@@ -236,17 +250,6 @@ def panel(trans_id, is_query_tool, editor_title):
else:
new_browser_tab = 'false'
if is_query_tool == 'true':
prompt_save_changes = pref.preference(
'prompt_save_query_changes'
).get()
else:
prompt_save_changes = pref.preference(
'prompt_save_data_changes'
).get()
display_connection_status = pref.preference('connection_status').get()
# Fetch the server details
bgcolor = None
fgcolor = None
@@ -264,6 +267,27 @@ def panel(trans_id, is_query_tool, editor_title):
bgcolor = s.bgcolor
fgcolor = s.fgcolor or 'black'
url_params = dict()
if is_query_tool == 'true':
prompt_save_changes = pref.preference(
'prompt_save_query_changes'
).get()
url_params['sgid'] = trans_obj.sgid
url_params['sid'] = trans_obj.sid
url_params['did'] = trans_obj.did
else:
prompt_save_changes = pref.preference(
'prompt_save_data_changes'
).get()
url_params['cmd_type'] = trans_obj.cmd_type
url_params['obj_type'] = trans_obj.object_type
url_params['sgid'] = trans_obj.sgid
url_params['sid'] = trans_obj.sid
url_params['did'] = trans_obj.did
url_params['obj_id'] = trans_obj.obj_id
display_connection_status = pref.preference('connection_status').get()
return render_template(
"datagrid/index.html",
_=gettext,
@@ -281,50 +305,62 @@ def panel(trans_id, is_query_tool, editor_title):
# convert python boolean value to equivalent js boolean literal
# before passing it to html template.
prompt_save_changes='true' if prompt_save_changes else 'false',
display_connection_status=display_connection_status
display_connection_status=display_connection_status,
url_params=json.dumps(url_params)
)
@blueprint.route(
'/initialize/query_tool/<int:sid>/<int:did>',
'/initialize/query_tool/<int:sgid>/<int:sid>/<int:did>',
methods=["POST"], endpoint='initialize_query_tool_with_did'
)
@blueprint.route(
'/initialize/query_tool/<int:sid>',
'/initialize/query_tool/<int:sgid>/<int:sid>',
methods=["POST"], endpoint='initialize_query_tool'
)
@login_required
def initialize_query_tool(sid, did=None):
def initialize_query_tool(sgid, sid, did=None):
"""
This method is responsible for instantiating and initializing
the query tool object. It will also create a unique
transaction id and store the information into session variable.
Args:
sgid: Server group Id
sid: Server Id
did: Database Id
"""
connect = True
if ('recreate' in request.args and
request.args['recreate'] == '1'):
connect = False
# Create asynchronous connection using random connection id.
conn_id = str(random.randint(1, 9999999))
# Use Maintenance database OID
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
if did is None:
# Use Maintenance database OID
from pgadmin.utils.driver import get_driver
driver = get_driver(PG_DEFAULT_DRIVER)
manager = driver.connection_manager(sid)
conn = manager.connection()
if conn.connected():
did = manager.did
else:
internal_server_error(
errormsg=gettext(
'Server disconnected. Please connect and try again.'
)
)
did = manager.did
try:
command_obj = ObjectRegistry.get_object(
'query_tool', sid=sid, did=did
'query_tool', conn_id=conn_id, sgid=sgid, sid=sid, did=did
)
except Exception as e:
app.logger.error(e)
return internal_server_error(errormsg=str(e))
try:
conn = manager.connection(did=did, conn_id=conn_id,
auto_reconnect=False,
use_binary_placeholder=True,
array_to_string=True)
if connect:
conn.connect()
except ConnectionLost as e:
raise
except Exception as e:
app.logger.error(e)
return internal_server_error(errormsg=str(e))
# Create a unique id for the transaction
@@ -366,6 +402,8 @@ def close(trans_id):
Args:
trans_id: unique transaction id
"""
if 'gridData' not in session:
return make_json_response(data={'status': True})
grid_data = session['gridData']
# Return from the function if transaction id not found
@@ -384,6 +422,7 @@ def close(trans_id):
conn = manager.connection(
did=cmd_obj.did, conn_id=cmd_obj.conn_id)
except Exception as e:
app.logger.error(e)
return internal_server_error(errormsg=str(e))
# Release the connection
@@ -424,6 +463,7 @@ def validate_filter(sid, did, obj_id):
# Call validate_filter method to validate the SQL.
status, res = sql_filter_obj.validate_filter(filter_sql)
except Exception as e:
app.logger.error(e)
return internal_server_error(errormsg=str(e))
return make_json_response(data={'status': status, 'result': res})

File diff suppressed because it is too large Load Diff

View File

@@ -24,7 +24,7 @@
<span class="sql-editor-busy-icon wcLoadingIcon fa fa-spinner fa-pulse"></span>
<span class="sql-editor-busy-text wcLoadingLabel"></span>
</div>
<div class="sql-editor" data-trans-id="{{ uniqueId }}">
<div class="sql-editor">
<div id="btn-toolbar" class="pg-prop-btn-group bg-gray-2 border-gray-3" role="toolbar" aria-label="">
<div class="btn-group" role="group" aria-label="">
<button id="btn-load-file" type="button" class="btn btn-default btn-load-file"
@@ -361,44 +361,21 @@
loadingDiv.addClass('hide');
}
});
// Fetch the SQL for Scripts (eg: CREATE/UPDATE/DELETE/SELECT)
var script_sql = '';
{% if script_type_url%}
// Call AJAX only if script type url is present
$.ajax({
url: '{{ script_type_url }}',
type:'GET',
async: false,
success: function(res) {
script_sql = res;
},
error: function(jqx) {
var msg = jqx.responseText;
/* Error from the server */
if (jqx.status == 410 || jqx.status == 500) {
try {
var data = $.parseJSON(jqx.responseText);
msg = data.errormsg;
} catch (e) {}
}
pgBrowser.report_error(
S('{{ _('Error fetching SQL for script: "%s"') }}')
.sprintf(msg)
.value(), msg
);
}
});
{% endif %}
{% if script_type_url %}
var script_type_url = '{{ script_type_url }}';
{% else %}
var script_type_url = '';
{% endif %}
// Start the query tool.
sqlEditorController.start(
{{ uniqueId }},
{{ is_query_tool }},
"{{ editor_title }}",
script_sql,
script_type_url,
{{ is_new_browser_tab }},
"{{ server_type }}",
{{ prompt_save_changes }}
{{ prompt_save_changes }},
{{ url_params|safe}}
);
});
{% endblock %}

View File

@@ -14,7 +14,8 @@ import pickle
import random
import codecs
from flask import Response, url_for, render_template, session, request
from flask import Response, url_for, render_template, session, request,\
current_app
from flask_babel import gettext
from flask_security import login_required
from pgadmin.tools.sqleditor.command import QueryToolCommand
@@ -26,6 +27,7 @@ from pgadmin.utils.driver import get_driver
from pgadmin.utils.sqlautocomplete.autocomplete import SQLAutoComplete
from pgadmin.misc.file_manager import Filemanager
from pgadmin.utils.menu import MenuItem
from pgadmin.utils.exception import ConnectionLost
from config import PG_DEFAULT_DRIVER, ON_DEMAND_RECORD_COUNT
@@ -51,13 +53,13 @@ TX_STATUS_INTRANS = 2
TX_STATUS_INERROR = 3
# Connection status codes mapping
CONNECTION_STATUS_MESSAGE_MAPPING = dict({
0: 'The session is idle and there is no current transaction.',
1: 'A command is currently in progress.',
2: 'The session is idle in a valid transaction block.',
3: 'The session is idle in a failed transaction block.',
4: 'The connection with the server is bad.'
})
CONNECTION_STATUS_MESSAGE_MAPPING = dict([
(0, 'The session is idle and there is no current transaction.'),
(1, 'A command is currently in progress.'),
(2, 'The session is idle in a valid transaction block.'),
(3, 'The session is idle in a failed transaction block.'),
(4, 'The connection with the server is bad.')
])
class SqlEditorModule(PgAdminModule):
@@ -393,9 +395,11 @@ def check_transaction_status(trans_id):
Returns: status and connection object
"""
if 'gridData' not in session:
return False, unauthorized(gettext("Unauthorized request.")), \
None, None, None
return False, gettext(
'Transaction ID not found in the session.'
), None, None, None
grid_data = session['gridData']
@@ -416,18 +420,23 @@ def check_transaction_status(trans_id):
conn = manager.connection(
did=trans_obj.did,
conn_id=trans_obj.conn_id,
auto_reconnect=False,
use_binary_placeholder=True,
array_to_string=True
)
except ConnectionLost as e:
raise
except Exception as e:
current_app.logger.error(e)
return False, internal_server_error(errormsg=str(e)), None, None, None
if conn.connected():
return True, None, conn, trans_obj, session_obj
else:
return False, gettext('Not connected to server or connection with '
'the server has been closed.'), \
None, trans_obj, session_obj
connect = True if 'connect' in request.args and \
request.args['connect'] == '1' else False
if connect:
conn.connect()
return True, None, conn, trans_obj, session_obj
@blueprint.route(
@@ -448,12 +457,25 @@ def start_view_data(trans_id):
status, error_msg, conn, trans_obj, session_obj = \
check_transaction_status(trans_id)
if error_msg == gettext(
'Transaction ID not found in the session.'):
return make_json_response(success=0, errormsg=error_msg,
info='DATAGRID_TRANSACTION_REQUIRED',
status=404)
# get the default connection as current connection which is attached to
# trans id holds the cursor which has query result so we cannot use that
# connection to execute another query otherwise we'll lose query result.
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(trans_obj.sid)
default_conn = manager.connection(did=trans_obj.did)
try:
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(
trans_obj.sid)
default_conn = manager.connection(did=trans_obj.did)
except ConnectionLost as e:
raise
except Exception as e:
current_app.logger.error(e)
return internal_server_error(errormsg=str(e))
# Connect to the Server if not connected.
if not default_conn.connected():
@@ -465,41 +487,41 @@ def start_view_data(trans_id):
if status and conn is not None \
and trans_obj is not None and session_obj is not None:
# set fetched row count to 0 as we are executing query again.
trans_obj.update_fetched_row_cnt(0)
session_obj['command_obj'] = pickle.dumps(trans_obj, -1)
# Fetch the sql and primary_keys from the object
sql = trans_obj.get_sql(default_conn)
pk_names, primary_keys = trans_obj.get_primary_keys(default_conn)
has_oids = False
if trans_obj.object_type == 'table':
# Fetch OIDs status
has_oids = trans_obj.has_oids(default_conn)
# Fetch the applied filter.
filter_applied = trans_obj.is_filter_applied()
# Fetch the limit for the SQL query
limit = trans_obj.get_limit()
can_edit = trans_obj.can_edit()
can_filter = trans_obj.can_filter()
# Store the primary keys to the session object
session_obj['primary_keys'] = primary_keys
# Store the OIDs status into session object
session_obj['has_oids'] = has_oids
update_session_grid_transaction(trans_id, session_obj)
# Execute sql asynchronously
try:
# set fetched row count to 0 as we are executing query again.
trans_obj.update_fetched_row_cnt(0)
session_obj['command_obj'] = pickle.dumps(trans_obj, -1)
# Fetch the sql and primary_keys from the object
sql = trans_obj.get_sql()
pk_names, primary_keys = trans_obj.get_primary_keys(default_conn)
has_oids = False
if trans_obj.object_type == 'table':
# Fetch OIDs status
has_oids = trans_obj.has_oids(default_conn)
# Fetch the applied filter.
filter_applied = trans_obj.is_filter_applied()
# Fetch the limit for the SQL query
limit = trans_obj.get_limit()
can_edit = trans_obj.can_edit()
can_filter = trans_obj.can_filter()
# Store the primary keys to the session object
session_obj['primary_keys'] = primary_keys
# Store the OIDs status into session object
session_obj['has_oids'] = has_oids
update_session_grid_transaction(trans_id, session_obj)
# Execute sql asynchronously
status, result = conn.execute_async(sql)
except Exception as e:
return internal_server_error(errormsg=str(e))
except ConnectionLost as e:
raise
else:
status = False
result = error_msg
@@ -537,26 +559,24 @@ def start_query_tool(trans_id):
else:
sql = request.args or request.form
connect = True if 'connect' in request.args and \
request.args['connect'] == '1' else False
if 'gridData' not in session:
return make_json_response(
data={
'status': False,
'result': gettext('Transaction ID not found in the session.'),
'can_edit': False, 'can_filter': False
}
)
success=0,
errormsg=gettext('Transaction ID not found in the session.'),
info='DATAGRID_TRANSACTION_REQUIRED', status=404)
grid_data = session['gridData']
# Return from the function if transaction id not found
if str(trans_id) not in grid_data:
return make_json_response(
data={
'status': False,
'result': gettext('Transaction ID not found in the session.'),
'can_edit': False, 'can_filter': False
}
)
success=0,
errormsg=gettext('Transaction ID not found in the session.'),
info='DATAGRID_TRANSACTION_REQUIRED',
status=404)
# Fetch the object for the specified transaction id.
# Use pickle.loads function to get the command object
@@ -570,60 +590,55 @@ def start_query_tool(trans_id):
if trans_obj is not None and session_obj is not None:
conn_id = trans_obj.conn_id
# if conn_id is None then we will have to create a new connection
if conn_id is None:
# Create asynchronous connection using random connection id.
conn_id = str(random.randint(1, 9999999))
try:
manager = get_driver(
PG_DEFAULT_DRIVER).connection_manager(trans_obj.sid)
conn = manager.connection(did=trans_obj.did, conn_id=conn_id,
auto_reconnect=False,
use_binary_placeholder=True,
array_to_string=True)
except ConnectionLost as e:
raise
except Exception as e:
current_app.logger.error(e)
return internal_server_error(errormsg=str(e))
# Connect to the Server if not connected.
if not conn.connected():
if connect and not conn.connected():
status, msg = conn.connect()
if not status:
current_app.logger.error(msg)
return internal_server_error(errormsg=str(msg))
if conn.connected():
# on successful connection set the connection id to the
# transaction object
trans_obj.set_connection_id(conn_id)
# on successful connection set the connection id to the
# transaction object
trans_obj.set_connection_id(conn_id)
# As we changed the transaction object we need to
# restore it and update the session variable.
session_obj['command_obj'] = pickle.dumps(trans_obj, -1)
update_session_grid_transaction(trans_id, session_obj)
# As we changed the transaction object we need to
# restore it and update the session variable.
session_obj['command_obj'] = pickle.dumps(trans_obj, -1)
update_session_grid_transaction(trans_id, session_obj)
# If auto commit is False and transaction status is Idle
# then call is_begin_not_required() function to check BEGIN
# is required or not.
# If auto commit is False and transaction status is Idle
# then call is_begin_not_required() function to check BEGIN
# is required or not.
if not trans_obj.auto_commit \
and conn.transaction_status() == TX_STATUS_IDLE \
and is_begin_required(sql):
conn.execute_void("BEGIN;")
if not trans_obj.auto_commit \
and conn.transaction_status() == TX_STATUS_IDLE \
and is_begin_required(sql):
conn.execute_void("BEGIN;")
# Execute sql asynchronously with params is None
# and formatted_error is True.
# Execute sql asynchronously with params is None
# and formatted_error is True.
try:
status, result = conn.execute_async(sql)
# If the transaction aborted for some reason and
# Auto RollBack is True then issue a rollback to cleanup.
trans_status = conn.transaction_status()
if trans_status == TX_STATUS_INERROR and trans_obj.auto_rollback:
conn.execute_void("ROLLBACK;")
else:
status = False
result = gettext(
'Not connected to server or connection with the server has '
'been closed.')
except ConnectionLost as e:
raise
# If the transaction aborted for some reason and
# Auto RollBack is True then issue a rollback to cleanup.
trans_status = conn.transaction_status()
if trans_status == TX_STATUS_INERROR and trans_obj.auto_rollback:
conn.execute_void("ROLLBACK;")
can_edit = trans_obj.can_edit()
can_filter = trans_obj.can_filter()
@@ -655,10 +670,16 @@ def preferences(trans_id):
trans_id: unique transaction id
"""
if request.method == 'GET':
# Check the transaction and connection status
status, error_msg, conn, trans_obj, session_obj = \
check_transaction_status(trans_id)
if error_msg == gettext(
'Transaction ID not found in the session.'):
return make_json_response(success=0, errormsg=error_msg,
info='DATAGRID_TRANSACTION_REQUIRED',
status=404)
if status and conn is not None \
and trans_obj is not None and session_obj is not None:
# Call the set_auto_commit and set_auto_rollback method of
@@ -728,6 +749,13 @@ def poll(trans_id):
# Check the transaction and connection status
status, error_msg, conn, trans_obj, session_obj = \
check_transaction_status(trans_id)
if error_msg == gettext(
'Transaction ID not found in the session.'):
return make_json_response(success=0, errormsg=error_msg,
info='DATAGRID_TRANSACTION_REQUIRED',
status=404)
if status and conn is not None and session_obj is not None:
status, result = conn.poll(
formatted_exception_msg=True, no_result=True)
@@ -915,6 +943,13 @@ def fetch(trans_id, fetch_all=None):
# Check the transaction and connection status
status, error_msg, conn, trans_obj, session_obj = \
check_transaction_status(trans_id)
if error_msg == gettext(
'Transaction ID not found in the session.'):
return make_json_response(success=0, errormsg=error_msg,
info='DATAGRID_TRANSACTION_REQUIRED',
status=404)
if status and conn is not None and session_obj is not None:
status, result = conn.async_fetchmany_2darray(fetch_row_cnt)
if not status:
@@ -1030,6 +1065,13 @@ def save(trans_id):
# Check the transaction and connection status
status, error_msg, conn, trans_obj, session_obj = \
check_transaction_status(trans_id)
if error_msg == gettext(
'Transaction ID not found in the session.'):
return make_json_response(success=0, errormsg=error_msg,
info='DATAGRID_TRANSACTION_REQUIRED',
status=404)
if status and conn is not None \
and trans_obj is not None and session_obj is not None:
@@ -1092,6 +1134,12 @@ def get_filter(trans_id):
# Check the transaction and connection status
status, error_msg, conn, trans_obj, session_obj = \
check_transaction_status(trans_id)
if error_msg == gettext(
'Transaction ID not found in the session.'):
return make_json_response(success=0, errormsg=error_msg,
info='DATAGRID_TRANSACTION_REQUIRED',
status=404)
if status and conn is not None \
and trans_obj is not None and session_obj is not None:
@@ -1123,6 +1171,13 @@ def apply_filter(trans_id):
# Check the transaction and connection status
status, error_msg, conn, trans_obj, session_obj = \
check_transaction_status(trans_id)
if error_msg == gettext(
'Transaction ID not found in the session.'):
return make_json_response(success=0, errormsg=error_msg,
info='DATAGRID_TRANSACTION_REQUIRED',
status=404)
if status and conn is not None \
and trans_obj is not None and session_obj is not None:
@@ -1159,6 +1214,13 @@ def append_filter_inclusive(trans_id):
# Check the transaction and connection status
status, error_msg, conn, trans_obj, session_obj = \
check_transaction_status(trans_id)
if error_msg == gettext(
'Transaction ID not found in the session.'):
return make_json_response(success=0, errormsg=error_msg,
info='DATAGRID_TRANSACTION_REQUIRED',
status=404)
if status and conn is not None \
and trans_obj is not None and session_obj is not None:
@@ -1208,6 +1270,12 @@ def append_filter_exclusive(trans_id):
# Check the transaction and connection status
status, error_msg, conn, trans_obj, session_obj = \
check_transaction_status(trans_id)
if error_msg == gettext(
'Transaction ID not found in the session.'):
return make_json_response(success=0, errormsg=error_msg,
info='DATAGRID_TRANSACTION_REQUIRED',
status=404)
if status and conn is not None \
and trans_obj is not None and session_obj is not None:
@@ -1255,6 +1323,13 @@ def remove_filter(trans_id):
# Check the transaction and connection status
status, error_msg, conn, trans_obj, session_obj = \
check_transaction_status(trans_id)
if error_msg == gettext(
'Transaction ID not found in the session.'):
return make_json_response(success=0, errormsg=error_msg,
info='DATAGRID_TRANSACTION_REQUIRED',
status=404)
if status and conn is not None \
and trans_obj is not None and session_obj is not None:
@@ -1293,6 +1368,13 @@ def set_limit(trans_id):
# Check the transaction and connection status
status, error_msg, conn, trans_obj, session_obj = \
check_transaction_status(trans_id)
if error_msg == gettext(
'Transaction ID not found in the session.'):
return make_json_response(success=0, errormsg=error_msg,
info='DATAGRID_TRANSACTION_REQUIRED',
status=404)
if status and conn is not None \
and trans_obj is not None and session_obj is not None:
@@ -1325,16 +1407,20 @@ def cancel_transaction(trans_id):
trans_id: unique transaction id
"""
if 'gridData' not in session:
return make_json_response(
success=0,
errormsg=gettext('Transaction ID not found in the session.'),
info='DATAGRID_TRANSACTION_REQUIRED', status=404)
grid_data = session['gridData']
# Return from the function if transaction id not found
if str(trans_id) not in grid_data:
return make_json_response(
data={
'status': False,
'result': gettext('Transaction ID not found in the session.')
}
)
success=0,
errormsg=gettext('Transaction ID not found in the session.'),
info='DATAGRID_TRANSACTION_REQUIRED', status=404)
# Fetch the object for the specified transaction id.
# Use pickle.loads function to get the command object
@@ -1403,6 +1489,13 @@ def get_object_name(trans_id):
# Check the transaction and connection status
status, error_msg, conn, trans_obj, session_obj = \
check_transaction_status(trans_id)
if error_msg == gettext(
'Transaction ID not found in the session.'):
return make_json_response(success=0, errormsg=error_msg,
info='DATAGRID_TRANSACTION_REQUIRED',
status=404)
if status and conn is not None \
and trans_obj is not None and session_obj is not None:
res = trans_obj.object_name
@@ -1433,6 +1526,13 @@ def set_auto_commit(trans_id):
# Check the transaction and connection status
status, error_msg, conn, trans_obj, session_obj = \
check_transaction_status(trans_id)
if error_msg == gettext(
'Transaction ID not found in the session.'):
return make_json_response(success=0, errormsg=error_msg,
info='DATAGRID_TRANSACTION_REQUIRED',
status=404)
if status and conn is not None \
and trans_obj is not None and session_obj is not None:
@@ -1475,6 +1575,13 @@ def set_auto_rollback(trans_id):
# Check the transaction and connection status
status, error_msg, conn, trans_obj, session_obj = \
check_transaction_status(trans_id)
if error_msg == gettext(
'Transaction ID not found in the session.'):
return make_json_response(success=0, errormsg=error_msg,
info='DATAGRID_TRANSACTION_REQUIRED',
status=404)
if status and conn is not None \
and trans_obj is not None and session_obj is not None:
@@ -1524,6 +1631,13 @@ def auto_complete(trans_id):
# Check the transaction and connection status
status, error_msg, conn, trans_obj, session_obj = \
check_transaction_status(trans_id)
if error_msg == gettext(
'Transaction ID not found in the session.'):
return make_json_response(success=0, errormsg=error_msg,
info='DATAGRID_TRANSACTION_REQUIRED',
status=404)
if status and conn is not None \
and trans_obj is not None and session_obj is not None:
@@ -1947,7 +2061,7 @@ def query_tool_status(trans_id):
)
if conn and trans_obj and session_obj:
status = conn.conn.get_transaction_status()
status = conn.transaction_status()
return make_json_response(
data={
'status': status,

View File

@@ -104,7 +104,9 @@ class BaseCommand(object):
**kwargs : N number of parameters
"""
# Save the server id and database id, namespace id, object id
# Save the server group id, server id and database id, namespace id,
# object id
self.sgid = kwargs['sgid'] if 'sgid' in kwargs else None
self.sid = kwargs['sid'] if 'sid' in kwargs else None
self.did = kwargs['did'] if 'did' in kwargs else None
@@ -922,7 +924,7 @@ class QueryToolCommand(BaseCommand, FetchedRowTracker):
BaseCommand.__init__(self, **kwargs)
FetchedRowTracker.__init__(self, **kwargs)
self.conn_id = None
self.conn_id = kwargs['conn_id'] if 'conn_id' in kwargs else None
self.auto_rollback = False
self.auto_commit = True

View File

@@ -581,3 +581,24 @@ input.editor-checkbox:focus {
.sql-editor .copy-all:focus {
outline: 5px auto -webkit-focus-ring-color;
}
.ajs-body .warn-icon {
color:#f1c40f;
font-size: 2em;
margin-right: 20px;
padding-top: 10px;
}
.ajs-body .warn-header {
font-size: 13px;
font-weight: bold;
line-height: 3em;
}
.ajs-body .warn-body {
font-size: 13px;
}
.ajs-body .warn-footer {
font-size: 13px;
line-height: 3em;
}

File diff suppressed because it is too large Load Diff

View File

@@ -13,7 +13,7 @@ import simplejson as json
import re
from flask import render_template, request, \
url_for, Response, abort
url_for, Response, abort, current_app
from flask_babel import gettext as _
from flask_security import login_required, roles_required, current_user
from flask_security.utils import encrypt_password
@@ -73,7 +73,7 @@ class UserManagementModule(PgAdminModule):
'user_management.roles', 'user_management.role',
'user_management.update_user', 'user_management.delete_user',
'user_management.create_user', 'user_management.users',
'user_management.user'
'user_management.user', current_app.login_manager.login_view
]

View File

@@ -129,6 +129,95 @@ define([
alertify.ChangePassword(title, url).resizeTo('75%', '70%');
},
is_pga_login_required(xhr) {
return xhr.status == 401 && xhr.responseJSON &&
xhr.responseJSON.info &&
xhr.responseJSON.info == 'PGADMIN_LOGIN_REQUIRED';
},
// Callback to draw pgAdmin4 login dialog.
pga_login: function(url) {
var title = gettext('pgAdmin 4 login');
url = url || url_for('security.login');
if(!alertify.PgaLogin) {
alertify.dialog('PgaLogin' ,function factory() {
return {
main: function(title, url) {
this.set({
'title': title,
'url': url,
});
},
build: function() {
alertify.pgDialogBuild.apply(this);
},
settings:{
url: undefined,
},
setup:function() {
return {
buttons: [{
text: gettext('Close'), key: 27,
className: 'btn btn-danger fa fa-lg fa-times pg-alertify-button',
attrs:{name:'close', type:'button'},
}],
// Set options for dialog
options: {
//disable both padding and overflow control.
padding : !1,
overflow: !1,
modal: true,
resizable: true,
maximizable: true,
pinnable: false,
closableByDimmer: false,
closable: false,
},
};
},
hooks: {
// Triggered when the dialog is closed
onclose: function() {
// Clear the view
return setTimeout((function() {
return alertify.PgaLogin().destroy();
}));
},
},
prepare: function() {
// create the iframe element
var self = this,
iframe = document.createElement('iframe'),
url = this.setting('url');
iframe.onload = function() {
var doc = this.contentDocument || this.contentWindow.document;
if (doc.location.href.indexOf(url) == -1) {
// login successful.
this.contentWindow.stop();
this.onload = null;
// close the dialog.
self.close();
pgBrowser.Events.trigger('pgadmin:user:logged-in');
}
};
iframe.frameBorder = 'no';
iframe.width = '100%';
iframe.height = '100%';
iframe.src = url;
// add it to the dialog
self.elements.content.appendChild(iframe);
},
};
});
}
alertify.PgaLogin(title, url).resizeTo('75%','70%');
},
// Callback to draw User Management Dialog.
show_users: function() {
if (!userInfo['is_admin']) return;