Fixed cognitive complexity issues reported by SonarQube.

This commit is contained in:
Nikhil Mohite 2020-07-17 15:29:27 +05:30 committed by Akshay Joshi
parent 13d2f9131d
commit 4e2c4b0498
4 changed files with 527 additions and 279 deletions

View File

@ -344,6 +344,25 @@ class ResourceGroupView(NodeView):
status=200
)
@staticmethod
def _check_req_parameters(data, required_args):
"""
This function is used to check the request parameter.
:param data:
:param required_args:
:return:
"""
for arg in required_args:
if arg not in data:
return True, make_json_response(
status=410,
success=0,
errormsg=gettext(
"Could not find the required parameter ({})."
).format(arg)
)
return False, ''
@check_precondition
def create(self, gid, sid):
"""
@ -360,15 +379,13 @@ class ResourceGroupView(NodeView):
data = request.form if request.form else json.loads(
request.data, encoding='utf-8'
)
for arg in required_args:
if arg not in data:
return make_json_response(
status=410,
success=0,
errormsg=gettext(
"Could not find the required parameter ({})."
).format(arg)
)
is_error, errmsg = ResourceGroupView._check_req_parameters(
data, required_args)
if is_error:
return errmsg
try:
# Below logic will create new resource group
sql = render_template(
@ -416,6 +433,32 @@ class ResourceGroupView(NodeView):
except Exception as e:
return internal_server_error(errormsg=str(e))
def _check_cpu_and_dirty_rate_limit(self, data, old_data):
"""
Below logic will update the cpu_rate_limit and dirty_rate_limit
for resource group we need to add this logic because in
resource group you can't run multiple commands in one
transaction.
:param data:
:param old_data:
:return:
"""
# Below logic will update the cpu_rate_limit and dirty_rate_limit
# for resource group we need to add this logic because in
# resource group you can't run multiple commands in one
# transaction.
if data['cpu_rate_limit'] != old_data['cpu_rate_limit'] or \
data['dirty_rate_limit'] != old_data['dirty_rate_limit']:
sql = render_template(
"/".join([self.sql_path, 'update.sql']),
data=data, conn=self.conn
)
if sql and sql.strip('\n') and sql.strip(' '):
status, res = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=res)
@check_precondition
def update(self, gid, sid, rg_id):
"""
@ -459,16 +502,7 @@ class ResourceGroupView(NodeView):
# for resource group we need to add this logic because in
# resource group you can't run multiple commands in one
# transaction.
if data['cpu_rate_limit'] != old_data['cpu_rate_limit'] or \
data['dirty_rate_limit'] != old_data['dirty_rate_limit']:
sql = render_template(
"/".join([self.sql_path, 'update.sql']),
data=data, conn=self.conn
)
if sql and sql.strip('\n') and sql.strip(' '):
status, res = self.conn.execute_scalar(sql)
if not status:
return internal_server_error(errormsg=res)
self._check_cpu_and_dirty_rate_limit(data, old_data)
return jsonify(
node=self.blueprint.generate_browser_node(
@ -571,6 +605,50 @@ class ResourceGroupView(NodeView):
status=200
)
def _get_update_sql(self, rg_id, data, required_args):
"""
This function is used to get the sql for resource group
:param rg_id:
:param data:
:param required_args:
:return:
"""
sql = render_template(
"/".join([self.sql_path, 'properties.sql']), rgid=rg_id)
status, res = self.conn.execute_dict(sql)
if not status:
return internal_server_error(errormsg=res)
if len(res['rows']) == 0:
return gone(
gettext("The specified resource group could not be found.")
)
old_data = res['rows'][0]
for arg in required_args:
if arg not in data:
data[arg] = old_data[arg]
sql = ''
name_changed = False
if data['name'] != old_data['name']:
name_changed = True
sql = render_template(
"/".join([self.sql_path, 'update.sql']),
oldname=old_data['name'], newname=data['name'],
conn=self.conn
)
if data['cpu_rate_limit'] != old_data['cpu_rate_limit'] or \
data['dirty_rate_limit'] != old_data['dirty_rate_limit']:
if name_changed:
sql += "\n-- Following query will be executed in a " \
"separate transaction\n"
sql += render_template(
"/".join([self.sql_path, 'update.sql']),
data=data, conn=self.conn
)
return sql, old_data['name']
def get_sql(self, data, rg_id=None):
"""
This function will generate sql from model data
@ -582,40 +660,11 @@ class ResourceGroupView(NodeView):
required_args = [
'name', 'cpu_rate_limit', 'dirty_rate_limit'
]
old_name = ''
if rg_id is not None:
sql = render_template(
"/".join([self.sql_path, 'properties.sql']), rgid=rg_id)
status, res = self.conn.execute_dict(sql)
if not status:
return internal_server_error(errormsg=res)
if len(res['rows']) == 0:
return gone(
gettext("The specified resource group could not be found.")
)
old_data = res['rows'][0]
for arg in required_args:
if arg not in data:
data[arg] = old_data[arg]
sql = ''
name_changed = False
if data['name'] != old_data['name']:
name_changed = True
sql = render_template(
"/".join([self.sql_path, 'update.sql']),
oldname=old_data['name'], newname=data['name'],
conn=self.conn
)
if data['cpu_rate_limit'] != old_data['cpu_rate_limit'] or \
data['dirty_rate_limit'] != old_data['dirty_rate_limit']:
if name_changed:
sql += "\n-- Following query will be executed in a " \
"separate transaction\n"
sql += render_template(
"/".join([self.sql_path, 'update.sql']),
data=data, conn=self.conn
)
# Get sql for Resource group by ID.
sql, old_name = self._get_update_sql(rg_id, data, required_args)
else:
sql = render_template(
"/".join([self.sql_path, 'create.sql']),
@ -638,7 +687,7 @@ class ResourceGroupView(NodeView):
data=data, conn=self.conn
)
return sql, data['name'] if 'name' in data else old_data['name']
return sql, data['name'] if 'name' in data else old_name
@check_precondition
def sql(self, gid, sid, rg_id):

View File

@ -111,6 +111,142 @@ class RoleView(PGChildNodeView):
'variables': [{'get': 'variables'}],
})
@staticmethod
def _get_request_data():
"""
Get data from client request.
"""
if request.data:
data = json.loads(request.data, encoding='utf-8')
else:
data = dict()
req = request.args or request.form
for key in req:
val = req[key]
if key in [
u'rolcanlogin', u'rolsuper', u'rolcreatedb',
u'rolcreaterole', u'rolinherit', u'rolreplication',
u'rolcatupdate', u'variables', u'rolmembership',
u'seclabels'
]:
data[key] = json.loads(val, encoding='utf-8')
else:
data[key] = val
return data
@staticmethod
def _check_roleconnlimit(data):
"""
Check connection limit for role.
"""
if u'rolconnlimit' in data:
# If roleconnlimit is empty string then set it to -1
if data[u'rolconnlimit'] == '':
data[u'rolconnlimit'] = -1
if data[u'rolconnlimit'] is not None:
data[u'rolconnlimit'] = int(data[u'rolconnlimit'])
if type(data[u'rolconnlimit']) != int or \
data[u'rolconnlimit'] < -1:
return True, "Connection limit must be an integer value " \
"or equal to -1."
return False, ''
@staticmethod
def _check_role(data):
"""
Check user role
"""
msg = _("""
Role membership information must be passed as an array of JSON objects
in the following format:
rolmembership:[{
role: [rolename],
admin: True/False
},
...
]""")
if type(data[u'rolmembership']) != list:
return True, msg
data[u'members'] = []
data[u'admins'] = []
for r in data[u'rolmembership']:
if type(r) != dict or u'role' not in r or \
u'admin' not in r:
return True, msg
else:
if r[u'admin']:
data[u'admins'].append(r[u'role'])
else:
data[u'members'].append(r[u'role'])
return False, ''
@staticmethod
def _check_precondition_added(data):
"""
Check for pre condition for added
"""
if u'added' in data[u'rolmembership']:
roles = (data[u'rolmembership'])[u'added']
if type(roles) != list:
return True
for r in roles:
if type(r) != dict or \
u'role' not in r or \
u'admin' not in r:
return True
if r[u'admin']:
data[u'admins'].append(r[u'role'])
else:
data[u'members'].append(r[u'role'])
return False
@staticmethod
def _check_precondition_deleted(data):
if u'deleted' in data[u'rolmembership']:
roles = (data[u'rolmembership'])[u'deleted']
if type(roles) != list:
return True
for r in roles:
if type(r) != dict or u'role' not in r:
return True
data[u'revoked'].append(r[u'role'])
return False
@staticmethod
def _check_precondition_change(data):
if u'changed' in data[u'rolmembership']:
roles = (data[u'rolmembership'])[u'changed']
if type(roles) != list:
return True
for r in roles:
if type(r) != dict or \
u'role' not in r or \
u'admin' not in r:
return True
if not r[u'admin']:
data[u'revoked_admins'].append(r[u'role'])
else:
data[u'admins'].append(r[u'role'])
return False
def validate_request(f):
@wraps(f)
def wrap(self, **kwargs):
@ -444,6 +580,81 @@ rolmembership:{
return wrap
@staticmethod
def _check_action(action, kwargs):
check_permission = False
fetch_name = False
forbidden_msg = None
if action in ['drop', 'update']:
if 'rid' in kwargs:
fetch_name = True
check_permission = True
if action == 'drop':
forbidden_msg = _(
"The current user does not have permission to drop"
" the role."
)
else:
forbidden_msg = _(
"The current user does not have permission to "
"update the role."
)
elif action == 'create':
check_permission = True
forbidden_msg = _(
"The current user does not have permission to create "
"the role."
)
elif action == 'msql' and 'rid' in kwargs:
fetch_name = True
return fetch_name, check_permission, forbidden_msg
def _check_permission(self, check_permission, action, kwargs):
if check_permission:
user = self.manager.user_info
if not user['is_superuser'] and \
not user['can_create_role'] and \
(action != 'update' or 'rid' in kwargs) and \
kwargs['rid'] != -1 and \
user['id'] != kwargs['rid']:
return True
return False
def _check_and_fetch_name(self, fetch_name, kwargs):
if fetch_name:
status, res = self.conn.execute_dict(
render_template(
self.sql_path + 'permission.sql',
rid=kwargs['rid'],
conn=self.conn
)
)
if not status:
return True, internal_server_error(
_(
"Error retrieving the role information.\n{0}"
).format(res)
)
if len(res['rows']) == 0:
return True, gone(
_("Could not find the role on the database "
"server.")
)
row = res['rows'][0]
self.role = row['rolname']
self.rolCanLogin = row['rolcanlogin']
self.rolCatUpdate = row['rolcatupdate']
self.rolSuper = row['rolsuper']
return False, ''
def check_precondition(action=None):
"""
This function will behave as a decorator which will checks the status
@ -488,72 +699,18 @@ rolmembership:{
u'rolvaliduntil', u'rolpassword'
]
check_permission = False
fetch_name = False
forbidden_msg = None
fetch_name, check_permission, \
forbidden_msg = RoleView._check_action(action, kwargs)
if action in ['drop', 'update']:
if 'rid' in kwargs:
fetch_name = True
check_permission = True
is_permission_error = self._check_permission(check_permission,
action, kwargs)
if is_permission_error:
return forbidden(forbidden_msg)
if action == 'drop':
forbidden_msg = _(
"The current user does not have permission to drop"
" the role."
)
else:
forbidden_msg = _(
"The current user does not have permission to "
"update the role."
)
elif action == 'create':
check_permission = True
forbidden_msg = _(
"The current user does not have permission to create "
"the role."
)
elif action == 'msql' and 'rid' in kwargs:
fetch_name = True
if check_permission:
user = self.manager.user_info
if not user['is_superuser'] and \
not user['can_create_role'] and \
(action != 'update' or 'rid' in kwargs) and \
kwargs['rid'] != -1 and \
user['id'] != kwargs['rid']:
return forbidden(forbidden_msg)
if fetch_name:
status, res = self.conn.execute_dict(
render_template(
self.sql_path + 'permission.sql',
rid=kwargs['rid'],
conn=self.conn
)
)
if not status:
return internal_server_error(
_(
"Error retrieving the role information.\n{0}"
).format(res)
)
if len(res['rows']) == 0:
return gone(
_("Could not find the role on the database "
"server.")
)
row = res['rows'][0]
self.role = row['rolname']
self.rolCanLogin = row['rolcanlogin']
self.rolCatUpdate = row['rolcatupdate']
self.rolSuper = row['rolsuper']
is_error, errmsg = self._check_and_fetch_name(fetch_name,
kwargs)
if is_error:
return errmsg
return f(self, **kwargs)
@ -932,6 +1089,74 @@ rolmembership:{
status=200
)
@staticmethod
def _handel_dependents_type(types, type_str, type_name, rel_name, row):
if types[type_str[0]] is None:
if type_str[0] == 'i':
type_name = 'index'
rel_name = row['indname'] + ' ON ' + rel_name
elif type_str[0] == 'o':
type_name = 'operator'
rel_name = row['relname']
else:
type_name = types[type_str[0]]
return type_name, rel_name
@staticmethod
def _handel_dependents_data(result, types, dependents, db_row):
for row in result['rows']:
rel_name = row['nspname']
if rel_name is not None:
rel_name += '.'
if rel_name is None:
rel_name = row['relname']
else:
rel_name += row['relname']
type_name = ''
type_str = row['relkind']
# Fetch the type name from the dictionary
# if type is not present in the types dictionary then
# we will continue and not going to add it.
if type_str[0] in types:
# if type is present in the types dictionary, but it's
# value is None then it requires special handling.
type_name, rel_name = RoleView._handel_dependents_type(
types, type_str, type_name, rel_name, row)
else:
continue
dependents.append(
{
'type': type_name,
'name': rel_name,
'field': db_row['datname']
}
)
def _temp_connection_check(self, rid, temp_conn, db_row, types,
dependents):
if temp_conn.connected():
query = render_template(
"/".join([self.sql_path, 'dependents.sql']),
fetch_dependents=True, rid=rid,
lastsysoid=db_row['datlastsysoid']
)
status, result = temp_conn.execute_dict(query)
if not status:
current_app.logger.error(result)
RoleView._handel_dependents_data(result, types, dependents, db_row)
@staticmethod
def _release_connection(is_connected, manager, db_row):
# Release only those connections which we have created above.
if not is_connected:
manager.release(db_row['datname'])
def get_dependents(self, conn, sid, rid):
"""
This function is used to fetch the dependents for the selected node.
@ -1009,59 +1234,9 @@ rolmembership:{
except Exception as e:
current_app.logger.exception(e)
if temp_conn.connected():
query = render_template(
"/".join([self.sql_path, 'dependents.sql']),
fetch_dependents=True, rid=rid,
lastsysoid=db_row['datlastsysoid']
)
status, result = temp_conn.execute_dict(query)
if not status:
current_app.logger.error(result)
for row in result['rows']:
rel_name = row['nspname']
if rel_name is not None:
rel_name += '.'
if rel_name is None:
rel_name = row['relname']
else:
rel_name += row['relname']
type_name = ''
type_str = row['relkind']
# Fetch the type name from the dictionary
# if type is not present in the types dictionary then
# we will continue and not going to add it.
if type_str[0] in types:
# if type is present in the types dictionary, but it's
# value is None then it requires special handling.
if types[type_str[0]] is None:
if type_str[0] == 'i':
type_name = 'index'
rel_name = row['indname'] + ' ON ' + rel_name
elif type_str[0] == 'o':
type_name = 'operator'
rel_name = row['relname']
else:
type_name = types[type_str[0]]
else:
continue
dependents.append(
{
'type': type_name,
'name': rel_name,
'field': db_row['datname']
}
)
# Release only those connections which we have created above.
if not is_connected:
manager.release(db_row['datname'])
self._temp_connection_check(rid, temp_conn, db_row, types,
dependents)
RoleView._release_connection(is_connected, manager, db_row)
return dependents

View File

@ -467,6 +467,22 @@ class TablespaceView(PGChildNodeView):
status=200
)
def _format_privilege_data(self, data):
for key in ['spcacl']:
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(self, gid, sid, data, tsid=None):
"""
This function will genrate sql from model/properties data
@ -494,20 +510,7 @@ class TablespaceView(PGChildNodeView):
old_data = self._formatter(old_data, tsid)
# To format privileges data coming from client
for key in ['spcacl']:
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
)
self._format_privilege_data(data)
# If name is not present with in update data then copy it
# from old data
@ -669,6 +672,61 @@ class TablespaceView(PGChildNodeView):
status=200
)
def _handel_dependents_type(self, types, type_str, row, rel_name):
type_name = ''
if types[type_str[0]] is None:
if type_str[0] == 'i':
type_name = 'index'
rel_name = row['indname'] + ' ON ' + rel_name
elif type_str[0] == 'o':
type_name = 'operator'
rel_name = row['relname']
else:
type_name = types[type_str[0]]
return type_name, rel_name
def _check_dependents_type(self, types, dependents, db_row, result):
for row in result['rows']:
rel_name = row['nspname']
if rel_name is not None:
rel_name += '.'
if rel_name is None:
rel_name = row['relname']
else:
rel_name += row['relname']
type_str = row['relkind']
# Fetch the type name from the dictionary
# if type is not present in the types dictionary then
# we will continue and not going to add it.
if type_str[0] in types:
# if type is present in the types dictionary, but it's
# value is None then it requires special handling.
type_name, rel_name = self._handel_dependents_type(types,
type_str,
row,
rel_name)
else:
continue
dependents.append(
{
'type': type_name,
'name': rel_name,
'field': db_row['datname']
}
)
def _create_dependents_data(self, types, result, dependents, db_row,
is_connected, manager):
self._check_dependents_type(types, dependents, db_row, result)
# Release only those connections which we have created above.
if not is_connected:
manager.release(db_row['datname'])
def get_dependents(self, conn, sid, tsid):
"""
This function is used to fetch the dependents for the selected node.
@ -746,48 +804,8 @@ class TablespaceView(PGChildNodeView):
if not status:
current_app.logger.error(result)
for row in result['rows']:
rel_name = row['nspname']
if rel_name is not None:
rel_name += '.'
if rel_name is None:
rel_name = row['relname']
else:
rel_name += row['relname']
type_name = ''
type_str = row['relkind']
# Fetch the type name from the dictionary
# if type is not present in the types dictionary then
# we will continue and not going to add it.
if type_str[0] in types:
# if type is present in the types dictionary, but it's
# value is None then it requires special handling.
if types[type_str[0]] is None:
if type_str[0] == 'i':
type_name = 'index'
rel_name = row['indname'] + ' ON ' + rel_name
elif type_str[0] == 'o':
type_name = 'operator'
rel_name = row['relname']
else:
type_name = types[type_str[0]]
else:
continue
dependents.append(
{
'type': type_name,
'name': rel_name,
'field': db_row['datname']
}
)
# Release only those connections which we have created above.
if not is_connected:
manager.release(db_row['datname'])
self._create_dependents_data(types, result, dependents, db_row,
is_connected, manager)
return dependents

View File

@ -36,6 +36,48 @@ def parse_priv_from_db(db_privileges):
return acl
def _check_privilege_type(priv):
if isinstance(priv['privileges'], dict) \
and 'changed' in priv['privileges']:
tmp = []
for p in priv['privileges']['changed']:
tmp_p = {'privilege_type': p['privilege_type'],
'privilege': False,
'with_grant': False}
if 'with_grant' in p:
tmp_p['privilege'] = True
tmp_p['with_grant'] = p['with_grant']
if 'privilege' in p:
tmp_p['privilege'] = p['privilege']
tmp.append(tmp_p)
priv['privileges'] = tmp
def _parse_privileges(priv, db_privileges, allowed_acls, priv_with_grant,
priv_without_grant):
_check_privilege_type(priv)
for privilege in priv['privileges']:
if privilege['privilege_type'] not in db_privileges:
continue
if privilege['privilege_type'] not in allowed_acls:
continue
if privilege['with_grant']:
priv_with_grant.append(
db_privileges[privilege['privilege_type']]
)
elif privilege['privilege']:
priv_without_grant.append(
db_privileges[privilege['privilege_type']]
)
def parse_priv_to_db(str_privileges, allowed_acls=[]):
"""
Common utility function to parse privileges before sending to database.
@ -66,41 +108,9 @@ def parse_priv_to_db(str_privileges, allowed_acls=[]):
priv_with_grant = []
priv_without_grant = []
if isinstance(priv['privileges'], dict) \
and 'changed' in priv['privileges']:
tmp = []
for p in priv['privileges']['changed']:
tmp_p = {'privilege_type': p['privilege_type'],
'privilege': False,
'with_grant': False}
_parse_privileges(priv, db_privileges, allowed_acls, priv_with_grant,
priv_without_grant)
if 'with_grant' in p:
tmp_p['privilege'] = True
tmp_p['with_grant'] = p['with_grant']
if 'privilege' in p:
tmp_p['privilege'] = p['privilege']
tmp.append(tmp_p)
priv['privileges'] = tmp
for privilege in priv['privileges']:
if privilege['privilege_type'] not in db_privileges:
continue
if privilege['privilege_type'] not in allowed_acls:
continue
if privilege['with_grant']:
priv_with_grant.append(
db_privileges[privilege['privilege_type']]
)
elif privilege['privilege']:
priv_without_grant.append(
db_privileges[privilege['privilege_type']]
)
# If we have all acl then just return all
if len(priv_with_grant) == allowed_acls_len > 1:
priv_with_grant = ['ALL']
@ -182,6 +192,20 @@ def validate_options(options, option_name, option_value):
return is_valid_options, valid_options
def _password_check(server, manager, old_key, new_key):
# Check if old password was stored in pgadmin4 sqlite database.
# If yes then update that password.
if server.password is not None:
password = decrypt(server.password, old_key)
if isinstance(password, bytes):
password = password.decode()
password = encrypt(password, new_key)
setattr(server, 'password', password)
manager.password = password
def reencrpyt_server_passwords(user_id, old_key, new_key):
"""
This function will decrypt the saved passwords in SQLite with old key
@ -193,25 +217,7 @@ def reencrpyt_server_passwords(user_id, old_key, new_key):
for server in Server.query.filter_by(user_id=user_id).all():
manager = driver.connection_manager(server.id)
# Check if old password was stored in pgadmin4 sqlite database.
# If yes then update that password.
if server.password is not None:
password = decrypt(server.password, old_key)
if isinstance(password, bytes):
password = password.decode()
password = encrypt(password, new_key)
setattr(server, 'password', password)
manager.password = password
elif manager.password is not None:
password = decrypt(manager.password, old_key)
if isinstance(password, bytes):
password = password.decode()
password = encrypt(password, new_key)
manager.password = password
_password_check(server, manager, old_key, new_key)
if server.tunnel_password is not None:
tunnel_password = decrypt(server.tunnel_password, old_key)