Skip to content

Commit

Permalink
admin and moderator levels for admin panel
Browse files Browse the repository at this point in the history
  • Loading branch information
singharaj-usai committed Oct 15, 2024
1 parent 2e7c7e1 commit 0ff9376
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 52 deletions.
112 changes: 72 additions & 40 deletions client/js/admin/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,42 +26,50 @@ function displayUsers(users) {
userManagement.empty();

const currentAdminId = localStorage.getItem('userId');
const currentAdminLevel = localStorage.getItem('adminLevel');

users.forEach((user) => {
const panel = $(`
<div class="col-md-6 col-lg-4 mb-4">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">${escapeHtml(user.username)}</h3>
</div>
<div class="panel-body">
<div class="user-info">
<p><i class="fa fa-envelope"></i> ${escapeHtml(user.email)}</p>
<p><i class="fa fa-calendar"></i> ${new Date(user.signupDate).toLocaleString()}</p>
<p><i class="fa fa-money"></i> Currency: ${user.currency}</p>
<p>
<span class="label label-${user.isBanned ? 'danger' : 'success'}">
<i class="fa fa-${user.isBanned ? 'ban' : 'check'}"></i> ${user.isBanned ? 'Banned' : 'Active'}
</span>
<span class="label label-${user.isAdmin ? 'primary' : 'default'}">
<i class="fa fa-${user.isAdmin ? 'shield' : 'user'}"></i> ${user.isAdmin ? 'Admin' : 'User'}
</span>
</p>
</div>
<div class="user-actions mt-3">
<button class="btn btn-sm btn-${user.isBanned ? 'success' : 'warning'} ban-user" data-user-id="${user._id}" data-is-banned="${user.isBanned}" ${user.isAdmin ? 'disabled' : ''}>
<i class="fa fa-${user.isBanned ? 'unlock' : 'ban'}"></i> ${user.isBanned ? 'Unban User' : 'Ban User'}
</button>
${user.isAdmin ? user._id !== currentAdminId ? `<button class="btn btn-sm btn-danger demote-admin" data-user-id="${user._id}"><i class="fa fa-level-down"></i> Demote from Admin</button>`
: '<button class="btn btn-sm btn-success" disabled><i class="fa fa-user-circle"></i> Current Admin</button>'
: `<button class="btn btn-sm btn-info promote-admin" data-user-id="${user._id}"><i class="fa fa-level-up"></i> Promote to Admin</button>`
}
<button class="btn btn-sm btn-danger delete-user" data-user-id="${user._id}" ${user.isAdmin ? 'disabled' : ''}><i class="fa fa-trash"></i> Delete User</button>
<button class="btn btn-sm btn-info view-messages" data-user-id="${user._id}"><i class="fa fa-envelope"></i> View Messages</button>
</div>
</div>
</div>
<div class="col-md-6 col-lg-4 mb-4">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">${escapeHtml(user.username)}</h3>
</div>
<div class="panel-body">
<div class="user-info">
<p><i class="fa fa-envelope"></i> ${escapeHtml(user.email)}</p>
<p><i class="fa fa-calendar"></i> ${new Date(user.signupDate).toLocaleString()}</p>
<p><i class="fa fa-money"></i> Currency: ${user.currency}</p>
<p>
<span class="label label-${user.isBanned ? 'danger' : 'success'}">
<i class="fa fa-${user.isBanned ? 'ban' : 'check'}"></i> ${user.isBanned ? 'Banned' : 'Active'}
</span>
<span class="label label-${user.adminLevel === 'admin' ? 'primary' : user.adminLevel === 'moderator' ? 'info' : 'default'}">
<i class="fa fa-${user.adminLevel === 'admin' ? 'shield' : user.adminLevel === 'moderator' ? 'gavel' : 'user'}"></i> ${user.adminLevel.charAt(0).toUpperCase() + user.adminLevel.slice(1)}
</span>
</p>
</div>
<div class="user-actions mt-3">
${currentAdminLevel === 'admin' ? `
<button class="btn btn-sm btn-${user.isBanned ? 'success' : 'warning'} ban-user" data-user-id="${user._id}" data-is-banned="${user.isBanned}" ${user.adminLevel === 'admin' ? 'disabled' : ''}>
<i class="fa fa-${user.isBanned ? 'unlock' : 'ban'}"></i> ${user.isBanned ? 'Unban User' : 'Ban User'}
</button>
${user.adminLevel === 'user' ? `
<button class="btn btn-sm btn-info promote-moderator" data-user-id="${user._id}"><i class="fa fa-level-up"></i> Promote to Moderator</button>
` : user.adminLevel === 'moderator' ? `
<button class="btn btn-sm btn-primary promote-admin" data-user-id="${user._id}"><i class="fa fa-level-up"></i> Promote to Admin</button>
` : ''}
${user.adminLevel !== 'user' && user._id !== currentAdminId ? `
<button class="btn btn-sm btn-danger demote-user" data-user-id="${user._id}"><i class="fa fa-level-down"></i> Demote User</button>
` : ''}
<button class="btn btn-sm btn-danger delete-user" data-user-id="${user._id}" ${user.adminLevel !== 'user' ? 'disabled' : ''}><i class="fa fa-trash"></i> Delete User</button>
` : ''}
<button class="btn btn-sm btn-info view-messages" data-user-id="${user._id}"><i class="fa fa-envelope"></i> View Messages</button>
</div>
`);
</div>
</div>
</div>
`);

userManagement.append(panel);
});
Expand All @@ -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 () {
Expand Down Expand Up @@ -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}`);
},
});
}
Expand Down
5 changes: 5 additions & 0 deletions server/functions/api/models/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
51 changes: 39 additions & 12 deletions server/functions/api/routes/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -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' });
Expand All @@ -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' });
}
});

Expand Down Expand Up @@ -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.' });
}

Expand Down

0 comments on commit 0ff9376

Please sign in to comment.