Subject: [pgAdmin4][PATCH] To fix the validation in Types node

From: Murtuza Zabuawala <[email-masked]>
Date: Fri, 2 Jun 2017 14:49:10 +0530

Hi,

PFA patch to fix the validation issues with Range & External type in Types
node.
RM#1795

--
Regards,
Murtuza Zabuawala
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
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 9c88c63..cb38b5c 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
@@ -907,7 +907,7 @@ class TypeView(PGChildNodeView, DataTypeReader):
                     )
             # If type is range then check if subtype is defined or not
             if data and data[arg] == 'r':
-                if data['typname'] is None:
+                if 'typname' not in data or data['typname'] is None:
                     return make_json_response(
                         status=410,
                         success=0,
@@ -918,7 +918,9 @@ class TypeView(PGChildNodeView, DataTypeReader):
             # If type is external then check if input/output
             # conversion function is defined
             if data and data[arg] == 'b':
-                if data['typinput'] is None or \
+                if 'typinput' not in data or \
+                                'typoutput' not in data or \
+                                data['typinput'] is None or \
                                 data['typoutput'] is None:
                     return make_json_response(
                         status=410,
@@ -1224,7 +1226,27 @@ class TypeView(PGChildNodeView, DataTypeReader):
 
             for arg in required_args:
                 if arg not in data:
-                    return " --definition incomplete"
+                    return "-- definition incomplete"
+
+            # Additional checks goes here
+            # If type is composite then check if it has two members
+            if data and data[arg] == 'c':
+                if len(data['composite']) < 2:
+                    return "-- definition incomplete"
+
+            # If type is range then check if subtype is defined or not
+            if data and data[arg] == 'r':
+                if 'typname' not in data or data['typname'] is None:
+                    return "-- definition incomplete"
+
+            # If type is external then check if input/output
+            # conversion function is defined
+            if data and data[arg] == 'b':
+                if 'typinput' not in data or \
+                                'typoutput' not in data or \
+                                data['typinput'] is None or \
+                                data['typoutput'] is None:
+                    return "-- definition incomplete"
 
             # Privileges
             if 'typacl' in data and data['typacl'] is not None:
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/js/type.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/js/type.js
index 4c101fd..775ef2d 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/js/type.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/js/type.js
@@ -789,42 +789,72 @@ function($, _, S, pgAdmin, pgBrowser, alertify, Backgrid) {
 
           this.errorModel.clear();
 
-          if (_.has(changedAttrs, 'name') &&
-                (_.isUndefined(this.get('name'))
-              || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '')) {
+          if (
+            _.isUndefined(this.get('name')) ||
+            _.isNull(this.get('name')) ||
+            String(this.get('name')).replace(/^\s+|\s+$/g, '') == ''
+          ) {
             msg = '{{ _('Name cannot be empty.') }}';
             this.errorModel.set('name', msg);
-          } else if (_.has(changedAttrs, 'schema') &&
-                (_.isUndefined(this.get('schema'))
-              || String(this.get('schema')).replace(/^\s+|\s+$/g, '') == '')) {
+            return msg;
+          }
+
+          if (
+            _.isUndefined(this.get('schema')) ||
+            _.isNull(this.get('schema')) ||
+            String(this.get('schema')).replace(/^\s+|\s+$/g, '') == ''
+          ) {
             msg = '{{ _('Schema cannot be empty.') }}';
             this.errorModel.set('schema', msg);
-          } else if (_.has(changedAttrs, 'typtype') &&
-                (_.isUndefined(this.get('typtype'))
-              || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '')) {
+            return msg;
+          }
+
+          if (
+            _.isUndefined(this.get('typtype')) ||
+            _.isNull(this.get('typtype')) ||
+            String(this.get('typtype')).replace(/^\s+|\s+$/g, '') == ''
+          ) {
             msg = '{{ _('Type cannot be empty.') }}';
             this.errorModel.set('typtype', msg);
-          } else if (this.get('typtype') == 'r' &&
-                _.has(changedAttrs, 'typname')
-              && (_.isUndefined(this.get('typname'))
-              || String(this.get('typname')).replace(/^\s+|\s+$/g, '') == '')) {
-            msg = '{{ _('Subtype name cannot be empty.') }}';
-            this.errorModel.set('typname', msg);
-          } else if (this.get('typtype') == 'x' &&
-                _.has(changedAttrs, 'typinput')
-              && (_.isUndefined(this.get('typinput'))
-              || String(this.get('typinput')).replace(/^\s+|\s+$/g, '') == '')) {
-            msg = '{{ _('Input function cannot be empty.') }}';
-            this.errorModel.set('typinput', msg);
-          } else if (this.get('typtype') == 'x' &&
-                _.has(changedAttrs, 'typoutput')
-              && (_.isUndefined(this.get('typoutput'))
-              || String(this.get('typoutput')).replace(/^\s+|\s+$/g, '') == '')) {
-            msg = '{{ _('Output function cannot be empty.') }}';
-            this.errorModel.set('typoutput', msg);
+            return msg;
+          }
+
+          // For Range
+          if(this.get('typtype') == 'r') {
+              if (
+                _.isUndefined(this.get('typname')) ||
+                _.isNull(this.get('typname')) ||
+                String(this.get('typname')).replace(/^\s+|\s+$/g, '') == ''
+              ) {
+                msg = '{{ _('Subtype name cannot be empty.') }}';
+                this.errorModel.set('typname', msg);
+                return msg;
+              }
+          }
+
+          // For External
+          if(this.get('typtype') == 'b') {
+              if (
+                _.isUndefined(this.get('typinput')) ||
+                _.isNull(this.get('typinput')) ||
+                String(this.get('typinput')).replace(/^\s+|\s+$/g, '') == ''
+              ) {
+                msg = '{{ _('Input function cannot be empty.') }}';
+                this.errorModel.set('typinput', msg);
+                return msg;
+              }
+              if (
+                _.isUndefined(this.get('typoutput')) ||
+                _.isNull(this.get('typoutput')) ||
+                String(this.get('typoutput')).replace(/^\s+|\s+$/g, '') == ''
+              ) {
+                msg = '{{ _('Output function cannot be empty.') }}';
+                this.errorModel.set('typoutput', msg);
+                return msg;
+              }
           }
 
-          return msg ? msg : null;
+          return null;
         },
         // We will disable everything if we are under catalog node
         inSchema: function() {
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 9c88c63..cb38b5c 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
@@ -907,7 +907,7 @@ class TypeView(PGChildNodeView, DataTypeReader):
                     )
             # If type is range then check if subtype is defined or not
             if data and data[arg] == 'r':
-                if data['typname'] is None:
+                if 'typname' not in data or data['typname'] is None:
                     return make_json_response(
                         status=410,
                         success=0,
@@ -918,7 +918,9 @@ class TypeView(PGChildNodeView, DataTypeReader):
             # If type is external then check if input/output
             # conversion function is defined
             if data and data[arg] == 'b':
-                if data['typinput'] is None or \
+                if 'typinput' not in data or \
+                                'typoutput' not in data or \
+                                data['typinput'] is None or \
                                 data['typoutput'] is None:
                     return make_json_response(
                         status=410,
@@ -1224,7 +1226,27 @@ class TypeView(PGChildNodeView, DataTypeReader):
 
             for arg in required_args:
                 if arg not in data:
-                    return " --definition incomplete"
+                    return "-- definition incomplete"
+
+            # Additional checks goes here
+            # If type is composite then check if it has two members
+            if data and data[arg] == 'c':
+                if len(data['composite']) < 2:
+                    return "-- definition incomplete"
+
+            # If type is range then check if subtype is defined or not
+            if data and data[arg] == 'r':
+                if 'typname' not in data or data['typname'] is None:
+                    return "-- definition incomplete"
+
+            # If type is external then check if input/output
+            # conversion function is defined
+            if data and data[arg] == 'b':
+                if 'typinput' not in data or \
+                                'typoutput' not in data or \
+                                data['typinput'] is None or \
+                                data['typoutput'] is None:
+                    return "-- definition incomplete"
 
             # Privileges
             if 'typacl' in data and data['typacl'] is not None:
diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/js/type.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/js/type.js
index 4c101fd..775ef2d 100644
--- a/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/js/type.js
+++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/types/templates/type/js/type.js
@@ -789,42 +789,72 @@ function($, _, S, pgAdmin, pgBrowser, alertify, Backgrid) {
 
           this.errorModel.clear();
 
-          if (_.has(changedAttrs, 'name') &&
-                (_.isUndefined(this.get('name'))
-              || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '')) {
+          if (
+            _.isUndefined(this.get('name')) ||
+            _.isNull(this.get('name')) ||
+            String(this.get('name')).replace(/^\s+|\s+$/g, '') == ''
+          ) {
             msg = '{{ _('Name cannot be empty.') }}';
             this.errorModel.set('name', msg);
-          } else if (_.has(changedAttrs, 'schema') &&
-                (_.isUndefined(this.get('schema'))
-              || String(this.get('schema')).replace(/^\s+|\s+$/g, '') == '')) {
+            return msg;
+          }
+
+          if (
+            _.isUndefined(this.get('schema')) ||
+            _.isNull(this.get('schema')) ||
+            String(this.get('schema')).replace(/^\s+|\s+$/g, '') == ''
+          ) {
             msg = '{{ _('Schema cannot be empty.') }}';
             this.errorModel.set('schema', msg);
-          } else if (_.has(changedAttrs, 'typtype') &&
-                (_.isUndefined(this.get('typtype'))
-              || String(this.get('name')).replace(/^\s+|\s+$/g, '') == '')) {
+            return msg;
+          }
+
+          if (
+            _.isUndefined(this.get('typtype')) ||
+            _.isNull(this.get('typtype')) ||
+            String(this.get('typtype')).replace(/^\s+|\s+$/g, '') == ''
+          ) {
             msg = '{{ _('Type cannot be empty.') }}';
             this.errorModel.set('typtype', msg);
-          } else if (this.get('typtype') == 'r' &&
-                _.has(changedAttrs, 'typname')
-              && (_.isUndefined(this.get('typname'))
-              || String(this.get('typname')).replace(/^\s+|\s+$/g, '') == '')) {
-            msg = '{{ _('Subtype name cannot be empty.') }}';
-            this.errorModel.set('typname', msg);
-          } else if (this.get('typtype') == 'x' &&
-                _.has(changedAttrs, 'typinput')
-              && (_.isUndefined(this.get('typinput'))
-              || String(this.get('typinput')).replace(/^\s+|\s+$/g, '') == '')) {
-            msg = '{{ _('Input function cannot be empty.') }}';
-            this.errorModel.set('typinput', msg);
-          } else if (this.get('typtype') == 'x' &&
-                _.has(changedAttrs, 'typoutput')
-              && (_.isUndefined(this.get('typoutput'))
-              || String(this.get('typoutput')).replace(/^\s+|\s+$/g, '') == '')) {
-            msg = '{{ _('Output function cannot be empty.') }}';
-            this.errorModel.set('typoutput', msg);
+            return msg;
+          }
+
+          // For Range
+          if(this.get('typtype') == 'r') {
+              if (
+                _.isUndefined(this.get('typname')) ||
+                _.isNull(this.get('typname')) ||
+                String(this.get('typname')).replace(/^\s+|\s+$/g, '') == ''
+              ) {
+                msg = '{{ _('Subtype name cannot be empty.') }}';
+                this.errorModel.set('typname', msg);
+                return msg;
+              }
+          }
+
+          // For External
+          if(this.get('typtype') == 'b') {
+              if (
+                _.isUndefined(this.get('typinput')) ||
+                _.isNull(this.get('typinput')) ||
+                String(this.get('typinput')).replace(/^\s+|\s+$/g, '') == ''
+              ) {
+                msg = '{{ _('Input function cannot be empty.') }}';
+                this.errorModel.set('typinput', msg);
+                return msg;
+              }
+              if (
+                _.isUndefined(this.get('typoutput')) ||
+                _.isNull(this.get('typoutput')) ||
+                String(this.get('typoutput')).replace(/^\s+|\s+$/g, '') == ''
+              ) {
+                msg = '{{ _('Output function cannot be empty.') }}';
+                this.errorModel.set('typoutput', msg);
+                return msg;
+              }
           }
 
-          return msg ? msg : null;
+          return null;
         },
         // We will disable everything if we are under catalog node
         inSchema: function() {

-- 
Sent via pgadmin-hackers mailing list ([email-masked])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgadmin-hackers

---

From: Dave Page <[email-masked]>
Date: Tue, 6 Jun 2017 11:24:54 +0100

Thanks, applied.

-- 
Dave Page
Blog: http://pgsnake.blogspot.com
Twitter: @pgsnake

EnterpriseDB UK: http://www.enterprisedb.com
The Enterprise PostgreSQL Company