* fix: keep post drafts unscheduled by default * Align schedule validation and keep drafts unscheduled. Require scheduled_at only when status is scheduled and the post has no usable future schedule. Share that rule across web, API, and MCP, keep create without a date as null, and preserve the legacy date → 09:00 UTC fallback. * Polish schedule validation typing and tests. Type requiresExplicitSchedule status as ?string, reuse a local status variable in request/tool validation, tighten the web reject assertion, and collapse overlapping MCP unscheduled-create cases. * Centralize status helper in post update validation. Reuse the typed status() helper across FormRequests and the already-parsed $status in UpdatePostTool so schedule checks stay consistent and less noisy. * Share scheduled_at update rules across web, API, and MCP. Centralize schedule validation in PostStatusRules, normalize status parsing in one place, and align past-schedule coverage across entry points. * Cover the full unscheduled-draft checklist in Pest. Add feature coverage for null/past schedule rejection, explicit scheduling, draft saves, publish-now without a schedule, calendar exclusion, and 09:00 UTC date defaults across web, API, and MCP. * Remove normalizeStatus helper. Keep the inline is_string check at the few call sites that read raw request status before validation — no shared wrapper needed. Co-authored-by: Cursor <cursoragent@cursor.com> * Drop is_string status guards from schedule validation. Accept mixed status in PostStatusRules and rely on strict comparisons with Rule::requiredIf / Rule::when — malformed input simply does not match. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Paulo Castellano <paulo@castellanos.llc>
66 lines
2.2 KiB
PHP
66 lines
2.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Enums\Post\Status as PostStatus;
|
|
use App\Models\Post;
|
|
use App\Support\PostStatusRules;
|
|
|
|
test('blocks editing for terminal statuses', function (PostStatus $status) {
|
|
$post = Post::factory()->make(['status' => $status]);
|
|
|
|
expect(PostStatusRules::blocksEditing($post))->toBeTrue();
|
|
})->with([
|
|
PostStatus::Publishing,
|
|
PostStatus::Published,
|
|
PostStatus::PartiallyPublished,
|
|
PostStatus::Failed,
|
|
]);
|
|
|
|
test('allows editing for non terminal statuses', function (PostStatus $status) {
|
|
$post = Post::factory()->make(['status' => $status]);
|
|
|
|
expect(PostStatusRules::blocksEditing($post))->toBeFalse();
|
|
})->with([
|
|
PostStatus::Draft,
|
|
PostStatus::Scheduled,
|
|
]);
|
|
|
|
test('blocks deletion for published statuses', function (PostStatus $status) {
|
|
$post = Post::factory()->make(['status' => $status]);
|
|
|
|
expect(PostStatusRules::blocksDeletion($post))->toBeTrue();
|
|
})->with([
|
|
PostStatus::Publishing,
|
|
PostStatus::Published,
|
|
PostStatus::PartiallyPublished,
|
|
]);
|
|
|
|
test('allows deletion for draft, scheduled and failed statuses', function (PostStatus $status) {
|
|
$post = Post::factory()->make(['status' => $status]);
|
|
|
|
expect(PostStatusRules::blocksDeletion($post))->toBeFalse();
|
|
})->with([
|
|
PostStatus::Draft,
|
|
PostStatus::Scheduled,
|
|
PostStatus::Failed,
|
|
]);
|
|
|
|
test('requires explicit schedule when status is scheduled and post has no usable schedule', function (?string $scheduledAt, bool $expected) {
|
|
$post = Post::factory()->make([
|
|
'scheduled_at' => $scheduledAt,
|
|
]);
|
|
|
|
expect(PostStatusRules::requiresExplicitSchedule($post, PostStatus::Scheduled->value))->toBe($expected);
|
|
})->with([
|
|
'missing schedule' => [null, true],
|
|
'past schedule' => [now()->subHour()->toDateTimeString(), true],
|
|
'future schedule' => [now()->addDay()->toDateTimeString(), false],
|
|
]);
|
|
|
|
test('does not require explicit schedule for non scheduled statuses', function () {
|
|
$post = Post::factory()->make(['scheduled_at' => null]);
|
|
|
|
expect(PostStatusRules::requiresExplicitSchedule($post, PostStatus::Draft->value))->toBeFalse()
|
|
->and(PostStatusRules::requiresExplicitSchedule(null, PostStatus::Scheduled->value))->toBeTrue();
|
|
});
|