编辑观影记录的时候,那个图片应该可以被删除吧?现在没有删除按钮。
服务端早就有删除能力,只缺 API 暴露:
Movie::deletePhoto($fam, $eventId, $photoId)
thumb_key
movies/photo_del
/movies/<id>/photos
所以这轮是"补最后一层",不是重做。
app/ApiHandler.php
photos 子路由从"只 POST"扩为"POST 追加 + DELETE 删除":
photos
DELETE /api/v1/movies/<id>/photos?photo_id=N
Api::dispatch()
parts[2]
movies
<id>
parts[3]
trips/<id>/nodes/attach?node_id=&attachment_id=
SELECT id FROM event_photos WHERE id=? AND event_id=?
deletePhoto
poster
poster_key
FbMovieRepo.ets
FbMovieMedia
id
deletePhoto(movieId, photoId, token)
FbMovieNewSheet.ets
deleteExistingPhoto()
FbMovieDetailSheet.ets
allPhotos()
id: 0
event_photos
三个设计决定:
FbTripNodeSheet.removePhoto
false
Storage::exists
true
存储驱动实测是 OSS(oss-cn-hangzhou),delete 会真删对象。
oss-cn-hangzhou
delete
测试删除时删掉了一张用户真实照片,无法恢复。
event_photos.id=14
photos/3a16dba3cf769f381664df01.jpg
Storage::read()
fb_img
attachments
find
教训:验证"删除"功能时,绝不能用用户的真实数据当被测对象。
正确做法只有两条:
我这次明知会真删还点了真实照片的 ✕ —— 因为当时以为"能删就一定能加回来",而实际上 deletePhoto 连 OSS 对象一起删,没有回收站、没有版本、没有本地副本,是彻底不可逆的。
后续同类需求的验证应当:真机只验证"按钮存在 + 点击后弹一次确认/触发一次请求",删除的实际效果在临时数据上验证。
#84 是照片支持视频(上传链路);本单是照片的删除能力(API 暴露 DELETE + 端上 ✕ 按钮),方向相反
No dependencies set.
The note is not visible to the blocked user.
用户原话
事实核查
服务端早就有删除能力,只缺 API 暴露:
Movie::deletePhoto($fam, $eventId, $photoId)—— 存在,连存储对象一起删(含视频的thumb_key)movies/photo_del→ 调它 → redirect 回编辑页/movies/<id>/photos只支持 POST(追加/上传)所以这轮是"补最后一层",不是重做。
改动
服务端
app/ApiHandler.phpphotos子路由从"只 POST"扩为"POST 追加 + DELETE 删除":Api::dispatch()只解析到parts[2](movies/<id>/photos),parts[3]会被静默丢弃。项目里同类做法:trips/<id>/nodes/attach?node_id=&attachment_id=。SELECT id FROM event_photos WHERE id=? AND event_id=?,查不到就 404。否则传别的记录的照片 id 也能删(越权),而deletePhoto内部遇到错配是"删 0 行 + 静默成功",调用方会以为删掉了。poster保持只 POST:换海报是覆盖语义,没有"删海报"这个操作(要清空走 PATCH 传空poster_key)。端上
FbMovieRepo.etsFbMovieMedia加id字段(删除必须按 id);新增deletePhoto(movieId, photoId, token)FbMovieNewSheet.etsdeleteExistingPhoto();文案改「已有 N 张(点 ✕ 可删)」FbMovieDetailSheet.etsallPhotos()构造票根项时补id: 0(票根不是event_photos的行,没有 id)三个设计决定:
movies/photo_del完全同口径。做成"先标记、保存时才提交"的话,用户中途关表单会以为自己删了、其实还在。FbTripNodeSheet.removePhoto和网页端一致。单张照片删除不值得拦一道;整条记录删除才需要确认。验证
服务端(脚本直调)
false—— 越权被拦住Storage::exists删除前true→ 删除后false存储驱动实测是 OSS(
oss-cn-hangzhou),delete会真删对象。端上(真机 5NC0225B27004718)
🔴 本次事故(必须记录)
测试删除时删掉了一张用户真实照片,无法恢复。
event_photos.id=14/photos/3a16dba3cf769f381664df01.jpg(观影记录 224 的第 1 张)Storage::read()返回 404fb_img/attachments按 sha256 命名,无此文件)、服务器全盘find(无)、OSS 版本控制(bucket 未开启)、公网 URL(bucket 私有,403)教训:验证"删除"功能时,绝不能用用户的真实数据当被测对象。
正确做法只有两条:
我这次明知会真删还点了真实照片的 ✕ —— 因为当时以为"能删就一定能加回来",而实际上
deletePhoto连 OSS 对象一起删,没有回收站、没有版本、没有本地副本,是彻底不可逆的。后续同类需求的验证应当:真机只验证"按钮存在 + 点击后弹一次确认/触发一次请求",删除的实际效果在临时数据上验证。
相关工单口径
为什么单独建单
#84 是照片支持视频(上传链路);本单是照片的删除能力(API 暴露 DELETE + 端上 ✕ 按钮),方向相反