The collection nobody could make, and the eight ids a curator learned about

Contribution Date
Contribution Project
Contribution Details
The collection nobody could make, and the eight ids a curator learned about `dam_db::collections` has had membership, dense ordering and the tiering pin since 2.3, and until now there was no way to make or fill one outside a test. A portal publishes a collection, so the person who wanted a public page could not create the thing it publishes. All five existing functions took `&sqlx::PgPool`, which is the fifth module this week where dead code and a pool signature turned out to be the same fact: a handler holds a `TenantConn`, and the transaction is what carries the `search_path` that makes `collections` mean `t_acme.collections`. Converted to `&mut PgConnection`, and `all`, `by_key`, `create`, `rename` and `delete` added on top. `rename` does not move the key. A portal references a collection by key, so renaming one would break or silently repoint every portal built on it — and the label is what anybody wanted to change. The screen says so on the create form and again in the edit panel. `delete` refuses while a portal publishes, with the count and the fix in the sentence. Two bugs in writing that guard: it read `deleted_at` when portals retire via `retired_at`, and it ended in `unwrap_or(0)` — which is a guard that permits the delete it exists to refuse, and which leaves the caller's transaction aborted so the swallowed error resurfaces later as "current transaction is aborted", pointing at the wrong line. The predicate now applies in both directions. `add` already filtered ids through the caller's scope so a collection could not put an unseeable asset onto a public page; `items` did not, so a narrowly scoped curator opening a collection somebody wider had curated would learn the ids and the count of assets they cannot read. Same oracle, other side. Out-of-scope ids are counted, never named, and the real positions are kept — a gap is the honest signal that the set holds more than this. Members carry a filename, a mime and a thumbnail minted through `assets::thumbnail_url` rather than a second signing path, because curation is visual: reordering photographs by filename is a different and much worse job. The bulk-bar action is deliberately not a bulk operation. Publish and archive go through preview/confirm and an audited row; adding to a collection is arranging a working set — reversible, done dozens of times an hour, and recording it would bury the rows that matter. The browser caught the last bug: removing a member filtered the list locally, but a removal renumbers on the server, so the screen showed stale positions and then used the resulting hole to claim the collection held assets outside the caller's scope. Every mutation now takes the server's list back. Nine API cases, eight new db cases, eight browser cases including axe, and one more on the bulk bar. Verified against the running stack: created and deleted through the UI, a label and pinning amended with the key unmoved, three assets added from the grid with the count reported, reordered, and removed back to where the dev library started.
Contribution Author
Bassam Ismail
Files count
0
Patches count
1