Permanently deleting a photo whose album was deleted failed because authorization resolved through the album. Fall back to uploader ownership when the photo is albumless. Add a bulk DELETE /trash that removes every trashed photo the caller may delete (uncapped listing) and returns the deleted count, with an «Очистить корзину» action on the trash screen.
2.5 KiB
2.5 KiB
Tasks
1. Fix permanent delete for albumless photos
- 1.1 In
photos.Service.PermanentDelete, whenp.AlbumID == "", authorize byp.UploaderID == userIDinstead of callingalbums.Access; keep the album-role check when an album is present. Verify with a Go test that permanently deletes an albumless trashed photo (add tobackend/internal/e2e/sqlite_test.go) and passes. - 1.2 Confirm object garbage collection still runs for albumless deletes (
PhotoObjectIDs+MarkObjectDeleting); verify the test asserts the photo row is gone and an unbound object is marked deleting.
2. Add empty-trash operation
- 2.1 Add a photos repository/store method that lists all accessible trashed photo identities (
id,album_id,uploader_id) without the 200-item display cap; verify with a test that seeds more than 200 trashed photos and asserts all are returned. - 2.2 Add
Service.EmptyTrash(ctx, userID)that authorizes each listed photo with the same rules asPermanentDelete(album role when bound, uploader when albumless), skips forbidden ones, and returns the deleted count; verify with a test where a shared album holds another user's trashed photo — the foreign photo remains, the caller's are removed, and the count matches. - 2.3 Add
Handler.EmptyTrashand theDELETE /trashroute returning{ "deleted": n }; verify with an HTTP-level test asserting the status code and response body. - 2.4 Add end-to-end coverage: emptying an empty trash returns
0, and after emptying a non-empty trashTrashCountis0; verify withmake test.
3. Trash screen action
- 3.1 Add
photosApi.emptyTrash()callingDELETE /trashinfrontend/src/lib/api.ts; verify withnpm run check. - 3.2 Add an «Очистить корзину» control to
frontend/src/routes/(app)/trash/+page.svelte, enabled only when the list is non-empty, opening the existingConfirmDialog; on confirm callemptyTrash, then reload the list and calltrash.load(); verify by clearing a non-empty trash and observing the empty state and a busy state during the call. - 3.3 Verify the rail counter reflects the result: after clearing, the trash count in
AlbumRailbecomes0(observable in the running app).
4. Integration verification
- 4.1 Run
make test(backend) andnpm run checkplusnpm run build(frontend); verify all pass with no regressions.
Workflow follow-up
- Run
/opsx-applyto implement this change. - Archive the change after review and verification (sync delta specs into main specs).