Skip to content

Commit

Permalink
Merge pull request #13 from tylerlight071/Features
Browse files Browse the repository at this point in the history
User Verification + Audit Trails
  • Loading branch information
tylerlight071 authored Jan 30, 2024
2 parents 04a7e7d + 268f765 commit 9ca07b0
Show file tree
Hide file tree
Showing 12 changed files with 321 additions and 120 deletions.
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
# User Files
*.json
*.txt
69 changes: 7 additions & 62 deletions FurEver_Friends.py
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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()

Expand All @@ -93,19 +34,23 @@ 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)
choice = input("\nPlease select an option: ")

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)

Expand Down
89 changes: 51 additions & 38 deletions add_animal.py
Original file line number Diff line number Diff line change
@@ -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
6 changes: 4 additions & 2 deletions admin_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand 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':
Expand Down
11 changes: 10 additions & 1 deletion change_adopted_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
24 changes: 24 additions & 0 deletions common_functions.py
Original file line number Diff line number Diff line change
@@ -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")
Loading

0 comments on commit 9ca07b0

Please sign in to comment.