From d782d4da40bd3d2548aafb1554d77d13226ae984 Mon Sep 17 00:00:00 2001 From: Jake Pullen Date: Sun, 11 May 2025 14:04:35 +0100 Subject: [PATCH 01/13] =?UTF-8?q?feat:=20=E2=9C=A8=20stylesheet=20is=20now?= =?UTF-8?q?=20accessible?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/front/home.py | 11 ++++------- src/front/static/{style.css => verity_style.css} | 0 src/front/templates/base.html | 6 +++++- src/front/templates/home.html | 1 + src/verity.py | 3 +-- 5 files changed, 11 insertions(+), 10 deletions(-) rename src/front/static/{style.css => verity_style.css} (100%) diff --git a/src/front/home.py b/src/front/home.py index e8da2eb..817b3dd 100644 --- a/src/front/home.py +++ b/src/front/home.py @@ -1,15 +1,12 @@ from flask import Blueprint, render_template, flash, redirect, url_for, session import os -home_bp = Blueprint('home',__name__, template_folder='templates') +home_bp = Blueprint('home', + __name__, + template_folder='templates' +) @home_bp.route('/') def home_page(): cwd = os.getcwd() return render_template('home.html',cwd=cwd) - -@home_bp.route('/clear_session') -def clear_session(): - session.clear() - flash('All Clear!',category='success') - return redirect(url_for('home.home')) diff --git a/src/front/static/style.css b/src/front/static/verity_style.css similarity index 100% rename from src/front/static/style.css rename to src/front/static/verity_style.css diff --git a/src/front/templates/base.html b/src/front/templates/base.html index 918789f..dffef7b 100644 --- a/src/front/templates/base.html +++ b/src/front/templates/base.html @@ -13,7 +13,11 @@ crossorigin="anonymous" /> - + diff --git a/src/front/templates/home.html b/src/front/templates/home.html index 5ddacd4..470f524 100644 --- a/src/front/templates/home.html +++ b/src/front/templates/home.html @@ -2,4 +2,5 @@ %}

Home of Verity

Current Directory: {{ cwd }}

+ {% endblock %} diff --git a/src/verity.py b/src/verity.py index 4234943..6ddc097 100644 --- a/src/verity.py +++ b/src/verity.py @@ -29,9 +29,8 @@ def set_up_logging(config): verity.build_database() # app initialise - app = Flask(__name__) + app = Flask('Verity', static_folder='./front/static/') app.config['SECRET_KEY'] = verity_config.SECRET_KEY app.config['DEBUG'] = True - app.config['STATIC_FOLDER'] = 'front/static' app.register_blueprint(home_bp) app.run() From 0060cce975fd1826803f409c95a7024935ec902b Mon Sep 17 00:00:00 2001 From: Jake Pullen Date: Sun, 11 May 2025 18:32:41 +0100 Subject: [PATCH 02/13] =?UTF-8?q?feat:=20=E2=9C=A8=20can=20add=20budget=20?= =?UTF-8?q?name=20to=20database?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config_files/logging_config.yaml | 2 +- src/data_handler.py | 37 +++++++++++++++++++++++++--- src/front/home.py | 32 +++++++++++++++++++++--- src/front/templates/home.html | 15 ++++++++++- src/verity.py | 2 +- 5 files changed, 77 insertions(+), 11 deletions(-) diff --git a/src/config_files/logging_config.yaml b/src/config_files/logging_config.yaml index 3d8b5b4..6af3902 100644 --- a/src/config_files/logging_config.yaml +++ b/src/config_files/logging_config.yaml @@ -11,7 +11,7 @@ formatters: handlers: stderr: class: logging.StreamHandler - level: INFO + level: DEBUG formatter: nodate stream: ext://sys.stdout file: diff --git a/src/data_handler.py b/src/data_handler.py index 825c8da..7869ea4 100644 --- a/src/data_handler.py +++ b/src/data_handler.py @@ -1,14 +1,17 @@ import sqlite3 import logging from config import VerityConfig +from datetime import datetime +from posix import error logger = logging.getLogger(__name__) class database(): 'basic Database class to start some development' - def __init__(self, config: VerityConfig ) -> None: - self.database = config.DATABASE - self.schema = config.DATABASE_SCHEMA + def __init__(self) -> None: + self.verity_config = VerityConfig() + self.database = self.verity_config.DATABASE + self.schema = self.verity_config.DATABASE_SCHEMA @staticmethod def _build_column(column:dict) -> str: @@ -96,4 +99,30 @@ def print_table_schema(self, table_name): try: connection.close() except Exception as e: - logger.error(e) \ No newline at end of file + logger.error(e) + + def add_budget_name(self,budget_name:str) -> int: + 'takes budget name string, returns budget id' + now = datetime.now() + formatted_datetime = now.strftime("%Y-%m-%d %H:%M:%S") + logger.debug(f'current datetime: {formatted_datetime}') + try: + connection = sqlite3.connect(self.database) + cursor = connection.cursor() + cursor.execute('''INSERT INTO budget ( + name, + created_date + ) + VALUES (?,?) + ''',(budget_name, formatted_datetime)) + budget_id = cursor.lastrowid + + except Exception as e: + logger.error(e) + finally: + try: + connection.close() + return budget_id + except Exception as e: + logger.error(e) + return 0 diff --git a/src/front/home.py b/src/front/home.py index 817b3dd..2eaccf5 100644 --- a/src/front/home.py +++ b/src/front/home.py @@ -1,5 +1,9 @@ -from flask import Blueprint, render_template, flash, redirect, url_for, session -import os +from flask import Blueprint, render_template, flash, redirect, url_for, session, request +import logging + +import data_handler + +logger = logging.getLogger(__name__) home_bp = Blueprint('home', __name__, @@ -8,5 +12,25 @@ @home_bp.route('/') def home_page(): - cwd = os.getcwd() - return render_template('home.html',cwd=cwd) + logger.info('home page hit') + return render_template('home.html') + +@home_bp.route('/submit', methods=['POST']) +def submit_budget_name(): + budget_name = request.form.get('budgetName') + logger.debug(request.form) + if budget_name: + logger.info(f'User submitted new budget name: {budget_name}') + session['budget_name'] = budget_name + db_call = data_handler.database() + budget_id = db_call.add_budget_name(budget_name) + if budget_id == 0: + # db entry failed, throw error message + flash('Budget Name not saved, please check the logs','error') + return redirect(url_for('home.home_page')) + session['budget_id'] = budget_id + flash('Budget name saved!', 'success') + return redirect(url_for('home.home_page')) + else: + flash('Please enter a budget name.', 'error') + return redirect(url_for('home.home_page')) diff --git a/src/front/templates/home.html b/src/front/templates/home.html index 470f524..2f6b66f 100644 --- a/src/front/templates/home.html +++ b/src/front/templates/home.html @@ -1,6 +1,19 @@ {% extends "base.html" %} {% block title %} Home {% endblock %} {% block content %}

