diff --git a/backend/debug.py b/backend/debug.py index 35edc6d..5ce2260 100644 --- a/backend/debug.py +++ b/backend/debug.py @@ -29,11 +29,15 @@ "(group_id TEXT NOT NULL, user_id TEXT NOT NULL, " "role_id TEXT);" ) -CREATE_GROUP_ROLES_TABLE: str = ( - "CREATE TABLE IF NOT EXISTS group_roles" - "(group_id TEXT NOT NULL, uuid TEXT NOT NULL, " - "role_name TEXT NOT NULL, role_description TEXT, " - "role_permissions TEXT, admin INT NOT NULL);" +# CREATE_GROUP_ROLES_TABLE: str = ( +# "CREATE TABLE IF NOT EXISTS group_roles" +# "(group_id TEXT NOT NULL, uuid TEXT NOT NULL, " +# "role_name TEXT NOT NULL, role_description TEXT, " +# "role_permissions TEXT, admin INT NOT NULL);" +# ) +CREATE_PENDING_INVITE_TABLE: str = ( + "CREATE TABLE IF NOT EXISTS pending_invite " + "(group_id TEXT NOT NULL, user_id TEXT NOT NULL);" ) @@ -117,6 +121,21 @@ def delete_dummy_group(): conn.close() +def delete_tasks() -> None: + """This will delete everything in the task table. DANGER!""" + + try: + data_con: Connection = check_table() + data_cursor: Cursor = data_con.cursor() + except Error as e_msg: + raise e_msg + + data_cursor.execute("DELETE FROM task;") + data_con.commit() + data_con.close() + return + + def delete_everything() -> None: """This will delete everything in the task table. DANGER!""" @@ -144,13 +163,13 @@ def check_table() -> Connection: raise e_msg data_cursor: Cursor = data_con.cursor() - print(CREATE_TASK_TABLE) + # print(CREATE_TASK_TABLE) data_cursor.execute(CREATE_TASK_TABLE) - print(CREATE_USER_TABLE) + # print(CREATE_USER_TABLE) data_cursor.execute(CREATE_USER_TABLE) - print(CREATE_GROUP_TABLE) + # print(CREATE_GROUP_TABLE) data_cursor.execute(CREATE_GROUP_TABLE) - print(CREATE_GROUP_USER_TABLE) + # print(CREATE_GROUP_USER_TABLE) data_cursor.execute(CREATE_GROUP_USER_TABLE) if ( @@ -171,7 +190,10 @@ def check_table() -> Connection: if __name__ == "__main__": # prompt the user for action check_table() - action = input("Do you want to create or delete a dummy user? ([c]reate/[d]elete): ") + action = input( + "Do you want to create or delete a dummy user? Or do you want to delete the tasks? " + "([c]reate/[d]elete/[t]asks): " + ) if action[0] == "c": create_dummy_user() create_dummy_group() @@ -180,5 +202,8 @@ def check_table() -> Connection: delete_dummy_user() delete_dummy_group() print("Dummy user deleted.") + elif action[0] == "t": + delete_tasks() + print("All tasks deleted.") else: - print("Invalid action. Please enter 'create' or 'delete'.") + print("Invalid action. Please enter 'create', 'delete', or 'tasks'.") diff --git a/backend/error.py b/backend/error.py new file mode 100644 index 0000000..f689a82 --- /dev/null +++ b/backend/error.py @@ -0,0 +1,19 @@ +# coding: utf-8 +"""This will hold the information with errors.""" + + +class BackendError(Exception): + """ Custom exception class for backend errors.""" + + def __init__(self, message, error_code) -> None: + self.message = message + super().__init__(self.message) + self.error_code = error_code + return + + def __list__(self) -> list: + return [self.message, self.error_code] + + +if __name__ == "__main__": + print("This is a module for handling backend errors.") diff --git a/backend/error_code.txt b/backend/error_code.txt deleted file mode 100644 index effdd6a..0000000 --- a/backend/error_code.txt +++ /dev/null @@ -1,6 +0,0 @@ -List of error codes that corresponds to the error messages in the backend. - -0: "Success" -1: "Invalid request" -2: "Backend Error" -3: "Not enough information" \ No newline at end of file diff --git a/backend/main.py b/backend/main.py index f2d576d..0818f01 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,20 +1,24 @@ # coding: utf-8 """This file will create the server and accept the backend processes.""" -from os.path import join +# from os.path import join from datetime import datetime from flask import Flask, request, jsonify, Response + +# from werkzeug.utils import secure_filename + from task import ( add_task, add_user, login_user, + edit_user, + delete_user, edit_task, delete_task, get_user_task, - get_group + get_group, ) # edit_task, get_user_task, get_group_task, -from werkzeug.utils import secure_filename - +from error import BackendError from log import make_new_log app: Flask = Flask(__name__) @@ -36,44 +40,97 @@ def handle_root() -> Response: respose_json: Response = jsonify( [ { + "error_no": "0", "message": "This is a debug message, yes, the server is running.", - "success": True, } ] ) return respose_json +# ----- User Handlers ---- + + @app.route("/signup", methods=["POST"]) def handle_signup() -> Response: """Adds a new user to the database.""" response_json: Response if request.method != "POST": - response_json = jsonify([{"error_no": "1", "message": "Wrong request type"}]) + response_json = jsonify([{"error_no": "100", "message": "Wrong request type"}]) return response_json try: request_data: dict = request.get_json() username: str = request_data.get("username", "") email: str = request_data.get("email", "") password: str = request_data.get("password", "") + except AttributeError: + response_json = jsonify( + [ + { + "error_no": "101", + "message": "Invalid data format! Please check your request. (AttributeError)", + } + ] + ) + return response_json + except KeyError: + response_json = jsonify( + [ + { + "error_no": "102", + "message": "Invalid data format! Please check your request. (KeyError)", + } + ] + ) + return response_json + except TypeError: + response_json = jsonify( + [ + { + "error_no": "103", + "message": "Invalid data format! Please check your request. (TypeError)", + } + ] + ) + return response_json except Exception as e: response_json = jsonify( - [{"error_no": "2", "message": "Trouble with backend! Sorry!"}] + [{"error_no": "199", "message": "Failed to retrive data from request!"}] ) make_new_log("signup", e) return response_json if username == "" or email == "" or password == "": response_json = jsonify( - [{"error_no": "3", "message": "Given data is invalid!"}] + [ + { + "error_no": "110", + "message": "One or more of the required fields are empty!", + } + ] ) return response_json try: user_id: str = add_user(username=username, email=email, password=password) + except BackendError as e: + response_json = jsonify( + [ + { + "error_no": e.error_code, + "message": e.message, + } + ] + ) + return response_json except Exception as e: response_json = jsonify( - [{"error_no": "2", "message": "Trouble with backend! Sorry!"}] + [ + { + "error_no": "200", + "message": "Trouble with backend! Sorry, but please notify the devs!", + } + ] ) make_new_log("signup", e) return response_json @@ -89,30 +146,80 @@ def handle_login() -> Response: """Login a user.""" response_json: Response if request.method != "POST": - response_json = jsonify([{"error_no": "1", "message": "Wrong request type"}]) + response_json = jsonify([{"error_no": "100", "message": "Wrong request type"}]) return response_json try: request_data: dict = request.get_json() email: str = request_data.get("email", "") password: str = request_data.get("password", "") + except AttributeError: + response_json = jsonify( + [ + { + "error_no": "101", + "message": "Invalid data format! Please check your request. (AttributeError)", + } + ] + ) + return response_json + except KeyError: + response_json = jsonify( + [ + { + "error_no": "102", + "message": "Invalid data format! Please check your request. (KeyError)", + } + ] + ) + return response_json + except TypeError: + response_json = jsonify( + [ + { + "error_no": "103", + "message": "Invalid data format! Please check your request. (TypeError)", + } + ] + ) + return response_json except Exception as e: response_json = jsonify( - [{"error_no": "2", "message": "Trouble with backend! Sorry!"}] + [{"error_no": "199", "message": "Failed to retrive data from request!"}] ) make_new_log("login", e) return response_json if email == "" or password == "": response_json = jsonify( - [{"error_no": "3", "message": "Given data is invalid!"}] + [ + { + "error_no": "110", + "message": "One or more of the required fields are empty!", + } + ] ) return response_json try: user_id: str = login_user(email=email, password=password) + except BackendError as e: + response_json = jsonify( + [ + { + "error_no": e.error_code, + "message": e.message, + } + ] + ) + return response_json except Exception as e: response_json = jsonify( - [{"error_no": "2", "message": "Trouble with backend! Sorry!"}] + [ + { + "error_no": "200", + "message": "Trouble with backend! Sorry, but please notify the devs!", + } + ] ) make_new_log("login", e) return response_json @@ -123,12 +230,196 @@ def handle_login() -> Response: return response_json +@app.route("/edit_user", methods=["POST"]) +def handle_edit_user() -> Response: + """Edit a user.""" + response_json: Response + if request.method != "POST": + response_json = jsonify([{"error_no": "100", "message": "Wrong request type"}]) + return response_json + try: + request_data: dict = request.get_json() + user_id: str = request_data.get("user_id", "") + username: str = request_data.get("username", "") + email: str = request_data.get("email", "") + password: str = request_data.get("password", "") + new_password: str = request_data.get("new_password", "") + except AttributeError: + response_json = jsonify( + [ + { + "error_no": "101", + "message": "Invalid data format! Please check your request. (AttributeError)", + } + ] + ) + return response_json + except KeyError: + response_json = jsonify( + [ + { + "error_no": "102", + "message": "Invalid data format! Please check your request. (KeyError)", + } + ] + ) + return response_json + except TypeError: + response_json = jsonify( + [ + { + "error_no": "103", + "message": "Invalid data format! Please check your request. (TypeError)", + } + ] + ) + return response_json + except Exception as e: + response_json = jsonify( + [{"error_no": "199", "message": "Failed to retrive data from request!"}] + ) + make_new_log("edit_user", e) + return response_json + + if username == "" or email == "" or password == "" or user_id == "": + response_json = jsonify( + [ + { + "error_no": "110", + "message": "One or more of the required fields are empty!", + } + ] + ) + return response_json + + try: + edit_user( + user_id=user_id, + username=username, + email=email, + password=password, + new_password=new_password, + ) + except BackendError as e: + response_json = jsonify( + [ + { + "error_no": e.error_code, + "message": e.message, + } + ] + ) + return response_json + except Exception as e: + response_json = jsonify( + [ + { + "error_no": "200", + "message": "Trouble with backend! Sorry, but please notify the devs!", + } + ] + ) + make_new_log("edit_user", e) + return response_json + + response_json = jsonify([{"error_no": "0", "message": "success"}]) + return response_json + + +@app.route("/delete_user", methods=["POST"]) +def handle_delete_user() -> Response: + """Delete a user.""" + response_json: Response + if request.method != "POST": + response_json = jsonify([{"error_no": "100", "message": "Wrong request type"}]) + return response_json + try: + request_data: dict = request.get_json() + user_id: str = request_data.get("user_id", "") + password: str = request_data.get("password", "") + except AttributeError: + response_json = jsonify( + [ + { + "error_no": "101", + "message": "Invalid data format! Please check your request. (AttributeError)", + } + ] + ) + return response_json + except KeyError: + response_json = jsonify( + [ + { + "error_no": "102", + "message": "Invalid data format! Please check your request. (KeyError)", + } + ] + ) + return response_json + except TypeError: + response_json = jsonify( + [ + { + "error_no": "103", + "message": "Invalid data format! Please check your request. (TypeError)", + } + ] + ) + return response_json + except Exception as e: + response_json = jsonify( + [{"error_no": "199", "message": "Failed to retrive data from request!"}] + ) + make_new_log("delete_user", e) + return response_json + + if user_id == "" or password == "": + response_json = jsonify( + [ + { + "error_no": "110", + "message": "One or more of the required fields are empty!", + } + ] + ) + return response_json + + try: + delete_user( + user_id=user_id, + password=password, + ) + except BackendError as e: + response_json = jsonify( + [ + { + "error_no": e.error_code, + "message": e.message, + } + ] + ) + return response_json + except Exception as e: + response_json = jsonify( + [{"error_no": "200", "message": "Trouble with backend! Sorry!"}] + ) + make_new_log("delete_user", e) + return response_json + + response_json = jsonify([{"error_no": "0", "message": "success"}]) + return response_json + + +# ----- Task Handlers ---- + + @app.route("/add_task", methods=["POST"]) def handle_add_task() -> Response: """Adds a new task to the database.""" response_json: Response if request.method != "POST": - response_json = jsonify([{"error_no": "1", "message": "Wrong request type"}]) + response_json = jsonify([{"error_no": "100", "message": "Wrong request type"}]) return response_json try: request_data: dict = request.get_json() @@ -157,16 +448,51 @@ def handle_add_task() -> Response: # if image_file and image_file.filename != "": # file_name: str = secure_filename(image_file.filename) # image_file.save(join(app.config["UPLOAD_FOLDER"], file_name)) + except AttributeError: + response_json = jsonify( + [ + { + "error_no": "101", + "message": "Invalid data format! Please check your request. (AttributeError)", + } + ] + ) + return response_json + except KeyError: + response_json = jsonify( + [ + { + "error_no": "102", + "message": "Invalid data format! Please check your request. (KeyError)", + } + ] + ) + return response_json + except TypeError: + response_json = jsonify( + [ + { + "error_no": "103", + "message": "Invalid data format! Please check your request. (TypeError)", + } + ] + ) + return response_json except Exception as e: response_json = jsonify( - [{"error_no": "2", "message": "Trouble with backend! Sorry!"}] + [{"error_no": "199", "message": "Failed to retrive data from request!"}] ) make_new_log("add_task", e) return response_json if task_name == "" or assigner_id == "" or assign_id == "" or group_id == "": response_json = jsonify( - [{"error_no": "3", "message": "Given data is invalid!"}] + [ + { + "error_no": "110", + "message": "One or more of the required fields are empty!", + } + ] ) return response_json @@ -186,9 +512,19 @@ def handle_add_task() -> Response: image_path=file_name, password=password, ) + except BackendError as e: + response_json = jsonify( + [ + { + "error_no": e.error_code, + "message": e.message, + } + ] + ) + return response_json except Exception as e: response_json = jsonify( - [{"error_no": "2", "message": "Trouble with backend! Sorry!"}] + [{"error_no": "200", "message": "Trouble with backend! Sorry!"}] ) make_new_log("add_task", e) return response_json @@ -202,7 +538,7 @@ def handle_edit_task() -> Response: """Edits a task.""" response_json: Response if request.method != "POST": - response_json = jsonify([{"error_no": "1", "message": "Wrong request type"}]) + response_json = jsonify([{"error_no": "100", "message": "Wrong request type"}]) return response_json try: request_data: dict = request.get_json() @@ -220,21 +556,59 @@ def handle_edit_task() -> Response: assigner_id: str = request_data.get("assigner_id", "") assign_id: str = request_data.get("assign_id", "") group_id: str = request_data.get("group_id", "") + recursive: int = int(request_data.get("recursive", "0")) + priority: int = int(request_data.get("priority", "0")) + completed: int = int(request_data.get("completed", "0")) password: str = request_data.get("password", "") task_due: float = datetime( task_due_year, task_due_month, task_due_date, task_due_hour, task_due_min, 0 ).timestamp() + except AttributeError: + response_json = jsonify( + [ + { + "message": "Invalid data format! Please check your request. (AttributeError)", + "error_no": "101", + } + ] + ) + return response_json + except KeyError: + response_json = jsonify( + [ + { + "message": "Invalid data format! Please check your request. (KeyError)", + "error_no": "102", + } + ] + ) + return response_json + except TypeError: + response_json = jsonify( + [ + { + "message": "Invalid data format! Please check your request. (TypeError)", + "error_no": "103", + } + ] + ) + return response_json except Exception as e: response_json = jsonify( - [{"message": f"There was an error! {e}", "error_no": "2"}] + [{"error_no": "199", "message": "Failed to retrive data from request!"}] ) print(e) return response_json - if task_name == "" or assigner_id == "" or assign_id == "": + if task_name == "" or assigner_id == "" or assign_id == "" or password == "": response_json = jsonify( - [{"message": "Given data is invalid!", "error_no": "3"}] + [ + { + "message": "One or more of the required fields are empty!", + "error_no": "110", + } + ] ) return response_json @@ -250,11 +624,18 @@ def handle_edit_task() -> Response: assigner_id=assigner_id, assign_id=assign_id, group_id=group_id, + recursive=recursive, + priority=priority, + completed=completed, + image_path="TODO CHANGE HERE", password=password, ) + except BackendError as e: + response_json = jsonify([{"message": e.message, "error_no": e.error_code}]) + return response_json except Exception as e: response_json = jsonify( - [{"message": f"Trouble with backend! Sorry! {e}", "error_no": "2"}] + [{"error_no": "200", "message": "Trouble with backend! Sorry!"}] ) print(e) return response_json @@ -269,23 +650,58 @@ def handle_delete_task() -> Response: """Delete a task.""" response_json: Response if request.method != "POST": - response_json = jsonify([{"error_no": "1", "message": "Wrong request type"}]) + response_json = jsonify([{"error_no": "100", "message": "Wrong request type"}]) return response_json try: request_data: dict = request.get_json() task_id: str = request_data.get("task_id", "") user_id: str = request_data.get("user_id", "") password: str = request_data.get("password", "") + except AttributeError: + response_json = jsonify( + [ + { + "error_no": "101", + "message": "Invalid data format! Please check your request. (AttributeError)", + } + ] + ) + return response_json + except KeyError: + response_json = jsonify( + [ + { + "error_no": "102", + "message": "Invalid data format! Please check your request. (KeyError)", + } + ] + ) + return response_json + except TypeError: + response_json = jsonify( + [ + { + "error_no": "103", + "message": "Invalid data format! Please check your request. (TypeError)", + } + ] + ) + return response_json except Exception as e: response_json = jsonify( - [{"error_no": "2", "message": "Trouble with backend! Sorry!"}] + [{"error_no": "199", "message": "Failed to retrive data from request!"}] ) make_new_log("delete_task", e) return response_json - if task_id == "": + if task_id == "" or user_id == "" or password == "": response_json = jsonify( - [{"error_no": "3", "message": "Given data is invalid!"}] + [ + { + "error_no": "110", + "message": "One or more of the required fields are empty!", + } + ] ) return response_json @@ -295,9 +711,19 @@ def handle_delete_task() -> Response: task_id=task_id, password=password, ) + except BackendError as e: + response_json = jsonify( + [ + { + "error_no": e.error_code, + "message": e.message, + } + ] + ) + return response_json except Exception as e: response_json = jsonify( - [{"error_no": "2", "message": "Trouble with backend! Sorry!"}] + [{"error_no": "200", "message": "Trouble with backend! Sorry!"}] ) make_new_log("delete_task", e) return response_json @@ -311,33 +737,75 @@ def handle_get_user_task() -> Response: """Get all tasks for a user.""" response_json: Response if request.method != "POST": - response_json = jsonify([{"error_no": "1", "message": "Wrong request type"}]) + response_json = jsonify([{"error_no": "100", "message": "Wrong request type"}]) return response_json try: request_data: dict = request.get_json() user_id: str = request_data.get("user_id", "") password: str = request_data.get("password", "") + except AttributeError: + response_json = jsonify( + [ + { + "error_no": "101", + "message": "Invalid data format! Please check your request. (AttributeError)", + } + ] + ) + return response_json + except KeyError: + response_json = jsonify( + [ + { + "error_no": "102", + "message": "Invalid data format! Please check your request. (KeyError)", + } + ] + ) + return response_json + except TypeError: + response_json = jsonify( + [ + { + "error_no": "103", + "message": "Invalid data format! Please check your request. (TypeError)", + } + ] + ) + return response_json except Exception as e: response_json = jsonify( - [{"error_no": "2", "message": "Trouble with backend! Sorry!"}] + [{"error_no": "199", "message": "Failed to retrive data from request!"}] ) make_new_log("get_user_task", e) return response_json - if user_id == "": + if user_id == "" or password == "": response_json = jsonify( - [{"error_no": "3", "message": "Given data is invalid!"}] + [ + { + "error_no": "110", + "message": "One or more of the required fields are empty!", + } + ] ) return response_json try: - tasks: dict[str, dict] = get_user_task( - user_id=user_id, - password=password + tasks: dict[str, dict] = get_user_task(user_id=user_id, password=password) + except BackendError as e: + response_json = jsonify( + [ + { + "error_no": e.error_code, + "message": e.message, + } + ] ) + return response_json except Exception as e: response_json = jsonify( - [{"error_no": "2", "message": "Trouble with backend! Sorry!"}] + [{"error_no": "200", "message": "Trouble with backend! Sorry!"}] ) make_new_log("get_user_task", e) return response_json @@ -346,27 +814,65 @@ def handle_get_user_task() -> Response: return response_json +# ----- Group Handlers ---- + + @app.route("/get_group_list", methods=["POST"]) def handle_get_group_list() -> Response: """Get all groups for a user.""" response_json: Response if request.method != "POST": - response_json = jsonify([{"error_no": "1", "message": "Wrong request type"}]) + response_json = jsonify([{"error_no": "100", "message": "Wrong request type"}]) return response_json try: request_data: dict = request.get_json() user_id: str = request_data.get("user_id", "") password: str = request_data.get("password", "") + except AttributeError: + response_json = jsonify( + [ + { + "error_no": "101", + "message": "Invalid data format! Please check your request. (AttributeError)", + } + ] + ) + return response_json + except KeyError: + response_json = jsonify( + [ + { + "error_no": "102", + "message": "Invalid data format! Please check your request. (KeyError)", + } + ] + ) + return response_json + except TypeError: + response_json = jsonify( + [ + { + "error_no": "103", + "message": "Invalid data format! Please check your request. (TypeError)", + } + ] + ) + return response_json except Exception as e: response_json = jsonify( - [{"error_no": "2", "message": "Trouble with backend! Sorry!"}] + [{"error_no": "199", "message": "Failed to retrive data from request!"}] ) make_new_log("get_user_task", e) return response_json - if user_id == "": + if user_id == "" or password == "": response_json = jsonify( - [{"error_no": "3", "message": "Given data is invalid!"}] + [ + { + "error_no": "110", + "message": "One or more of the required fields are empty!", + } + ] ) return response_json @@ -374,7 +880,7 @@ def handle_get_group_list() -> Response: groups: dict[str, dict] = get_group(user_id=user_id, password=password) except Exception as e: response_json = jsonify( - [{"error_no": "2", "message": "Trouble with backend! Sorry!"}] + [{"error_no": "200", "message": "Trouble with backend! Sorry!"}] ) make_new_log("get_user_task", e) return response_json @@ -382,7 +888,6 @@ def handle_get_group_list() -> Response: return response_json - if __name__ == "__main__": print("Running main.py") make_new_log("main", "Server started") # type: ignore @@ -393,4 +898,3 @@ def handle_get_group_list() -> Response: except Exception as e: print("There was a problem setting up the server here is the error info:") print(e) - exit(-1) diff --git a/backend/requirements.txt b/backend/requirements.txt index 433896c..3eed42a 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,3 +1,9 @@ -flask -dotenv -pytz +blinker==1.9.0 +click==8.1.8 +colorama==0.4.6 +Flask==3.1.0 +itsdangerous==2.2.0 +Jinja2==3.1.6 +MarkupSafe==3.0.2 +pytz==2025.2 +Werkzeug==3.1.3 diff --git a/backend/task.py b/backend/task.py index 0809a63..bd0f38a 100644 --- a/backend/task.py +++ b/backend/task.py @@ -5,6 +5,8 @@ from sqlite3 import connect, Connection, Cursor, Error from uuid import uuid4 +from error import BackendError + CREATE_TASK_TABLE: str = ( "CREATE TABLE IF NOT EXISTS task" "(uuid TEXT PRIMARY KEY, name TEXT NOT NULL, " @@ -30,13 +32,19 @@ "(group_id TEXT NOT NULL, user_id TEXT NOT NULL, " "role_id TEXT);" ) -CREATE_GROUP_ROLES_TABLE: str = ( - "CREATE TABLE IF NOT EXISTS group_roles" - "(group_id TEXT NOT NULL, uuid TEXT NOT NULL, " - "role_name TEXT NOT NULL, role_description TEXT, " - "role_permissions TEXT, admin INT NOT NULL);" +# CREATE_GROUP_ROLES_TABLE: str = ( +# "CREATE TABLE IF NOT EXISTS group_roles " +# "(group_id TEXT NOT NULL, uuid TEXT NOT NULL, " +# "role_name TEXT NOT NULL, role_description TEXT, " +# "role_permissions TEXT, admin INT NOT NULL);" +# ) +CREATE_PENDING_INVITE_TABLE: str = ( + "CREATE TABLE IF NOT EXISTS pending_invite " + "(group_id TEXT NOT NULL, user_id TEXT NOT NULL);" ) +# ---- Check Functions ---------------- + def check_table() -> Connection: """This will check if the task table exists.""" @@ -44,22 +52,27 @@ def check_table() -> Connection: try: data_con: Connection = connect("data/data.db") except Error as e_msg: - raise e_msg + raise BackendError("Backend Error: Cannot Connect to Database", 200) from e_msg data_cursor: Cursor = data_con.cursor() data_cursor.execute(CREATE_TASK_TABLE) data_cursor.execute(CREATE_USER_TABLE) data_cursor.execute(CREATE_GROUP_TABLE) data_cursor.execute(CREATE_GROUP_USER_TABLE) + data_cursor.execute(CREATE_PENDING_INVITE_TABLE) if ( len(data_cursor.execute("SELECT * FROM task;").description) != 14 or len(data_cursor.execute("SELECT * FROM user;").description) != 4 or len(data_cursor.execute("SELECT * FROM task_group;").description) != 4 or len(data_cursor.execute("SELECT * FROM group_user;").description) != 3 + or len(data_cursor.execute("SELECT * FROM pending_invite;").description) != 2 ): data_con.close() - raise Exception("User Database has not been configured successfully.") + raise BackendError( + "Backend Error: Not Been Configured Correctly, Ask Developers", + 201, + ) return data_con @@ -129,6 +142,9 @@ def check_password(data_con: Connection, user_id: str, password: str) -> bool: return True +# ---- User Functions ---------------- + + def add_user( username: str, email: str, @@ -139,22 +155,27 @@ def add_user( data_con: Connection = check_table() data_cursor: Cursor = data_con.cursor() except Error as e_msg: - raise e_msg + raise BackendError("Backend Error: Cannot Connect to Database", 200) from e_msg user_id: str = str(uuid4()) while check_id_exists(data_con, "user", user_id): user_id = str(uuid4()) data_cursor.execute( - "SELECT * FROM user WHERE username = ? OR email = ?;", - ( - username, - email, - ), + "SELECT * FROM user WHERE username = ?;", + (username,), ) if len(data_cursor.fetchall()) != 0: data_con.close() - raise Exception("Username or Email already exists.") + raise BackendError("Backend Error: Username already exists", 301) + + data_cursor.execute( + "SELECT * FROM user WHERE email = ?;", + (email,), + ) + if len(data_cursor.fetchall()) != 0: + data_con.close() + raise BackendError("Backend Error: Email already exists", 302) data_cursor.execute( "INSERT INTO user VALUES (?, ?, ?, ?);", @@ -175,7 +196,7 @@ def login_user( data_con: Connection = check_table() data_cursor: Cursor = data_con.cursor() except Error as e_msg: - raise e_msg + raise BackendError("Backend Error: Cannot Connect to Database", 200) from e_msg data_cursor.execute( "SELECT * FROM user WHERE email = ? AND password = ?;", @@ -183,7 +204,7 @@ def login_user( ) if len(data_cursor.fetchall()) == 0: data_con.close() - raise Exception("Email or Password is incorrect.") + raise BackendError("Backend Error: Email or Password is incorrect", 303) data_cursor.execute( "SELECT uuid FROM user WHERE email = ?;", @@ -196,53 +217,64 @@ def login_user( def edit_user( - user_id: str, - username: str, - email: str, - password: str, -): + user_id: str, username: str, email: str, password: str, new_password: str +) -> None: """Edits a user information.""" try: data_con: Connection = check_table() data_cursor: Cursor = data_con.cursor() except Error as e_msg: - raise e_msg + raise BackendError("Backend Error: Cannot Connect to Database", 200) from e_msg if check_user_exists(data_con, user_id) is False: data_con.close() - raise Exception("User does not exist.") + raise BackendError("Backend Error: User does not exist", 304) data_cursor.execute( - "SELECT * FROM user WHERE username = ? OR email = ?;", - ( - username, - email, - ), + "SELECT * FROM user WHERE username = ?;", + (username,), ) if len(data_cursor.fetchall()) != 0: data_con.close() - raise Exception("Username or Email already exists.") + raise BackendError("Backend Error: Username already exists", 301) + + data_cursor.execute( + "SELECT * FROM user WHERE email = ?;", + (email,), + ) + if len(data_cursor.fetchall()) != 0: + data_con.close() + raise BackendError("Backend Error: Email already exists", 302) + + if check_password(data_con, user_id, password) is False: + data_con.close() + raise BackendError("Backend Error: Password is incorrect", 305) data_cursor.execute( "UPDATE user SET username = ?, email = ?, password = ? WHERE uuid = ?;", - (username, email, password, user_id), + (username, email, new_password, user_id), ) return def delete_user( user_id: str, + password: str, ) -> None: """Deletes a user from the database.""" try: data_con: Connection = check_table() data_cursor: Cursor = data_con.cursor() except Error as e_msg: - raise e_msg + raise BackendError("Backend Error: Cannot Connect to Database", 200) from e_msg if check_user_exists(data_con, user_id) is False: data_con.close() - raise Exception("User does not exist.") + raise BackendError("Backend Error: User does not exist", 304) + + if check_password(data_con, user_id, password) is False: + data_con.close() + raise BackendError("Backend Error: Password is incorrect", 305) data_cursor.execute( "DELETE FROM user WHERE uuid = ?;", @@ -281,22 +313,34 @@ def delete_user( return +# ---- Group Functions ---------------- + + def create_group( user_id: str, description: str, group_name: str, + password: str, ) -> None: """This will create a group.""" try: data_con: Connection = check_table() data_cursor: Cursor = data_con.cursor() except Error as e_msg: - raise e_msg + raise BackendError("Backend Error: Cannot Connect to Database", 200) from e_msg group_id: str = str(uuid4()) while check_id_exists(data_con, "group", group_id): group_id = str(uuid4()) + if check_user_exists(data_con, user_id) is False: + data_con.close() + raise BackendError("Backend Error: User does not exist", 304) + + if check_password(data_con, user_id, password) is False: + data_con.close() + raise BackendError("Backend Error: Password is incorrect", 305) + data_cursor.execute( "INSERT INTO group VALUES (?, ?, ?, ?);", (group_id, group_name, description, user_id), @@ -315,25 +359,30 @@ def create_group( def add_user_to_group( user_id: str, group_id: str, + password: str, ) -> None: """Adds a user to a group.""" try: data_con: Connection = check_table() data_cursor: Cursor = data_con.cursor() except Error as e_msg: - raise e_msg + raise BackendError("Backend Error: Cannot Connect to Database", 200) from e_msg if check_user_exists(data_con, user_id) is False: data_con.close() - raise Exception("User does not exist.") + raise BackendError("Backend Error: User does not exist", 304) + + if check_password(data_con, user_id, password) is False: + data_con.close() + raise BackendError("Backend Error: Password is incorrect", 305) if check_group_exists(data_con, group_id) is False: data_con.close() - raise Exception("Group does not exist.") + raise BackendError("Backend Error: Group does not exist", 306) if check_user_in_group(data_con, user_id, group_id): data_con.close() - raise Exception("User is already in the group.") + raise BackendError("Backend Error: User already in group", 307) data_cursor.execute( "INSERT INTO group_user VALUES (?, ?);", @@ -346,21 +395,26 @@ def add_user_to_group( def remove_user_from_group( user_id: str, group_id: str, + password: str, ) -> None: """Removes a user from a group.""" try: data_con: Connection = check_table() data_cursor: Cursor = data_con.cursor() except Error as e_msg: - raise e_msg + raise BackendError("Backend Error: Cannot Connect to Database", 200) from e_msg if check_user_exists(data_con, user_id) is False: data_con.close() - raise Exception("User does not exist.") + raise BackendError("Backend Error: User does not exist", 304) + + if check_password(data_con, user_id, password) is False: + data_con.close() + raise BackendError("Backend Error: Password is incorrect", 305) if check_group_exists(data_con, group_id) is False: data_con.close() - raise Exception("Group does not exist.") + raise BackendError("Backend Error: Group does not exist", 306) data_cursor.execute( "DELETE FROM group_user WHERE group_id = ? AND user_id = ?;", @@ -373,21 +427,26 @@ def remove_user_from_group( def delete_group( user_id: str, group_id: str, + password: str, ) -> None: """Deletes a group.""" try: data_con: Connection = check_table() data_cursor: Cursor = data_con.cursor() except Error as e_msg: - raise e_msg + raise BackendError("Backend Error: Cannot Connect to Database", 200) from e_msg if check_group_exists(data_con, group_id) is False: data_con.close() - raise Exception("Group does not exist.") + raise BackendError("Backend Error: Group does not exist", 306) if check_user_exists(data_con, user_id) is False: data_con.close() - raise Exception("User does not exist.") + raise BackendError("Backend Error: User does not exist in group", 304) + + if check_password(data_con, user_id, password) is False: + data_con.close() + raise BackendError("Backend Error: Password is incorrect", 305) data_cursor.execute( "SELECT * FROM task_group WHERE uuid = ? AND owner_id = ?;", @@ -396,7 +455,7 @@ def delete_group( if len(data_cursor.fetchall()) == 0: data_con.close() - raise Exception("User does not own the group.") + raise BackendError("Backend Error: User is not the owner of the group", 308) data_cursor.execute( "DELETE FROM task_group WHERE uuid = ?;", @@ -420,15 +479,15 @@ def get_group( data_con: Connection = check_table() data_cursor: Cursor = data_con.cursor() except Error as e_msg: - raise e_msg + raise BackendError("Backend Error: Cannot Connect to Database", 200) from e_msg if check_user_exists(data_con, user_id) is False: data_con.close() - raise Exception("User does not exist.") + raise BackendError("Backend Error: User does not exist", 304) if check_password(data_con, user_id, password) is False: data_con.close() - raise Exception("Password is incorrect.") + raise BackendError("Backend Error: Password is incorrect", 305) data_cursor.execute( "SELECT * FROM group_user WHERE user_id = ?;", @@ -448,6 +507,9 @@ def get_group( return new_group_list +# ---- Task Functions ---------------- + + def add_task( task_name: str, task_description: str, @@ -461,7 +523,7 @@ def add_task( recursive: int, priority: int, image_path: str, - password: str = "", + password: str, ) -> None: """This will add the task.""" @@ -469,19 +531,22 @@ def add_task( data_con: Connection = check_table() data_cursor: Cursor = data_con.cursor() except Error as e_msg: - raise e_msg + raise BackendError("Backend Error: Cannot Connect to Database", 200) from e_msg if ( check_user_exists(data_con, assigner_id) is False or check_user_exists(data_con, assign_id) is False - or (group_id != "0" and check_group_exists(data_con, group_id) is False) ): data_con.close() - raise Exception("User or Group does not exist.") + raise BackendError("Backend Error: User does not exist", 304) + + if group_id != "0" and check_group_exists(data_con, group_id) is False: + data_con.close() + raise BackendError("Backend Error: Group does not exist", 306) if check_password(data_con, assigner_id, password) is False: data_con.close() - raise Exception("Password is incorrect.") + raise BackendError("Backend Error: Password is incorrect", 305) task_id: str = str(uuid4()) while check_id_exists(data_con, "task", task_id): @@ -523,34 +588,42 @@ def edit_task( assigner_id: str, assign_id: str, group_id: str, - password: str + recursive: int, + priority: int, + completed: int, + image_path: str, + password: str, ) -> bool: """This will edit the task.""" try: data_con: Connection = check_table() data_cursor: Cursor = data_con.cursor() except Error as e_msg: - raise e_msg + raise BackendError("Backend Error: Cannot Connect to Database", 200) from e_msg if check_task_exists(data_con, task_id) is False: data_con.close() - raise Exception("Task does not exist.") + raise BackendError("Backend Error: Task does not exist", 309) if ( check_user_exists(data_con, assigner_id) is False or check_user_exists(data_con, assign_id) is False - or (group_id != "0" and check_group_exists(data_con, group_id) is False) ): data_con.close() - raise Exception("User or Group does not exist.") + raise BackendError("Backend Error: User does not exist", 304) + + if group_id != "0" and check_group_exists(data_con, group_id) is False: + data_con.close() + raise BackendError("Backend Error: Group does not exist", 306) if check_password(data_con, assigner_id, password) is False: data_con.close() - raise Exception("Password is incorrect.") + raise BackendError("Backend Error: Password is incorrect", 305) data_cursor.execute( "UPDATE task SET name = ?, description = ?, due = ?, est_day = ?, " "est_hour = ?, est_min = ?, assigner_uuid = ?, assign_uuid = ?, group_id = ? " + "recursive = ?, priority = ?, image_path = ? completed = ? " "WHERE uuid = ?;", ( task_name, @@ -562,6 +635,10 @@ def edit_task( assigner_id, assign_id, group_id, + recursive, + priority, + image_path, + completed, task_id, ), ) @@ -581,15 +658,15 @@ def delete_task( data_con: Connection = check_table() data_cursor: Cursor = data_con.cursor() except Error as e_msg: - raise e_msg + raise BackendError("Backend Error: Cannot Connect to Database", 200) from e_msg if check_task_exists(data_con, task_id) is False: data_con.close() - raise Exception("Task does not exist.") + raise BackendError("Backend Error: Task does not exist", 309) if check_password(data_con, user_id, password) is False: data_con.close() - raise Exception("Password is incorrect.") + raise BackendError("Backend Error: Password is incorrect", 305) data_cursor.execute("DELETE FROM task WHERE uuid = ?;", (task_id,)) data_con.commit() @@ -604,15 +681,15 @@ def get_user_task(user_id: str, password: str) -> dict[str, dict]: data_con: Connection = check_table() data_cursor: Cursor = data_con.cursor() except Error as e_msg: - raise e_msg + raise BackendError("Backend Error: Cannot Connect to Database", 200) from e_msg if check_user_exists(data_con, user_id) is False: data_con.close() - raise Exception("User does not exist.") + raise BackendError("Backend Error: User does not exist", 304) if check_password(data_con, user_id, password) is False: data_con.close() - raise Exception("Password is incorrect.") + raise BackendError("Backend Error: Password is incorrect", 305) data_cursor.execute("SELECT * FROM task WHERE assign_uuid = ?;", (user_id,)) @@ -641,23 +718,30 @@ def get_user_task(user_id: str, password: str) -> dict[str, dict]: def get_group_task( user_id: str, group_id: str, + password: str, ) -> dict[str, dict]: """This will get the task from the user.""" try: data_con: Connection = check_table() data_cursor: Cursor = data_con.cursor() except Error as e_msg: - raise e_msg + raise BackendError("Backend Error: Cannot Connect to Database", 200) from e_msg - if ( - check_user_exists(data_con, user_id) is False - or check_group_exists(data_con, group_id) is False - or check_user_in_group(data_con, user_id, group_id) is False - ): + if check_user_exists(data_con, user_id) is False: data_con.close() - raise Exception( - "User does not exist or Group does not exist or User is not in the group." - ) + raise BackendError("Backend Error: User does not exist", 304) + + if check_password(data_con, user_id, password) is False: + data_con.close() + raise BackendError("Backend Error: Password is incorrect", 305) + + if check_group_exists(data_con, group_id) is False: + data_con.close() + raise BackendError("Backend Error: Group does not exist", 306) + + if check_user_in_group(data_con, user_id, group_id) is False: + data_con.close() + raise BackendError("Backend Error: User is not in the group", 310) data_cursor.execute( "SELECT * FROM task WHERE group_id = ?;", @@ -685,23 +769,38 @@ def get_group_task( def get_completed_task( user_id: str, + group_id: str, + password: str, ) -> dict[str, dict]: """This will get the completed task from the user.""" try: data_con: Connection = check_table() data_cursor: Cursor = data_con.cursor() except Error as e_msg: - raise e_msg + raise BackendError("Backend Error: Cannot Connect to Database", 200) from e_msg + if check_user_exists(data_con, user_id) is False: data_con.close() - raise Exception("User does not exist.") + raise BackendError("Backend Error: User does not exist", 304) + + if check_group_exists(data_con, group_id) is False: + data_con.close() + raise BackendError("Backend Error: Group does not exist", 306) + + if check_user_in_group(data_con, user_id, group_id) is False: + data_con.close() + raise BackendError("Backend Error: User is not in the group", 310) + + if check_password(data_con, user_id, password) is False: + data_con.close() + raise BackendError("Backend Error: Password is incorrect", 305) data_cursor.execute( "SELECT * FROM task WHERE assign_id = ? " "OR group_id IN (SELECT group_id FROM group_user WHERE user_id = ?) " "AND completed = 1;", ( - user_id, + group_id, user_id, ), ) @@ -726,42 +825,42 @@ def get_completed_task( return new_task_list -def complete_task( +def toggle_complete_task( task_id: str, + user_id: str, + password: str, + completed: int, ) -> None: """This will complete the task.""" try: data_con: Connection = check_table() data_cursor: Cursor = data_con.cursor() except Error as e_msg: - raise e_msg + raise BackendError("Backend Error: Cannot Connect to Database", 200) from e_msg - if check_task_exists(data_con, task_id) is False: + if check_user_exists(data_con, user_id) is False: data_con.close() - raise Exception("Task does not exist.") - - data_cursor.execute("UPDATE task SET completed = 1 WHERE uuid = ?;", (task_id,)) - data_con.commit() - data_con.close() - - return + raise BackendError("Backend Error: User does not exist", 304) + if check_password(data_con, user_id, password) is False: + data_con.close() + raise BackendError("Backend Error: Password is incorrect", 305) -def uncomplete_task( - task_id: str, -) -> None: - """This will uncomplete the task.""" - try: - data_con: Connection = check_table() - data_cursor: Cursor = data_con.cursor() - except Error as e_msg: - raise e_msg + if check_user_in_group(data_con, user_id, task_id) is False: + data_con.close() + raise BackendError("Backend Error: User is not in the group", 310) if check_task_exists(data_con, task_id) is False: data_con.close() - raise Exception("Task does not exist.") + raise BackendError("Backend Error: Task does not exist", 309) - data_cursor.execute("UPDATE task SET completed = 0 WHERE uuid = ?;", (task_id,)) + data_cursor.execute( + "UPDATE task SET completed = ? WHERE uuid = ?;", + ( + completed, + task_id, + ), + ) data_con.commit() data_con.close() diff --git a/documentation/backend_error_code.txt b/documentation/backend_error_code.txt new file mode 100644 index 0000000..69596cd --- /dev/null +++ b/documentation/backend_error_code.txt @@ -0,0 +1,60 @@ +List of error codes that corresponds to the error messages in the backend. + +0: "Success" + +--------------- +Client error codes +--------------- + +100: "Invalid request" + The request is invalid. Most likely the reuqest was not used correctly. [POST] +101: "Attribute Error" + The request is missing an attribute. Please check the request and try again. +102: "Key Error" + The request is missing a key. Please check the request and try again. +103: "Type Error" + The request has an invalid type. Please check the request and try again. +110: "Missing Criteria" + Some of the criteria is empty. Please check the request and try again. + +199: "Generic Client Error" + The request is invalid. Most likely the reuqest was not used correctly. + + +---------------- +Backend error codes +---------------- + +200: "Generic Backend Error" + Somethign went wrong in the backend, but we don't know what. + +201: "Backend Not Been configured correctly" + The backend has not been configured correctly. Please check the backend configuration. + + +---------------- +sqlite3 error codes +---------------- +300: "sqlite3 error" + Somethign went wrong in the sqlite3 database, but we don't know what. +301: "Username Duplicate" + The username already exists. Please choose a different username. +302: "Email Duplicate" + The email already exists. Please choose a different email. +303: "email or password is incorrect" + The email or password is incorrect. Please check the email and password and try again. +304: "User not found" + The user was not found. Please check the email and password and try again. +305: "Password is not correct" + The password is not correct. Please check the password and try again. + (The difference with 303 is that 303 is for login and 305 is for modifying data) +306: "Group not found" + The group was not found. Please check the group id and try again. +307: "User is already in the group" + The user is already in the group. Please check the group id and try again. +308: "User is not the owner of the group" + The user is not the owner of the group. Please check the group id and try again. +309: "Task does not exist" + The task does not exist. Please check the task id and try again. +310: "User is not in the group" + The user is not in the group. Please check the group id and try again. \ No newline at end of file diff --git a/backend/dotenv.md b/documentation/dotenv.md similarity index 79% rename from backend/dotenv.md rename to documentation/dotenv.md index 583e5e9..6d1610b 100644 --- a/backend/dotenv.md +++ b/documentation/dotenv.md @@ -3,14 +3,19 @@ This is a memo for how to create an venv to run the python backend. https://python.land/virtual-environments/virtualenv - 1: Make sure your terminal is in the `roomiebuddy`. + + - 2: run `python3 -m venv .env` + They might ask you for to install venv, so do it. - 3: run `source .env/bin/activate` +- 4: or run with `.env/bin/python3 [PATH_TO_PYTHON_FILE]` +- 4.5: or run with `.env/bin/pip3 [SOME PIP COMMAND]` Note: If you use vscode, make sure the inteperter is set to the `python3.xx` (xx is the version number) that is inside the `.env/bin/` folder.