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 a8004f2958
Signed by: jonny
SSH key fingerprint: SHA256:CTuSlns5U7qlD9jqHvtnVmfYV3Zwl2Z7WnJ4/dqOaL8

View file

@ -41,7 +41,7 @@ class MicropubMediaTest extends TestCase
'/api/media?q=last',
['HTTP_Authorization' => 'Bearer abc123']
);
$response->assertStatus(400);
$response->assertStatus(401);
$response->assertJsonFragment(['error_description' => 'The provided token did not pass validation']);
}
@ -63,7 +63,7 @@ class MicropubMediaTest extends TestCase
'/api/media?q=last',
['HTTP_Authorization' => 'Bearer '.$this->getTokenWithIncorrectScope()]
);
$response->assertStatus(401);
$response->assertStatus(403);
$response->assertJsonFragment(['error_description' => 'The token’s scope does not have the necessary requirements.']);
}
@ -210,14 +210,14 @@ class MicropubMediaTest extends TestCase
}
#[Test]
public function media_endpoint_request_with_invalid_token_returns400_response(): void
public function media_endpoint_request_with_invalid_token_returns401_response(): void
{
$response = $this->post(
'/api/media',
[],
['HTTP_Authorization' => 'Bearer abc123']
);
$response->assertStatus(400);
$response->assertStatus(401);
$response->assertJsonFragment(['error_description' => 'The provided token did not pass validation']);
}
@ -234,14 +234,14 @@ class MicropubMediaTest extends TestCase
}
#[Test]
public function media_endpoint_request_with_insufficient_token_scopes_returns401_response(): void
public function media_endpoint_request_with_insufficient_token_scopes_returns403_response(): void
{
$response = $this->post(
'/api/media',
[],
['HTTP_Authorization' => 'Bearer '.$this->getTokenWithIncorrectScope()]
);
$response->assertStatus(401);
$response->assertStatus(403);
$response->assertJsonFragment([
'error_description' => 'The token’s scope does not have the necessary requirements.',
]);