Home of Verity

-

Current Directory: {{ cwd }}

+
+
+

New Budget Name:

+ + +
+
{% endblock %} diff --git a/src/verity.py b/src/verity.py index 6ddc097..2217f75 100644 --- a/src/verity.py +++ b/src/verity.py @@ -25,7 +25,7 @@ def set_up_logging(config): logger.info('app starting') # database initialise - verity = database(verity_config) + verity = database() verity.build_database() # app initialise From 23fcdbd0a21bf475cb452580282cacaedd053e15 Mon Sep 17 00:00:00 2001 From: Jake Pullen Date: Sun, 11 May 2025 19:40:14 +0100 Subject: [PATCH 03/13] =?UTF-8?q?feat:=20=E2=9C=A8=20working=20towards=20a?= =?UTF-8?q?dding=20budget?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/data_handler.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/data_handler.py b/src/data_handler.py index 7869ea4..a7ded7c 100644 --- a/src/data_handler.py +++ b/src/data_handler.py @@ -2,7 +2,6 @@ import logging from config import VerityConfig from datetime import datetime -from posix import error logger = logging.getLogger(__name__) @@ -105,24 +104,32 @@ def add_budget_name(self,budget_name:str) -> int: 'takes budget name string, returns budget id' now = datetime.now() formatted_datetime = now.strftime("%Y-%m-%d %H:%M:%S") - logger.debug(f'current datetime: {formatted_datetime}') + logger.debug(f'attempting to insert values into budget table {budget_name} | {formatted_datetime}') try: connection = sqlite3.connect(self.database) + logger.debug('connection to db open') cursor = connection.cursor() + logger.debug('cursor activated') cursor.execute('''INSERT INTO budget ( name, created_date ) VALUES (?,?) ''',(budget_name, formatted_datetime)) + logger.debug('cursor executed') budget_id = cursor.lastrowid + logger.debug(f'insert attempt seems successful, budget id is {budget_id}') + if budget_id is None: + budget_id = 0 except Exception as e: - logger.error(e) + logger.error(f'Failed to insert budget name, error: {e}') + budget_id = 0 finally: try: connection.close() + logger.debug('connection to db closed') return budget_id except Exception as e: - logger.error(e) + logger.error(f'failed to close connection message: {e}') return 0 From 745a126d8fd5d3f26f57bcc81085f85a5b9b80e2 Mon Sep 17 00:00:00 2001 From: Jake Pullen Date: Sat, 17 May 2025 09:37:41 +0100 Subject: [PATCH 04/13] =?UTF-8?q?fix:=20=F0=9F=90=9E=20Working=20insert=20?= =?UTF-8?q?into=20database?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/data_handler.py | 94 +++++++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/src/data_handler.py b/src/data_handler.py index a7ded7c..1996904 100644 --- a/src/data_handler.py +++ b/src/data_handler.py @@ -5,46 +5,50 @@ logger = logging.getLogger(__name__) -class database(): - 'basic Database class to start some development' + +class database: + "basic Database class to start some development" + def __init__(self) -> None: self.verity_config = VerityConfig() self.database = self.verity_config.DATABASE self.schema = self.verity_config.DATABASE_SCHEMA @staticmethod - def _build_column(column:dict) -> str: - name = column['column_name'] - is_pk = column['is_pk'] - datatype = column['datatype'] - nullable = column['nullable'] - column_string = f'{name} {datatype}' + def _build_column(column: dict) -> str: + name = column["column_name"] + is_pk = column["is_pk"] + datatype = column["datatype"] + nullable = column["nullable"] + column_string = f"{name} {datatype}" if is_pk: - column_string += ' PRIMARY KEY AUTOINCREMENT' + column_string += " PRIMARY KEY AUTOINCREMENT" if not nullable: - column_string += ' NOT NULL' + column_string += " NOT NULL" return column_string @staticmethod - def _build_foreign_key(key:dict) -> str: - column = key['column'] - reference_table = key['references'] - reference_column = key['reference_column'] - return f'FOREIGN KEY ({column}) REFERENCES {reference_table} ({reference_column})' - - def _add_table_to_db(self, table:dict) -> bool: - 'Creates the table in the verity database, based on the schema yaml' - sql = f'''CREATE TABLE IF NOT EXISTS {table['table_name']} ( - ''' + def _build_foreign_key(key: dict) -> str: + column = key["column"] + reference_table = key["references"] + reference_column = key["reference_column"] + return ( + f"FOREIGN KEY ({column}) REFERENCES {reference_table} ({reference_column})" + ) + + def _add_table_to_db(self, table: dict) -> bool: + "Creates the table in the verity database, based on the schema yaml" + sql = f"""CREATE TABLE IF NOT EXISTS {table["table_name"]} ( + """ columns = [] - for column in table['table_columns']: + for column in table["table_columns"]: columns.append(self._build_column(column)) - sql += ',\n'.join(columns) - if table.get('table_foreign_keys', None): - sql += ',\n' - for key in table['table_foreign_keys']: - sql += f'{self._build_foreign_key(key)}' - sql += '\n);' + sql += ",\n".join(columns) + if table.get("table_foreign_keys", None): + sql += ",\n" + for key in table["table_foreign_keys"]: + sql += f"{self._build_foreign_key(key)}" + sql += "\n);" success_status = False try: connection = sqlite3.connect(self.database) @@ -66,7 +70,7 @@ def _add_table_to_db(self, table:dict) -> bool: return success_status def build_database(self): - for table in self.schema['tables']: + for table in self.schema["tables"]: logger.info(f"Checking {table['table_name']}") # Add true/false handling here to gracefully handle errors self._add_table_to_db(table) @@ -89,7 +93,9 @@ def print_table_schema(self, table_name): # Print the schema logger.debug(f"Schema for table: {table_name}") for row in cursor.fetchall(): - logger.debug(f" Column Name: {row[1]}, Data Type: {row[2]}, Not Null: {row[3]}") + logger.debug( + f" Column Name: {row[1]}, Data Type: {row[2]}, Not Null: {row[3]}" + ) except Exception as e: logger.error(f"An error occurred: {e}") @@ -100,36 +106,42 @@ def print_table_schema(self, table_name): except Exception as e: logger.error(e) - def add_budget_name(self,budget_name:str) -> int: - 'takes budget name string, returns budget id' + def add_budget_name(self, budget_name: str) -> int: + "takes budget name string, returns budget id" now = datetime.now() formatted_datetime = now.strftime("%Y-%m-%d %H:%M:%S") - logger.debug(f'attempting to insert values into budget table {budget_name} | {formatted_datetime}') + logger.debug( + f"attempting to insert values into budget table {budget_name} | {formatted_datetime}" + ) try: connection = sqlite3.connect(self.database) - logger.debug('connection to db open') + logger.debug("connection to db open") cursor = connection.cursor() - logger.debug('cursor activated') - cursor.execute('''INSERT INTO budget ( + logger.debug("cursor activated") + cursor.execute( + """INSERT INTO budget ( name, created_date ) VALUES (?,?) - ''',(budget_name, formatted_datetime)) - logger.debug('cursor executed') + """, + (budget_name, formatted_datetime), + ) + logger.debug("cursor executed") + connection.commit() budget_id = cursor.lastrowid - logger.debug(f'insert attempt seems successful, budget id is {budget_id}') + logger.debug(f"insert attempt seems successful, budget id is {budget_id}") if budget_id is None: budget_id = 0 except Exception as e: - logger.error(f'Failed to insert budget name, error: {e}') + logger.error(f"Failed to insert budget name, error: {e}") budget_id = 0 finally: try: connection.close() - logger.debug('connection to db closed') + logger.debug("connection to db closed") return budget_id except Exception as e: - logger.error(f'failed to close connection message: {e}') + logger.error(f"failed to close connection message: {e}") return 0 From 3f2c309b6635a4f50ba258ffb584ddb666de9400 Mon Sep 17 00:00:00 2001 From: Jake Pullen Date: Sat, 17 May 2025 15:08:11 +0100 Subject: [PATCH 05/13] =?UTF-8?q?chore:=20=F0=9F=A7=B9=20Minor=20tweaks=20?= =?UTF-8?q?to=20satisfy=20linters?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 1 + src/config.py | 18 +++++++++--------- src/data_handler.py | 41 +++++++++++++++++++++++++++++++++-------- src/front/home.py | 38 +++++++++++++++++++------------------- src/verity.py | 14 ++++++++------ 5 files changed, 70 insertions(+), 42 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0d8897a..b2ff274 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,3 +16,4 @@ pythonpath = ["."] testspaths = ["tests"] python_files = "test_*.py" python_functions = "test_*" + diff --git a/src/config.py b/src/config.py index d39aacf..02db6f5 100644 --- a/src/config.py +++ b/src/config.py @@ -1,20 +1,20 @@ import os import yaml -class VerityConfig: +class VerityConfig: def __init__(self): - self.SECRET_KEY = os.environ.get('SECRET_KEY') or 'super_secure_secret_key' - self.DATABASE = 'Verity.db' - self.CONFIG_FILE_DIRECTORY = 'config_files' - self.LOGGING_CONFIG = self.load_config_file('logging_config.yaml') - self.DATABASE_SCHEMA = self.load_config_file('verity_schema.yaml') + self.SECRET_KEY = os.environ.get("SECRET_KEY") or "super_secret_key" + self.DATABASE = "Verity.db" + self.CONFIG_FILE_DIRECTORY = "config_files" + self.LOGGING_CONFIG = self.load_config_file("logging_config.yaml") + self.DATABASE_SCHEMA = self.load_config_file("verity_schema.yaml") def load_config_file(self, file): - config = '' - filepath = os.path.join(self.CONFIG_FILE_DIRECTORY,file) + config = "" + filepath = os.path.join(self.CONFIG_FILE_DIRECTORY, file) try: - with open(filepath, 'r') as f: + with open(filepath, "r") as f: try: config = yaml.safe_load(f) except yaml.YAMLError as e: diff --git a/src/data_handler.py b/src/data_handler.py index 1996904..9a8a25f 100644 --- a/src/data_handler.py +++ b/src/data_handler.py @@ -14,6 +14,30 @@ def __init__(self) -> None: self.database = self.verity_config.DATABASE self.schema = self.verity_config.DATABASE_SCHEMA + def execute_sql(self, sql_statement: str, return_id: bool = False) -> (bool, int): + "send the query here, returns true if successful, false if fail" + logging.debug(f"received request to execute {sql_statement}") + new_id: int = 0 + is_success: bool = False + try: + connection = sqlite3.connect( + database=self.database, + timeout=10, # seconds i hope + ) + logging.debug("opened connection to database") + cursor = connection.cursor() + cursor.execute(sql=sql_statement) + connection.commit() + if return_id: + new_id = cursor.lastrowid + is_success = True + except Exception as e: # TODO: better Exception handling + logging.error(e) + is_success = False + finally: + connection.close() + return (is_success, new_id) + @staticmethod def _build_column(column: dict) -> str: name = column["column_name"] @@ -30,11 +54,9 @@ def _build_column(column: dict) -> str: @staticmethod def _build_foreign_key(key: dict) -> str: column = key["column"] - reference_table = key["references"] - reference_column = key["reference_column"] - return ( - f"FOREIGN KEY ({column}) REFERENCES {reference_table} ({reference_column})" - ) + ref_table = key["references"] + ref_column = key["reference_column"] + return f"FOREIGN KEY ({column}) REFERENCES {ref_table} ({ref_column})" def _add_table_to_db(self, table: dict) -> bool: "Creates the table in the verity database, based on the schema yaml" @@ -77,7 +99,8 @@ def build_database(self): def print_table_schema(self, table_name): """ - Connects to the sqlite3 database, retrieves the schema of a specified table, + Connects to the sqlite3 database, + retrieves the schema of a specified table, and prints it to the console. Args: @@ -94,7 +117,7 @@ def print_table_schema(self, table_name): logger.debug(f"Schema for table: {table_name}") for row in cursor.fetchall(): logger.debug( - f" Column Name: {row[1]}, Data Type: {row[2]}, Not Null: {row[3]}" + f"Column Name: {row[1]}, Data Type: {row[2]}, Not Null: {row[3]}" ) except Exception as e: @@ -111,7 +134,9 @@ def add_budget_name(self, budget_name: str) -> int: now = datetime.now() formatted_datetime = now.strftime("%Y-%m-%d %H:%M:%S") logger.debug( - f"attempting to insert values into budget table {budget_name} | {formatted_datetime}" + f"attempting to insert values into budget table {budget_name} | { + formatted_datetime + }" ) try: connection = sqlite3.connect(self.database) diff --git a/src/front/home.py b/src/front/home.py index 2eaccf5..6b1750f 100644 --- a/src/front/home.py +++ b/src/front/home.py @@ -1,36 +1,36 @@ -from flask import Blueprint, render_template, flash, redirect, url_for, session, request +from flask import Blueprint, render_template +from flask import flash, redirect, url_for, session, request import logging import data_handler logger = logging.getLogger(__name__) -home_bp = Blueprint('home', - __name__, - template_folder='templates' -) +home_bp = Blueprint("home", __name__, template_folder="templates") -@home_bp.route('/') + +@home_bp.route("/") def home_page(): - logger.info('home page hit') - return render_template('home.html') + logger.info("home page hit") + return render_template("home.html") + -@home_bp.route('/submit', methods=['POST']) +@home_bp.route("/submit", methods=["POST"]) def submit_budget_name(): - budget_name = request.form.get('budgetName') + budget_name = request.form.get("budgetName") logger.debug(request.form) if budget_name: - logger.info(f'User submitted new budget name: {budget_name}') - session['budget_name'] = budget_name + logger.info(f"User submitted new budget name: {budget_name}") + session["budget_name"] = budget_name db_call = data_handler.database() budget_id = db_call.add_budget_name(budget_name) if budget_id == 0: # db entry failed, throw error message - flash('Budget Name not saved, please check the logs','error') - return redirect(url_for('home.home_page')) - session['budget_id'] = budget_id - flash('Budget name saved!', 'success') - return redirect(url_for('home.home_page')) + flash("Budget Name not saved, please check the logs", "error") + return redirect(url_for("home.home_page")) + session["budget_id"] = budget_id + flash("Budget name saved!", "success") + return redirect(url_for("home.home_page")) else: - flash('Please enter a budget name.', 'error') - return redirect(url_for('home.home_page')) + flash("Please enter a budget name.", "error") + return redirect(url_for("home.home_page")) diff --git a/src/verity.py b/src/verity.py index 2217f75..f58b41d 100644 --- a/src/verity.py +++ b/src/verity.py @@ -9,28 +9,30 @@ from data_handler import database from front.home import home_bp + def set_up_logging(config): - os.makedirs('../logs', exist_ok=True) + os.makedirs("../logs", exist_ok=True) logging.config.dictConfig(config.LOGGING_CONFIG) - queue_handler = logging.getHandlerByName('queue_handler') + queue_handler = logging.getHandlerByName("queue_handler") if queue_handler is not None: queue_handler.listener.start() atexit.register(queue_handler.listener.stop) + if __name__ == "__main__": # config and logging verity_config = VerityConfig() logger = logging.getLogger(__name__) set_up_logging(verity_config) - logger.info('app starting') + logger.info("app starting") # database initialise verity = database() verity.build_database() # app initialise - app = Flask('Verity', static_folder='./front/static/') - app.config['SECRET_KEY'] = verity_config.SECRET_KEY - app.config['DEBUG'] = True + app = Flask("Verity", static_folder="./front/static/") + app.config["SECRET_KEY"] = verity_config.SECRET_KEY + app.config["DEBUG"] = True app.register_blueprint(home_bp) app.run() From d4905034fba87741e9de1b8ef373b130a4f96549 Mon Sep 17 00:00:00 2001 From: Jake Pullen Date: Thu, 22 May 2025 18:34:41 +0100 Subject: [PATCH 06/13] =?UTF-8?q?ci:=20=F0=9F=93=A6=20Updated=20workflow?= =?UTF-8?q?=20to=20trigger=20on=20PR?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/stage_unit_tests.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stage_unit_tests.yml b/.github/workflows/stage_unit_tests.yml index d8d4846..e487139 100644 --- a/.github/workflows/stage_unit_tests.yml +++ b/.github/workflows/stage_unit_tests.yml @@ -1,9 +1,11 @@ name: Unit Tests - Stage Branch on: - push: + pull_request: + types: [opened , reopened] branches: - - stage + - 'stage' + workflow_dispatch: # Allows manual triggering from the UI jobs: From 46dcce3a5339f0358b44d851762f73f3d30b96ac Mon Sep 17 00:00:00 2001 From: Jake Pullen Date: Thu, 22 May 2025 18:46:34 +0100 Subject: [PATCH 07/13] =?UTF-8?q?fix:=20=F0=9F=90=9B=20broke=20my=20own=20?= =?UTF-8?q?tests=20X.X?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tests/test_config.py | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/tests/test_config.py b/src/tests/test_config.py index a9d74c5..307da81 100644 --- a/src/tests/test_config.py +++ b/src/tests/test_config.py @@ -2,46 +2,54 @@ import os import yaml + def test_verity_config_default_secret_key(monkeypatch): - """Test that the default secret key is used if the environment variable is not set.""" + """Test that the default secret key is used + if the environment variable is not set.""" testing_config = config.VerityConfig() - assert testing_config.SECRET_KEY == 'super_secure_secret_key' + assert testing_config.SECRET_KEY == "super_secret_key" + def test_verity_config_secret_key_from_env(monkeypatch): """Test that the secret key is loaded from the environment variable.""" - os.environ['SECRET_KEY'] = 'a_real_secret' + os.environ["SECRET_KEY"] = "a_real_secret" testing_config = config.VerityConfig() - assert testing_config.SECRET_KEY == 'a_real_secret' - del os.environ['SECRET_KEY'] # Clean up the environment + assert testing_config.SECRET_KEY == "a_real_secret" + del os.environ["SECRET_KEY"] # Clean up the environment + def test_verity_config_database_name(monkeypatch): """Test that the database name is correctly set.""" testing_config = config.VerityConfig() - assert testing_config.DATABASE == 'Verity.db' + assert testing_config.DATABASE == "Verity.db" + def test_verity_config_config_file_directory(monkeypatch): """Test that the config file directory is set.""" testing_config = config.VerityConfig() - assert testing_config.CONFIG_FILE_DIRECTORY == 'config_files' + assert testing_config.CONFIG_FILE_DIRECTORY == "config_files" + def test_verity_config_load_config_file(monkeypatch): """Test that load_config_file handles successful YAML loading.""" # Mock the YAML file content - mock_config = {'logging_level': 'INFO'} + mock_config = {"logging_level": "INFO"} # Create a temporary file import tempfile + temp_dir = tempfile.mkdtemp() - mock_filepath = os.path.join(temp_dir, 'logging_config.yaml') - with open(mock_filepath, 'w') as f: + mock_filepath = os.path.join(temp_dir, "logging_config.yaml") + with open(mock_filepath, "w") as f: yaml.safe_dump(mock_config, f) # Configure monkeypatch to simulate file loading testing_config = config.VerityConfig() - monkeypatch.setattr(testing_config, 'CONFIG_FILE_DIRECTORY', temp_dir) - loaded_config = testing_config.load_config_file('logging_config.yaml') + monkeypatch.setattr(testing_config, "CONFIG_FILE_DIRECTORY", temp_dir) + loaded_config = testing_config.load_config_file("logging_config.yaml") assert loaded_config == mock_config # Clean up the temporary file import shutil + shutil.rmtree(temp_dir) From 565d829dc89fa7198b934f2398be904835d9064c Mon Sep 17 00:00:00 2001 From: Jake Pullen Date: Thu, 22 May 2025 18:49:58 +0100 Subject: [PATCH 08/13] =?UTF-8?q?ci:=20=F0=9F=A6=8A=20updated=20Workflow?= =?UTF-8?q?=20to=20also=20run=20on=20PR=20edit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/stage_unit_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stage_unit_tests.yml b/.github/workflows/stage_unit_tests.yml index e487139..91fab72 100644 --- a/.github/workflows/stage_unit_tests.yml +++ b/.github/workflows/stage_unit_tests.yml @@ -2,7 +2,7 @@ name: Unit Tests - Stage Branch on: pull_request: - types: [opened , reopened] + types: [opened , reopene, edited] branches: - 'stage' From d841f7b2f9936f0c38958a7b59e64935dbb8653d Mon Sep 17 00:00:00 2001 From: Jake Pullen Date: Thu, 22 May 2025 18:59:40 +0100 Subject: [PATCH 09/13] =?UTF-8?q?ci:=20=F0=9F=93=A6=20Changed=20Job=20Name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/stage_unit_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stage_unit_tests.yml b/.github/workflows/stage_unit_tests.yml index 91fab72..e5f8769 100644 --- a/.github/workflows/stage_unit_tests.yml +++ b/.github/workflows/stage_unit_tests.yml @@ -9,7 +9,7 @@ on: workflow_dispatch: # Allows manual triggering from the UI jobs: - pydantic_tests: + Stage_Pull_Request_Unit_Tests: runs-on: ubuntu-latest steps: - name: Checkout code From 92b3888bfa9e34197118fec0b459126e75f3e1ff Mon Sep 17 00:00:00 2001 From: Jake Pullen Date: Thu, 22 May 2025 21:42:30 +0100 Subject: [PATCH 10/13] feat: Can now see budgets added to the database --- src/data_handler.py | 34 +++++++++++++++++++++++++++++++--- src/front/home.py | 4 +++- src/front/templates/home.html | 8 +++++++- src/tests/test_data_handler.py | 10 ++++++++++ 4 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 src/tests/test_data_handler.py diff --git a/src/data_handler.py b/src/data_handler.py index 9a8a25f..d0cff7e 100644 --- a/src/data_handler.py +++ b/src/data_handler.py @@ -7,12 +7,15 @@ class database: - "basic Database class to start some development" + """basic Database class to start some development + Will need a proper refactor once basic functions are in and working + This is POC + """ def __init__(self) -> None: self.verity_config = VerityConfig() - self.database = self.verity_config.DATABASE self.schema = self.verity_config.DATABASE_SCHEMA + self.database = self.verity_config.DATABASE def execute_sql(self, sql_statement: str, return_id: bool = False) -> (bool, int): "send the query here, returns true if successful, false if fail" @@ -36,7 +39,27 @@ def execute_sql(self, sql_statement: str, return_id: bool = False) -> (bool, int is_success = False finally: connection.close() - return (is_success, new_id) + if return_id: + return (is_success, new_id) + else: + return is_success + + def read_database(self, sql_statement: str): + "reads the database query and returns the results" + logging.debug(f"received request to read {sql_statement}") + results = 0 + try: + connection = sqlite3.connect(self.database) + logging.debug("opened connection to database") + cursor = connection.cursor() + results = cursor.execute(sql_statement, {}) + results = results.fetchall() + logging.debug(f"query returned: {results}") + except Exception as e: + logging.error(f"Read error occured: {e}") + finally: + connection.close() + return results @staticmethod def _build_column(column: dict) -> str: @@ -170,3 +193,8 @@ def add_budget_name(self, budget_name: str) -> int: except Exception as e: logger.error(f"failed to close connection message: {e}") return 0 + + def get_budgets(self) -> list: + get_budget_sql = "SELECT name FROM budget" + budgets = self.read_database(get_budget_sql) + return budgets diff --git a/src/front/home.py b/src/front/home.py index 6b1750f..62768e1 100644 --- a/src/front/home.py +++ b/src/front/home.py @@ -12,7 +12,9 @@ @home_bp.route("/") def home_page(): logger.info("home page hit") - return render_template("home.html") + db_call = data_handler.database() + budgets = db_call.get_budgets() + return render_template("home.html", budgets=budgets) @home_bp.route("/submit", methods=["POST"]) diff --git a/src/front/templates/home.html b/src/front/templates/home.html index 2f6b66f..633fc07 100644 --- a/src/front/templates/home.html +++ b/src/front/templates/home.html @@ -15,5 +15,11 @@

