97 lines
4.0 KiB
Python
97 lines
4.0 KiB
Python
from django.db.models import Q
|
|
from rest_framework.views import APIView
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from rest_framework import status
|
|
from drf_yasg.utils import swagger_auto_schema
|
|
from drf_yasg import openapi
|
|
from learn.models import ChapterRead
|
|
from article.models import Article
|
|
from learn.models import CourseFavorite
|
|
|
|
from utils.response_codes import create_standardized_response, create_standardized_error_response
|
|
|
|
success_response = openapi.Response('成功', examples={'application/json': {'code': 10000, 'message': 'success'}})
|
|
unauthorized_response = openapi.Response('未授权', examples={'application/json': {'code': 40101, 'message': '未登录'}})
|
|
|
|
|
|
class UserActivityView(APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
@swagger_auto_schema(
|
|
tags=['用户'],
|
|
operation_summary='获取用户活动时间线',
|
|
operation_description='聚合用户的各种活动(发表文章、收藏、学习进度等),按时间倒序返回',
|
|
manual_parameters=[
|
|
openapi.Parameter('page', openapi.IN_QUERY, description='页码', type=openapi.TYPE_INTEGER, default=1),
|
|
openapi.Parameter('page_size', openapi.IN_QUERY, description='每页数量', type=openapi.TYPE_INTEGER, default=20),
|
|
],
|
|
responses={200: success_response, 401: unauthorized_response},
|
|
)
|
|
def get(self, request):
|
|
user = request.user
|
|
page = int(request.query_params.get('page', 1))
|
|
page_size = int(request.query_params.get('page_size', 20))
|
|
|
|
activities = []
|
|
|
|
# 文章活动
|
|
articles = Article.objects.filter(author=user, status='published').order_by('-created_at')[:50]
|
|
for article in articles:
|
|
activities.append({
|
|
'id': f'article_{article.id}',
|
|
'type': 'article',
|
|
'title': '发表文章',
|
|
'description': f'发布了《{article.title}》',
|
|
'target_id': article.id,
|
|
'target_type': 'article',
|
|
'created_at': article.created_at.strftime('%Y-%m-%d %H:%M:%S'),
|
|
'timestamp': int(article.created_at.timestamp()),
|
|
})
|
|
|
|
# 收藏活动
|
|
favorites = CourseFavorite.objects.filter(user=user).select_related('course').order_by('-created_at')[:50]
|
|
for fav in favorites:
|
|
activities.append({
|
|
'id': f'favorite_{fav.id}',
|
|
'type': 'favorite',
|
|
'title': '收藏课程',
|
|
'description': f'收藏了《{fav.course.title}》',
|
|
'target_id': fav.course.id,
|
|
'target_type': 'course',
|
|
'created_at': fav.created_at.strftime('%Y-%m-%d %H:%M:%S'),
|
|
'timestamp': int(fav.created_at.timestamp()),
|
|
})
|
|
|
|
# 学习进度
|
|
reads = ChapterRead.objects.filter(user=user, completed=True).select_related('chapter', 'course').order_by('-completed_at')[:50]
|
|
for read in reads:
|
|
activities.append({
|
|
'id': f'study_{read.id}',
|
|
'type': 'study',
|
|
'title': '完成学习',
|
|
'description': f'完成了《{read.course.title}》- {read.chapter.title}',
|
|
'target_id': read.chapter.id,
|
|
'target_type': 'chapter',
|
|
'created_at': read.completed_at.strftime('%Y-%m-%d %H:%M:%S') if read.completed_at else '',
|
|
'timestamp': int(read.completed_at.timestamp()) if read.completed_at else 0,
|
|
})
|
|
|
|
# 按时间戳倒序排序
|
|
activities.sort(key=lambda x: x['timestamp'], reverse=True)
|
|
|
|
# 分页
|
|
total = len(activities)
|
|
start = (page - 1) * page_size
|
|
end = start + page_size
|
|
paginated = activities[start:end]
|
|
|
|
return create_standardized_response(
|
|
data={
|
|
'activities': paginated,
|
|
'total': total,
|
|
'page': page,
|
|
'page_size': page_size,
|
|
'has_more': end < total,
|
|
}
|
|
)
|