fix: 软删除字段NULL兼容,用COALESCE避免已有用户无法登录
All checks were successful
PR Preview / teardown-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 5s
Test / build-check (push) Successful in 4s
PR Preview / test (pull_request) Successful in 5s
PR Preview / deploy-preview (pull_request) Successful in 10s
Test / e2e-test (push) Successful in 50s

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-11 22:05:24 +00:00
parent 5848a21540
commit f579a459a0
2 changed files with 9 additions and 8 deletions

View File

@@ -248,6 +248,7 @@ def init_db():
# Migration: soft-delete for users
if "deleted" not in user_cols:
c.execute("ALTER TABLE users ADD COLUMN deleted INTEGER DEFAULT 0")
c.execute("UPDATE users SET deleted = 0 WHERE deleted IS NULL")
if "deleted_at" not in user_cols:
c.execute("ALTER TABLE users ADD COLUMN deleted_at TEXT")

View File

@@ -57,7 +57,7 @@ def get_current_user(request: Request):
if not token:
return ANON_USER
conn = get_db()
user = conn.execute("SELECT id, username, role, display_name, password, business_verified FROM users WHERE token = ? AND NOT deleted", (token,)).fetchone()
user = conn.execute("SELECT id, username, role, display_name, password, business_verified FROM users WHERE token = ? AND COALESCE(deleted,0)=0", (token,)).fetchone()
conn.close()
if not user:
return ANON_USER
@@ -373,7 +373,7 @@ def login(body: dict):
if not username or not password:
raise HTTPException(400, "请输入用户名和密码")
conn = get_db()
user = conn.execute("SELECT id, token, password, display_name, role FROM users WHERE username = ? AND NOT deleted", (username,)).fetchone()
user = conn.execute("SELECT id, token, password, display_name, role FROM users WHERE username = ? AND COALESCE(deleted,0)=0", (username,)).fetchone()
if not user:
conn.close()
raise HTTPException(401, "用户名不存在")
@@ -747,7 +747,7 @@ def list_recipes(user=Depends(get_current_user)):
if user["role"] == "admin":
rows = conn.execute("SELECT id, name, note, owner_id, version, en_name FROM recipes ORDER BY id").fetchall()
else:
admin = conn.execute("SELECT id FROM users WHERE role = 'admin' AND NOT deleted LIMIT 1").fetchone()
admin = conn.execute("SELECT id FROM users WHERE role = 'admin' AND COALESCE(deleted,0)=0 LIMIT 1").fetchone()
admin_id = admin["id"] if admin else 1
user_id = user.get("id")
if user_id:
@@ -786,7 +786,7 @@ def create_recipe(recipe: RecipeIn, user=Depends(get_current_user)):
# Senior editors adding directly to public library: set owner to admin so everyone can see
owner_id = user["id"]
if user["role"] in ("senior_editor",):
admin = c.execute("SELECT id FROM users WHERE role = 'admin' AND NOT deleted LIMIT 1").fetchone()
admin = c.execute("SELECT id FROM users WHERE role = 'admin' AND COALESCE(deleted,0)=0 LIMIT 1").fetchone()
if admin:
owner_id = admin["id"]
c.execute("INSERT INTO recipes (name, note, owner_id) VALUES (?, ?, ?)",
@@ -1063,7 +1063,7 @@ def delete_tag(name: str, user=Depends(require_role("admin"))):
@app.get("/api/users")
def list_users(user=Depends(require_role("admin"))):
conn = get_db()
rows = conn.execute("SELECT id, username, token, role, display_name, created_at, business_verified FROM users WHERE NOT deleted ORDER BY id").fetchall()
rows = conn.execute("SELECT id, username, token, role, display_name, created_at, business_verified FROM users WHERE COALESCE(deleted,0)=0 ORDER BY id").fetchall()
conn.close()
return [dict(r) for r in rows]
@@ -1092,7 +1092,7 @@ def delete_user(user_id: int, user=Depends(require_role("admin"))):
if user_id == user["id"]:
raise HTTPException(400, "不能删除自己")
conn = get_db()
target = conn.execute("SELECT id, username, display_name FROM users WHERE id = ? AND NOT deleted", (user_id,)).fetchone()
target = conn.execute("SELECT id, username, display_name FROM users WHERE id = ? AND COALESCE(deleted,0)=0", (user_id,)).fetchone()
if not target:
conn.close()
raise HTTPException(404, "User not found")
@@ -1690,7 +1690,7 @@ def mark_notification_added(nid: int, user=Depends(get_current_user)):
requester_name = body_text.split(" 搜索了")[0].strip()
# Find the user
requester = conn.execute(
"SELECT id, role FROM users WHERE (display_name = ? OR username = ?) AND NOT deleted",
"SELECT id, role FROM users WHERE (display_name = ? OR username = ?) AND COALESCE(deleted,0)=0",
(requester_name, requester_name)
).fetchone()
if requester:
@@ -1734,7 +1734,7 @@ def weekly_review(user=Depends(require_role("admin"))):
conn = get_db()
# 1. Pending recipes for admin review
admin = conn.execute("SELECT id FROM users WHERE role = 'admin' AND NOT deleted LIMIT 1").fetchone()
admin = conn.execute("SELECT id FROM users WHERE role = 'admin' AND COALESCE(deleted,0)=0 LIMIT 1").fetchone()
admin_id = admin["id"] if admin else 1
pending = conn.execute(
"SELECT COUNT(*) as cnt FROM recipes WHERE owner_id != ?", (admin_id,)