open_api.py 3.9 KB

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