Files
landing-api/app/Console/Commands/ScheduleContentCommand.php
Josep Piguillem 3897113313 Initial commit: Pireon Admin — headless admin panel and public API
Laravel 13 + Filament 5 admin panel and REST API for a non-profit developer
collective, backed by the Pireon OAuth identity server. The public site is a
separate, server-rendered application consuming /api/public/v1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 17:55:27 +02:00

83 lines
2.8 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Console\Commands;
use App\Enums\CallStatus;
use App\Models\Call;
use App\Models\Page;
use App\Models\Project;
use Illuminate\Console\Command;
/**
* Keeps the stored state honest about what the site is actually showing.
*
* Most of scheduling needs no command at all: the `published` scopes read the
* dates, so content appears and disappears on time whether or not anything is
* running. What a scope cannot do is change what the panel *says*, and a panel
* that reports "Open" for a call the site stopped offering weeks ago is how a
* counter stops being read.
*
* So this closes what has expired and leaves everything else alone. In
* particular it does not touch the status of pages or projects: their window
* already hides them, and rewriting a status would throw away the one somebody
* chose in order to record something the dates already say.
*/
class ScheduleContentCommand extends Command
{
protected $signature = 'content:schedule
{--dry-run : Report what would change without changing it}';
protected $description = 'Close calls past their date and report content entering or leaving the site';
public function handle(): int
{
$expired = Call::query()
->where('status', CallStatus::Open)
->whereNotNull('closes_at')
->where('closes_at', '<', now())
->get();
foreach ($expired as $call) {
$title = $call->getTranslation('title', (string) config('locales.default'), false);
$this->components->twoColumnDetail(
$title ?: "#{$call->id}",
'<fg=gray>'.__('console.schedule.closed').'</>',
);
if (! $this->option('dry-run')) {
$call->update(['status' => CallStatus::Closed]);
}
}
$this->report();
$this->components->info(
trans_choice('console.schedule.summary', $expired->count(), ['count' => $expired->count()])
);
return self::SUCCESS;
}
/**
* What the dates are about to do on their own. Nothing here needs acting
* on; it is here so that a scheduled release is visible in the logs before
* it happens rather than only afterwards.
*/
protected function report(): void
{
$pending = Page::query()->scheduled()->count() + Project::query()->scheduled()->count();
$expiring = Page::query()->expired()->count() + Project::query()->expired()->count();
if ($pending > 0) {
$this->components->twoColumnDetail(__('console.schedule.pending'), (string) $pending);
}
if ($expiring > 0) {
$this->components->twoColumnDetail(__('console.schedule.off_site'), (string) $expiring);
}
}
}