call(RolesAndPermissionsSeeder::class); $adminUser = User::firstOrCreate( ['email' => 'admin@example.com'], ['name' => 'Admin', 'password' => Hash::make('password'), 'approved_at' => now()] ); $adminUser->syncRoles(['admin']); // Usuarios extra solo para que las analíticas (sección "usuarios más activos") // tengan algo interesante que mostrar de entrada. $extraUsers = collect([ ['name' => 'Carla Gómez', 'email' => 'carla@example.com'], ['name' => 'Martín Ruiz', 'email' => 'martin@example.com'], ['name' => 'Bea Fernández', 'email' => 'bea@example.com'], ])->map(function (array $data) { $u = User::firstOrCreate(['email' => $data['email']], ['name' => $data['name'], 'password' => Hash::make('password'), 'approved_at' => now()]); $u->syncRoles(['user']); return $u; }); // Usuario de ejemplo que se autorregistró y todavía nadie aprobó, para // que la pestaña "Pendientes" del panel de usuarios no arranque vacía. User::firstOrCreate( ['email' => 'nuevo@example.com'], ['name' => 'Nuevo Registro', 'password' => Hash::make('password'), 'approved_at' => null] )->assignRole('user'); // Cliente requerido para poder emitir Personal Access Tokens (grant "personal_access"). if (! Client::where('personal_access_client', true)->exists()) { $clients->createPersonalAccessGrantClient('Personal Access Client'); } // Cliente de demo para el flujo Authorization Code + PKCE (público, sin secret). $pkceClient = $adminUser->oauthApps()->firstOrCreate( ['name' => 'Demo SPA (Authorization Code + PKCE)'], [ 'secret' => null, 'redirect_uris' => ['http://localhost:8000/callback'], 'grant_types' => ['authorization_code', 'refresh_token'], 'revoked' => false, ] ); // Cliente de demo para Client Credentials (machine-to-machine). $ccClient = $adminUser->oauthApps()->firstOrCreate( ['name' => 'Demo Service (Client Credentials)'], [ 'secret' => Str::random(40), 'redirect_uris' => [], 'grant_types' => ['client_credentials'], 'revoked' => false, ] ); // Cliente de demo para Password Grant. $pwClient = $adminUser->oauthApps()->firstOrCreate( ['name' => 'Demo First-Party App (Password Grant)'], [ 'secret' => Str::random(40), 'redirect_uris' => [], 'grant_types' => ['password', 'refresh_token'], 'revoked' => false, ] ); // Cliente confidencial para probar el botón "Authorize" de Swagger UI // (usa /api/oauth2-callback, que ya registra L5-Swagger). $swaggerClient = $adminUser->oauthApps()->firstOrCreate( ['name' => 'Swagger UI'], [ 'secret' => Str::random(40), 'redirect_uris' => [rtrim(config('app.url'), '/').'/api/oauth2-callback'], 'grant_types' => ['authorization_code', 'client_credentials', 'refresh_token'], 'revoked' => false, ] ); // Rol por-app de ejemplo: carla@example.com es "admin" dentro de la app // "Demo SPA", aunque globalmente sea un usuario normal. Muestra que el // rol puede variar según qué app pregunte por el usuario. DB::table('app_user_roles')->insertOrIgnore([ 'user_id' => $extraUsers->first()->id, 'client_id' => $pkceClient->id, 'role' => 'admin', 'created_at' => now(), 'updated_at' => now(), ]); if (! LoginEvent::query()->exists()) { $this->seedLoginEvents( $extraUsers->push($adminUser), collect([$pkceClient, $ccClient, $pwClient, $swaggerClient]), ); } $this->command?->info('Admin: admin@example.com / password'); $this->command?->info('Client Credentials -> client_id: '.$ccClient->id.' secret: '.($ccClient->plainSecret ?? '(ya existía, ver DB)')); $this->command?->info('Password Grant -> client_id: '.$pwClient->id.' secret: '.($pwClient->plainSecret ?? '(ya existía, ver DB)')); $this->command?->info('Swagger UI -> client_id: '.$swaggerClient->id.' secret: '.($swaggerClient->plainSecret ?? '(ya existía, ver DB)')); } /** * Historial sintético de logins (últimos 30 días) para que la pantalla de * analíticas tenga algo real que graficar apenas se levanta la app. * * @param \Illuminate\Support\Collection $users * @param \Illuminate\Support\Collection $clients */ private function seedLoginEvents($users, $clients): void { $rows = []; $now = now(); for ($daysAgo = 29; $daysAgo >= 0; $daysAgo--) { $dayStart = $now->copy()->subDays($daysAgo)->startOfDay(); $maxMinute = $daysAgo === 0 ? $now->diffInMinutes($dayStart) : 1439; $isWeekend = $dayStart->isWeekend(); $oauthLogins = random_int($isWeekend ? 1 : 4, $isWeekend ? 6 : 14); $sessionLogins = random_int($isWeekend ? 0 : 1, $isWeekend ? 2 : 5); for ($i = 0; $i < $oauthLogins; $i++) { $rows[] = [ 'user_id' => $users->random()->id, 'client_id' => $clients->random()->id, 'type' => 'oauth', 'ip_address' => '10.0.'.random_int(0, 9).'.'.random_int(2, 254), 'user_agent' => 'Mozilla/5.0 (demo seed)', 'created_at' => $dayStart->copy()->addMinutes(random_int(0, max(0, $maxMinute))), ]; } for ($i = 0; $i < $sessionLogins; $i++) { $rows[] = [ 'user_id' => $users->random()->id, 'client_id' => null, 'type' => 'session', 'ip_address' => '10.0.'.random_int(0, 9).'.'.random_int(2, 254), 'user_agent' => 'Mozilla/5.0 (demo seed)', 'created_at' => $dayStart->copy()->addMinutes(random_int(0, max(0, $maxMinute))), ]; } } foreach (array_chunk($rows, 200) as $chunk) { LoginEvent::insert($chunk); } } }