option('dry-run'); $portal = $this->option('portal'); $limit = (int) $this->option('limit'); $query = User::query() ->where('is_active', true) ->whereNotNull('email') ->when($portal, fn ($q) => $q->where('portal', $portal)); $total = $query->count(); $this->info("Aktive Benutzer gefunden: {$total}"); if ($portal) { $this->line(" → Portal-Filter: {$portal}"); } if ($limit > 0) { $this->line(" → Limit: {$limit}"); $query->limit($limit); $total = min($total, $limit); } if ($isDryRun) { $this->warn("[DRY-RUN] Es würden {$total} Mails versendet. Kein tatsächlicher Versand."); return self::SUCCESS; } if (! $this->option('force') && ! $this->confirm("Jetzt {$total} Go-Live-Mails senden?")) { $this->info('Abgebrochen.'); return self::SUCCESS; } $sent = 0; $failed = 0; $bar = $this->output->createProgressBar($total); $bar->start(); $query->each(function (User $user) use (&$sent, &$failed, $bar): void { try { $token = Password::broker()->createToken($user); $resetUrl = url(route('password.reset', [ 'token' => $token, 'email' => $user->email, ], false)); Mail::to($user->email)->send( new GoLivePasswordReset($user, $resetUrl, self::EXPIRES_IN_MINUTES) ); $sent++; } catch (\Throwable $e) { $failed++; $this->newLine(); $this->error("Fehler für {$user->email}: {$e->getMessage()}"); } $bar->advance(); }); $bar->finish(); $this->newLine(2); $this->info("Versendet: {$sent}"); if ($failed > 0) { $this->warn("Fehlgeschlagen: {$failed}"); } return $failed > 0 ? self::FAILURE : self::SUCCESS; } }