chore: stage changes before history rewrite

This commit is contained in:
2026-07-07 11:28:18 +08:00
parent a619b919be
commit 137304090a
13 changed files with 670 additions and 83 deletions

View File

@@ -67,6 +67,19 @@ def _strftime(dt: datetime, fmt: str) -> str:
templates.env.filters["strftime"] = _strftime
import json as _json
def _json_loads(raw: str) -> list:
"""Parse JSON string for Jinja2 templates."""
try:
return _json.loads(raw) if raw else []
except (ValueError, TypeError):
return []
templates.env.filters["json_loads"] = _json_loads
def _translate_filter(key: str, lang: str = "zh") -> str:
return _t(key, lang)
@@ -77,6 +90,21 @@ from app.i18n import get_languages as _get_languages
templates.env.globals["available_languages"] = _get_languages()
def _get_copyright() -> str:
from app.models import SystemConfig as _SC
from app.database import SessionLocal
try:
db = SessionLocal()
cfg = db.query(_SC).filter(_SC.key == "copyright_text").first()
db.close()
return cfg.value if cfg else ""
except Exception:
return ""
templates.env.globals["copyright_text"] = _get_copyright()
def _redirect(url: str) -> RedirectResponse:
return RedirectResponse(url, status_code=303)
@@ -188,6 +216,32 @@ def _require_admin(user: User) -> bool:
return user.is_admin
def _admin_context(user, db, active_tab="invites", **extra):
"""Build context for admin.html with invite codes and system config."""
from app.models import SystemConfig
codes = db.query(InviteCode).order_by(InviteCode.created_at.desc()).all()
config = {r.key: r.value for r in db.query(SystemConfig).all()}
ctx = {"request": extra.get("request"), "user": user, "codes": codes, "active_tab": active_tab, "config": config}
ctx.update({k: v for k, v in extra.items() if k != "request"})
return ctx
def _admin_render(request, user, db, active_tab="invites", **extra):
return templates.TemplateResponse("admin.html", _admin_context(user, db, active_tab, request=request, **extra))
@router.get("/admin", response_class=HTMLResponse)
def admin_page(
request: Request,
active_tab: str = Query("invites", alias="tab"),
user: User = Depends(get_current_user_web),
db: Session = Depends(get_db),
):
if not _require_admin(user):
return _redirect("/dashboard")
return _admin_render(request, user, db, active_tab)
@router.get("/admin/invites", response_class=HTMLResponse)
def admin_invites_page(
request: Request,
@@ -196,10 +250,27 @@ def admin_invites_page(
):
if not _require_admin(user):
return _redirect("/dashboard")
codes = db.query(InviteCode).order_by(InviteCode.created_at.desc()).all()
return templates.TemplateResponse("admin_invites.html", {
"request": request, "user": user, "codes": codes,
})
return _admin_render(request, user, db, "invites")
@router.post("/admin/config")
def admin_save_config(
request: Request,
copyright_text: str = Form(""),
user: User = Depends(get_current_user_web),
db: Session = Depends(get_db),
):
if not _require_admin(user):
return _redirect("/dashboard")
from app.models import SystemConfig
cfg = db.query(SystemConfig).filter(SystemConfig.key == "copyright_text").first()
if cfg:
cfg.value = copyright_text.strip()
else:
cfg = SystemConfig(key="copyright_text", value=copyright_text.strip())
db.add(cfg)
db.commit()
return _admin_render(request, user, db, "config", success="Saved")
@router.post("/admin/invites/add")
@@ -220,17 +291,9 @@ def admin_add_invite(
else:
code = code.strip()
if len(code) != 8:
codes = db.query(InviteCode).order_by(InviteCode.created_at.desc()).all()
return templates.TemplateResponse("admin_invites.html", {
"request": request, "user": user, "codes": codes,
"error": "邀请码必须为8个字符",
})
return _admin_render(request, user, db, "invites", error="邀请码必须为8个字符")
if db.query(InviteCode).filter(InviteCode.code == code).first():
codes = db.query(InviteCode).order_by(InviteCode.created_at.desc()).all()
return templates.TemplateResponse("admin_invites.html", {
"request": request, "user": user, "codes": codes,
"error": "邀请码已存在",
})
return _admin_render(request, user, db, "invites", error="邀请码已存在")
# Parse limits
m_uses = None
exp_at = None
@@ -244,11 +307,7 @@ def admin_add_invite(
)
db.add(new_code)
db.commit()
codes = db.query(InviteCode).order_by(InviteCode.created_at.desc()).all()
return templates.TemplateResponse("admin_invites.html", {
"request": request, "user": user, "codes": codes,
"success": f"邀请码 {code} 已创建",
})
return _admin_render(request, user, db, "invites", success=f"邀请码 {code} 已创建")
@router.post("/admin/invites/{code_id}/edit")
@@ -276,11 +335,7 @@ def admin_edit_invite(
code_obj.max_uses = None
code_obj.expires_at = None
db.commit()
codes = db.query(InviteCode).order_by(InviteCode.created_at.desc()).all()
return templates.TemplateResponse("admin_invites.html", {
"request": request, "user": user, "codes": codes,
"success": f"邀请码 {code_obj.code} 已更新",
})
return _admin_render(request, user, db, "invites", success=f"邀请码 {code_obj.code} 已更新")
@router.post("/admin/invites/{code_id}/delete")
@@ -296,7 +351,7 @@ def admin_delete_invite(
if code_obj:
db.delete(code_obj)
db.commit()
return _redirect("/admin/invites")
return _redirect("/admin?tab=invites")
# ---------- Settings ----------
@@ -862,17 +917,21 @@ def public_showcase(request: Request, username: str, db: Session = Depends(get_d
def apikey_create(
request: Request,
name: str = Form(""),
permissions: list[str] = Form([]),
user: User = Depends(get_current_user_web),
db: Session = Depends(get_db),
):
from app.models import ApiKey
from app.models import ApiKey, ALL_PERMISSIONS
from secrets import token_hex
import json
key = f"mv_{token_hex(24)}"
ak = ApiKey(key=key, name=name.strip(), user_id=user.id)
# Filter to valid scopes only
valid = [p for p in permissions if p in ALL_PERMISSIONS]
perms_json = json.dumps(valid) if valid else "[]"
ak = ApiKey(key=key, name=name.strip(), user_id=user.id, permissions=perms_json)
db.add(ak)
db.commit()
db.refresh(ak)
# Re-render settings with apikeys tab active and the new key shown
api_keys = db.query(ApiKey).filter(ApiKey.user_id == user.id).order_by(ApiKey.created_at.desc()).all()
return templates.TemplateResponse("settings.html", {
"request": request, "user": user, "active_tab": "apikeys",
@@ -894,6 +953,27 @@ def apikey_delete(
return _redirect("/settings?tab=apikeys")
@router.post("/settings/apikeys/{key_id}/edit")
def apikey_edit(
key_id: int,
request: Request,
name: str = Form(""),
permissions: list[str] = Form([]),
user: User = Depends(get_current_user_web),
db: Session = Depends(get_db),
):
from app.models import ApiKey, ALL_PERMISSIONS
import json
ak = db.query(ApiKey).filter(ApiKey.id == key_id, ApiKey.user_id == user.id).first()
if not ak:
return _redirect("/settings?tab=apikeys")
ak.name = name.strip()
valid = [p for p in permissions if p in ALL_PERMISSIONS]
ak.permissions = json.dumps(valid) if valid else "[]"
db.commit()
return _redirect("/settings?tab=apikeys")
# ---------- API Docs ----------
@router.get("/api/docs", response_class=HTMLResponse)