diff --git a/.gitignore b/.gitignore index d440725..e2ef110 100644 --- a/.gitignore +++ b/.gitignore @@ -159,6 +159,6 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ -# Json Files -animals.json -users.json \ No newline at end of file +# User Files +*.json +*.txt diff --git a/FurEver_Friends.py b/FurEver_Friends.py index 917c8d8..36437ce 100644 --- a/FurEver_Friends.py +++ b/FurEver_Friends.py @@ -1,13 +1,12 @@ import os import json import time -import getpass from colorama import Fore, Style from view_animals import view_animals from add_animal import add_animal from change_adopted_status import change_adopted_status -from common_functions import clear_screen, save_data -from admin_dashboard import admin_dashboard +from common_functions import clear_screen, log_action +from login import login # File paths for user and animal data USER_DATA_FILE = "users.json" @@ -17,70 +16,12 @@ DEFAULT_USER_DATA = { "ADMIN": { "password": "ADMIN", - "level": 5 + "level": 3 } } DEFAULT_ANIMAL_DATA = {} -def change_admin_password(): - clear_screen() - print(Fore.YELLOW + "\nYour password must be changed from the default 'ADMIN' for security reasons." + Style.RESET_ALL) - new_password = getpass.getpass("\nEnter a new password for ADMIN: ") - confirm_password = getpass.getpass("Confirm the new password: ") - - if new_password == confirm_password: - with open(USER_DATA_FILE, 'r+') as user_file: - data = json.load(user_file) - data["ADMIN"] = { - "password": new_password, - "level": 5 - } - user_file.seek(0) - json.dump(data, user_file, indent=4) - user_file.truncate() - print(Fore.GREEN + "\nPassword changed successfully!" + Style.RESET_ALL) - time.sleep(2) - clear_screen() - else: - print(Fore.RED + "\nPasswords do not match. Please try again." + Style.RESET_ALL) - time.sleep(2) - clear_screen() - change_admin_password() - -def login(): - while True: - print("\nšŸ‘¤ User Login šŸ‘¤") - username = input("\nEnter your username: ") - password = getpass.getpass("Enter your password: ") - - with open(USER_DATA_FILE, 'r') as user_file: - users = json.load(user_file) - - if username in users: - if users[username]['password'] == password: - user_level = users[username]['level'] # Retrieve the user level - if username == "ADMIN" and password == "ADMIN": - change_admin_password() - admin_dashboard() - return username, user_level # Ensure to return after admin login - elif username == "ADMIN": - admin_dashboard() - return username, user_level - else: - print("\nLogging in...") - time.sleep(2) - return username, user_level # Return username and user level for non-admin users - - else: - print(Fore.RED + "\nIncorrect password. Please try again." + Style.RESET_ALL) - time.sleep(2) - clear_screen() - else: - print(Fore.RED + "\nUsername not found. Please try again." + Style.RESET_ALL) - time.sleep(2) - clear_screen() - def main(): clear_screen() @@ -93,8 +34,10 @@ 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) + try: while True: + # Display main menu options 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) @@ -102,10 +45,12 @@ def main(): if choice == '1': clear_screen() + # Pull the username and user level from the login function username, user_level = login() if username is not None: while True: clear_screen() + # Display main menu after successful login print(Fore.CYAN + "\nšŸ“– Main Menu šŸ“–" + Style.RESET_ALL) print("\n1. " + Fore.GREEN + "šŸ”Ž View all animals" + Style.RESET_ALL) diff --git a/add_animal.py b/add_animal.py index 2a0cab7..7e984e0 100644 --- a/add_animal.py +++ b/add_animal.py @@ -1,59 +1,72 @@ import time from colorama import Fore, Style -from common_functions import clear_screen ,load_data, save_data +from common_functions import clear_screen, load_data, save_data, log_action +from sudo_user import sudo_user ANIMAL_DATA_FILE = "animals.json" def add_animal(): + # Load animal data from file animals = load_data(ANIMAL_DATA_FILE) + # Continuous loop for adding animals while True: - clear_screen() # Clear the screen before prompting for input + clear_screen() - name = input("\nEnter the animal's name: ") - if not name.strip(): # Check if the name 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 + # Display header + print(Fore.CYAN + "\nšŸ¾ Add Animal šŸ¾\n" + Style.RESET_ALL) - species = input("Enter the animal's species: ") - if not species.strip(): # Check if the species 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 + print("Enter animal details or type 'exit' to cancel:") - breed = input("Enter the animal's breed: ") - if not breed.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 + #Input fields for animal data + name = input(Fore.CYAN + "Name: " + Style.RESET_ALL).strip() - 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 + # Check if user wants to exit + if name.lower() == 'exit': + print(Fore.YELLOW + "\nExiting..." + Style.RESET_ALL) + time.sleep(2) + break + + species = input(Fore.GREEN + "Species: " + Style.RESET_ALL).strip() + breed = input(Fore.GREEN + "Breed: " + Style.RESET_ALL).strip() + gender = input(Fore.GREEN + "Gender: " + Style.RESET_ALL).strip() + age = input(Fore.GREEN + "Age: " + Style.RESET_ALL).strip() - 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) - input(Fore.GREEN + "Press Enter to continue..."+ Style.RESET_ALL) + # Validate input fields + if not all([name, species, breed, gender, age]): + print(Fore.RED + "\nInvalid input. All fields are required." + Style.RESET_ALL) + input(Fore.GREEN + "Press Enter to continue..." + Style.RESET_ALL) continue - elif not age.isdigit(): # Check if the age is a valid number - print(Fore.RED + "Invalid input. Please enter the animal's name." + Style.RESET_ALL) - input(Fore.GREEN + "Press Enter to continue..."+ Style.RESET_ALL) + + # Validate age as positive integer + if not age.isdigit() or int(age) <= 0: + print(Fore.RED + "\nInvalid age. Please enter a positive integer." + Style.RESET_ALL) + input(Fore.GREEN + "Press Enter to continue..." + Style.RESET_ALL) continue - age = int(age) # Convert age to an integer + age = int(age) - # Assuming age should be a positive number - if age <= 0: - 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 + # Add animals to the data dictionary + animals[name] = { + 'name': name, + 'species': species, + 'breed': breed, + 'gender': gender, + 'age': age, + 'adopted': False + } + + # Make the user verify their identity + current_user = sudo_user() - 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) + + # Log the action of adding animal into the audit file + log_action(current_user, f"Added animal: {name}") + + # Confirm successful addition of the animal + print(Fore.GREEN + "\nāœØ Animal added successfully! āœØ" + Style.RESET_ALL) time.sleep(2) - break # Break the loop after successfully adding the animal + + # Exit the loop after successful addition + break diff --git a/admin_dashboard.py b/admin_dashboard.py index fc86da0..94d1f00 100644 --- a/admin_dashboard.py +++ b/admin_dashboard.py @@ -7,6 +7,7 @@ USER_DATA_FILE = "users.json" def admin_dashboard(): + # Continuous loop for admin dashboard while True: clear_screen() print(Fore.YELLOW + "\nADMIN Dashboard\n" + Style.RESET_ALL) @@ -16,12 +17,13 @@ def admin_dashboard(): print("4. Logout") option = input("\nPlease select an option: ") + # Check user input and perform corresponding action if option == '1': - register() + register() elif option == '2': user_management() elif option == '3': - # Implement settings management + # ! Implement settings management print("\nThis feature is under development.") time.sleep(2) elif option == '4': diff --git a/change_adopted_status.py b/change_adopted_status.py index ac1c5b5..668d0ea 100644 --- a/change_adopted_status.py +++ b/change_adopted_status.py @@ -8,17 +8,26 @@ def change_adopted_status(): clear_screen() + + # Load animal data from file animals = load_data(ANIMAL_DATA_FILE) - name = input("\nEnter the name of the animal to toggle adoption status: ") + name = input("\nEnter the name of the animal to toggle adoption status: ") + + # Check if animal exists in the data if name in animals: + # Toggle the adopted status animals[name]['adopted'] = not animals[name].get('adopted', False) save_data(animals, ANIMAL_DATA_FILE) + + # Notify the user about the updated adoptino status if animals[name]['adopted']: print(Fore.GREEN + f"\n{name} has been marked as " + Fore.CYAN + "adopted!" + Style.RESET_ALL) else: print(Fore.GREEN + f"\n{name} has been marked as " + Fore.RED + "not adopted!" + Style.RESET_ALL) + + # Notify the user if the animal is not found else: print(Fore.RED + f"\nNo animal found with the name {name}" + Style.RESET_ALL) diff --git a/common_functions.py b/common_functions.py index 36fe3f2..9984044 100644 --- a/common_functions.py +++ b/common_functions.py @@ -1,13 +1,37 @@ import json import os +import datetime def clear_screen(): + # Clears the terminal screen based on the OS type os.system('cls' if os.name == 'nt' else 'clear') def load_data(file_name): + # Load data from a JSON file with open(file_name, 'r') as f: return json.load(f) def save_data(data, file_name): + # Save data to the JSON file with indentation for readability with open(file_name, 'w') as f: json.dump(data, f, indent=4) + +def log_action(username, action_description): + # Get the current timestamp + current_time = datetime.datetime.now() + + # Format the log entry + log_entry = f"[{current_time}] - {username}: {action_description}" + + # Define the filepath for the audit log file + log_file_path = "audit_log.txt" + + + # Check if the file exists, if not, create it + if not os.path.exists(log_file_path): + with open(log_file_path, "w"): + pass + + # Append the log entry to the file + with open(log_file_path, "a") as log_file: + log_file.write(log_entry + "\n") diff --git a/login.py b/login.py new file mode 100644 index 0000000..37138f5 --- /dev/null +++ b/login.py @@ -0,0 +1,84 @@ +import json +import getpass +import time +from colorama import Fore, Style +from common_functions import clear_screen +from admin_dashboard import admin_dashboard + +USER_DATA_FILE = "users.json" + +def change_admin_password(): + clear_screen() + + # Notify the user about changing the ADMIN password + print(Fore.YELLOW + "\nYour password must be changed from the default 'ADMIN' for security reasons." + Style.RESET_ALL) + + # Prompt user for a new password and confirmation + new_password = getpass.getpass("\nEnter a new password for ADMIN: ") + confirm_password = getpass.getpass("Confirm the new password: ") + + # Check if passowrds match + if new_password == confirm_password: + #Update the password in the user data file + with open(USER_DATA_FILE, 'r+') as user_file: + data = json.load(user_file) + data["ADMIN"] = { + "password": new_password, + "level": 5 + } + user_file.seek(0) + json.dump(data, user_file, indent=4) + user_file.truncate() + print(Fore.GREEN + "\nPassword changed successfully!" + Style.RESET_ALL) + time.sleep(2) + clear_screen() + # Notify the user about mismatching passwords and prompt again + else: + print(Fore.RED + "\nPasswords do not match. Please try again." + Style.RESET_ALL) + time.sleep(2) + clear_screen() + change_admin_password() + +def login(): + # Continuous loop for login + while True: + # Display login prompt + print("\nšŸ‘¤ User Login šŸ‘¤") + username = input("\nEnter your username: ") + password = getpass.getpass("Enter your password: ") + + # Check user credentials from the user data file + with open(USER_DATA_FILE, 'r') as user_file: + users = json.load(user_file) + + if username in users: + if users[username]['password'] == password: + user_level = users[username]['level'] + # Change admin password if not already done so + if username == "ADMIN" and password == "ADMIN": + change_admin_password() + admin_dashboard() + return username, user_level + + # Go straight to admin dashboard + elif username == "ADMIN": + admin_dashboard() + return username, user_level + + # Log in as regular user + else: + print("\nLogging in...") + time.sleep(2) + return username, user_level + + # Notify about incorrect password + else: + print(Fore.RED + "\nIncorrect password. Please try again." + Style.RESET_ALL) + time.sleep(2) + clear_screen() + + # Notify about non-existing username + else: + print(Fore.RED + "\nUsername not found. Please try again." + Style.RESET_ALL) + time.sleep(2) + clear_screen() diff --git a/register.py b/register.py index 76006ed..38c22be 100644 --- a/register.py +++ b/register.py @@ -7,27 +7,44 @@ def register(): clear_screen() + + # Load user data from file users = load_data(USER_DATA_FILE) + + # Prompt user to enter a username username = input("\nEnter a username: ") + + # Check if usernaem already exists if username in users: print(Fore.RED + "\nUsername already exists. Please choose another one." + Style.RESET_ALL) time.sleep(2) return + # Continuous loop for user registration while True: + # Prompt user to enter and confirm a password password = getpass.getpass("Enter a password: ") confirm_password = getpass.getpass("Confirm your password: ") + + # Check if passwords match if password == confirm_password: + # Prompt user to enter their user level user_level = input("Enter your user level (1-3): ") + + # Validate user level input if user_level.isdigit() and 1 <= int(user_level) <= 3: + # Update user data with new registration information users[username] = {'password': password, 'level': int(user_level)} save_data(users, USER_DATA_FILE) print(Fore.GREEN + "\nRegistration successful!" + Style.RESET_ALL) time.sleep(2) clear_screen() - break # Exit the loop when registration is successful + # Exit the loop when registration is successful + break + # Notify about invalid user level else: print(Fore.RED + "\nInvalid user level. Please enter a number between 1 and 3." + Style.RESET_ALL) + # Notify about mismatching passwords else: print(Fore.RED + "\nPasswords do not match. Please try again." + Style.RESET_ALL) diff --git a/sudo_user.py b/sudo_user.py new file mode 100644 index 0000000..4c32c04 --- /dev/null +++ b/sudo_user.py @@ -0,0 +1,60 @@ +import getpass +import json +import time +from colorama import Fore, Style +from common_functions import clear_screen, log_action + +USER_DATA_FILE = "users.json" + +def sudo_user(): + # Continuous loop for sudo user authentication + while True: + print("\nPlease enter your credentials") + username = input("\nEnter your username: ") + password = getpass.getpass("Enter your password: ") + + # Check user credentials from the user data file + with open(USER_DATA_FILE, 'r') as user_file: + users = json.load(user_file) + + if username in users: + if users[username]['password'] == password: + user_level = users[username]['level'] + # Throw error if user is logging in with ADMIN account + if username == "ADMIN": + print("\nNot a valid username") + clear_screen() + sudo_user() + return username + + # Notify about user verification for high level users + elif user_level >= 2: + print(Fore.GREEN +"\nUser Verified..." + Style.RESET_ALL) + time.sleep(2) + return username,user_level + + # Notify insufficent clearance + else: + print(Fore.RED + "\nYou do not have clearance to do this." + Style.RESET_ALL) + time.sleep(1) + print(Fore.RED + "\nADMIN user will be alerted." + Style.RESET_ALL) + time.sleep(1) + print(Fore.RED + "\nExiting..." + Style.RESET_ALL) + time.sleep(1) + + # Log user's username and add it to audit log + current_user = username + log_action(current_user, f"Tried to access without clearance") + exit() + + # Notify about incorrect password + else: + print(Fore.RED + "\nIncorrect password. Please try again." + Style.RESET_ALL) + time.sleep(2) + clear_screen() + + # Notify about non-existing username + else: + print(Fore.RED + "\nUsername not found. Please try again." + Style.RESET_ALL) + time.sleep(2) + clear_screen() diff --git a/user_management.py b/user_management.py index 3657ccd..af82425 100644 --- a/user_management.py +++ b/user_management.py @@ -5,6 +5,7 @@ USER_DATA_FILE = "users.json" def user_management(): + # Continuous loop for user management options while True: clear_screen() print(Fore.YELLOW + "\nUser Management\n" + Style.RESET_ALL) @@ -14,6 +15,7 @@ def user_management(): print("4. Back to admin dashboard") option = input("\nPlease select an option: ") + # Perform actions based on user input if option == '1': change_user_password() elif option == '2': @@ -29,11 +31,13 @@ def user_management(): time.sleep(2) def change_user_password(): + # Load user data and prompt for username and new password users = load_data(USER_DATA_FILE) username = input("\nEnter the username to change the password: ") + # Change password if the user exist and is not ADMIN if username in users and username != "ADMIN": - new_password = input("Enter the new password: ") + new_password = input("Enter the new password (use password to set their own): ") users[username]['password'] = new_password save_data(users, USER_DATA_FILE) print(Fore.GREEN + f"\nPassword for user '{username}' changed successfully!" + Style.RESET_ALL) @@ -45,6 +49,7 @@ def change_user_password(): time.sleep(2) def update_user_information(): + # Load user data and prompt for username and updates users = load_data(USER_DATA_FILE) clear_screen() username = input("\nEnter the username to update information: ") @@ -55,6 +60,7 @@ def update_user_information(): print(f"\nUsername: {username}") print(f"User Level: {users[username]['level']}") + # Prompt for the information to be updated print("\nSelect the information you want to update:") print("\n1. Username") print("2. User Level") @@ -62,6 +68,7 @@ def update_user_information(): option = input("\nEnter your choice: ") + # Process user's choice and perform updates accordingly if option == '1': new_username = input("Enter the new username: ") if new_username not in users: @@ -86,14 +93,19 @@ def update_user_information(): time.sleep(2) def delete_user(): + # Load user data and prompt for username to be deleted 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) ") + # Throw error if user tries to delete ADMIN user if username == "ADMIN": print("\nThe ADMIN user cannot be modified.") time.sleep(2) clear_screen() + delete_user() + + # Process user's choice and perform deletion accordingly else: if username in users and confirm_delete.lower() == 'y': del users[username] diff --git a/view_animal_profile.py b/view_animal_profile.py index d046e0b..00ae1c5 100644 --- a/view_animal_profile.py +++ b/view_animal_profile.py @@ -9,7 +9,7 @@ ANIMAL_DATA_FILE = "animals.json" def print_animal_table_with_index(animals): - """Prints the table of animals with index numbers.""" + # Displays 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 + " |") @@ -28,9 +28,10 @@ def print_animal_table_with_index(animals): 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) + + # Allows the user to select an animal from the table to view its profile selected_index = input("\nEnter the index of the animal to view its profile: ") try: @@ -44,10 +45,10 @@ def select_animal_to_view(animals): 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) + # Displays the profile of the selected animal in a Tkinter window print_animal_table_with_index(animals) selected_index = input("\nEnter the index of the animal to view its profile: ") @@ -119,10 +120,10 @@ def upload_image(): 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: + # Continuous loop for viewing the animal options 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) diff --git a/view_animals.py b/view_animals.py index c8a0671..00cc767 100644 --- a/view_animals.py +++ b/view_animals.py @@ -1,17 +1,26 @@ +# Import necessary libraries and modules import time from colorama import Fore, Style from common_functions import clear_screen, load_data from view_animal_profile import view_animal_profile +# Define constant for animal data file ANIMAL_DATA_FILE = "animals.json" +# Function to print the table of animals def print_animal_table(animals): - """Prints the table of animals.""" + """ + Print a formatted table of animals with their attributes. + Args: + animals (dict): Dictionary containing animal data. + """ + # Print table header print("\nšŸ¾ " + Fore.CYAN + "List of Animals" + Style.RESET_ALL + " šŸ¾") 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("---------------------------------------------------------------------------------------------") + # Print each animal's data row by row for name, data in animals.items(): name_column = f"| {name.ljust(20)}" species_column = f"| {data['species'].ljust(8)}" @@ -21,16 +30,23 @@ def print_animal_table(animals): adopted_column = f"| {str(data['adopted']).ljust(7)} |" print(name_column + species_column + breed_column + gender_column + age_column + adopted_column) + # Print table footer print("---------------------------------------------------------------------------------------------") +# Function to filter animals based on user input def filter_animals(animals): - """Filters animals based on species, breed and adoption status.""" + """ + Filter animals based on user-defined criteria. + Args: + animals (dict): Dictionary containing animal data. + """ species_query = input(Fore.GREEN + "\nEnter species" + Style.RESET_ALL + " (leave blank to skip): ").lower() breed_query = input(Fore.GREEN + "Enter breed " + Style.RESET_ALL + "(leave blank to skip): ").lower() adopted_query = input(Fore.GREEN + "Enter adoption status " + Style.RESET_ALL + "(True/False, leave blank to skip): ").lower() clear_screen() filtered_animals = {} + # Iterate through animals and apply filters for name, data in animals.items(): if (not species_query or species_query == data['species'].lower()) and \ (not breed_query or breed_query == data['breed'].lower()) and \ @@ -46,13 +62,18 @@ def filter_animals(animals): clear_screen() print_animal_table(animals) +# Function to search animals based on user input def search_animals(animals): - """Allows user to search for animals.""" + """ + Search animals based on user input criteria. + Args: + animals (dict): Dictionary containing animal data. + """ while True: search_query = input("\nEnter (name/species/breed/age): ").lower() found_results = False - if search_query.strip(): # Check if the query is not empty + if search_query.strip(): for name, data in animals.items(): if search_query in name.lower() or \ search_query in data['species'].lower() or \ @@ -87,9 +108,17 @@ def search_animals(animals): time.sleep(2) clear_screen() - +# Function to sort animals based on user input def sort_animals(animals, key='name', reverse=False): - """Sorts the animals based on the specified key.""" + """ + Sort animals based on a specified key. + Args: + animals (dict): Dictionary containing animal data. + key (str): Key to sort the animals by (default is 'name'). + reverse (bool): Whether to sort in reverse order (default is False). + Returns: + dict: Sorted dictionary of animals. + """ if key == 'name': sorted_animals = sorted(animals.items(), key=lambda x: x[0], reverse=reverse) elif key == 'age': @@ -97,11 +126,14 @@ def sort_animals(animals, key='name', reverse=False): else: print("Invalid key for sorting.") return - + return dict(sorted_animals) +# Function to view animals and interact with options def view_animals(): - """Main function to view animals.""" + """ + View animals and interact with different options. + """ clear_screen() animals = load_data(ANIMAL_DATA_FILE) print_animal_table(animals) @@ -120,6 +152,8 @@ def view_animals(): clear_screen() search_animals(animals) elif user_input == '2': + clear_screen() + print_animal_table(animals) print("\nSort by:") print("1." + Fore.GREEN + " Name (A-Z)" + Style.RESET_ALL) print("2." + Fore.GREEN + " Name (Z-A)" + Style.RESET_ALL)