""" Course API Serializers. Representing course catalog data """ import urllib from django.core.urlresolvers import reverse from rest_framework import serializers from openedx.core.djangoapps.models.course_details import CourseDetails from openedx.core.lib.api.fields import AbsoluteURLField class _MediaSerializer(serializers.Serializer): # pylint: disable=abstract-method """ Nested serializer to represent a media object. """ def __init__(self, uri_attribute, *args, **kwargs): super(_MediaSerializer, self).__init__(*args, **kwargs) self.uri_attribute = uri_attribute uri = serializers.SerializerMethodField(source='*') def get_uri(self, course_overview): """ Get the representation for the media resource's URI """ return getattr(course_overview, self.uri_attribute) class ImageSerializer(serializers.Serializer): # pylint: disable=abstract-method """ Collection of URLs pointing to images of various sizes. The URLs will be absolute URLs with the host set to the host of the current request. If the values to be serialized are already absolute URLs, they will be unchanged. """ raw = AbsoluteURLField() small = AbsoluteURLField() large = AbsoluteURLField() class _CourseApiMediaCollectionSerializer(serializers.Serializer): # pylint: disable=abstract-method """ Nested serializer to represent a collection of media objects """ course_image = _MediaSerializer(source='*', uri_attribute='course_image_url') course_video = _MediaSerializer(source='*', uri_attribute='course_video_url') image = ImageSerializer(source='image_urls') class CourseSerializer(serializers.Serializer): # pylint: disable=abstract-method """ Serializer for Course objects providing minimal data about the course. Compare this with CourseDetailSerializer. """ blocks_url = serializers.SerializerMethodField() effort = serializers.CharField() end = serializers.DateTimeField() enrollment_start = serializers.DateTimeField() enrollment_end = serializers.DateTimeField() id = serializers.CharField() # pylint: disable=invalid-name media = _CourseApiMediaCollectionSerializer(source='*') name = serializers.CharField(source='display_name_with_default_escaped') number = serializers.CharField(source='display_number_with_default') org = serializers.CharField(source='display_org_with_default') short_description = serializers.CharField() start = serializers.DateTimeField() start_display = serializers.CharField() start_type = serializers.CharField() pacing = serializers.CharField() mobile_available = serializers.BooleanField() hidden = serializers.SerializerMethodField() # 'course_id' is a deprecated field, please use 'id' instead. course_id = serializers.CharField(source='id', read_only=True) def get_hidden(self, course_overview): """ Get the representation for SerializerMethodField `hidden` Represents whether course is hidden in LMS """ catalog_visibility = course_overview.catalog_visibility return catalog_visibility in ['about', 'none'] def get_blocks_url(self, course_overview): """ Get the representation for SerializerMethodField `blocks_url` """ base_url = '?'.join([ reverse('blocks_in_course'), urllib.urlencode({'course_id': course_overview.id}), ]) return self.context['request'].build_absolute_uri(base_url) class CourseDetailSerializer(CourseSerializer): # pylint: disable=abstract-method """ Serializer for Course objects providing additional details about the course. This serializer makes additional database accesses (to the modulestore) and returns more data (including 'overview' text). Therefore, for performance and bandwidth reasons, it is expected that this serializer is used only when serializing a single course, and not for serializing a list of courses. """ overview = serializers.SerializerMethodField() def get_overview(self, course_overview): """ Get the representation for SerializerMethodField `overview` """ # Note: This makes a call to the modulestore, unlike the other # fields from CourseSerializer, which get their data # from the CourseOverview object in SQL. return CourseDetails.fetch_about_attribute(course_overview.id, 'overview')