feat(upload): #13 添加上传至sub2api

This commit is contained in:
cnlimiter
2026-03-18 18:23:04 +08:00
parent 6a5d9064f3
commit ffd3a81a38
8 changed files with 551 additions and 45 deletions

View File

@@ -7,7 +7,7 @@ from datetime import datetime, timedelta
from sqlalchemy.orm import Session
from sqlalchemy import and_, or_, desc, asc, func
from .models import Account, EmailService, RegistrationTask, Setting, Proxy, CpaService
from .models import Account, EmailService, RegistrationTask, Setting, Proxy, CpaService, Sub2ApiService
# ============================================================================
@@ -583,4 +583,68 @@ def delete_cpa_service(db: Session, service_id: int) -> bool:
return False
db.delete(db_service)
db.commit()
return True
# ============================================================================
# Sub2API 服务 CRUD
# ============================================================================
def create_sub2api_service(
db: Session,
name: str,
api_url: str,
api_key: str,
enabled: bool = True,
priority: int = 0
) -> Sub2ApiService:
"""创建 Sub2API 服务配置"""
svc = Sub2ApiService(
name=name,
api_url=api_url,
api_key=api_key,
enabled=enabled,
priority=priority,
)
db.add(svc)
db.commit()
db.refresh(svc)
return svc
def get_sub2api_service_by_id(db: Session, service_id: int) -> Optional[Sub2ApiService]:
"""按 ID 获取 Sub2API 服务"""
return db.query(Sub2ApiService).filter(Sub2ApiService.id == service_id).first()
def get_sub2api_services(
db: Session,
enabled: Optional[bool] = None
) -> List[Sub2ApiService]:
"""获取 Sub2API 服务列表"""
query = db.query(Sub2ApiService)
if enabled is not None:
query = query.filter(Sub2ApiService.enabled == enabled)
return query.order_by(asc(Sub2ApiService.priority), asc(Sub2ApiService.id)).all()
def update_sub2api_service(db: Session, service_id: int, **kwargs) -> Optional[Sub2ApiService]:
"""更新 Sub2API 服务配置"""
svc = get_sub2api_service_by_id(db, service_id)
if not svc:
return None
for key, value in kwargs.items():
setattr(svc, key, value)
db.commit()
db.refresh(svc)
return svc
def delete_sub2api_service(db: Session, service_id: int) -> bool:
"""删除 Sub2API 服务配置"""
svc = get_sub2api_service_by_id(db, service_id)
if not svc:
return False
db.delete(svc)
db.commit()
return True

View File

@@ -144,6 +144,20 @@ class CpaService(Base):
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
class Sub2ApiService(Base):
"""Sub2API 服务配置表"""
__tablename__ = 'sub2api_services'
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(100), nullable=False) # 服务名称
api_url = Column(String(500), nullable=False) # API URL (host)
api_key = Column(Text, nullable=False) # x-api-key
enabled = Column(Boolean, default=True)
priority = Column(Integer, default=0) # 优先级
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
class Proxy(Base):
"""代理列表表"""
__tablename__ = 'proxies'

View File

@@ -10,6 +10,7 @@ from .settings import router as settings_router
from .email_services import router as email_services_router
from .payment import router as payment_router
from .cpa_services import router as cpa_services_router
from .sub2api_services import router as sub2api_services_router
api_router = APIRouter()
@@ -20,3 +21,4 @@ api_router.include_router(settings_router, prefix="/settings", tags=["settings"]
api_router.include_router(email_services_router, prefix="/email-services", tags=["email-services"])
api_router.include_router(payment_router, prefix="/payment", tags=["payment"])
api_router.include_router(cpa_services_router, prefix="/cpa-services", tags=["cpa-services"])
api_router.include_router(sub2api_services_router, prefix="/sub2api-services", tags=["sub2api-services"])

View File

@@ -785,3 +785,54 @@ async def batch_upload_accounts_to_cpa(request: BatchCPAUploadRequest):
results = batch_upload_to_cpa(ids, proxy, api_url=cpa_api_url, api_token=cpa_api_token)
return results
class BatchSub2ApiUploadRequest(BaseModel):
"""批量 Sub2API 上传请求"""
ids: List[int] = []
select_all: bool = False
status_filter: Optional[str] = None
email_service_filter: Optional[str] = None
search_filter: Optional[str] = None
service_id: Optional[int] = None # 指定 Sub2API 服务 ID不传则使用第一个启用的
concurrency: int = 3
priority: int = 50
@router.post("/batch-upload-sub2api")
async def batch_upload_accounts_to_sub2api(request: BatchSub2ApiUploadRequest):
"""批量上传账号到 Sub2API"""
from ...core.sub2api_upload import batch_upload_to_sub2api
# 解析指定的 Sub2API 服务
api_url = None
api_key = None
if request.service_id:
with get_db() as db:
svc = crud.get_sub2api_service_by_id(db, request.service_id)
if not svc:
raise HTTPException(status_code=404, detail="指定的 Sub2API 服务不存在")
api_url = svc.api_url
api_key = svc.api_key
else:
with get_db() as db:
svcs = crud.get_sub2api_services(db, enabled=True)
if svcs:
api_url = svcs[0].api_url
api_key = svcs[0].api_key
if not api_url or not api_key:
raise HTTPException(status_code=400, detail="未找到可用的 Sub2API 服务,请先在设置中配置")
with get_db() as db:
ids = resolve_account_ids(
db, request.ids, request.select_all,
request.status_filter, request.email_service_filter, request.search_filter
)
results = batch_upload_to_sub2api(
ids, api_url, api_key,
concurrency=request.concurrency,
priority=request.priority,
)
return results