option('dry-run'); $limit = max(1, (int) $this->option('limit')); $now = now(); // Gelb und Grün gehen zum Termin automatisch live (Decision-Update // §5.0); nur Rot wird abgelehnt. Unklassifizierte PMs bleiben als // Fallback in der manuellen Queue. $candidates = PressRelease::withoutGlobalScopes() ->where('status', PressReleaseStatus::Review->value) ->whereIn('classification', [ PressReleaseClassification::Green->value, PressReleaseClassification::Yellow->value, ]) ->whereNotNull('scheduled_at') ->where('scheduled_at', '<=', $now) ->orderBy('scheduled_at') ->limit($limit) ->get(); if ($candidates->isEmpty()) { $this->info('Keine fälligen geplanten Pressemitteilungen gefunden.'); return self::SUCCESS; } $this->info(sprintf( '%d fällige Pressemitteilung(en) gefunden.%s', $candidates->count(), $dryRun ? ' (Dry-Run)' : '', )); $published = 0; $rejected = 0; $failed = 0; foreach ($candidates as $pressRelease) { $line = sprintf( ' #%d scheduled_at=%s title="%s"', $pressRelease->id, $pressRelease->scheduled_at?->format('Y-m-d H:i') ?? '-', Str::limit($pressRelease->title, 60), ); if ($dryRun) { $this->line($line.' [DRY]'); continue; } try { $service->publish($pressRelease, source: 'scheduler'); $published++; $this->line($line.' [OK]'); } catch (BlacklistViolationException $e) { $rejected++; $this->warn($line.' [REJECT: '.$e->word.']'); } catch (Throwable $e) { $failed++; $this->error($line.' [FAIL: '.$e->getMessage().']'); report($e); } } if (! $dryRun) { $this->newLine(); $this->info(sprintf( 'Fertig: %d veröffentlicht, %d wegen Blacklist abgelehnt, %d fehlgeschlagen.', $published, $rejected, $failed, )); } return self::SUCCESS; } }