diff --git a/docs/en_US/images/server_advanced.png b/docs/en_US/images/server_advanced.png index dfd3c9133..898bf9dfc 100644 Binary files a/docs/en_US/images/server_advanced.png and b/docs/en_US/images/server_advanced.png differ diff --git a/docs/en_US/server_dialog.rst b/docs/en_US/server_dialog.rst index 3cd33c238..06901803e 100644 --- a/docs/en_US/server_dialog.rst +++ b/docs/en_US/server_dialog.rst @@ -44,4 +44,5 @@ Click the *Advanced* tab to continue. Use the fields in the *Advanced* tab to configure a connection: -* Specify the IP address of the server host. Using this field to specify the host IP address will avoid a DNS lookup on connection, however it may be useful to specify both a host name and address when using Kerberos, GSSAPI, or SSPI authentication methods, as well as for verify-full SSL certificate verification \ No newline at end of file +* Specify the IP address of the server host. Using this field to specify the host IP address will avoid a DNS lookup on connection, however it may be useful to specify both a host name and address when using Kerberos, GSSAPI, or SSPI authentication methods, as well as for verify-full SSL certificate verification +* The DB restriction field allows you to enter an SQL restriction that will be used against the pg_database table to limit the databases that you see. For example, you might enter: *live_db test_db* so that only live_db and test_db are shown in the pgAdmin browser. Separate entries with a comma or tab as you type. \ No newline at end of file diff --git a/web/migrations/versions/d85a62333272_.py b/web/migrations/versions/d85a62333272_.py new file mode 100644 index 000000000..54da9d06e --- /dev/null +++ b/web/migrations/versions/d85a62333272_.py @@ -0,0 +1,28 @@ + +"""empty message + +Revision ID: d85a62333272 +Revises: 3c1e4b6eda55 +Create Date: 2017-07-07 16:03:23.842734 + +""" +from alembic import op +import sqlalchemy as sa +from pgadmin.model import db + + +# revision identifiers, used by Alembic. +revision = 'd85a62333272' +down_revision = 'f195f9a4923d' +branch_labels = None +depends_on = None + + +def upgrade(): + db.engine.execute( + 'ALTER TABLE server ADD COLUMN db_res TEXT' + ) + + +def downgrade(): + pass diff --git a/web/pgadmin/browser/server_groups/servers/__init__.py b/web/pgadmin/browser/server_groups/servers/__init__.py index 5e9d378cf..a74436efa 100644 --- a/web/pgadmin/browser/server_groups/servers/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/__init__.py @@ -380,7 +380,8 @@ class ServerNode(PGChildNodeView): 'sslmode': 'ssl_mode', 'gid': 'servergroup_id', 'comment': 'comment', - 'role': 'role' + 'role': 'role', + 'db_res': 'db_res' } disp_lbl = { @@ -398,6 +399,8 @@ class ServerNode(PGChildNodeView): data = request.form if request.form else json.loads( request.data, encoding='utf-8' ) + if 'db_res' in data: + data['db_res'] = ','.join(data['db_res']) if 'hostaddr' in data and data['hostaddr'] != '': if not self.pat4.match(data['hostaddr']): @@ -497,7 +500,8 @@ class ServerNode(PGChildNodeView): 'role': server.role, 'connected': connected, 'version': manager.ver, - 'server_type': manager.server_type if connected else 'pg' + 'server_type': manager.server_type if connected else 'pg', + 'db_res': server.db_res.split(',') if server.db_res else None }) return ajax_response( @@ -544,7 +548,8 @@ class ServerNode(PGChildNodeView): 'connected': connected, 'version': manager.ver, 'sslmode': server.ssl_mode, - 'server_type': manager.server_type if connected else 'pg' + 'server_type': manager.server_type if connected else 'pg', + 'db_res': server.db_res.split(',') if server.db_res else None } ) @@ -597,7 +602,8 @@ class ServerNode(PGChildNodeView): username=data[u'username'], ssl_mode=data[u'sslmode'], comment=data[u'comment'] if u'comment' in data else None, - role=data[u'role'] if u'role' in data else None + role=data[u'role'] if u'role' in data else None, + db_res=','.join(data[u'db_res']) if u'db_res' in data else None ) db.session.add(server) db.session.commit() diff --git a/web/pgadmin/browser/server_groups/servers/databases/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/__init__.py index e40c78753..010049d7b 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/__init__.py @@ -28,7 +28,9 @@ from pgadmin.utils.ajax import gone from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER - +from pgadmin.browser.server_groups.servers import ServerNode +from flask_security import current_user +from pgadmin.model import Server class DatabaseModule(CollectionNodeModule): NODE_TYPE = 'database' @@ -166,11 +168,18 @@ class DatabaseView(PGChildNodeView): (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 + + db_disp_res = None + params = None + if self.manager and self.manager.db_res: + db_disp_res = ", ".join(['%s'] * len(self.manager.db_res.split(','))) + params = tuple(self.manager.db_res.split(',')) + SQL = render_template( "/".join([self.template_path, 'properties.sql']), - conn=self.conn, last_system_oid=last_system_oid + conn=self.conn, last_system_oid=last_system_oid, db_restrictions=db_disp_res ) - status, res = self.conn.execute_dict(SQL) + status, res = self.conn.execute_dict(SQL, params) if not status: return internal_server_error(errormsg=res) @@ -188,12 +197,19 @@ class DatabaseView(PGChildNodeView): if self.manager.db_info is not None and \ self.manager.did in self.manager.db_info else 0 ) + server_node_res = self.manager + db_disp_res = None + params = None + if server_node_res and server_node_res.db_res: + db_disp_res = ", ".join(['%s']*len(server_node_res.db_res.split(','))) + params = tuple(server_node_res.db_res.split(',')) SQL = render_template( "/".join([self.template_path, 'nodes.sql']), - last_system_oid=last_system_oid + last_system_oid=last_system_oid, + db_restrictions=db_disp_res ) - status, rset = self.conn.execute_dict(SQL) + status, rset = self.conn.execute_dict(SQL, params) if not status: return internal_server_error(errormsg=rset) @@ -851,12 +867,17 @@ class DatabaseView(PGChildNodeView): if self.manager.db_info is not None and \ self.manager.did in self.manager.db_info else 0 + db_disp_res = None + params = None + if self.manager and self.manager.db_res: + db_disp_res = ", ".join(['%s'] * len(self.manager.db_res.split(','))) + params = tuple(self.manager.db_res.split(',')) + conn = self.manager.connection() - status, res = conn.execute_dict( - render_template( - "/".join([self.template_path, 'stats.sql']), - did=did, conn=conn, last_system_oid=last_system_oid - ) + status, res = conn.execute_dict(render_template( + "/".join([self.template_path, 'stats.sql']), + did=did, conn=conn, last_system_oid=last_system_oid, db_restrictions=db_disp_res + ),params ) if not status: diff --git a/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/9.2_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/9.2_plus/properties.sql index cb1a454ea..928124fae 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/9.2_plus/properties.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/9.2_plus/properties.sql @@ -41,5 +41,10 @@ db.oid = {{ did|qtLiteral }}::OID{% else %}{% if name %} db.datname = {{ name|qtLiteral }}::text{% else %} db.oid > {{ last_system_oid|qtLiteral }}::OID {% endif %}{% endif %} +{% if db_restrictions %} + +AND +db.datname in ({{db_restrictions}}) +{% endif %} ORDER BY datname; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/9.2_plus/stats.sql b/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/9.2_plus/stats.sql index 5b192432c..ee920a97a 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/9.2_plus/stats.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/9.2_plus/stats.sql @@ -29,5 +29,10 @@ WHERE {% if did %} db.datid = {{ did|qtLiteral }}::OID{% else %} db.datid > {{ last_system_oid|qtLiteral }}::OID {% endif %} +{% if db_restrictions %} + +AND +db.datname in ({{db_restrictions}}) +{% endif %} ORDER BY db.datname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/default/nodes.sql b/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/default/nodes.sql index b05880c37..82c58d0e2 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/default/nodes.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/default/nodes.sql @@ -8,5 +8,10 @@ WHERE {% if did %} db.oid = {{ did|qtLiteral }}::OID{% else %} db.oid > {{ last_system_oid }}::OID {% endif %} +{% if db_restrictions %} + +AND +db.datname in ({{db_restrictions}}) +{% endif %} ORDER BY datname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/default/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/default/properties.sql index 2f6e42319..a251ebd59 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/default/properties.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/default/properties.sql @@ -34,5 +34,10 @@ db.oid = {{ did|qtLiteral }}::OID{% else %}{% if name %} db.datname = {{ name|qtLiteral }}::text{% else %} db.oid > {{ last_system_oid|qtLiteral }}::OID {% endif %}{% endif %} +{% if db_restrictions %} + +AND +db.datname in ({{db_restrictions}}) +{% endif %} ORDER BY datname; diff --git a/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/default/stats.sql b/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/default/stats.sql index 4f23b9db6..5cc5d6704 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/default/stats.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/templates/databases/sql/default/stats.sql @@ -24,5 +24,10 @@ WHERE {% if did %} db.datid = {{ did|qtLiteral }}::OID{% else %} db.datid > {{ last_system_oid|qtLiteral }}::OID {% endif %} +{% if db_restrictions %} + +AND +db.datname in ({{db_restrictions}}) +{% endif %} ORDER BY db.datname; diff --git a/web/pgadmin/browser/server_groups/servers/static/js/server.js b/web/pgadmin/browser/server_groups/servers/static/js/server.js index c57a0e241..a337dfe9f 100644 --- a/web/pgadmin/browser/server_groups/servers/static/js/server.js +++ b/web/pgadmin/browser/server_groups/servers/static/js/server.js @@ -624,7 +624,8 @@ define('pgadmin.node.server', [ role: null, connect_now: true, password: undefined, - save_password: false + save_password: false, + db_res: '' }, // Default values! initialize: function(attrs, args) { @@ -669,6 +670,10 @@ define('pgadmin.node.server', [ },{ id: 'hostaddr', label: gettext('Host address'), type: 'text', group: gettext('Advanced'), mode: ['properties', 'edit', 'create'], disabled: 'isConnected' + },{ + id: 'db_res', label: gettext('DB restriction'), type: 'select2', group: gettext('Advanced'), + mode: ['properties', 'edit', 'create'], disabled: 'isConnected', select2: {multiple: true, allowClear: false, + tags: true, tokenSeparators: [','], first_empty: false, selectOnClose: true, emptyOptions: true} },{ id: 'port', label: gettext('Port'), type: 'int', group: gettext('Connection'), mode: ['properties', 'edit', 'create'], disabled: 'isConnected', min: 1024, max: 65535 diff --git a/web/pgadmin/model/__init__.py b/web/pgadmin/model/__init__.py index 2205508ba..e1e1d4a73 100644 --- a/web/pgadmin/model/__init__.py +++ b/web/pgadmin/model/__init__.py @@ -128,6 +128,8 @@ class Server(db.Model): servers = db.relationship('ServerGroup', backref=db.backref('server', cascade="all, delete-orphan"), lazy='joined') + db_res = db.Column(db.Text(), nullable=True) + diff --git a/web/pgadmin/static/js/backform.pgadmin.js b/web/pgadmin/static/js/backform.pgadmin.js index dec018559..af95d9f42 100644 --- a/web/pgadmin/static/js/backform.pgadmin.js +++ b/web/pgadmin/static/js/backform.pgadmin.js @@ -1707,7 +1707,8 @@ defaults: _.extend({}, Backform.SelectControl.prototype.defaults, { select2: { first_empty: true, - multiple: false + multiple: false, + emptyOptions: false } }), formatter: Select2Formatter, @@ -1761,7 +1762,8 @@ data.select2 = data.select2 || {}; _.defaults(data.select2, this.defaults.select2, { first_empty: true, - multiple: false + multiple: false, + emptyOptions: false }); // Evaluate the disabled, visible, and required option @@ -1807,8 +1809,29 @@ * Add empty option as Select2 requires any empty '