T9.8 - D7: archiving stops reading as deletion - for project admins
Archiving already froze a project (the server refuses every write); what did not exist was the way back in. Now: - GET /api/projects?archived=only|all filters the answer BY PER-PROJECT ROLE: a project admin (or super/app admin) on THAT project sees it; everyone else receives an empty list from the same request - archived projects appear nowhere for them, counts and pickers included (the default listing already excluded them for everyone; asking is what got gated). Admin-on-Job-A does not surface archived Job B. - The launcher gains a visibly separate, labelled "Archived projects" section (dashed border, read-only stated in words), rendered only when the server returns rows. Opening one makes it active; the launcher's reconcile learned that an active project whose stored summary says archived:true was opened ON PURPOSE and keeps it, while a project archived out from under someone still drops with the existing explanation. - The creator shows ARCHIVED - READ-ONLY where the project is named (both ctx-bar branches, from the SERVER's answer - the page's project comes from the URL, so a stale local summary is not trusted) and refuses saves with a reason before the round trip. The courtesy; the server's refusal is the rule, verified by calling the endpoints directly (wp upsert AND the material-list write both refuse with "archived" even for an admin). - No unarchive button, no second mechanism, and it fits at 390px. Verification (each probe run alone): NEW tests/archived_check.py 15/15. Regressions: launcher_check 58/58, sample_check 10/10, export_check 20/20, frame_check 38/38. Items: D7 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1294,6 +1294,15 @@ def list_projects(
|
||||
elif archived != "all":
|
||||
stmt = stmt.where(models.Project.archived_at.is_(None)) # default: hide archived
|
||||
rows = db.scalars(stmt.order_by(models.Project.updated_at.desc())).all()
|
||||
# D7 / T9.8: archived projects are readable by PROJECT ADMINS only - anyone
|
||||
# below that sees them nowhere, counts and pickers included. The default
|
||||
# listing already excludes them; asking for them is what gets gated, and it
|
||||
# is gated per project, so admin-on-Job-A does not surface archived Job B.
|
||||
if archived != "exclude":
|
||||
rows = [p for p in rows
|
||||
if p.archived_at is None
|
||||
or effective_role(db, user, p.id) in (
|
||||
auth.ROLE_ADMIN, auth.ROLE_PROJECT_SUPER, auth.ROLE_PROJECT_ADMIN)]
|
||||
return [p.summary() for p in rows]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user