MCPcopy Create free account
hub / github.com/TheSmallHanCat/flow2api / get_tokens

Function get_tokens

src/api/admin.py:793–857  ·  view source on GitHub ↗

Get all tokens with statistics

(token: str = Depends(verify_admin_token))

Source from the content-addressed store, hash-verified

791
792@router.get("/api/tokens")
793async def get_tokens(token: str = Depends(verify_admin_token)):
794 """Get all tokens with statistics"""
795 token_rows = await db.get_all_tokens_with_stats()
796 to_iso = lambda value: value.isoformat() if hasattr(value, "isoformat") else value
797 now = datetime.now(timezone.utc)
798
799 def normalize_dt(value):
800 if not value:
801 return None
802 if isinstance(value, str):
803 try:
804 value = datetime.fromisoformat(value.replace("Z", "+00:00"))
805 except Exception:
806 return None
807 if getattr(value, "tzinfo", None) is None:
808 return value.replace(tzinfo=timezone.utc)
809 return value.astimezone(timezone.utc)
810
811 return [{
812 "id": row.get("id"),
813 "st": row.get("st"), # Session Token for editing
814 "at": row.get("at"), # Access Token for editing (从ST转换而来)
815 "at_expires": to_iso(row.get("at_expires")) if row.get("at_expires") else None, # 🆕 AT过期时间
816 "at_expired": bool(normalize_dt(row.get("at_expires")) and normalize_dt(row.get("at_expires")) <= now),
817 "at_expiring_within_1h": bool(
818 normalize_dt(row.get("at_expires"))
819 and normalize_dt(row.get("at_expires")) > now
820 and (normalize_dt(row.get("at_expires")) - now).total_seconds() < 3600
821 ),
822 "token": row.get("at"), # 兼容前端 token.token 的访问方式
823 "email": row.get("email"),
824 "name": row.get("name"),
825 "remark": row.get("remark"),
826 "is_active": bool(row.get("is_active")),
827 "created_at": to_iso(row.get("created_at")) if row.get("created_at") else None,
828 "last_used_at": to_iso(row.get("last_used_at")) if row.get("last_used_at") else None,
829 "use_count": row.get("use_count"),
830 "credits": row.get("credits"), # 🆕 余额
831 "user_paygate_tier": row.get("user_paygate_tier"),
832 "current_project_id": row.get("current_project_id"), # 🆕 项目ID
833 "current_project_name": row.get("current_project_name"), # 🆕 项目名称
834 "captcha_proxy_url": row.get("captcha_proxy_url") or "",
835 "extension_route_key": row.get("extension_route_key") or "",
836 "protocol_mode": row.get("protocol_mode") or "session",
837 "google_cookies": row.get("google_cookies") or "",
838 "login_account": row.get("login_account") or "",
839 "login_password": row.get("login_password") or "",
840 "proxy_url": row.get("proxy_url") or "",
841 "auto_refresh_enabled": bool(row.get("auto_refresh_enabled", True)),
842 "refresh_interval_minutes": row.get("refresh_interval_minutes") or 120,
843 "last_st_refresh_at": to_iso(row.get("last_st_refresh_at")) if row.get("last_st_refresh_at") else None,
844 "last_st_refresh_result": row.get("last_st_refresh_result") or "",
845 "image_enabled": bool(row.get("image_enabled")),
846 "video_enabled": bool(row.get("video_enabled")),
847 "image_concurrency": row.get("image_concurrency"),
848 "video_concurrency": row.get("video_concurrency"),
849 "image_count": row.get("image_count", 0),
850 "video_count": row.get("video_count", 0),

Callers

nothing calls this directly

Calls 2

normalize_dtFunction · 0.85

Tested by

no test coverage detected