231 lines
8.2 KiB
Python
231 lines
8.2 KiB
Python
"""
|
|
Course Info serializers
|
|
"""
|
|
|
|
from typing import Dict, Union
|
|
|
|
from rest_framework import serializers
|
|
from rest_framework.reverse import reverse
|
|
|
|
from common.djangoapps.course_modes.models import CourseMode
|
|
from common.djangoapps.student.models import CourseEnrollment
|
|
from common.djangoapps.util.course import get_encoded_course_sharing_utm_params, get_link_for_about_page
|
|
from common.djangoapps.util.milestones_helpers import get_pre_requisite_courses_not_completed
|
|
from lms.djangoapps.courseware.access import administrative_accesses_to_course_for_user, has_access
|
|
from lms.djangoapps.courseware.access_utils import check_course_open_for_learner
|
|
from lms.djangoapps.courseware.courses import get_assignments_completions
|
|
from lms.djangoapps.mobile_api.course_info.utils import get_user_certificate_download_url
|
|
from lms.djangoapps.mobile_api.users.serializers import ModeSerializer
|
|
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
|
from openedx.features.course_duration_limits.access import get_user_course_expiration_date
|
|
|
|
|
|
class CourseInfoOverviewSerializer(serializers.ModelSerializer):
|
|
"""
|
|
Serializer for additional course fields that should be returned in BlocksInfoInCourseView.
|
|
"""
|
|
|
|
name = serializers.CharField(source='display_name')
|
|
number = serializers.CharField(source='display_number_with_default')
|
|
org = serializers.CharField(source='display_org_with_default')
|
|
is_self_paced = serializers.BooleanField(source='self_paced')
|
|
media = serializers.SerializerMethodField()
|
|
course_sharing_utm_parameters = serializers.SerializerMethodField()
|
|
course_about = serializers.SerializerMethodField('get_course_about_url')
|
|
course_modes = serializers.SerializerMethodField()
|
|
course_progress = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = CourseOverview
|
|
fields = (
|
|
'name',
|
|
'number',
|
|
'org',
|
|
'start',
|
|
'start_display',
|
|
'start_type',
|
|
'end',
|
|
'is_self_paced',
|
|
'media',
|
|
'course_sharing_utm_parameters',
|
|
'course_about',
|
|
'course_modes',
|
|
'course_progress',
|
|
)
|
|
|
|
@staticmethod
|
|
def get_media(obj):
|
|
"""
|
|
Return course images in the correct format.
|
|
"""
|
|
return {'image': obj.image_urls}
|
|
|
|
def get_course_sharing_utm_parameters(self, obj):
|
|
return get_encoded_course_sharing_utm_params()
|
|
|
|
def get_course_about_url(self, course_overview):
|
|
return get_link_for_about_page(course_overview)
|
|
|
|
def get_course_modes(self, course_overview):
|
|
"""
|
|
Retrieve course modes associated with the course.
|
|
"""
|
|
course_modes = CourseMode.modes_for_course(
|
|
course_overview.id,
|
|
only_selectable=False
|
|
)
|
|
return [
|
|
ModeSerializer(mode).data
|
|
for mode in course_modes
|
|
]
|
|
|
|
def get_course_progress(self, obj: CourseOverview) -> Dict[str, int]:
|
|
"""
|
|
Gets course progress calculated by course completed assignments.
|
|
"""
|
|
return get_assignments_completions(obj.id, self.context.get('user'))
|
|
|
|
|
|
class MobileCourseEnrollmentSerializer(serializers.ModelSerializer):
|
|
"""
|
|
Serializer for the CourseEnrollment object used in the BlocksInfoInCourseView.
|
|
"""
|
|
|
|
class Meta:
|
|
fields = ('created', 'mode', 'is_active', 'upgrade_deadline')
|
|
model = CourseEnrollment
|
|
lookup_field = 'username'
|
|
|
|
|
|
class CourseAccessSerializer(serializers.Serializer):
|
|
"""
|
|
Get info whether a user should be able to view course material.
|
|
"""
|
|
|
|
has_unmet_prerequisites = serializers.SerializerMethodField(method_name='get_has_unmet_prerequisites')
|
|
is_too_early = serializers.SerializerMethodField(method_name='get_is_too_early')
|
|
is_staff = serializers.SerializerMethodField(method_name='get_is_staff')
|
|
audit_access_expires = serializers.SerializerMethodField()
|
|
courseware_access = serializers.SerializerMethodField()
|
|
|
|
def get_has_unmet_prerequisites(self, data: dict) -> bool:
|
|
"""
|
|
Check whether or not a course has unmet prerequisites.
|
|
"""
|
|
return any(get_pre_requisite_courses_not_completed(data.get('user'), [data.get('course_id')]))
|
|
|
|
def get_is_too_early(self, data: dict) -> bool:
|
|
"""
|
|
Determine if the course is open to a learner (course has started or user has early beta access).
|
|
"""
|
|
return not check_course_open_for_learner(data.get('user'), data.get('course'))
|
|
|
|
def get_is_staff(self, data: dict) -> bool:
|
|
"""
|
|
Determine whether a user has staff access to this course.
|
|
"""
|
|
return any(administrative_accesses_to_course_for_user(data.get('user'), data.get('course_id')))
|
|
|
|
def get_audit_access_expires(self, data: dict) -> Union[str, None]:
|
|
"""
|
|
Returns expiration date for a course audit expiration, if any or null
|
|
"""
|
|
return get_user_course_expiration_date(data.get('user'), data.get('course'))
|
|
|
|
def get_courseware_access(self, data: dict) -> dict:
|
|
"""
|
|
Determine if the learner has access to the course, otherwise show error message.
|
|
"""
|
|
return has_access(data.get('user'), 'load_mobile', data.get('course')).to_json()
|
|
|
|
|
|
class CourseDetailSerializer(serializers.Serializer):
|
|
"""
|
|
Serializer for Course enrollment and overview details.
|
|
"""
|
|
|
|
id = serializers.SerializerMethodField()
|
|
course_access_details = serializers.SerializerMethodField()
|
|
certificate = serializers.SerializerMethodField()
|
|
enrollment_details = serializers.SerializerMethodField()
|
|
course_handouts = serializers.SerializerMethodField()
|
|
course_updates = serializers.SerializerMethodField()
|
|
discussion_url = serializers.SerializerMethodField()
|
|
course_info_overview = serializers.SerializerMethodField()
|
|
|
|
@staticmethod
|
|
def get_id(data):
|
|
"""
|
|
Returns course id.
|
|
"""
|
|
return str(data['course_id'])
|
|
|
|
@staticmethod
|
|
def get_course_overview(course_id):
|
|
"""
|
|
Returns course overview.
|
|
"""
|
|
return CourseOverview.get_from_id(course_id)
|
|
|
|
def get_course_info_overview(self, data):
|
|
"""
|
|
Returns course info overview.
|
|
"""
|
|
course_overview = self.get_course_overview(data['course_id'])
|
|
course_info_context = {'user': data['user']}
|
|
return CourseInfoOverviewSerializer(course_overview, context=course_info_context).data
|
|
|
|
@staticmethod
|
|
def get_discussion_url(data):
|
|
"""
|
|
Returns discussion url.
|
|
"""
|
|
course_overview = CourseOverview.get_from_id(data['course_id'])
|
|
if not course_overview.is_discussion_tab_enabled(data['user']):
|
|
return
|
|
|
|
return reverse('discussion_course', kwargs={'course_id': data['course_id']}, request=data['request'])
|
|
|
|
def get_course_access_details(self, data):
|
|
"""
|
|
Returns course access details.
|
|
"""
|
|
course_access_data = {
|
|
'course': self.get_course_overview(data['course_id']),
|
|
'course_id': data['course_id'],
|
|
'user': data['user'],
|
|
}
|
|
return CourseAccessSerializer(course_access_data).data
|
|
|
|
@staticmethod
|
|
def get_certificate(data):
|
|
"""
|
|
Returns course certificate url.
|
|
"""
|
|
return get_user_certificate_download_url(data['request'], data['user'], data['course_id'])
|
|
|
|
@staticmethod
|
|
def get_enrollment_details(data):
|
|
"""
|
|
Retrieve course enrollment details of the course.
|
|
"""
|
|
user_enrollment = CourseEnrollment.get_enrollment(user=data['user'], course_key=data['course_id'])
|
|
return MobileCourseEnrollmentSerializer(user_enrollment).data
|
|
|
|
@staticmethod
|
|
def get_course_handouts(data):
|
|
"""
|
|
Returns course_handouts.
|
|
"""
|
|
|
|
url_params = {'api_version': data['api_version'], 'course_id': data['course_id']}
|
|
return reverse('course-handouts-list', kwargs=url_params, request=data['request'])
|
|
|
|
@staticmethod
|
|
def get_course_updates(data):
|
|
"""
|
|
Returns course_updates.
|
|
"""
|
|
url_params = {'api_version': data['api_version'], 'course_id': data['course_id']}
|
|
return reverse('course-updates-list', kwargs=url_params, request=data['request'])
|