refactor: React 前端重构,新旧平台合并为莞易学
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
"""账号 / 登录 / 登录记录接口。"""
|
||||
import time
|
||||
|
||||
from study_tool.webapp import app
|
||||
|
||||
from study_tool import store
|
||||
from study_tool.config import *
|
||||
from study_tool.models import *
|
||||
from study_tool.platforms.jspx import *
|
||||
from study_tool.runtime import log
|
||||
|
||||
def _log_login(username, ok, code, error, elapsed, stage=""):
|
||||
"""每次登录尝试:统一日志 + login_log 表(登录记录页用)。"""
|
||||
log(username or "-", "登录%s code=%s%s %s %.1fs" % (
|
||||
"成功" if ok else "失败", code, (" " + stage) if stage else "",
|
||||
(error or "")[:120], elapsed or 0))
|
||||
try:
|
||||
store.login_log_add(username, ok, code, elapsed, stage, error)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _login_account(b: LoginIn):
|
||||
"""解析出一组可登录的凭据:显式传入优先,否则按账号 id 从库里取。"""
|
||||
acc = store.account_get(b.account_id) if b.account_id else None
|
||||
username = (b.username or "").strip() or ((acc or {}).get("username") or "")
|
||||
password = b.password or (store.account_password(b.account_id) if b.account_id else "")
|
||||
return acc, username, password
|
||||
|
||||
|
||||
@app.post("/api/login")
|
||||
def api_login(b: LoginIn):
|
||||
t0 = time.time()
|
||||
acc, username, password = _login_account(b)
|
||||
if not username or not password:
|
||||
err = "没有可用的账号密码:新账号请在「添加账号」里填密码,服务端会把它存进 SQLite"
|
||||
_log_login(username or b.account_id, False, "no_credential", err, time.time() - t0,
|
||||
"LoginIn")
|
||||
return JSONResponse({"ok": False, "code": "no_credential", "error": err}, status_code=200)
|
||||
try:
|
||||
s, user = login(username, password)
|
||||
except Exception as e:
|
||||
err = str(e)[:300]
|
||||
_log_login(username, False, "login_failed", err, time.time() - t0, type(e).__name__)
|
||||
if acc:
|
||||
store.account_upsert({"id": acc["id"], "username": acc["username"],
|
||||
"status": "login_failed", "lastError": err,
|
||||
"lastErrorAt": time.time()})
|
||||
return JSONResponse({"ok": False, "code": "login_failed", "error": err}, status_code=200)
|
||||
warn = ""
|
||||
try:
|
||||
courses = scrape_courses(s)
|
||||
except Exception as e:
|
||||
courses, warn = [], str(e)[:200]
|
||||
cookies = dump_cookies(s)
|
||||
_log_login(username, True, "ok", warn, time.time() - t0, "user=%s" % user)
|
||||
if acc:
|
||||
store.account_save_login(acc["id"], user, cookies, courses)
|
||||
return {"ok": True, "user": user, "cookies": cookies, "courses": courses, "warn": warn}
|
||||
|
||||
|
||||
@app.get("/api/loginlog")
|
||||
def api_loginlog(tail: int = 40):
|
||||
"""登录尝试回放:前端点「登录」后,这里能看到平台到底回了什么。"""
|
||||
return {"ok": True, "lines": store.login_log_tail(tail)}
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ accounts
|
||||
|
||||
@app.get("/api/accounts")
|
||||
def api_accounts():
|
||||
"""全部账号(含会话 cookie / 课程缓存 / 勾选),**不含密码**。"""
|
||||
return {"ok": True, "accounts": store.account_list()}
|
||||
|
||||
|
||||
@app.post("/api/accounts")
|
||||
def api_account_save(b: AccountIn):
|
||||
"""新增或更新一个账号。password 不传(或传空)表示保留库里已有的密码。"""
|
||||
rec = b.model_dump()
|
||||
if not (rec.get("password") or "").strip():
|
||||
rec["password"] = None
|
||||
if not rec.get("id") and not rec.get("username"):
|
||||
return JSONResponse({"ok": False, "error": "缺少 username"}, status_code=200)
|
||||
try:
|
||||
aid = store.account_upsert(rec)
|
||||
except Exception as e:
|
||||
return JSONResponse({"ok": False, "error": "写入 SQLite 失败:%s" % str(e)[:200]},
|
||||
status_code=200)
|
||||
return {"ok": True, "id": aid, "account": store.account_get(aid)}
|
||||
|
||||
|
||||
@app.get("/api/accounts/{account_id}")
|
||||
def api_account_get(account_id: str):
|
||||
acc = store.account_get(account_id)
|
||||
if not acc:
|
||||
return JSONResponse({"ok": False, "error": "账号不存在"}, status_code=200)
|
||||
return {"ok": True, "account": acc}
|
||||
|
||||
|
||||
@app.delete("/api/accounts/{account_id}")
|
||||
def api_account_del(account_id: str):
|
||||
store.account_delete(account_id)
|
||||
with RUNS_LOCK:
|
||||
RUNS.pop(account_id, None)
|
||||
return {"ok": True}
|
||||
Reference in New Issue
Block a user