feat: implement system-wide activity logging with database persistence, repository patterns, and admin controller access.
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Admin\ActivityLog;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\ActivityLog;
|
||||
use App\Repositories\ActivityLog\ActivityLogRepositoryInterface;
|
||||
use App\Support\Cache\CacheKey;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class ActivityLogController extends Controller
|
||||
{
|
||||
private const CACHE_TTL = 60; // seconds
|
||||
|
||||
public function __construct(
|
||||
private readonly ActivityLogRepositoryInterface $activityLogRepository,
|
||||
) {}
|
||||
|
||||
public function index(Request $request): JsonResponse
|
||||
{
|
||||
$perPage = min((int) $request->get('per_page', 20), 200);
|
||||
|
||||
$filters = $request->only([
|
||||
'log_name',
|
||||
'event',
|
||||
'causer_type',
|
||||
'causer_id',
|
||||
'causer_name',
|
||||
'subject_type',
|
||||
'subject_id',
|
||||
'ip_address',
|
||||
'date_from',
|
||||
'date_to',
|
||||
'search',
|
||||
'page',
|
||||
]);
|
||||
|
||||
$cacheKey = CacheKey::build('activity_logs', 'list', array_merge(
|
||||
$filters,
|
||||
['per_page' => $perPage, 'page' => (int) $request->get('page', 1)]
|
||||
));
|
||||
|
||||
$data = Cache::remember($cacheKey, self::CACHE_TTL, function () use ($filters, $perPage) {
|
||||
$paginator = $this->activityLogRepository->filter($filters, $perPage);
|
||||
|
||||
return [
|
||||
'items' => $paginator->items(),
|
||||
'total' => $paginator->total(),
|
||||
'per_page' => $paginator->perPage(),
|
||||
'current_page' => $paginator->currentPage(),
|
||||
'last_page' => $paginator->lastPage(),
|
||||
];
|
||||
});
|
||||
|
||||
return response()->json(['error' => false, 'data' => $data]);
|
||||
}
|
||||
|
||||
public function show(int $id): JsonResponse
|
||||
{
|
||||
$cacheKey = CacheKey::build('activity_logs', 'detail', ['id' => $id]);
|
||||
|
||||
$log = Cache::remember($cacheKey, self::CACHE_TTL * 5, function () use ($id) {
|
||||
return $this->activityLogRepository->find($id);
|
||||
});
|
||||
|
||||
if (!$log) {
|
||||
return response()->json(['error' => true, 'message' => 'Không tìm thấy log'], 404);
|
||||
}
|
||||
|
||||
return response()->json(['error' => false, 'data' => $log]);
|
||||
}
|
||||
|
||||
public function modules(): JsonResponse
|
||||
{
|
||||
$cacheKey = CacheKey::build('activity_logs', 'modules');
|
||||
|
||||
$modules = Cache::remember($cacheKey, self::CACHE_TTL * 10, function () {
|
||||
return ActivityLog::query()
|
||||
->select('log_name')
|
||||
->distinct()
|
||||
->orderBy('log_name')
|
||||
->pluck('log_name');
|
||||
});
|
||||
|
||||
return response()->json(['error' => false, 'data' => $modules]);
|
||||
}
|
||||
|
||||
public function stats(): JsonResponse
|
||||
{
|
||||
$cacheKey = CacheKey::build('activity_logs', 'stats');
|
||||
|
||||
$stats = Cache::remember($cacheKey, self::CACHE_TTL * 2, function () {
|
||||
return [
|
||||
'total' => ActivityLog::count(),
|
||||
'today' => ActivityLog::whereDate('created_at', today())->count(),
|
||||
'by_event' => ActivityLog::selectRaw('event, COUNT(*) as count')
|
||||
->groupBy('event')
|
||||
->orderByDesc('count')
|
||||
->limit(10)
|
||||
->pluck('count', 'event'),
|
||||
'by_causer' => ActivityLog::selectRaw('causer_type, COUNT(*) as count')
|
||||
->groupBy('causer_type')
|
||||
->pluck('count', 'causer_type'),
|
||||
];
|
||||
});
|
||||
|
||||
return response()->json(['error' => false, 'data' => $stats]);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api\Admin\Auth;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\Api\Admin\AdminUserResource;
|
||||
use App\Services\ActivityLogger;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
@@ -12,6 +13,8 @@ use Tymon\JWTAuth\Exceptions\JWTException;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
public function __construct(private readonly ActivityLogger $activityLogger) {}
|
||||
|
||||
public function login(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
@@ -22,6 +25,11 @@ class AuthController extends Controller
|
||||
$token = Auth::guard('admin')->attempt($request->only('username', 'password'));
|
||||
|
||||
if (!$token) {
|
||||
$this->activityLogger->log(
|
||||
event: 'login_failed',
|
||||
logName: 'auth',
|
||||
description: '[admin] Đăng nhập thất bại với username: ' . $request->username,
|
||||
);
|
||||
return response()->json([
|
||||
'error' => true,
|
||||
'message' => 'Thông tin đăng nhập không chính xác.',
|
||||
@@ -30,6 +38,8 @@ class AuthController extends Controller
|
||||
|
||||
$user = Auth::guard('admin')->user();
|
||||
|
||||
$this->activityLogger->logAuth('login', 'admin', $user->id, $user->username ?? $user->email);
|
||||
|
||||
return response()->json([
|
||||
'error' => false,
|
||||
'data' => [
|
||||
@@ -76,6 +86,11 @@ class AuthController extends Controller
|
||||
|
||||
public function logout(): JsonResponse
|
||||
{
|
||||
$user = Auth::guard('admin')->user();
|
||||
if ($user) {
|
||||
$this->activityLogger->logAuth('logout', 'admin', $user->id, $user->username ?? $user->email);
|
||||
}
|
||||
|
||||
Auth::guard('admin')->logout();
|
||||
|
||||
return response()->json([
|
||||
|
||||
Reference in New Issue
Block a user