[MTM] Micropub improvements and other fixes #152

Merged
jonny merged 9 commits from develop into main 2026-11-07 16:17:46 +01:00

2026-11-02

Reject Micropub updates that would do nothing
Updating a property we don't support returned a 200 with no change, so
clients believed the update had worked. Return invalid_request instead,
and apply nothing if any part of the request is unsupported.

This also covers empty operations, syndication URLs we have nowhere to
store, and photos added without an https URL, all of which were being
silently ignored.

Mastodon and Bluesky URLs can now be added and deleted through updates,
as they are our active syndication targets and q=source returns them.
Mastodon can be on any host, so accept the instances we have syndication
targets for rather than hard-coding one.

Stop reading instagram_url in q=source, as notes have no such column.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:26:26 +00:00
Add Micropub q=source and reject malformed requests
Servers supporting updates must support the source content query. It
was falling through to the token response, so clients got a 200 with no
post in it. Return the raw note as microformats2 JSON, honouring
properties[].

Malformed requests could cause a 500 or worse. A replace value sent as a
string overwrote the note with its first character, because $value[0]
indexes the string. Validate update operations before applying any of
them, and return invalid_request for wrongly shaped properties, unknown
or malformed q values, and missing update URLs.

Share URL resolution between updates and q=source in NoteResolver, which
also rejects URLs on other hosts and invalid note IDs. Those IDs used to
decode to a real note because invalid characters were skipped.

Allow photo objects without alt text, and parse the published date
before saving so that an invalid date doesn't leave a stray note behind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 18:59:23 +00:00
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>
2026-11-02 18:45:39 +00:00

2026-11-01

Drop the unused notes.shorturl column
The short domain is gone and nothing reads or writes this column any more.

Refs #148

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:29:05 +00:00
Link to likes through the uri attribute in the like template
Refs #148

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:29:00 +00:00
Return our permalink in the Micropub Location header for likes
Likes returned `url`, which is the liked post rather than our page. Use
`uri` instead. Bookmarks already asked for `uri`, which didn't exist until
the previous commit, so their Location header was empty.

Neither case had a test, so assert the header value for both.

Refs #148

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:29:00 +00:00
Use uri for the like and bookmark permalinks
`uri` is the attribute every other postable model uses for its absolute
permalink on this site. Add it to Like, which had none, and rename
Bookmark's `local_uri` to match. `url` stays as the thing being liked or
bookmarked.

Refs #148

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 15:28:30 +00:00