refactor: 补全services层+消除core/models.py冗余+修复network.py缩进错误

高优先级问题1 - Router层业务逻辑泄漏:
- 新建 services/proxy_service.py: 从routers/proxy.py提取ProxyService类,
  封装代理/白名单测试逻辑、全局状态管理、所有core/ import
- 新建 services/account_service.py: 从routers/accounts.py提取
  split_account_line、cookie_account_ids_query、parse_and_build_accounts,
  封装core.douyu.email_verifier的import
- 重写routers/proxy.py为薄HTTP/WS层,移除所有core/直接依赖
- 精简routers/accounts.py,从account_service导入业务函数
- 将_active_batches全局状态移入login_service.py的BatchRegistry类
- routers/login.py改为使用batch_registry单例

高优先级问题2 - 两套models.py冗余:
- 删除core/models.py(Account dataclass + ProxyConfig死代码)
- 在core/douyu/login.py新增AccountLike Protocol替代Account dataclass
- login_service.py中Account(...)构造改为SimpleNamespace(...)
- 清理core/__init__.py导出

附带修复:
- core/geetest/common/network.py的get_picture()函数缩进错误
  (缺少if match:块和data赋值语句)
This commit is contained in:
yml2213
2026-06-23 07:34:17 +08:00
parent 12c31c2e09
commit 2ab6724543
10 changed files with 411 additions and 333 deletions
+9 -62
View File
@@ -1,41 +1,20 @@
"""账号管理路由"""
import re
import csv
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from sqlalchemy import func
from sqlalchemy.orm import Session, joinedload
from ..database import get_db
from ..models import User, Account, AuditLog, LoginTask
from ..schemas import AccountImport, AccountAssign, AccountTag, AccountOut, BatchAssign
from ..deps import get_current_user, require_permission
from ..permissions import user_has_permission
from sqlalchemy import func
from sqlalchemy.orm import joinedload
from ..services.account_service import (
cookie_account_ids_query, parse_and_build_accounts,
)
router = APIRouter(prefix="/api/accounts", tags=["账号管理"])
EMAIL_PATTERN = re.compile(r'^[^\s@|]+@[^\s@|]+\.[^\s@|]+$')
def _split_account_line(line: str) -> list[str]:
if '|' in line:
return line.split('|')
if '\t' in line:
return line.split('\t')
if ',' in line:
return next(csv.reader([line]))
return line.split()
def _cookie_account_ids_query(db: Session):
"""返回有成功登录记录(cookie非空)的账号ID子查询。"""
return db.query(LoginTask.account_id).filter(
LoginTask.status == 'success',
LoginTask.cookie != '',
LoginTask.cookie.isnot(None),
).distinct()
@router.get("", response_model=list[AccountOut])
def list_accounts(
@@ -50,7 +29,7 @@ def list_accounts(
# 只展示已成功登录过的账号
if has_cookie:
query = query.filter(Account.id.in_(_cookie_account_ids_query(db)))
query = query.filter(Account.id.in_(cookie_account_ids_query(db)))
# 权限控制:客服只能看分配给自己的
if not user_has_permission(current, "account:view_all"):
@@ -91,39 +70,7 @@ def import_accounts(
current: User = Depends(require_permission("account:import")),
):
"""批量导入账号。格式:用户名|密码|邮箱|邮箱密码|标签(可选)"""
from core.douyu.email_verifier import get_email_config_for_account
accounts = []
skipped = 0
for line_num, line in enumerate(req.text.strip().split('\n'), 1):
line = line.strip()
if not line or line.startswith('#'):
continue
parts = _split_account_line(line)
if len(parts) < 4:
skipped += 1
continue
username, password, email, email_password = [p.strip() for p in parts[:4]]
tag = parts[4].strip() if len(parts) > 4 else ""
if not all([username, password, email, email_password]):
skipped += 1
continue
if not EMAIL_PATTERN.match(email):
skipped += 1
continue
email_cfg = get_email_config_for_account(email)
accounts.append(Account(
username=username,
password=password,
email=email,
email_password=email_password,
email_imap_server=email_cfg['server'],
email_imap_port=email_cfg.get('port', 993),
email_imap_ssl=email_cfg.get('ssl', True),
tag=tag,
))
accounts, skipped = parse_and_build_accounts(req.text)
if accounts:
db.add_all(accounts)
@@ -187,7 +134,7 @@ def batch_assign_accounts(
raise HTTPException(status_code=400, detail="只能分配给客服角色")
# 只能分配已成功登录过的账号(有cookie)
cookie_ids_query = _cookie_account_ids_query(db).subquery()
cookie_ids_query = cookie_account_ids_query(db).subquery()
invalid_ids = db.query(Account.id).filter(
Account.id.in_(req.account_ids),
Account.id.notin_(cookie_ids_query),
@@ -220,7 +167,7 @@ def assignments_summary(
current: User = Depends(require_permission("account:assign")),
):
"""分配概览:每个客服分配了多少账号(仅统计已成功登录的账号)。"""
cookie_subq = _cookie_account_ids_query(db).subquery()
cookie_subq = cookie_account_ids_query(db).subquery()
cookie_accounts = db.query(Account).filter(Account.id.in_(cookie_subq)).subquery()
results = (