diff --git a/backend/fastAPI.py b/backend/fastAPI.py
index 849fe1a..17b25ff 100644
--- a/backend/fastAPI.py
+++ b/backend/fastAPI.py
@@ -1,3 +1,5 @@
+from typing import List, Optional
+from pydantic import BaseModel
import devices_json as dj
import users
@@ -12,7 +14,6 @@
USER_DB_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "database", "users_db.json")
# print(USER_DB_PATH) # For testing purposes
-# FastAPI initialization and routes
app = FastAPI()
# Add CORS Middleware
@@ -24,6 +25,11 @@
allow_headers=["*"],
)
+class UserRequest(BaseModel):
+ user_name: str
+ user_password: str
+ allocated_devices: Optional[List[str]] = None
+
@app.on_event("startup")
async def startup_event():
"""Starts device updates when the FastAPI server starts."""
@@ -94,10 +100,10 @@ def get_selected_user():
"""Returns the selected user"""
return users.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)
+@app.post("/add_user/")
+def add_new_user(user: UserRequest):
+ """Adds a new user with the given name, password, and optional allocated devices."""
+ return users.add_user(user.user_name, user.user_password, user.allocated_devices or [])
@app.delete("/delete_user/{user_name}/{user_password}")
def delete_user(user_name: str, user_password: str):
diff --git a/backend/users.py b/backend/users.py
index 55aa01d..cfc6805 100644
--- a/backend/users.py
+++ b/backend/users.py
@@ -18,6 +18,7 @@ def load_devices():
except json.JSONDecodeError:
return []
+
def load_users():
"""Load user data from users_db.json."""
if os.path.exists(USER_DB_FILE):
@@ -30,12 +31,14 @@ def load_users():
return []
return []
+
def save_users(users):
"""Save updated user data back to users_db.json."""
with open(USER_DB_FILE, "w") as f:
json.dump({"users": users}, f, indent=4)
-def add_user(user_name: str, user_password: str):
+
+def add_user(user_name: str, user_password: str, allocated_device_ids: list = None):
"""Adds a new user with correct role and allocated devices."""
users = load_users()
available_devices = load_devices()
@@ -45,7 +48,10 @@ def add_user(user_name: str, user_password: str):
allocated_devices = available_devices
else:
user_role = "sub_user"
- allocated_devices = []
+ if allocated_device_ids:
+ allocated_devices = [str(device_id) for device_id in allocated_device_ids]
+ else:
+ allocated_devices = []
new_user_id = (max(user["user_id"] for user in users) + 1) if users else 1
@@ -57,8 +63,6 @@ def add_user(user_name: str, user_password: str):
"user_role": user_role
}
- # print(new_user)
-
users.append(new_user)
save_users(users)
@@ -67,6 +71,7 @@ def add_user(user_name: str, user_password: str):
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.
Re-indexes user IDs to maintain sequential order.
@@ -99,24 +104,42 @@ def delete_user(user_name: str, user_password: str):
updates.append(message)
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():
@@ -147,6 +170,7 @@ def create_selected_user_devices_json():
with open(SELECTED_USER_FILE, "w") as f:
json.dump({"user"})
+
def getUpdates():
global updates
messages = updates[:]
@@ -155,4 +179,4 @@ def getUpdates():
# DEBUGGING SHIT DONT MIND
# load_users()
-# add_user("Aditya S", "0000")
\ No newline at end of file
+# add_user("Aditya S", "0000", [1, 2, 3, 4])
\ No newline at end of file
diff --git a/frontend/src/app/devices/page.jsx b/frontend/src/app/devices/page.jsx
index 00b7323..e786385 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,
}}
>
- }
- onClick={handleAddDeviceClick}
- sx={{
- fontFamily: "JetBrains Mono",
- fontWeight: 600,
- textTransform: "none",
- color: "white",
- }}
- >
- Add Device
-
+ {isSuperUser && (
+ }
+ onClick={handleAddDeviceClick}
+ sx={{
+ fontFamily: "JetBrains Mono",
+ fontWeight: 600,
+ textTransform: "none",
+ color: "white",
+ }}
+ >
+ Add Device
+
+ )}
@@ -336,13 +350,14 @@ const Devices = () => {
}}
onClick={() => handleEdit(device.id, device.name)}
>
-
+ {isSuperUser && }
+
handleDeleteClick(device.id)}
>
-
+ {isSuperUser && }
diff --git a/frontend/src/app/ui/dashboard/accountMenu.jsx b/frontend/src/app/ui/dashboard/accountMenu.jsx
index c1c27f1..6794e81 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";
@@ -21,6 +23,8 @@ 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 [openUserDialog, setOpenUserDialog] = React.useState(false);
const open = Boolean(anchorEl);
@@ -42,7 +46,6 @@ export default function AccountMenu() {
}
};
- // Fetch selected user from the backend
React.useEffect(() => {
const fetchSelectedUser = async () => {
try {
@@ -52,6 +55,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 +66,9 @@ export default function AccountMenu() {
fetchSelectedUser();
}, []);
+ // Log just before rendering
+ // console.log("isSuperUser:", isSuperUser);
+
return (
@@ -73,7 +81,7 @@ export default function AccountMenu() {
aria-haspopup="true"
aria-expanded={open ? "true" : undefined}
>
- {selectedUser.charAt(0)}
+ {selectedUser.charAt(0)}
@@ -122,15 +130,17 @@ export default function AccountMenu() {
color: "primary.main",
}}
>
- {selectedUser}
+ {selectedUser.charAt(0)} {selectedUser}
-
+ {isSuperUser && (
+
+ )}
+
+ 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..7b41dcc
--- /dev/null
+++ b/frontend/src/app/ui/newUserDialogue.jsx
@@ -0,0 +1,153 @@
+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 = {
+ user_name: username,
+ user_password: password,
+ allocated_devices: selectedDevices.map(String), // Ensure they are strings
+ };
+
+ fetch("http://localhost:8000/add_user/", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(newUser),
+ })
+ .then((res) => res.json())
+ .then((data) => {
+ handleClose();
+ })
+ .catch((err) => console.error("Error adding user:", err));
+ };
+
+ const handleClose = () => {
+ setUsername("");
+ setPassword("");
+ setSelectedDevices([]);
+ onClose();
+ };
+
+ return (
+
+ );
+};
+
+export default AddUserDialog;