From f12d981a9d24d9d3725f7d51d99706fa211c7938 Mon Sep 17 00:00:00 2001 From: Ashesh Vashi Date: Mon, 29 Aug 2016 11:52:50 +0530 Subject: [PATCH] Handling the bad/lost connection of a database server. Made backend changes for: * Taking care of the connection status in the psycopg2 driver. And, when the connection is lost, it throws a exception with 503 http status message, and connection lost information in it. * Allowing the flask application to propagate the exceptions even in the release mode. * Utilising the existing password (while reconnection, if not disconnected explicitly). * Introduced a new ajax response message 'service_unavailable' (http status code: 503), which suggests temporary service unavailable. Client (front-end) changes: * To handle the connection lost of a database server for different operations by generating proper events, and handle them properly. Removed the connection status check code from different nodes, so that - it generates the proper exception, when accessing the non-alive connection. Fixes #1387 --- web/pgadmin/__init__.py | 1 + web/pgadmin/browser/collection.py | 3 +- .../browser/server_groups/servers/__init__.py | 57 ++- .../servers/databases/__init__.py | 332 +++++++--------- .../servers/databases/casts/__init__.py | 48 ++- .../databases/event_triggers/__init__.py | 21 +- .../foreign_data_wrappers/__init__.py | 18 +- .../foreign_servers/__init__.py | 19 +- .../foreign_servers/user_mapping/__init__.py | 19 +- .../servers/databases/languages/__init__.py | 19 +- .../servers/databases/schemas/__init__.py | 14 +- .../schemas/catalog_objects/__init__.py | 13 +- .../catalog_objects/columns/__init__.py | 13 +- .../databases/schemas/collations/__init__.py | 17 +- .../databases/schemas/domains/__init__.py | 17 +- .../domains/domain_constraints/__init__.py | 20 +- .../schemas/foreign_tables/__init__.py | 14 +- .../schemas/fts_configurations/__init__.py | 25 +- .../schemas/fts_dictionaries/__init__.py | 21 +- .../databases/schemas/fts_parser/__init__.py | 20 +- .../schemas/fts_templates/__init__.py | 35 +- .../databases/schemas/functions/__init__.py | 24 +- .../databases/schemas/sequences/__init__.py | 43 +- .../databases/schemas/tables/__init__.py | 29 +- .../schemas/tables/column/__init__.py | 17 +- .../constraints/check_constraint/__init__.py | 14 +- .../exclusion_constraint/__init__.py | 16 +- .../constraints/foreign_key/__init__.py | 50 +-- .../constraints/index_constraint/__init__.py | 15 +- .../templates/constraints/js/constraints.js | 4 +- .../schemas/tables/indexes/__init__.py | 26 +- .../schemas/tables/rules/__init__.py | 26 +- .../templates/foreign_key/sql/nodes.sql | 2 +- .../schemas/tables/triggers/__init__.py | 31 +- .../databases/schemas/types/__init__.py | 19 +- .../databases/schemas/views/__init__.py | 15 +- .../templates/databases/js/databases.js | 195 ++++++--- .../servers/templates/servers/servers.js | 374 ++++++++++++------ .../templates/servers/sql/9.1_plus/stats.sql | 40 +- .../templates/servers/sql/9.2_plus/stats.sql | 40 +- .../browser/templates/browser/js/browser.js | 6 +- .../templates/browser/js/collection.js | 22 +- .../browser/templates/browser/js/messages.js | 11 +- .../browser/templates/browser/js/node.js | 63 ++- web/pgadmin/misc/depends/static/js/depends.js | 32 +- web/pgadmin/misc/sql/static/js/sql.js | 29 +- .../misc/statistics/static/js/statistics.js | 29 +- .../static/js/alertifyjs/pgadmin.defaults.js | 143 ++++++- web/pgadmin/utils/ajax.py | 28 +- web/pgadmin/utils/driver/psycopg2/__init__.py | 74 +++- web/pgadmin/utils/exception.py | 42 ++ 51 files changed, 1235 insertions(+), 970 deletions(-) create mode 100644 web/pgadmin/utils/exception.py diff --git a/web/pgadmin/__init__.py b/web/pgadmin/__init__.py index d4c174a87..538bb3a17 100644 --- a/web/pgadmin/__init__.py +++ b/web/pgadmin/__init__.py @@ -124,6 +124,7 @@ def create_app(app_name=config.APP_NAME): # Removes unwanted whitespace from render_template function app.jinja_env.trim_blocks = True app.config.from_object(config) + app.config.update(dict(PROPAGATE_EXCEPTIONS=True)) ########################################################################## # Setup session management diff --git a/web/pgadmin/browser/collection.py b/web/pgadmin/browser/collection.py index 97f58b6b1..003184ef3 100644 --- a/web/pgadmin/browser/collection.py +++ b/web/pgadmin/browser/collection.py @@ -85,7 +85,8 @@ class CollectionNodeModule(PgAdminModule, PGChildModule): "_type": 'coll-%s' % (self.node_type), "_id": parent_id, "_pid": parent_id, - "module": 'pgadmin.node.%s' % self.node_type + "module": 'pgadmin.node.%s' % self.node_type, + "subnodes": sorted([m.node_type for m in self.submodules]) } for key in kwargs: diff --git a/web/pgadmin/browser/server_groups/servers/__init__.py b/web/pgadmin/browser/server_groups/servers/__init__.py index 181cf0c22..f5caf94a5 100644 --- a/web/pgadmin/browser/server_groups/servers/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/__init__.py @@ -712,8 +712,16 @@ class ServerNode(PGChildNodeView): from pgadmin.utils.driver import get_driver manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid) conn = manager.connection() + res = conn.connected() - return make_json_response(data={'connected': conn.connected()}) + if res: + from pgadmin.utils.exception import ConnectionLost + try: + conn.execute_scalar('SELECT 1') + except ConnectionLost: + res = False + + return make_json_response(data={'connected': res}) def connect(self, gid, sid): """ @@ -752,8 +760,14 @@ class ServerNode(PGChildNodeView): password = None save_password = False + # Connect the Server + from pgadmin.utils.driver import get_driver + manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid) + conn = manager.connection() + if 'password' not in data: - if server.password is None: + conn_passwd = getattr(conn, 'password', None) + if conn_passwd is None and server.password is None: # Return the password template in case password is not # provided, or password has not been saved earlier. return make_json_response( @@ -772,19 +786,15 @@ class ServerNode(PGChildNodeView): data['save_password'] if password and \ 'save_password' in data else False - # Encrypt the password before saving with user's login password key. - try: - password = encrypt(password, user.password) \ - if password is not None else server.password - except Exception as e: - current_app.logger.exception(e) - return internal_server_error(errormsg=e.message) - - # Connect the Server - from pgadmin.utils.driver import get_driver - manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid) - conn = manager.connection() + # Encrypt the password before saving with user's login password key. + try: + password = encrypt(password, user.password) \ + if password is not None else server.password + except Exception as e: + current_app.logger.exception(e) + return internal_server_error(errormsg=e.message) + status = True try: status, errmsg = conn.connect( password=password, @@ -792,13 +802,18 @@ class ServerNode(PGChildNodeView): ) except Exception as e: current_app.logger.exception(e) - # TODO:: - # Ask the password again (if existing password couldn't be - # descrypted) - if e.message: - return internal_server_error(errormsg=e.message) - else: - return internal_server_error(errormsg=str(e)) + + return make_json_response( + success=0, + status=401, + result=render_template( + 'servers/password.html', + server_label=server.name, + username=server.username, + errmsg=e.message if e.message else str(e), + _=gettext + ) + ) if not status: current_app.logger.error( diff --git a/web/pgadmin/browser/server_groups/servers/databases/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/__init__.py index 7e5758a92..1c69b0579 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/__init__.py @@ -24,7 +24,7 @@ from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \ from pgadmin.browser.utils import PGChildNodeView from pgadmin.utils.ajax import make_json_response, \ make_response as ajax_response, internal_server_error, unauthorized -from pgadmin.utils.ajax import precondition_required, gone +from pgadmin.utils.ajax import gone from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -133,11 +133,6 @@ class DatabaseView(PGChildNodeView): self.conn = self.manager.connection(did=kwargs['did']) else: self.conn = self.manager.connection() - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - _("Connection to the server has been lost!") - ) ver = self.manager.version # we will set template path for sql scripts @@ -147,6 +142,7 @@ class DatabaseView(PGChildNodeView): self.template_path = 'databases/sql/9.2_plus' else: self.template_path = 'databases/sql/9.1_plus' + return f(self, *args, **kwargs) return wrapped @@ -156,7 +152,9 @@ class DatabaseView(PGChildNodeView): @check_precondition(action="list") def list(self, gid, sid): last_system_oid = 0 if self.blueprint.show_system_objects else \ - (self.manager.db_info[self.manager.did])['datlastsysoid'] + (self.manager.db_info[self.manager.did])['datlastsysoid'] \ + if self.manager.db_info is not None and \ + self.manager.did in self.manager.db_info else 0 SQL = render_template( "/".join([self.template_path, 'properties.sql']), conn=self.conn, last_system_oid=last_system_oid @@ -175,8 +173,10 @@ class DatabaseView(PGChildNodeView): res = [] last_system_oid = 0 if self.blueprint.show_system_objects or \ show_system_templates else ( - self.manager.db_info[self.manager.did] - )['datlastsysoid'] + (self.manager.db_info[self.manager.did])['datlastsysoid'] \ + if self.manager.db_info is not None and \ + self.manager.did in self.manager.db_info else 0 + ) SQL = render_template( "/".join([self.template_path, 'nodes.sql']), @@ -403,26 +403,22 @@ class DatabaseView(PGChildNodeView): This function to return list of avialable encodings """ res = [{'label': '', 'value': ''}] - try: - SQL = render_template( - "/".join([self.template_path, 'get_encodings.sql']) - ) - status, rset = self.conn.execute_dict(SQL) - if not status: - return internal_server_error(errormsg=res) + SQL = render_template( + "/".join([self.template_path, 'get_encodings.sql']) + ) + status, rset = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=rset) - for row in rset['rows']: - res.append( - {'label': row['encoding'], 'value': row['encoding']} - ) - - return make_json_response( - data=res, - status=200 + for row in rset['rows']: + res.append( + {'label': row['encoding'], 'value': row['encoding']} ) - except Exception as e: - return internal_server_error(errormsg=str(e)) + return make_json_response( + data=res, + status=200 + ) @check_precondition(action="get_ctypes") def get_ctypes(self, gid, sid, did=None): @@ -435,25 +431,21 @@ class DatabaseView(PGChildNodeView): res.append( {'label': val, 'value': val} ) - try: - SQL = render_template( - "/".join([self.template_path, 'get_ctypes.sql']) - ) - status, rset = self.conn.execute_dict(SQL) - if not status: - return internal_server_error(errormsg=res) + SQL = render_template( + "/".join([self.template_path, 'get_ctypes.sql']) + ) + status, rset = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=rset) - for row in rset['rows']: - if row['cname'] not in default_list: - res.append({'label': row['cname'], 'value': row['cname']}) + for row in rset['rows']: + if row['cname'] not in default_list: + res.append({'label': row['cname'], 'value': row['cname']}) - return make_json_response( - data=res, - status=200 - ) - - except Exception as e: - return internal_server_error(errormsg=str(e)) + return make_json_response( + data=res, + status=200 + ) @check_precondition(action="create") def create(self, gid, sid): @@ -475,64 +467,56 @@ class DatabaseView(PGChildNodeView): "Could not find the required parameter (%s)." % arg ) ) - try: - # The below SQL will execute CREATE DDL only - SQL = render_template( - "/".join([self.template_path, 'create.sql']), - data=data, conn=self.conn - ) + # The below SQL will execute CREATE DDL only + SQL = render_template( + "/".join([self.template_path, 'create.sql']), + data=data, conn=self.conn + ) + status, msg = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=msg) + + if 'datacl' in data: + data['datacl'] = parse_priv_to_db(data['datacl'], 'DATABASE') + + # The below SQL will execute rest DMLs because we can not execute CREATE with any other + SQL = render_template( + "/".join([self.template_path, 'grant.sql']), + data=data, conn=self.conn + ) + SQL = SQL.strip('\n').strip(' ') + if SQL and SQL != "": status, msg = self.conn.execute_scalar(SQL) if not status: return internal_server_error(errormsg=msg) - if 'datacl' in data: - data['datacl'] = parse_priv_to_db(data['datacl'], 'DATABASE') + # We need oid of newly created database + SQL = render_template( + "/".join([self.template_path, 'properties.sql']), + name=data['name'], conn=self.conn, last_system_oid=0 + ) + SQL = SQL.strip('\n').strip(' ') + if SQL and SQL != "": + status, res = self.conn.execute_dict(SQL) + if not status: + return internal_server_error(errormsg=res) - # The below SQL will execute rest DMLs because we can not execute CREATE with any other - SQL = render_template( - "/".join([self.template_path, 'grant.sql']), - data=data, conn=self.conn - ) - SQL = SQL.strip('\n').strip(' ') - if SQL and SQL != "": - status, msg = self.conn.execute_scalar(SQL) - if not status: - return internal_server_error(errormsg=msg) - - # We need oid of newly created database - SQL = render_template( - "/".join([self.template_path, 'properties.sql']), - name=data['name'], conn=self.conn, last_system_oid=0 - ) - SQL = SQL.strip('\n').strip(' ') - if SQL and SQL != "": - status, res = self.conn.execute_dict(SQL) - if not status: - return internal_server_error(errormsg=res) - - response = res['rows'][0] - - return jsonify( - node=self.blueprint.generate_browser_node( - response['did'], - sid, - response['name'], - icon="icon-database-not-connected", - connected=False, - tablespace=response['default_tablespace'], - allowConn=True, - canCreate=response['cancreate'], - canDisconn=True, - canDrop=True - ) - ) - - except Exception as e: - return make_json_response( - status=410, - success=0, - errormsg=e.message + response = res['rows'][0] + + return jsonify( + node=self.blueprint.generate_browser_node( + response['did'], + sid, + response['name'], + icon="icon-database-not-connected", + connected=False, + tablespace=response['default_tablespace'], + allowConn=True, + canCreate=response['cancreate'], + canDisconn=True, + canDrop=True ) + ) @check_precondition(action="update") def update(self, gid, sid, did): @@ -563,91 +547,79 @@ class DatabaseView(PGChildNodeView): if 'name' not in data: data['name'] = data['old_name'] - try: - status = self.manager.release(did=did) - conn = self.manager.connection() - for action in ["rename_database", "tablespace"]: - SQL = self.get_offline_sql(gid, sid, data, did, action) - SQL = SQL.strip('\n').strip(' ') - if SQL and SQL != "": - status, msg = conn.execute_scalar(SQL) - if not status: - return internal_server_error(errormsg=msg) - - info = "Database updated." - - self.conn = self.manager.connection(database=data['name'], auto_reconnect=True) - status, errmsg = self.conn.connect() - - SQL = self.get_online_sql(gid, sid, data, did) + status = self.manager.release(did=did) + conn = self.manager.connection() + for action in ["rename_database", "tablespace"]: + SQL = self.get_offline_sql(gid, sid, data, did, action) SQL = SQL.strip('\n').strip(' ') if SQL and SQL != "": - status, msg = self.conn.execute_scalar(SQL) + status, msg = conn.execute_scalar(SQL) if not status: return internal_server_error(errormsg=msg) info = "Database updated." - return make_json_response( - success=1, - info=info, - data={ - 'id': did, - 'sid': sid, - 'gid': gid, - } - ) + self.conn = self.manager.connection(database=data['name'], auto_reconnect=True) + status, errmsg = self.conn.connect() - except Exception as e: - return make_json_response( - status=410, - success=0, - errormsg=str(e) - ) + SQL = self.get_online_sql(gid, sid, data, did) + SQL = SQL.strip('\n').strip(' ') + if SQL and SQL != "": + status, msg = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=msg) + + info = "Database updated." + + return make_json_response( + success=1, + info=info, + data={ + 'id': did, + 'sid': sid, + 'gid': gid, + } + ) @check_precondition(action="drop") def delete(self, gid, sid, did): """Delete the database.""" - try: - default_conn = self.manager.connection() - SQL = render_template( - "/".join([self.template_path, 'delete.sql']), - did=did, conn=self.conn - ) - status, res = default_conn.execute_scalar(SQL) - if not status: - return internal_server_error(errormsg=res) + default_conn = self.manager.connection() + SQL = render_template( + "/".join([self.template_path, 'delete.sql']), + did=did, conn=self.conn + ) + status, res = default_conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=res) - if res is None: - return make_json_response( - success=0, - errormsg=_( - 'Error: Object not found.' - ), - info=_( - 'The specified database could not be found.\n' - ) - ) - else: - - status = self.manager.release(did=did) - - SQL = render_template( - "/".join([self.template_path, 'delete.sql']), - datname=res, conn=self.conn - ) - - status, msg = default_conn.execute_scalar(SQL) - if not status: - # reconnect if database drop failed. - conn = self.manager.connection(did=did, auto_reconnect=True) - status, errmsg = conn.connect() - return internal_server_error(errormsg=msg) - - except Exception as e: + if res is None: return make_json_response( success=0, - errormsg=str(e)) + errormsg=_( + 'Error: Object not found.' + ), + info=_( + 'The specified database could not be found.\n' + ) + ) + else: + + status = self.manager.release(did=did) + + SQL = render_template( + "/".join([self.template_path, 'delete.sql']), + datname=res, conn=self.conn + ) + + status, msg = default_conn.execute_scalar(SQL) + if not status: + # reconnect if database drop failed. + conn = self.manager.connection(did=did, auto_reconnect=True) + status, errmsg = conn.connect() + + return internal_server_error(errormsg=msg) + return make_json_response(success=1) @@ -662,25 +634,18 @@ class DatabaseView(PGChildNodeView): data[k] = json.loads(v, encoding='utf-8') except ValueError: data[k] = v - try: - status, res = self.get_sql(gid, sid, data, did) + status, res = self.get_sql(gid, sid, data, did) - if not status: - return res + if not status: + return res - res = re.sub('\n{2,}', '\n\n', res) - SQL = res.strip('\n').strip(' ') + res = re.sub('\n{2,}', '\n\n', res) + SQL = res.strip('\n').strip(' ') - return make_json_response( - data=SQL, - status=200 - ) - except Exception as e: - current_app.logger.exception(e) - return make_json_response( - data=_("-- modified SQL"), - status=200 - ) + return make_json_response( + data=SQL, + status=200 + ) def get_sql(self, gid, sid, data, did=None): SQL = '' @@ -819,7 +784,10 @@ class DatabaseView(PGChildNodeView): server. """ last_system_oid = 0 if self.blueprint.show_system_objects else \ - (self.manager.db_info[self.manager.did])['datlastsysoid'] + (self.manager.db_info[self.manager.did])['datlastsysoid'] \ + if self.manager.db_info is not None and \ + self.manager.did in self.manager.db_info else 0 + status, res = self.conn.execute_dict( render_template( "/".join([self.template_path, 'stats.sql']), diff --git a/web/pgadmin/browser/server_groups/servers/databases/casts/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/casts/__init__.py index 86a7eca78..6be5d63da 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/casts/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/casts/__init__.py @@ -17,9 +17,8 @@ from flask import render_template, make_response, request, jsonify from flask_babel import gettext from pgadmin.browser.collection import CollectionNodeModule from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response, gone from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -201,17 +200,8 @@ class CastView(PGChildNodeView): self = args[0] self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(kwargs['sid']) self.conn = self.manager.connection(did=kwargs['did']) - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) - ver = self.manager.version - # we will set template path for sql scripts - if ver >= 90100: - self.template_path = 'cast/sql/9.1_plus' + # Set template path for the SQL scripts + self.template_path = 'cast/sql/9.1_plus' return f(*args, **kwargs) @@ -226,9 +216,13 @@ class CastView(PGChildNodeView): :param did: database id :return: """ + last_system_oid = 0 if self.blueprint.show_system_objects else \ + (self.manager.db_info[did])['datlastsysoid'] \ + if self.manager.db_info is not None and \ + did in self.manager.db_info else 0 sql = render_template( "/".join([self.template_path, 'properties.sql']), - datlastsysoid=self.manager.db_info[did]['datlastsysoid'], + datlastsysoid=last_system_oid, showsysobj=self.blueprint.show_system_objects ) status, res = self.conn.execute_dict(sql) @@ -255,9 +249,13 @@ class CastView(PGChildNodeView): :return: """ res = [] + last_system_oid = 0 if self.blueprint.show_system_objects else \ + (self.manager.db_info[did])['datlastsysoid'] \ + if self.manager.db_info is not None and \ + did in self.manager.db_info else 0 sql = render_template( "/".join([self.template_path, 'nodes.sql']), - datlastsysoid=self.manager.db_info[did]['datlastsysoid'], + datlastsysoid=last_system_oid, showsysobj=self.blueprint.show_system_objects ) status, rset = self.conn.execute_2darray(sql) @@ -313,17 +311,19 @@ class CastView(PGChildNodeView): :param cid: cast id :return: """ + last_system_oid = (self.manager.db_info[did])['datlastsysoid'] if \ + self.manager.db_info is not None and \ + did in self.manager.db_info else 0 sql = render_template( "/".join([self.template_path, 'properties.sql']), cid=cid, - datlastsysoid=self.manager.db_info[did]['datlastsysoid'], + datlastsysoid=last_system_oid, showsysobj=self.blueprint.show_system_objects ) status, res = self.conn.execute_dict(sql) if not status: return internal_server_error(errormsg=res) - result = res['rows'][0] return ajax_response( response=res['rows'][0], @@ -367,10 +367,14 @@ class CastView(PGChildNodeView): return internal_server_error(errormsg=res) # we need oid to to add object in tree at browser, below sql will gives the same + last_system_oid = 0 if self.blueprint.show_system_objects else \ + (self.manager.db_info[did])['datlastsysoid'] \ + if self.manager.db_info is not None and \ + did in self.manager.db_info else 0 sql = render_template("/".join([self.template_path, 'properties.sql']), srctyp=data['srctyp'], trgtyp=data['trgtyp'], - datlastsysoid=self.manager.db_info[did]['datlastsysoid'], + datlastsysoid=last_system_oid, showsysobj=self.blueprint.show_system_objects ) status, cid = self.conn.execute_scalar(sql) @@ -529,9 +533,13 @@ class CastView(PGChildNodeView): """ try: if cid is not None: + last_system_oid = 0 if self.blueprint.show_system_objects else \ + (self.manager.db_info[did])['datlastsysoid'] \ + if self.manager.db_info is not none and \ + did in self.manager.db_info else 0 sql = render_template("/".join([self.template_path, 'properties.sql']), cid=cid, - datlastsysoid=self.manager.db_info[did]['datlastsysoid'], + datlastsysoid=last_system_oid, showsysobj=self.blueprint.show_system_objects) status, res = self.conn.execute_dict(sql) diff --git a/web/pgadmin/browser/server_groups/servers/databases/event_triggers/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/event_triggers/__init__.py index 9f434e14d..aae333d81 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/event_triggers/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/event_triggers/__init__.py @@ -16,9 +16,8 @@ from flask import render_template, make_response, request, jsonify from flask_babel import gettext from pgadmin.browser.collection import CollectionNodeModule from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -188,22 +187,12 @@ class EventTriggerView(PGChildNodeView): @wraps(f) def wrap(*args, **kwargs): - # Here args[0] will hold self & kwargs will hold gid,sid,did + + # Here - args[0] will always hold self & kwargs will hold gid, sid, did self = args[0] self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(kwargs['sid']) self.conn = self.manager.connection(did=kwargs['did']) - - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) - - ver = self.manager.version - if ver >= 90300: - self.template_path = 'event_triggers/sql/9.3_plus' + self.template_path = 'event_triggers/sql/9.3_plus' return f(*args, **kwargs) diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/__init__.py index d4494a1f7..3e1b47d93 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/__init__.py @@ -19,9 +19,8 @@ from pgadmin.browser.collection import CollectionNodeModule from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \ parse_priv_to_db from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -211,17 +210,8 @@ class ForeignDataWrapperView(PGChildNodeView): self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(kwargs['sid']) self.conn = self.manager.connection(did=kwargs['did']) - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) - - ver = self.manager.version - # we will set template path for sql scripts - if ver >= 90300: + # Set the template path for the SQL scripts + if self.manager.version >= 90300: self.template_path = 'foreign_data_wrappers/sql/9.3_plus' else: self.template_path = 'foreign_data_wrappers/sql/9.1_plus' diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/__init__.py index f51975f1b..55e965924 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/__init__.py @@ -19,9 +19,8 @@ from pgadmin.browser.collection import CollectionNodeModule from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \ parse_priv_to_db from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -204,18 +203,8 @@ class ForeignServerView(PGChildNodeView): self = args[0] self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(kwargs['sid']) self.conn = self.manager.connection(did=kwargs['did']) - - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) - - ver = self.manager.version - # we will set template path for sql scripts - if ver >= 90300: + # Set the template path for the SQL scripts + if self.manager.version >= 90300: self.template_path = 'foreign_servers/sql/9.3_plus' else: self.template_path = 'foreign_servers/sql/9.1_plus' diff --git a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/__init__.py index c0e3f582d..2ab692baf 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/foreign_data_wrappers/foreign_servers/user_mapping/__init__.py @@ -17,9 +17,8 @@ from flask import render_template, make_response, request, jsonify from flask_babel import gettext from pgadmin.browser.collection import CollectionNodeModule from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -219,21 +218,9 @@ class UserMappingView(PGChildNodeView): self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(kwargs['sid']) self.conn = self.manager.connection(did=kwargs['did']) - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) - + # Set the template path for the SQL scripts self.template_path = 'user_mappings/sql/9.1_plus' - ver = self.manager.version - # we will set template path for sql scripts - if ver >= 90100: - self.template_path = 'user_mappings/sql/9.1_plus' - return f(*args, **kwargs) return wrap diff --git a/web/pgadmin/browser/server_groups/servers/databases/languages/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/languages/__init__.py index 4f0238580..1045cc981 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/languages/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/languages/__init__.py @@ -19,9 +19,8 @@ from pgadmin.browser.collection import CollectionNodeModule from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \ parse_priv_to_db from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -229,18 +228,8 @@ class LanguageView(PGChildNodeView): self.driver = get_driver(PG_DEFAULT_DRIVER) self.manager = self.driver.connection_manager(kwargs['sid']) self.conn = self.manager.connection(did=kwargs['did']) - - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) - - ver = self.manager.version - # we will set template path for sql scripts - if ver >= 90300: + # Set the template path for the SQL scripts + if self.manager.version >= 90300: self.template_path = 'languages/sql/9.3_plus' else: self.template_path = 'languages/sql/9.1_plus' diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/__init__.py index 4671897b1..dcf23d5d9 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/__init__.py @@ -18,10 +18,8 @@ from pgadmin.browser.collection import CollectionNodeModule, PGChildModule from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \ parse_priv_to_db from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error, gone, \ - bad_request -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response, gone, bad_request from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -129,13 +127,7 @@ def check_precondition(f): kwargs['sid'] ) self.conn = self.manager.connection(did=kwargs['did']) - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - gettext("Connection to the server has been lost!") - ) - - # Set template path for sql scripts + # Set the template path for the SQL scripts self.template_path = self.template_initial + '/' + ( self.ppas_template_path(self.manager.version) if self.manager.server_type == 'ppas' else diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/__init__.py index e55afdf0a..a77c0c235 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/__init__.py @@ -17,9 +17,8 @@ from flask_babel import gettext from pgadmin.browser.server_groups.servers.databases.schemas.utils \ import SchemaChildModule from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -146,14 +145,6 @@ class CatalogObjectView(PGChildNodeView): kwargs['sid'] ) self.conn = self.manager.connection(did=kwargs['did']) - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) - self.template_path = 'catalog_object/sql/{0}/9.1_plus'.format( 'ppas' if self.manager.server_type == 'ppas' else 'pg' ) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/__init__.py index b0e784fa4..758d9b051 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/catalog_objects/columns/__init__.py @@ -16,9 +16,8 @@ from flask import render_template from flask_babel import gettext from pgadmin.browser.collection import CollectionNodeModule from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from pgadmin.utils.preferences import Preferences @@ -166,14 +165,6 @@ class CatalogObjectColumnsView(PGChildNodeView): kwargs['sid'] ) self.conn = self.manager.connection(did=kwargs['did']) - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) - self.template_path = 'catalog_object_column/sql/9.1_plus' return f(*args, **kwargs) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/collations/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/collations/__init__.py index c4e7bc3f5..68d38e8ba 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/collations/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/collations/__init__.py @@ -18,9 +18,8 @@ from flask_babel import gettext from pgadmin.browser.server_groups.servers.databases.schemas.utils \ import SchemaChildModule from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -185,18 +184,10 @@ class CollationView(PGChildNodeView): kwargs['sid'] ) self.conn = self.manager.connection(did=kwargs['did']) - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) - - # we will set template path for sql scripts + # Set the template path for the SQL scripts self.template_path = 'collation/sql/9.1_plus' - return f(*args, **kwargs) + return f(*args, **kwargs) return wrap @check_precondition diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/__init__.py index 39f36f588..0e07a2618 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/__init__.py @@ -20,9 +20,8 @@ from pgadmin.browser.server_groups.servers.databases.schemas.utils import \ from pgadmin.browser.server_groups.servers.databases.utils import \ parse_sec_labels_from_db from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error, gone -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response, gone from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -263,18 +262,10 @@ class DomainView(PGChildNodeView, DataTypeReader): self.conn = self.manager.connection(did=kwargs['did']) self.qtIdent = driver.qtIdent - if not self.conn.connected(): - return precondition_required( - gettext("Connection to the server has been lost!") - ) - - ver = self.manager.version - server_type = self.manager.server_type - # we will set template path for sql scripts - if ver >= 90200: + if self.manager.version >= 90200: self.template_path = 'domains/sql/9.2_plus' - elif ver >= 90100: + else: self.template_path = 'domains/sql/9.1_plus' return f(*args, **kwargs) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain_constraints/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain_constraints/__init__.py index 8eef4d196..db375f562 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain_constraints/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/domains/domain_constraints/__init__.py @@ -18,9 +18,8 @@ from flask import render_template, make_response, request, jsonify from flask_babel import gettext from pgadmin.browser.collection import CollectionNodeModule from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -256,22 +255,13 @@ class DomainConstraintView(PGChildNodeView): self.conn = self.manager.connection(did=kwargs['did']) self.qtIdent = driver.qtIdent - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - gettext("Connection to the server has been lost!") - ) - - ver = self.manager.version - - # we will set template path for sql scripts - if ver >= 90200: + # Set the template path for the SQL scripts + if self.manager.version >= 90200: self.template_path = 'domain_constraints/sql/9.2_plus' - elif ver >= 90100: + else: self.template_path = 'domain_constraints/sql/9.1_plus' return f(*args, **kwargs) - return wrap @check_precondition diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/foreign_tables/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/foreign_tables/__init__.py index c171d01da..e7239f542 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/foreign_tables/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/foreign_tables/__init__.py @@ -25,9 +25,8 @@ from pgadmin.browser.server_groups.servers.databases.utils import \ from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \ parse_priv_to_db from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error, gone -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response, gone from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -338,16 +337,8 @@ class ForeignTableView(PGChildNodeView, DataTypeReader): # Get database connection self.conn = self.manager.connection(did=kwargs['did']) - self.qtIdent = driver.qtIdent - if not self.conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) - ver = self.manager.version # Set template path for sql scripts depending # on the server version. @@ -360,7 +351,6 @@ class ForeignTableView(PGChildNodeView, DataTypeReader): self.template_path = 'foreign_tables/sql/9.1_plus' return f(*args, **kwargs) - return wrap @check_precondition diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_configurations/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_configurations/__init__.py index 8c3202572..122f45903 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_configurations/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_configurations/__init__.py @@ -18,9 +18,8 @@ from flask_babel import gettext as _ from pgadmin.browser.server_groups.servers.databases.schemas.utils \ import SchemaChildModule from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error, gone -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response, gone from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -230,17 +229,10 @@ class FtsConfigurationView(PGChildNodeView): self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager( kwargs['sid']) self.conn = self.manager.connection(did=kwargs['did']) - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - _("Connection to the server has been lost!") - ) - # we will set template path for sql scripts depending upon server version - ver = self.manager.version - if ver >= 90100: - self.template_path = 'fts_configuration/sql/9.1_plus' - return f(*args, **kwargs) + # Set the template path for the SQL scripts + self.template_path = 'fts_configuration/sql/9.1_plus' + return f(*args, **kwargs) return wrap @check_precondition @@ -741,7 +733,6 @@ class FtsConfigurationView(PGChildNodeView): :param scid: schema id """ # Fetch last system oid - datlastsysoid = self.manager.db_info[did]['datlastsysoid'] sql = render_template( "/".join([self.template_path, 'parser.sql']), @@ -752,6 +743,8 @@ class FtsConfigurationView(PGChildNodeView): if not status: return internal_server_error(errormsg=rset) + datlastsysoid = self.manager.db_info[did]['datlastsysoid'] + # Empty set is added before actual list as initially it will be visible # at parser control while creating a new FTS Configuration res = [{'label': '', 'value': ''}] @@ -776,8 +769,6 @@ class FtsConfigurationView(PGChildNodeView): :param scid: schema id """ # Fetch last system oid - datlastsysoid = self.manager.db_info[did]['datlastsysoid'] - sql = render_template( "/".join([self.template_path, 'copy_config.sql']), copy_config=True @@ -787,6 +778,8 @@ class FtsConfigurationView(PGChildNodeView): if not status: return internal_server_error(errormsg=rset) + datlastsysoid = self.manager.db_info[did]['datlastsysoid'] + # Empty set is added before actual list as initially it will be visible # at copy_config control while creating a new FTS Configuration res = [{'label': '', 'value': ''}] diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_dictionaries/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_dictionaries/__init__.py index b7dea0867..24b9d2d57 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_dictionaries/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_dictionaries/__init__.py @@ -18,9 +18,8 @@ from flask_babel import gettext as _ from pgadmin.browser.server_groups.servers.databases.schemas.utils \ import SchemaChildModule from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error, gone -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response, gone from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -222,17 +221,10 @@ class FtsDictionaryView(PGChildNodeView): self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager( kwargs['sid']) self.conn = self.manager.connection(did=kwargs['did']) - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - _("Connection to the server has been lost!") - ) - # we will set template path for sql scripts depending upon server version - ver = self.manager.version - if ver >= 90100: - self.template_path = 'fts_dictionary/sql/9.1_plus' - return f(*args, **kwargs) + # Set the template path for the SQL scripts + self.template_path = 'fts_dictionary/sql/9.1_plus' + return f(*args, **kwargs) return wrap def tokenize_options(self, option_value): @@ -725,8 +717,6 @@ class FtsDictionaryView(PGChildNodeView): :param scid: schema id """ # Fetch last system oid - datlastsysoid = self.manager.db_info[did]['datlastsysoid'] - sql = render_template("/".join([self.template_path, 'templates.sql']), template=True) status, rset = self.conn.execute_dict(sql) @@ -734,6 +724,7 @@ class FtsDictionaryView(PGChildNodeView): if not status: return internal_server_error(errormsg=rset) + datlastsysoid = self.manager.db_info[did]['datlastsysoid'] # Empty set is added before actual list as initially it will be visible # at template control while creating a new FTS Dictionary res = [{'label': '', 'value': ''}] diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_parser/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_parser/__init__.py index cd3192246..b821fbe93 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_parser/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_parser/__init__.py @@ -17,9 +17,8 @@ from flask_babel import gettext as _ from pgadmin.browser.server_groups.servers.databases import DatabaseModule from pgadmin.browser.server_groups.servers.databases.schemas.utils import SchemaChildModule from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response, gone from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -220,19 +219,10 @@ class FtsParserView(PGChildNodeView): self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager( kwargs['sid']) self.conn = self.manager.connection(did=kwargs['did']) - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - _( - "Connection to the server has been lost!" - ) - ) - # we will set template path for sql scripts depending upon server version - ver = self.manager.version - if ver >= 90100: - self.template_path = 'fts_parser/sql/9.1_plus' - return f(*args, **kwargs) + # Set the template path for the SQL scripts + self.template_path = 'fts_parser/sql/9.1_plus' + return f(*args, **kwargs) return wrap @check_precondition diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/__init__.py index a349197ad..85a8ca5a0 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/fts_templates/__init__.py @@ -17,9 +17,8 @@ from flask_babel import gettext from pgadmin.browser.server_groups.servers.databases import DatabaseModule from pgadmin.browser.server_groups.servers.databases.schemas.utils import SchemaChildModule from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response, gone from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -209,19 +208,9 @@ class FtsTemplateView(PGChildNodeView): self.manager = get_driver(PG_DEFAULT_DRIVER).connection_manager( kwargs['sid']) self.conn = self.manager.connection(did=kwargs['did']) - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) - # we will set template path for sql scripts depending upon server version - ver = self.manager.version - if ver >= 90100: - self.template_path = 'fts_template/sql/9.1_plus' - return f(*args, **kwargs) + self.template_path = 'fts_template/sql/9.1_plus' + return f(*args, **kwargs) return wrap @check_precondition @@ -267,7 +256,6 @@ class FtsTemplateView(PGChildNodeView): @check_precondition def node(self, gid, sid, did, scid, tid): - res = [] sql = render_template( "/".join([self.template_path, 'nodes.sql']), tid=tid @@ -286,6 +274,9 @@ class FtsTemplateView(PGChildNodeView): ), status=200 ) + return gone( + _("Could not the requested FTS template.") + ) @check_precondition def properties(self, gid, sid, did, scid, tid): @@ -609,9 +600,9 @@ class FtsTemplateView(PGChildNodeView): :param scid: schema id :param tid: fts tempate id """ - data = request.args - sql = render_template("/".join([self.template_path, 'functions.sql']), - lexize=True) + sql = render_template( + "/".join([self.template_path, 'functions.sql']), lexize=True + ) status, rset = self.conn.execute_dict(sql) if not status: @@ -638,9 +629,9 @@ class FtsTemplateView(PGChildNodeView): :param scid: schema id :param tid: fts tempate id """ - data = request.args - sql = render_template("/".join([self.template_path, 'functions.sql']), - init=True) + sql = render_template( + "/".join([self.template_path, 'functions.sql']), init=True + ) status, rset = self.conn.execute_dict(sql) if not status: diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py index ca69cac0b..105038a6d 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/functions/__init__.py @@ -27,9 +27,8 @@ from pgadmin.browser.server_groups.servers.databases.utils import \ from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \ parse_priv_to_db from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error, gone -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response, gone from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -329,21 +328,12 @@ class FunctionView(PGChildNodeView, DataTypeReader): # Get database connection self.conn = self.manager.connection(did=kwargs['did']) - self.qtIdent = driver.qtIdent self.qtLiteral = driver.qtLiteral - if not self.conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) - ver = self.manager.version - # Set template path for sql scripts depending - # on the server version. + # Set the template path for the SQL scripts self.template_path = "/".join([ self.node_type ]) @@ -469,10 +459,9 @@ class FunctionView(PGChildNodeView, DataTypeReader): proallargtypes = data['proallargtypes'] \ if data['proallargtypes'] else [] - proargout = [] - proargid = [] - proargmodenames = {'i': 'IN', 'o': 'OUT', 'b': 'INOUT', - 'v': 'VARIADIC', 't': 'TABLE'} + proargmodenames = { + 'i': 'IN', 'o': 'OUT', 'b': 'INOUT', 'v': 'VARIADIC', 't': 'TABLE' + } # The proargtypes doesn't give OUT params, so we need to fetch # those from database explicitly, below code is written for this @@ -1325,7 +1314,6 @@ It may have been removed by another user or moved to another schema. if not status: return internal_server_error(errormsg=res) - func_def = res['rows'][0]['func_def'] name = res['rows'][0]['name'] # Fetch only arguments diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/sequences/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/sequences/__init__.py index 29be4fd75..fed62f88f 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/sequences/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/sequences/__init__.py @@ -20,9 +20,8 @@ from pgadmin.browser.server_groups.servers.databases.schemas.utils \ from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \ parse_priv_to_db from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -145,20 +144,11 @@ class SequenceView(PGChildNodeView): self.conn = self.manager.connection(did=kwargs['did']) else: self.conn = self.manager.connection() - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - _( - "Connection to the server has been lost!" - ) - ) - self.template_path = 'sequence/sql/9.1_plus' self.acl = ['r', 'w', 'U'] + return f(self, *args, **kwargs) - return wrapped - return wrap @check_precondition(action='list') @@ -336,10 +326,10 @@ class SequenceView(PGChildNodeView): # We need oid of newly created sequence. SQL = render_template("/".join([self.template_path, 'get_oid.sql']), name=data['name'], scid=scid) SQL = SQL.strip('\n').strip(' ') - if SQL and SQL != "": - status, seid = self.conn.execute_scalar(SQL) - if not status: - return internal_server_error(errormsg=res) + + status, seid = self.conn.execute_scalar(SQL) + if not status: + return internal_server_error(errormsg=seid) return jsonify( node=self.blueprint.generate_browser_node( @@ -504,18 +494,13 @@ class SequenceView(PGChildNodeView): "Could not find the required parameter (%s)." % arg ) ) - try: - SQL = self.getSQL(gid, sid, did, data, scid, seid) - SQL = SQL.strip('\n').strip(' ') - return make_json_response( - data=SQL, - status=200 - ) - except Exception as e: - return make_json_response( - data="-- modified SQL", - status=200 - ) + SQL = self.getSQL(gid, sid, did, data, scid, seid) + SQL = SQL.strip('\n').strip(' ') + + return make_json_response( + data=SQL, + status=200 + ) def getSQL(self, gid, sid, did, data, scid, seid=None): """ diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py index 0d29ab32d..d913b195d 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/__init__.py @@ -22,9 +22,8 @@ from pgadmin.browser.server_groups.servers.databases.schemas.utils \ from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \ parse_priv_to_db from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -272,22 +271,18 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings): # Here args[0] will hold self & kwargs will hold gid,sid,did self = args[0] driver = get_driver(PG_DEFAULT_DRIVER) + did = kwargs['did'] self.manager = driver.connection_manager(kwargs['sid']) self.conn = self.manager.connection(did=kwargs['did']) self.qtIdent = driver.qtIdent # We need datlastsysoid to check if current table is system table - self.datlastsysoid = self.manager.db_info[kwargs['did']]['datlastsysoid'] - self.server_type = self.manager.server_type - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) - # we will set template path for sql scripts + self.datlastsysoid = self.manager.db_info[ + did + ]['datlastsysoid'] if self.manager.db_info is not None and \ + did in self.manager.db_info else 0 + ver = self.manager.version - # Template for Column node + # Set the template path for the SQL scripts if ver >= 90500: self.template_path = 'table/sql/9.5_plus' else: @@ -1193,7 +1188,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings): try: SQL = render_template("/".join([self.template_path, 'get_oftype.sql']), scid=scid, - server_type=self.server_type, + server_type=self.manager.server_type, show_sys_objects=self.blueprint.show_system_objects) status, rset = self.conn.execute_2darray(SQL) if not status: @@ -1224,7 +1219,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings): SQL = render_template("/".join([self.template_path, 'get_inherits.sql']), show_system_objects=self.blueprint.show_system_objects, tid=tid, - server_type=self.server_type) + server_type=self.manager.server_type) status, rset = self.conn.execute_2darray(SQL) if not status: return internal_server_error(errormsg=res) @@ -1253,7 +1248,7 @@ class TableView(PGChildNodeView, DataTypeReader, VacuumSettings): try: SQL = render_template("/".join([self.template_path, 'get_relations.sql']), show_sys_objects=self.blueprint.show_system_objects, - server_type=self.server_type) + server_type=self.manager.server_type) status, rset = self.conn.execute_2darray(SQL) if not status: return internal_server_error(errormsg=res) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/__init__.py index ef5cbe45a..fe88123cf 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/column/__init__.py @@ -21,9 +21,8 @@ from pgadmin.browser.server_groups.servers.databases.schemas.utils \ from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \ parse_priv_to_db from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -199,17 +198,9 @@ class ColumnsView(PGChildNodeView, DataTypeReader): ) self.conn = self.manager.connection(did=kwargs['did']) self.qtIdent = driver.qtIdent - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) - ver = self.manager.version - # we will set template path for sql scripts - if ver >= 90200: + # Set the template path for the SQL scripts + if self.manager.version >= 90200: self.template_path = 'column/sql/9.2_plus' else: self.template_path = 'column/sql/9.1_plus' diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/__init__.py index 3405dedda..a6ccec3fd 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/check_constraint/__init__.py @@ -19,9 +19,8 @@ from pgadmin.browser.collection import CollectionNodeModule from pgadmin.browser.server_groups.servers.databases.schemas.tables.constraints.type \ import ConstraintRegistry from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -208,15 +207,8 @@ class CheckConstraintView(PGChildNodeView): self.conn = self.manager.connection(did=kwargs['did']) self.qtIdent = driver.qtIdent - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - _("Connection to the server has been lost!") - ) - ver = self.manager.version - - # we will set template path for sql scripts + # Set the template path for the SQL scripts if ver >= 90200: self.template_path = 'check_constraint/sql/9.2_plus' elif ver >= 90100: diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/__init__.py index 26115f7dc..1c1834ae1 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/__init__.py @@ -18,9 +18,8 @@ from flask_babel import gettext as _ from pgadmin.browser.server_groups.servers.databases.schemas.tables.constraints.type \ import ConstraintRegistry, ConstraintTypeModule from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -216,16 +215,7 @@ class ExclusionConstraintView(PGChildNodeView): ) self.conn = self.manager.connection(did=kwargs['did']) - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - _( - "Connection to the server has been lost!" - ) - ) - ver = self.manager.version - if ver >= 90200: self.template_path = 'exclusion_constraint/sql/9.2_plus' elif ver >= 90100: @@ -242,8 +232,8 @@ class ExclusionConstraintView(PGChildNodeView): for row in rset['rows']: self.schema = row['schema'] self.table = row['table'] - return f(*args, **kwargs) + return f(*args, **kwargs) return wrap def end_transaction(self): diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/__init__.py index 9a2ee0663..43e270e64 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/foreign_key/__init__.py @@ -18,9 +18,8 @@ from flask_babel import gettext as _ from pgadmin.browser.server_groups.servers.databases.schemas.tables.constraints.type \ import ConstraintRegistry, ConstraintTypeModule from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -194,7 +193,7 @@ class ForeignKeyConstraintView(PGChildNodeView): ], 'delete': [{'delete': 'delete'}], 'children': [{'get': 'children'}], - 'nodes': [{'get': 'node'}, {'get': 'nodes'}], + 'nodes': [{'get': 'nodes'}, {'get': 'nodes'}], 'sql': [{'get': 'sql'}], 'msql': [{'get': 'msql'}, {'get': 'msql'}], 'stats': [{'get': 'statistics'}], @@ -234,16 +233,8 @@ class ForeignKeyConstraintView(PGChildNodeView): kwargs['sid'] ) self.conn = self.manager.connection(did=kwargs['did']) - - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - _( - "Connection to the server has been lost!" - ) - ) - self.template_path = 'foreign_key/sql' + # We need parent's name eg table name and schema name SQL = render_template("/".join([self.template_path, 'get_parent.sql']), @@ -255,8 +246,8 @@ class ForeignKeyConstraintView(PGChildNodeView): for row in rset['rows']: self.schema = row['schema'] self.table = row['table'] - return f(*args, **kwargs) + return f(*args, **kwargs) return wrap def end_transaction(self): @@ -398,31 +389,8 @@ class ForeignKeyConstraintView(PGChildNodeView): Returns: """ - try: - res = self.get_nodes(gid, sid, did, scid, tid, fkid) - return make_json_response( - data=res, - status=200 - ) - except Exception as e: - return internal_server_error(errormsg=str(e)) + res = self.get_nodes(gid, sid, did, scid, tid, fkid) - @check_precondition - def get_nodes(self, gid, sid, did, scid, tid, fkid=None): - """ - This function returns all event trigger nodes as a list. - - Args: - gid: Server Group ID - sid: Server ID - did: Database ID - scid: Schema ID - tid: Table ID - fkid: Foreign key constraint ID - - Returns: - - """ res = [] SQL = render_template("/".join([self.template_path, 'nodes.sql']), @@ -444,7 +412,11 @@ class ForeignKeyConstraintView(PGChildNodeView): icon=icon, valid=valid )) - return res + + return make_json_response( + data=res, + status=200 + ) @check_precondition def create(self, gid, sid, did, scid, tid, fkid=None): diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/__init__.py index ecdbd8b25..349b5e39b 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/index_constraint/__init__.py @@ -18,9 +18,8 @@ from flask_babel import gettext as _ from pgadmin.browser.server_groups.servers.databases.schemas.tables.constraints.type \ import ConstraintRegistry, ConstraintTypeModule from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -237,16 +236,8 @@ class IndexConstraintView(PGChildNodeView): kwargs['sid'] ) self.conn = self.manager.connection(did=kwargs['did']) - - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - _( - "Connection to the server has been lost!" - ) - ) - self.template_path = 'index_constraint/sql' + # We need parent's name eg table name and schema name SQL = render_template("/".join([self.template_path, 'get_parent.sql']), diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/templates/constraints/js/constraints.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/templates/constraints/js/constraints.js index c8144fd3e..7fc9b3d9e 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/templates/constraints/js/constraints.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/templates/constraints/js/constraints.js @@ -1,7 +1,7 @@ define( [ 'jquery', 'underscore', 'underscore.string', 'pgadmin', 'pgadmin.browser', - 'pgadmin.browser.collection'{% for c in constraints %}, 'pgadmin.node.{{ c|safe }}'{%endfor%} + 'pgadmin.browser.collection'{% for c in constraints %}, 'pgadmin.node.{{ c }}'{%endfor%} ], function($, _, S, pgAdmin, pgBrowser) { @@ -51,4 +51,4 @@ function($, _, S, pgAdmin, pgBrowser) { } return pgBrowser.Nodes['constraints']; -}); \ No newline at end of file +}); diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/__init__.py index d79c9465b..94ffbf1f3 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/indexes/__init__.py @@ -17,9 +17,8 @@ from flask import render_template, request, jsonify from flask_babel import gettext from pgadmin.browser.collection import CollectionNodeModule from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -69,13 +68,6 @@ class IndexesModule(CollectionNodeModule): """ if super(IndexesModule, self).BackendSupported(manager, **kwargs): conn = manager.connection(did=kwargs['did']) - # If DB is not connected then return error to browser - if not conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) if 'vid' not in kwargs: return True @@ -228,16 +220,11 @@ class IndexesView(PGChildNodeView): kwargs['sid'] ) self.conn = self.manager.connection(did=kwargs['did']) - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) - # We need datlastsysoid to check if current index is system index - self.datlastsysoid = self.manager.db_info[kwargs['did']]['datlastsysoid'] + self.datlastsysoid = self.manager.db_info[ + kwargs['did'] + ]['datlastsysoid'] if self.manager.db_info is not None and \ + kwargs['did'] in self.manager.db_info else 0 # we will set template path for sql scripts self.template_path = 'index/sql/9.1_plus' @@ -440,7 +427,6 @@ class IndexesView(PGChildNodeView): # 'options' we need true/false to render switch ASC(false)/DESC(true) columns = [] cols = [] - cnt = 1 for row in rset['rows']: # We need all data as collection for ColumnsModel cols_data = { diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/__init__.py index d46245425..79d6398eb 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/rules/__init__.py @@ -19,9 +19,8 @@ from pgadmin.browser.collection import CollectionNodeModule from pgadmin.browser.server_groups.servers.databases.schemas.utils import \ parse_rule_definition from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -53,13 +52,6 @@ class RuleModule(CollectionNodeModule): """ if super(RuleModule, self).BackendSupported(manager, **kwargs): conn = manager.connection(did=kwargs['did']) - # If DB is not connected then return error to browser - if not conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) if 'vid' not in kwargs: return True @@ -202,16 +194,10 @@ class RuleView(PGChildNodeView): self.manager = get_driver( PG_DEFAULT_DRIVER).connection_manager(kwargs['sid']) self.conn = self.manager.connection(did=kwargs['did']) - - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) - - self.datlastsysoid = self.manager.db_info[kwargs['did']]['datlastsysoid'] + self.datlastsysoid = self.manager.db_info[ + kwargs['did'] + ]['datlastsysoid'] if self.manager.db_info is not None and \ + kwargs['did'] in self.manager.db_info else 0 self.template_path = 'rules/sql' return f(*args, **kwargs) diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/nodes.sql index 966758828..be54e8cb0 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/nodes.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/templates/foreign_key/sql/nodes.sql @@ -4,4 +4,4 @@ SELECT ct.oid, FROM pg_constraint ct WHERE contype='f' AND conrelid = {{tid}}::oid -ORDER BY conname \ No newline at end of file +ORDER BY conname diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/__init__.py index 9f0943e20..ba5cb287e 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/triggers/__init__.py @@ -17,9 +17,8 @@ from flask import render_template, request, jsonify from flask_babel import gettext from pgadmin.browser.collection import CollectionNodeModule from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -69,24 +68,21 @@ class TriggerModule(CollectionNodeModule): """ if super(TriggerModule, self).BackendSupported(manager, **kwargs): conn = manager.connection(did=kwargs['did']) - # If DB is not connected then return error to browser - if not conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) if 'vid' not in kwargs: return True template_path = 'trigger/sql/9.1_plus' SQL = render_template("/".join( - [template_path, 'backend_support.sql']), vid=kwargs['vid']) + [template_path, 'backend_support.sql']), vid=kwargs['vid'] + ) + status, res = conn.execute_scalar(SQL) + # check if any errors if not status: return internal_server_error(errormsg=res) + # Check vid is view not material view # then true, othewise false return res @@ -255,16 +251,11 @@ class TriggerView(PGChildNodeView): kwargs['sid'] ) self.conn = self.manager.connection(did=kwargs['did']) - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) - # We need datlastsysoid to check if current trigger is system trigger - self.datlastsysoid = self.manager.db_info[kwargs['did']]['datlastsysoid'] + self.datlastsysoid = self.manager.db_info[ + kwargs['did'] + ]['datlastsysoid'] if self.manager.db_info is not None and \ + kwargs['did'] in self.manager.db_info else 0 # we will set template path for sql scripts self.template_path = 'trigger/sql/9.1_plus' diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/__init__.py index 8ea7aa9cd..9c8b30f81 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/__init__.py @@ -20,9 +20,8 @@ from pgadmin.browser.server_groups.servers.databases.schemas.utils \ from pgadmin.browser.server_groups.servers.utils import parse_priv_from_db, \ parse_priv_to_db from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -223,15 +222,10 @@ class TypeView(PGChildNodeView, DataTypeReader): self.conn = self.manager.connection(did=kwargs['did']) # We need datlastsysoid to check if current type is system type - self.datlastsysoid = self.manager.db_info[kwargs['did']]['datlastsysoid'] - - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - gettext( - "Connection to the server has been lost!" - ) - ) + self.datlastsysoid = self.manager.db_info[ + kwargs['did'] + ]['datlastsysoid'] if self.manager.db_info is not None and \ + kwargs['did'] in self.manager.db_info else 0 # Declare allows acl on type self.acl = ['U'] @@ -240,7 +234,6 @@ class TypeView(PGChildNodeView, DataTypeReader): self.template_path = 'type/sql/9.1_plus' return f(*args, **kwargs) - return wrap @check_precondition diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py index 317a488a4..9034f43e7 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/__init__.py @@ -18,10 +18,8 @@ from flask_babel import gettext from pgadmin.browser.server_groups.servers.databases.schemas.utils import \ SchemaChildModule, parse_rule_definition, VacuumSettings from pgadmin.browser.utils import PGChildNodeView -from pgadmin.utils.ajax import make_json_response, \ - make_response as ajax_response, internal_server_error, \ - bad_request -from pgadmin.utils.ajax import precondition_required +from pgadmin.utils.ajax import make_json_response, internal_server_error, \ + make_response as ajax_response, bad_request from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER @@ -171,13 +169,10 @@ def check_precondition(f): kwargs['sid'] ) self.conn = self.manager.connection(did=kwargs['did']) - # If DB not connected then return error to browser - if not self.conn.connected(): - return precondition_required( - gettext("Connection to the server has been lost!") - ) self.datlastsysoid = self.manager.db_info[ - kwargs['did']]['datlastsysoid'] + kwargs['did'] + ]['datlastsysoid'] if self.manager.db_info is not None and \ + kwargs['did'] in self.manager.db_info else 0 # Set template path for sql scripts self.template_path = self.template_initial + '/' + ( diff --git a/web/pgadmin/browser/server_groups/servers/databases/templates/databases/js/databases.js b/web/pgadmin/browser/server_groups/servers/databases/templates/databases/js/databases.js index f5cd6a9d4..aec26123d 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/templates/databases/js/databases.js +++ b/web/pgadmin/browser/server_groups/servers/databases/templates/databases/js/databases.js @@ -69,6 +69,11 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) { category: 'drop', priority: 5, label: '{{ _('Disconnect Database...') }}', icon: 'fa fa-chain-broken', enable : 'is_connected' }]); + + _.bindAll(this, 'connection_lost'); + pgBrowser.Events.on( + 'pgadmin:database:connection:lost', this.connection_lost + ); }, can_create_database: function(node, item) { var treeData = this.getTreeNodeHierarchy(item), @@ -82,6 +87,67 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) { is_connected: function(node) { return (node && node.connected == true && node.canDisconn == true); }, + connection_lost: function(i, resp, server_connected) { + if (pgBrowser.tree) { + var t = pgBrowser.tree, + info = i && this.getTreeNodeHierarchy(i), + s = null, + d = i && t.itemData(i), + self = this, + _i = i; + + while (d && d._type != 'database') { + i = t.parent(i); + d = i && t.itemData(i); + } + + if (i && d) { + if (_.isUndefined(d.is_connecting) || !d.is_connecting) { + d.is_connecting = true; + + var disconnect = function(_i, _d) { + if (_d._id == this._id) { + d.is_connecting = false; + pgBrowser.Events.off( + 'pgadmin:database:connect:cancelled', disconnect + ); + _i = _i && t.parent(_i); + _d = _i && t.itemData(_i); + if (_i && _d) { + pgBrowser.Events.trigger( + 'pgadmin:server:disconnect', + {item: _i, data: _d}, false + ); + } + } + }; + + pgBrowser.Events.on( + 'pgadmin:database:connect:cancelled', disconnect + ); + if (server_connected) { + connect(self, d, t, i, true); + return; + } + Alertify.confirm( + '{{ _('Connection lost') }}', + '{{ _('Would you like to reconnect to the database?') }}', + function() { + connect(self, d, t, i, true); + }, + function() { + d.is_connecting = false; + t.unload(i); + t.setInode(i); + t.addIcon(i, {icon: 'icon-database-not-connected'}); + pgBrowser.Events.trigger( + 'pgadmin:database:connect:cancelled', i, d, self + ); + }); + } + } + } + }, callbacks: { /* Connect the database */ connect_database: function(args){ @@ -374,58 +440,91 @@ function($, _, S, pgAdmin, pgBrowser, Alertify) { return null; } }) - }); - function connect_to_database(obj, data, tree, item, interactive) { - connect(obj, data, tree, item) - }; - function connect(obj, data, tree, item) { - var onFailure = function(xhr, status, error, _model, _data, _tree, _item) { + }); - tree.setInode(_item); - tree.addIcon(_item, {icon: 'icon-database-not-connected'}); + function connect_to_database(obj, data, tree, item, interactive) { + connect(obj, data, tree, item) + } - Alertify.pgNotifier('error', xhr, error, function(msg) { - setTimeout(function() { - Alertify.dlgServerPass( - '{{ _('Connect to database') }}', - msg, _model, _data, _tree, _item - ).resizeTo(); - }, 100); - }); - }, - onSuccess = function(res, model, data, tree, item) { - tree.deselect(item); - tree.setInode(item); - - if (res && res.data) { - if(typeof res.data.connected == 'boolean') { - data.connected = res.data.connected; - } - if (typeof res.data.icon == 'string') { - tree.removeIcon(item); - data.icon = res.data.icon; - tree.addIcon(item, {icon: data.icon}); - } - - Alertify.success(res.info); - setTimeout(function() {tree.select(item);}, 10); - setTimeout(function() {tree.open(item);}, 100); - } - }, - url = obj.generate_url(item, "connect", data, true); - $.post(url) - .done( - function(res) { - if (res.success == 1) { - return onSuccess(res, obj, data, tree, item); + function connect(obj, data, tree, item, _wasConnected) { + var wasConnected = _wasConnected || data.connected, + onFailure = function( + xhr, status, error, _model, _data, _tree, _item, _status + ) { + if (!_status) { + tree.setInode(_item); + tree.addIcon(_item, {icon: 'icon-database-not-connected'}); } - }) - .fail( - function(xhr, status, error) { - return onFailure(xhr, status, error, obj, data, tree, item); - }); - } + Alertify.pgNotifier('error', xhr, error, function(msg) { + setTimeout(function() { + Alertify.dlgServerPass( + '{{ _('Connect to database') }}', + msg, _model, _data, _tree, _item, _status, + onSuccess, onFailure, onCancel + ).resizeTo(); + }, 100); + }); + }, + onSuccess = function( + res, model, data, tree, item, connected + ) { + data.is_connecting = false; + if (!connected) { + tree.deselect(item); + tree.setInode(item); + } + + if (res && res.data) { + if(typeof res.data.connected == 'boolean') { + data.connected = res.data.connected; + } + if (typeof res.data.icon == 'string') { + tree.removeIcon(item); + data.icon = res.data.icon; + tree.addIcon(item, {icon: data.icon}); + } + + Alertify.success(res.info); + obj.trigger('connected', obj, item, data); + pgBrowser.Events.trigger( + 'pgadmin:database:connected', item, data + ); + + if (!connected) { + setTimeout(function() { + tree.select(item); + tree.open(item); + }, 10); + } + } + }, + onCancel = function(_tree, _item, _data, _status) { + _data.is_connecting = false; + var server = _tree.parent(_item); + _tree.unload(_item); + _tree.setInode(_item); + _tree.removeIcon(_item); + _tree.addIcon(_item, {icon: 'icon-database-not-connected'}); + obj.trigger('connect:cancelled', obj, _item, _data); + pgBrowser.Events.trigger( + 'pgadmin:database:connect:cancelled', _item, _data, obj + ); + _tree.select(server); + }; + + $.post( + obj.generate_url(item, "connect", data, true) + ).done(function(res) { + if (res.success == 1) { + return onSuccess(res, obj, data, tree, item, wasConnected); + } + }).fail(function(xhr, status, error) { + return onFailure( + xhr, status, error, obj, data, tree, item, wasConnected + ); + }); + } } return pgBrowser.Nodes['coll-database']; diff --git a/web/pgadmin/browser/server_groups/servers/templates/servers/servers.js b/web/pgadmin/browser/server_groups/servers/templates/servers/servers.js index ca0c2697f..e6c92e1d1 100644 --- a/web/pgadmin/browser/server_groups/servers/templates/servers/servers.js +++ b/web/pgadmin/browser/server_groups/servers/templates/servers/servers.js @@ -102,6 +102,18 @@ function($, _, S, pgAdmin, pgBrowser, alertify) { '{{ _('A grantee must be selected.') }}'; pgBrowser.messages['NO_PRIV_SELECTED'] = '{{ _('At least one privilege should be selected.') }}'; + + pgBrowser.Events.on( + 'pgadmin:server:disconnect', this.callbacks.disconnect_server + ); + pgBrowser.Events.on( + 'pgadmin:server:connect', this.callbacks.connect_server + ); + + _.bindAll(this, 'connection_lost'); + pgBrowser.Events.on( + 'pgadmin:server:connection:lost', this.connection_lost + ); }, is_not_connected: function(node) { return (node && node.connected != true); @@ -158,11 +170,11 @@ function($, _, S, pgAdmin, pgBrowser, alertify) { if (!d) return false; - connect_to_server(obj, d, t, i); + connect_to_server(obj, d, t, i, false); return false; }, /* Disconnect the server */ - disconnect_server: function(args) { + disconnect_server: function(args, notify) { var input = args || {}, obj = this, t = pgBrowser.tree, @@ -172,48 +184,60 @@ function($, _, S, pgAdmin, pgBrowser, alertify) { if (!d) return false; - alertify.confirm( - '{{ _('Disconnect server') }}', - S('{{ _('Are you sure you want to disconnect the server %s?') }}').sprintf(d.label).value(), - function(evt) { - $.ajax({ - url: obj.generate_url(i, 'connect', d, true), - type:'DELETE', - success: function(res) { - if (res.success == 1) { - alertify.success(res.info); - d = t.itemData(i); - t.removeIcon(i); - d.connected = false; - d.icon = 'icon-server-not-connected'; - t.addIcon(i, {icon: d.icon}); - obj.callbacks.refresh.apply(obj, [null, i]); - if (pgBrowser.serverInfo && d._id in pgBrowser.serverInfo) { - delete pgBrowser.serverInfo[d._id] - } - obj.trigger('server-disconnected', obj, i, d); + notify = notify || _.isUndefined(notify) || _.isNull(notify); + + var disconnect = function() { + $.ajax({ + url: obj.generate_url(i, 'connect', d, true), + type:'DELETE', + success: function(res) { + if (res.success == 1) { + alertify.success(res.info); + d = t.itemData(i); + t.removeIcon(i); + d.connected = false; + d.icon = 'icon-server-not-connected'; + t.addIcon(i, {icon: d.icon}); + obj.callbacks.refresh.apply(obj, [null, i]); + if (pgBrowser.serverInfo && d._id in pgBrowser.serverInfo) { + delete pgBrowser.serverInfo[d._id] } - else { - try { - alertify.error(res.errormsg); - } catch (e) {} - t.unload(i); - } - }, - error: function(xhr, status, error) { + obj.trigger('server-disconnected', obj, i, d); + } + else { try { - var err = $.parseJSON(xhr.responseText); - if (err.success == 0) { - alertify.error(err.errormsg); - } + alertify.error(res.errormsg); } catch (e) {} t.unload(i); } + }, + error: function(xhr, status, error) { + try { + var err = $.parseJSON(xhr.responseText); + if (err.success == 0) { + alertify.error(err.errormsg); + } + } catch (e) {} + t.unload(i); + } + }); + }; + + if (notify) { + alertify.confirm( + '{{ _('Disconnect server') }}', + S('{{ _('Are you sure you want to disconnect the server %s?') }}').sprintf( + d.label + ).value(), + function(evt) { + disconnect(); + }, + function(evt) { + return true; }); - }, - function(evt) { - return true; - }); + } else { + disconnect(); + } return false; }, @@ -226,7 +250,7 @@ function($, _, S, pgAdmin, pgBrowser, alertify) { pgBrowser.tree.addIcon(item, {icon: data.icon}); if (!data.connected) { - connect_to_server(this, data, pgBrowser.tree, item); + connect_to_server(this, data, pgBrowser.tree, item, false); return false; } @@ -409,7 +433,6 @@ function($, _, S, pgAdmin, pgBrowser, alertify) { } }, prepare: function() { - //console.log(this.get('server').user.name); var self = this; // Disable Backup button until user provides Filename this.__internal.buttons[0].element.disabled = true; @@ -487,13 +510,14 @@ function($, _, S, pgAdmin, pgBrowser, alertify) { alertify.changeServerPassword(d).resizeTo('40%','52%'); return false; }, + /* Pause WAL Replay */ pause_wal_replay: function(args) { - var input = args || {}; - obj = this, - t = pgBrowser.tree, - i = input.item || t.selected(), - d = i && i.length == 1 ? t.itemData(i) : undefined; + var input = args || {}, + obj = this, + t = pgBrowser.tree, + i = input.item || t.selected(), + d = i && i.length == 1 ? t.itemData(i) : undefined; if (!d) return false; @@ -528,13 +552,14 @@ function($, _, S, pgAdmin, pgBrowser, alertify) { } }) }, + /* Resume WAL Replay */ resume_wal_replay: function(args) { - var input = args || {}; - obj = this, - t = pgBrowser.tree, - i = input.item || t.selected(), - d = i && i.length == 1 ? t.itemData(i) : undefined; + var input = args || {}, + obj = this, + t = pgBrowser.tree, + i = input.item || t.selected(), + d = i && i.length == 1 ? t.itemData(i) : undefined; if (!d) return false; @@ -709,66 +734,157 @@ function($, _, S, pgAdmin, pgBrowser, alertify) { isConnected: function(model) { return model.get('connected'); } - }) - }); - function connect_to_server(obj, data, tree, item) { - var onFailure = function(xhr, status, error, _model, _data, _tree, _item) { + }), + connection_lost: function(i, resp) { + if (pgBrowser.tree) { + var t = pgBrowser.tree, + info = i && this.getTreeNodeHierarchy(i), + s = null, + d = i && t.itemData(i), + self = this; - tree.setInode(_item); - tree.addIcon(_item, {icon: 'icon-server-not-connected'}); - - alertify.pgNotifier('error', xhr, error, function(msg) { - setTimeout(function() { - alertify.dlgServerPass( - '{{ _('Connect to Server') }}', - msg, _model, _data, _tree, _item - ).resizeTo(); - }, 100); - }); - }, - onSuccess = function(res, model, data, tree, item) { - tree.deselect(item); - tree.setInode(item); - - if (res && res.data) { - - if (typeof res.data.icon == 'string') { - tree.removeIcon(item); - data.icon = res.data.icon; - tree.addIcon(item, {icon: data.icon}); + while (d && d._type != 'server') { + i = t.parent(i); + d = i && t.itemData(i); } - // Update 'in_recovery' and 'wal_pause' options at server node - tree.itemData(item).in_recovery=res.data.in_recovery; - tree.itemData(item).wal_pause=res.data.wal_pause; + if (i && d && d._type == 'server') { + if (_.isUndefined(d.is_connecting) || !d.is_connecting) { + d.is_connecting = true; - _.extend(data, res.data); + var disconnect = function(_sid) { + if (d._id == _sid) { + d.is_connecting = false; + // Stop listening to the connection cancellation event + pgBrowser.Events.off( + 'pgadmin:server:connect:cancelled', disconnect + ); - var serverInfo = pgBrowser.serverInfo = pgBrowser.serverInfo || {}; - serverInfo[data._id] = _.extend({}, data); + // Connection to the database will also be cancelled + pgBrowser.Events.trigger( + 'pgadmin:database:connect:cancelled',_sid, + resp.data.database || d.db + ); - alertify.success(res.info); - obj.trigger('server-connected', obj, item, data); - - setTimeout(function() { - tree.select(item); - tree.open(item); - }, 10); + // Make sure - the server is disconnected properly + pgBrowser.Events.trigger( + 'pgadmin:server:disconnect', + {item: _i, data: _d}, false + ); + } + }; + // Listen for the server connection cancellation event + pgBrowser.Events.on( + 'pgadmin:server:connect:cancelled', disconnect + ); + alertify.confirm( + '{{ _('Connection lost') }}', + '{{ _('Would you like to reconnect to the database?') }}', + function() { + connect_to_server(self, d, t, i, true); + }, + function() { + d.is_connecting = false; + t.unload(i); + t.setInode(i); + t.addIcon(i, {icon: 'icon-database-not-connected'}); + pgBrowser.Events.trigger( + 'pgadmin:server:connect:cancelled', i, d, self + ); + t.select(i); + }); + } + } } - }; + } + }); + function connect_to_server(obj, data, tree, item, reconnect) { + var wasConnected = reconnect || data.connected, + onFailure = function( + xhr, status, error, _node, _data, _tree, _item, _wasConnected + ) { + data.connected = false; + + // It should be attempt to reconnect. + // Let's not change the status of the tree node now. + if (!_wasConnected) { + tree.setInode(_item); + tree.addIcon(_item, {icon: 'icon-server-not-connected'}); + } + + alertify.pgNotifier('error', xhr, error, function(msg) { + setTimeout(function() { + alertify.dlgServerPass( + '{{ _('Connect to Server') }}', + msg, _node, _data, _tree, _item, _wasConnected + ).resizeTo(); + }, 100); + }); + }, + onSuccess = function(res, node, data, tree, item, _wasConnected) { + if (res && res.data) { + if (typeof res.data.icon == 'string') { + tree.removeIcon(item); + data.icon = res.data.icon; + tree.addIcon(item, {icon: data.icon}); + } + + _.extend(data, res.data); + data.is_connecting = false; + + var serverInfo = pgBrowser.serverInfo = + pgBrowser.serverInfo || {}; + serverInfo[data._id] = _.extend({}, data); + + alertify.success(res.info); + obj.trigger('connected', obj, item, data); + + // Generate the event that server is connected + pgBrowser.Events.trigger( + 'pgadmin:server:connected', data._id, item, data + ); + // Generate the event that database is connected + pgBrowser.Events.trigger( + 'pgadmin:database:connected', data._id, data.db, item, data + ); + + // We're not reconnecting + if (!_wasConnected) { + tree.setInode(item); + tree.deselect(item); + + setTimeout(function() { + tree.select(item); + tree.open(item); + }, 10); + } else { + // We just need to refresh the tree now. + setTimeout(function() { + node.callbacks.refresh.apply(node, [true]); + }, 10); + } + } + }; // Ask Password and send it back to the connect server if (!alertify.dlgServerPass) { alertify.dialog('dlgServerPass', function factory() { return { - main: function(title, message, model, data, tree, item) { + main: function( + title, message, node, data, tree, item, + _status, _onSuccess, _onFailure, _onCancel + ) { this.set('title', title); this.message = message; this.tree = tree; this.nodeData = data; this.nodeItem = item; - this.nodeModel = model; + this.node= node; + this.connected = _status; + this.onSuccess = _onSuccess || onSuccess; + this.onFailure = _onFailure || onFailure; + this.onCancel = _onCancel || onCancel; }, setup:function() { return { @@ -791,18 +907,24 @@ function($, _, S, pgAdmin, pgBrowser, alertify) { this.setContent(this.message); }, callback: function(closeEvent) { - var _sdata = this.nodeData, - _tree = this.tree, + var _tree = this.tree, _item = this.nodeItem, - _model = this.nodeModel; + _node = this.node, + _data = this.nodeData, + _status = this.connected, + _onSuccess = this.onSuccess, + _onFailure = this.onFailure, + _onCancel = this.onCancel; if (closeEvent.button.text == "{{ _('OK') }}") { - var _url = _model.generate_url(_item, 'connect', _sdata, true); + var _url = _node.generate_url(_item, 'connect', _data, true); - _tree.setLeaf(_item); - _tree.removeIcon(_item); - _tree.addIcon(_item, {icon: 'icon-server-connecting'}); + if (!_status) { + _tree.setLeaf(_item); + _tree.removeIcon(_item); + _tree.addIcon(_item, {icon: 'icon-server-connecting'}); + } $.ajax({ type: 'POST', @@ -810,38 +932,58 @@ function($, _, S, pgAdmin, pgBrowser, alertify) { url: _url, data: $('#frmPassword').serialize(), success: function(res) { - return onSuccess( - res, _model, _sdata, _tree, _item + return _onSuccess( + res, _node, _data, _tree, _item, _status ); }, error: function(xhr, status, error) { - return onFailure( - xhr, status, error, _model, _sdata, _tree, _item + return _onFailure( + xhr, status, error, _node, _data, _tree, _item, _status ); } }); } else { - _tree.setInode(_item); - _tree.removeIcon(_item); - _tree.addIcon(_item, {icon: 'icon-server-not-connected'}); + this.onCancel && typeof(this.onCancel) == 'function' && + this.onCancel(_tree, _item, _data, _status); } } }; }); } + var onCancel = function(_tree, _item, _data, _status) { + _data.is_connecting = false; + _tree.unload(_item); + _tree.setInode(_item); + _tree.removeIcon(_item); + _tree.addIcon(_item, {icon: 'icon-server-not-connected'}); + obj.trigger('connect:cancelled', data._id, data.db, obj, _item, _data); + pgBrowser.Events.trigger( + 'pgadmin:server:connect:cancelled', data._id, _item, _data, obj + ); + pgBrowser.Events.trigger( + 'pgadmin:database:connect:cancelled', data._id, data.db, _item, _data, obj + ); + if (_status) { + _tree.select(_item); + } + }; + + data.is_connecting = true; url = obj.generate_url(item, "connect", data, true); $.post(url) - .done( - function(res) { - if (res.success == 1) { - return onSuccess(res, obj, data, tree, item); - } - }) - .fail( - function(xhr, status, error) { - return onFailure(xhr, status, error, obj, data, tree, item); - }); + .done(function(res) { + if (res.success == 1) { + return onSuccess( + res, obj, data, tree, item, wasConnected + ); + } + }) + .fail(function(xhr, status, error) { + return onFailure( + xhr, status, error, obj, data, tree, item, wasConnected + ); + }); } /* Send PING to indicate that session is alive */ diff --git a/web/pgadmin/browser/server_groups/servers/templates/servers/sql/9.1_plus/stats.sql b/web/pgadmin/browser/server_groups/servers/templates/servers/sql/9.1_plus/stats.sql index f8d4a6abe..54447ba72 100644 --- a/web/pgadmin/browser/server_groups/servers/templates/servers/sql/9.1_plus/stats.sql +++ b/web/pgadmin/browser/server_groups/servers/templates/servers/sql/9.1_plus/stats.sql @@ -1,8 +1,8 @@ SELECT - procpid AS "{{ conn|qtIdent('PID') }}, - usename AS "{{ conn|qtIdent(_('User')|safe) }}, - datname AS "{{ conn|qtIdent(_('Database')|safe) }}, - backend_start AS "{{ conn|qtIdent(_('Backend start')|safe) }}, + procpid AS {{ conn|qtIdent('PID') }}, + usename AS {{ conn|qtIdent(_('User')) }}, + datname AS {{ conn|qtIdent(_('Database')) }}, + backend_start AS {{ conn|qtIdent(_('Backend start')) }}, CASE WHEN client_hostname IS NOT NULL AND client_hostname != '' THEN client_hostname || ':' || client_port @@ -12,22 +12,22 @@ SELECT 'local pipe' ELSE 'localhost:' || client_port - END AS "{{ conn|qtIdent(_('Client')|safe) }}, - application_name AS "{{ conn|qtIdent(_('Application')|safe) }}, - waiting AS "{{ conn|qtIdent(_('Waiting?')|safe) }}, - current_query AS "{{ conn|qtIdent(_('Query')|safe) }}, - query_start AS "{{ conn|qtIdent(_('Query start')|safe) }}, - xact_start AS "{{ conn|qtIdent(_('Xact start')|safe) }} + END AS {{ conn|qtIdent(_('Client')) }}, + application_name AS {{ conn|qtIdent(_('Application')) }}, + waiting AS {{ conn|qtIdent(_('Waiting?')) }}, + current_query AS {{ conn|qtIdent(_('Query')) }}, + query_start AS {{ conn|qtIdent(_('Query start')) }}, + xact_start AS {{ conn|qtIdent(_('Xact start')) }} FROM pg_stat_activity sa WHERE (SELECT r.rolsuper OR r.oid = sa.usesysid FROM pg_roles r WHERE r.rolname = current_user) UNION SELECT - procpid AS "{{ conn|qtIdent('PID') }}, - usename AS "{{ conn|qtIdent(_('User')|safe) }}, - '' AS "{{ conn|qtIdent(_('Database')|safe) }}, - backend_start AS "{{ conn|qtIdent(_('Backend start')|safe) }}, + procpid AS "PID", + usename AS {{ conn|qtIdent(_('User')) }}, + datname AS {{ conn|qtIdent(_('Database')) }}, + backend_start AS {{ conn|qtIdent(_('Backend start')) }}, CASE WHEN client_hostname IS NOT NULL AND client_hostname != '' THEN client_hostname || ':' || client_port @@ -37,12 +37,12 @@ SELECT 'local pipe' ELSE 'localhost:' || client_port - END AS "{{ conn|qtIdent(_('Client')|safe) }}, - {{ _('Streaming Replication') }}|safe|qtLiteral AS "{{ conn|qtIdent(_('Application')|safe) }}, - null AS "{{ conn|qtIdent(_('Waiting?')|safe) }}, - state || ' [sync (state: ' || COALESCE(sync_state, '') || ', priority: ' || sync_priority::text || ')] (' || sent_location || ' sent, ' || write_location || ' written, ' || flush_location || ' flushed, ' || replay_location || ' applied)' AS "{{ conn|qtIdent(_('Query')|safe) }}, - null AS "{{ conn|qtIdent(_('Query start')|safe) }}, - null AS "{{ conn|qtIdent(_('Xact start')|safe) }} + END AS {{ conn|qtIdent(_('Client')) }}, + {{ _('Streaming Replication') }}|qtLiteral AS {{ conn|qtIdent(_('Application')) }}, + null AS {{ conn|qtIdent(_('Waiting?')) }}, + state || ' [sync (state: ' || COALESCE(sync_state, '') || ', priority: ' || sync_priority::text || ')] (' || sent_location || ' sent, ' || write_location || ' written, ' || flush_location || ' flushed, ' || replay_location || ' applied)' AS {{ conn|qtIdent(_('Query')) }}, + null AS {{ conn|qtIdent(_('Query start')) }}, + null AS {{ conn|qtIdent(_('Xact start')) }} FROM pg_stat_replication sa WHERE diff --git a/web/pgadmin/browser/server_groups/servers/templates/servers/sql/9.2_plus/stats.sql b/web/pgadmin/browser/server_groups/servers/templates/servers/sql/9.2_plus/stats.sql index 79ab873c0..0b397f670 100644 --- a/web/pgadmin/browser/server_groups/servers/templates/servers/sql/9.2_plus/stats.sql +++ b/web/pgadmin/browser/server_groups/servers/templates/servers/sql/9.2_plus/stats.sql @@ -1,8 +1,8 @@ SELECT - pid AS {{ conn|qtIdent('PID') }}, - usename AS {{ conn|qtIdent(_('User')|safe) }}, - datname AS {{ conn|qtIdent(_('Database')|safe) }}, - backend_start AS {{ conn|qtIdent(_('Backend start')|safe) }}, + pid AS "PID", + usename AS {{ conn|qtIdent(_('User')) }}, + datname AS {{ conn|qtIdent(_('Database')) }}, + backend_start AS {{ conn|qtIdent(_('Backend start')) }}, CASE WHEN client_hostname IS NOT NULL AND client_hostname != '' THEN client_hostname || ':' || client_port @@ -12,22 +12,22 @@ SELECT 'local pipe' ELSE 'localhost:' || client_port - END AS {{ conn|qtIdent(_('Client')|safe) }}, - application_name AS {{ conn|qtIdent(_('Application')|safe) }}, - waiting AS {{ conn|qtIdent(_('Waiting?')|safe) }}, - query AS {{ conn|qtIdent(_('Query')|safe) }}, - query_start AS {{ conn|qtIdent(_('Query start')|safe) }}, - xact_start AS {{ conn|qtIdent(_('Xact start')|safe) }} + END AS {{ conn|qtIdent(_('Client')) }}, + application_name AS {{ conn|qtIdent(_('Application')) }}, + waiting AS {{ conn|qtIdent(_('Waiting?')) }}, + query AS {{ conn|qtIdent(_('Query')) }}, + query_start AS {{ conn|qtIdent(_('Query start')) }}, + xact_start AS {{ conn|qtIdent(_('Xact start')) }} FROM pg_stat_activity sa WHERE (SELECT r.rolsuper OR r.oid = sa.usesysid FROM pg_roles r WHERE r.rolname = current_user) UNION SELECT - pid AS {{ conn|qtIdent('PID') }}, - usename AS {{ conn|qtIdent(_('User')|safe) }}, - '' AS {{ conn|qtIdent(_('Database')|safe) }}, - backend_start AS {{ conn|qtIdent(_('Backend start')|safe) }}, + pid AS "PID", + usename AS {{ conn|qtIdent(_('User')) }}, + '' AS {{ conn|qtIdent(_('Database')) }}, + backend_start AS {{ conn|qtIdent(_('Backend start')) }}, CASE WHEN client_hostname IS NOT NULL AND client_hostname != '' THEN client_hostname || ':' || client_port @@ -37,12 +37,12 @@ SELECT 'local pipe' ELSE 'localhost:' || client_port - END AS {{ conn|qtIdent(_('Client')|safe) }}, - {{ _('Streaming Replication')|safe|qtLiteral }} AS {{ conn|qtIdent(_('Application')|safe) }}, - null AS {{ conn|qtIdent(_('Waiting?')|safe) }}, - state || ' [sync (state: ' || COALESCE(sync_state, '') || ', priority: ' || sync_priority::text || ')] (' || sent_location || ' sent, ' || write_location || ' written, ' || flush_location || ' flushed, ' || replay_location || ' applied)' AS {{ conn|qtIdent(_('Query')|safe) }}, - null AS {{ conn|qtIdent(_('Query start')|safe) }}, - null AS {{ conn|qtIdent(_('Xact start')|safe) }} + END AS {{ conn|qtIdent(_('Client')) }}, + {{ _('Streaming Replication')|qtLiteral }} AS {{ conn|qtIdent(_('Application')) }}, + null AS {{ conn|qtIdent(_('Waiting?')) }}, + state || ' [sync (state: ' || COALESCE(sync_state, '') || ', priority: ' || sync_priority::text || ')] (' || sent_location || ' sent, ' || write_location || ' written, ' || flush_location || ' flushed, ' || replay_location || ' applied)' AS {{ conn|qtIdent(_('Query')) }}, + null AS {{ conn|qtIdent(_('Query start')) }}, + null AS {{ conn|qtIdent(_('Xact start')) }} FROM pg_stat_replication sa WHERE diff --git a/web/pgadmin/browser/templates/browser/js/browser.js b/web/pgadmin/browser/templates/browser/js/browser.js index c319ceb06..e1f1b3820 100644 --- a/web/pgadmin/browser/templates/browser/js/browser.js +++ b/web/pgadmin/browser/templates/browser/js/browser.js @@ -335,7 +335,11 @@ function(require, $, _, S, Bootstrap, pgAdmin, alertify, CodeMirror) { url: '{{ url_for('browser.get_nodes') }}', converters: { 'text json': function(payload) { - data = JSON.parse(payload).data; + data = JSON.parse(payload).data.sort(function(a, b) { + return ( + (a.label === b.label) ? 0 : (a.label < b.label ? -1 : 1) + ); + }); _.each(data, function(d){ d.label = _.escape(d.label); }) diff --git a/web/pgadmin/browser/templates/browser/js/collection.js b/web/pgadmin/browser/templates/browser/js/collection.js index 12c80b7db..84a214018 100644 --- a/web/pgadmin/browser/templates/browser/js/collection.js +++ b/web/pgadmin/browser/templates/browser/js/collection.js @@ -114,14 +114,24 @@ function($, _, S, pgAdmin, Backbone, Alertify, Backform) { // Fetch Data collection.fetch({reset: true}) - .error(function(jqxhr, error, message) { + .error(function(xhr, error, message) { + pgBrowser.Events.trigger( + 'pgadmin:collection:retrieval:error', 'properties', xhr, error, message, item, that + ); + if ( + !Alertify.pgHandleItemError(xhr, error, message, {item: item, info: info}) + ) { Alertify.pgNotifier( - error, jqxhr, + error, xhr, S( - "{{ _("Error retrieving properties: %s.") }}" - ).sprintf(message).value() - ); - }); + "{{ _("Error retrieving properties- %s") }}" + ).sprintf(message || that.label).value(), + function() { + console.log(arguments); + } + ); + } + }); }, generate_url: function(item, type, d) { var url = pgAdmin.Browser.URL + '{TYPE}/{REDIRECT}{REF}', diff --git a/web/pgadmin/browser/templates/browser/js/messages.js b/web/pgadmin/browser/templates/browser/js/messages.js index cac7994b7..4a1950407 100644 --- a/web/pgadmin/browser/templates/browser/js/messages.js +++ b/web/pgadmin/browser/templates/browser/js/messages.js @@ -14,8 +14,8 @@ function(_, S, pgAdmin) { 'SQL_TAB': '{{ _('SQL') }}', 'SQL_INCOMPLETE': '{{ _('Incomplete definition') }}', 'SQL_NO_CHANGE': '{{ _('Nothing changed')|safe }}', - 'MUST_BE_INT' : "{{ _("'%s' must be an integer.")|safe }}", - 'MUST_BE_NUM' : "{{ _("'%s' must be a numeric.")|safe }}", + 'MUST_BE_INT' : "{{ _("'%s' must be an integer.") }}", + 'MUST_BE_NUM' : "{{ _("'%s' must be a numeric.") }}", 'MUST_GR_EQ' : "{{ _("'%s' must be greater than or equal to %d.")|safe }}", 'MUST_LESS_EQ' : "{{ _("'%s' must be less than or equal to %d.")|safe }}", 'STATISTICS_LABEL': "{{ _("Statistics") }}", @@ -24,12 +24,13 @@ function(_, S, pgAdmin) { 'NODE_HAS_NO_STATISTICS': "{{ _("No statistics are available for the selected object.") }}", 'TRUE': "{{ _("True") }}", 'FALSE': "{{ _("False") }}", - 'NOTE_CTRL_LABEL': "{{ _("Note") }}" + 'NOTE_CTRL_LABEL': "{{ _("Note") }}", + 'ERR_RETRIEVAL_INFO': "{{ _("Error retrieving the information- %s") }}", + 'CONNECTION_LOST': "{{ _("Connection to the server has been lost!") }}" }; {% for key in current_app.messages.keys() %} - messages['{{ key|safe }}'] = '{{ current_app.messages[key]|safe }}'; - + messages['{{ key }}'] = '{{ current_app.messages[key] }}'; {% endfor %} return pgBrowser.messages; diff --git a/web/pgadmin/browser/templates/browser/js/node.js b/web/pgadmin/browser/templates/browser/js/node.js index 06152f6c6..e53d465d5 100644 --- a/web/pgadmin/browser/templates/browser/js/node.js +++ b/web/pgadmin/browser/templates/browser/js/node.js @@ -36,6 +36,14 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, pgBrowser, Backform) { // Make sure - a child have all the callbacks of the parent. child.callbacks = _.extend({}, parent.callbacks, props.callbacks); + var bindToChild = function(cb) { + if (typeof(child.callbacks[cb]) == 'function') { + child.callbacks[cb] = child.callbacks[cb].bind(child); + } + }, + callbacks = _.keys(child.callbacks); + for(var idx = 0; idx < callbacks.length; idx++) bindToChild(callbacks[idx]); + // Registering the node by calling child.Init(...) function child.Init.apply(child); @@ -174,7 +182,7 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, pgBrowser, Backform) { // // Used to generate view for the particular node properties, edit, // creation. - getView: function(item, type, el, node, formType, callback, ctx) { + getView: function(item, type, el, node, formType, callback, ctx, cancelFunc) { var that = this; if (!this.type || this.type == '') @@ -265,24 +273,43 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, pgBrowser, Backform) { if (!newModel.isNew()) { // This is definetely not in create mode newModel.fetch() - .success(function(res, msg, xhr) { - // We got the latest attributes of the - // object. Render the view now. - view.render(); - if (type != 'properties') { - $(el).focus(); - } - newModel.startNewSession(); - }) - .error(function(jqxhr, error, message) { - // TODO:: We may not want to continue from here + .success(function(res, msg, xhr) { + // We got the latest attributes of the + // object. Render the view now. + view.render(); + if (type != 'properties') { + $(el).focus(); + } + newModel.startNewSession(); + }) + .error(function(xhr, error, message) { + var _label = that && item ? + that.getTreeNodeHierarchy(item)[that.type].label : + ''; + pgBrowser.Events.trigger( + 'pgadmin:node:retrieval:error', 'properties', + xhr, error, message, item + ); + if ( + !Alertify.pgHandleItemError( + xhr, error, message, {item: item, info: info} + ) + ) { Alertify.pgNotifier( - error, jqxhr, + error, xhr, S( - "{{ _("Error retrieving properties: %s.") }}" - ).sprintf(message).value() - ); - }); + "{{ _("Error retrieving properties- %s") }}" + ).sprintf(message || _label).value(), + function() { + console.log(arguments); + } + ); + } + // Close the panel (if couldn't fetch properties) + if (cancelFunc) { + cancelFunc(); + } + }); } else { // Yay - render the view now! $(el).focus(); @@ -1039,7 +1066,7 @@ function($, _, S, pgAdmin, Menu, Backbone, Alertify, pgBrowser, Backform) { }; // Create a view to edit/create the properties in fieldsets - view = that.getView(item, action, content, data, 'dialog', updateButtons, j); + view = that.getView(item, action, content, data, 'dialog', updateButtons, j, onCancelFunc); if (view) { // Save it to release it later j.data('obj-view', view); diff --git a/web/pgadmin/misc/depends/static/js/depends.js b/web/pgadmin/misc/depends/static/js/depends.js index 3acd30964..d68d641d0 100644 --- a/web/pgadmin/misc/depends/static/js/depends.js +++ b/web/pgadmin/misc/depends/static/js/depends.js @@ -1,6 +1,7 @@ -define( - ['underscore', 'underscore.string', 'jquery', 'pgadmin.browser'], - function(_, S, $, pgBrowser) { +define([ + 'underscore', 'underscore.string', 'jquery', 'pgadmin.browser', + 'alertify', 'pgadmin.alertifyjs' +], function(_, S, $, pgBrowser, Alertify) { if (pgBrowser.ShowNodeDepends) return pgBrowser.ShowNodeDepends; @@ -226,7 +227,30 @@ define( $gridContainer.removeClass('hidden'); // Set the url, fetch the data and update the collection collection.url = url; - collection.fetch({ reset: true }); + collection.fetch({ + reset: true, + error: function(coll, xhr, error, message) { + var _label = treeHierarchy[n_type].label; + pgBrowser.Events.trigger( + 'pgadmin:node:retrieval:error', 'depends', xhr, status, error + ); + if ( + !Alertify.pgHandleItemError(xhr, error, message, { + item: item, info: treeHierarchy + }) + ) { + Alertify.pgNotifier( + status, xhr, + S( + pgBrowser.messages['ERR_RETRIEVAL_INFO'] + ).sprintf(message || _label).value(), + function() { + console.log(arguments); + } + ); + } + } + }); } } if (msg != '') { diff --git a/web/pgadmin/misc/sql/static/js/sql.js b/web/pgadmin/misc/sql/static/js/sql.js index a6db15016..0766daf29 100644 --- a/web/pgadmin/misc/sql/static/js/sql.js +++ b/web/pgadmin/misc/sql/static/js/sql.js @@ -1,6 +1,7 @@ -define( - ['underscore', 'jquery', 'pgadmin.browser'], -function(_, $, pgBrowser) { +define([ + 'underscore', 'underscore.string', 'jquery', 'pgadmin.browser', + 'alertify', 'pgadmin.alertifyjs' +], function(_, S, $, pgBrowser, Alertify) { pgBrowser.ShowNodeSQL = pgBrowser.ShowNodeSQL || {}; @@ -84,8 +85,26 @@ function(_, $, pgBrowser) { pgAdmin.Browser.editor.setValue(res); } }, - error: function() { - // TODO:: Report this + error: function(xhr, error, message) { + var _label = treeHierarchy[n_type].label; + pgBrowser.Events.trigger( + 'pgadmin:node:retrieval:error', 'sql', xhr, status, error, item + ); + if ( + !Alertify.pgHandleItemError(xhr, error, message, { + item: item, info: treeHierarchy + }) + ) { + Alertify.pgNotifier( + status, xhr, + S( + pgBrowser.messages['ERR_RETRIEVAL_INFO'] + ).sprintf(message || _label).value(), + function() { + console.log(arguments); + } + ); + } } }); } diff --git a/web/pgadmin/misc/statistics/static/js/statistics.js b/web/pgadmin/misc/statistics/static/js/statistics.js index c1a032717..652b7202d 100644 --- a/web/pgadmin/misc/statistics/static/js/statistics.js +++ b/web/pgadmin/misc/statistics/static/js/statistics.js @@ -1,6 +1,7 @@ -define( - ['underscore', 'jquery', 'pgadmin.browser', 'backgrid', 'wcdocker', 'pgadmin.backgrid'], -function(_, $, pgBrowser, Backgrid) { +define([ + 'underscore', 'underscore.string', 'jquery', 'pgadmin.browser', 'backgrid', + 'alertify', 'wcdocker', 'pgadmin.backgrid', 'pgadmin.alertifyjs' +], function(_, S, $, pgBrowser, Backgrid, Alertify) { if (pgBrowser.NodeStatistics) return pgBrowser.NodeStatistics; @@ -210,8 +211,26 @@ function(_, $, pgBrowser, Backgrid) { $msgContainer.removeClass('hidden'); } }, - error: function() { - // TODO:: Report this error. + error: function(xhr, error, message) { + var _label = treeHierarchy[n_type].label; + pgBrowser.Events.trigger( + 'pgadmin:node:retrieval:error', 'statistics', xhr, status, error, item + ); + if ( + !Alertify.pgHandleItemError(xhr, error, message, { + item: item, info: treeHierarchy + }) + ) { + Alertify.pgNotifier( + status, xhr, + S( + pgBrowser.messages['ERR_RETRIEVAL_INFO'] + ).sprintf(message || _label).value(), + function() { + console.log(arguments); + } + ); + } } }); } diff --git a/web/pgadmin/static/js/alertifyjs/pgadmin.defaults.js b/web/pgadmin/static/js/alertifyjs/pgadmin.defaults.js index f1b7472ba..d7e961481 100644 --- a/web/pgadmin/static/js/alertifyjs/pgadmin.defaults.js +++ b/web/pgadmin/static/js/alertifyjs/pgadmin.defaults.js @@ -95,7 +95,7 @@ function(alertify, S) { if (contentType) { try { - if (contentType.indexOf('text/json') == 0) { + if (contentType.indexOf('application/json') == 0) { resp = $.parseJSON(msg); if (resp.result != null && (!resp.errormsg || resp.errormsg == '') && @@ -104,17 +104,19 @@ function(alertify, S) { } msg = _.escape(resp.result) || _.escape(resp.errormsg) || "Unknown error"; } - } catch (exc) { - } - - if (contentType.indexOf('text/html') == 0) { - alertify.notify( + if (contentType.indexOf('text/html') == 0) { + alertify.notify( S( - '%s

