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
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:
@@ -248,6 +248,7 @@ def init_db():
|
|||||||
# Migration: soft-delete for users
|
# Migration: soft-delete for users
|
||||||
if "deleted" not in user_cols:
|
if "deleted" not in user_cols:
|
||||||
c.execute("ALTER TABLE users ADD COLUMN deleted INTEGER DEFAULT 0")
|
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:
|
if "deleted_at" not in user_cols:
|
||||||
c.execute("ALTER TABLE users ADD COLUMN deleted_at TEXT")
|
c.execute("ALTER TABLE users ADD COLUMN deleted_at TEXT")
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ def get_current_user(request: Request):
|
|||||||
if not token:
|
if not token:
|
||||||
return ANON_USER
|
return ANON_USER
|
||||||
conn = get_db()
|
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()
|
conn.close()
|
||||||
if not user:
|
if not user:
|
||||||
return ANON_USER
|
return ANON_USER
|
||||||
@@ -373,7 +373,7 @@ def login(body: dict):
|
|||||||
if not username or not password:
|
if not username or not password:
|
||||||
raise HTTPException(400, "请输入用户名和密码")
|
raise HTTPException(400, "请输入用户名和密码")
|
||||||
conn = get_db()
|
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:
|
if not user:
|
||||||
conn.close()
|
conn.close()
|
||||||
raise HTTPException(401, "用户名不存在")
|
raise HTTPException(401, "用户名不存在")
|
||||||
@@ -747,7 +747,7 @@ def list_recipes(user=Depends(get_current_user)):
|
|||||||
if user["role"] == "admin":
|
if user["role"] == "admin":
|
||||||
rows = conn.execute("SELECT id, name, note, owner_id, version, en_name FROM recipes ORDER BY id").fetchall()
|
rows = conn.execute("SELECT id, name, note, owner_id, version, en_name FROM recipes ORDER BY id").fetchall()
|
||||||
else:
|
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
|
admin_id = admin["id"] if admin else 1
|
||||||
user_id = user.get("id")
|
user_id = user.get("id")
|
||||||
if user_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
|
# Senior editors adding directly to public library: set owner to admin so everyone can see
|
||||||
owner_id = user["id"]
|
owner_id = user["id"]
|
||||||
if user["role"] in ("senior_editor",):
|
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:
|
if admin:
|
||||||
owner_id = admin["id"]
|
owner_id = admin["id"]
|
||||||
c.execute("INSERT INTO recipes (name, note, owner_id) VALUES (?, ?, ?)",
|
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")
|
@app.get("/api/users")
|
||||||
def list_users(user=Depends(require_role("admin"))):
|
def list_users(user=Depends(require_role("admin"))):
|
||||||
conn = get_db()
|
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()
|
conn.close()
|
||||||
return [dict(r) for r in rows]
|
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"]:
|
if user_id == user["id"]:
|
||||||
raise HTTPException(400, "不能删除自己")
|
raise HTTPException(400, "不能删除自己")
|
||||||
conn = get_db()
|
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:
|
if not target:
|
||||||
conn.close()
|
conn.close()
|
||||||
raise HTTPException(404, "User not found")
|
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()
|
requester_name = body_text.split(" 搜索了")[0].strip()
|
||||||
# Find the user
|
# Find the user
|
||||||
requester = conn.execute(
|
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)
|
(requester_name, requester_name)
|
||||||
).fetchone()
|
).fetchone()
|
||||||
if requester:
|
if requester:
|
||||||
@@ -1734,7 +1734,7 @@ def weekly_review(user=Depends(require_role("admin"))):
|
|||||||
conn = get_db()
|
conn = get_db()
|
||||||
|
|
||||||
# 1. Pending recipes for admin review
|
# 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
|
admin_id = admin["id"] if admin else 1
|
||||||
pending = conn.execute(
|
pending = conn.execute(
|
||||||
"SELECT COUNT(*) as cnt FROM recipes WHERE owner_id != ?", (admin_id,)
|
"SELECT COUNT(*) as cnt FROM recipes WHERE owner_id != ?", (admin_id,)
|
||||||
|
|||||||
Reference in New Issue
Block a user