From 731ba32e816fa30e5cb6116108edecd504572d2c Mon Sep 17 00:00:00 2001 From: Pradip Parkale Date: Fri, 19 Feb 2021 14:56:45 +0530 Subject: [PATCH] 1) Added SSL support for creating a subscription. Fixes #6201 2) Fixed an issue where the user is not able to create the subscription. Fixes #6230 3) Fixed a couple of issues raised during testing of logical replication. --- docs/en_US/release_notes_5_0.rst | 2 + .../browser/server_groups/servers/__init__.py | 3 + .../publications/static/js/publication.js | 15 ++ .../publications/sql/11_plus/properties.sql | 2 +- .../publications/sql/13_plus/create.sql | 23 +++ .../publications/sql/13_plus/properties.sql | 9 ++ .../publications/sql/13_plus/update.sql | 48 ++++++ .../sql/default/get_all_tables.sql | 1 + .../publications/sql/default/properties.sql | 2 +- .../databases/subscriptions/__init__.py | 23 ++- .../subscriptions/static/js/subscription.js | 138 ++++++++++++++++-- .../subscriptions/sql/default/create.sql | 4 +- .../subscriptions/sql/default/properties.sql | 36 +++-- .../subscriptions/sql/default/update.sql | 4 +- .../server_groups/servers/model_validation.js | 4 - .../utils/versioned_template_loader.py | 3 +- 16 files changed, 277 insertions(+), 40 deletions(-) create mode 100644 web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/13_plus/create.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/13_plus/properties.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/13_plus/update.sql diff --git a/docs/en_US/release_notes_5_0.rst b/docs/en_US/release_notes_5_0.rst index 94cfdc404..f78c26bf8 100644 --- a/docs/en_US/release_notes_5_0.rst +++ b/docs/en_US/release_notes_5_0.rst @@ -43,4 +43,6 @@ Bug fixes | `Issue #6187 `_ - Limit the upgrade check to run once per day. | `Issue #6193 `_ - Ensure that ERD throws a warning before closing unsaved changes if open in a new tab. | `Issue #6197 `_ - Fixed an issue where the ERD image is not properly downloaded. +| `Issue #6201 `_ - Added SSL support for creating a subscription. | `Issue #6208 `_ - Fixed an issue where utility(Backup, Maintenance, ...) jobs are failing when the log level is set to DEBUG. +| `Issue #6230 `_ - Fixed an issue where the user is not able to create the subscription. diff --git a/web/pgadmin/browser/server_groups/servers/__init__.py b/web/pgadmin/browser/server_groups/servers/__init__.py index 5daef8120..2f22caf57 100644 --- a/web/pgadmin/browser/server_groups/servers/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/__init__.py @@ -244,6 +244,7 @@ class ServerModule(sg.ServerGroupPluginModule): user=user_info, in_recovery=in_recovery, wal_pause=wal_paused, + host=server.host, is_password_saved=bool(server.save_password), is_tunnel_password_saved=True if server.tunnel_password is not None else False, @@ -535,6 +536,7 @@ class ServerNode(PGChildNodeView): server_type=server_type, version=manager.version, db=manager.db, + host=server.host, user=manager.user_info if connected else None, in_recovery=in_recovery, wal_pause=wal_paused, @@ -604,6 +606,7 @@ class ServerNode(PGChildNodeView): user=manager.user_info if connected else None, in_recovery=in_recovery, wal_pause=wal_paused, + host=server.host, is_password_saved=bool(server.save_password), is_tunnel_password_saved=True if server.tunnel_password is not None else False, diff --git a/web/pgadmin/browser/server_groups/servers/databases/publications/static/js/publication.js b/web/pgadmin/browser/server_groups/servers/databases/publications/static/js/publication.js index 720d628be..4fe459717 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/publications/static/js/publication.js +++ b/web/pgadmin/browser/server_groups/servers/databases/publications/static/js/publication.js @@ -80,6 +80,7 @@ define('pgadmin.node.publication', [ evnt_update:true, evnt_truncate:true, only_table: undefined, + publish_via_partition_root: false, }, // Default values! @@ -177,6 +178,20 @@ define('pgadmin.node.publication', [ return false; }, + },{ + id: 'publish_via_partition_root', label: gettext('Publish via root?'), + type: 'switch', group: gettext('With'), + extraToggleClasses: 'pg-el-sm-6', + controlLabelClassName: 'control-label pg-el-sm-5 pg-el-12', + controlsClassName: 'pgadmin-controls pg-el-sm-7 pg-el-12', + visible: function(m) { + if(!_.isUndefined(m.node_info) && !_.isUndefined(m.node_info.server) + && !_.isUndefined(m.node_info.server.version) && + m.node_info.server.version >= 130000) + return true; + return false; + }, + }], }, ], diff --git a/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/11_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/11_plus/properties.sql index 06c953ba7..0bded27d1 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/11_plus/properties.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/11_plus/properties.sql @@ -2,7 +2,7 @@ SELECT c.oid AS oid, c.pubname AS name, pubinsert AS evnt_insert, pubupdate AS evnt_update, pubdelete AS evnt_delete, pubtruncate AS evnt_truncate, puballtables AS all_table, pga.rolname AS pubowner FROM pg_publication c -JOIN pg_authid pga ON c.pubowner= pga.oid +JOIN pg_roles pga ON c.pubowner= pga.oid {% if pbid %} WHERE c.oid = {{ pbid }} {% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/13_plus/create.sql b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/13_plus/create.sql new file mode 100644 index 000000000..4f574127e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/13_plus/create.sql @@ -0,0 +1,23 @@ +{% if data.evnt_delete or data.evnt_update or data.evnt_truncate %} +{% set add_comma_after_insert = 'insert' %} +{% endif %} +{% if data.evnt_truncate %} +{% set add_comma_after_delete = 'delete' %} +{% endif %} +{% if data.evnt_delete or data.evnt_truncate%} +{% set add_comma_after_update = 'update' %} +{% endif %} +{% if data.publish_via_partition_root%} +{% set add_comma_after_truncate = 'truncate' %} +{% endif %} +{### Create PUBLICATION ###} +CREATE PUBLICATION {{ conn|qtIdent(data.name) }} +{% if data.all_table %} + FOR ALL TABLES +{% elif data.pubtable %} + FOR TABLE {% if data.only_table%}ONLY {% endif %}{% for pub_table in data.pubtable %}{% if loop.index != 1 %}, {% endif %}{{ pub_table }}{% endfor %} + +{% endif %} +{% if data.evnt_insert or data.evnt_update or data.evnt_delete or data.evnt_truncate %} + WITH (publish = '{% if data.evnt_insert %}insert{% if add_comma_after_insert == 'insert' %}, {% endif %}{% endif %}{% if data.evnt_update %}update{% if add_comma_after_update == 'update' %}, {% endif %}{% endif %}{% if data.evnt_delete %}delete{% if add_comma_after_delete == 'delete' %}, {% endif %}{% endif %}{% if data.evnt_truncate %}truncate{% endif %}', publish_via_partition_root = {{ data.publish_via_partition_root|lower }}); +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/13_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/13_plus/properties.sql new file mode 100644 index 000000000..1694577f6 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/13_plus/properties.sql @@ -0,0 +1,9 @@ +SELECT c.oid AS oid, c.pubname AS name, +pubinsert AS evnt_insert, pubupdate AS evnt_update, pubdelete AS evnt_delete, pubtruncate AS evnt_truncate, +puballtables AS all_table, +pubviaroot AS publish_via_partition_root, +pga.rolname AS pubowner FROM pg_publication c +JOIN pg_roles pga ON c.pubowner= pga.oid +{% if pbid %} + WHERE c.oid = {{ pbid }} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/13_plus/update.sql b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/13_plus/update.sql new file mode 100644 index 000000000..58542ea4b --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/13_plus/update.sql @@ -0,0 +1,48 @@ +{% if data.evnt_delete or data.evnt_update or data.evnt_truncate %} +{% set add_comma_after_insert = 'insert' %} +{% endif %} +{% if data.evnt_truncate %} +{% set add_comma_after_delete = 'delete' %} +{% endif %} +{% if data.evnt_delete or data.evnt_truncate%} +{% set add_comma_after_update = 'update' %} +{% endif %} +{### Alter publication owner ###} +{% if data.pubowner %} +ALTER PUBLICATION {{ conn|qtIdent(o_data.name) }} + OWNER TO {{ data.pubowner }}; + +{% endif %} +{### Alter publication event ###} +{% if (data.evnt_insert is defined and data.evnt_insert != o_data.evnt_insert) or (data.evnt_update is defined and data.evnt_update != o_data.evnt_update) or (data.evnt_delete is defined and data.evnt_delete != o_data.evnt_delete) or (data.evnt_truncate is defined and data.evnt_truncate != o_data.evnt_truncate) %} +ALTER PUBLICATION {{ conn|qtIdent(o_data.name) }} SET + (publish = '{% if data.evnt_insert %}insert{% if add_comma_after_insert == 'insert' %}, {% endif %}{% endif %}{% if data.evnt_update %}update{% if add_comma_after_update == 'update' %}, {% endif %}{% endif %}{% if data.evnt_delete %}delete{% if add_comma_after_delete == 'delete' %}, {% endif %}{% endif %}{% if data.evnt_truncate %}truncate{% endif %}'); + +{% endif %} +{### Alter publication partition root ###} +{% if data.publish_via_partition_root is defined and data.publish_via_partition_root != o_data.publish_via_partition_root%} +ALTER PUBLICATION {{ conn|qtIdent(o_data.name) }} SET + (publish_via_partition_root = {{ data.publish_via_partition_root|lower }}); + +{% endif %} +{### Alter drop publication table ###} +{% if drop_table %} +ALTER PUBLICATION {{ conn|qtIdent(o_data.name) }} + DROP TABLE {% if data.only_table%}ONLY {% endif %}{% for pub_table in drop_table_data %}{% if loop.index != 1 %}, {% endif %}{{ pub_table }}{% endfor %}; + +{% endif %} +{### Alter publication table ###} +{% if add_table %} +ALTER PUBLICATION {{ conn|qtIdent(o_data.name) }} + ADD TABLE {% if data.only_table%}ONLY {% endif %}{% for pub_table in add_table_data %}{% if loop.index != 1 %}, {% endif %}{{ pub_table }}{% endfor %}; + +{% endif %} +{### Alter publication name ###} +{% if data.name != o_data.name %} +ALTER PUBLICATION {{ conn|qtIdent(o_data.name) }} + RENAME TO {{ conn|qtIdent(data.name) }}; +{% endif %} + + + + diff --git a/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/get_all_tables.sql b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/get_all_tables.sql index 874cf00eb..ea1048af9 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/get_all_tables.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/get_all_tables.sql @@ -3,4 +3,5 @@ FROM information_schema.tables c WHERE c.table_type = 'BASE TABLE' AND c.table_schema NOT LIKE 'pg\_%' AND c.table_schema NOT LIKE 'pgagent' + AND c.table_schema NOT LIKE 'sys' AND c.table_schema NOT IN ('information_schema') ORDER BY 1; diff --git a/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/properties.sql index 56ac3dac3..8f6edee94 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/properties.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/publications/templates/publications/sql/default/properties.sql @@ -2,7 +2,7 @@ SELECT c.oid AS oid, c.pubname AS name, pubinsert AS evnt_insert, pubupdate AS evnt_update, pubdelete AS evnt_delete, puballtables AS all_table, pga.rolname AS pubowner FROM pg_publication c -JOIN pg_authid pga ON c.pubowner= pga.oid +JOIN pg_roles pga ON c.pubowner= pga.oid {% if pbid %} where c.oid = {{ pbid }} {% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/__init__.py index f2e72207d..48cc1a1ad 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/__init__.py @@ -261,8 +261,14 @@ class SubscriptionView(PGChildNodeView, SchemaDiffObjectCompare): self._PROPERTIES_SQL]), did=did) status, res = self.conn.execute_dict(sql) + # Check for permission denied message + if 'permission denied' in res: + return internal_server_error( + errormsg="Access is revoked for normal users") + if not status: return internal_server_error(errormsg=res) + return ajax_response( response=res['rows'], status=200 @@ -680,14 +686,21 @@ class SubscriptionView(PGChildNodeView, SchemaDiffObjectCompare): host=connection_details['host'], database=connection_details['db'], user=connection_details['username'], - password=connection_details['password'] if - connection_details['password'] else None, + password=connection_details[ + 'password'] if 'password' in connection_details else None, port=connection_details['port'] if connection_details['port'] else None, passfile=get_complete_file_path(passfile), connect_timeout=connection_details['connect_timeout'] if 'connect_timeout' in connection_details and - connection_details['connect_timeout'] else 0 + connection_details['connect_timeout'] else 0, + sslmode=connection_details['sslmode'], + sslcert=get_complete_file_path(connection_details['sslcert']), + sslkey=get_complete_file_path(connection_details['sslkey']), + sslrootcert=get_complete_file_path( + connection_details['sslrootcert']), + sslcompression=True if connection_details[ + 'sslcompression'] else False, ) # create a cursor cur = conn.cursor() @@ -715,7 +728,9 @@ class SubscriptionView(PGChildNodeView, SchemaDiffObjectCompare): url_params = {k: v for k, v in request.args.items()} required_connection_args = ['host', 'port', 'username', 'db', - 'connect_timeout', 'passfile'] + 'connect_timeout', 'passfile', 'sslmode', + 'sslcompression', 'sslcert', 'sslkey', + 'sslrootcert', 'sslcrl'] if 'oid' in url_params: status, params = self._fetch_properties(did, url_params['oid']) diff --git a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/static/js/subscription.js b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/static/js/subscription.js index 6c1b71521..78b530771 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/static/js/subscription.js +++ b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/static/js/subscription.js @@ -12,6 +12,7 @@ define('pgadmin.node.subscription', [ 'sources/pgadmin', 'pgadmin.browser', 'pgadmin.backform', 'sources/browser/server_groups/servers/model_validation', 'pgadmin.alertifyjs', 'pgadmin.browser.collection', ], function(gettext, url_for, $, _, pgAdmin, pgBrowser, Backform, modelValidation, Alertify) { + var SSL_MODES = ['prefer', 'require', 'verify-ca', 'verify-full']; // Extend the browser's collection class for subscriptions collection if (!pgBrowser.Nodes['coll-subscription']) { @@ -77,7 +78,7 @@ define('pgadmin.node.subscription', [ name: undefined, subowner: undefined, pubtable: undefined, - connect_timeout: undefined, + connect_timeout: 10, pub:[], enabled:true, create_slot: true, @@ -85,7 +86,18 @@ define('pgadmin.node.subscription', [ connect:true, copy_data_after_refresh:false, sync:'off', - refresh_pub: undefined, + refresh_pub: false, + password: '', + sslmode: 'prefer', + sslcompression: false, + sslcert: '', + sslkey: '', + sslrootcert: '', + sslcrl: '', + host: '', + hostaddr: '', + port: 5432, + db: 'postgres', }, // Default values! @@ -189,7 +201,7 @@ define('pgadmin.node.subscription', [ id: 'pub', label: gettext('Publication'), type: 'array', select2: { allowClear: true, multiple: true, width: '92%'}, group: gettext('Connection'), mode: ['create', 'edit'], controlsClassName: 'pgadmin-controls pg-el-sm-11 pg-el-12', deps: ['all_table', 'host', 'port', 'username', 'db', 'password'], disabled: 'isAllConnectionDataEnter', - helpMessage: gettext('Click the refresh button to get the publications"'), + helpMessage: gettext('Click the refresh button to get the publications'), control: Backform.Select2Control.extend({ defaults: _.extend(Backform.Select2Control.prototype.defaults, { select2: { @@ -280,6 +292,91 @@ define('pgadmin.node.subscription', [ }, }), }, + { + id: 'sslmode', label: gettext('SSL mode'), control: 'select2', group: gettext('SSL'), + select2: { + allowClear: false, + minimumResultsForSearch: Infinity, + }, + mode: ['properties', 'edit', 'create'], + 'options': [ + {label: gettext('Allow'), value: 'allow'}, + {label: gettext('Prefer'), value: 'prefer'}, + {label: gettext('Require'), value: 'require'}, + {label: gettext('Disable'), value: 'disable'}, + {label: gettext('Verify-CA'), value: 'verify-ca'}, + {label: gettext('Verify-Full'), value: 'verify-full'}, + ], + },{ + id: 'sslcert', label: gettext('Client certificate'), type: 'text', + group: gettext('SSL'), mode: ['edit', 'create'], + disabled: 'isSSL', control: Backform.FileControl, + dialog_type: 'select_file', supp_types: ['*'], + deps: ['sslmode'], + },{ + id: 'sslkey', label: gettext('Client certificate key'), type: 'text', + group: gettext('SSL'), mode: ['edit', 'create'], + disabled: 'isSSL', control: Backform.FileControl, + dialog_type: 'select_file', supp_types: ['*'], + deps: ['sslmode'], + },{ + id: 'sslrootcert', label: gettext('Root certificate'), type: 'text', + group: gettext('SSL'), mode: ['edit', 'create'], + disabled: 'isSSL', control: Backform.FileControl, + dialog_type: 'select_file', supp_types: ['*'], + deps: ['sslmode'], + },{ + id: 'sslcrl', label: gettext('Certificate revocation list'), type: 'text', + group: gettext('SSL'), mode: ['edit', 'create'], + disabled: 'isSSL', control: Backform.FileControl, + dialog_type: 'select_file', supp_types: ['*'], + deps: ['sslmode'], + },{ + id: 'sslcompression', label: gettext('SSL compression?'), type: 'switch', + mode: ['edit', 'create'], group: gettext('SSL'), + 'options': {'size': 'mini'}, + deps: ['sslmode'], disabled: 'isSSL', + },{ + id: 'sslcert', label: gettext('Client certificate'), type: 'text', + group: gettext('SSL'), mode: ['properties'], + deps: ['sslmode'], + visible: function(model) { + var sslcert = model.get('sslcert'); + return !_.isUndefined(sslcert) && !_.isNull(sslcert); + }, + },{ + id: 'sslkey', label: gettext('Client certificate key'), type: 'text', + group: gettext('SSL'), mode: ['properties'], + deps: ['sslmode'], + visible: function(model) { + var sslkey = model.get('sslkey'); + return !_.isUndefined(sslkey) && !_.isNull(sslkey); + }, + },{ + id: 'sslrootcert', label: gettext('Root certificate'), type: 'text', + group: gettext('SSL'), mode: ['properties'], + deps: ['sslmode'], + visible: function(model) { + var sslrootcert = model.get('sslrootcert'); + return !_.isUndefined(sslrootcert) && !_.isNull(sslrootcert); + }, + },{ + id: 'sslcrl', label: gettext('Certificate revocation list'), type: 'text', + group: gettext('SSL'), mode: ['properties'], + deps: ['sslmode'], + visible: function(model) { + var sslcrl = model.get('sslcrl'); + return !_.isUndefined(sslcrl) && !_.isNull(sslcrl); + }, + },{ + id: 'sslcompression', label: gettext('SSL compression?'), type: 'switch', + mode: ['properties'], group: gettext('SSL'), + 'options': {'size': 'mini'}, + deps: ['sslmode'], visible: function(model) { + var sslmode = model.get('sslmode'); + return _.indexOf(SSL_MODES, sslmode) != -1; + }, + }, { id: 'copy_data_after_refresh', label: gettext('Copy data?'), type: 'switch', mode: ['edit'], @@ -298,8 +395,8 @@ define('pgadmin.node.subscription', [ id: 'create_slot', label: gettext('Create slot?'), type: 'switch', mode: ['create'], group: gettext('With'), - disabled: 'isDisable', - readonly: 'isConnect', deps :['connect'], + disabled: 'isSameDB', + readonly: 'isConnect', deps :['connect', 'host'], helpMessage: gettext('Specifies whether the command should create the replication slot on the publisher.'), }, @@ -358,13 +455,21 @@ define('pgadmin.node.subscription', [ return false; return true; }, + isSameDB:function(m){ + if (m.attributes['host'] == m.node_info.server.host){ + setTimeout( function() { + m.set('create_slot', false); + }, 10); + return true; + } + return false; + }, isAllConnectionDataEnter: function(m){ let host = m.get('host'), db = m.get('db'), port = m.get('port'), - username = m.get('username'), - password = m.get('password'); - if ((!_.isUndefined(host) && host) && (!_.isUndefined(db) && db) && (!_.isUndefined(port) && port) && (!_.isUndefined(username) && username) && (!_.isUndefined(password) && password)) + username = m.get('username'); + if ((!_.isUndefined(host) && host) && (!_.isUndefined(db) && db) && (!_.isUndefined(port) && port) && (!_.isUndefined(username) && username)) return false; return true; }, @@ -388,8 +493,12 @@ define('pgadmin.node.subscription', [ } return false; }, + isSSL: function(model) { + var ssl_mode = model.get('sslmode'); + return _.indexOf(SSL_MODES, ssl_mode) == -1; + }, sessChanged: function() { - if (_.isEqual(_.omit(this.attributes, ['refresh_pub']), _.omit(this.origSessAttrs, ['refresh_pub'])) && !this.isNew()) + if (!this.isNew() && _.isUndefined(this.attributes['refresh_pub'])) return false; return pgBrowser.DataModel.prototype.sessChanged.apply(this); }, @@ -400,7 +509,8 @@ define('pgadmin.node.subscription', [ validate: function() { var msg; this.errorModel.clear(); - var name = this.get('name'); + var name = this.get('name'), + slot_name = this.get('slot_name'); if (_.isUndefined(name) || _.isNull(name) || String(name).replace(/^\s+|\s+$/g, '') == '') { @@ -409,6 +519,14 @@ define('pgadmin.node.subscription', [ return msg; } + if (!_.isUndefined(slot_name) && !_.isNull(slot_name)){ + if(/^[a-zA-Z0-9_]+$/.test(slot_name) == false){ + msg = gettext('Replication slot name may only contain lower case letters, numbers, and the underscore character.'); + this.errorModel.set('name', msg); + return msg; + } + } + const validateModel = new modelValidation.ModelValidation(this); return validateModel.validate(); }, diff --git a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/templates/subscriptions/sql/default/create.sql b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/templates/subscriptions/sql/default/create.sql index 08c28a1b6..31bf109f5 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/templates/subscriptions/sql/default/create.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/templates/subscriptions/sql/default/create.sql @@ -12,8 +12,8 @@ {% endif %} CREATE SUBSCRIPTION {{ conn|qtIdent(data.name) }} -{% if data.host or data.port or data.username or data.password or data.db %} - CONNECTION '{% if data.host %}host={{data.host}}{% endif %}{% if data.port %} port={{ data.port }}{% endif %}{% if data.username %} user={{ data.username }}{% endif %}{% if data.db %} dbname={{ data.db }}{% endif %}{% if data.connect_timeout %} connect_timeout={{ data.connect_timeout }}{% endif %}{% if data.passfile %} passfile={{ data.passfile }}{% endif %}{% if data.password %} {% if dummy %}password=xxxxxx{% else %}password={{ data.password}}{% endif %}{% endif %}' +{% if data.host or data.port or data.username or data.password or data.db or data.connect_timeout or data.passfile or data.sslmode or data.sslcompression or data.sslcert or data.sslkey or data.sslrootcert or data.sslcrl%} + CONNECTION '{% if data.host %}host={{data.host}}{% endif %}{% if data.port %} port={{ data.port }}{% endif %}{% if data.username %} user={{ data.username }}{% endif %}{% if data.db %} dbname={{ data.db }}{% endif %}{% if data.connect_timeout %} connect_timeout={{ data.connect_timeout }}{% endif %}{% if data.passfile %} passfile={{ data.passfile }}{% endif %}{% if data.password %} {% if dummy %}password=xxxxxx{% else %}password={{ data.password}}{% endif %}{% endif %}{% if data.sslmode %} sslmode={{ data.sslmode }}{% endif %}{% if data.sslcompression %} sslcompression={{ data.sslcompression }}{% endif %}{% if data.sslcert %} sslcert={{ data.sslcert }}{% endif %}{% if data.sslkey %} sslkey={{ data.sslkey }}{% endif %}{% if data.sslrootcert %} sslrootcert={{ data.sslrootcert }}{% endif %}{% if data.sslcrl %} sslcrl={{ data.sslcrl }}{% endif %}' {% endif %} {% if data.pub %} PUBLICATION {% for pub in data.pub %}{% if loop.index != 1 %},{% endif %}{{ conn|qtIdent(pub) }}{% endfor %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/templates/subscriptions/sql/default/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/templates/subscriptions/sql/default/properties.sql index 266525779..af958fcb2 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/templates/subscriptions/sql/default/properties.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/templates/subscriptions/sql/default/properties.sql @@ -1,18 +1,24 @@ -SELECT sub.oid AS oid, - subname AS name, - subpublications AS pub, - sub.subsynccommit AS sync, - subpublications AS cur_pub, - pga.rolname AS subowner, - subslotname AS slot_name, - subenabled AS enabled, - SPLIT_PART(SPLIT_PART(subconninfo,' port',1), '=',2) AS host, - SPLIT_PART(SPLIT_PART(subconninfo,'port=',2), ' ',1) AS port, - SPLIT_PART(SPLIT_PART(subconninfo,'user=',2), ' ',1) AS username, - SPLIT_PART(SPLIT_PART(subconninfo,'dbname=',2), ' ',1) AS db, - SPLIT_PART(SPLIT_PART(subconninfo,'connect_timeout=',2), ' ',1) AS connect_timeout, - SPLIT_PART(SPLIT_PART(subconninfo,'passfile=',2), ' ',1) AS passfile -FROM pg_subscription sub JOIN pg_authid pga ON sub.subowner= pga.oid +SELECT sub.oid as oid, + subname as name, + subpublications as pub, + sub.subsynccommit as sync, + subpublications as cur_pub, + pga.rolname as subowner, + subslotname as slot_name, + subenabled as enabled, + SPLIT_PART(SPLIT_PART(subconninfo,' port',1), '=',2) as host, + SPLIT_PART(SPLIT_PART(subconninfo,'port=',2), ' ',1) as port, + SPLIT_PART(SPLIT_PART(subconninfo,'user=',2), ' ',1) as username, + SPLIT_PART(SPLIT_PART(subconninfo,'dbname=',2), ' ',1) as db, + SPLIT_PART(SPLIT_PART(subconninfo,'connect_timeout=',2), ' ',1) as connect_timeout, + SPLIT_PART(SPLIT_PART(subconninfo,'passfile=',2), ' ',1) as passfile, + SPLIT_PART(SPLIT_PART(subconninfo,'sslmode=',2), ' ',1) as sslmode, + SPLIT_PART(SPLIT_PART(subconninfo,'sslcompression=',2), ' ',1) as sslcompression, + SPLIT_PART(SPLIT_PART(subconninfo,'sslcert=',2), ' ',1) as sslcert, + SPLIT_PART(SPLIT_PART(subconninfo,'sslkey=',2), ' ',1) as sslkey, + SPLIT_PART(SPLIT_PART(subconninfo,'sslrootcert=',2), ' ',1) as sslrootcert, + SPLIT_PART(SPLIT_PART(subconninfo,'sslcrl=',2), ' ',1) as sslcrl +FROM pg_subscription sub join pg_roles pga on sub.subowner= pga.oid WHERE {% if subid %} sub.oid = {{ subid }}; diff --git a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/templates/subscriptions/sql/default/update.sql b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/templates/subscriptions/sql/default/update.sql index f04a00466..04c435a69 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/subscriptions/templates/subscriptions/sql/default/update.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/subscriptions/templates/subscriptions/sql/default/update.sql @@ -47,9 +47,9 @@ ALTER SUBSCRIPTION {{ conn|qtIdent(o_data.name) }} {% endif %} {### Alter subscription connection info ###} -{% if data.host or data.port or data.username or data.password or data.db or data.connect_timeout or data.passfile %} +{% if data.host or data.port or data.username or data.password or data.db or data.connect_timeout or data.passfile or data.sslmode or data.sslcompression or data.sslcert or data.sslkey or data.sslrootcert or data.sslcrl %} ALTER SUBSCRIPTION {{ conn|qtIdent(o_data.name) }} - CONNECTION 'host={{ o_data.host}} port={{ o_data.port }} user={{ o_data.username }} dbname={{ o_data.db }}{% if data.connect_timeout %} connect_timeout={{ o_data.connect_timeout }}{% endif %}{% if data.passfile %} passfile={{ o_data.passfile }}{% endif %}{% if data.password %} {% if dummy %}password=xxxxxx{% else %} password={{ data.password}}{% endif %}{% endif %}'; + CONNECTION 'host={{ o_data.host}} port={{ o_data.port }} user={{ o_data.username }} dbname={{ o_data.db }}{% if data.connect_timeout %} connect_timeout={{ o_data.connect_timeout }}{% endif %}{% if data.passfile %} passfile={{ o_data.passfile }}{% endif %}{% if data.password %} {% if dummy %}password=xxxxxx{% else %} password={{ data.password}}{% endif %}{% endif %}{% if data.sslmode %} sslmode={{ data.sslmode }}{% endif %}{% if data.sslcompression %} sslcompression={{ data.sslcompression }}{% endif %}{% if data.sslcert %} sslcert={{ data.sslcert }}{% endif %}{% if data.sslkey %} sslkey={{ data.sslkey }}{% endif %}{% if data.sslrootcert %} sslrootcert={{ data.sslrootcert }}{% endif %}{% if data.sslcrl %} sslcrl={{ data.sslcrl }}{% endif %}'; {% endif %} {### Alter subscription name ###} {% if data.name and data.name != o_data.name %} diff --git a/web/pgadmin/static/js/browser/server_groups/servers/model_validation.js b/web/pgadmin/static/js/browser/server_groups/servers/model_validation.js index 2e391b5b6..33d073a6b 100644 --- a/web/pgadmin/static/js/browser/server_groups/servers/model_validation.js +++ b/web/pgadmin/static/js/browser/server_groups/servers/model_validation.js @@ -40,15 +40,11 @@ export class ModelValidation { this.checkForEmpty('username', gettext('Username must be specified.')); this.checkForEmpty('port', gettext('Port must be specified.')); if(!_.isUndefined(pub)){ - if (this.model.isNew()) - this.checkForEmpty('password', gettext('Password must be specified.')); this.checkForEmpty('pub', gettext('Publication must be specified.')); } } else { this.checkForEmpty('db', gettext('Maintenance database must be specified.')); if(!_.isUndefined(pub)){ - if (this.model.isNew()) - this.checkForEmpty('password', gettext('Password must be specified.')); this.checkForEmpty('pub', gettext('Publication must be specified.')); } this.clearHostAddressAndDbErrors(); diff --git a/web/pgadmin/utils/versioned_template_loader.py b/web/pgadmin/utils/versioned_template_loader.py index ca4f3146c..c4dcc1528 100644 --- a/web/pgadmin/utils/versioned_template_loader.py +++ b/web/pgadmin/utils/versioned_template_loader.py @@ -84,7 +84,8 @@ def get_version_mapping_directories(server_type): {'name': "default", 'number': 0} ) - return ({'name': "12_plus", 'number': 120000}, + return ({'name': "13_plus", 'number': 130000}, + {'name': "12_plus", 'number': 120000}, {'name': "11_plus", 'number': 110000}, {'name': "10_plus", 'number': 100000}, {'name': "9.6_plus", 'number': 90600},