diff --git a/src/spaceandtime/sxtbaseapi.py b/src/spaceandtime/sxtbaseapi.py index 0e688fd..ade0b91 100644 --- a/src/spaceandtime/sxtbaseapi.py +++ b/src/spaceandtime/sxtbaseapi.py @@ -71,6 +71,26 @@ def prep_biscuits(self, biscuits=[]) -> list: def prep_sql(self, sql_text:str) -> str: + if not sql_text: + return '' + + sql = ' '.join(sql_text.split()) + parts = [] + in_quotes = False + current = [] + + for char in sql: + if char == "'": + in_quotes = not in_quotes + if in_quotes: + current.append(char) + else: + if char != ';' or len(current) > 0: + current.append(char) + + result = ''.join(current) + return result.strip() + """------------------- Cleans and prepares sql_text for transmission and execution on-network. diff --git a/src/spaceandtime/sxtbiscuits.py b/src/spaceandtime/sxtbiscuits.py index 98667e9..cc27bb2 100644 --- a/src/spaceandtime/sxtbiscuits.py +++ b/src/spaceandtime/sxtbiscuits.py @@ -180,27 +180,33 @@ def add_capability(self, resource:str, *permissions): if not resource: resource = self.__lastresource if not resource: raise KeyError('must define a resource (schema.object) on which to assign permissions') self.__lastresource = resource - if resource not in self.__cap: self.__cap[resource] = [] + + self.__cap.setdefault(resource, []) + if 'ALL' in self.__cap[resource] or '*' in self.__cap[resource]: - self.logger.warning('Cannot add other permissions to a biscuit containing ALL permissions. Request disregarded.') + self.logger.warning('Cannot add other permissions to a biscuit containing ALL permissions. Request disregarded.') return self.__isall__(resource) - initial_count = len(self.__cap[resource]) - process_count = 0 - final_permissions = [] - for permission in permissions: - process_count += 1 - if type(permission) == list: - if 'ALL' in permission: return self.__isall__(resource) - final_permissions += list(permission) - process_count += len(list(permission))-1 + + current_perms = set(self.__cap[resource]) + added_count = 0 + + for permission in permissions: + if isinstance(permission, list): + if 'ALL' in permission: + return self.__isall__(resource) + new_perms = {p.value for p in permission if p.name != 'ALL'} + current_perms.update(new_perms) + added_count += len(new_perms) else: - if permission.name == 'ALL': return self.__isall__(resource) - final_permissions.append(permission) - self.__cap[resource] += [p.value for p in final_permissions] - self.__cap[resource] = list(set(self.__cap[resource])) + if permission.name == 'ALL': + return self.__isall__(resource) + current_perms.add(permission.value) + added_count += 1 + + self.__cap[resource] = list(current_perms) self.__bt = '' - added_count = len(self.__cap[resource]) - initial_count - self.logger.info(f'Added {added_count} permissions, from total {process_count} submitted ({process_count - added_count} duplicates)') + + self.logger.info(f'Added {added_count} unique permissions') return added_count def __isall__(self, resource): @@ -436,4 +442,4 @@ def load(self, filepath: Path, resource:str = None, date:str = None, time:str = # Return a json object with information print( bis.to_json() ) - pass + pass \ No newline at end of file diff --git a/src/spaceandtime/sxtresource.py b/src/spaceandtime/sxtresource.py index 40f5315..40fe72e 100644 --- a/src/spaceandtime/sxtresource.py +++ b/src/spaceandtime/sxtresource.py @@ -369,16 +369,20 @@ def to_list(self, obscure_private_key:bool = True, Returns: list: List representation of the class. """ - rtn = [] - for n,v in self.to_dict(obscure_private_key=obscure_private_key, include_keys=include_keys).items(): - if n=='biscuits': - for bname, token in dict(v).items(): - rtn.append(func_biscuit_formatter(bname, token)) - elif 'ddl' in n or 'sql' in n: - rtn.append(func_sql_formatter(n,v)) - else: - rtn.append(func_line_formatter(n,v)) - return rtn + dict_items = self.to_dict( + obscure_private_key=obscure_private_key, + include_keys=include_keys + ).items() + + return [ + func_biscuit_formatter(bname, token) + if n == 'biscuits' + else func_sql_formatter(n, v) + if 'ddl' in n or 'sql' in n + else func_line_formatter(n, v) + for n, v in dict_items + for bname, token in ([('', '')] if n != 'biscuits' else dict(v).items()) + ] def get_first_valid_user(self, *users) -> SXTUser: @@ -778,23 +782,15 @@ def get_column_names(self) -> dict: object type, this is technically not guaranteed. """ rtn = {} - - # prep ddl to isolate columns - ddl = str(self.create_ddl).replace('\t',' ').replace('\n',' ').strip() - while ' ' in ddl: ddl = ddl.replace(' ',' ') - first_paren = ddl.find('(')+1 - for i in range(len(ddl), 1, -1): - if ddl[i:i+1] == ')': - last_paren = i - break - - # process columns - cols = [c.strip() for c in ddl[first_paren:last_paren].split(',') ] - for col in cols: - if col.lower().startswith('primary key'): continue - colname = col.split(' ')[0] - coltype = col.split(' ')[1] - rtn[colname] = coltype + ddl = ' '.join(self.create_ddl.split()) + columns_section = ddl[ddl.find('(')+1:ddl.rfind(')')].strip() + + for col in (c.strip() for c in columns_section.split(',')): + if col.lower().startswith('primary key'): + continue + parts = col.split(maxsplit=2) + if len(parts) >= 2: + rtn[parts[0]] = parts[1] return rtn