242 lines
8.7 KiB
PHP
242 lines
8.7 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class NeblogisticAuditService
|
|
{
|
|
/**
|
|
* Log an INSERT operation
|
|
*/
|
|
public static function logInsert($neblogisticId, $newData, Request $request = null)
|
|
{
|
|
return self::log('INSERT', $neblogisticId, null, $newData, $request);
|
|
}
|
|
|
|
/**
|
|
* Log an UPDATE operation
|
|
*/
|
|
public static function logUpdate($neblogisticId, $oldData, $newData, $changedFields = null, Request $request = null)
|
|
{
|
|
return self::log('UPDATE', $neblogisticId, $oldData, $newData, $request, $changedFields);
|
|
}
|
|
|
|
/**
|
|
* Log a DELETE operation
|
|
*/
|
|
public static function logDelete($neblogisticId, $oldData, Request $request = null)
|
|
{
|
|
return self::log('DELETE', $neblogisticId, $oldData, null, $request);
|
|
}
|
|
|
|
/**
|
|
* Main logging method
|
|
*/
|
|
protected static function log($action, $neblogisticId, $oldData = null, $newData = null, Request $request = null, $changedFields = null)
|
|
{
|
|
try {
|
|
$user = Auth::user();
|
|
$requestData = self::getRequestData($request);
|
|
|
|
// Get old record if not provided and it's an update/delete
|
|
if (in_array($action, ['UPDATE', 'DELETE']) && !$oldData && $neblogisticId) {
|
|
$oldData = DB::table('neblogistic')->where('id', $neblogisticId)->first();
|
|
if ($oldData) {
|
|
$oldData = json_decode(json_encode($oldData), true);
|
|
}
|
|
}
|
|
|
|
// Get new record if it's an insert/update
|
|
if (in_array($action, ['INSERT', 'UPDATE']) && !$newData && $neblogisticId) {
|
|
$newRecord = DB::table('neblogistic')->where('id', $neblogisticId)->first();
|
|
if ($newRecord) {
|
|
$newData = json_decode(json_encode($newRecord), true);
|
|
}
|
|
}
|
|
|
|
// Calculate changed fields if not provided
|
|
if ($action === 'UPDATE' && !$changedFields && $oldData && $newData) {
|
|
$changedFields = [];
|
|
foreach ($newData as $key => $value) {
|
|
$oldValue = $oldData[$key] ?? null;
|
|
if ($oldValue !== $value) {
|
|
$changedFields[$key] = [
|
|
'old' => $oldValue,
|
|
'new' => $value
|
|
];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Parse browser details
|
|
$browserDetails = self::parseUserAgent($requestData['user_agent'] ?? '');
|
|
|
|
$auditData = [
|
|
'neblogistic_id' => $neblogisticId,
|
|
'action' => $action,
|
|
'old_data' => $oldData ? json_encode($oldData) : null,
|
|
'new_data' => $newData ? json_encode($newData) : null,
|
|
'changed_fields' => $changedFields ? json_encode($changedFields) : null,
|
|
'user_id' => $user ? $user->id : null,
|
|
'user_email' => $user ? ($user->email ?? null) : null,
|
|
'user_name' => $user ? ($user->name ?? null) : null,
|
|
'ip_address' => $requestData['ip'],
|
|
'user_agent' => $requestData['user_agent'],
|
|
'browser_details' => json_encode($browserDetails),
|
|
'request_url' => $requestData['url'],
|
|
'request_method' => $requestData['method'],
|
|
'created_at' => now(),
|
|
];
|
|
|
|
DB::table('neblogistic_audit_trail')->insert($auditData);
|
|
|
|
return true;
|
|
} catch (\Exception $e) {
|
|
// Log error but don't break the main operation
|
|
Log::error('Neblogistic audit trail logging failed: ' . $e->getMessage(), [
|
|
'action' => $action,
|
|
'neblogistic_id' => $neblogisticId,
|
|
'exception' => $e
|
|
]);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get request data safely
|
|
*/
|
|
protected static function getRequestData($request = null)
|
|
{
|
|
if (!$request && request()) {
|
|
$request = request();
|
|
}
|
|
|
|
if (!$request) {
|
|
return [
|
|
'ip' => null,
|
|
'user_agent' => null,
|
|
'url' => null,
|
|
'method' => null,
|
|
];
|
|
}
|
|
|
|
return [
|
|
'ip' => $request->ip() ??
|
|
$request->header('X-Forwarded-For') ??
|
|
$request->server('REMOTE_ADDR') ??
|
|
'unknown',
|
|
'user_agent' => $request->header('User-Agent'),
|
|
'url' => $request->fullUrl(),
|
|
'method' => $request->method(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Parse user agent to extract browser details
|
|
*/
|
|
protected static function parseUserAgent($userAgent)
|
|
{
|
|
if (empty($userAgent)) {
|
|
return [
|
|
'browser' => 'Unknown',
|
|
'browser_version' => null,
|
|
'platform' => 'Unknown',
|
|
'device' => 'Unknown',
|
|
];
|
|
}
|
|
|
|
$details = [
|
|
'browser' => 'Unknown',
|
|
'browser_version' => null,
|
|
'platform' => 'Unknown',
|
|
'device' => 'Unknown',
|
|
];
|
|
|
|
// Detect browser
|
|
if (preg_match('/MSIE|Trident/i', $userAgent)) {
|
|
$details['browser'] = 'Internet Explorer';
|
|
if (preg_match('/MSIE\s([\d.]+)/', $userAgent, $matches)) {
|
|
$details['browser_version'] = $matches[1];
|
|
}
|
|
} elseif (preg_match('/Edge/i', $userAgent)) {
|
|
$details['browser'] = 'Microsoft Edge';
|
|
if (preg_match('/Edge\/([\d.]+)/', $userAgent, $matches)) {
|
|
$details['browser_version'] = $matches[1];
|
|
}
|
|
} elseif (preg_match('/Chrome/i', $userAgent) && !preg_match('/Edge/i', $userAgent)) {
|
|
$details['browser'] = 'Chrome';
|
|
if (preg_match('/Chrome\/([\d.]+)/', $userAgent, $matches)) {
|
|
$details['browser_version'] = $matches[1];
|
|
}
|
|
} elseif (preg_match('/Firefox/i', $userAgent)) {
|
|
$details['browser'] = 'Firefox';
|
|
if (preg_match('/Firefox\/([\d.]+)/', $userAgent, $matches)) {
|
|
$details['browser_version'] = $matches[1];
|
|
}
|
|
} elseif (preg_match('/Safari/i', $userAgent) && !preg_match('/Chrome/i', $userAgent)) {
|
|
$details['browser'] = 'Safari';
|
|
if (preg_match('/Version\/([\d.]+)/', $userAgent, $matches)) {
|
|
$details['browser_version'] = $matches[1];
|
|
}
|
|
} elseif (preg_match('/Opera|OPR/i', $userAgent)) {
|
|
$details['browser'] = 'Opera';
|
|
if (preg_match('/(?:Opera|OPR)\/([\d.]+)/', $userAgent, $matches)) {
|
|
$details['browser_version'] = $matches[1];
|
|
}
|
|
}
|
|
|
|
// Detect platform
|
|
if (preg_match('/Windows/i', $userAgent)) {
|
|
$details['platform'] = 'Windows';
|
|
} elseif (preg_match('/Macintosh|Mac OS X/i', $userAgent)) {
|
|
$details['platform'] = 'macOS';
|
|
} elseif (preg_match('/Linux/i', $userAgent)) {
|
|
$details['platform'] = 'Linux';
|
|
} elseif (preg_match('/Android/i', $userAgent)) {
|
|
$details['platform'] = 'Android';
|
|
} elseif (preg_match('/iPhone|iPad|iPod/i', $userAgent)) {
|
|
$details['platform'] = 'iOS';
|
|
}
|
|
|
|
// Detect device
|
|
if (preg_match('/Mobile|Android|iPhone|iPad/i', $userAgent)) {
|
|
if (preg_match('/iPad/i', $userAgent)) {
|
|
$details['device'] = 'Tablet';
|
|
} elseif (preg_match('/iPhone|iPod/i', $userAgent)) {
|
|
$details['device'] = 'Mobile';
|
|
} elseif (preg_match('/Android/i', $userAgent)) {
|
|
$details['device'] = preg_match('/Mobile/i', $userAgent) ? 'Mobile' : 'Tablet';
|
|
} else {
|
|
$details['device'] = 'Mobile';
|
|
}
|
|
} else {
|
|
$details['device'] = 'Desktop';
|
|
}
|
|
|
|
return $details;
|
|
}
|
|
|
|
/**
|
|
* Clean up old audit logs (older than specified months)
|
|
*/
|
|
public static function cleanupOldLogs($months = 6)
|
|
{
|
|
try {
|
|
$cutoffDate = now()->subMonths($months);
|
|
$deleted = DB::table('neblogistic_audit_trail')
|
|
->where('created_at', '<', $cutoffDate)
|
|
->delete();
|
|
|
|
Log::info("Cleaned up {$deleted} old neblogistic audit trail records older than {$months} months");
|
|
return $deleted;
|
|
} catch (\Exception $e) {
|
|
Log::error('Failed to cleanup neblogistic audit trail logs: ' . $e->getMessage());
|
|
return 0;
|
|
}
|
|
}
|
|
}
|