session; $isSuper = (string) $session->get('role') === 'superadmin'; $activeWs = (int) $session->get('active_workspace_id'); $scope = (string) $this->request->getGet('scope'); if (! in_array($scope, ['active', 'global', 'all'], true)) { $scope = 'active'; } if (! $isSuper && $scope !== 'active') { $scope = 'active'; } $filters = [ 'user_id' => (int) $this->request->getGet('user_id'), 'action' => trim((string) $this->request->getGet('action')), 'date_from' => trim((string) $this->request->getGet('date_from')), 'date_to' => trim((string) $this->request->getGet('date_to')), ]; if ($scope === 'global') { $filters['workspace_id'] = null; } elseif ($scope === 'all' && $isSuper) { unset($filters['workspace_id']); } else { $filters['workspace_id'] = $activeWs > 0 ? $activeWs : null; } $model = new AuditLogModel(); $page = $model->paginateFiltered(25, $filters); $memberUsers = []; if ($activeWs > 0) { $rows = (new WorkspaceMemberModel()) ->select('workspace_members.user_id, users.name, users.email') ->join('users', 'users.id = workspace_members.user_id') ->where('workspace_members.workspace_id', $activeWs) ->orderBy('users.name', 'ASC') ->findAll(); foreach ($rows as $r) { $memberUsers[] = [ 'id' => (int) $r['user_id'], 'name' => (string) ($r['name'] ?? ''), 'email' => (string) ($r['email'] ?? ''), ]; } } return view('audit/index', [ 'title' => 'Audit log | Chart-Board', 'logs' => $page['data'], 'pager' => $page['pager'], 'filters' => $filters, 'scope' => $scope, 'isSuperadmin' => $isSuper, 'memberUsers' => $memberUsers, 'activeWorkspace' => $activeWs, ]); } public function detail(int $id) { $row = (new AuditLogModel())->findWithUser($id); if (! $row) { return $this->response->setJSON(['success' => false, 'message' => 'Not found.'])->setStatusCode(404); } $session = $this->session; $isSuper = (string) $session->get('role') === 'superadmin'; $activeWs = (int) $session->get('active_workspace_id'); $wid = $row['workspace_id'] !== null ? (int) $row['workspace_id'] : null; if (! $isSuper) { if ($wid === null || $wid !== $activeWs) { if ($wid !== null) { return $this->response->setJSON(['success' => false, 'message' => 'Forbidden.'])->setStatusCode(403); } return $this->response->setJSON(['success' => false, 'message' => 'Forbidden.'])->setStatusCode(403); } $member = (new WorkspaceMemberModel()) ->where('workspace_id', $activeWs) ->where('user_id', (int) $session->get('user_id')) ->first(); if (! $member || (string) ($member['role'] ?? '') !== 'admin') { return $this->response->setJSON(['success' => false, 'message' => 'Forbidden.'])->setStatusCode(403); } } $old = $this->decodeJson($row['old_value'] ?? null); $new = $this->decodeJson($row['new_value'] ?? null); return $this->response->setJSON([ 'success' => true, 'log' => [ 'id' => (int) $row['id'], 'action' => (string) ($row['action'] ?? ''), 'resource_type' => $row['resource_type'], 'resource_id' => $row['resource_id'], 'user_name' => $row['user_name'] ?? null, 'user_email' => $row['user_email'] ?? null, 'created_at' => (string) ($row['created_at'] ?? ''), 'ip_address' => $row['ip_address'] ?? null, 'user_agent' => $row['user_agent'] ?? null, 'old_value_json' => json_encode($old, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE), 'new_value_json' => json_encode($new, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE), ], ]); } private function decodeJson(mixed $raw): mixed { if ($raw === null || $raw === '') { return null; } if (is_array($raw)) { return $raw; } $d = json_decode((string) $raw, true); return is_array($d) ? $d : (string) $raw; } }