205 lines
5.8 KiB
Python
205 lines
5.8 KiB
Python
"""
|
|
用户注册 Use Case
|
|
"""
|
|
|
|
import secrets
|
|
from datetime import datetime, timedelta, timezone
|
|
from typing import Optional
|
|
from uuid import uuid4
|
|
|
|
from packages.adapters.smtp import get_email_service
|
|
from packages.domain.auth import password_hasher, password_validator
|
|
from packages.domain.entities import User
|
|
|
|
|
|
class RegisterUserRequest:
|
|
"""注册请求"""
|
|
|
|
def __init__(
|
|
self,
|
|
email: str,
|
|
password: str,
|
|
username: str,
|
|
display_name: str,
|
|
):
|
|
self.email = email.strip().lower()
|
|
self.password = password
|
|
self.username = username.strip()
|
|
self.display_name = display_name.strip()
|
|
|
|
|
|
class RegisterUserResponse:
|
|
"""注册响应"""
|
|
|
|
def __init__(
|
|
self,
|
|
user_id: str,
|
|
email: str,
|
|
username: str,
|
|
display_name: str,
|
|
email_verification_sent: bool,
|
|
):
|
|
self.user_id = user_id
|
|
self.email = email
|
|
self.username = username
|
|
self.display_name = display_name
|
|
self.email_verification_sent = email_verification_sent
|
|
|
|
|
|
class RegisterUserUseCase:
|
|
"""用户注册用例"""
|
|
|
|
def __init__(
|
|
self,
|
|
user_repository,
|
|
base_url: str = "http://localhost:3000",
|
|
email_service=None,
|
|
):
|
|
"""
|
|
初始化注册用例
|
|
|
|
Args:
|
|
user_repository: 用户仓储
|
|
base_url: 应用基础 URL(用于生成验证链接)
|
|
"""
|
|
self.user_repository = user_repository
|
|
self.base_url = base_url
|
|
self.email_service = email_service or get_email_service()
|
|
|
|
def execute(self, request: RegisterUserRequest) -> tuple[Optional[RegisterUserResponse], Optional[str]]:
|
|
"""
|
|
执行注册
|
|
|
|
Args:
|
|
request: 注册请求
|
|
|
|
Returns:
|
|
(注册响应, 错误信息)
|
|
"""
|
|
try:
|
|
# 1. 验证输入
|
|
if not request.email:
|
|
return None, "Email is required"
|
|
|
|
if not request.username:
|
|
return None, "Username is required"
|
|
|
|
if not request.display_name:
|
|
return None, "Display name is required"
|
|
|
|
# 2. 验证密码强度
|
|
valid, error = password_validator.validate(request.password)
|
|
if not valid:
|
|
return None, error
|
|
|
|
# 3. 检查邮箱是否已存在
|
|
existing_user = self.user_repository.find_by_email(request.email)
|
|
if existing_user:
|
|
return None, "Email already registered"
|
|
|
|
# 4. 检查用户名是否已存在
|
|
existing_username = self.user_repository.find_by_username(request.username)
|
|
if existing_username:
|
|
return None, "Username already taken"
|
|
|
|
# 5. 哈希密码
|
|
hashed_password = password_hasher.hash_password(request.password)
|
|
|
|
# 6. 生成邮箱验证令牌
|
|
verification_token = secrets.token_urlsafe(32)
|
|
|
|
# 7. 创建用户
|
|
user = User(
|
|
id=uuid4().hex,
|
|
email=request.email,
|
|
username=request.username,
|
|
display_name=request.display_name,
|
|
password_hash=hashed_password,
|
|
email_verified=False,
|
|
email_verification_token=verification_token,
|
|
created_at=datetime.now(timezone.utc),
|
|
)
|
|
|
|
# 8. 保存用户
|
|
self.user_repository.save(user)
|
|
|
|
# 9. 发送验证邮件
|
|
verification_url = f"{self.base_url}/verify-email?token={verification_token}"
|
|
email_sent = False
|
|
|
|
try:
|
|
success, error = self.email_service.send_verification_email(
|
|
to_email=user.email,
|
|
username=user.username,
|
|
verification_url=verification_url,
|
|
)
|
|
email_sent = success
|
|
|
|
if not success:
|
|
print(f"Failed to send verification email: {error}")
|
|
except Exception as e:
|
|
print(f"Email service error: {e}")
|
|
|
|
# 10. 返回响应(即使邮件发送失败,用户也已创建)
|
|
return (
|
|
RegisterUserResponse(
|
|
user_id=user.id,
|
|
email=user.email,
|
|
username=user.username,
|
|
display_name=user.display_name,
|
|
email_verification_sent=email_sent,
|
|
),
|
|
None,
|
|
)
|
|
|
|
except Exception as e:
|
|
return None, f"Registration failed: {str(e)}"
|
|
|
|
|
|
class VerifyEmailRequest:
|
|
"""邮箱验证请求"""
|
|
|
|
def __init__(self, token: str):
|
|
self.token = token
|
|
|
|
|
|
class VerifyEmailUseCase:
|
|
"""邮箱验证用例"""
|
|
|
|
def __init__(self, user_repository):
|
|
self.user_repository = user_repository
|
|
|
|
def execute(self, request: VerifyEmailRequest) -> tuple[bool, Optional[str]]:
|
|
"""
|
|
执行邮箱验证
|
|
|
|
Args:
|
|
request: 验证请求
|
|
|
|
Returns:
|
|
(是否成功, 错误信息)
|
|
"""
|
|
try:
|
|
if not request.token:
|
|
return False, "Verification token is required"
|
|
|
|
# 查找用户
|
|
user = self.user_repository.find_by_verification_token(request.token)
|
|
if not user:
|
|
return False, "Invalid or expired verification token"
|
|
|
|
# 检查是否已验证
|
|
if user.email_verified:
|
|
return True, None # 已验证,返回成功
|
|
|
|
# 更新用户状态
|
|
user.email_verified = True
|
|
user.email_verification_token = None # 清空令牌
|
|
|
|
self.user_repository.save(user)
|
|
|
|
return True, None
|
|
|
|
except Exception as e:
|
|
return False, f"Email verification failed: {str(e)}"
|