from rest_framework import status from adrf.views import APIView from rest_framework.permissions import IsAuthenticated from asgiref.sync import sync_to_async from utils.response_codes import ( ResponseCode, create_standardized_response, create_standardized_error_response ) from ..serializers.user_serializers import ( SendPhoneCodeSerializer, ChangePhoneSerializer, UserSerializer, ) class SendPhoneCodeAPIView(APIView): permission_classes = [IsAuthenticated] async def post(self, request): from utils.rate_limit import check_rate_limit identifier = str(request.user.id) if not await sync_to_async(check_rate_limit)('change_phone_send', identifier, limit=1, window_seconds=60): return create_standardized_error_response( code=ResponseCode.PARAMETER_ERROR, message="短信验证码发送过于频繁,请60秒后再试", status_code=status.HTTP_429_TOO_MANY_REQUESTS ) serializer = SendPhoneCodeSerializer( data=request.data, context={'request': request} ) # 校验/save 内含 cache 写入,线程池兜底 if not await sync_to_async(serializer.is_valid)(): errors = serializer.errors first_error = '' for field, msgs in errors.items(): if isinstance(msgs, list) and msgs: first_error = str(msgs[0]) break return create_standardized_error_response( data=errors, code=ResponseCode.PARAMETER_ERROR, message=first_error or '参数异常', status_code=status.HTTP_400_BAD_REQUEST ) try: phone = await serializer.asave() return create_standardized_response( data={'phone_sent': True}, code=ResponseCode.SUCCESS, status_code=status.HTTP_200_OK ) except Exception as e: return create_standardized_error_response( message=f'验证码发送失败: {str(e)}', code=ResponseCode.SERVER_INTERNAL_ERROR, status_code=status.HTTP_500_INTERNAL_SERVER_ERROR ) class ChangePhoneAPIView(APIView): permission_classes = [IsAuthenticated] async def post(self, request): serializer = ChangePhoneSerializer( data=request.data, context={'request': request} ) # 校验/save 内含 cache 读写与 user.save() ORM 调用,线程池兜底 if not await sync_to_async(serializer.is_valid)(): errors = serializer.errors first_error = '' for field, msgs in errors.items(): if isinstance(msgs, list) and msgs: first_error = str(msgs[0]) break return create_standardized_error_response( data=errors, code=ResponseCode.PARAMETER_ERROR, message=first_error or '参数异常', status_code=status.HTTP_400_BAD_REQUEST ) # 安全修复:此前从未调用 avalidate,短信验证码校验为死代码(可无码改绑手机号) try: await serializer.avalidate(serializer.validated_data) except Exception as e: return create_standardized_error_response( data=getattr(e, 'detail', None) or {'code': [str(e)]}, code=ResponseCode.PARAMETER_ERROR, message='验证码校验失败', status_code=status.HTTP_400_BAD_REQUEST ) try: updated_user = await serializer.asave() user_serializer = UserSerializer(updated_user) return create_standardized_response( data={'user': await user_serializer.adata}, code=ResponseCode.SUCCESS, status_code=status.HTTP_200_OK ) except Exception as e: return create_standardized_error_response( message=f'手机号修改失败: {str(e)}', code=ResponseCode.SERVER_INTERNAL_ERROR, status_code=status.HTTP_500_INTERNAL_SERVER_ERROR )