Home of Verity

- +
+

+ {% for budget in budgets %} +- {{ budget[0] }}
+ {% endfor %} +

+
{% endblock %} diff --git a/src/tests/test_data_handler.py b/src/tests/test_data_handler.py new file mode 100644 index 0000000..09ac218 --- /dev/null +++ b/src/tests/test_data_handler.py @@ -0,0 +1,10 @@ +import os +import sqlite3 +import pytest + +from src import data_handler + + +@pytest.fixture +def test_build_database(): + pass From f973ec2bd82132f583599d36e28d138126784159 Mon Sep 17 00:00:00 2001 From: Jake Pullen Date: Fri, 23 May 2025 09:30:56 +0100 Subject: [PATCH 11/13] =?UTF-8?q?feat:=20=E2=9C=A8=20Added=20unit=20tests?= =?UTF-8?q?=20for=20Database=20Handler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/data_handler.py | 7 ++--- src/front/home.py | 8 +++-- src/tests/test_data_handler.py | 56 ++++++++++++++++++++++++++++++++-- src/verity.py | 2 +- 4 files changed, 63 insertions(+), 10 deletions(-) diff --git a/src/data_handler.py b/src/data_handler.py index d0cff7e..16eb705 100644 --- a/src/data_handler.py +++ b/src/data_handler.py @@ -1,6 +1,5 @@ import sqlite3 import logging -from config import VerityConfig from datetime import datetime logger = logging.getLogger(__name__) @@ -12,8 +11,8 @@ class database: This is POC """ - def __init__(self) -> None: - self.verity_config = VerityConfig() + def __init__(self, config) -> None: + self.verity_config = config self.schema = self.verity_config.DATABASE_SCHEMA self.database = self.verity_config.DATABASE @@ -29,7 +28,7 @@ def execute_sql(self, sql_statement: str, return_id: bool = False) -> (bool, int ) logging.debug("opened connection to database") cursor = connection.cursor() - cursor.execute(sql=sql_statement) + cursor.execute(sql_statement, {}) connection.commit() if return_id: new_id = cursor.lastrowid diff --git a/src/front/home.py b/src/front/home.py index 62768e1..5f0a360 100644 --- a/src/front/home.py +++ b/src/front/home.py @@ -3,16 +3,18 @@ import logging import data_handler +from config import VerityConfig logger = logging.getLogger(__name__) home_bp = Blueprint("home", __name__, template_folder="templates") +verity_config = VerityConfig() @home_bp.route("/") def home_page(): logger.info("home page hit") - db_call = data_handler.database() + db_call = data_handler.database(verity_config) budgets = db_call.get_budgets() return render_template("home.html", budgets=budgets) @@ -20,11 +22,11 @@ def home_page(): @home_bp.route("/submit", methods=["POST"]) def submit_budget_name(): budget_name = request.form.get("budgetName") - logger.debug(request.form) + logger.debug(f"Request Received: {request.form}") if budget_name: logger.info(f"User submitted new budget name: {budget_name}") session["budget_name"] = budget_name - db_call = data_handler.database() + db_call = data_handler.database(verity_config) budget_id = db_call.add_budget_name(budget_name) if budget_id == 0: # db entry failed, throw error message diff --git a/src/tests/test_data_handler.py b/src/tests/test_data_handler.py index 09ac218..87cd2da 100644 --- a/src/tests/test_data_handler.py +++ b/src/tests/test_data_handler.py @@ -3,8 +3,60 @@ import pytest from src import data_handler +from src.config import VerityConfig @pytest.fixture -def test_build_database(): - pass +def test_db_call(): + config = VerityConfig() + db_call = data_handler.database(config) + db_call.build_database() + yield db_call + + +def test_execute_sql_success(test_db_call): + sql_statement = """INSERT INTO budget ( + name, + created_date + ) + VALUES ('a_budget_name','2025-05-23 09:04:00') + """ + result = test_db_call.execute_sql(sql_statement) + assert result + + +def test_execute_sql_error(test_db_call): + sql_statement = "SELECT * FROM non_existent_table" + result = test_db_call.execute_sql(sql_statement) + assert not result + # Check if an error message is logged + # You might need to add a logging assertion here + + +def test_read_database(test_db_call): + # Test reading database data + sql_statement = "SELECT name FROM budget" + results = test_db_call.read_database(sql_statement) + assert isinstance(results, list) + # Check the contents of the list + # self.assertIsNotNone(results) + # self.assertIsInstance(results[0], str) + + +def test_add_budget_name(test_db_call): + # Test adding a new budget name + budget_name = "Test Budget" + budget_id = test_db_call.add_budget_name(budget_name) + assert budget_id is not None + # Check if the budget name was actually added + # You might need to query the database to verify + # self.assertEqual(budget_id, 1) + + +def test_get_budgets(test_db_call): + # Test getting budgets + budgets = test_db_call.get_budgets() + assert isinstance(budgets, list) + # Check the contents of the list + # self.assertIsNotNone(budgets) + # self.assertIsInstance(budgets[0], str) diff --git a/src/verity.py b/src/verity.py index f58b41d..70baf24 100644 --- a/src/verity.py +++ b/src/verity.py @@ -27,7 +27,7 @@ def set_up_logging(config): logger.info("app starting") # database initialise - verity = database() + verity = database(verity_config) verity.build_database() # app initialise From bf951895ee718844289e11496606f3213ed280d8 Mon Sep 17 00:00:00 2001 From: Jake Pullen Date: Fri, 23 May 2025 09:43:37 +0100 Subject: [PATCH 12/13] =?UTF-8?q?deploy:=20=F0=9F=93=A6=20Added=20PR=20Tem?= =?UTF-8?q?plate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pull_request_template.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 pull_request_template.md diff --git a/pull_request_template.md b/pull_request_template.md new file mode 100644 index 0000000..a5b4256 --- /dev/null +++ b/pull_request_template.md @@ -0,0 +1,31 @@ +## Pull Request Type: + +**1. Title:** [Concise and Descriptive Title - Explain the Change] + + * Example: "Fix: Incorrect Calculation in User Profile" + * Example: "Feature: Add Support for Dark Mode" + * Keep titles short and informative. A good title should immediately convey the essence of the change. + +**2. Description:** + + * **Summary:** Briefly describe the purpose of this pull request in 1-2 sentences. + * **Motivation:** Explain *why* this change is needed. What problem does it solve? What opportunity does it address? Provide context. + * **Proposed Solution:** Describe your solution in detail. Explain *how* you implemented the change. Be specific. + * **Screenshots/GIFs (if applicable):** If your change involves UI changes, include screenshots or a GIF to demonstrate the impact. + * **Testing:** Describe the tests you've added or run to ensure the change is correct. (e.g., "Added unit tests for the new function," "Manually tested on Chrome, Firefox, and Safari"). + * **Known Limitations/Future Considerations:** Are there any known issues with this change? Are there any potential future improvements you envision? + +**3. Checklist:** + + [ ] I have followed the project's coding style and conventions. + [ ] I have written unit tests to cover my changes. + [ ] My code has been tested locally. + [ ] I have included screenshots/GIFs if applicable. + [ ] I have updated the documentation (if necessary). + [ ] I have labeled this PR appropriately (e.g., "bug," "feature," "refactor"). + + +**4. Reviewer Notes (Optional - Add if you have specific requests)** + + * "Please pay particular attention to the [specific section] of the code." + * "Would appreciate feedback on the design of this component." From d2f35a00915ccdfc9b5cda42cb92ae85358a2f4c Mon Sep 17 00:00:00 2001 From: Jake Pullen Date: Fri, 23 May 2025 09:47:41 +0100 Subject: [PATCH 13/13] =?UTF-8?q?chore:=20=F0=9F=A7=B9=20Ruff=20Fixed=20so?= =?UTF-8?q?me=20minor=20issues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tests/test_data_handler.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tests/test_data_handler.py b/src/tests/test_data_handler.py index 87cd2da..379c6ff 100644 --- a/src/tests/test_data_handler.py +++ b/src/tests/test_data_handler.py @@ -1,5 +1,3 @@ -import os -import sqlite3 import pytest from src import data_handler