Spaces:
Running
Running
提升帖子更新安全
Browse files- router_comments.py +8 -4
- router_posts.py +33 -23
router_comments.py
CHANGED
|
@@ -82,14 +82,16 @@ async def soft_delete_comment(item_id: str, comment_id: str, account: str = Depe
|
|
| 82 |
item_comments = comments_db.get(item_id, [])
|
| 83 |
target_comment = None
|
| 84 |
|
| 85 |
-
def find_comment(comments_list):
|
| 86 |
"""查找目标评论"""
|
|
|
|
|
|
|
| 87 |
nonlocal target_comment
|
| 88 |
for c in comments_list:
|
| 89 |
if c["id"] == comment_id:
|
| 90 |
target_comment = c
|
| 91 |
return True
|
| 92 |
-
if "replies" in c and find_comment(c["replies"]):
|
| 93 |
return True
|
| 94 |
return False
|
| 95 |
|
|
@@ -129,13 +131,15 @@ async def soft_delete_comment(item_id: str, comment_id: str, account: str = Depe
|
|
| 129 |
raise HTTPException(status_code=403, detail="无权删除此评论")
|
| 130 |
|
| 131 |
# 执行软删除
|
| 132 |
-
def mark_deleted(comments_list):
|
|
|
|
|
|
|
| 133 |
for c in comments_list:
|
| 134 |
if c["id"] == comment_id:
|
| 135 |
c["isDeleted"] = True
|
| 136 |
c["content"] = ""
|
| 137 |
return True
|
| 138 |
-
if "replies" in c and mark_deleted(c["replies"]):
|
| 139 |
return True
|
| 140 |
return False
|
| 141 |
|
|
|
|
| 82 |
item_comments = comments_db.get(item_id, [])
|
| 83 |
target_comment = None
|
| 84 |
|
| 85 |
+
def find_comment(comments_list, depth=0):
|
| 86 |
"""查找目标评论"""
|
| 87 |
+
if depth > 20: # 防止极端嵌套导致栈溢出
|
| 88 |
+
return False
|
| 89 |
nonlocal target_comment
|
| 90 |
for c in comments_list:
|
| 91 |
if c["id"] == comment_id:
|
| 92 |
target_comment = c
|
| 93 |
return True
|
| 94 |
+
if "replies" in c and find_comment(c["replies"], depth + 1):
|
| 95 |
return True
|
| 96 |
return False
|
| 97 |
|
|
|
|
| 131 |
raise HTTPException(status_code=403, detail="无权删除此评论")
|
| 132 |
|
| 133 |
# 执行软删除
|
| 134 |
+
def mark_deleted(comments_list, depth=0):
|
| 135 |
+
if depth > 20: # 防止极端嵌套导致栈溢出
|
| 136 |
+
return False
|
| 137 |
for c in comments_list:
|
| 138 |
if c["id"] == comment_id:
|
| 139 |
c["isDeleted"] = True
|
| 140 |
c["content"] = ""
|
| 141 |
return True
|
| 142 |
+
if "replies" in c and mark_deleted(c["replies"], depth + 1):
|
| 143 |
return True
|
| 144 |
return False
|
| 145 |
|
router_posts.py
CHANGED
|
@@ -180,32 +180,42 @@ async def create_post(post: PostCreate, current_user: str = Depends(require_auth
|
|
| 180 |
@router.put("/api/posts/{post_id}")
|
| 181 |
async def update_post(post_id: str, update_data: PostUpdate, current_user: str = Depends(require_auth)):
|
| 182 |
"""
|
| 183 |
-
更新帖子(仅作者可操作)
|
| 184 |
"""
|
| 185 |
-
|
| 186 |
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
if post
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
|
|
|
| 207 |
|
| 208 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 209 |
|
| 210 |
@router.delete("/api/posts/{post_id}")
|
| 211 |
async def delete_post(post_id: str, current_user: str = Depends(require_auth)):
|
|
|
|
| 180 |
@router.put("/api/posts/{post_id}")
|
| 181 |
async def update_post(post_id: str, update_data: PostUpdate, current_user: str = Depends(require_auth)):
|
| 182 |
"""
|
| 183 |
+
更新帖子(仅作者可操作,原子操作,并发安全)
|
| 184 |
"""
|
| 185 |
+
result_holder = {}
|
| 186 |
|
| 187 |
+
def updater(data):
|
| 188 |
+
for post in data:
|
| 189 |
+
if post["id"] == post_id:
|
| 190 |
+
if post.get("author") != current_user:
|
| 191 |
+
result_holder["error"] = "forbidden"
|
| 192 |
+
return False
|
| 193 |
+
# 更新字段
|
| 194 |
+
if update_data.title is not None:
|
| 195 |
+
post["title"] = update_data.title
|
| 196 |
+
if update_data.content is not None:
|
| 197 |
+
post["content"] = update_data.content
|
| 198 |
+
if update_data.cover_image is not None:
|
| 199 |
+
post["cover_image"] = update_data.cover_image
|
| 200 |
+
if update_data.images is not None:
|
| 201 |
+
post["images"] = update_data.images[:9]
|
| 202 |
+
if update_data.is_original is not None:
|
| 203 |
+
post["is_original"] = update_data.is_original # 🎨 更新原创作品标记
|
| 204 |
+
result_holder["post"] = post
|
| 205 |
+
return True
|
| 206 |
+
result_holder["error"] = "not_found"
|
| 207 |
+
return False
|
| 208 |
|
| 209 |
+
db.atomic_update("posts.json", updater, default_data=[])
|
| 210 |
+
|
| 211 |
+
if result_holder.get("error") == "forbidden":
|
| 212 |
+
raise HTTPException(status_code=403, detail="无权修改他人帖子")
|
| 213 |
+
if result_holder.get("error") == "not_found":
|
| 214 |
+
raise HTTPException(status_code=404, detail="帖子不存在")
|
| 215 |
+
|
| 216 |
+
# 🗂️ 清除排序缓存
|
| 217 |
+
sort_cache.invalidate("posts:")
|
| 218 |
+
return {"status": "success"}
|
| 219 |
|
| 220 |
@router.delete("/api/posts/{post_id}")
|
| 221 |
async def delete_post(post_id: str, current_user: str = Depends(require_auth)):
|