Skip to content

Commit

Permalink
Added deadline for upgrade
Browse files Browse the repository at this point in the history
  • Loading branch information
Giovanni Di Milia committed Jul 1, 2016
1 parent 1e647e5 commit 72e6ec5
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 55 deletions.
20 changes: 20 additions & 0 deletions courses/migrations/0011_courserun_upgrade_deadline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-06-29 13:32
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('courses', '0010_program_description'),
]

operations = [
migrations.AddField(
model_name='courserun',
name='upgrade_deadline',
field=models.DateTimeField(blank=True, null=True),
),
]
10 changes: 10 additions & 0 deletions courses/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class CourseRun(models.Model):
start_date = models.DateTimeField(blank=True, null=True)
enrollment_end = models.DateTimeField(blank=True, null=True)
end_date = models.DateTimeField(blank=True, null=True)
upgrade_deadline = models.DateTimeField(blank=True, null=True)
fuzzy_start_date = models.CharField(
max_length=255, blank=True, null=True,
help_text="If you don't know when your course will run exactly, "
Expand Down Expand Up @@ -114,3 +115,12 @@ def is_future(self):
if not self.start_date:
return False
return self.start_date > datetime.now(pytz.utc)

@property
def is_upgradable(self):
"""
Checks if the course can be upgraded
A null value means that the upgrade window is always open
"""
return (self.upgrade_deadline is None or
(self.upgrade_deadline > datetime.now(pytz.utc)))
22 changes: 21 additions & 1 deletion courses/models_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ def setUp(self):
super(CourseModelsMixin, self).setUp()
self.now = datetime.now(pytz.utc)

def create_run(self, course=None, start=None, end=None, enr_start=None, enr_end=None):
def create_run(self, course=None, start=None, end=None,
enr_start=None, enr_end=None, upgrade_deadline=None):
"""helper function to create course runs"""
# pylint: disable=too-many-arguments
return CourseRunFactory.create(
Expand All @@ -46,6 +47,7 @@ def create_run(self, course=None, start=None, end=None, enr_start=None, enr_end=
end_date=end,
enrollment_start=enr_start,
enrollment_end=enr_end,
upgrade_deadline=upgrade_deadline,
)


Expand Down Expand Up @@ -340,3 +342,21 @@ def test_is_future(self):
start=self.now-timedelta(weeks=2)
)
assert course_run.is_future is False

def test_is_upgradable(self):
"""Test for is_upgradable property"""
# with no upgrade_deadline
course_run = self.create_run()
assert course_run.is_upgradable is True

# with upgrade_deadline in the future
course_run = self.create_run(
upgrade_deadline=self.now+timedelta(weeks=2)
)
assert course_run.is_upgradable is True

# with upgrade_deadline in the past
course_run = self.create_run(
upgrade_deadline=self.now-timedelta(weeks=2)
)
assert course_run.is_upgradable is False
4 changes: 2 additions & 2 deletions dashboard/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,9 +315,9 @@ def get_status_for_courserun(course_run, user_enrollments):
elif course_run.is_future:
status = CourseRunStatus.WILL_ATTEND
else:
if course_run.is_current or course_run.is_future:
if (course_run.is_current or course_run.is_future) and course_run.is_upgradable:
status = CourseRunStatus.UPGRADE
elif course_run.is_past:
else:
status = CourseRunStatus.NOT_PASSED
return CourseRunUserStatus(
status=status,
Expand Down
129 changes: 78 additions & 51 deletions dashboard/api_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ def setUp(self):
super(CourseMixin, self).setUp()
self.now = datetime.now(pytz.utc)

def create_run(self, course=None, start=None, end=None, enr_start=None, enr_end=None, edx_key=None, title="Title"):
def create_run(self, course=None, start=None, end=None,
enr_start=None, enr_end=None, edx_key=None, title="Title",
upgrade_deadline=None):
"""helper function to create course runs"""
# pylint: disable=too-many-arguments
run = CourseRunFactory.create(
Expand All @@ -122,6 +124,7 @@ def create_run(self, course=None, start=None, end=None, enr_start=None, enr_end=
end_date=end,
enrollment_start=enr_start,
enrollment_end=enr_end,
upgrade_deadline=upgrade_deadline,
)
if edx_key is not None:
run.edx_course_key = edx_key
Expand All @@ -133,13 +136,13 @@ class FormatRunTest(CourseMixin):
"""Tests for the format_courserun_for_dashboard function"""

def test_format_run_no_run(self):
"""Test for format_courserun_for_dashboard"""
"""Test for format_courserun_for_dashboard if there is no run"""
self.assertIsNone(
api.format_courserun_for_dashboard(None, api.CourseStatus.PASSED)
)

def test_format_run(self):
"""Test for format_courserun_for_dashboard"""
"""Test for format_courserun_for_dashboard with passed run and position"""
crun = self.create_run(
start=self.now+timedelta(weeks=52),
end=self.now+timedelta(weeks=62),
Expand Down Expand Up @@ -252,15 +255,15 @@ def setUpTestData(cls):
cls.enrollments_json = json.loads(file_obj.read())

cls.enrollments = Enrollments(cls.enrollments_json)
cls.now = datetime.now(pytz.utc)

def test_status_for_run_not_enrolled(self):
"""test for get_status_for_courserun"""
now = datetime.now(pytz.utc)
"""test for get_status_for_courserun for course without enrollment"""
crun = self.create_run(
start=now+timedelta(weeks=52),
end=now+timedelta(weeks=62),
enr_start=now+timedelta(weeks=40),
enr_end=now+timedelta(weeks=50),
start=self.now+timedelta(weeks=52),
end=self.now+timedelta(weeks=62),
enr_start=self.now+timedelta(weeks=40),
enr_end=self.now+timedelta(weeks=50),
edx_key='foo_edx_key'
)
run_status = api.get_status_for_courserun(crun, self.enrollments)
Expand All @@ -270,14 +273,13 @@ def test_status_for_run_not_enrolled(self):
assert run_status.enrollment_for_course is None

def test_verified_grade(self):
"""test for get_status_for_courserun"""
now = datetime.now(pytz.utc)
"""test for get_status_for_courserun for an enrolled and verified current course"""
# create a run that is current
crun = self.create_run(
start=now-timedelta(weeks=1),
end=now+timedelta(weeks=2),
enr_start=now-timedelta(weeks=10),
enr_end=now+timedelta(weeks=1),
start=self.now-timedelta(weeks=1),
end=self.now+timedelta(weeks=2),
enr_start=self.now-timedelta(weeks=10),
enr_end=self.now+timedelta(weeks=1),
edx_key="course-v1:edX+DemoX+Demo_Course"
)
run_status = api.get_status_for_courserun(crun, self.enrollments)
Expand All @@ -287,14 +289,13 @@ def test_verified_grade(self):
self.enrollments.get_enrollment_for_course("course-v1:edX+DemoX+Demo_Course"))

def test_verified_read_cert(self):
"""test for get_status_for_courserun"""
now = datetime.now(pytz.utc)
"""test for get_status_for_courserun for a finished course"""
# create a run that is past
crun = self.create_run(
start=now-timedelta(weeks=52),
end=now-timedelta(weeks=45),
enr_start=now-timedelta(weeks=62),
enr_end=now-timedelta(weeks=53),
start=self.now-timedelta(weeks=52),
end=self.now-timedelta(weeks=45),
enr_start=self.now-timedelta(weeks=62),
enr_end=self.now-timedelta(weeks=53),
edx_key="course-v1:edX+DemoX+Demo_Course"
)
run_status = api.get_status_for_courserun(crun, self.enrollments)
Expand All @@ -304,14 +305,13 @@ def test_verified_read_cert(self):
self.enrollments.get_enrollment_for_course("course-v1:edX+DemoX+Demo_Course"))

def test_verified_read_will_attend(self):
"""test for get_status_for_courserun"""
now = datetime.now(pytz.utc)
"""test for get_status_for_courserun for an enrolled and verified future course"""
# create a run that is future
crun = self.create_run(
start=now+timedelta(weeks=52),
end=now+timedelta(weeks=62),
enr_start=now+timedelta(weeks=40),
enr_end=now+timedelta(weeks=50),
start=self.now+timedelta(weeks=52),
end=self.now+timedelta(weeks=62),
enr_start=self.now+timedelta(weeks=40),
enr_end=self.now+timedelta(weeks=50),
edx_key="course-v1:edX+DemoX+Demo_Course"
)
run_status = api.get_status_for_courserun(crun, self.enrollments)
Expand All @@ -321,22 +321,21 @@ def test_verified_read_will_attend(self):
self.enrollments.get_enrollment_for_course("course-v1:edX+DemoX+Demo_Course"))

def test_not_verified_upgrade(self):
"""test for get_status_for_courserun"""
now = datetime.now(pytz.utc)
"""test for get_status_for_courserun for present and future course with audit enrollment"""
# create a run that is future
future_run = self.create_run(
start=now+timedelta(weeks=52),
end=now+timedelta(weeks=62),
enr_start=now+timedelta(weeks=40),
enr_end=now+timedelta(weeks=50),
start=self.now+timedelta(weeks=52),
end=self.now+timedelta(weeks=62),
enr_start=self.now+timedelta(weeks=40),
enr_end=self.now+timedelta(weeks=50),
edx_key="course-v1:MITx+8.MechCX+2014_T1"
)
# create a run that is current
current_run = self.create_run(
start=now-timedelta(weeks=1),
end=now+timedelta(weeks=2),
enr_start=now-timedelta(weeks=10),
enr_end=now+timedelta(weeks=1),
start=self.now-timedelta(weeks=1),
end=self.now+timedelta(weeks=2),
enr_start=self.now-timedelta(weeks=10),
enr_end=self.now+timedelta(weeks=1),
edx_key="course-v1:MITx+8.MechCX+2014_T1"
)
run_status = api.get_status_for_courserun(future_run, self.enrollments)
Expand All @@ -350,15 +349,40 @@ def test_not_verified_upgrade(self):
assert (run_status.enrollment_for_course ==
self.enrollments.get_enrollment_for_course("course-v1:MITx+8.MechCX+2014_T1"))

def test_not_verified_upgradable(self):
"""test for get_status_for_courserun with check if course can be upgraded to verified"""
# create a run that is current with upgrade deadline None
current_run = self.create_run(
start=self.now-timedelta(weeks=1),
end=self.now+timedelta(weeks=2),
enr_start=self.now-timedelta(weeks=10),
enr_end=self.now+timedelta(weeks=1),
upgrade_deadline=None,
edx_key="course-v1:MITx+8.MechCX+2014_T1"
)
run_status = api.get_status_for_courserun(current_run, self.enrollments)
assert run_status.status == api.CourseRunStatus.UPGRADE

# modify the run to have an upgrade deadline in the future
current_run.upgrade_deadline = self.now+timedelta(weeks=1)
current_run.save()
run_status = api.get_status_for_courserun(current_run, self.enrollments)
assert run_status.status == api.CourseRunStatus.UPGRADE

# modify the run to have an upgrade deadline in the past
current_run.upgrade_deadline = self.now-timedelta(weeks=1)
current_run.save()
run_status = api.get_status_for_courserun(current_run, self.enrollments)
assert run_status.status == api.CourseRunStatus.NOT_PASSED

def test_not_verified_not_passed(self):
"""test for get_status_for_courserun"""
now = datetime.now(pytz.utc)
"""test for get_status_for_courserun for course not upgraded to verified but that is past"""
# create a run that is past
crun = self.create_run(
start=now-timedelta(weeks=52),
end=now-timedelta(weeks=45),
enr_start=now-timedelta(weeks=62),
enr_end=now-timedelta(weeks=53),
start=self.now-timedelta(weeks=52),
end=self.now-timedelta(weeks=45),
enr_start=self.now-timedelta(weeks=62),
enr_end=self.now-timedelta(weeks=53),
edx_key="course-v1:MITx+8.MechCX+2014_T1"
)
run_status = api.get_status_for_courserun(crun, self.enrollments)
Expand Down Expand Up @@ -455,7 +479,7 @@ def mock_return_status(actual_course_run, *args, **kargs):

@patch('dashboard.api.format_courserun_for_dashboard', autospec=True)
def test_info_no_runs(self, mock_format):
"""test for get_info_for_course"""
"""test for get_info_for_course for course with no runs"""
self.assert_course_equal(
self.course_noruns,
api.CourseStatus.NOT_OFFERED,
Expand All @@ -465,7 +489,7 @@ def test_info_no_runs(self, mock_format):

@patch('dashboard.api.format_courserun_for_dashboard', autospec=True)
def test_info_not_enrolled_offered(self, mock_format):
"""test for get_info_for_course"""
"""test for get_info_for_course for course with with an offered run"""
with patch(
'dashboard.api.get_status_for_courserun',
autospec=True,
Expand All @@ -483,7 +507,7 @@ def test_info_not_enrolled_offered(self, mock_format):

@patch('dashboard.api.format_courserun_for_dashboard', autospec=True)
def test_info_not_passed_offered(self, mock_format):
"""test for get_info_for_course"""
"""test for get_info_for_course for course with a run not passed and another offered"""
with patch(
'dashboard.api.get_status_for_courserun',
autospec=True,
Expand All @@ -503,7 +527,7 @@ def test_info_not_passed_offered(self, mock_format):

@patch('dashboard.api.format_courserun_for_dashboard', autospec=True)
def test_info_not_enrolled_not_passed_not_offered(self, mock_format):
"""test for get_info_for_course"""
"""test for get_info_for_course for course with run not passed and nothing offered"""
with patch(
'dashboard.api.get_status_for_courserun',
autospec=True,
Expand All @@ -520,7 +544,7 @@ def test_info_not_enrolled_not_passed_not_offered(self, mock_format):

@patch('dashboard.api.format_courserun_for_dashboard', autospec=True)
def test_info_grade(self, mock_format):
"""test for get_info_for_course"""
"""test for get_info_for_course for course with a course current and another not passed"""
with patch(
'dashboard.api.get_status_for_courserun',
autospec=True,
Expand Down Expand Up @@ -598,7 +622,7 @@ def test_info_read_cert_with_ver_cert(self, mock_format):

@patch('dashboard.api.format_courserun_for_dashboard', autospec=True)
def test_info_will_attend(self, mock_format):
"""test for get_info_for_course"""
"""test for get_info_for_course for course with enrolled run that will happen in the future"""
with patch(
'dashboard.api.get_status_for_courserun',
autospec=True,
Expand All @@ -614,7 +638,7 @@ def test_info_will_attend(self, mock_format):

@patch('dashboard.api.format_courserun_for_dashboard', autospec=True)
def test_info_upgrade(self, mock_format):
"""test for get_info_for_course"""
"""test for get_info_for_course for course with a run that needs to be upgraded"""
with patch(
'dashboard.api.get_status_for_courserun',
autospec=True,
Expand All @@ -630,7 +654,10 @@ def test_info_upgrade(self, mock_format):

@patch('dashboard.api.format_courserun_for_dashboard', autospec=True)
def test_info_default_should_not_happen(self, mock_format):
"""test for get_info_for_course"""
"""
test for get_info_for_course for course with a run with an
unespected state but that can be offered
"""
with patch(
'dashboard.api.get_status_for_courserun',
autospec=True,
Expand Down
1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,3 @@ uwsgi==2.0.12
Pillow==3.1.1
wagtail==1.5.2
edx-api-client==0.2.1

0 comments on commit 72e6ec5

Please sign in to comment.