Files
video/server/app/api/v1/invite.py
T
2026-10-15 20:36:59 +08:00

46 lines
2.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""推广归因路由(/invite/* + H5 中间页 /r/{code})
三段式归因:分享口令(主)→ H5 点击埋点模糊匹配(辅)→ 注册手填邀请码(兜底)
"""
import redis.asyncio as aioredis
from fastapi import APIRouter, Depends, Request
from fastapi.responses import HTMLResponse
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.response import ok
from app.database import get_db
from app.redis_client import get_redis
from app.schemas.invite import InviteClickReq, InviteMatchReq
from app.services import invite_service
router = APIRouter(prefix="/invite", tags=["推广归因"])
router_page = APIRouter(tags=["推广落地页"], include_in_schema=False)
def _client_ip(request: Request) -> str:
# Nginx 反代后取真实 IP
return request.headers.get("X-Real-IP") or (request.client.host if request.client else "")
@router.post("/click")
async def invite_click(req: InviteClickReq, request: Request,
redis: aioredis.Redis = Depends(get_redis)):
"""H5 中间页点击埋点(打开页面即上报,记录 code+IP+UA,24h 有效)"""
ua = request.headers.get("User-Agent", "")
return ok(await invite_service.record_click(redis, req.code.upper(), _client_ip(request), ua))
@router.post("/match")
async def invite_match(req: InviteMatchReq, request: Request,
redis: aioredis.Redis = Depends(get_redis)):
"""App 首启归因匹配:按 IP+时间就近匹配点击记录,结果按 device_id 服务端缓存"""
ua = request.headers.get("User-Agent", "")
return ok(await invite_service.match_and_cache(redis, req.device_id, _client_ip(request), ua))
@router_page.get("/r/{code}", response_class=HTMLResponse)
async def invite_landing(code: str, db: AsyncSession = Depends(get_db),
redis: aioredis.Redis = Depends(get_redis)):
"""推广落地页(复制口令 + 下载入口,打开即自动埋点)"""
return await invite_service.render_landing_page(db, redis, code.upper())