diff --git a/backend/fastAPI.py b/backend/fastAPI.py index de9a602..849fe1a 100644 --- a/backend/fastAPI.py +++ b/backend/fastAPI.py @@ -97,4 +97,9 @@ def get_selected_user(): @app.post("/add_user/{user_name}/{user_password}") def add_new_user(user_name: str, user_password: str): """Adds a new user with the given name and password.""" - return users.add_user(user_name, user_password) \ No newline at end of file + return users.add_user(user_name, user_password) + +@app.delete("/delete_user/{user_name}/{user_password}") +def delete_user(user_name: str, user_password: str): + """Deletes a user with the given name and password.""" + return users.delete_user(user_name, user_password) \ No newline at end of file diff --git a/backend/users.py b/backend/users.py index dc81ec7..0ab4679 100644 --- a/backend/users.py +++ b/backend/users.py @@ -1,12 +1,23 @@ import json import os -BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # Get current script directory +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) SELECTED_USER_FILE = "selected_user.json" -# print(os.path.abspath(os.path.join(BASE_DIR, "../database/users_db.json"))) USER_DB_FILE = os.path.abspath(os.path.join(BASE_DIR, "../database/users_db.json")) +DEVICE_DB_FILE = os.path.abspath(os.path.join(BASE_DIR, "../backend/devices.json")) +# print(os.path.abspath(os.path.join(BASE_DIR, "../backend/devices.json"))) updates = [] +def load_devices(): + """Load smart home devices data from devices.json.""" + if os.path.exists(DEVICE_DB_FILE): + with open(DEVICE_DB_FILE, "r") as f: + try: + data = json.load(f) + return [str(device["id"]) for device in data.get("smart_home_devices", [])] + except json.JSONDecodeError: + return [] + def load_users(): """Load user data from users_db.json.""" if os.path.exists(USER_DB_FILE): @@ -27,10 +38,11 @@ def save_users(users): def add_user(user_name: str, user_password: str): """Adds a new user with correct role and allocated devices.""" users = load_users() + available_devices = load_devices() if not users: user_role = "super_user" - allocated_devices = ["1", "2", "3", "4", "5", "6"] + allocated_devices = available_devices else: user_role = "sub_user" allocated_devices = [] @@ -45,17 +57,22 @@ def add_user(user_name: str, user_password: str): "user_role": user_role } + print(new_user) + users.append(new_user) save_users(users) - message = f"New user added: {user_name} ({user_role})" + message = f"New user added: {user_name} with role {'Super User' if user_role == 'super_user' else 'Sub User'}" updates.append(message) return {"success": message, "user": new_user} def delete_user(user_name: str, user_password: str): - """Deletes a user from the system if the given password matches. If deleting the super user, assign the position to the next user""" + """Deletes a user from the system if the given password matches. If deleting the super user, assign the position to the next user. + Re-indexes user IDs to maintain sequential order. + """ users = load_users() + available_devices = load_devices() user_to_delete = next((u for u in users if u["user_name"] == user_name), None) if not user_to_delete: @@ -68,13 +85,16 @@ def delete_user(user_name: str, user_password: str): users.remove(user_to_delete) message = f"User {user_name} deleted." - + if user_to_delete["user_role"] == "super_user" and users: next_super_user = min(users, key=lambda u: u["user_id"]) next_super_user["user_role"] = "super_user" - next_super_user["allocated_devices"] = ["1", "2", "3", "4", "5", "6"] + next_super_user["allocated_devices"] = available_devices message += f" {next_super_user['user_name']} is now the super user." + for index, user in enumerate(users, start=1): + user["user_id"] = index + save_users(users) updates.append(message) return {"success": message} @@ -98,6 +118,35 @@ def get_selected_user(): selected_user = data.get("selected_user", "") return {"selected_user": selected_user} +## USERS DEVICE MANAGEMENT ## +def create_selected_user_devices_json(): + """Create a JSON file with the selected users allocated devices""" + selected_user_data = get_selected_user() + selected_user_name = selected_user_data.get("selected_user") + + if not selected_user_name: + return {"error": "No user selected."} + + users = load_users() + devices = load_devices(full_details=True) + + selected_user = next((u for u in users if u["user_name"] == selected_user_name), None) + + if not selected_user: + return {"error": f"User {selected_user_name} not found."} + + allocated_device_ids = set(selected_user.get("allocated_devices", [])) + + allocated_devices = [device for device in devices if str(device["id"]) in allocated_device_ids] + + if not allocated_devices: + message = f"No devices allocated to {selected_user_name}." + updates.append(message) + return {"error": f"No devices allocated to {selected_user_name}."} + + with open(SELECTED_USER_FILE, "w") as f: + json.dump({"user"}) + def getUpdates(): global updates messages = updates[:] @@ -105,4 +154,5 @@ def getUpdates(): return messages # DEBUGGING SHIT DONT MIND -# load_users() \ No newline at end of file +# load_users() +# add_user("Aditya S", "0000") \ No newline at end of file diff --git a/database/users_db.json b/database/users_db.json index a69b845..55e0cbd 100644 --- a/database/users_db.json +++ b/database/users_db.json @@ -10,7 +10,9 @@ "3", "4", "5", - "6" + "6", + "7", + "8" ], "user_role": "super_user" }, @@ -20,6 +22,13 @@ "user_password": "1415", "allocated_devices": [], "user_role": "sub_user" + }, + { + "user_id": 3, + "user_name": "Ann E", + "user_password": "9999", + "allocated_devices": [], + "user_role": "sub_user" } ] } \ No newline at end of file diff --git a/frontend/src/app/users/page.jsx b/frontend/src/app/users/page.jsx index 22b9a6d..fa1da7a 100644 --- a/frontend/src/app/users/page.jsx +++ b/frontend/src/app/users/page.jsx @@ -112,13 +112,40 @@ const Users = () => { const [newUsername, setNewUsername] = useState(""); const [newPassword, setNewPassword] = useState(""); const [error, setError] = useState(""); + const [userToDelete, setUserToDelete] = useState(null); + const [deletePassword, setDeletePassword] = useState(""); + const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); + const [deleteError, setDeleteError] = useState(""); + + const handleDeleteClick = (user) => { + setUserToDelete(user); + setDeletePassword(""); + setDeleteError(""); + setDeleteDialogOpen(true); + }; + + const fetchUsers = async () => { + try { + const response = await fetch("http://localhost:8000/user_data"); + const data = await response.json(); + setUsers(data.users || []); + } catch (error) { + console.error("Error fetching users:", error); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + fetchUsers(); + }, []); const handleNewUserSubmit = async () => { if (newUsername.trim() === "" || newPassword.length !== 4 || isNaN(newPassword)) { setError("Username must not be empty and password must be a 4-digit number."); return; } - + try { const response = await fetch( `http://localhost:8000/add_user/${encodeURIComponent(newUsername)}/${encodeURIComponent(newPassword)}`, @@ -126,46 +153,59 @@ const Users = () => { method: "POST", } ); - + if (!response.ok) { const errorMessage = await response.text(); setError(`Failed to add user: ${errorMessage}`); return; } - - const newUser = await response.json(); - - setUsers((prevUsers) => [...prevUsers, newUser]); - + setOpenNewUserDialog(false); setNewUsername(""); setNewPassword(""); setError(""); + + fetchUsers(); } catch (error) { console.error("Error adding user:", error); setError("An error occurred while adding the user."); } }; - const router = useRouter(); + const handleConfirmDelete = async () => { + if (!userToDelete || deletePassword.length !== 4 || isNaN(deletePassword)) { + setDeleteError("Please enter a valid 4-digit password."); + return; + } - const theme = getTheme(darkMode ? "dark" : "light"); + try { + const response = await fetch( + `http://localhost:8000/delete_user/${encodeURIComponent(userToDelete.user_name)}/${encodeURIComponent(deletePassword)}`, + { + method: "DELETE", + } + ); - useEffect(() => { - const fetchUsers = async () => { - try { - const response = await fetch("http://localhost:8000/user_data"); - const data = await response.json(); - setUsers(data.users || []); - } catch (error) { - console.error("Error fetching users:", error); - } finally { - setLoading(false); + if (!response.ok) { + const errorMessage = await response.text(); + setDeleteError(`Failed to delete user: ${errorMessage}`); + return; } - }; - fetchUsers(); - }, []); + // Fetch users again to update the UI correctly + await fetchUsers(); + + setDeleteDialogOpen(false); + setUserToDelete(null); + } catch (error) { + console.error("Error deleting user:", error); + setDeleteError("An error occurred while deleting the user."); + } + }; + + const router = useRouter(); + + const theme = getTheme(darkMode ? "dark" : "light"); const handleUserClick = (user) => { setSelectedUser(user); @@ -266,8 +306,8 @@ const Users = () => { sx={{ bgcolor: "background.paper", color: "text.primary", - p: 2, textAlign: "center", + p: 2, boxShadow: 6, borderRadius: 3, cursor: "pointer", @@ -293,9 +333,9 @@ const Users = () => { position: "absolute", bottom: 8, right: 8, - color: "text.secondary", + color: "primary.main", }} - onClick={() => handleDeleteUser(user.user_name)} + onClick={() => handleDeleteClick(user)} > @@ -390,6 +430,37 @@ const Users = () => { + setDeleteDialogOpen(false)}> + + Confirm Delete + + + + Selected user to delete: {userToDelete?.user_name} + + setDeletePassword(e.target.value)} + inputProps={{ maxLength: 4, pattern: "[0-9]*", inputMode: "numeric" }} + sx={{ mb: 2 }} + /> + {deleteError && {deleteError}} + + + + + + +