Skip to content

Conversation

@ljonesfl
Copy link
Member

@ljonesfl ljonesfl commented Jan 16, 2026

Note

Adds scheduling and improves publishing/slug workflows across UI, DTOs, and services.

  • UI (resources/views/admin/posts/{create,edit}.php): add scheduled status; show published_at field for published|scheduled; enforce client-side check that scheduled posts include a date; make slug optional with [a-z0-9-]+ pattern and auto-generate from title with manual override.
  • DTOs (create-post-request.yaml, update-post-request.yaml): add published_at (datetime-local pattern) and include scheduled in status enum.
  • Services (Post/Creator.php, Post/Updater.php): require published_at for scheduled; parse dates with parseDateTime (throws on invalid); if published without a date, auto-set to now (preserves existing date on update); continue generating slug when absent.
  • Tests: add unit tests covering scheduled-post validation, invalid date parsing, and published_at behavior on create/update.

Written by Cursor Bugbot for commit 4265a66. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • New Features

    • "Scheduled" post status and a Published Date/Time field (shown for Published/Scheduled).
    • Auto-generate slug from title with manual-edit support; slug pattern and helper text updated.
    • Server-side create/update accept an optional published date.
  • Bug Fixes / Validation

    • Prevent saving a post as Scheduled without a published date; initialize published-date visibility on load; client-side validation added.
  • Tests

    • Added unit tests for scheduled-post validation and published-date handling.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 16, 2026

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Adds scheduled-post support: UI changes for slug and a Published Date/Time field, DTOs accept optional published_at, services enforce/parse published_at for scheduled/published statuses, and unit tests cover validation and parsing behaviors.

Changes

