From a76c84b40f1f62f7458ef8ee5c0fc122c99f45b3 Mon Sep 17 00:00:00 2001 From: Jonny Barnes Date: Sat, 22 Aug 2026 17:16:55 +0100 Subject: [PATCH] Respect Micropub post-status when creating articles Articles created via Micropub were always published immediately, ignoring the client-supplied post-status property. Clients like iA Writer that publish drafts (post-status: draft) had no way to land an article as unpublished. EntryData now extracts post-status from the request, and ArticleService sets published accordingly, defaulting to true when the property is omitted or set to anything other than "draft". Fixes #123 Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01AXyzNvQZPQgBoSZwW7cLG8 --- app/Services/ArticleService.php | 2 +- app/Services/Micropub/Data/EntryData.php | 5 ++++ tests/Feature/MicropubControllerTest.php | 31 ++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/app/Services/ArticleService.php b/app/Services/ArticleService.php index 3d5dcc56..2372ffb7 100644 --- a/app/Services/ArticleService.php +++ b/app/Services/ArticleService.php @@ -13,7 +13,7 @@ class ArticleService return Article::create([ 'title' => $data['name'], 'main' => $data['content'], - 'published' => true, + 'published' => ($data['post-status'] ?? null) !== 'draft', ]); } } diff --git a/app/Services/Micropub/Data/EntryData.php b/app/Services/Micropub/Data/EntryData.php index 52dde72d..192c50f7 100644 --- a/app/Services/Micropub/Data/EntryData.php +++ b/app/Services/Micropub/Data/EntryData.php @@ -24,6 +24,7 @@ class EntryData extends MicropubData public readonly mixed $checkin, public readonly mixed $syndication, public readonly ?array $photos, + public readonly ?string $postStatus, ) {} public static function fromRequest(Request $request): static @@ -49,6 +50,7 @@ class EntryData extends MicropubData checkin: Arr::get($data, 'properties.checkin.0'), syndication: Arr::get($data, 'properties.syndication.0'), photos: Arr::get($data, 'properties.photo'), + postStatus: Arr::get($data, 'properties.post-status.0'), ); } @@ -67,6 +69,7 @@ class EntryData extends MicropubData checkin: $request->input('checkin'), syndication: $request->input('syndication'), photos: $request->input('photos'), + postStatus: $request->input('post-status'), ); } @@ -100,6 +103,7 @@ class EntryData extends MicropubData checkin: $data['checkin'] ?? null, syndication: $data['syndication'] ?? null, photos: $data['photos'] ?? null, + postStatus: $data['post-status'] ?? null, ); } @@ -120,6 +124,7 @@ class EntryData extends MicropubData 'checkin' => $this->checkin, 'syndication' => $this->syndication, 'photos' => $this->photos, + 'post-status' => $this->postStatus, ]; } } diff --git a/tests/Feature/MicropubControllerTest.php b/tests/Feature/MicropubControllerTest.php index 1e9f0351..efcfb6ce 100644 --- a/tests/Feature/MicropubControllerTest.php +++ b/tests/Feature/MicropubControllerTest.php @@ -869,6 +869,37 @@ class MicropubControllerTest extends TestCase $this->assertDatabaseHas('articles', [ 'title' => $name, 'main' => $content, + 'published' => true, + ]); + } + + #[Test] + public function micropub_client_api_request_creates_an_unpublished_article_when_post_status_is_draft(): void + { + $faker = Factory::create(); + $name = $faker->text(50); + $content = $faker->paragraphs(5, true); + + $response = $this->postJson( + '/api/post', + [ + 'type' => ['h-entry'], + 'properties' => [ + 'name' => [$name], + 'content' => [$content], + 'post-status' => ['draft'], + ], + ], + ['HTTP_Authorization' => 'Bearer '.$this->getToken()] + ); + + $response + ->assertJson(['response' => 'created']) + ->assertStatus(201); + $this->assertDatabaseHas('articles', [ + 'title' => $name, + 'main' => $content, + 'published' => false, ]); } } -- 2.55.0