from django.db.models import Count from django.shortcuts import get_object_or_404 from rest_framework import permissions, status from rest_framework.response import Response from rest_framework.views import APIView from .models import ContentInteraction, ContentItem, VideoProgress from .services import complete_video ABILITY_META = { ContentItem.Ability.VISION: {"label": "数学眼光", "icon": "◉", "color": "#5d73e8"}, ContentItem.Ability.HUMANITIES: {"label": "数学人文", "icon": "▤", "color": "#b76d38"}, ContentItem.Ability.DETECTION: {"label": "数学侦探", "icon": "⌕", "color": "#287f78"}, ContentItem.Ability.MODELING: {"label": "数学建模", "icon": "⌁", "color": "#d98628"}, ContentItem.Ability.CONNECTION: {"label": "数学联结", "icon": "⛓", "color": "#8667b5"}, } def serialize_item(item, progress=None): return { "slug": item.slug, "title": item.title, "kind": item.kind, "summary": item.summary, "body": item.body, "cover_url": item.cover_url, "media_url": item.media_url, "topics": item.topics, "source": item.source, "ability_dimension": item.ability_dimension, "ability": ABILITY_META.get(item.ability_dimension), "module": item.module, "sub_category": item.sub_category, "discipline": item.discipline, "discipline_icon": item.discipline_icon, "author": item.author, "duration_seconds": item.duration_seconds, "view_count": item.view_count, "comment_count": item.comment_count, "published_at": item.published_at, "progress": ( { "position_seconds": progress.position_seconds, "completed": progress.completed, "reward_granted": progress.reward_granted, } if progress else None ), } class ContentListView(APIView): permission_classes = [permissions.AllowAny] def get(self, request): queryset = ContentItem.objects.filter(is_published=True) kind = request.query_params.get("kind") ability = request.query_params.get("ability") discipline = request.query_params.get("discipline") if kind: queryset = queryset.filter(kind=kind) if ability: queryset = queryset.filter(ability_dimension=ability) if discipline: queryset = queryset.filter(discipline=discipline) progress_by_content = {} if request.user.is_authenticated: progress_by_content = { item.content_id: item for item in VideoProgress.objects.filter( user=request.user, content__in=queryset, ) } return Response( [ serialize_item(item, progress_by_content.get(item.id)) for item in queryset[:100] ] ) class VideoCatalogView(APIView): permission_classes = [permissions.AllowAny] def get(self, request): videos = ContentItem.objects.filter( kind=ContentItem.Kind.VIDEO, is_published=True, ) counts = { row["ability_dimension"]: row["count"] for row in videos.values("ability_dimension").annotate(count=Count("id")) } abilities = [ { "id": ability, **meta, "count": counts.get(ability, 0), } for ability, meta in ABILITY_META.items() ] disciplines = [ { "name": row["discipline"], "icon": row["discipline_icon"], "count": row["count"], } for row in videos.values("discipline", "discipline_icon") .annotate(count=Count("id")) .order_by("discipline") ] return Response( { "total": videos.count(), "abilities": abilities, "disciplines": disciplines, } ) class ContentDetailView(APIView): permission_classes = [permissions.AllowAny] def get(self, request, slug): item = get_object_or_404(ContentItem, slug=slug, is_published=True) progress = None if request.user.is_authenticated: ContentInteraction.objects.get_or_create( user=request.user, content=item, action=ContentInteraction.Action.VIEW, ) progress, _ = VideoProgress.objects.get_or_create( user=request.user, content=item, ) return Response(serialize_item(item, progress)) class VideoCompleteView(APIView): def post(self, request, slug): item = get_object_or_404( ContentItem, slug=slug, kind=ContentItem.Kind.VIDEO, is_published=True, ) progress, reward = complete_video(request.user, item) return Response( { "completed": progress.completed, "reward_granted": progress.reward_granted, "reward": reward, } ) class FavoriteView(APIView): def post(self, request, slug): item = get_object_or_404(ContentItem, slug=slug, is_published=True) _, created = ContentInteraction.objects.get_or_create( user=request.user, content=item, action=ContentInteraction.Action.FAVORITE, ) return Response( {"favorite": True}, status=status.HTTP_201_CREATED if created else status.HTTP_200_OK, ) def delete(self, request, slug): ContentInteraction.objects.filter( user=request.user, content__slug=slug, action=ContentInteraction.Action.FAVORITE, ).delete() return Response(status=status.HTTP_204_NO_CONTENT)