M6: History, diff, revert, changes, feeds#15
Merged
Merged
Conversation
Three additions: - get_revisions(page_id, before, limit) — paginated list of a page's revisions, newest first. The `before` cursor takes a revision number and returns the next page back through history. - get_revisions_count(page_id) — total non-sentinel revisions; used for the history page-count math. - get_changes(site_id, before, limit) — joined site-wide activity feed across all pages. The 2007 helper returned `[]` with an "impossible query" comment; the query itself works fine on modern Postgres. `before` for get_changes is keyed by revision id (not revision number) because the order is by created-time across many pages, where revision numbers reset per page. First commit of M6. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the page-history view: a paginated list of revisions (20 per page, newest first) with revision number, timestamp, and the diff summary stored on each revision. The "Older →" link is cursor-based on the oldest revision in the current page rather than offset-based, so pages stay stable as new revisions land. m=history slots into the existing mode dispatch in page.view and maps onto the auth-matrix `view_revision` action — same as `?r=N` — so public sites gate it behind a sign-in while open sites allow anonymous browsing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Renders a between-revision diff using the better_diff renderer from jottit/diff.py. Revision selection follows the 2007 URL shape: - ?m=diff → latest vs previous - ?m=diff&r=N → revision N vs N-1 - ?m=diff&r=A&r=B → between A and B (ordering normalized so ?r=3&r=1 and ?r=1&r=3 produce the same output) More than two `r` values, non-integer values, and unknown revision numbers all return 400. Like history, the action maps to view_revision so public sites gate it behind a sign-in. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Revert restores a page's content to an earlier revision by writing a new revision (so history stays linear). If the page is deleted, the revert path also undeletes it. Reverting to a revision whose content already matches the latest is a no-op. Undelete restores a soft-deleted page and appends a "<em>Delete undone.</em>" revision that re-promotes the pre-delete content as the new latest. The deleted sentinel revision stays in history. Both POST endpoints go through the auth matrix as `edit` and the unified mode dispatch in page.view. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Site-wide activity feed: every revision across every page on the site, newest first, paginated 20 at a time. The "Older →" link uses the revision id as the cursor since revisions are ordered by created-time across pages (revision numbers reset per page so they can't double as a global cursor). Deleted pages still appear in the feed with an "(page since deleted)" mark so the timeline remains continuous after a delete. Auth maps to view_revision — public sites gate it behind a sign-in, open sites allow anonymous reads. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Four feeds: - /<page>?m=history_rss + /<page>?m=history_json (per-page history) - /site/changes.rss + /site/changes.json (site-wide recent changes) RSS templates live under jottit/templates/feeds/ as `.rss.xml`. JSON Feed is built as a dict and jsonify'd — no template needed. Both content types are returned with the right MIME (`application/rss+xml`, `application/feed+json`). Self-link URLs are absolute and respect the current request: per-page links live under the site's subdomain or secret-URL prefix as appropriate. Auth-wise feeds map to the loose "view" action since feed readers typically don't authenticate — that means private sites still gate them behind a sign-in, but public sites expose them anonymously (matches the original 2007 behavior for history_atom / changes_atom). The replaced `/site/changes.atom` route is gone; `changes_atom` view stub is removed. Closes out M6. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Port the history-flavored UI: per-page revision list, between-revision diff, revert / undelete actions, site-wide changes feed, and RSS 2.0 + JSON Feed endpoints.
Decisions
?r=A&r=Bmulti-value (matches the 2007 site for URL compatibility).Test plan
get_revisions,get_revisions_count,get_changes)/<page>?m=history/<page>?m=diff/<page>?m=revert+ POST/<page>?m=undelete/site/changes?m=history_rss/?m=history_jsonper-page;/site/changes.rss+/site/changes.jsonsite-wide)🤖 Generated with Claude Code