tracking.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. from fastapi import APIRouter, Depends, Request
  2. from sqlalchemy.orm import Session
  3. from pydantic import BaseModel
  4. from database import get_db, get_unix
  5. from models.tracking import TrackingRecord, ApiPathMapping
  6. import uuid
  7. router = APIRouter()
  8. class TrackingRequest(BaseModel):
  9. api_path: str
  10. api_name: str = ""
  11. def _get_tracking_user_id(user) -> str:
  12. """统一获取埋点所需的字符串用户标识。"""
  13. if not user:
  14. return ""
  15. return str(
  16. getattr(user, "userCode", "")
  17. or getattr(user, "user_code", "")
  18. or getattr(user, "account", "")
  19. or getattr(user, "account_id", "")
  20. or getattr(user, "user_id", "")
  21. or ""
  22. )
  23. @router.post("/tracking/record")
  24. async def record_tracking(
  25. request: Request,
  26. data: TrackingRequest,
  27. db: Session = Depends(get_db)
  28. ):
  29. """记录埋点"""
  30. user = request.state.user
  31. user_id = _get_tracking_user_id(user)
  32. if not user_id:
  33. return {"statusCode": 401, "msg": "未授权"}
  34. # 获取客户端IP
  35. client_ip = request.client.host if request.client else ""
  36. # 生成请求ID
  37. request_id = str(uuid.uuid4())
  38. # 创建埋点记录
  39. record = TrackingRecord(
  40. user_id=user_id,
  41. api_path=data.api_path,
  42. api_name=data.api_name,
  43. method=request.method,
  44. request_id=request_id,
  45. ip_address=client_ip,
  46. created_at=get_unix()
  47. )
  48. db.add(record)
  49. db.commit()
  50. return {"statusCode": 200, "msg": "记录成功", "data": {"request_id": request_id}}
  51. @router.get("/tracking/records")
  52. async def get_tracking_records(
  53. request: Request,
  54. limit: int = 100,
  55. db: Session = Depends(get_db)
  56. ):
  57. """获取埋点记录"""
  58. user = request.state.user
  59. user_id = _get_tracking_user_id(user)
  60. if not user_id:
  61. return {"statusCode": 401, "msg": "未授权"}
  62. records = db.query(TrackingRecord).filter(
  63. TrackingRecord.user_id == user_id
  64. ).order_by(TrackingRecord.created_at.desc()).limit(limit).all()
  65. return {
  66. "statusCode": 200,
  67. "msg": "success",
  68. "data": [
  69. {
  70. "id": r.id,
  71. "api_path": r.api_path,
  72. "api_name": r.api_name,
  73. "created_at": r.created_at
  74. }
  75. for r in records
  76. ]
  77. }
  78. class ApiMappingRequest(BaseModel):
  79. api_path: str
  80. api_name: str
  81. api_desc: str = ""
  82. @router.post("/tracking/api_mapping")
  83. async def add_api_mapping(
  84. request: Request,
  85. data: ApiMappingRequest,
  86. db: Session = Depends(get_db)
  87. ):
  88. """添加API映射"""
  89. user = request.state.user
  90. if not user:
  91. return {"statusCode": 401, "msg": "未授权"}
  92. # 检查是否已存在
  93. existing = db.query(ApiPathMapping).filter(
  94. ApiPathMapping.api_path == data.api_path
  95. ).first()
  96. if existing:
  97. return {"statusCode": 400, "msg": "API映射已存在"}
  98. mapping = ApiPathMapping(
  99. api_path=data.api_path,
  100. api_name=data.api_name,
  101. api_desc=data.api_desc,
  102. created_at=get_unix()
  103. )
  104. db.add(mapping)
  105. db.commit()
  106. db.refresh(mapping)
  107. return {
  108. "statusCode": 200,
  109. "msg": "添加成功",
  110. "data": {"id": mapping.id}
  111. }
  112. @router.get("/tracking/api_mappings")
  113. async def get_api_mappings(
  114. request: Request,
  115. db: Session = Depends(get_db)
  116. ):
  117. """获取API映射"""
  118. user = request.state.user
  119. if not user:
  120. return {"statusCode": 401, "msg": "未授权"}
  121. mappings = db.query(ApiPathMapping).all()
  122. return {
  123. "statusCode": 200,
  124. "msg": "success",
  125. "data": [
  126. {
  127. "id": m.id,
  128. "api_path": m.api_path,
  129. "api_name": m.api_name,
  130. "api_desc": m.api_desc,
  131. "status": m.status
  132. }
  133. for m in mappings
  134. ]
  135. }
  136. # get_user_data_id 已移至 routers/total.py,避免路由重复