Initial commit: OAuth IAM Laravel application
Laravel-based OAuth/IAM service with Passport, Vue 3 frontend, and Docker Compose setup for local and production deployment. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
103
app/Support/AnalyticsSummary.php
Normal file
103
app/Support/AnalyticsSummary.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace App\Support;
|
||||
|
||||
use App\Models\LoginEvent;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Passport\Token;
|
||||
|
||||
/**
|
||||
* Agregación compartida por Admin\AnalyticsController (sesión) y
|
||||
* Api\AnalyticsController (token) — misma data, dos superficies de auth.
|
||||
*/
|
||||
class AnalyticsSummary
|
||||
{
|
||||
public static function build(int $days = 30): array
|
||||
{
|
||||
$since = Carbon::now()->subDays($days - 1)->startOfDay();
|
||||
|
||||
return [
|
||||
'kpis' => [
|
||||
'total_users' => User::count(),
|
||||
'active_sessions' => Token::query()->where('revoked', false)->where('expires_at', '>', now())->count(),
|
||||
'logins_today' => LoginEvent::whereDate('created_at', today())->count(),
|
||||
'logins_7d' => LoginEvent::where('created_at', '>=', now()->subDays(7))->count(),
|
||||
],
|
||||
'logins_by_day' => self::loginsByDay($since, $days),
|
||||
'logins_by_app' => self::loginsByApp($since),
|
||||
'top_users' => self::topUsers($since),
|
||||
'recent' => self::recent(),
|
||||
];
|
||||
}
|
||||
|
||||
private static function loginsByDay(Carbon $since, int $days): array
|
||||
{
|
||||
$rows = LoginEvent::query()
|
||||
->selectRaw("date(created_at) as day, type, count(*) as count")
|
||||
->where('created_at', '>=', $since)
|
||||
->groupBy('day', 'type')
|
||||
->get()
|
||||
->groupBy('day');
|
||||
|
||||
$out = [];
|
||||
for ($i = 0; $i < $days; $i++) {
|
||||
$date = $since->copy()->addDays($i)->toDateString();
|
||||
$dayRows = $rows->get($date, collect());
|
||||
|
||||
$out[] = [
|
||||
'date' => $date,
|
||||
'session' => (int) $dayRows->firstWhere('type', 'session')?->count,
|
||||
'oauth' => (int) $dayRows->firstWhere('type', 'oauth')?->count,
|
||||
];
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
private static function loginsByApp(Carbon $since): array
|
||||
{
|
||||
return LoginEvent::query()
|
||||
->join('oauth_clients', 'oauth_clients.id', '=', 'login_events.client_id')
|
||||
->where('login_events.type', 'oauth')
|
||||
->where('login_events.created_at', '>=', $since)
|
||||
->groupBy('oauth_clients.id', 'oauth_clients.name')
|
||||
->orderByDesc('count')
|
||||
->limit(8)
|
||||
->get(['oauth_clients.name as client_name', DB::raw('count(*) as count')])
|
||||
->toArray();
|
||||
}
|
||||
|
||||
private static function topUsers(Carbon $since): array
|
||||
{
|
||||
return LoginEvent::query()
|
||||
->join('users', 'users.id', '=', 'login_events.user_id')
|
||||
->where('login_events.created_at', '>=', $since)
|
||||
->groupBy('users.id', 'users.name', 'users.email')
|
||||
->orderByDesc('count')
|
||||
->limit(8)
|
||||
->get(['users.name', 'users.email', DB::raw('count(*) as count')])
|
||||
->toArray();
|
||||
}
|
||||
|
||||
private static function recent(int $limit = 15): array
|
||||
{
|
||||
return LoginEvent::with(['user:id,name,email', 'client:id,name'])
|
||||
->latest('created_at')
|
||||
->limit($limit)
|
||||
->get()
|
||||
->map(fn (LoginEvent $event) => [
|
||||
'user_name' => $event->user?->name,
|
||||
'user_email' => $event->user?->email,
|
||||
// null para logins de sesión (el frontend lo traduce como "Panel admin"/"Admin
|
||||
// panel" según el idioma) y para apps borradas (el frontend traduce ese caso
|
||||
// también) — así el backend no filtra texto sin traducir a la UI.
|
||||
'client_name' => $event->type === 'session' ? null : $event->client?->name,
|
||||
'type' => $event->type,
|
||||
'ip_address' => $event->ip_address,
|
||||
'created_at' => $event->created_at,
|
||||
])
|
||||
->toArray();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user