132 lines
4.1 KiB
Python
132 lines
4.1 KiB
Python
"""
|
||
邮箱池控制器(PRD-00009 MT-1)
|
||
|
||
职责:
|
||
- 解析 HTTP 请求参数
|
||
- 调用 services/pool.py 的业务方法
|
||
- 将 service 层业务结果映射为 FD 统一响应格式
|
||
- 将 PoolServiceError 映射为统一错误响应
|
||
|
||
响应格式(FD-00009 §6):
|
||
- 成功:{"success": true, "data": {...}}
|
||
- 失败:{"success": false, "error": "error_code", "message": "错误说明"}
|
||
|
||
HTTP 状态码映射(TD-00009 §6.3):
|
||
- 参数错误 → 400
|
||
- 归属/凭据错误 → 403
|
||
- 状态冲突 → 409
|
||
- 业务失败(如 no_available_account) → 200 + success=false
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from flask import jsonify, request
|
||
|
||
from outlook_web.services.pool import (
|
||
PoolServiceError,
|
||
claim_random,
|
||
complete_claim,
|
||
get_pool_stats,
|
||
release_claim,
|
||
)
|
||
|
||
|
||
def _success_response(data: dict, http_status: int = 200):
|
||
"""统一成功响应:{"success": true, "data": {...}}"""
|
||
return jsonify({"success": True, "data": data}), http_status
|
||
|
||
|
||
def _error_response(error_code: str, message: str, http_status: int = 400):
|
||
"""统一失败响应:{"success": false, "error": "...", "message": "..."}"""
|
||
return jsonify({"success": False, "error": error_code, "message": message}), http_status
|
||
|
||
|
||
def api_claim_random():
|
||
body = request.get_json(silent=True) or {}
|
||
caller_id = body.get("caller_id", "")
|
||
task_id = body.get("task_id", "")
|
||
provider = body.get("provider")
|
||
|
||
try:
|
||
account = claim_random(
|
||
caller_id=caller_id,
|
||
task_id=task_id,
|
||
provider=provider,
|
||
)
|
||
return _success_response(
|
||
{
|
||
"account_id": account["id"],
|
||
"email": account["email"],
|
||
"claim_token": account["claim_token"],
|
||
"lease_expires_at": account["lease_expires_at"],
|
||
}
|
||
)
|
||
except PoolServiceError as exc:
|
||
return _error_response(exc.error_code, str(exc), exc.http_status)
|
||
|
||
|
||
def api_claim_release():
|
||
body = request.get_json(silent=True) or {}
|
||
account_id = body.get("account_id")
|
||
claim_token = body.get("claim_token", "")
|
||
caller_id = body.get("caller_id", "")
|
||
task_id = body.get("task_id", "")
|
||
reason = body.get("reason")
|
||
|
||
if account_id is None:
|
||
return _error_response("account_id_missing", "account_id 不能为空", 400)
|
||
try:
|
||
account_id = int(account_id)
|
||
except (TypeError, ValueError):
|
||
return _error_response("account_id_invalid", "account_id 必须为整数", 400)
|
||
|
||
try:
|
||
release_claim(
|
||
account_id=account_id,
|
||
claim_token=claim_token,
|
||
caller_id=caller_id,
|
||
task_id=task_id,
|
||
reason=reason,
|
||
)
|
||
return _success_response({"account_id": account_id, "pool_status": "available"})
|
||
except PoolServiceError as exc:
|
||
return _error_response(exc.error_code, str(exc), exc.http_status)
|
||
|
||
|
||
def api_claim_complete():
|
||
body = request.get_json(silent=True) or {}
|
||
account_id = body.get("account_id")
|
||
claim_token = body.get("claim_token", "")
|
||
caller_id = body.get("caller_id", "")
|
||
task_id = body.get("task_id", "")
|
||
result = body.get("result", "")
|
||
detail = body.get("detail")
|
||
|
||
if account_id is None:
|
||
return _error_response("account_id_missing", "account_id 不能为空", 400)
|
||
try:
|
||
account_id = int(account_id)
|
||
except (TypeError, ValueError):
|
||
return _error_response("account_id_invalid", "account_id 必须为整数", 400)
|
||
|
||
try:
|
||
new_status = complete_claim(
|
||
account_id=account_id,
|
||
claim_token=claim_token,
|
||
caller_id=caller_id,
|
||
task_id=task_id,
|
||
result=result,
|
||
detail=detail,
|
||
)
|
||
return _success_response({"account_id": account_id, "pool_status": new_status})
|
||
except PoolServiceError as exc:
|
||
return _error_response(exc.error_code, str(exc), exc.http_status)
|
||
|
||
|
||
def api_pool_stats():
|
||
try:
|
||
stats = get_pool_stats()
|
||
return _success_response(stats)
|
||
except Exception as exc:
|
||
return _error_response("internal_error", str(exc), 500)
|