Update: 2026-05-07 18:56:48
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Core\Database;
|
||||
use App\Core\Encryption;
|
||||
use App\Middleware\AuthMiddleware;
|
||||
|
||||
$decoded = AuthMiddleware::check();
|
||||
@@ -19,13 +20,19 @@ try {
|
||||
$where = "WHERE 1=1";
|
||||
$params = [];
|
||||
} else {
|
||||
$where = "WHERE tenant_id = ?";
|
||||
$where = "WHERE a.tenant_id = ?";
|
||||
$params = [$tenantId];
|
||||
}
|
||||
|
||||
// Join with users table to get the name of the person who did the action
|
||||
$stmt = $db->prepare("
|
||||
SELECT a.id, a.action, a.entity_type, a.created_at, u.name as user_name
|
||||
SELECT
|
||||
a.id,
|
||||
a.action,
|
||||
a.entity_type,
|
||||
a.entity_id,
|
||||
a.new_data,
|
||||
a.created_at,
|
||||
u.name AS user_name
|
||||
FROM audit_logs a
|
||||
LEFT JOIN users u ON a.user_id = u.id
|
||||
$where
|
||||
@@ -35,8 +42,142 @@ try {
|
||||
$stmt->execute($params);
|
||||
$activities = $stmt->fetchAll();
|
||||
|
||||
foreach ($activities as &$activity) {
|
||||
$activity['user_name'] = decryptIfEncrypted($activity['user_name'] ?? null) ?: 'مستخدم مجهول';
|
||||
$activity['details'] = decodeAuditData($activity['new_data'] ?? null);
|
||||
$activity['summary'] = buildActivitySummary($activity);
|
||||
unset($activity['new_data']);
|
||||
}
|
||||
unset($activity);
|
||||
|
||||
json_success($activities);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
error_log('Dashboard Recent Activity Error: ' . $e->getMessage());
|
||||
json_error('Failed to fetch recent activity', 500);
|
||||
}
|
||||
|
||||
function decodeAuditData(?string $json): array
|
||||
{
|
||||
if (!$json) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$decoded = json_decode($json, true);
|
||||
if (!is_array($decoded)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return decryptAuditPayload($decoded);
|
||||
}
|
||||
|
||||
function decryptAuditPayload(array $payload): array
|
||||
{
|
||||
foreach ($payload as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$payload[$key] = decryptAuditPayload($value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_string($value)) {
|
||||
$payload[$key] = decryptIfEncrypted($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
function decryptIfEncrypted(mixed $value): string
|
||||
{
|
||||
if ($value === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$text = trim((string)$value);
|
||||
if ($text === '' || !looksEncrypted($text)) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
try {
|
||||
$decrypted = Encryption::decrypt($text);
|
||||
return $decrypted !== false ? $decrypted : $text;
|
||||
} catch (\Throwable $e) {
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
|
||||
function looksEncrypted(string $value): bool
|
||||
{
|
||||
$normalized = str_starts_with($value, '==') ? substr($value, 2) : $value;
|
||||
|
||||
if (strlen($normalized) < 40 || strlen($normalized) % 4 !== 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool)preg_match('/^[A-Za-z0-9+\/]+={0,2}$/', $normalized);
|
||||
}
|
||||
|
||||
function buildActivitySummary(array $activity): string
|
||||
{
|
||||
$data = is_array($activity['details'] ?? null) ? $activity['details'] : [];
|
||||
$action = (string)($activity['action'] ?? '');
|
||||
|
||||
return match ($action) {
|
||||
'payment.created' => buildPaymentSummary('تم إنشاء طلب دفع', $data),
|
||||
'payment.approved' => buildPaymentSummary('تم اعتماد طلب دفع', $data),
|
||||
'payment.rejected' => buildPaymentSummary('تم رفض طلب دفع', $data),
|
||||
'subscription.activated' => buildPaymentSummary('تم تفعيل الاشتراك', $data),
|
||||
'invoice.approved' => buildEntitySummary('تم اعتماد الفاتورة', $data, ['invoice_number', 'number']),
|
||||
'invoice.extracted' => buildEntitySummary('تم استخراج بيانات الفاتورة', $data, ['invoice_number', 'number']),
|
||||
'company.created' => buildEntitySummary('تمت إضافة شركة', $data, ['name', 'company_name']),
|
||||
'user.created' => buildEntitySummary('تمت إضافة مستخدم', $data, ['name', 'email']),
|
||||
default => '',
|
||||
};
|
||||
}
|
||||
|
||||
function buildPaymentSummary(string $label, array $data): string
|
||||
{
|
||||
$parts = [$label];
|
||||
|
||||
$plan = firstTextValue($data, ['plan_name', 'plan_name_ar', 'plan_id']);
|
||||
if ($plan !== '') {
|
||||
$parts[] = "الباقة: {$plan}";
|
||||
}
|
||||
|
||||
$amount = firstTextValue($data, ['amount', 'amount_jod', 'price_jod']);
|
||||
if ($amount !== '') {
|
||||
$parts[] = "القيمة: {$amount} د.أ";
|
||||
}
|
||||
|
||||
$reference = firstTextValue($data, ['ref', 'reference', 'internal_reference']);
|
||||
if ($reference !== '') {
|
||||
$parts[] = "المرجع: {$reference}";
|
||||
}
|
||||
|
||||
return implode(' - ', $parts);
|
||||
}
|
||||
|
||||
function buildEntitySummary(string $label, array $data, array $keys): string
|
||||
{
|
||||
$value = firstTextValue($data, $keys);
|
||||
return $value === '' ? $label : "{$label}: {$value}";
|
||||
}
|
||||
|
||||
function firstTextValue(array $data, array $keys): string
|
||||
{
|
||||
foreach ($keys as $key) {
|
||||
if (!array_key_exists($key, $data) || $data[$key] === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = $data[$key];
|
||||
if (is_scalar($value)) {
|
||||
$text = trim((string)$value);
|
||||
if ($text !== '') {
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user