Files
baodev0andClaude Sonnet 5.5 62596d9063 feat(vm): hoàn tiền khi cấp VM lỗi, theo dõi job queue, uuid dịch vụ cho ticket, chuẩn hoá RAM addon
- VmProvisionException/VmProvisionRefund xử lý lỗi cấp phát VM
- QueueJobInspector + QueueMonitorController xem chi tiết job
- Thêm service uuid cho ticket, thời lượng cho activity_logs
- Migration chuẩn hoá RAM addon sang MB, trạng thái deleting cho snapshot

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-30 11:54:05 +07:00

172 lines
5.1 KiB
PHP

<?php
namespace App\Services;
use App\Jobs\LogActivityJob;
use Carbon\CarbonInterface;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Log;
class ActivityLogger
{
private array $hiddenFields = [
'password',
'remember_token',
'plain_password',
'token',
'secret',
'api_key',
'updated_at',
];
public function log(
string $event,
string $logName,
string $description,
?Model $subject = null,
array $oldValues = [],
array $newValues = [],
?CarbonInterface $startedAt = null,
?CarbonInterface $finishedAt = null,
): void {
try {
[$causerType, $causerId, $causerName] = $this->resolveCauser();
LogActivityJob::dispatch([
'log_name' => $logName,
'event' => $event,
'description' => $description,
'subject_type' => $subject ? get_class($subject) : null,
'subject_id' => $subject?->getKey(),
'causer_type' => $causerType,
'causer_id' => $causerId,
'causer_name' => $causerName,
'old_values' => $oldValues ?: null,
'new_values' => $newValues ?: null,
'ip_address' => request()->getClientIp(),
'user_agent' => request()->userAgent(),
'started_at' => $startedAt?->format('Y-m-d H:i:s.v'),
'finished_at' => $finishedAt?->format('Y-m-d H:i:s.v'),
'created_at' => now()->format('Y-m-d H:i:s.v'),
]);
} catch (\Throwable $e) {
Log::warning('[ActivityLogger] Failed to dispatch log job', [
'error' => $e->getMessage(),
'event' => $event,
'log_name' => $logName,
]);
}
}
public function logCreated(Model $model, string $logName): void
{
$causer = $this->getCauserName();
$id = $model->getKey();
$this->log(
event: 'created',
logName: $logName,
description: "$causer tạo mới $logName" . ($id ? " #$id" : ''),
subject: $model,
newValues: $this->filterValues($model->getAttributes()),
);
}
public function logUpdated(Model $model, string $logName): void
{
$dirty = $model->getDirty();
if (empty($dirty)) {
return;
}
$dirty = $this->filterValues($dirty);
$original = $this->filterValues(array_intersect_key($model->getOriginal(), $dirty));
if (empty($dirty)) {
return;
}
$causer = $this->getCauserName();
$id = $model->getKey();
$fields = implode(', ', array_keys($dirty));
$this->log(
event: 'updated',
logName: $logName,
description: "$causer cập nhật $logName" . ($id ? " #$id" : '') . " [$fields]",
subject: $model,
oldValues: $original,
newValues: $dirty,
);
}
public function logDeleted(Model $model, string $logName): void
{
$causer = $this->getCauserName();
$id = $model->getOriginal($model->getKeyName()) ?? $model->getKey();
$this->log(
event: 'deleted',
logName: $logName,
description: "$causer xóa $logName" . ($id ? " #$id" : ''),
subject: $model,
);
}
public function logRestored(Model $model, string $logName): void
{
$causer = $this->getCauserName();
$id = $model->getKey();
$this->log(
event: 'restored',
logName: $logName,
description: "$causer khôi phục $logName" . ($id ? " #$id" : ''),
subject: $model,
);
}
public function logAuth(string $event, string $causerType, $causerId, string $causerName): void
{
$action = match ($event) {
'login' => 'đăng nhập',
'logout' => 'đăng xuất',
'register' => 'đăng ký tài khoản',
default => $event,
};
$this->log(
event: $event,
logName: 'auth',
description: "[$causerType] $causerName $action",
subject: null,
oldValues: [],
newValues: ['causer_type' => $causerType, 'causer_id' => $causerId, 'causer_name' => $causerName],
);
}
private function resolveCauser(): array
{
if ($admin = auth()->guard('admin')->user()) {
return ['admin', $admin->id, $admin->username ?? $admin->email];
}
if ($customer = auth()->guard('client')->user()) {
return ['customer', $customer->id, $customer->email ?? $customer->name];
}
return ['system', null, 'System'];
}
public function getCauserName(): string
{
[, , $name] = $this->resolveCauser();
return $name;
}
private function filterValues(array $values): array
{
return array_diff_key($values, array_flip($this->hiddenFields));
}
}