From 11824ae5a10330caa9381d864c71a206612ca145 Mon Sep 17 00:00:00 2001 From: Terence <terence2.frayne@live.uwe.ac.uk> Date: Wed, 19 Feb 2025 11:10:29 +0000 Subject: [PATCH] Updated login system, GUI, and added database export --- GUI.py | 90 +++++- Horizon_cinema Database.sql | 232 ++++++++++++++++ README.md | 22 +- __pycache__/main.cpython-312.pyc | Bin 5680 -> 6324 bytes main.py | 78 +++--- src/__pycache__/__init__.cpython-312.pyc | Bin 549 -> 512 bytes src/__pycache__/adminUser.cpython-312.pyc | Bin 860 -> 823 bytes src/__pycache__/bookingObj.cpython-312.pyc | Bin 855 -> 818 bytes src/__pycache__/cinemaObj.cpython-312.pyc | Bin 2756 -> 2719 bytes src/__pycache__/constants.cpython-312.pyc | Bin 603 -> 601 bytes src/__pycache__/dbfunc.cpython-312.pyc | Bin 7724 -> 8557 bytes src/__pycache__/managerUser.cpython-312.pyc | Bin 1031 -> 994 bytes src/__pycache__/reportObj.cpython-312.pyc | Bin 738 -> 701 bytes src/__pycache__/screenObj.cpython-312.pyc | Bin 3580 -> 3543 bytes src/__pycache__/staffUser.cpython-312.pyc | Bin 5434 -> 5463 bytes src/constants.py | 8 +- src/dbfunc.py | 288 ++++++++++---------- 17 files changed, 528 insertions(+), 190 deletions(-) create mode 100644 Horizon_cinema Database.sql diff --git a/GUI.py b/GUI.py index 8a45610..24a0776 100644 --- a/GUI.py +++ b/GUI.py @@ -1,5 +1,16 @@ from tkinter import Tk, Frame, Label, Entry, Button, messagebox from main import * +from src.staffUser import StaffUser +from src.adminUser import AdminUser +from src.managerUser import ManagerUser +from main import loginAttempt +from tkinter import Listbox +from src.dbfunc import fetch_movies + +import sys +sys.path.append("src") # Ensure Python finds 'src' modules +from main import * + # Initialize main window window = Tk() @@ -49,21 +60,59 @@ def apply_theme(): theme_toggle_button.configure(bg=current_theme["button_bg"], fg=current_theme["button_fg"]) # Handle login action + +# Function - open dashboards based on user role +def open_dashboard(user): + """Opens different GUI windows based on user role""" + + if user is None: + messagebox.showerror("Error", "Invalid login attempt.") + return + + dashboard = Tk() + dashboard.title("Dashboard") + dashboard.geometry("500x400") + + # Display Welcome Message Using `user.username` + welcome_label = Label(dashboard, text=f"Welcome, {user['username']}!", font=("Arial", 16)) + welcome_label.pack(pady=20) + + if isinstance(user, StaffUser): + Label(dashboard, text="Staff Dashboard").pack() + Button(dashboard, text="View Listings").pack() + Button(dashboard, text="Create Booking").pack() + + elif isinstance(user, AdminUser): + Label(dashboard, text="Admin Dashboard").pack() + Button(dashboard, text="Manage Listings").pack() + Button(dashboard, text="View Reports").pack() + + elif isinstance(user, ManagerUser): + Label(dashboard, text="Manager Dashboard").pack() + Button(dashboard, text="Expand Business").pack() + Button(dashboard, text="Generate Revenue Reports").pack() + + Button(dashboard, text="Logout", command=dashboard.quit).pack(pady=20) + + dashboard.mainloop() + def gui_login(): username = username_entry.get() password = password_entry.get() - # check form not empty + if not username or not password: messagebox.showwarning("Warning", "Please fill in both fields.") - # escape function - else: # remove else and message box when login function is finished. - messagebox.showinfo("Login", "Login successful!") - # function call "loginAttempt()" from main.py - user = None - while user is None: - user = loginAttempt(username=username, password=password) - if user: - break + return + + # Call loginAttempt() from main.py + user = loginAttempt(username, password) + + if user: + messagebox.showinfo("Login", f"Login successful! Welcome {user['username']}.") + window.destroy() # Close login window + open_dashboard(user) # Open appropriate dashboard based on user role + else: + messagebox.showerror("Error", "Incorrect username or password!") # Make rows and columns in the main window expand to center the form frame window.grid_rowconfigure(0, weight=1) @@ -103,4 +152,23 @@ apply_theme() # app will only launch if run directly from this file. if __name__ == "__main__": - window.mainloop() \ No newline at end of file + window.mainloop() + +def fetch_movies(): + conn = get_connection() + if conn: + cursor = conn.cursor(dictionary=True) + cursor.execute("SELECT title, genre, age_rating FROM Films") + movies = cursor.fetchall() + conn.close() + return movies + return [] + +# Create a listbox widget +movie_listbox = Listbox(dashboard) +movie_listbox.pack() + +# Fetch movies from database and display +movies = fetch_movies() +for movie in movies: + movie_listbox.insert("end", f"{movie['title']} ({movie['genre']}, Rated: {movie['age_rating']})") \ No newline at end of file diff --git a/Horizon_cinema Database.sql b/Horizon_cinema Database.sql new file mode 100644 index 0000000..c8832d0 --- /dev/null +++ b/Horizon_cinema Database.sql @@ -0,0 +1,232 @@ +-- MySQL dump 10.13 Distrib 8.0.19, for Win64 (x86_64) +-- +-- Host: localhost Database: horizon_cinema +-- ------------------------------------------------------ +-- Server version 8.0.19 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!50503 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `bookings` +-- + +DROP TABLE IF EXISTS `bookings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `bookings` ( + `booking_id` int NOT NULL AUTO_INCREMENT, + `user_id` int DEFAULT NULL, + `showing_id` int DEFAULT NULL, + `seat_number` varchar(10) NOT NULL, + `total_price` decimal(6,2) NOT NULL, + `booking_date` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`booking_id`), + KEY `user_id` (`user_id`), + KEY `showing_id` (`showing_id`), + CONSTRAINT `bookings_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) ON DELETE CASCADE, + CONSTRAINT `bookings_ibfk_2` FOREIGN KEY (`showing_id`) REFERENCES `showings` (`showing_id`) ON DELETE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `bookings` +-- + +LOCK TABLES `bookings` WRITE; +/*!40000 ALTER TABLE `bookings` DISABLE KEYS */; +/*!40000 ALTER TABLE `bookings` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `cancellations` +-- + +DROP TABLE IF EXISTS `cancellations`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `cancellations` ( + `cancellation_id` int NOT NULL AUTO_INCREMENT, + `booking_id` int DEFAULT NULL, + `cancelled_by` int DEFAULT NULL, + `cancellation_date` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `refund_amount` decimal(6,2) DEFAULT NULL, + PRIMARY KEY (`cancellation_id`), + KEY `booking_id` (`booking_id`), + KEY `cancelled_by` (`cancelled_by`), + CONSTRAINT `cancellations_ibfk_1` FOREIGN KEY (`booking_id`) REFERENCES `bookings` (`booking_id`) ON DELETE CASCADE, + CONSTRAINT `cancellations_ibfk_2` FOREIGN KEY (`cancelled_by`) REFERENCES `users` (`user_id`) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `cancellations` +-- + +LOCK TABLES `cancellations` WRITE; +/*!40000 ALTER TABLE `cancellations` DISABLE KEYS */; +/*!40000 ALTER TABLE `cancellations` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `cinemas` +-- + +DROP TABLE IF EXISTS `cinemas`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `cinemas` ( + `cinema_id` int NOT NULL AUTO_INCREMENT, + `city` varchar(50) NOT NULL, + `location` varchar(255) NOT NULL, + PRIMARY KEY (`cinema_id`) +) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `cinemas` +-- + +LOCK TABLES `cinemas` WRITE; +/*!40000 ALTER TABLE `cinemas` DISABLE KEYS */; +INSERT INTO `cinemas` VALUES (1,'Birmingham','Downtown Birmingham'),(2,'London','West End'),(3,'Birmingham','Downtown Birmingham'),(4,'London','West End'),(5,'Birmingham','Downtown Birmingham'),(6,'London','West End'),(7,'Birmingham','Downtown Birmingham'),(8,'London','West End'),(9,'Birmingham','Downtown Birmingham'),(10,'London','West End'); +/*!40000 ALTER TABLE `cinemas` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `films` +-- + +DROP TABLE IF EXISTS `films`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `films` ( + `film_id` int NOT NULL AUTO_INCREMENT, + `title` varchar(100) NOT NULL, + `genre` varchar(50) DEFAULT NULL, + `age_rating` varchar(10) DEFAULT NULL, + `duration` int NOT NULL, + `description` text, + PRIMARY KEY (`film_id`) +) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `films` +-- + +LOCK TABLES `films` WRITE; +/*!40000 ALTER TABLE `films` DISABLE KEYS */; +INSERT INTO `films` VALUES (1,'Interstellar','Sci-Fi','PG-13',169,'A team of explorers travel through a wormhole in space.'),(2,'Inception','Action','PG-13',148,'A thief who enters people’s dreams.'),(3,'Interstellar','Sci-Fi','PG-13',169,'A team of explorers travel through a wormhole in space.'),(4,'Inception','Action','PG-13',148,'A thief who enters people’s dreams.'),(5,'Interstellar','Sci-Fi','PG-13',169,'A team of explorers travel through a wormhole in space.'),(6,'Inception','Action','PG-13',148,'A thief who enters people’s dreams.'),(7,'Interstellar','Sci-Fi','PG-13',169,'A team of explorers travel through a wormhole in space.'),(8,'Inception','Action','PG-13',148,'A thief who enters people’s dreams.'),(9,'Interstellar','Sci-Fi','PG-13',169,'A team of explorers travel through a wormhole in space.'),(10,'Inception','Action','PG-13',148,'A thief who enters people’s dreams.'); +/*!40000 ALTER TABLE `films` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `screens` +-- + +DROP TABLE IF EXISTS `screens`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `screens` ( + `screen_id` int NOT NULL AUTO_INCREMENT, + `cinema_id` int DEFAULT NULL, + `screen_number` int NOT NULL, + `seating_capacity` int DEFAULT NULL, + PRIMARY KEY (`screen_id`), + KEY `cinema_id` (`cinema_id`), + CONSTRAINT `screens_ibfk_1` FOREIGN KEY (`cinema_id`) REFERENCES `cinemas` (`cinema_id`) ON DELETE CASCADE, + CONSTRAINT `screens_chk_1` CHECK ((`seating_capacity` between 50 and 120)) +) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `screens` +-- + +LOCK TABLES `screens` WRITE; +/*!40000 ALTER TABLE `screens` DISABLE KEYS */; +INSERT INTO `screens` VALUES (1,1,1,100),(2,1,2,120),(3,2,1,80),(4,1,1,100),(5,1,2,120),(6,2,1,80),(7,1,1,100),(8,1,2,120),(9,2,1,80),(10,1,1,100),(11,1,2,120),(12,2,1,80),(13,1,1,100),(14,1,2,120),(15,2,1,80); +/*!40000 ALTER TABLE `screens` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `showings` +-- + +DROP TABLE IF EXISTS `showings`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `showings` ( + `showing_id` int NOT NULL AUTO_INCREMENT, + `film_id` int DEFAULT NULL, + `screen_id` int DEFAULT NULL, + `show_time` datetime NOT NULL, + `price` decimal(5,2) NOT NULL, + PRIMARY KEY (`showing_id`), + KEY `film_id` (`film_id`), + KEY `screen_id` (`screen_id`), + CONSTRAINT `showings_ibfk_1` FOREIGN KEY (`film_id`) REFERENCES `films` (`film_id`) ON DELETE CASCADE, + CONSTRAINT `showings_ibfk_2` FOREIGN KEY (`screen_id`) REFERENCES `screens` (`screen_id`) ON DELETE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `showings` +-- + +LOCK TABLES `showings` WRITE; +/*!40000 ALTER TABLE `showings` DISABLE KEYS */; +INSERT INTO `showings` VALUES (1,1,1,'2025-05-10 18:00:00',10.00),(2,2,2,'2025-05-10 21:00:00',12.00),(3,1,1,'2025-05-10 18:00:00',10.00),(4,2,2,'2025-05-10 21:00:00',12.00),(5,1,1,'2025-05-10 18:00:00',10.00),(6,2,2,'2025-05-10 21:00:00',12.00),(7,1,1,'2025-05-10 18:00:00',10.00),(8,2,2,'2025-05-10 21:00:00',12.00),(9,1,1,'2025-05-10 18:00:00',10.00),(10,2,2,'2025-05-10 21:00:00',12.00); +/*!40000 ALTER TABLE `showings` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users` +-- + +DROP TABLE IF EXISTS `users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `users` ( + `user_id` int NOT NULL AUTO_INCREMENT, + `username` varchar(50) NOT NULL, + `password_hash` varchar(255) NOT NULL, + `role` enum('Admin','Manager','Staff') NOT NULL, + PRIMARY KEY (`user_id`), + UNIQUE KEY `username` (`username`) +) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users` +-- + +LOCK TABLES `users` WRITE; +/*!40000 ALTER TABLE `users` DISABLE KEYS */; +INSERT INTO `users` VALUES (10,'admin','password','Admin'),(15,'manager','password','Manager'),(21,'staff','password','Staff'); +/*!40000 ALTER TABLE `users` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Dumping events for database 'horizon_cinema' +-- +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2025-02-19 11:08:45 diff --git a/README.md b/README.md index 6769dd6..5814983 100644 --- a/README.md +++ b/README.md @@ -1 +1,21 @@ -Hello world! \ No newline at end of file +To run the programme: python GUI.py + +SQL Database Guidance: + +1. Ensure SQL Workbench is installed +2. Create your own local connection +3. Click 'Server' - 'Data Import' +4. Select File - 'horizon_cinema +5. Click 'start import' + +You will now have the SQL database on your own system. Remember any word done to the database will need to be exported and pushed back onto gitlab with the coding. To export: + +1. Click 'server' - 'data export' +2. Select Database +3. Click 'Export to Self-Contained File (.sql)' +4. This will create a file of the database - this needs to be pushed on gitlab with any coding change + +To get database connected within coding: +1. Each person will need to update constants.py file +2. In file find row 4-7. +3. Update username & password with your own SQL workbench credentials. \ No newline at end of file diff --git a/__pycache__/main.cpython-312.pyc b/__pycache__/main.cpython-312.pyc index c0a103ab4bc10ecf94bfb2896fbe25635bfaac5d..219c7b89736cb328d9b6f143a51c28993ccb875c 100644 GIT binary patch delta 2934 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 delta 2348 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 diff --git a/main.py b/main.py index 85cca51..b9d3f43 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,11 @@ import logging logging.basicConfig(level=0, format="{asctime} - {levelname} - {message}", style="{", datefmt="%Y-%m-%d %H:%M") from src import * +from src.dbfunc import get_connection +import json +from src.staffUser import StaffUser +from src.adminUser import AdminUser +from src.managerUser import ManagerUser """_summary_ @@ -15,40 +20,38 @@ from src import * """ -def loginAttempt(username: str, password: str) -> StaffUser | ManagerUser | AdminUser | None: - """_summary_ - - queries database for matching args - returns user(staff, admin or manager) obj if found - else returns None type. - - Args: - username (str): encrypted username. - password (str): encrypted password. - - Raises: - ValueError: if db returns invalid permissionLevel. +def loginAttempt(username: str, password: str): + """Check if the user exists in the database and return the appropriate user object""" - Returns: + conn = get_connection() + if conn: + cursor = conn.cursor(dictionary=True) - StaffUser | ManagerUser | AdminUser | None: returns user object or NoneType if login unsucssesfull. - """ - # 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")) # returns a dict with args to be used in condition switch. + # Fetch user details from the database + cursor.execute("SELECT username, password_hash, role FROM users WHERE username = %s AND password_hash = %s", + (username, password)) + user_data = cursor.fetchone() + + cursor.close() + conn.close() + + if user_data: + logging.info(f"User {user_data['username']} logged in successfully.") + + # Return an instance of the correct user class + if user_data['role'] == 'Staff': + return StaffUser(username=user_data['username']) + elif user_data['role'] == 'Admin': + return AdminUser(username=user_data['username']) + elif user_data['role'] == 'Manager': + return ManagerUser(username=user_data['username']) + else: + logging.error("Unknown role in database.") + return None + else: + logging.warning("Invalid username or password.") - # 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 + return None # Return None if no user found def staffUser_options_cli(user:StaffUser) -> None: while True: @@ -167,4 +170,15 @@ def main_cli() -> None: if __name__ == "__main__": logging.debug("STARTING main_cli") main_cli() - logging.debug("main_cli finished, program exiting. bye bye!") \ No newline at end of file + logging.debug("main_cli finished, program exiting. bye bye!") + +def loginAttempt(username: str, password: str): + """Check if the user exists in the database""" + conn = get_connection() + if conn: + cursor = conn.cursor(dictionary=True) + cursor.execute("SELECT * FROM Users WHERE username = %s AND password_hash = %s", (username, password)) + user = cursor.fetchone() + conn.close() + return user # Returns user details if found + return None \ No newline at end of file diff --git a/src/__pycache__/__init__.cpython-312.pyc b/src/__pycache__/__init__.cpython-312.pyc index 3f1fc8b9e0a01db80694b92be3fcaab43153e0cf..aaa784897475dad772c7a61107c760b558fdf570 100644 GIT binary patch delta 48 zcmZ3=(!j!fnwOW0fq{YH{Pe9GxvLn(Et0KbLW@(2iepMri&FDqTvCg(OY#dQA7o4c E0ARKdJpcdz delta 85 zcmZo*S<1qFnwOW0fq{WxKCAUc?kYx`SZAx4(Bjmh;+Q;3-K50q)S?*wyi}K>%(7Gk oU4_taR|Th{%;J*#oEVqX;_Q<Af|$tE#3BWw7{_3j$#WP}04^>Y2><{9 diff --git a/src/__pycache__/adminUser.cpython-312.pyc b/src/__pycache__/adminUser.cpython-312.pyc index 59b6ca51d02eb599240a53f84bd560ae3b735992..e862f6391397e9c67c1dd92ae1fbf20e7b084608 100644 GIT binary patch delta 49 zcmcb^ww;apG%qg~0|NuY`RQ9XaxY>Ow@kK*2`x@7Dvl{hElSOcaY-%CF3B(0{F1Sl F5de&$5ikG% delta 86 zcmdnac887oG%qg~0|NuYd{*m?+>01(;+(BwLW@(2ievIDb(0daQ;TB!^HN=kGRsmG qbQMCwT@{>)GK)*{b7EXli?d7e3t}Qu6N?m#VjP2AHXmUuW&{9xO&k0G diff --git a/src/__pycache__/bookingObj.cpython-312.pyc b/src/__pycache__/bookingObj.cpython-312.pyc index 608b7ed8602e445546f3e6f5f05508f9f3851e13..4678c08d458aad37f39f436e7a08d250feb3dad2 100644 GIT binary patch delta 49 zcmcc4wuz1VG%qg~0|NuY`RQ9Xayv4LTP0h?gche36~~mM7NzFJxTF?mm*f|0?qEF6 F2mpRl5WxTd delta 86 zcmdnQcAbs;G%qg~0|NuYd{*m?+>VSk@y=E;p~b01#W8u7x=D%IsYNmVd8sZ%nPsU8 qx(cD;t_n^?nZ+gfIWaD&#n~nK1u>DSiA4%VF^<75o0A#OGXelztQ(C0 diff --git a/src/__pycache__/cinemaObj.cpython-312.pyc b/src/__pycache__/cinemaObj.cpython-312.pyc index 8ed8d33b9767d6df731b780292a6cee3a72e52dc..e889a025d413312cfd167d1a991a2a5909f13fd5 100644 GIT binary patch delta 49 zcmX>iI$xCgG%qg~0|NuY`RQ9XaxZ5Rw@kK*2`x@7Dvl{hElSOcaY-%CF3B(0{Eq1w FI{=En5t9G_ delta 86 zcmbO)dPJ1_G%qg~0|NuY{{)wf+{>A4;+(BwLW@(2ievIDb(0daQ;TB!^HN=kGRsmG qbQMCwT@{>)GK)*{b7EXli?d7e3t}Qu6N?m#VjP2AHlJj=#ts0lCLJRH diff --git a/src/__pycache__/constants.cpython-312.pyc b/src/__pycache__/constants.cpython-312.pyc index 7ee442bfdb3ba45e22195732f7d80ad565f07e9a..d3bc49915e4b08b2493f7d0b87854b992d1d9ce7 100644 GIT binary patch delta 319 zcmcc3a+8JkG%qg~0|Ns?*@ms@(<bt2)iXsgr7%Y^r?5n^q_U>6rLfvCFfed3q_9P? zgZb=GK1UQsDrYKN3MZ7$6~zVSb3^$&QQTlYFO<&}#RKN^f%ujDngX}@Jo1Y&tMc>W zoip=Na}#f|6y@iah~DBTNGvWc&o4@;;xsfe*E7&F&@-I4vNMvEfq~%`Yg$fzV#zK3 z`1r)Uy!?{HlFa<P;`sO?HU<WUB6g4p=FGg3B2Ew&<gX%b1_p+e44*+>{AKBE6%$&V zT2vfUl3J9S7vqvzoL!P%FnI%`o~9TB0|O%i14D5R0|UbcW=2NF4;&1PQWrQS8`y5} W3O8`w;1vfE5|i1O0$D^D7#IMhI!(s_ delta 334 zcmcb~a+`(sG%qg~0|NuYJ%P>X6%%>2>KUV$QW&F{Q<$PyQdv{kQkZQR7#KJiQdpwc z!F*OIpDl_bl{1wsg&oT0h~fhCIiY;6C~h#H8_MU1;sNt{K>SKxO}<;Ki6C%`Asu8t z14E?4Ee>DDi8pHMSr`}?Zn382<R_Ng;*XC{%*)F!Ni50C&nu3PFJfh2U?^e(sbJ2` zD=FdtaXCQ*$QvseK7$PV73XXf6Iz^FR2-9MshgCTomv#*pO@-Vlv$RlpsNrX?yBHa zlv!MopA+MfTAW>yUl0?SnpmV@6yq4|5;J)nqppT10|Nsi0|P^GHUk602WCb_#t$3} ajDj8F4Qw}f`5U-k#AFtxKo(&J1_l5!$xrD3 diff --git a/src/__pycache__/dbfunc.cpython-312.pyc b/src/__pycache__/dbfunc.cpython-312.pyc index eb843504dc7790e9bd0f122a324b2154a3d89437..55dfe2f82b5871a26d95ff2418ec5379258e663c 100644 GIT binary patch literal 8557 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 QL~t<jeHP(m6aw1}0RGlfwg3PC literal 7724 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 YiC{2wAvE$cNb++MqY|S+5vcYC0B`wJOaK4? diff --git a/src/__pycache__/managerUser.cpython-312.pyc b/src/__pycache__/managerUser.cpython-312.pyc index ea3ceee10e626fb3e288ed6bfe4a169886048fc3..066114c00fe160c03d83e6e6c335ee8c4347c0b7 100644 GIT binary patch delta 49 zcmZqYc*M?qnwOW0fq{YH{Pe9Gxfe2uTPIt^gche36~~mM7NzFJxTF?mm*f|0e!(cu F1OS9S5VimS delta 86 zcmaFF-p;{&nwOW0fq{XcGsJ!)_d-US1ZS(5(Bjmh;+Q;3-K50q)S?*wyi}K>%(7Gk pU4_taR|Th{%;J*#oEVqX;_Q<Af|$tE#3BWw7{_3j&4(G~nE-!x8@~Vm diff --git a/src/__pycache__/reportObj.cpython-312.pyc b/src/__pycache__/reportObj.cpython-312.pyc index 642554601c431f1833b8aa56b9135901b1a274e8..84e9396990ad1e391f3e1c38a0873b3ca6ac71b5 100644 GIT binary patch delta 49 zcmaFFx|fyvG%qg~0|NuY`RQ9Xa$7NqTP9n@gche36~~mM7NzFJxTF?mm*f|0Ze&bk F1OR|25Lf^J delta 86 zcmdnX`iPbLG%qg~0|NuYGwID6xvdy&;+(BwLW@(2ievIDb(0daQ;TB!^HN=kGRsmG qbQMCwT@{>)GK)*{b7EXli?d7e3t}Qu6N?m#VjP2AHpeg~G6Ddc^c(pA diff --git a/src/__pycache__/screenObj.cpython-312.pyc b/src/__pycache__/screenObj.cpython-312.pyc index 818715ed3fa550818788af402c31924b8c63a4cd..404eaa518842cffc596ae0349cfae21c58093a3f 100644 GIT binary patch delta 49 zcmew(eO;RSG%qg~0|NuY`RQ9Xa_?mlw@kK*2`x@7Dvl{hElSOcaY-%CF3B(0%)<PG F3jm=&5n%uT delta 86 zcmcaE{YRSnG%qg~0|NuYd{*m?+<Td9;+(BwLW@(2ievIDb(0daQ;TB!^HN=kGRsmG qbQMCwT@{>)GK)*{b7EXli?d7e3t}Qu6N?m#VjP2AHs5FZ!36-PMjb2w diff --git a/src/__pycache__/staffUser.cpython-312.pyc b/src/__pycache__/staffUser.cpython-312.pyc index 4988db65302ceac12f65b8e5218373debd4dc439..1aee61bed589a71284cd861e87f81a6ed12f6fe9 100644 GIT binary patch delta 883 zcmdm`bzO`1G%qg~0|NuY`RQBJqc`$SWvpjmU|?WoU|{&1#lXNYouP)Uh_8eZqy&Uh z7*m+mFt26;u^AW`87diS7;6~f;qo<1H4O1kSq6q0<{E~0kXc~mH7qp@@gUP7Jk}b9 zcvdizfq|itL6gPr7Dq`^j!9^7YEkhm22G}0tR;y_IjOfelk@XZGD|Y^^EBCRi592k zq$ZcdrxoSr#+M}J#FuBJ7Nt&RVM-OZOty*vYmO;NElSOcaY-%CF3B&Lyp+jJ%z}Y| zp@HEcx6l(F#T8sTlCJVN-ry0~{FBL<QAw16fuTqYM2Le32?hp+m5fD_3=9m#Ab%+o zNllJpnaL=#`3K7xM%E$$1_p-7=h(bhi$p*yeRf?oklG@#$w};Lf;u2=Yzzzx3Sdwq zHF+lc8Ah4OjRKOJ>p4srg+bc=G}()^L3XKu2=&RwIklufX53;gPR&Vk$t=3Xm|6@9 zHw6WSBB{;XTr(NfAW9h+7;dp-=B4Eqfn9A5(ys`z66VrV+|dx*CfoBoVS{LztjVj$ zC^^}iSB_C?au#n3qs-*@ymi_TNsx)ce)%Pyxdl0?xv6<2sVS~SMfpWVD8|m<^9Acl zob1joCFq1<Z4tjWSUz*Ix_~eid2ay&Hdl}?nazy?rx{@m3lh>6asdfjF)%P_GJ^xX zNM~}tkT{zZ$YElW&k2c5J|r|(Tn40ou?Up3G?|K&85kJ+GzE(kCYK4z1^9!MG8dN= z-D1hfEH1gll9ZpHQzQ*CR|!NIfCz9<fvhQV0CB;#x`SArAR-79=?q06TZ*J6KM`(| z0WCUeBc=O$+6#m8&%6oJD`V{)5_rM3b{j<vKnwaBo@4`fCJhyZH?x&0T1O>TZl RX-=wLQT*grB0el2832(l!;k;~ delta 841 zcmcbvwM&clG%qg~0|Nttul?q9wT-+}8Izb87#Nrt7#KbWFfcGoXQ*K-VytASVXR?@ z2dM+&8m1bCct$Xjfq|ihxrQMgqzf!i!&1W#57H0evDPrevw)cl3=EYFnv8y$tdm2T zQf=a#tztrpQ;UjY@+@_e60=i_V*K+`U5YZxQWbO+Lc?7ZoQg7wOY(DKTvCg(OY#e1 zB2yEK6pUgVgIy+HWOCy(U|?WqV0g$a^ns0mS8%f~vooWT00RR<ksyc=0ujOt3=At7 zi$oY07>Ys8RVWgjJc(r{qxfbW)-#M;w>V0Ya=>nw{FlvZvK^DeWM6h2Hjwfn!O8XP zYJ!>|oooyY3<_XSBszH;`x!>@$@2sxH_zcPWfWFmU|{gmWG~VHS*HXdlqWyo)M6Bw z%+DpkD7smLYbK)_M4W+v;TB6~URr(;*p((A#WEoCVJ>^l9St#hatzNCHi)LlZoG<& zB9k+C<rqaLxAV3zicjX@tAj~S;FA<VHUeY?Z*o!U<N^V)$(Q-`!KxD{r|?S&+GAMP z&+iSE&z$TcAdE#mL%@K|38YJW^E`pmj4(U%g|xLCLBi$?3=Epg;J_`?1li14oSKuG zT#}ieR}6}O1qD!W9}(J7FAh@4SOiKUnoLD<;2;w$k_PGFijU9DPbtkwjgP;@6CYn# znwXQ9n420OU*rRlW-cx%y2X-{SzL09B`H5Yr$`KBvn+_v1rgvt1UaP07Q_X+%LT-8 z0}=k9=w~Qm1KD3BI+;<VO$N;502$2@AD^3;nHL|g$x{RlYt_k%MJ%<!u3{}MPAxJl g@&*|a3L?PTL>U+uesS19+-p}9Gnrk~hXo`90AHrFmH+?% diff --git a/src/constants.py b/src/constants.py index 348dab2..d548e2d 100644 --- a/src/constants.py +++ b/src/constants.py @@ -1,10 +1,10 @@ # 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 = "" +DBNAME = "Horizon_Cinema" +DBUSERNAME = "root" +DBPASSWORD = "password" +DBHOSTNAME = "127.0.0.1" # screenObj: MAX_SIZE:float = 100.0 diff --git a/src/dbfunc.py b/src/dbfunc.py index 72465bd..d388d5a 100644 --- a/src/dbfunc.py +++ b/src/dbfunc.py @@ -1,155 +1,159 @@ -import logging, json, mysql.connector -from .constants import DBNAME, DBHOSTNAME, DBUSERNAME, DBPASSWORD +import logging +import json +import mysql.connector from mysql.connector import errorcode +from src.constants import DBNAME, DBHOSTNAME, DBUSERNAME, DBPASSWORD +# Configure logging for debugging +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') +def get_connection(): + """Creates and returns a database connection.""" + try: + conn = mysql.connector.connect( + host=DBHOSTNAME, + user=DBUSERNAME, + password=DBPASSWORD, + database=DBNAME + ) + logging.info("Connected to the database successfully.") + return conn + except mysql.connector.Error as err: + if err.errno == errorcode.ER_ACCESS_DENIED_ERROR: + logging.error("Invalid database credentials.") + elif err.errno == errorcode.ER_BAD_DB_ERROR: + logging.error("Database does not exist.") + else: + logging.error(f"Database connection error: {err}") + return None +# Function to SELECT data from any table +def select_from_table(table, *columns): + """Fetches data from a given table.""" + conn = get_connection() + if not conn: + return [] + try: + cursor = conn.cursor(dictionary=True) + query = f"SELECT {', '.join(columns) if columns else '*'} FROM {table}" + cursor.execute(query) + results = cursor.fetchall() + return results + except mysql.connector.Error as err: + logging.error(f"Error fetching data: {err}") + return [] + finally: + cursor.close() + conn.close() +# Function to SELECT data with a WHERE condition +def select_from_table_where(table, condition, *columns): + """Fetches data from a table with a WHERE condition.""" + conn = get_connection() + if not conn: + return [] -def getConnection(db=""): - # if specified database - if db != "": - try: - 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: - logging.error("Username or Password is not working") - elif err.errno == errorcode.ER_BAD_DB_ERROR: - logging.error("Database dose not exist") - else: - logging.error(err) - else: - logging.info("Connected to server.") - return conn - # if database not specified try default from line 5 - else: - try: - 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") - else: - logging.error(err) - else: - logging.error("Connected to server, without database.") - return conn - -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) - if conn != None: - if conn.is_connected(): - SELECT_statement = f"SELECT " - for arg in args: - 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) - logging.info("SELECT statement executed successfully.") - data = dbcursor.fetchall() - logging.debug(f"dataOut: {data}") - dbcursor.close() - conn.close() - data = json.dumps(data) - return data - else: - logging.error("conn not connected") - raise ConnectionError() - else: - logging.error("conn returned NoneType") - raise ConnectionAbortedError() - -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. + try: + cursor = conn.cursor(dictionary=True) + query = f"SELECT {', '.join(columns) if columns else '*'} FROM {table} WHERE {condition}" + cursor.execute(query) + results = cursor.fetchall() + return results + except mysql.connector.Error as err: + logging.error(f"Error fetching data with condition: {err}") + return [] + finally: + cursor.close() + conn.close() - Raises: - ConnectionAbortedError: if the connection variables are invalid. - ConnectionError: if the database could not be connected to. +# Function to INSERT data into any table +def insert_into_table(table, data): + """Inserts data into a specified table.""" + conn = get_connection() + if not conn: + return False - 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.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"WHERE {condition};") - - dbcursor = conn.cursor() - dbcursor.execute(f"USE {dbname}") - dbcursor.execute(SELECT_statement) - logging.info("SELECT statement executed successfully.") - data = dbcursor.fetchall() - logging.debug(f"dataOut: {data}") - dbcursor.close() + try: + cursor = conn.cursor() + columns = ', '.join(data.keys()) + values = ', '.join(['%s'] * len(data)) + query = f"INSERT INTO {table} ({columns}) VALUES ({values})" + cursor.execute(query, tuple(data.values())) + conn.commit() + logging.info("Data inserted successfully.") + return True + except mysql.connector.Error as err: + logging.error(f"Error inserting data: {err}") + return False + finally: + cursor.close() conn.close() - data = json.dumps(data) - return data - else: - logging.error("conn not connected") - raise ConnectionError() - - -def save_to_Tbl(table, data): - """need to fix""" - logging.debug(f"running update statment with values: tablename='{table}', data='{data}'") - if type(data) is json: - data = json.loads(data) - elif type(data) is dict: - pass - else: - raise TypeError() - - conn = getConnection(db=DBNAME) - if conn == None: - logging.error("conn returned NoneType") - raise ConnectionAbortedError() - if conn.is_connected(): - logging.debug("MySQL Connection is established.") - INSERT_statement = f"INSERT INTO {table} (" - - keys = "" - values = "" - for key, value in data.items(): - keys.append(f"{key}, ") - values.append(f"{value}, ") - INSERT_statement.append(f"{keys.removesuffix(", ")}) VALUES ({values.removesuffix(", ")});") - - dbcursor = conn.cursor() - dbcursor.execute(INSERT_statement) + +# Function to DELETE data +def delete_from_table(table, condition): + """Deletes data from a specified table based on a condition.""" + conn = get_connection() + if not conn: + return False + + try: + cursor = conn.cursor() + query = f"DELETE FROM {table} WHERE {condition}" + cursor.execute(query) + conn.commit() + logging.info("Data deleted successfully.") + return True + except mysql.connector.Error as err: + logging.error(f"Error deleting data: {err}") + return False + finally: + cursor.close() + conn.close() + +# Function to UPDATE data +def update_table(table, data, condition): + """Updates data in a specified table based on a condition.""" + conn = get_connection() + if not conn: + return False + + try: + cursor = conn.cursor() + set_clause = ', '.join([f"{key} = %s" for key in data.keys()]) + query = f"UPDATE {table} SET {set_clause} WHERE {condition}" + cursor.execute(query, tuple(data.values())) conn.commit() - dbcursor.close() - + logging.info("Data updated successfully.") + return True + except mysql.connector.Error as err: + logging.error(f"Error updating data: {err}") + return False + finally: + cursor.close() + conn.close() + +def fetch_users(): + conn = get_connection() + if conn: + cursor = conn.cursor(dictionary=True) + cursor.execute("SELECT * FROM Users") + users = cursor.fetchall() + conn.close() + return users + return [] + +def fetch_movies(): + """ + Fetch all movies from the database. + """ + conn = get_connection() + if conn: + cursor = conn.cursor(dictionary=True) + cursor.execute("SELECT * FROM Movies") # Change 'Movies' to your actual table name + movies = cursor.fetchall() + cursor.close() conn.close() - logging.debug("INSERT query executed with no issues.") + return movies else: - logging.error("conn not connected") - raise ConnectionError() - + return [] -- GitLab