Add moderator UI for delisting a published extension - #321
Conversation
Paygate's source repo is gone and paygate.love is down, so its catalogue
page links to a dead download with no way to reach the developer. The api
repo now has POST /extensions/{id}/delist for this (moderator-only); this
wires it up here:
- Regenerated openapi/extensions-v2.json and the typed client against a
local api dev server running the new endpoint.
- Added ApiClient.delistExtension().
- Added a "Delist a published extension" form to /account/moderate,
posting to a new /account/moderate/delist route. Unlike approve/reject,
which act on a queue entry already in view, this targets an arbitrary
extension id typed into the form, so id travels in the body rather than
the URL path.
Does not yet email the developer - the delist reason is visible to them via
GET /extensions/mine once that's surfaced in the owner-facing UI, but actual
notification needs picking an email provider, which is out of scope here.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
extensions | cfbc2bd | Commit Preview URL Branch Preview URL |
Sep 04 2026, 09:23 AM |
There was a problem hiding this comment.
All reported issues were addressed across 7 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
… carry Every other method on the ApiClient object, and both sibling moderate/[id]/*.ts action routes, are comment-free by convention here (this repo's house style is terser than the api repo's) - the two comments I'd added on delistExtension() and delist.ts were the only ones in either file.
There was a problem hiding this comment.
0 issues found across 2 files (changes from recent commits).
Requires human review: Auto-approval blocked by 1 unresolved issue from previous reviews.
Re-trigger cubic
Delisting is destructive and immediate - the extension leaves the public catalogue as soon as the form posts - but it had no confirmation step, unlike the reject flow it otherwise mirrors (which uses RejectDialog, a modal the moderator must explicitly confirm in). The id/reason form no longer posts directly. Submitting it (native required validation still applies first) populates and opens a confirmation dialog - same structure as RejectDialog: title naming the extension, Cancel/Delist buttons, a close icon - whose own form does the actual POST to /account/moderate/delist. The populate-then-open logic needed more than the single-expression inline onclick handlers this file otherwise uses (see RejectDialog's trigger button), so it's a <script> block instead, matching the existing precedent for non-trivial client interactivity in src/pages/account/index.astro.
There was a problem hiding this comment.
0 issues found across 1 file (changes from recent commits).
Requires human review: Adds moderator UI to delist published extensions, wiring a new API endpoint and regenerating client code. Depends on the unmerged API PR #215, so this cannot be safely deployed independently.
Re-trigger cubic
Regenerated the client against api's delist-published-extensions branch (now has the new endpoint). Adds: - ApiClient.getModerationExtension() - A new detail page, /account/moderate/extensions/[id], showing the full record - developer, published content, pending edit, last review, and the delist reason/timestamp front and center when present. Mirrors developers/[id]/history.astro's layout and error handling. - A "View an extension" lookup on the moderation index page, and the revision queue's extension id is now a link to the same page - so a moderator can get from 'reviewing a revision' or 'typing paygate' to the full record in one step, not just after delisting something.
There was a problem hiding this comment.
All reported issues were addressed across 7 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
repositoryURL() returns repository.repo verbatim for type: 'custom', so a developer-supplied javascript:/data: URI would execute in a moderator's session on click. DetailsCard.astro (the public extension page) already guards this with isSafeHttpUrl() before rendering it as a link - this page missed it, matching the Website field on the same page which already had the guard.
There was a problem hiding this comment.
0 issues found across 1 file (changes from recent commits).
Requires human review: Adds moderator UI to delist published extensions, wiring a new API endpoint and regenerating client code. Still depends on the unmerged API PR #215, so merging this client change first would break the site.
Re-trigger cubic
Why
Companion to FOSSBilling/api#215, which adds
POST /extensions/{id}/delistso moderators can pull a published extension out of the catalogue. This PR wires that endpoint up on the site side.Depends on api#215 — the regenerated
openapi/extensions-v2.jsonand typed client here were generated against a localapidev server running that PR's branch, not against production, since production doesn't have the endpoint yet. This should merge/deploy after (or alongside) api#215, not before.What
openapi/extensions-v2.jsonandsrc/lib/api/generated/extensions-v2/*.ApiClient.delistExtension()./account/moderate, posting to a new/account/moderate/delistroute. Unlike approve/reject, which act on a queue entry already in view, this targets an arbitrary extension id typed into the form, so the id travels in the form body rather than the URL path.