Cohort / File(s) Change summary
Admin views
resources/views/admin/posts/create.php, resources/views/admin/posts/edit.php
Added slug pattern and auto-generation behavior; added "Scheduled" status option; introduced published_at UI (published-at-wrapper, #published_at); client-side show/hide and validation for scheduled posts. Note: edit.php contains duplicated client-side logic.
DTOs
src/Cms/Dtos/posts/create-post-request.yaml, src/Cms/Dtos/posts/update-post-request.yaml
Added optional published_at string field with pattern enforcing YYYY-MM-DDTHH:MM or empty.
Post services
src/Cms/Services/Post/Creator.php, src/Cms/Services/Post/Updater.php
Extract published_at; parse and validate datetime; enforce that SCHEDULED status requires a published date; set PublishedAt based on provided value or now for PUBLISHED; added parseDateTime helper and error handling.
Unit tests
tests/Unit/Cms/Services/Post/CreatorTest.php, tests/Unit/Cms/Services/Post/UpdaterTest.php
Added publishedAt support in DTO builders; new tests for scheduled-post validation, valid scheduled publish dates, and various invalid date-format cases; updated helper signatures.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Browser
participant AdminUI as "Admin UI (create/edit)"
participant Server as "Controller → Creator/Updater"
participant Service as "Post Service (Creator/Updater)"
participant DB as "Database"

Browser->>AdminUI: fill title/slug/status/published_at
AdminUI-->>Browser: auto-generate slug; validate published_at when status=Scheduled
AdminUI->>Server: submit form (includes published_at)
Server->>Service: create/update post DTO (includes published_at)
Service->>Service: parseDateTime(published_at) / validate for SCHEDULED
alt published_at valid or status=PUBLISHED without published_at
Service->>DB: persist post with PublishedAt set
DB-->>Service: success
Service-->>Server: success response
Server-->>Browser: redirect/confirm
else invalid or missing for SCHEDULED
Service-->>Server: throw InvalidArgumentException
Server-->>Browser: validation error shown
end

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

"I nibble at slugs and dates with glee,
A scheduled hop from draft to be,
Title to slug, time set just right,
I stamp the clock and tuck it tight.
🐇✨"

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title mentions 'editing post pubished dates' and 'auto updates post slug', which are real parts of the changeset. However, the primary focus is scheduled posting functionality with comprehensive validation and service logic, making the title incomplete and not fully representative of the main change.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Jan 16, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

Flag Coverage Δ Complexity Δ
cms 73.90% <100.00%> (+0.09%) 2142.00 <4.00> (+14.00)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ Complexity Δ
src/Cms/Services/Post/Creator.php 100.00% <100.00%> (ø) 12.00 <2.00> (+7.00)
src/Cms/Services/Post/Updater.php 100.00% <100.00%> (ø) 14.00 <2.00> (+7.00)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@resources/views/admin/posts/create.php`:
- Around line 248-255: The current change handler only hides/shows the
published-at UI but does not clear or disable the underlying input, causing
stale published_at to be submitted; update the handler tied to
document.getElementById('status') so that when the status is 'published' or
'scheduled' it sets the published-at input (e.g., the element inside
'published-at-wrapper', such as id 'published-at' or name 'published_at') to
enabled and when hidden it clears its value (set to empty) and sets
disabled=true to prevent submission; also invoke the same logic once on page
load (or on DOMContentLoaded) to sync the initial visibility/state.

In `@resources/views/admin/posts/edit.php`:
- Around line 47-51: Add client-side validation to ensure a published date/time
is provided when the post status is set to "scheduled": hook into the post form
submit handler (element id 'post-form'), read the status field (id 'status') and
the published date input (id 'published_at'), and prevent submit with an inline
error (or alert) if status === 'scheduled' and published_at is empty; also
update the helper text near the published_at input (or the display logic in
'published-at-wrapper') to clearly state that scheduled posts require a future
publish date/time.
🧹 Nitpick comments (2)
src/Cms/Services/Post/Updater.php (1)

59-85: Guard published_at updates by status to avoid drafts carrying a publish timestamp.

Right now any non-empty published_at is applied regardless of status. If a user toggles from scheduled/published back to draft (or an API sends published_at with draft), drafts can still get a publish date. Consider applying published_at only for published/scheduled statuses (and ignore/clear otherwise). Please mirror the guard in src/Cms/Services/Post/Creator.php for parity.

♻️ Suggested adjustment
-		// Business rule: set published date
-		if( $publishedAt && trim( $publishedAt ) !== '' )
-		{
-			// Use provided published date
-			$post->setPublishedAt( new \DateTimeImmutable( $publishedAt ) );
-		}
-		elseif( $status === ContentStatus::PUBLISHED->value && !$post->getPublishedAt() )
-		{
-			// Auto-set to now for published posts when not provided and not already set
-			$post->setPublishedAt( new \DateTimeImmutable() );
-		}
+		// Business rule: set published date (only for published/scheduled)
+		if( in_array( $status, [ ContentStatus::PUBLISHED->value, ContentStatus::SCHEDULED->value ], true ) )
+		{
+			if( $publishedAt && trim( $publishedAt ) !== '' )
+			{
+				// Use provided published date
+				$post->setPublishedAt( new \DateTimeImmutable( $publishedAt ) );
+			}
+			elseif( $status === ContentStatus::PUBLISHED->value && !$post->getPublishedAt() )
+			{
+				// Auto-set to now for published posts when not provided and not already set
+				$post->setPublishedAt( new \DateTimeImmutable() );
+			}
+		}
resources/views/admin/posts/edit.php (1)

20-21: Slug pattern allows leading/trailing hyphens.

The pattern [a-z0-9-]+ permits slugs like --test--, while the auto-generation code strips leading/trailing hyphens. Consider a stricter pattern if you want consistency:

^[a-z0-9]+(-[a-z0-9]+)*$

Otherwise, the changes look good—removing required to enable auto-generation and the helper text update are clear.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e1ce088 and f5b519d.

📒 Files selected for processing (6)
  • resources/views/admin/posts/create.php
  • resources/views/admin/posts/edit.php
  • src/Cms/Dtos/posts/create-post-request.yaml
  • src/Cms/Dtos/posts/update-post-request.yaml
  • src/Cms/Services/Post/Creator.php
  • src/Cms/Services/Post/Updater.php
🧰 Additional context used
🧬 Code graph analysis (3)
src/Cms/Services/Post/Updater.php (2)
src/Cms/Models/Post.php (2)
  • setPublishedAt (300-304)
  • getPublishedAt (292-295)
src/Cms/Models/Page.php (2)
  • setPublishedAt (306-310)
  • getPublishedAt (298-301)
src/Cms/Services/Post/Creator.php (2)
src/Cms/Models/Post.php (1)
  • setPublishedAt (300-304)
src/Cms/Models/Page.php (1)
  • setPublishedAt (306-310)
resources/views/admin/posts/edit.php (3)
src/Cms/Models/Tag.php (1)
  • getSlug (72-75)
src/Cms/Models/Post.php (3)
  • getSlug (96-99)
  • getStatus (251-254)
  • getPublishedAt (292-295)
src/Cms/Models/Category.php (1)
  • getSlug (73-76)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Cursor Bugbot
  • GitHub Check: build-test (sqlite)
  • GitHub Check: build-test (postgres)
  • GitHub Check: build-test (mysql)
🔇 Additional comments (8)
src/Cms/Dtos/posts/create-post-request.yaml (1)

38-46: DTO update looks consistent with the update flow.

Optional published_at and the scheduled status align cleanly with the update DTO.

src/Cms/Services/Post/Creator.php (1)

59-81: LGTM — published_at handling matches the update flow.

Explicit dates are respected and the auto-set behavior for published posts is preserved.

resources/views/admin/posts/create.php (3)

19-20: Slug input validation/help text looks good.

Clear guidance and a tight pattern for URL-safe slugs.


42-50: Scheduled status option + Published Date/Time field integrate cleanly.

The UI now aligns with the new status and publish date workflow.


228-245: Auto-slug generation logic is clear and user-friendly.

The auto-generated vs. manual edit tracking is straightforward.

src/Cms/Dtos/posts/update-post-request.yaml (1)

38-46: No action required—scheduled status is fully implemented.

All concerns have been verified: ContentStatus enum includes SCHEDULED, the schedule() method in Publisher enforces that scheduled posts must have a future published_at date, repository methods support querying scheduled posts, and downstream services properly handle the new status. The implementation is complete and correct.

resources/views/admin/posts/edit.php (2)

43-43: LGTM!

The new "Scheduled" status option follows the same pattern as existing options and integrates well with the published_at visibility logic.


254-281: LGTM!

The JavaScript logic is well-implemented:

  • Auto-generation respects existing slugs on page load (since dataset.autoGenerated is undefined)
  • Clearing the slug re-enables auto-generation on subsequent title changes
  • The published-at visibility toggle correctly matches the server-side initial display condition

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

throw new \InvalidArgumentException( 'Scheduled posts require a published date' );
}
$post->setPublishedAt( $this->parseDateTime( $publishedAt ) );
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scheduled posts accept past dates, bypassing validation

Medium Severity

The new scheduling logic in Creator and Updater validates that scheduled posts have a published date, but unlike Publisher::schedule(), it doesn't validate that the date is in the future. This allows creating or updating scheduled posts with past dates, which is logically inconsistent. A post scheduled for a past date would be immediately eligible for publishing, defeating the purpose of scheduling.

Additional Locations (1)

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants