models.py 4.33 KB
Newer Older
1 2 3
"""
Models for the custom course feature
"""
4
import json
5
import logging
6
from datetime import datetime
7

8 9
from django.contrib.auth.models import User
from django.db import models
10
from django.utils.timezone import UTC
11

12
from lazy import lazy
13
from xmodule_django.models import CourseKeyField, LocationKeyField
14 15 16 17 18
from xmodule.error_module import ErrorDescriptor
from xmodule.modulestore.django import modulestore


log = logging.getLogger("edx.ccx")
19 20


cewing committed
21
class CustomCourseForEdX(models.Model):
22
    """
cewing committed
23
    A Custom Course.
24 25 26 27
    """
    course_id = CourseKeyField(max_length=255, db_index=True)
    display_name = models.CharField(max_length=255)
    coach = models.ForeignKey(User, db_index=True)
28 29 30
    # if not empty, this field contains a json serialized list of
    # the master course modules
    structure_json = models.TextField(verbose_name='Structure JSON', blank=True, null=True)
31

32 33 34
    class Meta(object):
        app_label = 'ccx'

35
    @lazy
36
    def course(self):
cewing committed
37
        """Return the CourseDescriptor of the course related to this CCX"""
38 39 40 41 42 43 44 45 46 47
        store = modulestore()
        with store.bulk_operations(self.course_id):
            course = store.get_course(self.course_id)
            if not course or isinstance(course, ErrorDescriptor):
                log.error("CCX {0} from {2} course {1}".format(  # pylint: disable=logging-format-interpolation
                    self.display_name, self.course_id, "broken" if course else "non-existent"
                ))
            return course

    @lazy
48
    def start(self):
cewing committed
49 50
        """Get the value of the override of the 'start' datetime for this CCX
        """
51 52 53
        # avoid circular import problems
        from .overrides import get_override_for_ccx
        return get_override_for_ccx(self, self.course, 'start')
54

55
    @lazy
56
    def due(self):
cewing committed
57 58
        """Get the value of the override of the 'due' datetime for this CCX
        """
59 60 61
        # avoid circular import problems
        from .overrides import get_override_for_ccx
        return get_override_for_ccx(self, self.course, 'due')
62

63 64 65 66 67 68 69 70 71 72
    @lazy
    def max_student_enrollments_allowed(self):
        """
        Get the value of the override of the 'max_student_enrollments_allowed'
        datetime for this CCX
        """
        # avoid circular import problems
        from .overrides import get_override_for_ccx
        return get_override_for_ccx(self, self.course, 'max_student_enrollments_allowed')

73
    def has_started(self):
cewing committed
74
        """Return True if the CCX start date is in the past"""
75 76 77
        return datetime.now(UTC()) > self.start

    def has_ended(self):
cewing committed
78
        """Return True if the CCX due date is set and is in the past"""
79 80 81 82 83 84
        if self.due is None:
            return False

        return datetime.now(UTC()) > self.due

    def start_datetime_text(self, format_string="SHORT_DATE"):
cewing committed
85 86 87 88
        """Returns the desired text representation of the CCX start datetime

        The returned value is always expressed in UTC
        """
89 90 91 92 93 94 95 96
        i18n = self.course.runtime.service(self.course, "i18n")
        strftime = i18n.strftime
        value = strftime(self.start, format_string)
        if format_string == 'DATE_TIME':
            value += u' UTC'
        return value

    def end_datetime_text(self, format_string="SHORT_DATE"):
cewing committed
97 98 99 100 101 102 103
        """Returns the desired text representation of the CCX due datetime

        If the due date for the CCX is not set, the value returned is the empty
        string.

        The returned value is always expressed in UTC
        """
104 105 106 107 108 109 110 111 112 113
        if self.due is None:
            return ''

        i18n = self.course.runtime.service(self.course, "i18n")
        strftime = i18n.strftime
        value = strftime(self.due, format_string)
        if format_string == 'DATE_TIME':
            value += u' UTC'
        return value

114 115 116 117 118 119 120 121 122
    @property
    def structure(self):
        """
        Deserializes a course structure JSON object
        """
        if self.structure_json:
            return json.loads(self.structure_json)
        return None

123

cewing committed
124
class CcxFieldOverride(models.Model):
125
    """
cewing committed
126
    Field overrides for custom courses.
127
    """
cewing committed
128
    ccx = models.ForeignKey(CustomCourseForEdX, db_index=True)
129 130 131
    location = LocationKeyField(max_length=255, db_index=True)
    field = models.CharField(max_length=255)

132
    class Meta(object):
133
        app_label = 'ccx'
cewing committed
134
        unique_together = (('ccx', 'location', 'field'),)
135 136

    value = models.TextField(default='null')