MIF_E31230069/spk_kontrakan/app/Models/ActivityLog.php

224 lines
7.0 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Support\Facades\Storage;
class ActivityLog extends Model
{
use HasFactory;
protected $fillable = [
'user_id',
'action',
'description',
'model_type',
'model_id',
'old_values',
'new_values',
'ip_address',
'user_agent',
];
protected $casts = [
'old_values' => 'array',
'new_values' => 'array',
'created_at' => 'datetime',
];
public function user()
{
return $this->belongsTo(User::class);
}
// Polymorphic relationship for better flexibility
public function loggable()
{
return $this->morphTo('model', 'model_type', 'model_id');
}
// Performance Query Scopes
public function scopeRecent($query, $days = 30)
{
return $query->where('created_at', '>=', now()->subDays($days));
}
public function scopeByAction($query, $action)
{
return $query->where('action', $action);
}
public function scopeByUser($query, $userId)
{
return $query->where('user_id', $userId);
}
public function scopeByModel($query, $modelType)
{
return $query->where('model_type', $modelType);
}
public static function log($action, $description, $modelType = null, $modelId = null, $oldValues = null, $newValues = null)
{
$userId = auth()->id();
if ($userId && ! User::query()->whereKey($userId)->exists()) {
$userId = null;
}
return self::create([
'user_id' => $userId,
'action' => $action,
'description' => $description,
'model_type' => $modelType,
'model_id' => $modelId,
'old_values' => $oldValues,
'new_values' => $newValues,
'ip_address' => request()->ip(),
'user_agent' => request()->userAgent(),
]);
}
// Security & Monitoring Enhancement
public static function detectSuspiciousActivity($userId, $threshold = 50)
{
$recentActivity = self::where('user_id', $userId)
->where('created_at', '>=', now()->subHour())
->count();
return $recentActivity > $threshold;
}
public static function logFailedAction($action, $reason, $ip = null)
{
return self::create([
'user_id' => null,
'action' => 'failed_' . $action,
'description' => "Failed: $reason",
'model_type' => null,
'model_id' => null,
'old_values' => null,
'new_values' => null,
'ip_address' => $ip ?: request()->ip(),
'user_agent' => request()->userAgent(),
]);
}
public static function getSecurityStats()
{
return [
'failed_attempts_today' => self::where('action', 'like', 'failed_%')
->whereDate('created_at', today())
->count(),
'unique_ips_today' => self::whereDate('created_at', today())
->distinct('ip_address')
->count('ip_address'),
'suspicious_users' => self::select('user_id')
->where('created_at', '>=', now()->subHour())
->groupBy('user_id')
->havingRaw('COUNT(*) > 50')
->pluck('user_id')
];
}
// Data Lifecycle Management
public static function cleanup($keepDays = 365)
{
return self::where('created_at', '<', now()->subDays($keepDays))->delete();
}
public static function archiveOldLogs($keepDays = 365)
{
$oldLogs = self::where('created_at', '<', now()->subDays($keepDays))->get();
if ($oldLogs->count() > 0) {
$filename = 'activity_logs_archive_' . date('Y_m_d_His') . '.json';
Storage::put("archives/$filename", $oldLogs->toJson());
$deleted = self::where('created_at', '<', now()->subDays($keepDays))->delete();
return [
'archived_file' => $filename,
'archived_count' => $oldLogs->count(),
'deleted_count' => $deleted
];
}
return ['archived_count' => 0, 'deleted_count' => 0];
}
// Dashboard Statistics
public static function getSummaryStats($userId = null)
{
$baseQuery = $userId ? self::where('user_id', $userId) : self::query();
return [
'total_actions' => (clone $baseQuery)->count(),
'today_actions' => (clone $baseQuery)->whereDate('created_at', today())->count(),
'this_week_actions' => (clone $baseQuery)->where('created_at', '>=', now()->startOfWeek())->count(),
'this_month_actions' => (clone $baseQuery)->whereMonth('created_at', now()->month)->count(),
'most_common_action' => self::select('action')
->groupBy('action')
->orderByRaw('count(*) desc')
->value('action'),
'actions_breakdown' => self::select('action')
->selectRaw('count(*) as count')
->groupBy('action')
->orderByRaw('count(*) desc')
->pluck('count', 'action'),
'recent_activity' => (clone $baseQuery)->with('user')
->latest()
->limit(10)
->get()
];
}
public static function getModelStats()
{
return [
'models_breakdown' => self::whereNotNull('model_type')
->select('model_type')
->selectRaw('count(*) as count')
->groupBy('model_type')
->orderByRaw('count(*) desc')
->pluck('count', 'model_type'),
'daily_activity' => self::selectRaw('DATE(created_at) as date, count(*) as count')
->where('created_at', '>=', now()->subDays(30))
->groupBy('date')
->orderBy('date')
->pluck('count', 'date')
];
}
// Utility Methods
public static function getTopUsers($limit = 10)
{
return self::with('user')
->select('user_id')
->selectRaw('count(*) as activity_count')
->whereNotNull('user_id')
->groupBy('user_id')
->orderByRaw('count(*) desc')
->limit($limit)
->get();
}
public static function getActivityByTimeRange($startDate, $endDate, $groupBy = 'day')
{
$format = match($groupBy) {
'hour' => '%Y-%m-%d %H:00:00',
'day' => '%Y-%m-%d',
'month' => '%Y-%m',
default => '%Y-%m-%d'
};
return self::selectRaw("DATE_FORMAT(created_at, '$format') as period, count(*) as count")
->whereBetween('created_at', [$startDate, $endDate])
->groupBy('period')
->orderBy('period')
->pluck('count', 'period');
}
}