web: RSS and Atom feed handlers duplicate their feed-building structure #101

Closed
opened 2026-07-04 17:50:55 +00:00 by rosa · 1 comment
Owner

get_user_rss and get_user_atom (crates/web/src/handlers/users.rs:483-591) share roughly 80% of their structure: resolve the profile with no viewer, loop over profile.listed, build the post permalink and profile URL, and set the content-type header. Only the feed-object assembly differs.

A small shared helper for the profile/permalink plumbing would keep the two feeds from drifting apart. (The missing Atom id/updated elements — #94 — is exactly the kind of divergence this duplication produces.)

`get_user_rss` and `get_user_atom` (`crates/web/src/handlers/users.rs:483-591`) share roughly 80% of their structure: resolve the profile with no viewer, loop over `profile.listed`, build the post permalink and profile URL, and set the content-type header. Only the feed-object assembly differs. A small shared helper for the profile/permalink plumbing would keep the two feeds from drifting apart. (The missing Atom `id`/`updated` elements — #94 — is exactly the kind of divergence this duplication produces.)
Author
Owner

This was generated by AI during triage.

Agent Brief

Category: enhancement
Summary: Extract the shared feed-assembly plumbing from the RSS and Atom handlers so the two feeds can't drift apart.

Current behavior:
The two feed handlers — the one serving application/rss+xml and the one serving application/atom+xml for a user's blog — share roughly 80% of their structure. Each independently resolves the profile as seen by no viewer, iterates the profile's listed posts, builds a per-post absolute permalink and the absolute blog/profile URL via the shared permalinks:: helpers, and sets the content-type header. Only the feed-object assembly differs: one uses the rss crate's channel/item builders, the other the atom_syndication crate's feed/entry builders. Because the plumbing is copy-pasted, the two feeds have already diverged once (#94: the Atom feed is missing id/updated elements).

Desired behavior:
The profile-resolution, per-post permalink construction, blog/profile URL construction, and content-type plumbing are computed once in a shared, format-agnostic step. Each handler consumes that shared data and maps it into its own crate's builders. Adding or correcting a field that belongs to "an entry" (title, link, published timestamp, content) or "the feed" (title, blog link) should have one obvious home per concern, not two. Both feeds' rendered output must be unchanged by this refactor (it is a pure restructuring).

Key interfaces:

  • A format-agnostic intermediate is the natural seam — e.g. a FeedEntry { title, url, published_at, html } and a FeedData { author/profile, blog_url, entries }, produced once from the resolved profile. Exact names and fields are the implementing agent's call; the contract is that both handlers derive their builder inputs from the same values.
  • Both handlers already resolve the profile via the app service's "profile as seen by nobody" path — reuse it; do not add a second resolution path.
  • Permalinks must continue to go through the existing shared permalinks:: helpers (post URL + profile/blog URL); do not hand-format paths.

Acceptance criteria:

  • The profile resolution, per-post permalink, blog/profile URL, and content-type handling exist in exactly one place shared by both feed handlers.
  • The RSS handler still emits application/rss+xml and the Atom handler still emits application/atom+xml, with output equivalent to today's (no field added or dropped as part of this refactor).
  • The format, clippy, and ci mise tasks pass.

Out of scope:

  • Fixing the missing Atom id/updated elements — that is #94. This refactor should make that fix land in one place afterward, but does not perform it.
  • Adding feeds for anything other than a user's blog, or new feed formats.
  • Changing the domain-layer profile/post read path.
> *This was generated by AI during triage.* ## Agent Brief **Category:** enhancement **Summary:** Extract the shared feed-assembly plumbing from the RSS and Atom handlers so the two feeds can't drift apart. **Current behavior:** The two feed handlers — the one serving `application/rss+xml` and the one serving `application/atom+xml` for a user's blog — share roughly 80% of their structure. Each independently resolves the profile as seen by no viewer, iterates the profile's listed posts, builds a per-post absolute permalink and the absolute blog/profile URL via the shared `permalinks::` helpers, and sets the content-type header. Only the feed-object assembly differs: one uses the `rss` crate's channel/item builders, the other the `atom_syndication` crate's feed/entry builders. Because the plumbing is copy-pasted, the two feeds have already diverged once (#94: the Atom feed is missing `id`/`updated` elements). **Desired behavior:** The profile-resolution, per-post permalink construction, blog/profile URL construction, and content-type plumbing are computed once in a shared, format-agnostic step. Each handler consumes that shared data and maps it into its own crate's builders. Adding or correcting a field that belongs to "an entry" (title, link, published timestamp, content) or "the feed" (title, blog link) should have one obvious home per concern, not two. Both feeds' rendered output must be unchanged by this refactor (it is a pure restructuring). **Key interfaces:** - A format-agnostic intermediate is the natural seam — e.g. a `FeedEntry { title, url, published_at, html }` and a `FeedData { author/profile, blog_url, entries }`, produced once from the resolved profile. Exact names and fields are the implementing agent's call; the contract is that both handlers derive their builder inputs from the same values. - Both handlers already resolve the profile via the app service's "profile as seen by nobody" path — reuse it; do not add a second resolution path. - Permalinks must continue to go through the existing shared `permalinks::` helpers (post URL + profile/blog URL); do not hand-format paths. **Acceptance criteria:** - [ ] The profile resolution, per-post permalink, blog/profile URL, and content-type handling exist in exactly one place shared by both feed handlers. - [ ] The RSS handler still emits `application/rss+xml` and the Atom handler still emits `application/atom+xml`, with output equivalent to today's (no field added or dropped as part of this refactor). - [ ] The `format`, `clippy`, and `ci` mise tasks pass. **Out of scope:** - Fixing the missing Atom `id`/`updated` elements — that is #94. This refactor should make that fix land in one place afterward, but does not perform it. - Adding feeds for anything other than a user's blog, or new feed formats. - Changing the domain-layer profile/post read path.
rosa closed this issue 2026-07-05 00:35:51 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
rosa/vernier#101
No description provided.