diff --git a/app/ApiHandler.php b/app/ApiHandler.php index b992724..2843c1d 100644 --- a/app/ApiHandler.php +++ b/app/ApiHandler.php @@ -2261,6 +2261,51 @@ final class ApiHandler if (!$m) { Api::notFound('这条观影记录'); } if ($sub === 'poster' || $sub === 'photos') { + /* 🔴 2026-11-06:`photos` 现在同时支持 **POST(追加)** 与 + **DELETE(删一张)** —— 用户「编辑观影记录的时候,那个图片 + 应该可以被删除吧?现在没有删除按钮。」 + ⚠️ `poster` 只有 POST(换海报是覆盖语义,没有"删海报"这个操作 —— + 清空海报请用 PATCH 传空 `poster_key`,那条路由本来就支持)。 + ⚠️ DELETE 的 `photo_id` 走 query:`Api::dispatch()` 只解析到 + 路径第三段(`movies//photos`),再往后会被丢掉。 + 同类做法见 `trips//nodes/attach`。 */ + if ($sub === 'photos' && $method === 'DELETE') { + Api::requireWrite(); + $photoId = (int)Api::int('photo_id'); + if ($photoId <= 0) { + Api::fail('要说明删哪一张(photo_id)。', 'bad_request', 400); + } + /* ⚠️ 先确认这张照片确实属于这条记录,再删 —— + 否则传一个别的记录的照片 id 也能删掉(越权删)。 + `deletePhoto` 内部是 `WHERE id = ? AND event_id = ?`, + 错配时它删 0 行、什么也不做,但那样**静默成功**会误导调用方, + 所以这里显式校验一次,删不到就报 404。 */ + $st = Database::get()->prepare( + 'SELECT id FROM event_photos WHERE id = ? AND event_id = ?' + ); + $st->execute([$photoId, $id]); + if (!$st->fetchColumn()) { + Api::notFound('这张照片'); + } + Movie::deletePhoto($fam, $id, $photoId); + Api::ok([ + 'deleted' => $photoId, + 'photos' => array_map( + static fn(array $p): array => [ + 'id' => (int)$p['id'], + 'key' => (string)$p['key'], + 'kind' => (string)($p['kind'] ?? 'image'), + 'url' => Storage\Storage::url($fam, (string)$p['key']), + 'thumb' => !empty($p['thumb_key']) + ? Storage\Storage::url($fam, (string)$p['thumb_key']) + : '', + 'mime' => (string)($p['mime'] ?? ''), + ], + Movie::photos($id) + ), + ]); + } + if ($method !== 'POST') { Api::fail('不支持的方法。', 'method_not_allowed', 405); } Api::requireWrite();