feat: implement Telegram account binding and update project structure in documentation

This commit is contained in:
2569718930@qq.com
2026-05-18 17:10:44 +08:00
parent 1b2731ed12
commit 78b23ef361
8 changed files with 247 additions and 99 deletions
+4
View File
@@ -411,6 +411,10 @@ class TelegramLoginRequest(BaseModel):
hash: str = Field(..., min_length=10)
class TelegramBindTokenRequest(BaseModel):
token: str = Field(..., min_length=8)
class AnalyticsEventRequest(BaseModel):
event_type: str = Field(..., min_length=3, max_length=64)
client_id: Optional[str] = Field(default=None, max_length=128)
+11 -2
View File
@@ -2,8 +2,12 @@
from fastapi import APIRouter, Request
from web.core import TelegramLoginRequest
from web.services.auth_api import get_auth_me_payload, login_with_telegram
from web.core import TelegramBindTokenRequest, TelegramLoginRequest
from web.services.auth_api import (
bind_telegram_by_token,
get_auth_me_payload,
login_with_telegram,
)
router = APIRouter(tags=["auth"])
@@ -16,3 +20,8 @@ async def auth_me(request: Request):
@router.post("/api/auth/telegram/login")
async def auth_telegram_login(request: Request, body: TelegramLoginRequest):
return login_with_telegram(request, body)
@router.post("/api/auth/telegram/bind-by-token")
async def auth_telegram_bind_by_token(request: Request, body: TelegramBindTokenRequest):
return bind_telegram_by_token(request, body)
+40
View File
@@ -157,3 +157,43 @@ def login_with_telegram(request: Request, body: TelegramLoginRequest) -> Dict[st
"binding": bind_result,
"telegram_pricing": price,
}
def bind_telegram_by_token(request: Request, body) -> Dict[str, Any]:
"""Bind Telegram identity using a one-time token from the bot /bind command."""
legacy_routes._assert_entitlement(request)
identity = legacy_routes._require_supabase_identity(request)
token = str(getattr(body, "token", "") or "").strip()
if not token:
raise HTTPException(status_code=400, detail="bind_token is required")
db = DBManager()
telegram_id = db.consume_bind_token(token)
if telegram_id is None:
raise HTTPException(status_code=400, detail="invalid or expired bind token")
pricing = TelegramGroupPricing()
member_status = pricing.get_member_status(telegram_id) if pricing.configured else None
if not member_status or member_status not in ("creator", "administrator", "member"):
raise HTTPException(status_code=403, detail="not a group member")
db.upsert_user(telegram_id, "")
bind_result = db.bind_supabase_identity(
telegram_id=telegram_id,
supabase_user_id=identity["user_id"],
supabase_email=identity.get("email") or "",
)
if not bind_result.get("ok"):
raise HTTPException(
status_code=409,
detail=str(bind_result.get("reason") or "telegram bind failed"),
)
price = pricing.resolve_price_for_telegram_id(telegram_id)
return {
"ok": True,
"telegram_id": telegram_id,
"binding": bind_result,
"telegram_pricing": price,
}