|
12 | 12 | from django.conf import settings |
13 | 13 | from django.db import models, transaction |
14 | 14 | from django.db.models import Q |
15 | | -from django.db.models.fields import ( |
16 | | - BooleanField, DateTimeField, DecimalField, FloatField, IntegerField, TextField |
17 | | -) |
18 | 15 | from django.db.models.signals import post_save, post_delete |
19 | 16 | from django.db.utils import IntegrityError |
20 | 17 | from django.template import defaultfilters |
@@ -65,82 +62,87 @@ class Meta: |
65 | 62 | app_label = 'course_overviews' |
66 | 63 |
|
67 | 64 | # IMPORTANT: Bump this whenever you modify this model and/or add a migration. |
68 | | - VERSION = 16 |
| 65 | + VERSION = 17 |
69 | 66 |
|
70 | 67 | # Cache entry versioning. |
71 | | - version = IntegerField() |
| 68 | + version = models.IntegerField() |
72 | 69 |
|
73 | 70 | # Course identification |
74 | 71 | id = CourseKeyField(db_index=True, primary_key=True, max_length=255) |
75 | 72 | _location = UsageKeyField(max_length=255) |
76 | | - org = TextField(max_length=255, default='outdated_entry') |
77 | | - display_name = TextField(null=True) |
78 | | - display_number_with_default = TextField() |
79 | | - display_org_with_default = TextField() |
| 73 | + org = models.TextField(max_length=255, default='outdated_entry') |
| 74 | + display_name = models.TextField(null=True) |
| 75 | + display_number_with_default = models.TextField() |
| 76 | + display_org_with_default = models.TextField() |
80 | 77 |
|
81 | | - start = DateTimeField(null=True) |
82 | | - end = DateTimeField(null=True) |
| 78 | + start = models.DateTimeField(null=True) |
| 79 | + end = models.DateTimeField(null=True) |
83 | 80 |
|
84 | 81 | # These are deprecated and unused, but cannot be dropped via simple migration due to the size of the downstream |
85 | 82 | # history table. See DENG-19 for details. |
86 | 83 | # Please use start and end above for these values. |
87 | | - start_date = DateTimeField(null=True) |
88 | | - end_date = DateTimeField(null=True) |
| 84 | + start_date = models.DateTimeField(null=True) |
| 85 | + end_date = models.DateTimeField(null=True) |
89 | 86 |
|
90 | | - advertised_start = TextField(null=True) |
91 | | - announcement = DateTimeField(null=True) |
| 87 | + advertised_start = models.TextField(null=True) |
| 88 | + announcement = models.DateTimeField(null=True) |
92 | 89 |
|
93 | 90 | # URLs |
94 | 91 | # Not allowing null per django convention; not sure why many TextFields in this model do allow null |
95 | | - banner_image_url = TextField() |
96 | | - course_image_url = TextField() |
97 | | - social_sharing_url = TextField(null=True) |
98 | | - end_of_course_survey_url = TextField(null=True) |
| 92 | + banner_image_url = models.TextField() |
| 93 | + course_image_url = models.TextField() |
| 94 | + social_sharing_url = models.TextField(null=True) |
| 95 | + end_of_course_survey_url = models.TextField(null=True) |
99 | 96 |
|
100 | 97 | # Certification data |
101 | | - certificates_display_behavior = TextField(null=True) |
102 | | - certificates_show_before_end = BooleanField(default=False) |
103 | | - cert_html_view_enabled = BooleanField(default=False) |
104 | | - has_any_active_web_certificate = BooleanField(default=False) |
105 | | - cert_name_short = TextField() |
106 | | - cert_name_long = TextField() |
107 | | - certificate_available_date = DateTimeField(default=None, null=True) |
| 98 | + certificates_display_behavior = models.TextField(null=True) |
| 99 | + certificates_show_before_end = models.BooleanField(default=False) |
| 100 | + cert_html_view_enabled = models.BooleanField(default=False) |
| 101 | + has_any_active_web_certificate = models.BooleanField(default=False) |
| 102 | + cert_name_short = models.TextField() |
| 103 | + cert_name_long = models.TextField() |
| 104 | + certificate_available_date = models.DateTimeField(default=None, null=True) |
108 | 105 |
|
109 | 106 | # Grading |
110 | | - lowest_passing_grade = DecimalField(max_digits=5, decimal_places=2, null=True) |
| 107 | + lowest_passing_grade = models.DecimalField(max_digits=5, decimal_places=2, null=True) |
111 | 108 |
|
112 | 109 | # Access parameters |
113 | | - days_early_for_beta = FloatField(null=True) |
114 | | - mobile_available = BooleanField(default=False) |
115 | | - visible_to_staff_only = BooleanField(default=False) |
116 | | - _pre_requisite_courses_json = TextField() # JSON representation of list of CourseKey strings |
| 110 | + days_early_for_beta = models.FloatField(null=True) |
| 111 | + mobile_available = models.BooleanField(default=False) |
| 112 | + visible_to_staff_only = models.BooleanField(default=False) |
| 113 | + _pre_requisite_courses_json = models.TextField() # JSON representation of list of CourseKey strings |
117 | 114 |
|
118 | 115 | # Enrollment details |
119 | | - enrollment_start = DateTimeField(null=True) |
120 | | - enrollment_end = DateTimeField(null=True) |
121 | | - enrollment_domain = TextField(null=True) |
122 | | - invitation_only = BooleanField(default=False) |
123 | | - max_student_enrollments_allowed = IntegerField(null=True) |
| 116 | + enrollment_start = models.DateTimeField(null=True) |
| 117 | + enrollment_end = models.DateTimeField(null=True) |
| 118 | + enrollment_domain = models.TextField(null=True) |
| 119 | + invitation_only = models.BooleanField(default=False) |
| 120 | + max_student_enrollments_allowed = models.IntegerField(null=True) |
124 | 121 |
|
125 | 122 | # Catalog information |
126 | | - catalog_visibility = TextField(null=True) |
127 | | - short_description = TextField(null=True) |
128 | | - course_video_url = TextField(null=True) |
129 | | - effort = TextField(null=True) |
130 | | - self_paced = BooleanField(default=False) |
131 | | - marketing_url = TextField(null=True) |
132 | | - eligible_for_financial_aid = BooleanField(default=True) |
| 123 | + catalog_visibility = models.TextField(null=True) |
| 124 | + short_description = models.TextField(null=True) |
| 125 | + course_video_url = models.TextField(null=True) |
| 126 | + effort = models.TextField(null=True) |
| 127 | + self_paced = models.BooleanField(default=False) |
| 128 | + marketing_url = models.TextField(null=True) |
| 129 | + eligible_for_financial_aid = models.BooleanField(default=True) |
133 | 130 |
|
134 | 131 | # Course highlight info, used to guide course update emails |
135 | | - has_highlights = BooleanField(null=True, default=None) # if None, you have to look up the answer yourself |
| 132 | + has_highlights = models.BooleanField(null=True, default=None) # if None, you have to look up the answer yourself |
136 | 133 |
|
137 | 134 | # Proctoring |
138 | | - enable_proctored_exams = BooleanField(default=False) |
139 | | - proctoring_provider = TextField(null=True) |
140 | | - proctoring_escalation_email = TextField(null=True) |
141 | | - allow_proctoring_opt_out = BooleanField(default=False) |
| 135 | + enable_proctored_exams = models.BooleanField(default=False) |
| 136 | + proctoring_provider = models.TextField(null=True) |
| 137 | + proctoring_escalation_email = models.TextField(null=True) |
| 138 | + allow_proctoring_opt_out = models.BooleanField(default=False) |
142 | 139 |
|
143 | | - language = TextField(null=True) |
| 140 | + # Entrance Exam information |
| 141 | + entrance_exam_enabled = models.BooleanField(default=False) |
| 142 | + entrance_exam_id = models.CharField(max_length=255, blank=True) |
| 143 | + entrance_exam_minimum_score_pct = models.FloatField(default=0.65) |
| 144 | + |
| 145 | + language = models.TextField(null=True) |
144 | 146 |
|
145 | 147 | history = HistoricalRecords() |
146 | 148 |
|
@@ -252,6 +254,16 @@ def _create_or_update(cls, course): # lint-amnesty, pylint: disable=too-many-st |
252 | 254 | course_overview.proctoring_escalation_email = course.proctoring_escalation_email |
253 | 255 | course_overview.allow_proctoring_opt_out = course.allow_proctoring_opt_out |
254 | 256 |
|
| 257 | + course_overview.entrance_exam_enabled = course.entrance_exam_enabled |
| 258 | + # entrance_exam_id defaults to None in the course object, but '' is more reasonable for a string field |
| 259 | + course_overview.entrance_exam_id = course.entrance_exam_id or '' |
| 260 | + # Despite it being a float, the course object defaults to an int. So we will detect that case and update |
| 261 | + # it to be a float like everything else. |
| 262 | + if isinstance(course.entrance_exam_minimum_score_pct, int): |
| 263 | + course_overview.entrance_exam_minimum_score_pct = course.entrance_exam_minimum_score_pct / 100 |
| 264 | + else: |
| 265 | + course_overview.entrance_exam_minimum_score_pct = course.entrance_exam_minimum_score_pct |
| 266 | + |
255 | 267 | if not CatalogIntegration.is_enabled(): |
256 | 268 | course_overview.language = course.language |
257 | 269 |
|
|
0 commit comments