feat(surrenders): public rabbit surrender form + admin review queue #28
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/surrender-form"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #19.
Summary
Adds a public, anonymous rabbit surrender form and an admin-only review
queue. Nothing is added to the live rabbit records until an admin
explicitly accepts a submission — mirrors the existing
adopt.py/adoptions.pypublic-form + admin-management split.Public form (
/surrender, unauthenticated)submission is supported.
acceptance. Captures the acceptance timestamp + a version string
(
SURRENDER_AGREEMENT_VERSION) so wording can change later withoutlosing what a given submitter actually agreed to.
website, hidden off-screen) — a filled honeypotsilently "succeeds" without writing anything to the database.
SurrenderSubmissionrow withstatus=pending. No Rabbitrow is created at this point.
Admin queue (
/surrenders, admin only)timestamp/version.
Rabbit(status=Resident, no hutchassigned — staff place it later from the Rabbits page), links back via
rabbit_id, audit-logs both the rabbit creation and the status change.status=rejected+ optional admin note, no rabbitcreated, record kept.
the earlier design discussion on #19.
Data model
New
SurrenderSubmissiontable — no migration needed, picked up by theexisting
Base.metadata.create_all()on boot.Nav + audit integration
surrender_submissionsaudit entriesto the rabbit's name.
Testing
No local Postgres/Docker in this sandbox, so I wrote a throwaway smoke
test exercising the real FastAPI routers (public + admin) against an
in-memory SQLite engine — form load, missing-agreement rejection,
honeypot silently dropping a submission, a real submission creating a
pending row with no Rabbit, admin list/detail, accept creating an
unplaced Rabbit + audit logs, double-accept blocked, reject with a note,
and delete. All 10 checks passed.
Caught and fixed a real bug this way: escaped quotes nested inside an
onsubmitJS string aren't valid Jinja template syntax(
TemplateSyntaxError: unexpected char '\\'), which would have 500'dthe detail page for every pending submission. Simplified the confirm()
text instead of trying to interpolate the rabbit name into it (the name
is already shown in the page heading right above the button).
Please test against the live app and let me know if anything needs
adjusting.
Screenshots
Rendered the branch locally (SQLite demo instance) and drove it with a real
headless Chrome to capture the actual pages end to end: public form -> fill
-> submit -> thank you -> admin queue -> admin detail -> accept -> outcome.
1. Public surrender form (blank)

2. Public form filled in

3. Thank-you page after submit

4. Admin surrenders queue (pending filter)

5. Admin submission detail (pending, review buttons visible)

6. After Accept — rabbit created, outcome shown

Bug found + fixed while capturing these
Screenshot 6 originally showed the "Accepted — rabbit created" success banner
twice, stacked on top of each other —
surrenders/detail.htmlre-implementedits own success/error query-param banner, not realising
base.html's sharedcontent block already renders the identical alert for every page in the app.
The router-level smoke test in the PR description didn't catch this because it
only asserted the text was present, not that it appeared exactly once.
Fixed in the latest commit by removing the redundant local banner handling —
confirmed with a re-screenshot (image 6 above is from after the fix).