Warn about calls closing and content coming off the site
A dashboard widget lists what expires in the next two weeks, and a daily command reminds whoever edits it a week and a day ahead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
83
app/Support/Expiring.php
Normal file
83
app/Support/Expiring.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Support;
|
||||
|
||||
use App\Enums\CallStatus;
|
||||
use App\Filament\Resources\Calls\CallResource;
|
||||
use App\Models\Call;
|
||||
use App\Models\Page;
|
||||
use App\Models\Project;
|
||||
use App\Models\Service;
|
||||
use App\Models\User;
|
||||
use Carbon\CarbonInterface;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* What is about to stop being true on the site: calls about to close, and
|
||||
* published content about to come off by itself.
|
||||
*
|
||||
* Neither is a mistake — both were set on purpose — which is why the health
|
||||
* check does not flag them. But a call that closes on Friday with nobody
|
||||
* having replied, or a page that vanishes on the first of the month, is better
|
||||
* known about a week ahead than found out after.
|
||||
*/
|
||||
final class Expiring
|
||||
{
|
||||
/**
|
||||
* @return Collection<int, array{type: string, record: Model, title: string, event: string, at: CarbonInterface, url: string}>
|
||||
*/
|
||||
public static function within(int $days): Collection
|
||||
{
|
||||
$until = now()->addDays($days)->endOfDay();
|
||||
$items = collect();
|
||||
|
||||
Call::query()
|
||||
->where('status', CallStatus::Open)
|
||||
->whereNotNull('closes_at')
|
||||
->whereBetween('closes_at', [now()->startOfDay(), $until])
|
||||
->get()
|
||||
->each(fn (Call $call) => $items->push(self::item('calls', $call, 'closes', $call->closes_at)));
|
||||
|
||||
foreach (['pages' => Page::class, 'projects' => Project::class, 'services' => Service::class] as $type => $model) {
|
||||
$model::query()
|
||||
->published()
|
||||
->whereNotNull('unpublish_at')
|
||||
->whereBetween('unpublish_at', [now(), $until])
|
||||
->get()
|
||||
->each(fn (Model $record) => $items->push(self::item($type, $record, 'unpublishes', $record->unpublish_at)));
|
||||
}
|
||||
|
||||
return $items->sortBy(fn (array $item) => $item['at']->getTimestamp())->values();
|
||||
}
|
||||
|
||||
/**
|
||||
* Only those this person may do something about.
|
||||
*
|
||||
* @param Collection<int, array<string, mixed>> $items
|
||||
* @return Collection<int, array<string, mixed>>
|
||||
*/
|
||||
public static function for(Collection $items, User $user): Collection
|
||||
{
|
||||
return $items->filter(fn (array $item) => $user->can('update', $item['record']))->values();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{type: string, record: Model, title: string, event: string, at: CarbonInterface, url: string}
|
||||
*/
|
||||
protected static function item(string $type, Model $record, string $event, CarbonInterface $at): array
|
||||
{
|
||||
return [
|
||||
'type' => $type,
|
||||
'record' => $record,
|
||||
'title' => ContentTypes::title($record),
|
||||
'event' => $event,
|
||||
'at' => $at,
|
||||
'url' => $record instanceof Call
|
||||
? CallResource::getUrl('edit', ['record' => $record])
|
||||
: ReviewTarget::url($record),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user