' + window.pgAdmin.Browser.messages.CLICK_FOR_DETAILED_MSG - ).sprintf(promptmsg).value(), type, 0, function() { - alertify.pgIframeDialog().show().set({ frameless: false }).set('pg_msg', msg); + '%s

' + + window.pgAdmin.Browser.messages.CLICK_FOR_DETAILED_MSG + ).sprintf(promptmsg).value(), type, 0, function() { + alertify.pgIframeDialog().show().set({frameless: false}).set( + 'pg_msg', msg + ); }); - return; + return; + } + } catch (exc) { } } alertify.alert().show().set( @@ -185,4 +187,125 @@ function(alertify, S) { this.set('onrestored', alertifyDialogResized); }; + alertify.pgHandleItemError = function(xhr, error, message, args) { + var pgBrowser = window.pgAdmin.Browser; + + if (!xhr || !pgBrowser) { + return; + } + + var msg = xhr.responseText, + contentType = xhr.getResponseHeader('Content-Type'), + msg = xhr.responseText, + jsonResp = contentType && + contentType.indexOf('application/json') == 0 && + $.parseJSON(xhr.responseText); + + if ( + jsonResp && ( + xhr.status == 503 ? ( + jsonResp.info == 'CONNECTION_LOST' && + 'server' in args.info && jsonResp.data.sid >= 0 && + jsonResp.data.sid == args.info.server._id + ) : ( + xhr.status == 428 && + jsonResp.errormsg && + jsonResp.errormsg == pgBrowser.messages.CONNECTION_LOST + ) + ) + ) { + if ( + args.preHandleConnectionLost && + typeof(args.preHandleConnectionLost) == 'function' + ) { + args.preHandleConnectionLost.apply(this, arguments); + } + + // Check the status of the maintenance server connection. + var server = pgBrowser.Nodes['server'], + ctx = { + resp: jsonResp, + xhr: xhr, + args: args + }, + reconnectServer = function() { + var ctx = this, + onServerConnect = function(_sid, _i, _d) { + // Yay - server is reconnected. + if (this.args.info.server._id == _sid) { + pgBrowser.Events.off( + 'pgadmin:server:connected', onServerConnect + ); + pgBrowser.Events.off( + 'pgadmin:server:connect:cancelled', onConnectCancel + ); + + // Do we need to connect the disconnected server now? + if ( + this.resp.data.database && + this.resp.data.database != _d.db + ) { + // Server is connected now, we will need to inform the + // database to connect it now. + pgBrowser.Events.trigger( + 'pgadmin:database:connection:lost', this.args.item, + this.resp, true + ); + } + } + }.bind(ctx), + onConnectCancel = function(_sid, _item, _data) { + // User has cancelled the operation in between. + if (_sid == this.args.info.server.id) { + pgBrowser.Events.off('pgadmin:server:connected', onServerConnect); + pgBrowser.Events.off('pgadmin:server:connect:cancelled', onConnectCancel); + + // Connection to the database will also be cancelled + pgBrowser.Events.trigger( + 'pgadmin:database:connect:cancelled', _sid, + this.resp.data.database || _data.db, _item, _data + ); + } + }.bind(ctx); + + pgBrowser.Events.on('pgadmin:server:connected', onServerConnect); + pgBrowser.Events.on('pgadmin:server:connect:cancelled', onConnectCancel); + + // Connection to the server has been lost, we need to inform the + // server first to take the action first. + pgBrowser.Events.trigger( + 'pgadmin:server:connection:lost', this.args.item, this.resp + ); + }.bind(ctx); + + $.ajax({ + url: server.generate_url( + null, 'connect', args.info.server, true, args.info + ), + dataType: 'json', + success: function(res) { + if (res.success && 'connected' in res.data) { + if (res.data.connected) { + // Server is connected, but - the connection with the + // particular database has been lost. + pgBrowser.Events.trigger( + 'pgadmin:database:connection:lost', args.item, jsonResp + ); + return; + } + } + + // Serever was not connected, we should first try to connect + // the server. + reconnectServer(); + }, + error: function() { + reconnectServer(); + } + }); + return true; + } + return false; + }; + }); diff --git a/web/pgadmin/utils/ajax.py b/web/pgadmin/utils/ajax.py index 01e955651..0e11eac24 100644 --- a/web/pgadmin/utils/ajax.py +++ b/web/pgadmin/utils/ajax.py @@ -30,8 +30,9 @@ class DataTypeJSONEncoder(json.JSONEncoder): return json.JSONEncoder.default(self, obj) -def make_json_response(success=1, errormsg='', info='', result=None, - data=None, status=200): +def make_json_response( + success=1, errormsg='', info='', result=None, data=None, status=200 +): """Create a HTML response document describing the results of a request and containing the data.""" doc = dict() @@ -44,7 +45,7 @@ def make_json_response(success=1, errormsg='', info='', result=None, return Response( response=json.dumps(doc, cls=DataTypeJSONEncoder), status=status, - mimetype="text/json" + mimetype="application/json" ) @@ -53,7 +54,7 @@ def make_response(response=None, status=200): return Response( response=json.dumps(response, cls=DataTypeJSONEncoder), status=status, - mimetype="text/json" + mimetype="application/json" ) @@ -120,10 +121,25 @@ def gone(errormsg=''): ) -def not_implemented(errormsg=_('Not implemented.')): +def not_implemented(errormsg=_('Not implemented.'), info='', result=None, data=None): """Create a response with HTTP status code 501 - Not Implemented.""" return make_json_response( status=501, success=0, - errormsg=errormsg + errormsg=errormsg, + info=info, + result=result, + data=data + ) + + +def service_unavailable(errormsg=_("Service Unavailable"), info='', result=None, data=None): + """Create a response with HTTP status code 503 - Server Unavailable.""" + return make_json_response( + status=503, + success=0, + errormsg=errormsg, + info=info, + result=result, + data=data ) diff --git a/web/pgadmin/utils/driver/psycopg2/__init__.py b/web/pgadmin/utils/driver/psycopg2/__init__.py index 05622e607..e3a9e966e 100644 --- a/web/pgadmin/utils/driver/psycopg2/__init__.py +++ b/web/pgadmin/utils/driver/psycopg2/__init__.py @@ -30,6 +30,7 @@ from psycopg2.extensions import adapt import config from pgadmin.model import Server, User +from pgadmin.utils.exception import ConnectionLost from .keywords import ScanKeyword from ..abstract import BaseDriver, BaseConnection from .cursor import DictCursor @@ -179,6 +180,7 @@ class Connection(BaseConnection): self.execution_aborted = False self.row_count = 0 self.__notices = None + self.password = None super(Connection, self).__init__() @@ -225,10 +227,13 @@ class Connection(BaseConnection): password = None mgr = self.manager - if 'password' in kwargs: - encpass = kwargs['password'] - else: - encpass = getattr(mgr, 'password', None) + encpass = kwargs['password'] if 'password' in kwargs else None + + if encpass is None: + encpass = self.password or getattr(mgr, 'password', None) + + # Reset the existing connection password + self.password = None if encpass: # Fetch Logged in User Details. @@ -239,6 +244,10 @@ class Connection(BaseConnection): try: password = decrypt(encpass, user.password) + + # password is in bytes, for python3 we need it in string + if isinstance(password, bytes): + password = password.decode() except Exception as e: current_app.logger.exception(e) return False, \ @@ -246,10 +255,6 @@ class Connection(BaseConnection): str(e) ) - # password is in bytes, for python3 we need it in string - if isinstance(password, bytes): - password = password.decode() - try: if hasattr(str, 'decode'): database = self.db.encode('utf-8') @@ -401,11 +406,18 @@ WHERE mgr.server_cls = st break + mgr._update_password(encpass) mgr.update_session() return True, None def __cursor(self, server_cursor=False): + if not self.conn: + raise ConnectionLost( + self.manager.sid, + self.db, + None if self.conn_id[0:3] == u'DB:' else self.conn_id[5:] + ) cur = getattr(g, "{0}#{1}".format( self.manager.sid, self.conn_id.encode('utf-8') @@ -475,7 +487,7 @@ Attempting to reconnect to the database server (#{server_id}) for the connection Connection for server#{0} with database "{1}" was lost. Attempt to reconnect it failed with the error: {2}""" - ).format(self.driver.server_id, self.database, cur) + ).format(self.driver.server_id, self.db, cur) current_app.logger.error(msg) return False, cur @@ -593,6 +605,12 @@ Attempt to reconnect it failed with the error: self.__internal_blocking_execute(cur, query, params) except psycopg2.Error as pe: cur.close() + if not self.connected(): + raise ConnectionLost( + self.manager.sid, + self.db, + None if self.conn_id[0:3] == u'DB:' else self.conn_id[5:] + ) errmsg = self._formatted_exception_msg(pe, formatted_exception_msg) current_app.logger.error( u"Failed to execute query (execute_scalar) for the server #{server_id} - {conn_id} (Query-id: {query_id}):\nError Message:{errmsg}".format( @@ -694,6 +712,12 @@ Failed to execute query (execute_async) for the server #{server_id} - {conn_id} self.__internal_blocking_execute(cur, query, params) except psycopg2.Error as pe: cur.close() + if not self.connected(): + raise ConnectionLost( + self.manager.sid, + self.db, + None if self.conn_id[0:3] == u'DB:' else self.conn_id[5:] + ) errmsg = self._formatted_exception_msg(pe, formatted_exception_msg) current_app.logger.error(u""" Failed to execute query (execute_void) for the server #{server_id} - {conn_id} @@ -733,6 +757,12 @@ Failed to execute query (execute_void) for the server #{server_id} - {conn_id} self.__internal_blocking_execute(cur, query, params) except psycopg2.Error as pe: cur.close() + if not self.connected(): + raise ConnectionLost( + self.manager.sid, + self.db, + None if self.conn_id[0:3] == u'DB:' else self.conn_id[5:] + ) errmsg = self._formatted_exception_msg(pe, formatted_exception_msg) current_app.logger.error( u"Failed to execute query (execute_2darray) for the server #{server_id} - {conn_id} (Query-id: {query_id}):\nError Message:{errmsg}".format( @@ -778,6 +808,12 @@ Failed to execute query (execute_void) for the server #{server_id} - {conn_id} self.__internal_blocking_execute(cur, query, params) except psycopg2.Error as pe: cur.close() + if not self.connected(): + raise ConnectionLost( + self.manager.sid, + self.db, + None if self.conn_id[0:3] == u'DB:' else self.conn_id[5:] + ) errmsg = self._formatted_exception_msg(pe, formatted_exception_msg) current_app.logger.error( u"Failed to execute query (execute_dict) for the server #{server_id}- {conn_id} (Query-id: {query_id}):\nError Message:{errmsg}".format( @@ -867,6 +903,7 @@ Failed to reset the connection to the server due to following error: if self.conn: self.conn.close() self.conn = None + self.password = None def _wait(self, conn): """ @@ -942,6 +979,12 @@ Failed to reset the connection to the server due to following error: try: status = self._wait_timeout(self.conn, ASYNC_WAIT_TIMEOUT) except psycopg2.Error as pe: + if cur.closed: + raise ConnectionLost( + self.manager.sid, + self.db, + self.conn_id[5:] + ) errmsg = self._formatted_exception_msg(pe, formatted_exception_msg) return False, errmsg, None @@ -1242,10 +1285,6 @@ class ServerManager(object): self, database=None, conn_id=None, auto_reconnect=True, did=None, async=None ): - msg_active_conn = gettext( - "Server has no active connection. Please connect to the server." - ) - if database is not None: if hasattr(str, 'decode') and \ not isinstance(database, unicode): @@ -1285,7 +1324,7 @@ WHERE db.oid = {0}""".format(did)) )) if database is None: - raise Exception(msg_active_conn) + raise ConnectionLost(self.sid, None, None) my_id = (u'CONN:{0}'.format(conn_id)) if conn_id is not None else \ (u'DB:{0}'.format(database)) @@ -1387,6 +1426,13 @@ WHERE db.oid = {0}""".format(did)) return True + def _update_password(self, passwd): + self.password = passwd + for conn_id in self.connections: + conn = self.connections[conn_id] + if conn.conn is not None: + conn.password = passwd + def update_session(self): managers = session['__pgsql_server_managers'] \ if '__pgsql_server_managers' in session else dict() diff --git a/web/pgadmin/utils/exception.py b/web/pgadmin/utils/exception.py new file mode 100644 index 000000000..662ddec1c --- /dev/null +++ b/web/pgadmin/utils/exception.py @@ -0,0 +1,42 @@ +########################################################################## +# +# pgAdmin 4 - PostgreSQL Tools +# +# Copyright (C) 2013 - 2016, The pgAdmin Development Team +# This software is released under the PostgreSQL Licence +# +########################################################################## + +from werkzeug.exceptions import HTTPException +from werkzeug.http import HTTP_STATUS_CODES +from flask_babel import gettext as _ +from flask import request + +from pgadmin.utils.ajax import service_unavailable + + +class ConnectionLost(HTTPException): + """ + Exception + """ + + def __init__(self, _server_id, _database_name, _conn_id): + self.sid = _server_id + self.db = _database_name + self.conn_id = _conn_id + HTTPException.__init__(self) + + @property + def name(self): + return HTTP_STATUS_CODES.get(505, 'Service Unavailable') + + def get_response(self, environ=None): + return service_unavailable( + _("Connection to the server has been lost!"), + info="CONNECTION_LOST", + data={ + 'sid': self.sid, + 'database': self.db, + 'conn_id': self.conn_id + } + )