Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,37 @@ class Meta:
ref_name = "authoring_grading.Graders.v0"


class GracePeriodSerializer(serializers.Serializer):
"""Serializer for grace period (hours / minutes / seconds)."""
hours = serializers.IntegerField(default=0)
minutes = serializers.IntegerField(default=0)
seconds = serializers.IntegerField(default=0, required=False)

class Meta:
ref_name = "authoring_grading.GracePeriod.v0"


class CourseGradingModelSerializer(serializers.Serializer):
""" Serializer for course grading model data """
graders = GradersSerializer(many=True, allow_null=True, allow_empty=True)
grade_cutoffs = serializers.DictField(
child=serializers.FloatField(),
required=False,
help_text=(
"Mapping of letter grade to minimum score (0.0–1.0). "
"Required by CourseGradingModel.update_from_json — must be included in every PATCH."
),
)
grace_period = GracePeriodSerializer(
allow_null=True,
required=False,
help_text="Grace period duration. Pass null to clear the grace period.",
)
minimum_grade_credit = serializers.FloatField(
required=False,
allow_null=True,
help_text="Minimum passing score for credit eligibility (0.0–1.0).",
)

class Meta:
ref_name = "authoring_grading.CourseGrading.v0"
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class CourseDetailsSerializer(serializers.Serializer):
about_sidebar_html = serializers.CharField(allow_null=True, allow_blank=True)
banner_image_name = serializers.CharField(allow_blank=True)
banner_image_asset_path = serializers.CharField()
certificate_available_date = serializers.DateTimeField()
certificate_available_date = serializers.DateTimeField(allow_null=True)
certificates_display_behavior = serializers.CharField(allow_null=True)
course_id = serializers.CharField()
course_image_asset_path = serializers.CharField(allow_blank=True)
Expand Down
33 changes: 31 additions & 2 deletions cms/djangoapps/contentstore/rest_api/v4/views/home.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
"""HomeCoursesViewSet for getting courses available to the logged-in user (v4)."""

from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from drf_spectacular.openapi import AutoSchema
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema, inline_serializer
from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
from edx_rest_framework_extensions.auth.session.authentication import (
SessionAuthenticationAllowInactiveUser,
)
from edx_rest_framework_extensions.paginators import DefaultPagination
from rest_framework import serializers as _serializers
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
Expand All @@ -18,6 +20,15 @@
from openedx.core.lib.api.mixins import StandardizedErrorMixin


class _HomeCoursesAutoSchema(AutoSchema):
"""Custom AutoSchema that treats the 'list' action as a single-object response."""

def _is_list_view(self, serializer=None):
if self.view.action == 'list':
return False
return super()._is_list_view(serializer)


class HomePageCoursesPaginator(DefaultPagination):
"""
ADR 0032 - standard pagination for the Studio home courses list (v4).
Expand Down Expand Up @@ -136,6 +147,7 @@ class HomeCoursesViewSet(StandardizedErrorMixin, viewsets.ViewSet):
is used instead of the default ``SessionAuthentication``.
"""

schema = _HomeCoursesAutoSchema()
authentication_classes = (JwtAuthentication, SessionAuthenticationAllowInactiveUser)
permission_classes = (IsAuthenticated,)
serializer_class = CourseHomeTabSerializerV4
Expand All @@ -154,7 +166,24 @@ def get_serializer(self, *args, **kwargs):
parameters=_HOME_COURSES_QUERY_PARAMETERS,
responses={
200: OpenApiResponse(
response=CourseHomeTabSerializerV4,
response=inline_serializer(
name="PaginatedV4HomeCoursesResponse",
fields={
"count": _serializers.IntegerField(help_text="Total number of courses."),
"num_pages": _serializers.IntegerField(help_text="Total number of pages."),
"current_page": _serializers.IntegerField(help_text="Current page number."),
"start": _serializers.IntegerField(
help_text="Zero-based index of the first item on this page."
),
"next": _serializers.CharField(
allow_null=True, help_text="URL for the next page, or null."
),
"previous": _serializers.CharField(
allow_null=True, help_text="URL for the previous page, or null."
),
"results": CourseHomeTabSerializerV4(),
},
),
description="Paginated course list retrieved successfully.",
),
401: _UNAUTHENTICATED_RESPONSE,
Expand Down
Loading