feat: Add comprehensive admin user management system

- Add user status toggle (activate/deactivate) functionality
- Add user deletion with post/comment transfer to admin
- Implement safety checks for admin protection
- Add interactive JavaScript for user management actions
- Update admin users interface with action buttons
- Add confirmation dialogs for destructive operations
- Update README with new admin features and capabilities
- Add database migration utility for future updates

Features:
- Toggle user active/inactive status
- Delete users with content preservation
- Transfer all posts/comments to admin on user deletion
- Prevent admin self-modification and deletion
- AJAX-powered interface with real-time feedback
- Comprehensive error handling and user notifications
This commit is contained in:
ske087
2025-07-24 03:07:52 +03:00
parent 60ef02ced9
commit 7018ae13f0
4 changed files with 409 additions and 84 deletions

View File

@@ -74,8 +74,17 @@
<i class="fas fa-eye"></i>
</a>
{% if not user.is_admin or current_user.id != user.id %}
<button class="btn btn-sm btn-outline-warning" title="Toggle Status" disabled>
<i class="fas fa-toggle-on"></i>
<button class="btn btn-sm btn-outline-warning"
title="{{ 'Deactivate User' if user.is_active else 'Activate User' }}"
onclick="toggleUserStatus({{ user.id }}, '{{ user.nickname }}', {{ user.is_active|lower }})">
<i class="fas fa-{{ 'toggle-on' if user.is_active else 'toggle-off' }}"></i>
</button>
{% endif %}
{% if not user.is_admin and current_user.id != user.id %}
<button class="btn btn-sm btn-outline-danger"
title="Delete User"
onclick="confirmDeleteUser({{ user.id }}, '{{ user.nickname }}', {{ user.posts.count() }})">
<i class="fas fa-trash"></i>
</button>
{% endif %}
</div>
@@ -134,4 +143,88 @@
</div>
</div>
{% endif %}
<script>
function toggleUserStatus(userId, nickname, currentStatus) {
const action = currentStatus ? 'deactivate' : 'activate';
const message = `Are you sure you want to ${action} user "${nickname}"?`;
if (confirm(message)) {
fetch(`/admin/users/${userId}/toggle-status`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
showAlert(data.message, 'success');
setTimeout(() => {
location.reload();
}, 1000);
} else {
showAlert(data.message || 'An error occurred', 'danger');
}
})
.catch(error => {
console.error('Error:', error);
showAlert('An error occurred while updating user status', 'danger');
});
}
}
function confirmDeleteUser(userId, nickname, postsCount) {
let message = `Are you sure you want to delete user "${nickname}"?`;
if (postsCount > 0) {
message += `\n\nThis user has ${postsCount} post(s) that will be transferred to you as the admin.`;
}
message += '\n\nThis action cannot be undone.';
if (confirm(message)) {
fetch(`/admin/users/${userId}/delete`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
showAlert(data.message, 'success');
setTimeout(() => {
location.reload();
}, 1000);
} else {
showAlert(data.message || 'An error occurred', 'danger');
}
})
.catch(error => {
console.error('Error:', error);
showAlert('An error occurred while deleting user', 'danger');
});
}
}
function showAlert(message, type) {
// Create alert container if it doesn't exist
let alertContainer = document.querySelector('.alert-container');
if (!alertContainer) {
alertContainer = document.createElement('div');
alertContainer.className = 'alert-container mt-3';
document.querySelector('.container-fluid').insertBefore(
alertContainer,
document.querySelector('.container-fluid').firstChild
);
}
alertContainer.innerHTML = `
<div class="alert alert-${type} alert-dismissible fade show" role="alert">
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
`;
}
</script>
{% endblock %}