Add roles enum within backend
Add more admin functions
This commit is contained in:
parent
75bbc267ef
commit
4d8c3cb2e4
@ -1,6 +1,7 @@
|
||||
require("dotenv").config();
|
||||
const express = require("express");
|
||||
const cors = require("cors");
|
||||
const User = require("./models/user.model");
|
||||
|
||||
|
||||
|
||||
@ -26,7 +27,10 @@ app.use(
|
||||
);
|
||||
|
||||
app.get('/', async (req, res) => {
|
||||
res.status(200).send('Grocery List API is running.');
|
||||
resText = `Grocery List API is running.\n` +
|
||||
`Roles available: ${Object.values(User.ROLES).join(', ')}`
|
||||
|
||||
res.status(200).type("text/plain").send(resText);
|
||||
});
|
||||
|
||||
|
||||
|
||||
@ -8,9 +8,9 @@ exports.getList = async (req, res) => {
|
||||
|
||||
|
||||
exports.addItem = async (req, res) => {
|
||||
const { item_name, quantity } = req.body;
|
||||
const { itemName, quantity } = req.body;
|
||||
|
||||
const id = await List.addOrUpdateItem(item_name, quantity);
|
||||
const id = await List.addOrUpdateItem(itemName, quantity);
|
||||
|
||||
await List.addHistoryRecord(id, quantity);
|
||||
|
||||
|
||||
@ -4,3 +4,37 @@ exports.getAllUsers = async (req, res) => {
|
||||
const users = await User.getAllUsers();
|
||||
res.json(users);
|
||||
};
|
||||
|
||||
|
||||
exports.updateUserRole = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { role } = req.body;
|
||||
|
||||
if (!Object.values(ROLES).includes(role))
|
||||
return res.status(400).json({ error: "Invalid role" });
|
||||
|
||||
const updated = await User.updateUserRole(id, role);
|
||||
if (!updated)
|
||||
return res.status(404).json({ error: "User not found" });
|
||||
|
||||
res.json({ message: "Role updated", id, role });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: "Failed to update role" });
|
||||
}
|
||||
};
|
||||
|
||||
exports.deleteUser = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
const deleted = await User.deleteUser(id);
|
||||
if (!deleted)
|
||||
return res.status(404).json({ error: "User not found" });
|
||||
|
||||
|
||||
res.json({ message: "User deleted", id });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: "Failed to delete user" });
|
||||
}
|
||||
};
|
||||
|
||||
@ -20,3 +20,28 @@ exports.getAllUsers = async () => {
|
||||
const result = await pool.query("SELECT id, username, name, role FROM users ORDER BY id ASC");
|
||||
return result.rows;
|
||||
};
|
||||
|
||||
|
||||
exports.updateUserRole = async (id, role) => {
|
||||
const result = await pool.query(
|
||||
`UPDATE users SET role = $1 WHERE id = $2 RETURNING id`,
|
||||
[role, id]
|
||||
);
|
||||
return result.rowCount > 0;
|
||||
};
|
||||
|
||||
|
||||
exports.deleteUser = async (id) => {
|
||||
const result = await pool.query(
|
||||
`DELETE FROM users WHERE id = $1 RETURNING id`,
|
||||
[id]
|
||||
);
|
||||
return result.rowCount > 0;
|
||||
};
|
||||
|
||||
|
||||
exports.ROLES = {
|
||||
VIEWER: "viewer",
|
||||
EDITOR: "editor",
|
||||
ADMIN: "admin",
|
||||
}
|
||||
@ -2,8 +2,10 @@ const router = require("express").Router();
|
||||
const auth = require("../middleware/auth");
|
||||
const requireRole = require("../middleware/rbac");
|
||||
const usersController = require("../controllers/users.controller");
|
||||
const { ROLES } = require("../models/user.model");
|
||||
|
||||
// Admin-only route
|
||||
router.get("/users", auth, requireRole("admin"), usersController.getAllUsers);
|
||||
router.get("/users", auth, requireRole(ROLES.ADMIN), usersController.getAllUsers);
|
||||
router.put("/users", auth, requireRole(ROLES.ADMIN), usersController.updateUserRole);
|
||||
router.delete("/users", auth, requireRole(ROLES.ADMIN), usersController.deleteUser);
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@ -2,13 +2,16 @@ const router = require("express").Router();
|
||||
const controller = require("../controllers/lists.controller");
|
||||
const auth = require("../middleware/auth");
|
||||
const requireRole = require("../middleware/rbac");
|
||||
const { ROLES } = require("../models/user.model");
|
||||
const User = require("./models/user.model");
|
||||
|
||||
|
||||
router.get("/", auth, requireRole("viewer", "editor", "admin"), controller.getList);
|
||||
|
||||
router.get("/", auth, requireRole(ROLES.VIEWER, ROLES.EDITOR, ROLES.ADMIN), controller.getList);
|
||||
|
||||
|
||||
router.post("/add", auth, requireRole("editor", "admin"), controller.addItem);
|
||||
router.post("/mark-bought", auth, requireRole("editor", "admin"), controller.markBought);
|
||||
router.post("/add", auth, requireRole(ROLES.EDITOR, ROLES.ADMIN), controller.addItem);
|
||||
router.post("/mark-bought", auth, requireRole(ROLES.EDITOR, ROLES.ADMIN), controller.markBought);
|
||||
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@ -2,7 +2,8 @@ const router = require("express").Router();
|
||||
const auth = require("../middleware/auth");
|
||||
const requireRole = require("../middleware/rbac");
|
||||
const usersController = require("../controllers/users.controller");
|
||||
const { ROLES } = require("../models/user.model");
|
||||
|
||||
router.get("/", auth, requireRole("admin"), usersController.getAllUsers);
|
||||
router.get("/", auth, requireRole(ROLES.ADMIN), usersController.getAllUsers);
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
import api from "./axios";
|
||||
|
||||
export const loginRequest = async (username, password) => {
|
||||
const res = await api.post("/auth/login", { username, password });
|
||||
return res.data;
|
||||
};
|
||||
|
||||
export const registerRequest = async (data) => {
|
||||
const res = await api.post("/auth/register", data);
|
||||
return res.data;
|
||||
};
|
||||
@ -0,0 +1,18 @@
|
||||
import axios from "axios";
|
||||
|
||||
const api = axios.create({
|
||||
baseURL: process.env.VITE_API_URL || "http://localhost:5000",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
api.interceptors.request.use((config => {
|
||||
const token = localStorage.getItem("token");
|
||||
if (token) {
|
||||
config.headers["Authorization"] = `Bearer ${token}`;
|
||||
}
|
||||
return config;
|
||||
}));
|
||||
|
||||
export default api;
|
||||
@ -0,0 +1,6 @@
|
||||
import api from "./axios";
|
||||
|
||||
export const getList = () => api.get("/list");
|
||||
export cosnt addItem = (itemName, quantiy) =>
|
||||
api.post("/list/add", { itemName, quantiy });
|
||||
export const markBought = (id) => api.post("/list/mark-bought", { id });
|
||||
@ -0,0 +1,5 @@
|
||||
import api from "./axios";
|
||||
|
||||
export const getAllUsers = () => api.get("/admin/users");
|
||||
export const updateRole = (id, role) => api.put(`/admin/users/${id}/role`, { role });
|
||||
export const deleteUser = (id) => api.delete(`/admin/users/${id}`);
|
||||
@ -0,0 +1,32 @@
|
||||
import { createContext, useState } from 'react';
|
||||
import { ROLES } from '../../../backend/models/user.model';
|
||||
|
||||
export const authContext = createContext();
|
||||
|
||||
export const AuthProvider = ({ children }) => {
|
||||
const [token, setToken] = useState(localStorage.getItem('token') || null);
|
||||
const [role, setRole] = useState(localStorage.getItem('role') || null);
|
||||
const [username, setUsername] = useState(localStorage.getItem('username') || null);
|
||||
|
||||
const login = (data) => {
|
||||
localStorage.setItem('token', data.token);
|
||||
localStorage.setItem('role', data.role);
|
||||
localStorage.setItem('username', data.username);
|
||||
setToken(data.token);
|
||||
setRole(data.role);
|
||||
setUsername(data.username);
|
||||
};
|
||||
|
||||
const logout = () => {
|
||||
localStorage.clear();
|
||||
setToken(null);
|
||||
setRole(null);
|
||||
setUsername(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<authContext.Provider value={{ token, role, username, login, logout, ROLES }}>
|
||||
{children}
|
||||
</authContext.Provider>
|
||||
);
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user