Add error log management and bulk admin actions

Introduces error log tracking with new ErrorLog model, controller, views, and migration. Adds admin UI for viewing, resolving, and deleting errors. Implements bulk actions for users and notification groups, refactors domain filtering/pagination, and centralizes admin access checks using Auth::requireAdmin().
This commit is contained in:
Hosteroid
2025-10-10 14:01:19 +03:00
parent a29becc944
commit b50377492c
38 changed files with 3726 additions and 428 deletions

View File

@@ -12,14 +12,8 @@ class UserController extends Controller
public function __construct()
{
Auth::requireAdmin();
$this->userModel = new User();
// Ensure only admins can access user management
if (!isset($_SESSION['role']) || $_SESSION['role'] !== 'admin') {
$_SESSION['error'] = 'Access denied. Admin privileges required.';
$this->redirect('/');
exit;
}
}
/**
@@ -378,5 +372,112 @@ class UserController extends Controller
$this->redirect('/users');
}
}
/**
* Bulk toggle user status (activate or deactivate)
*/
public function bulkToggleStatus()
{
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
$this->redirect('/users');
return;
}
$this->verifyCsrf('/users');
$userIdsJson = $_POST['user_ids'] ?? '[]';
$userIds = json_decode($userIdsJson, true);
$action = $_POST['action'] ?? 'activate'; // 'activate' or 'deactivate'
if (empty($userIds) || !is_array($userIds)) {
$_SESSION['error'] = 'No users selected';
$this->redirect('/users');
return;
}
$newStatus = ($action === 'activate') ? 1 : 0;
$updatedCount = 0;
$skippedSelf = false;
foreach ($userIds as $userId) {
// Prevent modifying your own account
if ($userId == Auth::id()) {
$skippedSelf = true;
continue;
}
try {
$this->userModel->update((int)$userId, ['is_active' => $newStatus]);
$updatedCount++;
} catch (\Exception $e) {
// Continue with next user
}
}
$message = $action === 'activate' ? "Activated $updatedCount user(s)" : "Deactivated $updatedCount user(s)";
if ($skippedSelf) {
$message .= ' (skipped your own account)';
}
$_SESSION['success'] = $message;
$this->redirect('/users');
}
/**
* Bulk delete users
*/
public function bulkDelete()
{
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
$this->redirect('/users');
return;
}
$this->verifyCsrf('/users');
$userIdsJson = $_POST['user_ids'] ?? '[]';
$userIds = json_decode($userIdsJson, true);
if (empty($userIds) || !is_array($userIds)) {
$_SESSION['error'] = 'No users selected for deletion';
$this->redirect('/users');
return;
}
$deletedCount = 0;
$skippedSelf = false;
foreach ($userIds as $userId) {
// Prevent deleting your own account
if ($userId == Auth::id()) {
$skippedSelf = true;
continue;
}
// Prevent deleting if this is the last admin
$user = $this->userModel->find((int)$userId);
if ($user && $user['role'] === 'admin') {
$allAdmins = $this->userModel->where('role', 'admin');
if (count($allAdmins) <= 1) {
continue; // Skip - can't delete last admin
}
}
try {
$this->userModel->delete((int)$userId);
$deletedCount++;
} catch (\Exception $e) {
// Continue with next user
}
}
$message = "Successfully deleted $deletedCount user(s)";
if ($skippedSelf) {
$message .= ' (skipped your own account)';
}
$_SESSION['success'] = $message;
$this->redirect('/users');
}
}