mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-04 08:25:26 +08:00
Update accounts module description
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Admin 账号管理模块 - 账号验证和测试"""
|
||||
"""Admin 账号管理模块 - 账号测试与导入"""
|
||||
import asyncio
|
||||
import json
|
||||
import base64
|
||||
@@ -24,145 +24,6 @@ from .auth import verify_admin
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# 账号验证
|
||||
# ----------------------------------------------------------------------
|
||||
async def validate_single_account(account: dict) -> dict:
|
||||
"""验证单个账号的有效性"""
|
||||
acc_id = get_account_identifier(account)
|
||||
result = {
|
||||
"account": acc_id,
|
||||
"valid": False,
|
||||
"has_token": bool(account.get("token", "").strip()),
|
||||
"message": "",
|
||||
}
|
||||
|
||||
def _is_token_invalid(status_code: int, data: dict) -> bool:
|
||||
msg = (data.get("msg") or data.get("message") or "").lower()
|
||||
code = data.get("code")
|
||||
return status_code in {401, 403} or code in {40001, 40002, 40003} or "token" in msg or "unauthorized" in msg
|
||||
|
||||
def _create_session(token: str) -> dict:
|
||||
headers = {**BASE_HEADERS, "authorization": f"Bearer {token}"}
|
||||
try:
|
||||
session_resp = cffi_requests.post(
|
||||
DEEPSEEK_CREATE_SESSION_URL,
|
||||
headers=headers,
|
||||
json={"agent": "chat"},
|
||||
impersonate="safari15_3",
|
||||
timeout=15,
|
||||
)
|
||||
except Exception as e:
|
||||
return {"success": False, "message": f"请求异常: {e}", "status_code": 0, "data": {}}
|
||||
|
||||
try:
|
||||
data = session_resp.json()
|
||||
except Exception:
|
||||
data = {}
|
||||
finally:
|
||||
session_resp.close()
|
||||
if session_resp.status_code == 200 and data.get("code") == 0:
|
||||
return {
|
||||
"success": True,
|
||||
"session_id": data.get("data", {}).get("biz_data", {}).get("id"),
|
||||
"status_code": session_resp.status_code,
|
||||
"data": data,
|
||||
}
|
||||
return {
|
||||
"success": False,
|
||||
"message": data.get("msg") or f"HTTP {session_resp.status_code}",
|
||||
"status_code": session_resp.status_code,
|
||||
"data": data,
|
||||
}
|
||||
|
||||
try:
|
||||
token = account.get("token", "").strip()
|
||||
if token:
|
||||
session_result = _create_session(token)
|
||||
if session_result["success"]:
|
||||
result["valid"] = True
|
||||
result["message"] = "Token 有效"
|
||||
return result
|
||||
|
||||
if _is_token_invalid(session_result["status_code"], session_result["data"]):
|
||||
token = ""
|
||||
account["token"] = ""
|
||||
|
||||
if not token:
|
||||
try:
|
||||
login_deepseek_via_account(account)
|
||||
token = account.get("token", "").strip()
|
||||
session_result = _create_session(token)
|
||||
if session_result["success"]:
|
||||
result["valid"] = True
|
||||
result["has_token"] = True
|
||||
result["message"] = "登录成功并验证通过"
|
||||
else:
|
||||
result["message"] = f"登录成功但验证失败: {session_result['message']}"
|
||||
except Exception as e:
|
||||
result["valid"] = False
|
||||
result["message"] = f"登录失败: {str(e)}"
|
||||
except Exception as e:
|
||||
result["message"] = f"验证出错: {str(e)}"
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@router.post("/accounts/validate")
|
||||
async def validate_account(request: Request, _: bool = Depends(verify_admin)):
|
||||
"""验证单个账号"""
|
||||
data = await request.json()
|
||||
identifier = data.get("identifier", "").strip()
|
||||
|
||||
if not identifier:
|
||||
raise HTTPException(status_code=400, detail="需要账号标识(email 或 mobile)")
|
||||
|
||||
account = None
|
||||
for acc in CONFIG.get("accounts", []):
|
||||
if acc.get("email") == identifier or acc.get("mobile") == identifier:
|
||||
account = acc
|
||||
break
|
||||
|
||||
if not account:
|
||||
raise HTTPException(status_code=404, detail="账号不存在")
|
||||
|
||||
result = await validate_single_account(account)
|
||||
|
||||
if result["valid"] and result["has_token"]:
|
||||
save_config(CONFIG)
|
||||
|
||||
return JSONResponse(content=result)
|
||||
|
||||
|
||||
@router.post("/accounts/validate-all")
|
||||
async def validate_all_accounts(_: bool = Depends(verify_admin)):
|
||||
"""批量验证所有账号"""
|
||||
accounts = CONFIG.get("accounts", [])
|
||||
if not accounts:
|
||||
return JSONResponse(content={
|
||||
"total": 0, "valid": 0, "invalid": 0, "results": [],
|
||||
})
|
||||
|
||||
results = []
|
||||
valid_count = 0
|
||||
|
||||
for acc in accounts:
|
||||
result = await validate_single_account(acc)
|
||||
results.append(result)
|
||||
if result["valid"]:
|
||||
valid_count += 1
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
save_config(CONFIG)
|
||||
|
||||
return JSONResponse(content={
|
||||
"total": len(accounts),
|
||||
"valid": valid_count,
|
||||
"invalid": len(accounts) - valid_count,
|
||||
"results": results,
|
||||
})
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# 账号 API 测试
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
@@ -2,12 +2,8 @@ import { useState, useEffect } from 'react'
|
||||
import {
|
||||
Plus,
|
||||
Trash2,
|
||||
RefreshCw,
|
||||
CheckCircle2,
|
||||
AlertCircle,
|
||||
Search,
|
||||
Play,
|
||||
MoreHorizontal,
|
||||
X,
|
||||
Server,
|
||||
ShieldCheck,
|
||||
@@ -23,8 +19,6 @@ export default function AccountManager({ config, onRefresh, onMessage, authFetch
|
||||
const [copiedKey, setCopiedKey] = useState(null)
|
||||
const [newAccount, setNewAccount] = useState({ email: '', mobile: '', password: '' })
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [validating, setValidating] = useState({})
|
||||
const [validatingAll, setValidatingAll] = useState(false)
|
||||
const [testing, setTesting] = useState({})
|
||||
const [testingAll, setTestingAll] = useState(false)
|
||||
const [batchProgress, setBatchProgress] = useState({ current: 0, total: 0, results: [] })
|
||||
@@ -133,60 +127,6 @@ export default function AccountManager({ config, onRefresh, onMessage, authFetch
|
||||
}
|
||||
}
|
||||
|
||||
const validateAccount = async (identifier) => {
|
||||
setValidating(prev => ({ ...prev, [identifier]: true }))
|
||||
try {
|
||||
const res = await apiFetch('/admin/accounts/validate', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ identifier }),
|
||||
})
|
||||
const data = await res.json()
|
||||
onMessage(data.valid ? 'success' : 'error', `${identifier}: ${data.message}`)
|
||||
onRefresh()
|
||||
} catch (e) {
|
||||
onMessage('error', 'Validation failed: ' + e.message)
|
||||
} finally {
|
||||
setValidating(prev => ({ ...prev, [identifier]: false }))
|
||||
}
|
||||
}
|
||||
|
||||
const validateAllAccounts = async () => {
|
||||
if (!confirm('校验所有账号?这可能需要一些时间。')) return
|
||||
const accounts = config.accounts || []
|
||||
if (accounts.length === 0) return
|
||||
|
||||
setValidatingAll(true)
|
||||
setBatchProgress({ current: 0, total: accounts.length, results: [] })
|
||||
|
||||
let validCount = 0
|
||||
const results = []
|
||||
|
||||
for (let i = 0; i < accounts.length; i++) {
|
||||
const acc = accounts[i]
|
||||
const id = acc.email || acc.mobile
|
||||
|
||||
try {
|
||||
const res = await apiFetch('/admin/accounts/validate', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ identifier: id }),
|
||||
})
|
||||
const data = await res.json()
|
||||
results.push({ id, success: data.valid, message: data.message })
|
||||
if (data.valid) validCount++
|
||||
} catch (e) {
|
||||
results.push({ id, success: false, message: e.message })
|
||||
}
|
||||
|
||||
setBatchProgress({ current: i + 1, total: accounts.length, results: [...results] })
|
||||
}
|
||||
|
||||
onMessage('success', `Completed: ${validCount}/${accounts.length} valid`)
|
||||
onRefresh()
|
||||
setValidatingAll(false)
|
||||
}
|
||||
|
||||
const testAccount = async (identifier) => {
|
||||
setTesting(prev => ({ ...prev, [identifier]: true }))
|
||||
try {
|
||||
@@ -347,20 +287,12 @@ export default function AccountManager({ config, onRefresh, onMessage, authFetch
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<button
|
||||
onClick={testAllAccounts}
|
||||
disabled={testingAll || validatingAll || !config.accounts?.length}
|
||||
disabled={testingAll || !config.accounts?.length}
|
||||
className="flex items-center px-3 py-2 bg-secondary text-secondary-foreground rounded-lg hover:bg-secondary/80 transition-colors text-xs font-medium border border-border disabled:opacity-50"
|
||||
>
|
||||
{testingAll ? <span className="animate-spin mr-2">⟳</span> : <Play className="w-3 h-3 mr-2" />}
|
||||
测试全部
|
||||
</button>
|
||||
<button
|
||||
onClick={validateAllAccounts}
|
||||
disabled={validatingAll || testingAll || !config.accounts?.length}
|
||||
className="flex items-center px-3 py-2 bg-secondary text-secondary-foreground rounded-lg hover:bg-secondary/80 transition-colors text-xs font-medium border border-border disabled:opacity-50"
|
||||
>
|
||||
{validatingAll ? <span className="animate-spin mr-2">⟳</span> : <CheckCircle2 className="w-3 h-3 mr-2" />}
|
||||
校验全部
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setShowAddAccount(true)}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition-colors font-medium text-sm shadow-sm"
|
||||
@@ -372,10 +304,10 @@ export default function AccountManager({ config, onRefresh, onMessage, authFetch
|
||||
</div>
|
||||
|
||||
{/* Batch Progress */}
|
||||
{(testingAll || validatingAll) && batchProgress.total > 0 && (
|
||||
{testingAll && batchProgress.total > 0 && (
|
||||
<div className="p-4 border-b border-border bg-muted/30">
|
||||
<div className="flex items-center justify-between text-sm mb-2">
|
||||
<span className="font-medium">{testingAll ? '正在测试所有账号...' : '正在校验所有账号...'}</span>
|
||||
<span className="font-medium">正在测试所有账号...</span>
|
||||
<span className="text-muted-foreground">{batchProgress.current} / {batchProgress.total}</span>
|
||||
</div>
|
||||
<div className="w-full bg-muted rounded-full h-2 overflow-hidden mb-4">
|
||||
@@ -430,13 +362,6 @@ export default function AccountManager({ config, onRefresh, onMessage, authFetch
|
||||
>
|
||||
{testing[id] ? '正在测试...' : '测试'}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => validateAccount(id)}
|
||||
disabled={validating[id]}
|
||||
className="px-2 lg:px-3 py-1 lg:py-1.5 text-[10px] lg:text-xs font-medium border border-border rounded-md hover:bg-secondary transition-colors disabled:opacity-50"
|
||||
>
|
||||
{validating[id] ? '正在校验...' : '校验'}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => deleteAccount(id)}
|
||||
className="p-1 lg:p-1.5 text-muted-foreground hover:text-destructive hover:bg-destructive/10 rounded-md transition-colors"
|
||||
|
||||
Reference in New Issue
Block a user