Let only the owner delete a project, not an administrator (#272)
#179 decided that nobody deletes a project on someone else's behalf. The API still let an administrator do it, because the admin store treated every project as its own. Option A from the issue is now in place: opening, editing, snapshots and release stay open to the administrator, deleting stays with the owner. - Store::delete checks the owner under the save lock and throws NotOwnerException for anyone else. It follows the pattern of StaleRevisionException. - The route answers that with 403 "Only its owner may delete a project". A file without an owner is covered the same way. Non-admins still get 404 for a project that is not theirs. - The editor has no way to delete a foreign project, the project picker lists only one's own. Nothing changes there. - An account that owns projects can no longer be deleted by an administrator at all. Its owner has to delete them first. - e2e 49 deleted the throwaway projects as administrator, both in its sweep and in 49i. It now signs in as the owner for that. 49i checks both answers. Tests: - tests/php/accounts.test.php: 56 checks passed (was 52, one check turned around, five new) - e2e 49: 22 checks passed (was 21), deleteByAdmin 403, deleteByOwner 204 - Gate: 197 files, 2855 tests passed - Counter-checks: without the owner check 4 PHP checks and 49i fail - The e2e total of 1603 is computed (1602 + 1), not measured Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f14c4ecb77
commit
cbda6d64a7
5 files changed
+69
-17
No files matched your search
+10
-3
@@ -16,7 +16,8 @@ declare(strict_types=1);
|
||||
*
|
||||
* Everything below needs a signed-in user (401 otherwise), and projects belong to one: a project
|
||||
* of somebody else answers like one that is not there – unless the one asking is an administrator
|
||||
* (#179), who reads, saves and deletes it like their own; a save keeps its owner.
|
||||
* (#179), who reads and saves it like their own; a save keeps its owner. Deleting a project is
|
||||
* its owner's alone (#272).
|
||||
*
|
||||
* Administrators only (403 for everybody else, #180):
|
||||
*
|
||||
@@ -31,7 +32,8 @@ declare(strict_types=1);
|
||||
* POST ?r=projects {name} → {id,name,revision,updatedAt,project}
|
||||
* GET ?r=projects/{id} → {id,name,revision,updatedAt,project}
|
||||
* PUT ?r=projects/{id} {revision, project} → {revision,updatedAt} | 409 {error,revision}
|
||||
* DELETE ?r=projects/{id} → 204 (its snapshots and its release go with it)
|
||||
* DELETE ?r=projects/{id} → 204 | 403 | 404 (its snapshots and its release go with it;
|
||||
* 403 for an administrator who is not the owner)
|
||||
*
|
||||
* GET ?r=projects/{id}/snapshots → [{id,name,revision,createdAt}], newest first
|
||||
* POST ?r=projects/{id}/snapshots {name?} → 201 {id,name,revision,createdAt}
|
||||
@@ -230,7 +232,12 @@ function routeProjects(array $parts, string $method, string $owner, bool $seesAl
|
||||
}
|
||||
|
||||
if ($method === 'DELETE') {
|
||||
if (!$store->delete($id)) {
|
||||
try {
|
||||
$deleted = $store->delete($id);
|
||||
} catch (NotOwnerException $e) {
|
||||
Response::error($e->getMessage(), 403);
|
||||
}
|
||||
if (!$deleted) {
|
||||
Response::error('Project not found', 404);
|
||||
}
|
||||
$snapshots->deleteAll($id);
|
||||
|
||||
Reference in new issue
Block a user