Bring Micropub endpoint closer to the spec

- Detect form-encoded action=... requests, so form-encoded updates work
  and unhandled actions are no longer created as notes
- Default to h-entry when no type is given
- Read form-encoded photos from `photo` rather than `photos`
- Pass `category` through EntryData so bookmark tags are saved
- Accept single values for form-encoded multi-value properties
- Return 403 for insufficient_scope and 401 for invalid tokens
- Return 400 invalid_request for unsupported post types, update
  operations and models instead of reporting them as 500s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jonny Barnes 2026-10-24 22:26:41 +01:00
commit 6e96ca8304
Signed by: jonny
SSH key fingerprint: SHA256:CTuSlns5U7qlD9jqHvtnVmfYV3Zwl2Z7WnJ4/dqOaL8

View file

@ -116,6 +116,26 @@ class BookmarksTest extends TestCase
$response->assertJson(['response' => 'created']);
Queue::assertPushed(ProcessBookmark::class);
$this->assertDatabaseHas('bookmarks', ['url' => 'https://example.org/blog-post']);
$bookmark = Bookmark::where('url', 'https://example.org/blog-post')->firstOrFail();
$this->assertEqualsCanonicalizing(['tag1', 'tag2'], $bookmark->tags->pluck('tag')->all());
}
#[Test]
public function form_encoded_bookmark_with_categories_creates_tags(): void
{
Queue::fake();
$response = $this->withHeaders([
'Authorization' => 'Bearer '.$this->getToken(),
])->post('/api/post', [
'h' => 'entry',
'bookmark-of' => 'https://example.org/blog-post',
'category' => ['tag1', 'tag2'],
]);
$response->assertJson(['response' => 'created']);
$bookmark = Bookmark::where('url', 'https://example.org/blog-post')->firstOrFail();
$this->assertEqualsCanonicalizing(['tag1', 'tag2'], $bookmark->tags->pluck('tag')->all());
}
}