From 10042e1b55389a3429103319893a06d834a9aefd Mon Sep 17 00:00:00 2001 From: Tyler Lightwood Date: Mon, 29 Jan 2024 21:58:10 +0000 Subject: [PATCH] Major Features - Added user management features to update usernames and levels, change passwords and delete users - Added functionality to the animal profile and created a window that displays the information and allows the user to display an image of the animal - Removed certain options for specific levelled users and adjusted the logout to display the correct number based on how many options are displayed. - Added gender to the inputs for adding animals and displayed on the table - Added storage of the animals name outside of the label so the profile can display the name as well as some upcoming features that requires this distinction --- FurEver_Friends.py | 120 ++++++++++++++++++----------------- add_animal.py | 8 ++- admin_dashboard.py | 10 ++- user_management.py | 108 ++++++++++++++++++++++++++++++++ view_animal_profile.py | 138 +++++++++++++++++++++++++++++++++++++++++ view_animals.py | 23 ++++--- 6 files changed, 335 insertions(+), 72 deletions(-) create mode 100644 user_management.py create mode 100644 view_animal_profile.py diff --git a/FurEver_Friends.py b/FurEver_Friends.py index 397f0c6..917c8d8 100644 --- a/FurEver_Friends.py +++ b/FurEver_Friends.py @@ -93,62 +93,70 @@ def main(): if not os.path.exists(ANIMAL_DATA_FILE): with open(ANIMAL_DATA_FILE, 'w') as animal_file: json.dump(DEFAULT_ANIMAL_DATA, animal_file, indent=4) - - while True: - print(Fore.CYAN + "\nšŸ• Welcome to FurEver Friends Management System! šŸˆ" + Style.RESET_ALL) - print("\n1. " + Fore.GREEN + "Login" + Style.RESET_ALL) - print("2. " + Fore.YELLOW + "Exit" + Style.RESET_ALL) - choice = input("\nPlease select an option: ") - - if choice == '1': - clear_screen() - username, user_level = login() - if username is not None: - while True: - clear_screen() - print(Fore.CYAN + "\nšŸ“– Main Menu šŸ“–" + Style.RESET_ALL) - print("\n1. " + Fore.GREEN + "šŸ”Ž View all animals" + Style.RESET_ALL) - - # Initialize option counter - option_counter = 2 - - # Adjust options based on user level - if user_level >= 2: - print(f"{option_counter}. " + Fore.GREEN + "šŸ¶ Add a new animal" + Style.RESET_ALL) - option_counter += 1 - if user_level >= 3: - print(f"{option_counter}. " + Fore.GREEN + "šŸ” Change animal adoption status" + Style.RESET_ALL) - option_counter += 1 - - # Display Logout option with the correct number - print (f"{option_counter}. " + Fore.YELLOW + "šŸ” Logout" + Style.RESET_ALL) - option = input("\nPlease select an option: ") - - if option == '1': - view_animals() - elif option == '2' and user_level >= 2: - add_animal() - elif option == '3' and user_level >= 3: - change_adopted_status() - elif option == str(option_counter) and user_level >= 1: - print("\nLogging out...") - time.sleep(2) - clear_screen() - break - else: - print(Fore.RED + "\nInvalid option. Please try again.") - time.sleep(2) + try: + while True: + print(Fore.CYAN + "\nšŸ• Welcome to FurEver Friends Management System! šŸˆ" + Style.RESET_ALL) + print("\n1. " + Fore.GREEN + "Login" + Style.RESET_ALL) + print("2. " + Fore.YELLOW + "Exit" + Style.RESET_ALL) + choice = input("\nPlease select an option: ") + + if choice == '1': + clear_screen() + username, user_level = login() + if username is not None: + while True: clear_screen() - - elif choice == '2': - print("\nExiting...") - time.sleep(2) - exit() - else: - print(Fore.RED + "\nInvalid option. Please try again." + Style.RESET_ALL) - time.sleep(2) - clear_screen() + print(Fore.CYAN + "\nšŸ“– Main Menu šŸ“–" + Style.RESET_ALL) + print("\n1. " + Fore.GREEN + "šŸ”Ž View all animals" + Style.RESET_ALL) + + # Initialize option counter + option_counter = 2 + + # Adjust options based on user level + if user_level >= 2: + print(f"{option_counter}. " + Fore.GREEN + "šŸ¶ Add a new animal" + Style.RESET_ALL) + option_counter += 1 + if user_level >= 3: + print(f"{option_counter}. " + Fore.GREEN + "šŸ” Change animal adoption status" + Style.RESET_ALL) + option_counter += 1 + if user_level >= 3: + print(f"{option_counter}. " + Fore.GREEN + "šŸ—’ļø Edit animal entries" + Style.RESET_ALL) + option_counter += 1 + + # Display Logout option with the correct number + print (f"{option_counter}. " + Fore.YELLOW + "šŸ” Logout" + Style.RESET_ALL) + option = input("\nPlease select an option: ") + + if option == '1': + view_animals() + elif option == '2' and user_level >= 2: + add_animal() + elif option == '3' and user_level >= 3: + change_adopted_status() + elif option == '4' and user_level >= 3: + print("\nFeature coming soon") + time.sleep(2) + elif option == str(option_counter) and user_level >= 1: + print("\nLogging out...") + time.sleep(2) + clear_screen() + break + else: + print(Fore.RED + "\nInvalid option. Please try again.") + time.sleep(2) + clear_screen() + + elif choice == '2': + print("\nExiting...") + time.sleep(2) + exit() + else: + print(Fore.RED + "\nInvalid option. Please try again." + Style.RESET_ALL) + time.sleep(2) + clear_screen() + except KeyboardInterrupt: + print("\nExiting...") + time.sleep(2) if __name__ == "__main__": - main() - + main() \ No newline at end of file diff --git a/add_animal.py b/add_animal.py index 66d4175..2a0cab7 100644 --- a/add_animal.py +++ b/add_animal.py @@ -28,6 +28,12 @@ def add_animal(): input(Fore.GREEN + "Press Enter to continue..."+ Style.RESET_ALL) continue + gender = input("Enter the animal's gender: ") + if not gender.strip(): # Check if the breed is empty + print(Fore.RED + "Invalid input. Please enter the animal's name." + Style.RESET_ALL) + input(Fore.GREEN + "Press Enter to continue..."+ Style.RESET_ALL) + continue + age = input("Enter the animal's age: ") if not age.strip(): # Check if the age is empty print(Fore.RED + "Invalid input. Please enter the animal's name." + Style.RESET_ALL) @@ -46,7 +52,7 @@ def add_animal(): input(Fore.GREEN + "Press Enter to continue..."+ Style.RESET_ALL) continue - animals[name] = {'species': species, 'breed': breed, 'age': age, 'adopted': False} + animals[name] = {'name': name, 'species': species, 'breed': breed, 'gender': gender, 'age': age, 'adopted': False} save_data(animals, ANIMAL_DATA_FILE) print(Fore.GREEN + "\nAnimal added successfully!" + Style.RESET_ALL) time.sleep(2) diff --git a/admin_dashboard.py b/admin_dashboard.py index 648848b..fc86da0 100644 --- a/admin_dashboard.py +++ b/admin_dashboard.py @@ -2,6 +2,7 @@ from colorama import Fore, Style from common_functions import clear_screen, load_data, save_data from register import register +from user_management import user_management USER_DATA_FILE = "users.json" @@ -10,17 +11,20 @@ def admin_dashboard(): clear_screen() print(Fore.YELLOW + "\nADMIN Dashboard\n" + Style.RESET_ALL) print("1. Register a new user") - print("2. Manage settings") - print("3. Logout") + print("2. User Management") + print("3. Manage settings") + print("4. Logout") option = input("\nPlease select an option: ") if option == '1': register() elif option == '2': + user_management() + elif option == '3': # Implement settings management print("\nThis feature is under development.") time.sleep(2) - elif option == '3': + elif option == '4': print("\nLogging out...") exit() else: diff --git a/user_management.py b/user_management.py new file mode 100644 index 0000000..3657ccd --- /dev/null +++ b/user_management.py @@ -0,0 +1,108 @@ +import time +from colorama import Fore, Style +from common_functions import clear_screen, load_data, save_data + +USER_DATA_FILE = "users.json" + +def user_management(): + while True: + clear_screen() + print(Fore.YELLOW + "\nUser Management\n" + Style.RESET_ALL) + print("1. Change user password") + print("2. Update user information") + print("3. Delete user") + print("4. Back to admin dashboard") + option = input("\nPlease select an option: ") + + if option == '1': + change_user_password() + elif option == '2': + update_user_information() + elif option == '3': + delete_user() + elif option == '4': + print("\nReturning to admin dashboard...") + time.sleep(2) + return + else: + print(Fore.RED + "\nInvalid option. Please try again." + Style.RESET_ALL) + time.sleep(2) + +def change_user_password(): + users = load_data(USER_DATA_FILE) + username = input("\nEnter the username to change the password: ") + + if username in users and username != "ADMIN": + new_password = input("Enter the new password: ") + users[username]['password'] = new_password + save_data(users, USER_DATA_FILE) + print(Fore.GREEN + f"\nPassword for user '{username}' changed successfully!" + Style.RESET_ALL) + elif username == "ADMIN": + print(Fore.RED + "\nYou cannot change the password for the ADMIN user." + Style.RESET_ALL) + else: + print(Fore.RED + f"\nUser '{username}' not found." + Style.RESET_ALL) + + time.sleep(2) + +def update_user_information(): + users = load_data(USER_DATA_FILE) + clear_screen() + username = input("\nEnter the username to update information: ") + + if username in users and username != "ADMIN": + clear_screen() + print("\nCurrent user information:") + print(f"\nUsername: {username}") + print(f"User Level: {users[username]['level']}") + + print("\nSelect the information you want to update:") + print("\n1. Username") + print("2. User Level") + print("3. Cancel") + + option = input("\nEnter your choice: ") + + if option == '1': + new_username = input("Enter the new username: ") + if new_username not in users: + users[new_username] = users.pop(username) + print(Fore.GREEN + f"\nUsername updated successfully to '{new_username}'!" + Style.RESET_ALL) + else: + print(Fore.RED + f"\nUsername '{new_username}' already exists. Please choose a different username." + Style.RESET_ALL) + elif option == '2': + new_level = int(input("Enter the new user level: ")) + users[username]['level'] = new_level + print(Fore.GREEN + f"\nUser level updated successfully for '{username}'!" + Style.RESET_ALL) + elif option == '3': + print("\nOperation canceled.") + else: + print(Fore.RED + "\nInvalid option. Please try again." + Style.RESET_ALL) + elif username == "ADMIN": + print(Fore.RED + "\nYou cannot update information for the ADMIN user." + Style.RESET_ALL) + else: + print(Fore.RED + f"\nUser '{username}' not found." + Style.RESET_ALL) + + save_data(users, USER_DATA_FILE) + time.sleep(2) + +def delete_user(): + users = load_data(USER_DATA_FILE) + username = input("\nEnter the username to delete: ") + confirm_delete = input("Are you sure you want to delete this user? (y/n) ") + + if username == "ADMIN": + print("\nThe ADMIN user cannot be modified.") + time.sleep(2) + clear_screen() + else: + if username in users and confirm_delete.lower() == 'y': + del users[username] + save_data(users, USER_DATA_FILE) + print(Fore.GREEN + f"\nUser '{username}' deleted successfully!" + Style.RESET_ALL) + elif username in users and confirm_delete.lower() == 'n': + print(Fore.RED + "User has not been deleted!" + Style.RESET_ALL) + else: + print(Fore.RED + f"\nUser '{username}' not found." + Style.RESET_ALL) + + time.sleep(2) + diff --git a/view_animal_profile.py b/view_animal_profile.py new file mode 100644 index 0000000..d046e0b --- /dev/null +++ b/view_animal_profile.py @@ -0,0 +1,138 @@ +import tkinter as tk +from PIL import Image, ImageTk +from tkinter import filedialog +from colorama import Fore, Style +from tkinter import messagebox +from common_functions import clear_screen, load_data, save_data + + +ANIMAL_DATA_FILE = "animals.json" + +def print_animal_table_with_index(animals): + """Prints the table of animals with index numbers.""" + print("\nšŸ¾ " + Fore.CYAN + "List of Animals" + Style.RESET_ALL + " šŸ¾") + print("--------------------------------------------------------------------------------------------------") + print("| " + Fore.YELLOW + "Index".ljust(6) + Style.RESET_ALL + "| " + Fore.YELLOW + "Name".ljust(20) + Style.RESET_ALL + "| " + Fore.YELLOW + "Species".ljust(8) + Style.RESET_ALL + "| " + Fore.YELLOW + "Breed".ljust(25) + Style.RESET_ALL + "| " + Fore.YELLOW + "Gender".ljust(15) + Style.RESET_ALL + Fore.YELLOW + "Age".ljust(1) + Style.RESET_ALL + " | " + Fore.YELLOW + "Adopted".ljust(7) + Style.RESET_ALL + " |") + print("--------------------------------------------------------------------------------------------------") + + for i, (name, data) in enumerate(animals.items(), 1): + index_column = f"| {str(i).ljust(6)}" + name_column = f"| {name.ljust(20)}" + species_column = f"| {data['species'].ljust(8)}" + breed_column = f"| {data['breed'].ljust(25)}" + gender_column = f"| {data['gender'].ljust(15)}" + age_column = f"| {str(data['age']).ljust(3)}" + adopted_column = f"| {str(data['adopted']).ljust(7)}|" + print(index_column + name_column + species_column + breed_column + gender_column + age_column + adopted_column) + + print("--------------------------------------------------------------------------------------------------") + +def select_animal_to_view(animals): + """Allows the user to select an animal from the table to view its profile.""" + clear_screen() + print_animal_table_with_index(animals) + selected_index = input("\nEnter the index of the animal to view its profile: ") + + try: + selected_index = int(selected_index) + if 1 <= selected_index <= len(animals): + selected_animal = list(animals.keys())[selected_index - 1] + view_animal_profile(animals[selected_animal]) + else: + print(Fore.RED + "Invalid index!" + Style.RESET_ALL) + except ValueError: + print(Fore.RED + "Invalid input! Please enter a valid index." + Style.RESET_ALL) + +def view_animal_profile(): + """Displays the profile of the selected animal in a Tkinter window.""" + clear_screen() + animals = load_data(ANIMAL_DATA_FILE) + + print_animal_table_with_index(animals) + selected_index = input("\nEnter the index of the animal to view its profile: ") + + try: + selected_index = int(selected_index) + if 1 <= selected_index <= len(animals): + selected_animal = list(animals.keys())[selected_index - 1] + animal = animals[selected_animal] + + # Create a new Tkinter window + root = tk.Tk() + root.title(f"Animal Profile - {animal['name']}") + root.geometry("800x700") + + def on_closing(): + root.destroy() + + root.protocol("WM_DELETE_WINDOW", on_closing) + + if 'image' in animal: + image = Image.open(animal['image']) + image = image.resize((350, 350)) + photo = ImageTk.PhotoImage(image) + image_label = tk.Label(root, image=photo) + image_label.image = photo + image_label.pack(pady=10) + + # Create a frame to hold the labels and upload button + frame = tk.Frame(root) + frame.pack(pady=10) + + # Display the animal details + tk.Label(frame, text="Name:", font=("Helvetica", 12, "bold")).grid(row=0, column=0, sticky="w") + tk.Label(frame, text=animal['name'], font=("Helvetica", 12)).grid(row=0, column=1, sticky="w") + + tk.Label(frame, text="Species:", font=("Helvetica", 12, "bold")).grid(row=1, column=0, sticky="w") + tk.Label(frame, text=animal['species'], font=("Helvetica", 12)).grid(row=1, column=1, sticky="w") + + tk.Label(frame, text="Breed:", font=("Helvetica", 12, "bold")).grid(row=2, column=0, sticky="w") + tk.Label(frame, text=animal['breed'], font=("Helvetica", 12)).grid(row=2, column=1, sticky="w") + + tk.Label(frame, text="Gender:", font=("Helvetica", 12, "bold")).grid(row=3, column=0, sticky="w") + tk.Label(frame, text=animal['gender'], font=("Helvetica", 12)).grid(row=3, column=1, sticky="w") + + tk.Label(frame, text="Age:", font=("Helvetica", 12, "bold")).grid(row=4, column=0, sticky="w") + tk.Label(frame, text=str(animal['age']), font=("Helvetica", 12)).grid(row=4, column=1, sticky="w") + + tk.Label(frame, text="Adopted:", font=("Helvetica", 12, "bold")).grid(row=5, column=0, sticky="w") + tk.Label(frame, text=str(animal['adopted']), font=("Helvetica", 12)).grid(row=5, column=1, sticky="w") + + # Upload button + def upload_image(): + file_path = filedialog.askopenfilename() + if file_path: + animal['image'] = file_path + save_data(animals, ANIMAL_DATA_FILE) + + upload_button = tk.Button(root, text="Upload Image", command=upload_image, width=15, height=2) + upload_button.pack(pady=10) + + # Close button + close_button = tk.Button(root, text="Close", command=root.destroy, width=10, height=2, bg="red", fg="white") + close_button.pack(pady=20) + + root.mainloop() + else: + print(Fore.RED + "Invalid index!" + Style.RESET_ALL) + except ValueError: + print(Fore.RED + "Invalid input! Please enter a valid index." + Style.RESET_ALL) + +def view_animals(): + """Main function to view animals.""" + clear_screen() + + while True: + print(Fore.CYAN + "\nāš™ļø Options āš™ļø" + Style.RESET_ALL) + print("\n1. " + Fore.GREEN + "Select an animal to view profile" + Style.RESET_ALL) + print("2. " + Fore.YELLOW + "Exit" + Style.RESET_ALL) + + user_input = input("\nPlease select an option: ") + + if user_input == '1': + view_animal_profile() + elif user_input == '2': + clear_screen() + return + else: + print("\nInvalid input. Please choose one of the options.") \ No newline at end of file diff --git a/view_animals.py b/view_animals.py index 641b173..c8a0671 100644 --- a/view_animals.py +++ b/view_animals.py @@ -1,25 +1,27 @@ import time from colorama import Fore, Style from common_functions import clear_screen, load_data +from view_animal_profile import view_animal_profile ANIMAL_DATA_FILE = "animals.json" def print_animal_table(animals): """Prints the table of animals.""" print("\nšŸ¾ " + Fore.CYAN + "List of Animals" + Style.RESET_ALL + " šŸ¾") - print("--------------------------------------------------------------------------------------------") - print("| " + Fore.YELLOW + "Name".ljust(20) + Style.RESET_ALL + "| " + Fore.YELLOW + "Species".ljust(20) + Style.RESET_ALL + "| " + Fore.YELLOW + "Breed".ljust(25) + Style.RESET_ALL + "| " + Fore.YELLOW + "Age".ljust(5) + Style.RESET_ALL + " | " + Fore.YELLOW + "Adopted".ljust(9) + Style.RESET_ALL + " |") - print("--------------------------------------------------------------------------------------------") + print("---------------------------------------------------------------------------------------------") + print("| " + Fore.YELLOW + "Name".ljust(20) + Style.RESET_ALL + "| " + Fore.YELLOW + "Species".ljust(8) + Style.RESET_ALL + "| " + Fore.YELLOW + "Breed".ljust(25) + Style.RESET_ALL + "| " + Fore.YELLOW + "Gender".ljust(15) + Style.RESET_ALL + "| " + Fore.YELLOW + "Age".ljust(1) + Style.RESET_ALL + " | " + Fore.YELLOW + "Adopted".ljust(7) + Style.RESET_ALL + " |") + print("---------------------------------------------------------------------------------------------") for name, data in animals.items(): name_column = f"| {name.ljust(20)}" - species_column = f"| {data['species'].ljust(20)}" + species_column = f"| {data['species'].ljust(8)}" breed_column = f"| {data['breed'].ljust(25)}" - age_column = f"| {str(data['age']).ljust(6)}" - adopted_column = f"| {str(data['adopted']).ljust(10)}|" - print(name_column + species_column + breed_column + age_column + adopted_column) + gender_column = f"| {data['gender'].ljust(15)}" + age_column = f"| {str(data['age']).ljust(3)}" + adopted_column = f"| {str(data['adopted']).ljust(7)} |" + print(name_column + species_column + breed_column + gender_column + age_column + adopted_column) - print("--------------------------------------------------------------------------------------------") + print("---------------------------------------------------------------------------------------------") def filter_animals(animals): """Filters animals based on species, breed and adoption status.""" @@ -136,10 +138,7 @@ def view_animals(): elif user_input == '3': filter_animals(animals) elif user_input == '4': - print("\nThis feature is coming soon!") - time.sleep(2) - clear_screen() - print_animal_table(animals) + view_animal_profile() elif user_input == '5': clear_screen() return