Added admin panel and modified user action dropdown
This commit is contained in:
parent
78ab9acb04
commit
31f1fbae94
@ -7,6 +7,7 @@ import ArticleDetail from './components/ArticleDetail';
|
||||
import ArticleEditor from './components/ArticleEdit';
|
||||
import Login from './components/Login';
|
||||
import Registration from './components/Registration'
|
||||
import AdminPanel from './components/AdminPanel';
|
||||
|
||||
function App() {
|
||||
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
||||
@ -202,9 +203,21 @@ function App() {
|
||||
setAuthView('register');
|
||||
};
|
||||
|
||||
const handleOpenAdminPanel = () => {
|
||||
setCurrentView('admin');
|
||||
};
|
||||
|
||||
const handleBackFromAdmin = () => {
|
||||
setCurrentView('list');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="app">
|
||||
<Header />
|
||||
<Header
|
||||
currentUser={isLoggedIn ? currentUser : null}
|
||||
onLogout={handleLogout}
|
||||
onOpenAdminPanel={handleOpenAdminPanel}
|
||||
/>
|
||||
|
||||
{/* Show Login/Registration if not logged in */}
|
||||
{!isLoggedIn ? (
|
||||
@ -221,11 +234,6 @@ function App() {
|
||||
)
|
||||
) : (
|
||||
<>
|
||||
<div className="user-info">
|
||||
<span>Welcome, {currentUser?.display_name || currentUser?.username}({currentUser?.role})</span>
|
||||
<button className="logout-button" onClick={handleLogout}>Logout</button>
|
||||
</div>
|
||||
|
||||
{currentView === 'list' ? (
|
||||
<>
|
||||
<SearchBar onSearch={handleSearch} />
|
||||
@ -244,9 +252,11 @@ function App() {
|
||||
onDelete={handleDelete}
|
||||
currentUser={currentUser}
|
||||
/>
|
||||
) : (
|
||||
) : currentView === 'edit' ? (
|
||||
<ArticleEditor article={selectedArticle} onSave={handleSave} onCancel={handleCancelEdit} />
|
||||
)}
|
||||
) : currentView === 'admin' ? (
|
||||
<AdminPanel token={token} onBack={handleBackFromAdmin} />
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
158
client/kb-frontend/src/components/AdminPanel.css
Normal file
158
client/kb-frontend/src/components/AdminPanel.css
Normal file
@ -0,0 +1,158 @@
|
||||
.admin-panel {
|
||||
padding: 2rem;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.admin-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
border-bottom: 2px solid #333;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.admin-header h1 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.admin-section {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.admin-section h2 {
|
||||
margin-bottom: 1rem;
|
||||
color: #2c3e50;
|
||||
}
|
||||
|
||||
.users-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background: #242424;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.users-table th,
|
||||
.users-table td {
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.users-table th {
|
||||
background-color: #2c3e50;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.users-table tr:hover {
|
||||
background-color: #7f8c8d;
|
||||
}
|
||||
|
||||
.auth-badge {
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.auth-badge.local {
|
||||
background-color: #95a5a6;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.auth-badge.entra {
|
||||
background-color: #0078d4;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.role-badge {
|
||||
padding: 4px 12px;
|
||||
border-radius: 12px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.role-badge.admin {
|
||||
background-color: #e74c3c;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.role-badge.editor {
|
||||
background-color: #3498db;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.role-badge.user {
|
||||
background-color: #95a5a6;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.role-select {
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.action-buttons button {
|
||||
padding: 6px 12px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.edit-btn {
|
||||
background-color: #3498db;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.edit-btn:hover {
|
||||
background-color: #2980b9;
|
||||
}
|
||||
|
||||
.save-btn {
|
||||
background-color: #27ae60;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.save-btn:hover {
|
||||
background-color: #229954;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
background-color: #95a5a6;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.cancel-btn:hover {
|
||||
background-color: #7f8c8d;
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
background-color: #e74c3c;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.delete-btn:hover {
|
||||
background-color: #c0392b;
|
||||
}
|
||||
|
||||
.coming-soon {
|
||||
color: #7f8c8d;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
background-color: #ffebee;
|
||||
color: #c62828;
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
191
client/kb-frontend/src/components/AdminPanel.jsx
Normal file
191
client/kb-frontend/src/components/AdminPanel.jsx
Normal file
@ -0,0 +1,191 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import './AdminPanel.css';
|
||||
|
||||
function AdminPanel({ token, onBack }) {
|
||||
const [users, setUsers] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState('');
|
||||
const [editingUserId, setEditingUserId] = useState(null);
|
||||
const [selectedRole, setSelectedRole] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
fetchUsers();
|
||||
}, []);
|
||||
|
||||
const fetchUsers = async () => {
|
||||
try {
|
||||
const response = await fetch('http://localhost:9000/api/admin/users', {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setUsers(data);
|
||||
} else {
|
||||
setError('Failed to fetch users');
|
||||
}
|
||||
} catch(err) {
|
||||
console.error('Error fetching users', err);
|
||||
setError('Failed to connect to server');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRoleChange = (userId, currentRole) => {
|
||||
setEditingUserId(userId);
|
||||
setSelectedRole(currentRole);
|
||||
};
|
||||
|
||||
const handleSaveRole = async (userId) => {
|
||||
try {
|
||||
const response = await fetch(`http://localhost:9000/api/admin/users/${userId}/role`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ role: selectedRole })
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
setUsers(users.map(user => (
|
||||
user.id === userId ? { ...user, role: selectedRole} : user
|
||||
)));
|
||||
setEditingUserId(null);
|
||||
} else {
|
||||
const data = await response.json();
|
||||
alert(data.error || 'Failed to update role');
|
||||
}
|
||||
} catch(err) {
|
||||
console.error('Error updating role', err);
|
||||
alert('Failed to update role');
|
||||
}
|
||||
};
|
||||
|
||||
const handleCancelEdit = () => {
|
||||
setEditingUserId(null);
|
||||
setSelectedRole('');
|
||||
};
|
||||
|
||||
const handleDeleteUser = async (userId) => {
|
||||
if (!confirm('Are you sure you want to delete this user? This cannot be undone.')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`http://localhost:9000/api/admin/users/${userId}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
setUsers(users.filter(user => user.id !== userId));
|
||||
} else {
|
||||
const data = await response.json();
|
||||
alert(data.error || 'Failed to delete user');
|
||||
}
|
||||
} catch(err) {
|
||||
console.error('Failed to delete user', err);
|
||||
alert('Failed to delete user');
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <div className='admin-panel'>Loading...</div>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='admin-panel'>
|
||||
<div className='admin-header'>
|
||||
<button className='back-button' onClick={onBack}>← Back to Articles</button>
|
||||
</div>
|
||||
|
||||
{error && <div className='error-message'>{error}</div>}
|
||||
|
||||
<div className='admin-section'>
|
||||
<h2>User Management</h2>
|
||||
<table className='users-table'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Username</th>
|
||||
<th>Email</th>
|
||||
<th>Display Name</th>
|
||||
<th>Auth Provider</th>
|
||||
<th>Role</th>
|
||||
<th>Created</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{users.map(user => (
|
||||
<tr key ={user.id}>
|
||||
<td>{user.username}</td>
|
||||
<td>{user.email}</td>
|
||||
<td>{user.display_name}</td>
|
||||
<td>
|
||||
<span className={`auth-badge ${user.auth_provider}`}>
|
||||
{user.auth_provider}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
{editingUserId === user.id ? (
|
||||
<select
|
||||
value={selectedRole}
|
||||
onChange={(e) => setSelectedRole(e.target.value)}
|
||||
className='role-select'
|
||||
>
|
||||
<option value='Admin'>Admin</option>
|
||||
<option value='Editor'>Editor</option>
|
||||
<option value='User'>User</option>
|
||||
</select>
|
||||
) : (
|
||||
<span className={`role-badge ${user.role.toLowerCase()}`}>
|
||||
{user.role}
|
||||
</span>
|
||||
)}
|
||||
</td>
|
||||
<td>{new Date(user.created_at).toLocaleDateString()}</td>
|
||||
<td>
|
||||
{editingUserId === user.id ? (
|
||||
<div className='action-buttons'>
|
||||
<button
|
||||
className='save-btn'
|
||||
onClick={() => handleSaveRole(user.id)}
|
||||
>Save</button>
|
||||
<button
|
||||
className='cancel-btn'
|
||||
onClick={() => handleCancelEdit()}
|
||||
>Cancel</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className='action-buttons'>
|
||||
<button
|
||||
className='edit-btn'
|
||||
onClick={() => handleRoleChange(user.id, user.role)}
|
||||
>Edit Role</button>
|
||||
<button
|
||||
className='delete-btn'
|
||||
onClick={() => handleDeleteUser(user.id)}
|
||||
>Delete</button>
|
||||
</div>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className='admin-section'>
|
||||
<h2>Audit Logs</h2>
|
||||
<p className='coming-soon'>Coming Soon...</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AdminPanel;
|
||||
@ -1,11 +1,18 @@
|
||||
.header {
|
||||
background-color: #2c3e50;
|
||||
color: white;
|
||||
padding: 1rem 2rem;
|
||||
text-align: center;
|
||||
background-color: #2c3e50;
|
||||
color: white;
|
||||
padding: 1rem 2rem;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
margin: 0;
|
||||
font-size: 2rem;
|
||||
margin: 0;
|
||||
font-size: 2rem;
|
||||
}
|
||||
@ -1,9 +1,19 @@
|
||||
import './Header.css';
|
||||
import UserMenu from './UserMenu';
|
||||
|
||||
function Header() {
|
||||
function Header({ currentUser, onLogout, onOpenAdminPanel }) {
|
||||
return (
|
||||
<header className='header'>
|
||||
<h1>Cram-A-Lot Knowledge Base</h1>
|
||||
<div className='header-content'>
|
||||
<h1>Cram-A-Lot Knowledge Base</h1>
|
||||
{currentUser && (
|
||||
<UserMenu
|
||||
currentUser={currentUser}
|
||||
onLogout={onLogout}
|
||||
onOpenAdminPanel={onOpenAdminPanel}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
80
client/kb-frontend/src/components/UserMenu.css
Normal file
80
client/kb-frontend/src/components/UserMenu.css
Normal file
@ -0,0 +1,80 @@
|
||||
.user-menu {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.user-menu-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
background-color: #2c3e50;
|
||||
color: white;
|
||||
border: 2px solid #34495e;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 0.95rem;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.user-menu-button:hover {
|
||||
background-color: #34495e;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.user-role {
|
||||
color: #bdc3c7;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.dropdown-arrow {
|
||||
font-size: 0.7rem;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.dropdown-arrow.open {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.user-menu-dropdown {
|
||||
position: absolute;
|
||||
top: calc(100% + 0.5rem);
|
||||
right: 0;
|
||||
background-color: white;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
min-width: 200px;
|
||||
z-index: 1000;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
width: 100%;
|
||||
padding: 0.75rem 1rem;
|
||||
background: none;
|
||||
border: none;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
font-size: 0.95rem;
|
||||
color: #2c3e50;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.menu-item:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.menu-item.admin-item {
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.menu-item.admin-item:hover {
|
||||
background-color: #ffe5e5;
|
||||
}
|
||||
54
client/kb-frontend/src/components/UserMenu.jsx
Normal file
54
client/kb-frontend/src/components/UserMenu.jsx
Normal file
@ -0,0 +1,54 @@
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import './UserMenu.css';
|
||||
|
||||
function UserMenu({ currentUser, onLogout, onOpenAdminPanel }) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const menuRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event) => {
|
||||
if (menuRef.current && !menuRef.current.contains(event.target)) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
return () => document.removeEventListener('mousedown', handleClickOutside);
|
||||
}, []);
|
||||
|
||||
const toggleMenu = () => {
|
||||
setIsOpen(!isOpen);
|
||||
};
|
||||
|
||||
const handleMenuClick = (action) => {
|
||||
setIsOpen(false);
|
||||
action();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='user-menu' ref={menuRef}>
|
||||
<button className='user-menu-button' onClick={toggleMenu}>
|
||||
<span className='user-name'>{currentUser?.display_name}</span>
|
||||
<span className='user-role'>{currentUser?.role}</span>
|
||||
<span className={`dropdown-arrow ${isOpen ? 'open' : ''}`}>▼</span>
|
||||
</button>
|
||||
|
||||
{isOpen && (
|
||||
<div className='user-menu-dropdown'>
|
||||
{currentUser?.role === 'Admin' && (
|
||||
<button
|
||||
className='menu-item admin-item'
|
||||
onClick={() => handleMenuClick(onOpenAdminPanel)}
|
||||
>Admin Panel</button>
|
||||
)}
|
||||
<button
|
||||
className='menu-item'
|
||||
onClick={() => handleMenuClick(onLogout)}
|
||||
>Logout</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default UserMenu;
|
||||
@ -64,7 +64,8 @@ function authenticateToken(req, res, next) {
|
||||
email: user.email,
|
||||
username: user.username,
|
||||
display_name: user.display_name,
|
||||
auth_provider: user.auth_provider
|
||||
auth_provider: user.auth_provider,
|
||||
role: user.role
|
||||
};
|
||||
|
||||
next();
|
||||
|
||||
57
server/db.js
57
server/db.js
@ -285,6 +285,58 @@ function getUserById(id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the saved user's role
|
||||
* @param {Int} userId - The Id for the user
|
||||
* @param {string} newRole - The new role to be assigned
|
||||
* @returns {Object} - The updated user object
|
||||
*/
|
||||
function updateUserRole(userId, newRole) {
|
||||
db.run("UPDATE users SET role = ? WHERE id = ?",
|
||||
[newRole, userId]
|
||||
);
|
||||
|
||||
const data = db.export();
|
||||
fs.writeFileSync(DB_PATH, Buffer.from(data));
|
||||
|
||||
return getUserById(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the user from the database
|
||||
* @param {Int} userId - The Id of the user to be deleted
|
||||
*/
|
||||
function deleteUser(userId) {
|
||||
db.run("DELETE FROM users WHERE id = ?", [userId]);
|
||||
|
||||
const data = db.export();
|
||||
fs.writeFileSync(DB_PATH. Buffer.from(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all users currently stored in the database
|
||||
* @returns {[Object]} - an array of user objects
|
||||
*/
|
||||
function getAllUsers() {
|
||||
const result = db.exec(
|
||||
"SELECT id, username, email, display_name, auth_provider, role, created_at FROM users ORDER BY created_at DESC"
|
||||
);
|
||||
|
||||
if (result.length === 0) return [];
|
||||
|
||||
const columns = result[0].columns;
|
||||
const rows = result[0].values;
|
||||
|
||||
const users = rows.map(row => {
|
||||
const user = {};
|
||||
columns.forEach((col, index) => {
|
||||
user[col] = row[index];
|
||||
});
|
||||
return user;
|
||||
});
|
||||
return users;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
initDb,
|
||||
getAllArticles,
|
||||
@ -296,5 +348,8 @@ module.exports = {
|
||||
createUser,
|
||||
getUserByUsername,
|
||||
getUserByEmail,
|
||||
getUserById
|
||||
getUserById,
|
||||
updateUserRole,
|
||||
deleteUser,
|
||||
getAllUsers
|
||||
};
|
||||
@ -10,7 +10,11 @@ const {
|
||||
searchArticles,
|
||||
createUser,
|
||||
getUserByUsername,
|
||||
getUserByEmail
|
||||
getUserByEmail,
|
||||
getUserById,
|
||||
getAllUsers,
|
||||
updateUserRole,
|
||||
deleteUser
|
||||
} = require('./db');
|
||||
const { generateToken, authenticateToken, authorizeRoles } = require('./auth');
|
||||
const app = express();
|
||||
@ -272,6 +276,61 @@ initDb().then(() => {
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/admin/users', authenticateToken, authorizeRoles('Admin'), (req, res) => {
|
||||
try {
|
||||
const users = getAllUsers();
|
||||
res.status(200).json(users);
|
||||
} catch(error) {
|
||||
console.error('Error fetching users:', error);
|
||||
res.status(500).json({error: 'Failed to fetch users', details: String(error)});
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/admin/users/:id/role', authenticateToken, authorizeRoles('Admin'), (req, res) => {
|
||||
try {
|
||||
const userId = parseInt(req.params.id);
|
||||
const { role } = req.body;
|
||||
|
||||
if (!['Admin', 'Editor', 'User'].includes(role)) {
|
||||
return res.status(400).json({error: 'Invalid role. Must be Admin, Editor, or User'});
|
||||
}
|
||||
|
||||
if (userId === req.user.id) {
|
||||
return res.status(400).json({error: 'You cannot change your own role'});
|
||||
}
|
||||
|
||||
const user = getUserById(userId);
|
||||
if (!user) {
|
||||
return res.status(404).json({error: 'User not found'});
|
||||
}
|
||||
|
||||
const updatedUser = updateUserRole(userId, role);
|
||||
res.status(200).json(updatedUser);
|
||||
} catch(error) {
|
||||
console.error('Error updating user:', error);
|
||||
return res.status(500).json({error: 'Failed to update user role', details: String(error)});
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/admin/users/:id', authenticateToken, authorizeRoles('Admin'), (req, res) => {
|
||||
try {
|
||||
const userId = parseInt(req.params.id);
|
||||
|
||||
if (userId === req.user.id) {
|
||||
return res.status(400).json({error: 'You cannot delete your own user profile'});
|
||||
}
|
||||
|
||||
const user = getUserById(userId);
|
||||
if (!user) return res.status(404).json({error: 'User not found'});
|
||||
|
||||
deleteUser(userId);
|
||||
return res.status(200).json({message: 'User deleted successfully'});
|
||||
} catch(error) {
|
||||
console.error('Error deleting user:', error);
|
||||
return res.status(500).json({error: 'Failed to delete user', details: String(error)});
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server running on http://localhost:${PORT}`);
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user