diff --git a/client/js/admin/users.js b/client/js/admin/users.js index 7fad055..fc3cd39 100644 --- a/client/js/admin/users.js +++ b/client/js/admin/users.js @@ -26,42 +26,50 @@ function displayUsers(users) { userManagement.empty(); const currentAdminId = localStorage.getItem('userId'); + const currentAdminLevel = localStorage.getItem('adminLevel'); + users.forEach((user) => { const panel = $(` -
-
-
-

${escapeHtml(user.username)}

-
-
- - -
-
+
+
+
+

${escapeHtml(user.username)}

+
+
+ + - `); +
+
+
+ `); userManagement.append(panel); }); @@ -85,9 +93,14 @@ function addUserEventListeners() { promoteToAdmin(userId); }); - $('.demote-admin').on('click', function () { + $('.promote-moderator').on('click', function () { + const userId = $(this).data('user-id'); + promoteToModerator(userId); + }); + + $('.demote-user').on('click', function () { const userId = $(this).data('user-id'); - demoteAdmin(userId); + demoteUser(userId); }); $('.delete-user').on('click', function () { @@ -204,20 +217,39 @@ function promoteToAdmin(userId) { } } -function demoteAdmin(userId) { - if (confirm('Are you sure you want to demote this user from admin?')) { +function promoteToModerator(userId) { + if (confirm('Are you sure you want to promote this user to moderator?')) { + $.ajax({ + url: `/api/admin/promote-moderator/${userId}`, + method: 'POST', + headers: { + Authorization: `Bearer ${localStorage.getItem('token')}`, + }, + success: function () { + showAlert('success', 'User promoted to moderator successfully.'); + loadUsers(); + }, + error: function (xhr) { + showAlert('danger', `Error promoting user to moderator: ${xhr.responseJSON.error}`); + }, + }); + } +} + +function demoteUser(userId) { + if (confirm('Are you sure you want to demote this user?')) { $.ajax({ - url: `/api/admin/demote-admin/${userId}`, + url: `/api/admin/demote/${userId}`, method: 'POST', headers: { Authorization: `Bearer ${localStorage.getItem('token')}`, }, success: function () { - showAlert('success', 'User demoted from admin successfully.'); + showAlert('success', 'User demoted successfully.'); loadUsers(); }, error: function (xhr) { - showAlert('danger', `Error demoting user from admin: ${xhr.responseJSON.error}`); + showAlert('danger', `Error demoting user: ${xhr.responseJSON.error}`); }, }); } diff --git a/server/functions/api/models/User.js b/server/functions/api/models/User.js index ac0a943..bb00baf 100644 --- a/server/functions/api/models/User.js +++ b/server/functions/api/models/User.js @@ -7,6 +7,11 @@ const userSchema = new mongoose.Schema({ type: Boolean, default: false, }, + adminLevel: { + type: String, + enum: ['user', 'moderator', 'admin'], + default: 'user' + }, userId: { type: Number, unique: true, diff --git a/server/functions/api/routes/admin.js b/server/functions/api/routes/admin.js index 3aac13a..5150c4e 100644 --- a/server/functions/api/routes/admin.js +++ b/server/functions/api/routes/admin.js @@ -21,19 +21,41 @@ router.get('/check-auth', (req, res) => { res.json({ isAdmin: true }); }); +// Promote moderator +router.post('/promote-moderator/:id', authenticateToken, isAdmin, async (req, res) => { + try { + const userToPromote = await User.findById(req.params.id); + if (!userToPromote) { + return res.status(404).json({ error: 'User not found' }); + } + + if (userToPromote.adminLevel === 'moderator') { + return res.status(400).json({ error: 'User is already a moderator' }); + } + + userToPromote.adminLevel = 'moderator'; + await userToPromote.save(); + + res.json({ message: 'User promoted to moderator successfully' }); + } catch (error) { + console.error('Error promoting user to moderator:', error); + res.status(500).json({ error: 'Error promoting user to moderator' }); + } +}); + // Promote user to admin -router.post('/promote-admin/:id', authenticateToken, async (req, res) => { +router.post('/promote-admin/:id', authenticateToken, isAdmin, async (req, res) => { try { const userToPromote = await User.findById(req.params.id); if (!userToPromote) { return res.status(404).json({ error: 'User not found' }); } - if (userToPromote.isAdmin) { + if (userToPromote.adminLevel === 'admin') { return res.status(400).json({ error: 'User is already an admin' }); } - userToPromote.isAdmin = true; + userToPromote.adminLevel = 'admin'; await userToPromote.save(); res.json({ message: 'User promoted to admin successfully' }); @@ -43,28 +65,28 @@ router.post('/promote-admin/:id', authenticateToken, async (req, res) => { } }); -router.post('/demote-admin/:id', authenticateToken, async (req, res) => { +router.post('/demote/:id', authenticateToken, isAdmin, async (req, res) => { try { const userToDemote = await User.findById(req.params.id); if (!userToDemote) { return res.status(404).json({ error: 'User not found' }); } - if (!userToDemote.isAdmin) { - return res.status(400).json({ error: 'User is not an admin' }); + if (userToDemote.adminLevel === 'user') { + return res.status(400).json({ error: 'User is already a regular user' }); } if (userToDemote._id.toString() === req.user.id) { return res.status(400).json({ error: 'You cannot demote yourself' }); } - userToDemote.isAdmin = false; + userToDemote.adminLevel = 'user'; await userToDemote.save(); - res.json({ message: 'User demoted from admin successfully' }); + res.json({ message: 'User demoted successfully' }); } catch (error) { - console.error('Error demoting user from admin:', error); - res.status(500).json({ error: 'Error demoting user from admin' }); + console.error('Error demoting user:', error); + res.status(500).json({ error: 'Error demoting user' }); } }); @@ -423,15 +445,20 @@ router.post('/users/:id/ban', authenticateToken, isAdmin, async (req, res) => { }); // Delete a user (ONLY USE AS LAST RESORT, THIS IS DESTRUCTIVE) -router.delete('/users/:id', authenticateToken, isAdmin, async (req, res) => { +router.delete('/users/:id', authenticateToken, async (req, res) => { try { const userToDelete = await User.findById(req.params.id); + const currentUser = await User.findById(req.user.id); if (!userToDelete) { return res.status(404).json({ error: 'User not found' }); } - if (userToDelete.isAdmin) { + if (currentUser.adminLevel !== 'admin') { + return res.status(403).json({ error: 'Only admins can delete users.' }); + } + + if (userToDelete.adminLevel === 'admin') { return res.status(403).json({ error: 'Cannot delete an admin user.' }); }