serializers.py 3.88 KB
Newer Older
1
""" API v1 serializers. """
2 3 4
from datetime import datetime

import pytz
5 6 7 8
from django.utils.translation import ugettext as _

from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey
9 10 11 12 13
from rest_framework import serializers

from commerce.api.v1.models import Course
from course_modes.models import CourseMode

14 15
from xmodule.modulestore.django import modulestore

16 17 18 19 20

class CourseModeSerializer(serializers.ModelSerializer):
    """ CourseMode serializer. """
    name = serializers.CharField(source='mode_slug')
    price = serializers.IntegerField(source='min_price')
21 22 23 24 25 26
    expires = serializers.DateTimeField(
        source='expiration_datetime',
        required=False,
        allow_null=True,
        format=None
    )
27 28 29 30 31 32 33

    def get_identity(self, data):
        try:
            return data.get('name', None)
        except AttributeError:
            return None

34
    class Meta(object):
35
        model = CourseMode
36
        fields = ('name', 'currency', 'price', 'sku', 'expires')
37 38


39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
def validate_course_id(course_id):
    """
    Check that course id is valid and exists in modulestore.
    """
    try:
        course_key = CourseKey.from_string(unicode(course_id))
    except InvalidKeyError:
        raise serializers.ValidationError(
            _("{course_id} is not a valid course key.").format(
                course_id=course_id
            )
        )

    if not modulestore().has_course(course_key):
        raise serializers.ValidationError(
            _('Course {course_id} does not exist.').format(
                course_id=course_id
            )
        )


60 61
class CourseSerializer(serializers.Serializer):
    """ Course serializer. """
62
    id = serializers.CharField(validators=[validate_course_id])  # pylint: disable=invalid-name
63
    name = serializers.CharField(read_only=True)
64 65
    verification_deadline = serializers.DateTimeField(format=None, allow_null=True, required=False)
    modes = CourseModeSerializer(many=True)
66

67 68 69 70 71 72 73 74 75
    def validate(self, attrs):
        """ Ensure the verification deadline occurs AFTER the course mode enrollment deadlines. """
        verification_deadline = attrs.get('verification_deadline', None)

        if verification_deadline:
            upgrade_deadline = None

            # Find the earliest upgrade deadline
            for mode in attrs['modes']:
76
                expires = mode.get("expiration_datetime")
77 78 79 80 81 82 83 84 85 86 87 88 89
                if expires:
                    # If we don't already have an upgrade_deadline value, use datetime.max so that we can actually
                    # complete the comparison.
                    upgrade_deadline = min(expires, upgrade_deadline or datetime.max.replace(tzinfo=pytz.utc))

            # In cases where upgrade_deadline is None (e.g. the verified professional mode), allow a verification
            # deadline to be set anyway.
            if upgrade_deadline is not None and verification_deadline < upgrade_deadline:
                raise serializers.ValidationError(
                    'Verification deadline must be after the course mode upgrade deadlines.')

        return attrs

90 91 92 93 94 95 96 97 98 99 100 101 102
    def create(self, validated_data):
        """Create course modes for a course. """
        course = Course(
            validated_data["id"],
            self._new_course_mode_models(validated_data["modes"]),
            verification_deadline=validated_data["verification_deadline"]
        )
        course.save()
        return course

    def update(self, instance, validated_data):
        """Update course modes for an existing course. """
        validated_data["modes"] = self._new_course_mode_models(validated_data["modes"])
103

104 105
        instance.update(validated_data)
        instance.save()
106
        return instance
107 108 109 110 111 112 113 114

    @staticmethod
    def _new_course_mode_models(modes_data):
        """Convert validated course mode data to CourseMode objects. """
        return [
            CourseMode(**modes_dict)
            for modes_dict in modes_data
        ]