diff --git a/db/other.db b/db/other.db index 9d54596..7e235f4 100644 Binary files a/db/other.db and b/db/other.db differ diff --git a/db/test.db b/db/test.db index a05030f..bfbe8c4 100644 Binary files a/db/test.db and b/db/test.db differ diff --git a/modules/__pycache__/index.cpython-37.pyc b/modules/__pycache__/index.cpython-37.pyc index a7134b4..eeff6c6 100644 Binary files a/modules/__pycache__/index.cpython-37.pyc and b/modules/__pycache__/index.cpython-37.pyc differ diff --git a/modules/htmlize.py b/modules/htmlize.py new file mode 100644 index 0000000..1ab8329 --- /dev/null +++ b/modules/htmlize.py @@ -0,0 +1,88 @@ +import config + +def tabelize(table_list): + ''' Construct a table out of + + Connect to DB, execute a query and return data + + Args: + *table_list:* tuple() / list(), rows and items as tuples / lists + + Sets: + *N/A* + + Returns: + *table:* str(), html table code made from tuples / lists + + Raises: + *N/A* + + ''' + table = '' + for row in table_list: + table += '' + if not isinstance(row, (list,tuple)): + table += f"" + else: + for item in row: + table += f"" + table += '' + table += '
{row} {item}
' + return table + +def tabelize_links(table_list): + ''' Making a table with links + + Constructs a clickable link in HTML, so that the link points to ./link + + Args: + *table_list:* tuple() / list(), rows and items as tuples / lists + + Sets: + *N/A* + + Returns: + *table:* str(), html table code made from tuples / lists + + Raises: + *N/A* + + ''' + table = '' + for row in table_list: + table += '' + if not isinstance(row, (list, tuple)): + table += f"" + else: + for item in row: + table += f"" + table += '' + table += '
{row} {item}
' + return table + +def read_html(filename, _STATIC_DIR): + '''Read a html file + + Reads a file from a selected static directory - needs to be set as static + in the cherrypy (chttpd.py). + + Args: + ``filename`` *str()*, plain filename, without any path specification, + without extension + ``_STATIC_DIR`` *str()*, path relative to the project root, + where chttpd.py resides + + Returns: + *str()*, parsed html code from the read file, or a HTML + formatted error if file cannot be read for any reason + + Exceptions: + On file read fail, string with Exception text is returned + + ''' + read_path = config._ROOT+ _STATIC_DIR + filename + '.html' + try: + with open(read_path, 'r') as handle: + return handle.read() + except Exception as e: + return """
ERROR: {}!

{}""".format(e, read_path) diff --git a/modules/sqlite.py b/modules/sqlite.py index adeac4b..ebaa308 100644 --- a/modules/sqlite.py +++ b/modules/sqlite.py @@ -3,8 +3,57 @@ import cherrypy import config import sqlite3 import os +import json +from modules import htmlize +class Checker(object): + def __init__(self): + ''' Sanity check + Describes tables in DB, or lists the contents + + Args: + *None* + + Sets: + *N/A:* Nothing yet + + Returns: + *N/A:* boolean(), valid, or not? + + Raises: + *N/A* Nothing yet + + ''' + __name__ = "SQLite SQL validator" + + def is_table(db, table): + ''' Checks if table exists in a DB + + Escaping, sanitizing and checking what are we sending to the DB + + Args: + *query* Query to be sent to the DB + + Sets: + *N/A* + + Returns: + *result:* bool(), is the code to be executed OK, or not + + Raises: + *N/A* + + ''' + db_file = f"{config._ROOT}/{config._DB_PATH}/{db}" + try: + open(db_file) + except Exception as e: + result = [ False, e ] + + return result + + class select(object): def __init__(self): ''' SELECT method for API @@ -28,26 +77,6 @@ class select(object): self.html = '' self.json = '' - def CheckSelect(self): - ''' Checks and sanitizes a query - - Escaping, sanitizing and checking what are we sending to the DB - - Args: - *query* Query to be sent to the DB - - Sets: - *N/A* - - Returns: - *result:* bool(), is the code to be executed OK, or not - - Raises: - *N/A* - - ''' - return True - def _cp_dispatch(self, vpath): ''' Modify the request path, REST way @@ -69,11 +98,17 @@ class select(object): *N/A* ''' + dbs = os.listdir(f"{config._ROOT}/{config._DB_PATH}") if len(vpath) == 1: - cherrypy.request.params['schema'] = vpath.pop() - return self + schema = vpath.pop() + if schema in dbs: + cherrypy.request.params['schema'] = schema + return self + else: + del schema + return self - if len(vpath) == 2: + elif len(vpath) == 2: cherrypy.request.params['table'] = vpath.pop() cherrypy.request.params['db'] = vpath.pop() cherrypy.request.params['values'] = '*' @@ -100,11 +135,21 @@ class select(object): *N/A* ''' - db_file = f"{config._ROOT}/{db}" - try: - open(db_file) - except Exception as e: - raise RuntimeError(f"ERROR: Unable to read DB file: {e}") + db_file = f"{config._ROOT}/{config._DB_PATH}/{db}" + if os.path.exists(db_file): + error = False + if os.path.isfile(db_file): + error = False + else: + error = f"{db_file} is not a standard file" + html_result = htmlize.read_html('error', '/templates/') + result = html_result.format(_error=error) + return result + else: + error = f"{db_file} does not exist" + html_result = htmlize.read_html('error', '/templates/') + result = html_result.format(_error=error) + return result conn = sqlite3.connect(db_file) c = conn.cursor() if len(kwargs) == 0: @@ -117,32 +162,6 @@ class select(object): conn.close() return result - def tabelize(self, table_list): - ''' Calling the actual data from DB - - Connect to DB, execute a query and return data - - Args: - *table_list:* tuple() / list(), rows and items as tuples / lists - - Sets: - *N/A* - - Returns: - *table:* str(), html table code made from tuples / lists - - Raises: - *N/A* - - ''' - table = '' - for row in table_list: - table += '' - for item in row: - table += f"" - table += '' - table += '
{item}
' - return table @cherrypy.expose def index(self, **kwargs): @@ -166,19 +185,74 @@ class select(object): *N/A* ''' - if 'schema' in kwargs.keys(): - result = self.sqlite_wrapper( - kwargs["schema"] - ) - else: - result = self.sqlite_wrapper( - kwargs['db'], - table=kwargs['table'], - values=kwargs['values'] - ) self.html = '' - self.html += self.tabelize(result) - return self.html + self.json = {} + url = cherrypy.url() + if 'schema' in kwargs.keys(): + # No table is defined, we want the 'schema' of the DB + try: + db = kwargs["schema"] + result = self.sqlite_wrapper(db) + status = 'OK' + except Exception as e: + result = '' + status = f"ERROR: {e}" + self.html = htmlize.read_html('schema','/templates/') + # schema has weird structure, returns (val,) hence schema[0] + # [2] - third element '[0]CREATE [1]TABLE [2]'xyz' ... + tables = [schema[0].split(' ')[2].strip('\'') for schema in result] + self.html = self.html.format( + _db=db, + _schema=htmlize.tabelize(result), + _tables=htmlize.tabelize_links(tables), + _status=status + ) + self.json.update({ + "result": {"tables": tables}, + "status": status + }) + elif 'table' in kwargs.keys(): + # In case a table is defined, what are the values? + db = kwargs['db'] + table = kwargs['table'] + try: + result = self.sqlite_wrapper( + db, + table=table, + values=kwargs['values'] + ) + status = 'OK' + except Exception as e: + result = '' + status = f"ERROR: {e}" + self.html = htmlize.read_html('table','/templates/') + self.html = self.html.format( + _db=db, + _table=table, + _rows=htmlize.tabelize(result), + _status=status + ) + self.json.update({ + "result": {"rows": result}, + "status": status + }) + elif url.split('/')[-2] == 'select': + #No DB, nor table is defined, list DBs in config._DB_PATH + dbs = os.listdir(f"{config._ROOT}/{config._DB_PATH}") + result = [db for db in dbs] + self.html += htmlize.tabelize_links(result) + self.json.update({ + "result":{"databases": result}, + "status": "OK" + }) + else: + result = htmlize.read_html('error', '/templates/') + e = f'DB is non existent, or wrong parameter specified. Check URL' + return result.format(_error=e) + if 'json' in kwargs.keys(): + return json.dumps(self.json) + else: + return self.html class insert(object): diff --git a/templates/dbs.html b/templates/dbs.html new file mode 100644 index 0000000..34e438f --- /dev/null +++ b/templates/dbs.html @@ -0,0 +1,6 @@ +

DB Schema for {_db}

+{_schema} +

Tables:

+{_tables} +
+
Result: {_status}
diff --git a/templates/error.html b/templates/error.html new file mode 100644 index 0000000..9d488b3 --- /dev/null +++ b/templates/error.html @@ -0,0 +1,2 @@ +

ERROR

+

{_error}

diff --git a/templates/schema.html b/templates/schema.html new file mode 100644 index 0000000..34e438f --- /dev/null +++ b/templates/schema.html @@ -0,0 +1,6 @@ +

DB Schema for {_db}

+{_schema} +

Tables:

+{_tables} +
+
Result: {_status}
diff --git a/templates/table.html b/templates/table.html new file mode 100644 index 0000000..8d26c11 --- /dev/null +++ b/templates/table.html @@ -0,0 +1,6 @@ +

DB '{_db}' / Table '{_table}'

+
+ {_rows} +
+
+
Result: {_status}