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.email)}
-
${new Date(user.signupDate).toLocaleString()}
-
Currency: ${user.currency}
-
-
- ${user.isBanned ? 'Banned' : 'Active'}
-
-
- ${user.isAdmin ? 'Admin' : 'User'}
-
-
-
-
-
- ${user.isAdmin ? user._id !== currentAdminId ? ``
- : ''
- : ``
- }
-
-
-
-
-
+
+
+
+
${escapeHtml(user.username)}
+
+
+
+
${escapeHtml(user.email)}
+
${new Date(user.signupDate).toLocaleString()}
+
Currency: ${user.currency}
+
+
+ ${user.isBanned ? 'Banned' : 'Active'}
+
+
+ ${user.adminLevel.charAt(0).toUpperCase() + user.adminLevel.slice(1)}
+
+
+
+
+ ${currentAdminLevel === 'admin' ? `
+
+ ${user.adminLevel === 'user' ? `
+
+ ` : user.adminLevel === 'moderator' ? `
+
+ ` : ''}
+ ${user.adminLevel !== 'user' && user._id !== currentAdminId ? `
+
+ ` : ''}
+
+ ` : ''}
+
- `);
+
+
+
+ `);
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.' });
}