open_api.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. from typing import Any
  2. from fastapi import APIRouter, Depends, HTTPException, Body
  3. from sqlalchemy.orm import Session
  4. from pydantic import BaseModel
  5. from app.api.v1 import deps
  6. from app.core import security
  7. from app.core.utils import generate_english_name
  8. from app.schemas.user import UserRegister, User as UserSchema
  9. from app.models.user import User, UserStatus, UserRole
  10. from app.models.application import Application
  11. from app.services.sms_service import SmsService
  12. from app.services.captcha_service import CaptchaService
  13. router = APIRouter()
  14. @router.post("/register", response_model=UserSchema, summary="开发者注册")
  15. def register_developer(
  16. req: UserRegister,
  17. db: Session = Depends(deps.get_db),
  18. ):
  19. """
  20. 开发者公开注册接口。
  21. 如果是系统第一个用户,将自动成为超级管理员并激活。
  22. 否则,创建状态为 PENDING,角色为 DEVELOPER 的用户。
  23. """
  24. # 0. Verify SMS Code
  25. if not SmsService.verify_code(req.mobile, req.sms_code):
  26. raise HTTPException(status_code=400, detail="短信验证码无效")
  27. # 1. Check if mobile exists
  28. existing = db.query(User).filter(User.mobile == req.mobile).first()
  29. if existing:
  30. raise HTTPException(status_code=400, detail="该手机号已注册")
  31. # 2. Check if this is the first user
  32. user_count = db.query(User).count()
  33. is_first_user = (user_count == 0)
  34. role = UserRole.SUPER_ADMIN if is_first_user else UserRole.DEVELOPER
  35. status = UserStatus.ACTIVE if is_first_user else UserStatus.PENDING
  36. # 3. Create User
  37. english_name = generate_english_name(req.name)
  38. user = User(
  39. mobile=req.mobile,
  40. name=req.name,
  41. english_name=english_name,
  42. password_hash=security.get_password_hash(req.password),
  43. status=status,
  44. role=role,
  45. is_deleted=0
  46. )
  47. db.add(user)
  48. db.commit()
  49. db.refresh(user)
  50. return user
  51. class AppPublicInfo(BaseModel):
  52. app_id: str
  53. app_name: str
  54. protocol_type: str
  55. redirect_uris: str # JSON string
  56. @router.get("/apps/{app_id}", response_model=AppPublicInfo, summary="获取应用公开信息")
  57. def get_app_public_info(
  58. app_id: str,
  59. db: Session = Depends(deps.get_db),
  60. ):
  61. """
  62. 获取应用的公开信息(协议类型、重定向 URIs)。
  63. 用于登录页面的重定向逻辑。
  64. """
  65. app = db.query(Application).filter(Application.app_id == app_id).first()
  66. if not app:
  67. raise HTTPException(status_code=404, detail="应用未找到")
  68. return AppPublicInfo(
  69. app_id=app.app_id,
  70. app_name=app.app_name,
  71. protocol_type=app.protocol_type,
  72. redirect_uris=app.redirect_uris or "[]"
  73. )
  74. class SmsSendRequest(BaseModel):
  75. mobile: str
  76. captcha_id: str
  77. captcha_code: str
  78. class PasswordResetRequest(BaseModel):
  79. mobile: str
  80. sms_code: str
  81. new_password: str
  82. @router.post("/sms/send", summary="发送短信验证码")
  83. def send_sms(
  84. req: SmsSendRequest
  85. ):
  86. """
  87. 发送短信验证码。需要图形验证码验证。
  88. """
  89. # 1. Verify Captcha
  90. if not CaptchaService.verify_captcha(req.captcha_id, req.captcha_code):
  91. raise HTTPException(status_code=400, detail="图形验证码无效")
  92. # 2. Send SMS
  93. SmsService.send_code(req.mobile)
  94. return {"message": "短信发送成功"}
  95. @router.post("/pwd/reset", summary="重置密码")
  96. def reset_password(
  97. req: PasswordResetRequest,
  98. db: Session = Depends(deps.get_db),
  99. ):
  100. """
  101. 使用短信验证码重置密码。
  102. """
  103. # 1. Verify SMS Code
  104. if not SmsService.verify_code(req.mobile, req.sms_code):
  105. raise HTTPException(status_code=400, detail="短信验证码无效")
  106. # 2. Find User
  107. user = db.query(User).filter(User.mobile == req.mobile).first()
  108. if not user:
  109. raise HTTPException(status_code=404, detail="用户未找到")
  110. # 3. Update Password
  111. if not security.validate_password_strength(req.new_password):
  112. raise HTTPException(status_code=400, detail="密码强度不足,必须包含字母和数字")
  113. user.password_hash = security.get_password_hash(req.new_password)
  114. db.add(user)
  115. db.commit()
  116. return {"message": "密码重置成功"}