From d898277c4d1b5d4ea718331ecc79cdd85b98cf4a Mon Sep 17 00:00:00 2001 From: Aditya Date: Sun, 9 Mar 2025 10:41:32 +0400 Subject: [PATCH 01/13] Enhance user selection functionality to include user role and update account menu for super user access --- backend/users.py | 25 +++++++++++++++---- frontend/src/app/ui/dashboard/accountMenu.jsx | 23 +++++++++++------ 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/backend/users.py b/backend/users.py index 55aa01d..6d4d3d7 100644 --- a/backend/users.py +++ b/backend/users.py @@ -100,23 +100,38 @@ def delete_user(user_name: str, user_password: str): return {"success": message} def select_user(user: str): - """Set the selected user and persist it.""" + """Set the selected user and persist it along with their role.""" global selected_user selected_user = user + + users = load_users() + selected_user_data = next((u for u in users if u["user_name"] == selected_user), None) + + if selected_user_data: + user_role = selected_user_data["user_role"] + else: + user_role = "unknown" + with open(SELECTED_USER_FILE, "w") as f: - json.dump({"selected_user": selected_user}, f) + json.dump({"selected_user": selected_user, "user_role": user_role}, f) + message = f"Logged in as {selected_user}" updates.append(message) - return {"success": message} + + return {"success": message, "selected_user": selected_user, "user_role": user_role} def get_selected_user(): - """Retrieve the currently selected user.""" + """Retrieve the currently selected user and their role.""" global selected_user + user_role = "" + if os.path.exists(SELECTED_USER_FILE): with open(SELECTED_USER_FILE, "r") as f: data = json.load(f) selected_user = data.get("selected_user", "") - return {"selected_user": selected_user} + user_role = data.get("user_role", "") + + return {"selected_user": selected_user, "user_role": user_role} ## USERS DEVICE MANAGEMENT ## def create_selected_user_devices_json(): diff --git a/frontend/src/app/ui/dashboard/accountMenu.jsx b/frontend/src/app/ui/dashboard/accountMenu.jsx index c1c27f1..bbc3505 100644 --- a/frontend/src/app/ui/dashboard/accountMenu.jsx +++ b/frontend/src/app/ui/dashboard/accountMenu.jsx @@ -21,6 +21,7 @@ export default function AccountMenu() { const router = useRouter(); const [anchorEl, setAnchorEl] = React.useState(null); const [selectedUser, setSelectedUser] = React.useState("Loading..."); + const [isSuperUser, setIsSuperUser] = React.useState(false); const open = Boolean(anchorEl); @@ -42,7 +43,6 @@ export default function AccountMenu() { } }; - // Fetch selected user from the backend React.useEffect(() => { const fetchSelectedUser = async () => { try { @@ -52,6 +52,8 @@ export default function AccountMenu() { } const data = await response.json(); setSelectedUser(data.selected_user || "Unknown User"); + setIsSuperUser(data.user_role === "super_user"); + console.log("Fetched user role:", data.user_role); } catch (error) { console.error("Error fetching user:", error); setSelectedUser("Error fetching user"); @@ -61,6 +63,9 @@ export default function AccountMenu() { fetchSelectedUser(); }, []); + // Log just before rendering + // console.log("isSuperUser:", isSuperUser); + return ( @@ -122,15 +127,17 @@ export default function AccountMenu() { color: "primary.main", }} > - {selectedUser} + {selectedUser.charAt(0)} {selectedUser} - - - - - Add another account - + {isSuperUser && ( + + + + + Add another account + + )} From e4556f7d42bef341cd45ab3be0b4bf827165274a Mon Sep 17 00:00:00 2001 From: Aditya Date: Sun, 9 Mar 2025 11:08:31 +0400 Subject: [PATCH 02/13] Add super user role check to conditionally render Add Device button --- frontend/src/app/devices/page.jsx | 40 +++++++++++++------ frontend/src/app/ui/dashboard/accountMenu.jsx | 2 +- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/frontend/src/app/devices/page.jsx b/frontend/src/app/devices/page.jsx index 00b7323..6931f41 100644 --- a/frontend/src/app/devices/page.jsx +++ b/frontend/src/app/devices/page.jsx @@ -38,6 +38,7 @@ const Devices = () => { const [openAddDialog, setOpenAddDialog] = useState(false); const [notConnectedDevices, setNotConnectedDevices] = useState([]); const [selectedDeviceId, setSelectedDeviceId] = useState(null); + const [isSuperUser, setIsSuperUser] = useState(false); // const [selectedDeviceName, setSelectedDeviceName] = useState(""); const disappearingStyle = { @@ -46,6 +47,17 @@ const Devices = () => { }; useEffect(() => { + fetch("http://localhost:8000/selected_user") + .then((res) => res.json()) + .then((data) => { + setIsSuperUser(data.user_role === "super_user"); + }) + .catch((err) => { + console.error("Error fetching user role:", err); + setIsSuperUser(false); + }); + + // Fetch devices information fetch("http://localhost:8000/device_info") .then((res) => res.json()) .then((data) => { @@ -259,19 +271,21 @@ const Devices = () => { marginBottom: 3, }} > - + {isSuperUser && ( + + )} diff --git a/frontend/src/app/ui/dashboard/accountMenu.jsx b/frontend/src/app/ui/dashboard/accountMenu.jsx index bbc3505..a3f2a48 100644 --- a/frontend/src/app/ui/dashboard/accountMenu.jsx +++ b/frontend/src/app/ui/dashboard/accountMenu.jsx @@ -78,7 +78,7 @@ export default function AccountMenu() { aria-haspopup="true" aria-expanded={open ? "true" : undefined} > - {selectedUser.charAt(0)} + {selectedUser.charAt(0)} From a5745b65d9269e652b33eb9352ac898f508b911e Mon Sep 17 00:00:00 2001 From: Aditya Date: Sun, 9 Mar 2025 11:31:22 +0400 Subject: [PATCH 03/13] Add user dialog component and integrate with account menu for super user --- frontend/src/app/ui/dashboard/accountMenu.jsx | 11 +- frontend/src/app/ui/newUserDialogue.jsx | 136 ++++++++++++++++++ 2 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 frontend/src/app/ui/newUserDialogue.jsx diff --git a/frontend/src/app/ui/dashboard/accountMenu.jsx b/frontend/src/app/ui/dashboard/accountMenu.jsx index a3f2a48..16ec365 100644 --- a/frontend/src/app/ui/dashboard/accountMenu.jsx +++ b/frontend/src/app/ui/dashboard/accountMenu.jsx @@ -12,6 +12,8 @@ import PersonAdd from "@mui/icons-material/PersonAdd"; import Settings from "@mui/icons-material/Settings"; import Logout from "@mui/icons-material/Logout"; +import AddUserDialog from "../newUserDialogue"; + import { signOut } from "firebase/auth"; import { auth } from "@/app/firebase/config"; @@ -22,6 +24,7 @@ export default function AccountMenu() { const [anchorEl, setAnchorEl] = React.useState(null); const [selectedUser, setSelectedUser] = React.useState("Loading..."); const [isSuperUser, setIsSuperUser] = React.useState(false); + const [openUserDialog, setOpenUserDialog] = React.useState(false); const open = Boolean(anchorEl); @@ -131,7 +134,7 @@ export default function AccountMenu() { {isSuperUser && ( - + setOpenUserDialog(true)} sx={{ fontFamily: "JetBrains Mono" }}> @@ -151,6 +154,12 @@ export default function AccountMenu() { Logout + + setOpenUserDialog(false)} + // onSave={handleSaveUser} + /> ); } diff --git a/frontend/src/app/ui/newUserDialogue.jsx b/frontend/src/app/ui/newUserDialogue.jsx new file mode 100644 index 0000000..5fd0f69 --- /dev/null +++ b/frontend/src/app/ui/newUserDialogue.jsx @@ -0,0 +1,136 @@ +import { useState, useEffect } from "react"; +import { + Dialog, + DialogTitle, + DialogContent, + DialogActions, + TextField, + Button, + FormControl, + InputLabel, + Select, + MenuItem, + Checkbox, + ListItemText, + Chip, + Box, +} from "@mui/material"; + +const AddUserDialog = ({ open, onClose, onSave }) => { + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [devices, setDevices] = useState([]); + const [selectedDevices, setSelectedDevices] = useState([]); + + useEffect(() => { + // Fetch available devices from the API + fetch("http://localhost:8000/device_info") + .then((res) => res.json()) + .then((data) => { + const allDevices = data.smart_home_devices || []; + setDevices(allDevices); + }) + .catch((err) => console.error("Error fetching devices:", err)); + }, []); + + const handleDeviceChange = (event) => { + const { value } = event.target; + setSelectedDevices(value); + }; + + const handleSubmit = () => { + const newUser = { + username, + password, + devices: selectedDevices, + }; + + onSave(newUser); + onClose(); + }; + + const handleClose = () => { + setUsername(""); + setPassword(""); + setSelectedDevices([]); + onClose(); + }; + + return ( + + + Add New User + + + setUsername(e.target.value)} + sx={{ fontFamily: "Jetbrains Mono" }} + /> + setPassword(e.target.value)} + sx={{ fontFamily: "Jetbrains Mono" }} + /> + + {/* Device Selection */} + + Select Devices + + + + {/* Selected Devices as Chips */} + + {selectedDevices.map((deviceId) => { + const device = devices.find((d) => d.id === deviceId); + return ( + + setSelectedDevices((prev) => + prev.filter((id) => id !== deviceId) + ) + } + sx={{ fontFamily: "Jetbrains Mono" }} + /> + ); + })} + + + + + + + + ); +}; + +export default AddUserDialog; From f16a69857fc2d17e03e2f38bfae4716e2621fe4f Mon Sep 17 00:00:00 2001 From: Aditya Date: Sun, 9 Mar 2025 11:33:16 +0400 Subject: [PATCH 04/13] Adjust margin top for device selection in Add User dialog --- frontend/src/app/ui/newUserDialogue.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/ui/newUserDialogue.jsx b/frontend/src/app/ui/newUserDialogue.jsx index 5fd0f69..3042048 100644 --- a/frontend/src/app/ui/newUserDialogue.jsx +++ b/frontend/src/app/ui/newUserDialogue.jsx @@ -82,7 +82,7 @@ const AddUserDialog = ({ open, onClose, onSave }) => { /> {/* Device Selection */} - + Select Devices From 8cab8e55108680d89455e1c682b21f07bed501b1 Mon Sep 17 00:00:00 2001 From: Aditya Date: Sun, 9 Mar 2025 14:21:53 +0400 Subject: [PATCH 08/13] Apply Jetbrains Mono font to input fields and device selection in Add User dialog --- frontend/src/app/ui/newUserDialogue.jsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/ui/newUserDialogue.jsx b/frontend/src/app/ui/newUserDialogue.jsx index b440f1b..9d38d91 100644 --- a/frontend/src/app/ui/newUserDialogue.jsx +++ b/frontend/src/app/ui/newUserDialogue.jsx @@ -66,6 +66,9 @@ const AddUserDialog = ({ open, onClose, onSave }) => { autoFocus margin="dense" label="Username" + InputLabelProps={{ + sx: { fontFamily: "Jetbrains Mono" } + }} fullWidth value={username} onChange={(e) => setUsername(e.target.value)} @@ -74,6 +77,9 @@ const AddUserDialog = ({ open, onClose, onSave }) => { { {/* Device Selection */} - Select Devices + Select Devices