From 442ad12097f0fdce0763d51088a2bb4d074edce8 Mon Sep 17 00:00:00 2001 From: meleki Date: Wed, 30 Sep 2026 21:13:31 +0200 Subject: [PATCH] Say that only the owner deletes a project (#272) The API now answers an administrator 403 when they delete somebody else's project. The pages still said an administrator deletes every project like their own. - API: the DELETE row names the 403, and the paragraph on administrators says deleting stays with the owner. - Accounts: the list of what an administrator may do, and the Delete row of the user management. - Architecture: one line on what `seesAll` covers. - Development: the e2e total, 1602 to 1603. Co-Authored-By: Claude Opus 5.5 --- API.md | 9 ++++++--- Accounts.md | 12 +++++++----- Architecture.md | 1 + Development.md | 2 +- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/API.md b/API.md index 49e9cc1..c1e2ca7 100644 --- a/API.md +++ b/API.md @@ -10,7 +10,7 @@ All routes go through `api/index.php?r=…` (the site's nginx does not pass `PAT | POST | `projects` | `{name}` → project document (201) | | GET | `projects/{id}` | `{id,name,revision,updatedAt,project}` | | PUT | `projects/{id}` | `{revision, project}` → `{revision,updatedAt}` or **409** `{error,revision}` when stale | -| DELETE | `projects/{id}` | 204, and the snapshots and the release of the project go with it | +| DELETE | `projects/{id}` | 204, and the snapshots and the release of the project go with it. **403** `{error}` for an administrator who is not the owner | | GET | `projects/{id}/snapshots` | `[{id,name,revision,createdAt}]`, newest first — see [Concepts](Concepts) | | POST | `projects/{id}/snapshots` | `{name?}` → `{id,name,revision,createdAt}` (201). Copies the project as stored; a blank name becomes the UTC date and time. **422** over 120 characters | | DELETE | `projects/{id}/snapshots/{sid}` | 204 | @@ -39,8 +39,11 @@ All routes go through `api/index.php?r=…` (the site's nginx does not pass `PAT **Everything but `auth/*` needs a session** and answers **401** `{"error":"Sign in first"}` without one. Projects belong to an account: `projects` lists only the caller's own, and somebody else's project answers **404**, not 403 — that an id exists is already more than a stranger should learn. -An **administrator** (#180, #179) reads, saves and deletes every project with the same routes, and -a save keeps the project's `owner`; their `projects` list stays their own. The `users` routes and +An **administrator** (#180, #179) reads and saves every project with the same routes, and a save +keeps the project's `owner`; their `projects` list stays their own. Deleting a project stays with +its owner (#272): an administrator gets **403** `{"error":"Only its owner may delete a project"}`, +also for a file without an owner. Snapshots and the release of the project are theirs to manage +all the same. The `users` routes and deleting a stored image, font or sound answer anybody but an administrator **403** `{"error":"Administrators only"}`. Images, fonts, sounds, cels and plugins are shared between accounts; being signed in is still the price diff --git a/Accounts.md b/Accounts.md index 4144fd2..931fbbc 100644 --- a/Accounts.md +++ b/Accounts.md @@ -59,10 +59,12 @@ not offer; it shows the role nowhere else, there is no badge and no word in the An administrator - manages the accounts in the **User management** tab (below), and -- opens, edits and deletes **every** project as if it were their own (#179). A save keeps the - project's owner: an administrator who fixes somebody's project does not take it over. Their own - project list (*Open project…*) still shows only their own; the others are reached through the - user management. +- opens and edits **every** project as if it were their own (#179). A save keeps the project's + owner: an administrator who fixes somebody's project does not take it over. Their own project + list (*Open project…*) still shows only their own; the others are reached through the user + management. +- does **not** delete somebody else's project (#272). Only the owner deletes a project; the + server answers an administrator **403**, so nothing goes missing without its owner knowing. ## User management @@ -78,7 +80,7 @@ how many projects it owns, the projects listed under it with **Open**. On the ri | **Rename…** | A new name. The account's projects move with it — the name is their `owner` — and the account is signed out everywhere, since its sessions carry the old name | | **Role** | `user` or `admin`, picked from a menu | | **Password…** | Sets a new password without the old one. The account's sessions end; on the administrator's own row their own session stays | -| **Delete** | Asks first, then removes the account and signs it out. **Refused while it owns projects** — they would belong to nobody and vanish from every list; delete them first | +| **Delete** | Asks first, then removes the account and signs it out. **Refused while it owns projects** — they would belong to nobody and vanish from every list. The account deletes them first; an administrator cannot (#272) | | **New user…** | In the tab's header: name, password (twice) and role | On their **own row** an administrator may only set a password: renaming themselves would end the diff --git a/Architecture.md b/Architecture.md index 27145c5..945c441 100644 --- a/Architecture.md +++ b/Architecture.md @@ -199,6 +199,7 @@ src/editor/users/ the user management (#179): ManagementPane (the tab behin server's own sentence. The server decides everything: `api/lib/AccountRules.php` (not the own account, not the last administrator, not an account with projects), `Auth::requireAdmin()` (403), `Store` with `seesAll` for an administrator + (reads and saves every project, deletes only their own: `NotOwnerException`, #272) src/player/ GameScreen (the game on the page: Auto zoom, the caption before and after a run), Player (loads, starts on a click, ticks, stops), playerHook (`window.__gameMakerPlay` for the check scripts) — a released game (#266), without the editor diff --git a/Development.md b/Development.md index 2288320..2d919bd 100644 --- a/Development.md +++ b/Development.md @@ -18,7 +18,7 @@ php tests/php/accounts.test.php # the API's accoun # has and the web server's container has not (SKIP there) php tests/php/snapshots.test.php # the snapshot store (#231), the same way php tests/php/releases.test.php # the release store (#266), the same way -node tools/seed-e2e.mjs && node tools/e2e.mjs # 1602 editor checks, screenshots in /tmp/gm-e2e-*.png +node tools/seed-e2e.mjs && node tools/e2e.mjs # 1603 editor checks, screenshots in /tmp/gm-e2e-*.png GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step ./e2e.sh start [GM_STEPS] # the same run detached, see below ./e2e.sh status # live progress, or the last run's result