diff --git a/main.py b/main.py index dd8eec5f682781c19226d61962a3e531e2bec620..02e8383d2717b53875623b16ed9c6db501517a97 100644 --- a/main.py +++ b/main.py @@ -23,128 +23,143 @@ def loginAttempt(username: str, password: str) -> StaffUser | ManagerUser | Admi else returns None type. Args: - username (str): encrypted username - password (str): encrypted password + username (str): encrypted username. + password (str): encrypted password. + + Raises: + ValueError: if db returns invalid permissionLevel. + + Returns: + + StaffUser | ManagerUser | AdminUser | None: returns user object or NoneType if login unsucssesfull. """ - del_later = StaffUser() - del_later.userName = username - del_later.userPass = password - return del_later + # get permissionLevel and user_id where username and password are match. + conditon = json.loads(select_from_tbl_where("tblUsers", f"userName='{username}' AND userPass='{password}'", "permissionLevel")) + # based on permissonLevel create the relevant user class object. + match conditon["permissionLevel"]: + case 0: + user = StaffUser() + case 1: + user = AdminUser() + case 2: + user = ManagerUser() + case _: + logging.debug(f"input values {username}, {password} returned non-valid permissionLevel.") + raise ValueError() + user.login(username, password) + return user def staffUser_options_cli(user:StaffUser) -> None: - case = True - while case: - case = input("Menu options:\n" + while True: + selection = input("Menu options:\n" " 1. View Listings \n" " 2. Create booking \n" " 3. Logout \n" " please return a number to select: ") # switch case: - if case == "1": - logging.debug("selection 1, View listings") - user.viewFilmListings() - # get from cinema the listings and display film data in dict/jason - # user.viewFilmListings() - # format and display data - elif case == "2": - logging.debug("selection 2, Create booking") - # create booking obj and display attributes for selection - # save booking to cinema and db - # user.createBooking() - elif case == "3": - logging.debug("selection 3, logout") - user.logout() - exit() - else: - print("Invalid input, please input an integer value corresponding with an option.") - case = True + match selection: + case "1": + logging.debug("selection 1, loading View listings") + user.viewFilmListings() + # get from cinema the listings and display film data in dict/jason + # user.viewFilmListings() + # format and display data + case "2": + logging.debug("selection 2, loading Create booking") + # create booking obj and display attributes for selection + # save booking to cinema and db + user.createBooking() + case "3": + logging.debug("selection 3, loading logout") + break + case _: + print("Invalid input, please input an integer value corresponding with an option.") + user.logout() + exit() def managerUser_options_cli(user:ManagerUser) -> None: - case = True - while case: - case = input("Menu options:\n" + while True: + selection = input("Menu options:\n" " 1. View Listings \n" " 2. Create booking \n" " 3. Logout \n" " please return a number to select: ") - # switch case: - if case == "1": - logging.debug("selection 1, View listings") - elif case == "2": - logging.debug("selection 2, Create booking") - elif case == "3": - logging.debug("selection 3, logout") - user.logout() - exit() - else: - print("Invalid input, please input an integer value corresponding with an option.") - case = False + match selection: + case "1": + logging.debug("selection 1, loading View listings") + case "2": + logging.debug("selection 2, loading Create booking") + case "3": + logging.debug("selection 3, loading logout") + break + case _: + print("Invalid input, please input an integer value corresponding with an option.") + user.logout() + exit() def adminUser_options_cli(user:AdminUser) -> None: - case = True - while case: - case = input("Menu options:\n" + while True: + selection = input("Menu options:\n" " 1. View Listings \n" " 2. Create booking \n" " 3. Logout \n" " please return a number to select: ") - # switch case: - if case == "1": - logging.debug("selection 1, View listings") - elif case == "2": - logging.debug("selection 2, Create booking") - elif case == "3": - logging.debug("selection 3, logout") - user.logout() - exit() - else: - print("Invalid input, please input an integer value corresponding with an option.") - case = False + match selection: + case "1": + logging.debug("selection 1, loading View listings") + case "2": + logging.debug("selection 2, loading Create booking") + case "3": + logging.debug("selection 3, loading logout") + break + case _: + print("Invalid input, please input an integer value corresponding with an option.") + user.logout() + exit() + def load_cinema(cinemaID) -> Cinema: - pass + raise NotImplementedError() -def san(string:str) -> str: +def sanitize(string:str) -> str: """ String sanitization function Args: string (str): string variable to be sanitized. Returns: - string but without any escape chars + lower case string without any escape chars """ - return string.strip().replace('/', '_').replace('\\', '_') + return string.strip().replace('/', '_').replace('\\', '_').lower() def encrypt(string:str) -> str: # add encryption when necessary return string -def save(): - raise NotImplementedError() - def main_cli() -> None: print("\n\nSTARTING CINEMA MANAGEMENT SYSTEM.\n\n") # test db is connected.... # if not getConnection(): # logging.critical("Database cannot connect, or dose not exist. \nClosing application.") # exit() - user = None - while user is None: - username = encrypt(san(str(input("To login please enter your credentials.\nUsername: ")))) - password = encrypt(san(str(input("Password: ")))) + + while True: + username = encrypt(sanitize(input("To login please enter your credentials.\nUsername: "))) + password = encrypt(sanitize(input("Password: "))) user = loginAttempt(username=username, password=password) if user is None: print("Login attempt failed please try again.") else: break logging.info("successful login, loading menu...") - user.login() - - if user.permissionLevel == 1: - managerUser_options_cli(user) - elif user.permissionLevel == 2: - adminUser_options_cli(user) - else: - staffUser_options_cli(user) + + + match user.permissionLevel: + case 1: + managerUser_options_cli(user) + case 2: + adminUser_options_cli(user) + case _: + staffUser_options_cli(user) # following code will only execute if run directly from this file. if __name__ == "__main__": diff --git a/src/constants.py b/src/constants.py index dc652f59d5acca9b5edf1db9c7341362d6f9ef4e..b8ca0ff898ad48ba62d5b19d2d7d2667cc42ca33 100644 --- a/src/constants.py +++ b/src/constants.py @@ -1,5 +1,11 @@ # all constants are followed by docstrings labeling them, these strings show on hover in most IDEs(vscode and pycharm at least) +# database values: +DBNAME = "aaaaa" +DBUSERNAME = "" +DBPASSWORD = "" +DBHOSTNAME = "" + # screenObj: MAX_SIZE:float = 100.0 """Maximum screen size in meters""" diff --git a/src/dbfunc.py b/src/dbfunc.py index ac61c2b4bb0dde40d7480f83f59de678f7920f9d..e0190f031d0bbc7afe43b7dbfe658b98dc98e2fa 100644 --- a/src/dbfunc.py +++ b/src/dbfunc.py @@ -1,20 +1,17 @@ import logging, json, mysql +from .constants import DBNAME, DBHOSTNAME, DBUSERNAME, DBPASSWORD from mysql.connector import errorcode -# Vars -hostname = "localhost" -username = "" -passwd = "" + def getConnection(db=""): # if specified database if db != "": - try: - conn = mysql.connector.connect(host = hostname, - user = username, - password = passwd, + conn = mysql.connector.connect(host = DBHOSTNAME, + user = DBUSERNAME, + password = DBPASSWORD, database = db) except mysql.connector.Error as err: if err.errno == errorcode.ER_ACCESS_DENIED_ERROR: @@ -29,9 +26,9 @@ def getConnection(db=""): # if database not specified try default from line 5 else: try: - conn = mysql.connector.connect(host = hostname, - user = username, - password = passwd) + conn = mysql.connector.connect(host = DBHOSTNAME, + user = DBUSERNAME, + password = DBPASSWORD) except mysql.connector.Error as err: if err.errno == errorcode.ER_ACCESS_DENIED_ERROR: logging.error("Username or Password is not working") @@ -41,20 +38,20 @@ def getConnection(db=""): logging.error("Connected to server, without database.") return conn -def selectFromTbl(table, dbname, *args) -> json: +def select_from_tbl(table:str, dbname, *args) -> json: logging.debug(f"running slect statement with values: tablename='{table}'', dbname='{dbname}'', {args}") - conn = getConnection(db=dbname) + conn = getConnection(db=DBNAME) if conn != None: if conn.is_connected(): - SELECT_STATEMENT = f"SELECT " + SELECT_statement = f"SELECT " for arg in args: - SELECT_STATEMENT.append(f"{arg}, ") - SELECT_STATEMENT.removesuffix(", ") - SELECT_STATEMENT.append(f" from {table};") + SELECT_statement.append(f"{arg}, ") + SELECT_statement.removesuffix(", ") + SELECT_statement.append(f" from {table};") dbcursor = conn.cursor() dbcursor.execute(f"USE {dbname}") - dbcursor.execute(SELECT_STATEMENT) + dbcursor.execute(SELECT_statement) logging.info("SELECT statement executed successfully.") data = dbcursor.fetchall() logging.debug(f"dataOut: {data}") @@ -69,18 +66,39 @@ def selectFromTbl(table, dbname, *args) -> json: logging.error("conn returned NoneType") raise ConnectionAbortedError() -def selectFromTblWhere(table, dbname, condition, *args) -> json: - logging.debug(f"running select statement with values: tablename='{table}'', dbname='{dbname}'', {args}") - conn = getConnection(db=dbname) +def select_from_tbl_where(table:str, condition:str, dbname:str=DBNAME, *args:str) -> json: + """_summary_ + utility function for getting data from database. + + SQL query format: + 'SELECT args FROM table WHERE condition;' + + Args: + table (str): table name in database. + dbname (str): database name, defult from constants. + condition (str): condition used to search table with more detail and smaller retrun. + + Raises: + ConnectionAbortedError: if the connection variables are invalid. + ConnectionError: if the database could not be connected to. + + Returns: + json: json string of returned values. + """ + if len(args) == 0: + args = ("*") + logging.debug(f"running select statement with values: tablename={table}, dbname={dbname}, condition={condition}, args={args}") + conn = getConnection(db=DBNAME) if conn == None: - logging.error("conn returned NoneType") + logging.warning("conn returned NoneType") raise ConnectionAbortedError() if conn.is_connected(): SELECT_statement = "SELECT " for arg in args: SELECT_statement.append(f"{arg}, ") SELECT_statement.removesuffix(", ") - SELECT_statement.append(f" from {table};") + SELECT_statement.append(f" from {table} ") + SELECT_statement.append(f"WHERE {condition};") dbcursor = conn.cursor() dbcursor.execute(f"USE {dbname}") @@ -97,9 +115,10 @@ def selectFromTblWhere(table, dbname, condition, *args) -> json: raise ConnectionError() -def saveToTbl(table, dbname, jsonData): +def save_to_Tbl(table, dbname, jsonData): + """need to fix""" logging.debug(f"running update statment with values: tablename='{table}', dbname='{dbname}', data='{jsonData}'") - conn = getConnection(db=dbname) + conn = getConnection(db=DBNAME) if conn == None: logging.error("conn returned NoneType") raise ConnectionAbortedError() diff --git a/src/staffUser.py b/src/staffUser.py index b77d170b53645905639e6576904b94266aa74eb3..1a80f73fc1944b756cc594c3551120f72e30cec6 100644 --- a/src/staffUser.py +++ b/src/staffUser.py @@ -16,33 +16,26 @@ class StaffUser(object): def __str__(self): return f"{self.__class__.__name__} user object(userID={self.userID}, userName={self.userName}, userPass={self.userPass}, permissionLevel={self.permissionLevel})" - def login(self, userID) -> None: + def login(self, userName, userPassword) -> None: """get values for self from db""" logging.debug("called login func") - jsonData = selectFromTblWhere("tblUsers", "", f"user_id={userID}", "*") + jsonData = select_from_tbl_where("tblUsers", f"userName='{userName}' AND userPass='{userPassword}'") dictData = json.loads(jsonData) - logging.debug(f"loaded data: {dictData}") - - # update self data with new values. - raise NotImplementedError() -<<<<<<< Updated upstream -======= - - def login(self): - # check if self.userName AND self.userPass in tblUsers, then log - logging.debug(f"user {self.userID} logging in.") - raise NotImplementedError() + logging.debug(f"loaded data: {jsonData}") + # this will loop with i as any key from dictData and self.dict that matches, i hope lol. + for i in dictData.keys(), self.__dict__.keys(): + self.i = dictData[i] def logout(self): logging.debug(f"user {self.userID} logging out.") - self.save() ->>>>>>> Stashed changes + self._save_self_to_db() + self.close() def _save_self_to_db(self) -> None: """save self.__dict__ to db.""" logging.debug("called _save_self_to_db func") try: - saveToTbl("tblUsers", DBNAME, self.__dict__) + save_to_Tbl("tblUsers", DBNAME, self.__dict__) except Exception as e: logging.error(e.message, e.args) @@ -69,17 +62,20 @@ class StaffUser(object): logging.debug("called manageBooking func") raise NotImplementedError() - def cli_view_film_listings(self) -> None: + def cli_view_film_listings(self) -> None: # cant work out how to implement this function in main.py... would like to remove. logging.debug("called cli_viewFilmListing func") for i in self.returnFilmListings(): # will need formating, from json? print(f"listing:{i}") - case = input("Options: 1-exit, 2-move to create booking, 3-logout\n: ") - if case == "2": - self.createBooking() - elif case == "3": - self.logout() + selection = int(input("Options: 1-exit, 2-move to create booking, 3-logout\n: ")) + match selection: + case 2: + self.createBooking() + case 3: + self.logout() + case _: + print("input invalid, try again with valid option.")