Hi,
Plz find attached patch to fix session expired issue
from sqleditor/datadrid.
--
*Harshal Dhumal*
*Sr. Software Engineer*
EnterpriseDB India: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
diff --git a/web/pgadmin/__init__.py b/web/pgadmin/__init__.py
index db676c5..220ea6b 100644
--- a/web/pgadmin/__init__.py
+++ b/web/pgadmin/__init__.py
@@ -25,7 +25,7 @@ from flask_paranoid import Paranoid
from pgadmin.utils import PgAdminModule, driver
from pgadmin.utils.versioned_template_loader import VersionedTemplateLoader
-from pgadmin.utils.session import create_session_interface
+from pgadmin.utils.session import create_session_interface, pga_unauthorised
from werkzeug.local import LocalProxy
from werkzeug.utils import find_modules
@@ -344,6 +344,9 @@ def create_app(app_name=None):
security.init_app(app, user_datastore)
+ # register custom unauthorised handler.
+ app.login_manager.unauthorized_handler(pga_unauthorised)
+
app.session_interface = create_session_interface(app)
# Make the Session more secure against XSS & CSRF when running in web mode
diff --git a/web/pgadmin/browser/server_groups/servers/__init__.py b/web/pgadmin/browser/server_groups/servers/__init__.py
index 5330942..626526c 100644
--- a/web/pgadmin/browser/server_groups/servers/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/__init__.py
@@ -202,6 +202,9 @@ class ServerModule(sg.ServerGroupPluginModule):
"""
ServerType.register_preferences()
+ def get_exposed_url_endpoints(self):
+ return ['NODE-server.connect_id']
+
class ServerMenuItem(MenuItem):
def __init__(self, **kwargs):
diff --git a/web/pgadmin/tools/datagrid/__init__.py b/web/pgadmin/tools/datagrid/__init__.py
index 6b1d699..75f63d7 100644
--- a/web/pgadmin/tools/datagrid/__init__.py
+++ b/web/pgadmin/tools/datagrid/__init__.py
@@ -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,9 @@ 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):
"""
@@ -90,11 +92,11 @@ 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
@@ -104,6 +106,7 @@ def initialize_datagrid(cmd_type, obj_type, sid, did, obj_id):
Args:
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
@@ -118,15 +121,26 @@ 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,
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:
@@ -135,10 +149,13 @@ def initialize_datagrid(cmd_type, obj_type, sid, did, obj_id):
obj_type = 'table'
# Get the object as per the object type
- command_obj = ObjectRegistry.get_object(obj_type, conn_id=conn_id, sid=sid,
- did=did, obj_id=obj_id, cmd_type=cmd_type,
+ command_obj = ObjectRegistry.get_object(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
@@ -217,11 +234,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()
-
# Fetch the server details
#
bgcolor = None
@@ -239,6 +251,21 @@ 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
+
return render_template(
"datagrid/index.html", _=gettext, uniqueId=trans_id,
is_query_tool=is_query_tool,
@@ -252,48 +279,41 @@ def panel(trans_id, is_query_tool, editor_title):
fgcolor=fgcolor,
# 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'
+ prompt_save_changes='true' if prompt_save_changes else 'false',
+ 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
"""
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.'
- )
- )
-
+ manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
+ did = manager.did
try:
- command_obj = ObjectRegistry.get_object('query_tool', sid=sid, did=did)
+ command_obj = ObjectRegistry.get_object('query_tool', sgid=sgid,
+ sid=sid, did=did)
except Exception as e:
+ app.logger.error(e)
return internal_server_error(errormsg=str(e))
# Create a unique id for the transaction
@@ -330,6 +350,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
@@ -346,13 +368,15 @@ def close(trans_id):
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(cmd_obj.sid)
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
if conn.connected():
manager.release(did=cmd_obj.did, conn_id=cmd_obj.conn_id)
- # Remove the information of unique transaction id from the session variable.
+ # Remove the information of unique transaction id from the session
+ # variable.
grid_data.pop(str(trans_id), None)
session['gridData'] = grid_data
@@ -384,6 +408,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})
diff --git a/web/pgadmin/tools/datagrid/static/js/datagrid.js b/web/pgadmin/tools/datagrid/static/js/datagrid.js
index c44fbb1..28082b8 100644
--- a/web/pgadmin/tools/datagrid/static/js/datagrid.js
+++ b/web/pgadmin/tools/datagrid/static/js/datagrid.js
@@ -1,7 +1,9 @@
define('pgadmin.datagrid', [
'sources/gettext', 'sources/url_for', 'jquery', 'underscore', 'pgadmin.alertifyjs',
- 'sources/pgadmin', 'bundled_codemirror', 'sources/sqleditor_utils', 'wcdocker'
-], function(gettext, url_for, $, _, alertify, pgAdmin, codemirror, sqlEditorUtils) {
+ 'sources/pgadmin', 'bundled_codemirror', 'sources/sqleditor_utils',
+ 'backbone', 'wcdocker'
+], function(gettext, url_for, $, _, alertify, pgAdmin, codemirror,
+sqlEditorUtils, Backbone) {
// Some scripts do export their object in the window only.
// Generally the one, which do no have AMD support.
var wcDocker = window.wcDocker,
@@ -12,7 +14,9 @@ define('pgadmin.datagrid', [
if (pgAdmin.DataGrid)
return pgAdmin.DataGrid;
- pgAdmin.DataGrid = {
+ pgAdmin.DataGrid =
+ _.extend(
+ {
init: function() {
if (this.initialized)
return;
@@ -112,6 +116,9 @@ define('pgadmin.datagrid', [
// Load the newly created frame
dataGridFrameType.load(pgBrowser.docker);
+ this.on("pgadmin-datagrid:transaction:created", function(trans_obj) {
+ this.launch_grid(trans_obj);
+ });
},
// This is a callback function to show data when user click on menu item.
@@ -154,6 +161,7 @@ define('pgadmin.datagrid', [
var url_params = {
'cmd_type': data.mnuid,
'obj_type': d._type,
+ 'sgid': parentData.server_group._id,
'sid': parentData.server._id,
'did': parentData.database._id,
'obj_id': d._id
@@ -163,8 +171,7 @@ define('pgadmin.datagrid', [
var grid_title = parentData.server.label + ' - ' + parentData.database.label + ' - '
+ nsp_name + '.' + d.label;
- // Initialize the data grid.
- self.initialize_data_grid(baseUrl, grid_title, '', parentData.server.server_type);
+ self.create_transaction(baseUrl, null, 'false', parentData.server.server_type, '', grid_title, '');
},
// This is a callback function to show filtered data when user click on menu item.
@@ -209,10 +216,10 @@ define('pgadmin.datagrid', [
var url_params = {
'cmd_type': data.mnuid,
'obj_type': d._type,
+ 'sgid': parentData.server_group._id,
'sid': parentData.server._id,
'did': parentData.database._id,
'obj_id': d._id
-
};
var baseUrl = url_for('datagrid.initialize_datagrid', url_params);
@@ -295,7 +302,7 @@ define('pgadmin.datagrid', [
success: function(res) {
if (res.data.status) {
// Initialize the data grid.
- self.initialize_data_grid(that.baseUrl, grid_title, sql, parentData.server.server_type);
+ self.create_transaction(that.baseUrl, null, 'false', parentData.server.server_type, '', grid_title, sql);
}
else {
alertify.alert(
@@ -348,88 +355,6 @@ define('pgadmin.datagrid', [
parentData.server.label;
return grid_title;
},
-
- initialize_data_grid: function(baseUrl, grid_title, sql_filter, server_type) {
- var self = this;
- self.grid_title = grid_title;
-
- /* Ajax call to initialize the edit grid, which creates
- * an asynchronous connection and create appropriate query
- * for the selected node.
- */
- $.ajax({
- url: baseUrl,
- method: 'POST',
- dataType: 'json',
- contentType: "application/json",
- data: JSON.stringify(sql_filter),
- success: function(res) {
-
- /* On successfully initialization find the dashboard panel,
- * create new panel and add it to the dashboard panel.
- */
- var url_params = {
- 'trans_id': res.data.gridTransId,
- 'is_query_tool': 'false',
- 'editor_title': encodeURIComponent(self.grid_title)
- };
-
- var baseUrl = url_for('datagrid.panel', url_params) +
- "?query_url=&server_type=" + encodeURIComponent(server_type);
- var grid_title = gettext('Edit Data - ') + self.grid_title;
- if (res.data.newBrowserTab) {
- var newWin = window.open(baseUrl, '_blank');
-
- // add a load listener to the window so that the title gets changed on page load
- newWin.addEventListener("load", function() {
- newWin.document.title = grid_title;
- });
- } else {
- var propertiesPanel = pgBrowser.docker.findPanels('properties');
- var dataGridPanel = pgBrowser.docker.addPanel('frm_datagrid', wcDocker.DOCK.STACKED, propertiesPanel[0]);
-
- // Set panel title and icon
- dataGridPanel.title('<span title="'+grid_title+'">'+grid_title+'</span>');
- dataGridPanel.icon('fa fa-bolt');
- dataGridPanel.focus();
-
- // Listen on the panel closed event.
- dataGridPanel.on(wcDocker.EVENT.CLOSED, function() {
- $.ajax({
- url: url_for('datagrid.close', {'trans_id': res.data.gridTransId}),
- method: 'GET'
- });
- });
-
- var openDataGridURL = function(j) {
- // add spinner element
- $(j).data('embeddedFrame').$container.append(self.spinner_el);
- setTimeout(function() {
- var frameInitialized = $(j).data('frameInitialized');
- if (frameInitialized) {
- var frame = $(j).data('embeddedFrame');
- if (frame) {
- frame.openURL(baseUrl);
- frame.$container.find('.wcLoadingContainer').hide(1);
- }
- } else {
- openDataGridURL(j);
- }
- }, 100);
- };
-
- openDataGridURL(dataGridPanel);
- }
- },
- error: function(e) {
- alertify.alert(
- gettext('Error'),
- gettext('Query Tool Initialization Error')
- );
- }
- });
- },
-
// This is a callback function to show query tool when user click on menu item.
show_query_tool: function(url, i, panel_title) {
var self = this,
@@ -454,9 +379,10 @@ define('pgadmin.datagrid', [
}
var url_params = {
- 'sid': parentData.server._id
- };
- var url_endpoint = 'datagrid.initialize_query_tool'
+ 'sgid': parentData.server_group._id,
+ 'sid': parentData.server._id
+ },
+ url_endpoint = 'datagrid.initialize_query_tool';
// If database not present then use Maintenance database
// We will handle this at server side
if (parentData.database) {
@@ -465,87 +391,123 @@ define('pgadmin.datagrid', [
}
var baseUrl = url_for(url_endpoint, url_params);
+ this.create_transaction(baseUrl, null, 'true', parentData.server.server_type, sURL, panel_title, '');
+ },
+ create_transaction: function(baseUrl, target, is_query_tool, server_type, sURL, panel_title, sql_filter) {
+ var self = this;
+ target = target || self;
+
$.ajax({
url: baseUrl,
method: 'POST',
dataType: 'json',
+ data: JSON.stringify(sql_filter),
contentType: "application/json",
success: function(res) {
- var grid_title = self.get_panel_title();
- // Open the panel if frame is initialized
- var url_params = {
- 'trans_id': res.data.gridTransId,
- 'is_query_tool': 'true',
- 'editor_title': encodeURIComponent(grid_title)
+ res.data.is_query_tool = is_query_tool;
+ res.data.server_type = server_type;
+ res.data.sURL = sURL;
+ res.data.panel_title = panel_title;
+ target.trigger("pgadmin-datagrid:transaction:created", res.data);
+ },
+ error: function(xhr, status, error) {
+ if (target !== self) {
+ if(xhr.status == 503 && xhr.responseJSON.info != undefined &&
+ xhr.responseJSON.info == "CONNECTION_LOST") {
+ setTimeout(function() {
+ target.handle_connection_lost(true);
+ });
+ return;
+ }
}
- var baseUrl = url_for('datagrid.panel', url_params) +
- '?' + "query_url=" + encodeURI(sURL) + "&server_type=" + encodeURIComponent(parentData.server.server_type);
-
- // Create title for CREATE/DELETE scripts
- if (panel_title) {
- panel_title =
- sqlEditorUtils.capitalizeFirstLetter(panel_title) + ' script';
- }
- else {
- panel_title = gettext('Query - ') + grid_title;
+ try {
+ var err = $.parseJSON(xhr.responseText);
+ alertify.alert(gettext("Query Tool Initialize Error"),
+ err.errormsg
+ );
+ } catch (e) {
+ alertify.alert(
+ e.statusText, gettext("Query Tool Initialize Error")
+ );
}
+ }
+ });
+ },
+ launch_grid: function(trans_obj) {
+ var self = this,
+ panel_title = trans_obj.panel_title,
+ grid_title = self.get_panel_title(),
+ // Open the panel if frame is initialized
+ url_params = {
+ 'trans_id': trans_obj.gridTransId,
+ 'is_query_tool': trans_obj.is_query_tool,
+ 'editor_title': encodeURIComponent(grid_title)
+ },
+ baseUrl = url_for('datagrid.panel', url_params) +
+ '?' + "query_url=" + encodeURI(trans_obj.sURL) + "&server_type=" + encodeURIComponent(trans_obj.server_type);
+
+ if(trans_obj.is_query_tool == 'false') {
+ panel_title = gettext('Edit Data - ') + grid_title;
+ } else {
+ // Create title for CREATE/DELETE scripts
+ if (panel_title) {
+ panel_title =
+ sqlEditorUtils.capitalizeFirstLetter(panel_title) + ' script';
+ } else {
+ panel_title = gettext('Query - ') + grid_title;
+ }
+ }
- if (res.data.newBrowserTab) {
- var newWin = window.open(baseUrl, '_blank');
-
- // add a load listener to the window so that the title gets changed on page load
- newWin.addEventListener("load", function() {
- newWin.document.title = panel_title;
- });
- } else {
- /* On successfully initialization find the dashboard panel,
- * create new panel and add it to the dashboard panel.
- */
- var propertiesPanel = pgBrowser.docker.findPanels('properties');
- var queryToolPanel = pgBrowser.docker.addPanel('frm_datagrid', wcDocker.DOCK.STACKED, propertiesPanel[0]);
-
- // Set panel title and icon
- queryToolPanel.title('<span title="'+panel_title+'">'+panel_title+'</span>');
- queryToolPanel.icon('fa fa-bolt');
- queryToolPanel.focus();
-
- // Listen on the panel closed event.
- queryToolPanel.on(wcDocker.EVENT.CLOSED, function() {
- $.ajax({
- url: url_for('datagrid.close', {'trans_id': res.data.gridTransId}),
- method: 'GET'
- });
- });
+ if (trans_obj.newBrowserTab) {
+ var newWin = window.open(baseUrl, '_blank');
- var openQueryToolURL = function(j) {
- // add spinner element
- $(j).data('embeddedFrame').$container.append(pgAdmin.DataGrid.spinner_el);
- setTimeout(function() {
- var frameInitialized = $(j).data('frameInitialized');
- if (frameInitialized) {
- var frame = $(j).data('embeddedFrame');
- if (frame) {
- frame.openURL(baseUrl);
- frame.$container.find('.wcLoadingContainer').delay(1000).hide(1);
- }
- } else {
- openQueryToolURL(j);
- }
- }, 100);
- };
+ // add a load listener to the window so that the title gets changed on page load
+ newWin.addEventListener("load", function() {
+ newWin.document.title = panel_title;
+ });
+ } else {
+ /* On successfully initialization find the dashboard panel,
+ * create new panel and add it to the dashboard panel.
+ */
+ var propertiesPanel = pgBrowser.docker.findPanels('properties');
+ var queryToolPanel = pgBrowser.docker.addPanel('frm_datagrid', wcDocker.DOCK.STACKED, propertiesPanel[0]);
+
+ // Set panel title and icon
+ queryToolPanel.title('<span title="'+panel_title+'">'+panel_title+'</span>');
+ queryToolPanel.icon('fa fa-bolt');
+ queryToolPanel.focus();
+
+ // Listen on the panel closed event.
+ queryToolPanel.on(wcDocker.EVENT.CLOSED, function() {
+ $.ajax({
+ url: url_for('datagrid.close', {'trans_id': trans_obj.gridTransId}),
+ method: 'GET'
+ });
+ });
- openQueryToolURL(queryToolPanel);
- }
- },
- error: function(e) {
- alertify.alert(
- gettext("Query Tool Initialize Error")
- );
- }
- });
+ var openQueryToolURL = function(j) {
+ // add spinner element
+ $(j).data('embeddedFrame').$container.append(pgAdmin.DataGrid.spinner_el);
+ setTimeout(function() {
+ var frameInitialized = $(j).data('frameInitialized');
+ if (frameInitialized) {
+ var frame = $(j).data('embeddedFrame');
+ if (frame) {
+ frame.openURL(baseUrl);
+ frame.$container.find('.wcLoadingContainer').delay(1000).hide(1);
+ }
+ } else {
+ openQueryToolURL(j);
+ }
+ }, 100);
+ };
+
+ openQueryToolURL(queryToolPanel);
+ }
}
- };
+ },
+ Backbone.Events);
return pgAdmin.DataGrid;
});
diff --git a/web/pgadmin/tools/datagrid/templates/datagrid/index.html b/web/pgadmin/tools/datagrid/templates/datagrid/index.html
index ff4368d..427d51f 100644
--- a/web/pgadmin/tools/datagrid/templates/datagrid/index.html
+++ b/web/pgadmin/tools/datagrid/templates/datagrid/index.html
@@ -337,38 +337,14 @@
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({{ is_query_tool }}, "{{ editor_title }}",
- script_sql, {{ is_new_browser_tab }}, "{{ server_type }}", {{ prompt_save_changes }});
+ script_type_url, {{ is_new_browser_tab }}, "{{ server_type }}", {{ prompt_save_changes }}, {{ url_params|safe}});
+
});
{% endblock %}
diff --git a/web/pgadmin/tools/sqleditor/__init__.py b/web/pgadmin/tools/sqleditor/__init__.py
index d2b5f2e..4215ea9 100644
--- a/web/pgadmin/tools/sqleditor/__init__.py
+++ b/web/pgadmin/tools/sqleditor/__init__.py
@@ -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
@@ -77,7 +79,6 @@ class SqlEditorModule(PgAdminModule):
'when': None
}]
-
def get_panels(self):
return []
@@ -363,6 +364,12 @@ def check_transaction_status(trans_id):
Returns: status and connection object
"""
+
+ if 'gridData' not in session:
+ return False, gettext(
+ 'Transaction ID not found in the session.'
+ ), None, None, None
+
grid_data = session['gridData']
# Return from the function if transaction id not found
@@ -381,7 +388,10 @@ def check_transaction_status(trans_id):
conn = manager.connection(did=trans_obj.did, conn_id=trans_obj.conn_id,
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():
@@ -408,12 +418,23 @@ def start_view_data(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)
+
# 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():
@@ -435,7 +456,10 @@ def start_view_data(trans_id):
pk_names, primary_keys = trans_obj.get_primary_keys(default_conn)
# Fetch OIDs status
- has_oids = trans_obj.has_oids(default_conn)
+ if trans_obj.object_type == 'table':
+ has_oids = trans_obj.has_oids(default_conn)
+ else:
+ has_oids = False
# Fetch the applied filter.
filter_applied = trans_obj.is_filter_applied()
@@ -495,16 +519,20 @@ def start_query_tool(trans_id):
else:
sql = request.args or request.form
+ 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.'),
- '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
@@ -529,13 +557,17 @@ def start_query_tool(trans_id):
conn = manager.connection(did=trans_obj.did, conn_id=conn_id,
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():
status, msg = conn.connect()
if not status:
+ current_app.logger.error(msg)
return internal_server_error(errormsg=str(msg))
if conn.connected():
@@ -602,9 +634,16 @@ def preferences(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:
- # Call the set_auto_commit and set_auto_rollback method of transaction object
+ # Call the set_auto_commit and set_auto_rollback method of
+ # transaction object
trans_obj.set_auto_commit(blueprint.auto_commit.get())
trans_obj.set_auto_rollback(blueprint.auto_rollback.get())
@@ -668,6 +707,12 @@ 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)
if not status:
@@ -846,6 +891,12 @@ 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:
@@ -959,6 +1010,12 @@ 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:
@@ -1017,6 +1074,11 @@ 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:
@@ -1047,6 +1109,12 @@ 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:
@@ -1082,6 +1150,12 @@ 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:
@@ -1128,6 +1202,11 @@ 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:
@@ -1171,6 +1250,12 @@ 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:
@@ -1208,6 +1293,12 @@ 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:
@@ -1240,15 +1331,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
@@ -1310,6 +1406,12 @@ 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:
@@ -1340,6 +1442,12 @@ 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:
@@ -1381,6 +1489,12 @@ 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:
@@ -1429,6 +1543,12 @@ 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:
diff --git a/web/pgadmin/tools/sqleditor/command.py b/web/pgadmin/tools/sqleditor/command.py
index 70db0c9..919c4dc 100644
--- a/web/pgadmin/tools/sqleditor/command.py
+++ b/web/pgadmin/tools/sqleditor/command.py
@@ -103,7 +103,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
diff --git a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
index dbc416e..2154962 100644
--- a/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
+++ b/web/pgadmin/tools/sqleditor/static/js/sqleditor.js
@@ -17,18 +17,19 @@ define('tools.querytool', [
'react', 'react-dom',
'sources/sqleditor/keyboard_shortcuts',
'sources/sqleditor/query_tool_actions',
- 'sources/../bundle/slickgrid',
+ 'pgadmin.datagrid',
+ 'sources/../bundle/slickgrid',
'pgadmin.file_manager',
'backgrid.sizeable.columns',
'slick.pgadmin.formatters',
'slick.pgadmin.editors',
- 'pgadmin.browser'
+ 'pgadmin.browser',
+ 'pgadmin.tools.user_management'
], function(
babelPollyfill,gettext, url_for, $, _, S, alertify, pgAdmin, Backbone, codemirror,
pgExplain, GridSelector, ActiveCellCapture, clipboard, copyData, RangeSelectionHelper, handleQueryOutputKeyboardEvent,
XCellSelectionModel, setStagedRows, SqlEditorUtils, HistoryBundle, queryHistory, React, ReactDOM,
- keyboardShortcuts
-, queryToolActions) {
+ keyboardShortcuts, queryToolActions, Datagrid) {
/* Return back, this has been called more than once */
if (pgAdmin.SqlEditor)
return pgAdmin.SqlEditor;
@@ -41,6 +42,11 @@ define('tools.querytool', [
var is_query_running = false;
+ var is_new_transaction_required = function(xhr) {
+ return xhr.status == 404 && xhr.responseJSON &&
+ xhr.responseJSON.info &&
+ xhr.responseJSON.info == 'DATAGRID_TRANSACTION_REQUIRED'
+ }
// Defining Backbone view for the sql grid.
var SQLEditorView = Backbone.View.extend({
initialize: function (opts) {
@@ -398,6 +404,14 @@ define('tools.querytool', [
from: {line: self.current_line, ch: start},
to: {line: self.current_line, ch: end}
});
+ },
+ error:function(e) {
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ return pgAdmin.Browser.UserManagement.pga_login();
+ }
+ if(is_new_transaction_required(e)) {
+ return self.init_transaction();
+ }
}
});
}.bind(ctx)
@@ -1010,7 +1024,10 @@ define('tools.querytool', [
self.update_msg_history(false,
gettext('Not connected to the server or the connection to the server has been closed.')
);
- return;
+ }
+
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ pgAdmin.Browser.UserManagement.pga_login();
}
}
});
@@ -1580,14 +1597,128 @@ define('tools.querytool', [
Backbone.Events,
{
initialize: function (container, opts) {
+ self= this;
this.container = container;
+ if (!alertify.dlgGetServerPass) {
+ alertify.dialog('dlgGetServerPass', function factory() {
+ return {
+ main: function(
+ title, message
+ ) {
+ this.set('title', title);
+ this.setting('message',message);
+ },
+ setup:function() {
+ return {
+ buttons:[
+ {
+ text: gettext("OK"), key: 13, className: "btn btn-primary"
+ },
+ {
+ text: gettext("Cancel"), className: "btn btn-danger"
+ }
+ ],
+ focus: { element: '#password', select: true },
+ options: {
+ modal: 0, resizable: false, maximizable: false, pinnable: false
+ }
+ };
+ },
+ build:function() {},
+ settings:{
+ message: null
+ },
+ prepare:function() {
+ this.setContent(this.setting('message'));
+ },
+ callback: function(closeEvent) {
+ if (closeEvent.button.text == gettext("OK")) {
+ var passdata = $(this.elements.content).find('#frmPassword').serialize();
+ self.init_connection(false, passdata);
+ }
+ }
+ };
+ });
+ }
+ this.on("pgadmin-datagrid:transaction:created", function(trans_obj) {
+ self.transId = trans_obj.gridTransId;
+ if (self.is_query_tool) {
+ alertify.success(gettext('New SQL editor session created.'));
+ } else {
+ alertify.success(gettext('New Data grid session created.'));
+ }
+ });
+ pgBrowser.Events.on('pgadmin:user:logged-in', function() {
+ self.init_transaction();
+ });
+ },
+
+ init_transaction: function() {
+ var url_endpoint;
+ if (this.is_query_tool) {
+ url_endpoint = 'datagrid.initialize_query_tool';
+
+ // If database not present then use Maintenance database
+ // We will handle this at server side
+ if (this.url_params.did) {
+ url_endpoint = 'datagrid.initialize_query_tool_with_did';
+ }
+
+ } else {
+ url_endpoint = 'datagrid.initialize_datagrid';
+ }
+
+ var baseUrl = url_for(url_endpoint, this.url_params);
+
+ Datagrid.create_transaction(baseUrl, this, this.is_query_tool,
+ this.server_type, '', '', '');
},
+ handle_connection_lost: function(create_transaction) {
+ var self= this;
+ alertify.confirm(
+ gettext('Connection lost'),
+ gettext('Would you like to reconnect to the server?'),
+ function() {
+ self.init_connection(create_transaction);
+ }, function() {});
+ },
+
+ init_connection: function(create_transaction, passdata) {
+ var self = this;
+ $.post(url_for('NODE-server.connect_id', {'gid': this.url_params.sgid,
+ 'sid': this.url_params.sid}),
+ passdata)
+ .done(function(res) {
+ if (res.success == 1) {
+ alertify.success(res.info);
+ if (create_transaction) {
+ self.init_transaction();
+ }
+ }
+ })
+ .fail(function(xhr, status, error) {
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(xhr)) {
+ pgAdmin.Browser.UserManagement.pga_login();
+ } else {
+ if(xhr.responseJSON &&
+ xhr.responseJSON.result) {
+ alertify.dlgGetServerPass(gettext('Connect to Server'),
+ xhr.responseJSON.result);
+ } else {
+ alertify.dlgGetServerPass(gettext('Connect to Server'),
+ xhr.responseText);
+ }
+ }
+ });
+ },
/* This function is used to create instance of SQLEditorView,
* call the render method of the grid view to render the backgrid
* header and loading icon and start execution of the sql query.
*/
- start: function (is_query_tool, editor_title, script_sql, is_new_browser_tab, server_type, prompt_save_changes) {
+ start: function (is_query_tool, editor_title, script_type_url,
+ is_new_browser_tab, server_type, prompt_save_changes, url_params
+ ) {
var self = this;
self.is_query_tool = is_query_tool;
@@ -1603,6 +1734,8 @@ define('tools.querytool', [
self.close_on_save = false;
self.server_type = server_type;
self.prompt_save_changes = prompt_save_changes;
+ self.url_params = url_params;
+ self.script_type_url = script_type_url;
// We do not allow to call the start multiple times.
if (self.gridView)
@@ -1620,6 +1753,59 @@ define('tools.querytool', [
// Render the header
self.gridView.render();
+ if (self.is_query_tool) {
+ // Fetch the SQL for Scripts (eg: CREATE/UPDATE/DELETE/SELECT)
+ // Call AJAX only if script type url is present
+ if (script_type_url) {
+ $.ajax({
+ url: script_type_url,
+ type:'GET',
+ success: function(res) {
+ self.gridView.query_tool_obj.refresh();
+ if (res && res !== '') {
+ self.gridView.query_tool_obj.setValue(res);
+ }
+ self.init_events();
+ },
+ error: function(jqx) {
+ var msg = jqx.responseText;
+ self.init_events();
+
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ return pgAdmin.Browser.UserManagement.pga_login();
+ }
+
+ /* 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(gettext("Error fetching SQL for script: %s.")).sprintf(msg).value()
+ );
+ }
+ });
+ } else {
+ self.init_events();
+ }
+ }
+ else {
+ // Disable codemirror by setting cursor to nocursor and background to dark.
+ self.init_events();
+ self.gridView.query_tool_obj.setOption("readOnly", 'nocursor');
+ var cm = self.gridView.query_tool_obj.getWrapperElement();
+ if (cm) {
+ cm.className += ' bg-gray-1 opacity-5';
+ }
+ self.disable_tool_buttons(true);
+ self.execute_data_query();
+ }
+ },
+
+ init_events: function() {
+ var self = this;
// Listen to the file manager button events
pgAdmin.Browser.Events.on('pgadmin-storage:finish_btn:select_file', self._select_file_handler, self);
pgAdmin.Browser.Events.on('pgadmin-storage:finish_btn:create_file', self._save_file_handler, self);
@@ -1653,23 +1839,6 @@ define('tools.querytool', [
// Indentation related
self.on('pgadmin-sqleditor:indent_selected_code', self._indent_selected_code, self);
self.on('pgadmin-sqleditor:unindent_selected_code', self._unindent_selected_code, self);
-
- if (self.is_query_tool) {
- self.gridView.query_tool_obj.refresh();
- if (script_sql && script_sql !== '') {
- self.gridView.query_tool_obj.setValue(script_sql);
- }
- }
- else {
- // Disable codemirror by setting cursor to nocursor and background to dark.
- self.gridView.query_tool_obj.setOption("readOnly", 'nocursor');
- var cm = self.gridView.query_tool_obj.getWrapperElement();
- if (cm) {
- cm.className += ' bg-gray-1 opacity-5';
- }
- self.disable_tool_buttons(true);
- self.execute_data_query();
- }
},
// This function checks if there is any dirty data in the grid before
@@ -1778,11 +1947,27 @@ define('tools.querytool', [
);
return;
}
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ pgAdmin.Browser.UserManagement.pga_login();
+ }
+
+ if(is_new_transaction_required(e)) {
+ self.init_transaction();
+ }
var msg = e.responseText;
- if (e.responseJSON != undefined &&
- e.responseJSON.errormsg != undefined)
- msg = e.responseJSON.errormsg;
+ if (e.responseJSON != undefined) {
+ if(e.responseJSON.errormsg != undefined) {
+ msg = e.responseJSON.errormsg;
+ }
+
+ if(e.status == 503 && e.responseJSON.info != undefined &&
+ e.responseJSON.info == "CONNECTION_LOST") {
+ setTimeout(function() {
+ self.handle_connection_lost();
+ });
+ }
+ }
self.update_msg_history(false, msg);
}
@@ -1886,6 +2071,10 @@ define('tools.querytool', [
return;
}
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ return pgAdmin.Browser.UserManagement.pga_login();
+ }
+
var msg = e.responseText;
if (e.responseJSON != undefined &&
e.responseJSON.errormsg != undefined)
@@ -2512,6 +2701,10 @@ define('tools.querytool', [
return;
}
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ pgAdmin.Browser.UserManagement.pga_login();
+ }
+
var msg = e.responseText;
if (e.responseJSON != undefined &&
e.responseJSON.errormsg != undefined)
@@ -2653,9 +2846,13 @@ define('tools.querytool', [
self.is_query_changed = false;
},
error: function(e) {
+ self.trigger('pgadmin-sqleditor:loading-icon:hide');
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ return pgAdmin.Browser.UserManagement.pga_login();
+ }
+
var errmsg = $.parseJSON(e.responseText).errormsg;
alertify.error(errmsg);
- self.trigger('pgadmin-sqleditor:loading-icon:hide');
// hide cursor
$busy_icon_div.removeClass('show_progress');
}
@@ -2699,6 +2896,9 @@ define('tools.querytool', [
},
error: function (e) {
self.trigger('pgadmin-sqleditor:loading-icon:hide');
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ return pgAdmin.Browser.UserManagement.pga_login();
+ }
var errmsg = $.parseJSON(e.responseText).errormsg;
setTimeout(
@@ -2806,6 +3006,14 @@ define('tools.querytool', [
error: function (e) {
self.trigger('pgadmin-sqleditor:loading-icon:hide');
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ return pgAdmin.Browser.UserManagement.pga_login();
+ }
+
+ if(is_new_transaction_required(e)) {
+ return self.init_transaction();
+ }
+
var msg;
if (e.readyState == 0) {
msg =
@@ -2874,6 +3082,14 @@ define('tools.querytool', [
},
error: function (e) {
self.trigger('pgadmin-sqleditor:loading-icon:hide');
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ return pgAdmin.Browser.UserManagement.pga_login();
+ }
+
+ if(is_new_transaction_required(e)) {
+ return self.init_transaction();
+ }
+
setTimeout(
function () {
if (e.readyState == 0) {
@@ -2944,6 +3160,13 @@ define('tools.querytool', [
},
error: function (e) {
self.trigger('pgadmin-sqleditor:loading-icon:hide');
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ return pgAdmin.Browser.UserManagement.pga_login();
+ }
+
+ if(is_new_transaction_required(e)) {
+ return self.init_transaction();
+ }
setTimeout(
function () {
@@ -2995,6 +3218,14 @@ define('tools.querytool', [
},
error: function (e) {
self.trigger('pgadmin-sqleditor:loading-icon:hide');
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ return pgAdmin.Browser.UserManagement.pga_login();
+ }
+
+ if(is_new_transaction_required(e)) {
+ return self.init_transaction();
+ }
+
setTimeout(
function () {
if (e.readyState == 0) {
@@ -3050,6 +3281,14 @@ define('tools.querytool', [
},
error: function (e) {
self.trigger('pgadmin-sqleditor:loading-icon:hide');
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ return pgAdmin.Browser.UserManagement.pga_login();
+ }
+
+ if(is_new_transaction_required(e)) {
+ return self.init_transaction();
+ }
+
setTimeout(
function () {
if (e.readyState == 0) {
@@ -3184,6 +3423,14 @@ define('tools.querytool', [
},
error: function (e) {
self.trigger('pgadmin-sqleditor:loading-icon:hide');
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ return pgAdmin.Browser.UserManagement.pga_login();
+ }
+
+ if(is_new_transaction_required(e)) {
+ return self.init_transaction();
+ }
+
setTimeout(
function () {
if (e.readyState == 0) {
@@ -3306,11 +3553,26 @@ define('tools.querytool', [
return;
}
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ pgAdmin.Browser.UserManagement.pga_login();
+ }
+
+ if(is_new_transaction_required(e)) {
+ self.init_transaction();
+ }
var msg = e.responseText;
- if (e.responseJSON != undefined &&
- e.responseJSON.errormsg != undefined)
- msg = e.responseJSON.errormsg;
+ if (e.responseJSON != undefined) {
+ if(e.responseJSON.errormsg != undefined) {
+ msg = e.responseJSON.errormsg;
+ }
+ if(e.status == 503 && e.responseJSON.info != undefined &&
+ e.responseJSON.info == "CONNECTION_LOST") {
+ setTimeout(function() {
+ self.handle_connection_lost();
+ });
+ }
+ }
self.update_msg_history(false, msg);
}
});
@@ -3404,6 +3666,10 @@ define('tools.querytool', [
return;
}
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ return pgAdmin.Browser.UserManagement.pga_login();
+ }
+
var msg = e.responseText;
if (e.responseJSON != undefined &&
e.responseJSON.errormsg != undefined)
@@ -3453,6 +3719,10 @@ define('tools.querytool', [
return;
}
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ return pgAdmin.Browser.UserManagement.pga_login();
+ }
+
var msg = e.responseText;
if (e.responseJSON != undefined &&
e.responseJSON.errormsg != undefined)
@@ -3474,7 +3744,7 @@ define('tools.querytool', [
auto_commit = false;
}
- // Make ajax call to change the limit
+ // Make ajax call to toggle auto commit
$.ajax({
url: url_for('sqleditor.auto_commit', {'trans_id': self.transId}),
method: 'POST',
@@ -3492,6 +3762,14 @@ define('tools.querytool', [
return;
}
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ return pgAdmin.Browser.UserManagement.pga_login();
+ }
+
+ if(is_new_transaction_required(e)) {
+ return self.init_transaction();
+ }
+
var msg = e.responseText;
if (e.responseJSON != undefined &&
e.responseJSON.errormsg != undefined)
@@ -3532,6 +3810,15 @@ define('tools.querytool', [
}
},
error: function (e) {
+
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ return pgAdmin.Browser.UserManagement.pga_login();
+ }
+
+ if(is_new_transaction_required(e)) {
+ return self.init_transaction();
+ }
+
alertify.alert(gettext('Explain options error'),
gettext("Error occurred while setting verbose option in explain.")
);
@@ -3570,6 +3857,14 @@ define('tools.querytool', [
}
},
error: function (e) {
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ return pgAdmin.Browser.UserManagement.pga_login();
+ }
+
+ if(is_new_transaction_required(e)) {
+ return self.init_transaction();
+ }
+
alertify.alert(gettext('Explain options error'),
gettext("Error occurred while setting costs option in explain.")
);
@@ -3607,6 +3902,14 @@ define('tools.querytool', [
}
},
error: function (e) {
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ return pgAdmin.Browser.UserManagement.pga_login();
+ }
+
+ if(is_new_transaction_required(e)) {
+ return self.init_transaction();
+ }
+
alertify.alert(gettext('Explain options error'),
gettext("Error occurred while setting buffers option in explain.")
);
@@ -3643,6 +3946,14 @@ define('tools.querytool', [
}
},
error: function (e) {
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ return pgAdmin.Browser.UserManagement.pga_login();
+ }
+
+ if(is_new_transaction_required(e)) {
+ return self.init_transaction();
+ }
+
alertify.alert(gettext('Explain options error'),
gettext("Error occurred while setting timing option in explain.")
);
@@ -3739,6 +4050,9 @@ define('tools.querytool', [
}
},
error: function (e) {
+ if (pgAdmin.Browser.UserManagement.is_pga_login_required(e)) {
+ return pgAdmin.Browser.UserManagement.pga_login();
+ }
updateUI();
alertify.alert(gettext('Get Preferences error'),
gettext("Error occurred while getting query tool options.")
@@ -3748,6 +4062,8 @@ define('tools.querytool', [
},
close: function () {
var self = this;
+
+ pgBrowser.Events.off('pgadmin:user:logged-in', this.init_transaction);
_.each(window.top.pgAdmin.Browser.docker.findPanels('frm_datagrid'), function (panel) {
if (panel.isVisible()) {
window.onbeforeunload = null;
diff --git a/web/pgadmin/tools/user_management/__init__.py b/web/pgadmin/tools/user_management/__init__.py
index 77c1b4e..2cf4dfb 100644
--- a/web/pgadmin/tools/user_management/__init__.py
+++ b/web/pgadmin/tools/user_management/__init__.py
@@ -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
]
diff --git a/web/pgadmin/tools/user_management/static/js/user_management.js b/web/pgadmin/tools/user_management/static/js/user_management.js
index d51d6b4..a55594b 100644
--- a/web/pgadmin/tools/user_management/static/js/user_management.js
+++ b/web/pgadmin/tools/user_management/static/js/user_management.js
@@ -122,6 +122,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(action, item, params) {
if (!userInfo['is_admin']) return;
diff --git a/web/pgadmin/utils/exception.py b/web/pgadmin/utils/exception.py
index dab0d09..04a7d4b 100644
--- a/web/pgadmin/utils/exception.py
+++ b/web/pgadmin/utils/exception.py
@@ -28,7 +28,7 @@ class ConnectionLost(HTTPException):
@property
def name(self):
- return HTTP_STATUS_CODES.get(505, 'Service Unavailable')
+ return HTTP_STATUS_CODES.get(503, 'Service Unavailable')
def get_response(self, environ=None):
return service_unavailable(
diff --git a/web/pgadmin/utils/session.py b/web/pgadmin/utils/session.py
index 8f2ae61..84e7471 100644
--- a/web/pgadmin/utils/session.py
+++ b/web/pgadmin/utils/session.py
@@ -24,6 +24,9 @@ import random
import string
import time
from uuid import uuid4
+from flask import current_app, request, flash, redirect
+from flask_login import login_url
+from pgadmin.utils.ajax import make_json_response
try:
from cPickle import dump, load
@@ -298,3 +301,32 @@ def create_session_interface(app, skip_paths=[]):
1000
), skip_paths,
datetime.timedelta(days=1))
+
+
+def pga_unauthorised():
+
+ lm = current_app.login_manager
+ login_message = None
+
+ if lm.login_message:
+ if lm.localize_callback is not None:
+ login_message = lm.localize_callback(lm.login_message)
+ else:
+ login_message = lm.login_message
+
+ if not lm.login_view or request.is_xhr:
+ # Only 401 is not enough to distinguish pgAdmin login is required.
+ # There are other cases when we return 401. For eg. wrong password
+ # supplied while connecting to server.
+ # So send additional 'info' message.
+ return make_json_response(
+ status=401,
+ success=0,
+ errormsg=login_message,
+ info='PGADMIN_LOGIN_REQUIRED'
+ )
+
+ if login_message:
+ flash(login_message, category=lm.login_message_category)
+
+ return redirect(login_url(lm.login_view, request.url))