from rest_framework import status from rest_framework.response import Response from rest_framework.parsers import MultiPartParser, FormParser, JSONParser from asgiref.sync import sync_to_async from django.utils import timezone from drf_yasg.utils import swagger_auto_schema from drf_yasg import openapi from chunyu_project.common_schemas import success_response, error_response, unauthorized_response, not_found_response from adrf import generics from .models import BugReport, BugReportComment from .serializers import ( BugReportListSerializer, BugReportDetailSerializer, BugReportCreateSerializer, BugReportCommentCreateSerializer, BugReportCommentSerializer, ) from utils.response_codes import ResponseCode, create_standardized_response, create_standardized_error_response class BugReportListCreateAPIView(generics.ListCreateAPIView): parser_classes = [JSONParser, MultiPartParser, FormParser] def get_serializer_class(self): if self.request.method == 'POST': return BugReportCreateSerializer return BugReportListSerializer def get_queryset(self): if getattr(self, 'swagger_fake_view', False): return BugReport.objects.none() return BugReport.objects.filter(user=self.request.user) @swagger_auto_schema( tags=['反馈'], operation_summary='获取Bug反馈列表', operation_description='获取当前用户提交的所有Bug反馈列表', responses={200: success_response, 401: unauthorized_response} ) async def list(self, request, *args, **kwargs): queryset = self.get_queryset() items = [x async for x in queryset] serializer = self.get_serializer(items, many=True) # 兜底:user_name 触发 user 外键懒加载、images_count 内部有同步 ORM count() data = await sync_to_async(lambda: serializer.data)() return create_standardized_response( code=ResponseCode.SUCCESS, data=data, message='获取Bug反馈列表成功' ) @swagger_auto_schema( tags=['反馈'], operation_summary='提交Bug反馈', operation_description='提交新的Bug反馈,支持上传图片和附件', request_body=BugReportCreateSerializer, responses={201: success_response, 400: error_response, 401: unauthorized_response} ) async def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) is_valid = await sync_to_async(serializer.is_valid)() if is_valid: # 兜底:serializer.create 内部有同步 ORM(BugReport/BugReportImage/BugReportAttachment 的 create) bug_report = await sync_to_async(serializer.save)(user=request.user) detail_serializer = BugReportDetailSerializer(bug_report) # 兜底:detail 序列化会触发 user/images/attachments/comments 的同步懒加载 data = await sync_to_async(lambda: detail_serializer.data)() return create_standardized_response( code=ResponseCode.SUCCESS, data=data, message='Bug反馈提交成功', status_code=status.HTTP_201_CREATED ) return create_standardized_error_response( code=ResponseCode.VALIDATION_ERROR, data=serializer.errors, message='提交失败', status_code=status.HTTP_400_BAD_REQUEST ) class BugReportDetailAPIView(generics.RetrieveAPIView): serializer_class = BugReportDetailSerializer parser_classes = [JSONParser, MultiPartParser] def get_queryset(self): if getattr(self, 'swagger_fake_view', False): return BugReport.objects.none() return BugReport.objects.filter(user=self.request.user) @swagger_auto_schema( tags=['反馈'], operation_summary='获取Bug反馈详情', operation_description='获取指定Bug反馈的详细信息,包括评论和附件', manual_parameters=[ openapi.Parameter('pk', openapi.IN_PATH, description='Bug反馈ID', type=openapi.TYPE_INTEGER, required=True), ], responses={200: success_response, 401: unauthorized_response, 404: not_found_response} ) async def retrieve(self, request, *args, **kwargs): try: instance = await self.get_object() serializer = self.get_serializer(instance) # 兜底:detail 序列化会触发 user/images/attachments/comments 的同步懒加载 data = await sync_to_async(lambda: serializer.data)() return create_standardized_response( code=ResponseCode.SUCCESS, data=data, message='获取Bug反馈详情成功' ) except BugReport.DoesNotExist: return create_standardized_error_response( code=ResponseCode.NOT_FOUND, message='Bug反馈不存在', status_code=status.HTTP_404_NOT_FOUND ) class BugReportCommentCreateAPIView(generics.CreateAPIView): serializer_class = BugReportCommentCreateSerializer parser_classes = [JSONParser, MultiPartParser] @swagger_auto_schema( tags=['反馈'], operation_summary='回复Bug反馈', operation_description='为指定Bug反馈添加评论回复,支持上传图片和附件', manual_parameters=[ openapi.Parameter('bug_report_id', openapi.IN_PATH, description='Bug反馈ID', type=openapi.TYPE_INTEGER, required=True), ], request_body=BugReportCommentCreateSerializer, responses={201: success_response, 400: error_response, 401: unauthorized_response, 404: not_found_response} ) async def create(self, request, *args, **kwargs): bug_report_id = kwargs.get('bug_report_id') try: bug_report = await BugReport.objects.aget(id=bug_report_id, user=request.user) except BugReport.DoesNotExist: return create_standardized_error_response( code=ResponseCode.NOT_FOUND, message='Bug反馈不存在', status_code=status.HTTP_404_NOT_FOUND ) serializer = self.get_serializer(data=request.data) is_valid = await sync_to_async(serializer.is_valid)() if is_valid: # 兜底:serializer.create 内部有同步 ORM(comment 及其图片/附件的 create) comment = await sync_to_async(serializer.save)( user=request.user, bug_report=bug_report, is_admin=False ) comment_serializer = BugReportCommentSerializer(comment) # 兜底:comment 序列化会触发 user 外键与 images/attachments 的同步懒加载 data = await sync_to_async(lambda: comment_serializer.data)() return create_standardized_response( code=ResponseCode.SUCCESS, data=data, message='回复成功', status_code=status.HTTP_201_CREATED ) return create_standardized_error_response( code=ResponseCode.VALIDATION_ERROR, data=serializer.errors, message='回复失败', status_code=status.HTTP_400_BAD_REQUEST )