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 653c6b5d4..5ecef14f2 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 @@ -176,6 +176,65 @@ class DomainView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare): keys_to_ignore = ['oid', 'basensp', 'conoid', 'nspname', 'oid-2'] + @staticmethod + def _get_req_data(kwargs): + """ + Get req data from request. + :param kwargs: kwargs. + :return: if any error return error, else return req. + """ + if request.data: + req = json.loads(request.data, encoding='utf-8') + else: + req = request.args or request.form + + if 'doid' not in kwargs: + required_args = [ + 'name', + 'basetype' + ] + + for arg in required_args: + if arg not in req or req[arg] == '': + return req, True, make_json_response( + status=410, + success=0, + errormsg=gettext( + "Could not find the required parameter ({})." + ).format(arg), + ) + return req, False, '' + + @staticmethod + def _get_data(req): + """ + Get data from request and update required values. + :param req: request object. + :return: data. + """ + data = {} + list_params = [] + if request.method == 'GET': + list_params = ['constraints', 'seclabels'] + + for key in req: + if ( + key in list_params and req[key] != '' and + req[key] is not None + ): + # Coverts string into python list as expected. + data[key] = json.loads(req[key], encoding='utf-8') + elif key == 'typnotnull': + if req[key] == 'true' or req[key] is True: + data[key] = True + elif req[key] == 'false' or req[key] is False: + data[key] = False + else: + data[key] = '' + else: + data[key] = req[key] + return data + def validate_request(f): """ Works as a decorator. @@ -193,49 +252,12 @@ class DomainView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare): @wraps(f) def wrap(self, **kwargs): - data = {} - if request.data: - req = json.loads(request.data, encoding='utf-8') - else: - req = request.args or request.form - - if 'doid' not in kwargs: - required_args = [ - 'name', - 'basetype' - ] - - for arg in required_args: - if arg not in req or req[arg] == '': - return make_json_response( - status=410, - success=0, - errormsg=gettext( - "Could not find the required parameter ({})." - ).format(arg) - ) + req, is_error, errmsg = DomainView._get_req_data(kwargs) + if is_error: + return errmsg try: - list_params = [] - if request.method == 'GET': - list_params = ['constraints', 'seclabels'] - - for key in req: - if ( - key in list_params and req[key] != '' and - req[key] is not None - ): - # Coverts string into python list as expected. - data[key] = json.loads(req[key], encoding='utf-8') - elif key == 'typnotnull': - if req[key] == 'true' or req[key] is True: - data[key] = True - elif req[key] == 'false' or req[key] is False: - data[key] = False - else: - data[key] = '' - else: - data[key] = req[key] + data = DomainView._get_data(req) except Exception as e: return internal_server_error(errormsg=str(e)) 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 2687c867e..ac8121d7a 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 @@ -179,6 +179,35 @@ class DomainConstraintView(PGChildNodeView): 'dependent': [{'get': 'dependents'}] }) + @staticmethod + def _get_req_data(kwargs): + """ + Get data from request. + :param kwargs: kwargs for request. + :return: if any error return error with error msg else return req data + """ + if request.data: + req = json.loads(request.data, encoding='utf-8') + else: + req = request.args or request.form + + if 'coid' not in kwargs: + required_args = [ + 'name', + 'consrc' + ] + + for arg in required_args: + if arg not in req or req[arg] == '': + return True, make_json_response( + status=410, + success=0, + errormsg=gettext( + "Could not find the required parameter ({})." + ).format(arg) + ), req + return False, '', req + def validate_request(f): """ Works as a decorator. @@ -195,26 +224,9 @@ class DomainConstraintView(PGChildNodeView): def wrap(self, **kwargs): data = {} - if request.data: - req = json.loads(request.data, encoding='utf-8') - else: - req = request.args or request.form - - if 'coid' not in kwargs: - required_args = [ - 'name', - 'consrc' - ] - - for arg in required_args: - if arg not in req or req[arg] == '': - return make_json_response( - status=410, - success=0, - errormsg=gettext( - "Could not find the required parameter ({})." - ).format(arg) - ) + is_error, errmsg, req = DomainConstraintView._get_req_data(kwargs) + if is_error: + return errmsg try: for key in req: diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/__init__.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/__init__.py index 789376a6e..17202a969 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/__init__.py @@ -583,23 +583,102 @@ class ColumnsView(PGChildNodeView, DataTypeReader): except Exception as e: return internal_server_error(errormsg=str(e)) + def _parse_acl_to_db_parsing(self, data, old_data): + """ + Convert acl coming from client to required db parsing format. + :param data: Data. + :param old_data: old data for comparision and get name. + """ + # If name is not present in data then + # we will fetch it from old data, we also need schema & table name + if 'name' not in data: + data['name'] = old_data['name'] + + # Convert acl coming from client in db parsing format + key = 'attacl' + if key in data and data[key] is not None: + if 'added' in data[key]: + data[key]['added'] = parse_priv_to_db( + data[key]['added'], self.acl + ) + if 'changed' in data[key]: + data[key]['changed'] = parse_priv_to_db( + data[key]['changed'], self.acl + ) + if 'deleted' in data[key]: + data[key]['deleted'] = parse_priv_to_db( + data[key]['deleted'], self.acl + ) + + def _get_sql_for_create(self, data, is_sql): + """ + Get sql for create column model. + :param data: Data. + :param is_sql: flag for get sql. + :return: if any error return error else return sql. + """ + required_args = [ + 'name', + 'cltype' + ] + + for arg in required_args: + if arg not in data: + return True, gettext('-- definition incomplete'), '' + + # We will convert privileges coming from client required + # in server side format + if 'attacl' in data: + data['attacl'] = parse_priv_to_db(data['attacl'], + self.acl) + # If the request for new object which do not have did + sql = render_template( + "/".join([self.template_path, self._CREATE_SQL]), + data=data, conn=self.conn, is_sql=is_sql + ) + + return False, '', sql + + def _check_type(self, data, old_data): + """ + Check cltype and get required data form it. + :param data: Data. + :param old_data: old data for check and get default values. + """ + # check type for '[]' in it + if 'cltype' in old_data: + old_data['cltype'], old_data['hasSqrBracket'] = \ + column_utils.type_formatter(old_data['cltype']) + + if 'cltype' in data and data['cltype'] != old_data['cltype']: + length, precision, typeval = \ + self.get_length_precision(data['cltype']) + + # if new datatype does not have length or precision + # then we cannot apply length or precision of old + # datatype to new one. + if not length: + old_data['attlen'] = -1 + if not precision: + old_data['attprecision'] = None + def get_sql(self, scid, tid, clid, data, is_sql=False): """ - This function will genrate sql from model data + This function will generate sql from model data """ data = column_utils.convert_length_precision_to_string(data) if clid is not None: - SQL = render_template( + sql = render_template( "/".join([self.template_path, self._PROPERTIES_SQL]), tid=tid, clid=clid, show_sys_objects=self.blueprint.show_system_objects ) - status, res = self.conn.execute_dict(SQL) + status, res = self.conn.execute_dict(sql) if not status: return internal_server_error(errormsg=res) - if len(res['rows']) == 0: + elif len(res['rows']) == 0: return gone( gettext("Could not find the column on the server.") ) @@ -610,69 +689,19 @@ class ColumnsView(PGChildNodeView, DataTypeReader): old_data = column_utils.column_formatter( self.conn, tid, clid, old_data) - # check type for '[]' in it - if 'cltype' in old_data: - old_data['cltype'], old_data['hasSqrBracket'] = \ - column_utils.type_formatter(old_data['cltype']) + self._check_type(data, old_data) + self._parse_acl_to_db_parsing(data, old_data) - if 'cltype' in data and data['cltype'] != old_data['cltype']: - length, precision, typeval = \ - self.get_length_precision(data['cltype']) - - # if new datatype does not have length or precision - # then we cannot apply length or precision of old - # datatype to new one. - if not length: - old_data['attlen'] = -1 - if not precision: - old_data['attprecision'] = None - - # If name is not present in data then - # we will fetch it from old data, we also need schema & table name - if 'name' not in data: - data['name'] = old_data['name'] - - # Convert acl coming from client in db parsing format - key = 'attacl' - if key in data and data[key] is not None: - if 'added' in data[key]: - data[key]['added'] = parse_priv_to_db( - data[key]['added'], self.acl - ) - if 'changed' in data[key]: - data[key]['changed'] = parse_priv_to_db( - data[key]['changed'], self.acl - ) - if 'deleted' in data[key]: - data[key]['deleted'] = parse_priv_to_db( - data[key]['deleted'], self.acl - ) - - SQL = render_template( + sql = render_template( "/".join([self.template_path, self._UPDATE_SQL]), data=data, o_data=old_data, conn=self.conn ) else: - required_args = [ - 'name', - 'cltype' - ] + is_error, errmsg, sql = self._get_sql_for_create(data, is_sql) + if is_error: + return errmsg - for arg in required_args: - if arg not in data: - return gettext('-- definition incomplete') - - # We will convert privileges coming from client required - # in server side format - if 'attacl' in data: - data['attacl'] = parse_priv_to_db(data['attacl'], - self.acl) - # If the request for new object which do not have did - SQL = render_template( - "/".join([self.template_path, self._CREATE_SQL]), - data=data, conn=self.conn, is_sql=is_sql - ) - return SQL, data['name'] if 'name' in data else old_data['name'] + return sql, data['name'] if 'name' in data else old_data['name'] @check_precondition def sql(self, gid, sid, did, scid, tid, clid): diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/utils.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/utils.py index 8b55d26da..cd6d772bc 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/utils.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/columns/utils.py @@ -241,6 +241,53 @@ def get_formatted_columns(conn, tid, data, other_columns, return data +def _parse_column_actions(final_columns, column_acl): + """ + Check action and access for it. + :param final_columns: final column list + :param column_acl: Column access. + """ + for c in final_columns: + if 'attacl' in c: + if 'added' in c['attacl']: + c['attacl']['added'] = parse_priv_to_db( + c['attacl']['added'], column_acl + ) + elif 'changed' in c['attacl']: + c['attacl']['changed'] = parse_priv_to_db( + c['attacl']['changed'], column_acl + ) + elif 'deleted' in c['attacl']: + c['attacl']['deleted'] = parse_priv_to_db( + c['attacl']['deleted'], column_acl + ) + if 'cltype' in c: + # check type for '[]' in it + c['cltype'], c['hasSqrBracket'] = \ + type_formatter(c['cltype']) + + c = convert_length_precision_to_string(c) + + +def _parse_format_col_for_edit(data, columns, column_acl): + """ + This function parser columns for edit mode. + :param data: Data from req. + :param columns: Columns list from data + :param column_acl: Column access. + """ + for action in ['added', 'changed']: + if action in columns: + final_columns = [] + for c in columns[action]: + if 'inheritedfrom' not in c: + final_columns.append(c) + + _parse_column_actions(final_columns, column_acl) + + data['columns'][action] = final_columns + + def parse_format_columns(data, mode=None): """ This function will parse and return formatted list of columns @@ -254,35 +301,7 @@ def parse_format_columns(data, mode=None): columns = data['columns'] # 'EDIT' mode if mode is not None: - for action in ['added', 'changed']: - if action in columns: - final_columns = [] - for c in columns[action]: - if 'inheritedfrom' not in c: - final_columns.append(c) - - for c in final_columns: - if 'attacl' in c: - if 'added' in c['attacl']: - c['attacl']['added'] = parse_priv_to_db( - c['attacl']['added'], column_acl - ) - elif 'changed' in c['attacl']: - c['attacl']['changed'] = parse_priv_to_db( - c['attacl']['changed'], column_acl - ) - elif 'deleted' in c['attacl']: - c['attacl']['deleted'] = parse_priv_to_db( - c['attacl']['deleted'], column_acl - ) - if 'cltype' in c: - # check type for '[]' in it - c['cltype'], c['hasSqrBracket'] = \ - type_formatter(c['cltype']) - - c = convert_length_precision_to_string(c) - - data['columns'][action] = final_columns + _parse_format_col_for_edit(data, columns, column_acl) else: # We need to exclude all the columns which are inherited from other # tables 'CREATE' mode diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/utils.py b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/utils.py index f216adfbb..3c9e2e493 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/utils.py +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/tables/constraints/exclusion_constraint/utils.py @@ -59,6 +59,31 @@ def get_parent(conn, tid, template_path=None): return schema, table +def _get_columns(res): + """ + Get columns form response and return in required format. + :param res: response form constraints. + :return: column list. + """ + columns = [] + for row in res['rows']: + if row['options'] & 1: + order = False + nulls_order = True if (row['options'] & 2) else False + else: + order = True + nulls_order = True if (row['options'] & 2) else False + + columns.append({"column": row['coldef'].strip('"'), + "oper_class": row['opcname'], + "order": order, + "nulls_order": nulls_order, + "operator": row['oprname'], + "col_type": row['datatype'] + }) + return columns + + @get_template_path def get_exclusion_constraints(conn, did, tid, exid=None, template_path=None): """ @@ -87,22 +112,7 @@ def get_exclusion_constraints(conn, did, tid, exid=None, template_path=None): if not status: return status, internal_server_error(errormsg=res) - columns = [] - for row in res['rows']: - if row['options'] & 1: - order = False - nulls_order = True if (row['options'] & 2) else False - else: - order = True - nulls_order = True if (row['options'] & 2) else False - - columns.append({"column": row['coldef'].strip('"'), - "oper_class": row['opcname'], - "order": order, - "nulls_order": nulls_order, - "operator": row['oprname'], - "col_type": row['datatype'] - }) + columns = _get_columns(res) ex['columns'] = columns @@ -120,6 +130,28 @@ def get_exclusion_constraints(conn, did, tid, exid=None, template_path=None): return True, result['rows'] +def _get_delete_constraint(data, constraint, sql, template_path, conn): + """ + Check for delete constraints and return sql for it. + :param data: Data req. + :param constraint: Constraint list for check. + :param sql: sql list to append delete constraint sql. + :param template_path: Template path to fetch sql for delete constraint. + :param conn: Connection. + """ + if 'deleted' in constraint: + for c in constraint['deleted']: + c['schema'] = data['schema'] + c['table'] = data['name'] + + # Sql for drop + sql.append( + render_template("/".join( + [template_path, 'delete.sql']), + data=c, conn=conn).strip("\n") + ) + + @get_template_path def get_exclusion_constraint_sql(conn, did, tid, data, template_path=None): """ @@ -138,17 +170,7 @@ def get_exclusion_constraint_sql(conn, did, tid, data, template_path=None): if 'exclude_constraint' in data: constraint = data['exclude_constraint'] # If constraint(s) is/are deleted - if 'deleted' in constraint: - for c in constraint['deleted']: - c['schema'] = data['schema'] - c['table'] = data['name'] - - # Sql for drop - sql.append( - render_template("/".join( - [template_path, 'delete.sql']), - data=c, conn=conn).strip("\n") - ) + _get_delete_constraint(data, constraint, sql, template_path, conn) if 'changed' in constraint: for c in constraint['changed']: 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 5fb2b8cfe..e26e4896d 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 @@ -1066,18 +1066,12 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare): except Exception as e: return internal_server_error(errormsg=str(e)) - @check_precondition - def delete(self, gid, sid, did, scid, tid=None, only_sql=False): + def _get_req_delete_data(self, tid, only_sql): """ - This function will updates existing the type object - - Args: - gid: Server Group ID - sid: Server ID - did: Database ID - scid: Schema ID - tid: Type ID - only_sql: Return only sql if True + This function get data from request + :param tid: Table Id + :param only_sql: Flag for sql only. + :return: data and cascade flag. """ if tid is None: data = request.form if request.form else json.loads( @@ -1093,16 +1087,33 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare): else: cascade = False + return data, cascade + + @check_precondition + def delete(self, gid, sid, did, scid, tid=None, only_sql=False): + """ + This function will updates existing the type object + + Args: + gid: Server Group ID + sid: Server ID + did: Database ID + scid: Schema ID + tid: Type ID + only_sql: Return only sql if True + """ + data, cascade = self._get_req_delete_data(tid, only_sql) + try: for tid in data['ids']: - SQL = render_template( + sql = render_template( "/".join([self.template_path, self._PROPERTIES_SQL]), scid=scid, tid=tid, datlastsysoid=self.datlastsysoid, show_system_objects=self.blueprint.show_system_objects ) - status, res = self.conn.execute_dict(SQL) + status, res = self.conn.execute_dict(sql) if not status: return internal_server_error(errormsg=res) @@ -1121,7 +1132,7 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare): # Making copy of output for future use data = dict(res['rows'][0]) - SQL = render_template("/".join([self.template_path, + sql = render_template("/".join([self.template_path, self._DELETE_SQL]), data=data, cascade=cascade, @@ -1129,9 +1140,9 @@ class TypeView(PGChildNodeView, DataTypeReader, SchemaDiffObjectCompare): # Used for schema diff tool if only_sql: - return SQL + return sql - status, res = self.conn.execute_scalar(SQL) + status, res = self.conn.execute_scalar(sql) if not status: return internal_server_error(errormsg=res)