143 lines
5.8 KiB
Python
143 lines
5.8 KiB
Python
from rest_framework import status
|
||
from rest_framework.permissions import IsAuthenticated
|
||
from rest_framework.parsers import JSONParser
|
||
from adrf.views import APIView
|
||
from rest_framework.pagination import PageNumberPagination
|
||
from rest_framework.response import Response
|
||
from asgiref.sync import sync_to_async
|
||
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 adrf.generics import aget_object_or_404
|
||
|
||
from utils.response_codes import ResponseCode, create_standardized_response, create_standardized_error_response
|
||
from .models import BrowsingHistory
|
||
from .serializers import BrowsingHistorySerializer, BrowsingHistoryCreateSerializer
|
||
|
||
|
||
class HistoryPagination(PageNumberPagination):
|
||
page_size = 50
|
||
page_size_query_param = 'page_size'
|
||
max_page_size = 200
|
||
|
||
def get_paginated_response(self, data):
|
||
return Response({
|
||
'code': 10000,
|
||
'message': 'Success',
|
||
'data': {
|
||
'count': self.page.paginator.count,
|
||
'next': self.get_next_link(),
|
||
'previous': self.get_previous_link(),
|
||
'results': data,
|
||
}
|
||
})
|
||
|
||
|
||
class BrowsingHistoryListCreateView(generics.ListCreateAPIView):
|
||
permission_classes = [IsAuthenticated]
|
||
parser_classes = [JSONParser]
|
||
pagination_class = HistoryPagination
|
||
|
||
def get_serializer_class(self):
|
||
if self.request.method == 'POST':
|
||
return BrowsingHistoryCreateSerializer
|
||
return BrowsingHistorySerializer
|
||
|
||
def get_queryset(self):
|
||
qs = BrowsingHistory.objects.filter(user=self.request.user)
|
||
# 隐藏实用工具、编程学习和文章资源
|
||
qs = qs.exclude(type__in=['utility', 'learn', 'article'])
|
||
record_type = self.request.query_params.get('type')
|
||
if record_type:
|
||
qs = qs.filter(type=record_type)
|
||
return qs
|
||
|
||
@swagger_auto_schema(
|
||
tags=['历史'],
|
||
operation_summary='获取浏览历史列表',
|
||
operation_description='获取当前用户的浏览历史记录,支持按类型筛选和分页',
|
||
manual_parameters=[
|
||
openapi.Parameter('type', openapi.IN_QUERY, description='记录类型筛选: tool/api', type=openapi.TYPE_STRING),
|
||
openapi.Parameter('page', openapi.IN_QUERY, description='页码', type=openapi.TYPE_INTEGER),
|
||
openapi.Parameter('page_size', openapi.IN_QUERY, description='每页数量', type=openapi.TYPE_INTEGER),
|
||
],
|
||
responses={200: success_response, 401: unauthorized_response}
|
||
)
|
||
async def list(self, request, *args, **kwargs):
|
||
queryset = self.filter_queryset(self.get_queryset())
|
||
# 兜底:DRF 分页器内部同步评估 queryset(count + 切片取值)
|
||
page = await sync_to_async(self.paginate_queryset)(queryset)
|
||
if page is not None:
|
||
serializer = self.get_serializer(page, many=True)
|
||
return self.get_paginated_response(await serializer.adata)
|
||
results = [x async for x in queryset]
|
||
serializer = self.get_serializer(results, many=True)
|
||
return Response({'code': 10000, 'message': 'Success', 'data': await serializer.adata})
|
||
|
||
@swagger_auto_schema(
|
||
tags=['历史'],
|
||
operation_summary='创建浏览记录',
|
||
operation_description='记录用户的浏览历史,同一链接一小时内重复访问会更新时间',
|
||
request_body=BrowsingHistoryCreateSerializer,
|
||
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 = serializer.is_valid()
|
||
if is_valid:
|
||
# 兜底:serializer.create 内部有同步 ORM(filter/first/save/create)
|
||
instance = await serializer.asave()
|
||
return create_standardized_response(
|
||
data=BrowsingHistorySerializer(instance).data,
|
||
code=ResponseCode.SUCCESS,
|
||
message='记录成功',
|
||
status_code=status.HTTP_201_CREATED
|
||
)
|
||
return create_standardized_error_response(
|
||
data=serializer.errors,
|
||
code=ResponseCode.VALIDATION_ERROR,
|
||
status_code=status.HTTP_400_BAD_REQUEST
|
||
)
|
||
|
||
|
||
class BrowsingHistoryDeleteView(APIView):
|
||
permission_classes = [IsAuthenticated]
|
||
|
||
@swagger_auto_schema(
|
||
tags=['历史'],
|
||
operation_summary='删除浏览记录',
|
||
operation_description='删除指定的浏览历史记录',
|
||
manual_parameters=[
|
||
openapi.Parameter('pk', openapi.IN_PATH, description='记录ID', type=openapi.TYPE_INTEGER, required=True),
|
||
],
|
||
responses={204: '删除成功', 401: unauthorized_response, 404: not_found_response}
|
||
)
|
||
async def delete(self, request, pk):
|
||
record = await aget_object_or_404(BrowsingHistory, pk=pk, user=request.user)
|
||
await record.adelete()
|
||
return create_standardized_response(
|
||
code=ResponseCode.SUCCESS,
|
||
message='删除成功',
|
||
status_code=status.HTTP_204_NO_CONTENT
|
||
)
|
||
|
||
|
||
class BrowsingHistoryClearView(APIView):
|
||
permission_classes = [IsAuthenticated]
|
||
|
||
@swagger_auto_schema(
|
||
tags=['历史'],
|
||
operation_summary='清空浏览记录',
|
||
operation_description='清空当前用户的所有浏览历史记录',
|
||
responses={200: success_response, 401: unauthorized_response}
|
||
)
|
||
async def delete(self, request):
|
||
count = (await BrowsingHistory.objects.filter(user=request.user).adelete())[0]
|
||
return create_standardized_response(
|
||
data={'deleted': count},
|
||
code=ResponseCode.SUCCESS,
|
||
message='清空成功'
|
||
)
|