from rest_framework.generics import ListAPIView, RetrieveAPIView from django.db.models import Count, Q, F from drf_yasg.utils import swagger_auto_schema from drf_yasg import openapi from rest_framework.exceptions import NotFound from rest_framework.permissions import IsAuthenticated from rest_framework.filters import SearchFilter from apps.course.serializers import ( CourseListSerializer, CourseCategorySerializer, CourseDetailSerializer, AttachmentSerializer, GlossarySerializer, MyCourseListSerializer ) from apps.course.models import Course, CourseCategory, Attachment, Glossary, Participant from apps.course.doc import * class CourseCategoryAPIView(ListAPIView): queryset = CourseCategory.objects.all() serializer_class = CourseCategorySerializer @swagger_auto_schema( operation_description=doc_course_category(), ) def get(self, request, *args, **kwargs): return super().get(request, *args, **kwargs) class CourseListAPIView(ListAPIView): queryset = Course.objects.all().exclude(status=Course.StatusChoices.INACTIVE) serializer_class = CourseListSerializer filter_backends = [SearchFilter] search_fields = ['title'] @swagger_auto_schema( operation_description=doc_course_list(), manual_parameters=[ openapi.Parameter( 'category_slug', openapi.IN_QUERY, description="Category of the Course", type=openapi.TYPE_STRING, enum=[category.slug for category in CourseCategory.objects.all()] ), openapi.Parameter( 'status', openapi.IN_QUERY, type=openapi.TYPE_STRING, description="""Status => Upcoming (visible but registration not allowed)---Предстоящие Registering (registration is open)---регистрация Ongoing (course has started, registration closed)---Впроцессе Finished (course has ended)---закончился """, enum=[status for status in ['upcoming', 'registering', 'ongoing', 'finished']] ), openapi.Parameter( 'is_free', openapi.IN_QUERY, description="Ценообразование is_free ", type=openapi.TYPE_BOOLEAN, ), openapi.Parameter( 'is_online', openapi.IN_QUERY, description="Статус участия is_online ", type=openapi.TYPE_BOOLEAN, ), ]) def get(self, request, *args, **kwargs): return super().get(request, *args, **kwargs) def get_queryset(self): queryset = super().get_queryset() request = self.request filters = request.query_params # Handle category_slug with multiple values separated by commas if category_slugs := filters.get('category_slug'): category_slugs_list = category_slugs.split(',') queryset = queryset.filter(category__slug__in=category_slugs_list) # Handle status with multiple values separated by commas if statuses := filters.get('status'): statuses_list = statuses.split(',') queryset = queryset.filter(status__in=statuses_list) if is_free := filters.get('is_free'): is_free = is_free.lower() == 'true' queryset = queryset.filter( models.Q(is_free=is_free) | models.Q(price=0) if is_free else models.Q(is_free=False, price__gt=0) ) if is_online := filters.get('is_online'): is_online = is_online.lower() == 'true' queryset = queryset.filter(is_online=is_online) return queryset class CourseDetailAPIView(RetrieveAPIView): queryset = Course.objects.all() serializer_class = CourseDetailSerializer lookup_field = "slug" @swagger_auto_schema( operation_description=doc_course_detail(), ) def get(self, request, *args, **kwargs): return super().get(request, *args, **kwargs) class MyCourseListAPIView(ListAPIView): serializer_class = MyCourseListSerializer permission_classes = [IsAuthenticated] @swagger_auto_schema(manual_parameters=[ openapi.Parameter( 'completed', openapi.IN_QUERY, description="мои курсы completed true", type=openapi.TYPE_BOOLEAN, ), openapi.Parameter( 'certificate', openapi.IN_QUERY, type=openapi.TYPE_BOOLEAN, ), ], operation_description=doc_courses_my_courses(), operation_summary="Home", ) def get(self, request, *args, **kwargs): return super().get(request, *args, **kwargs) def get_queryset(self): queryset = Course.objects.all() request = self.request filters = request.query_params student = self.request.user qs = queryset.filter(participants__student=student) completed_only = filters.get('completed', '').lower() == 'true' if completed_only: queryset = queryset.annotate( total_lessons=Count('lessons', distinct=True), completed_lessons=Count( 'lessons__completions', filter=Q(lessons__completions__student=student), distinct=True ) ).filter(total_lessons=F('completed_lessons')) if certificate := filters.get('certificate', '').lower() == 'true': queryset = queryset.exclude( course_certificates__student=student, course_certificates__status__in=['pending', 'approved'] ) return queryset class AttachmentListAPIView(ListAPIView): serializer_class = AttachmentSerializer @swagger_auto_schema( manual_parameters=[ openapi.Parameter( 'slug', openapi.IN_PATH, description="Slug of the Course", type=openapi.TYPE_STRING, required=True ) ], operation_description="Retrieve a list of attachments for a given course by its slug." ) def get(self, request, *args, **kwargs): return super().get(request, *args, **kwargs) def get_queryset(self): course_slug = self.kwargs.get('slug') try: course = Course.objects.get(slug=course_slug) except Course.DoesNotExist: raise NotFound("Course not found") return Attachment.objects.filter(course=course) class GlossaryListAPIView(ListAPIView): serializer_class = GlossarySerializer filter_backends = [SearchFilter] search_fields = ['title', 'description'] def get_queryset(self): course_slug = self.kwargs.get('slug') try: course = Course.objects.get(slug=course_slug) except Course.DoesNotExist: raise NotFound("Course not found") return Glossary.objects.filter(course=course)