Commit 4df2bd33 by Will Daly

Merge pull request #7756 from edx/will/ecom-1408-take-two

Expose course start/end date in the enrollment API
parents 72dc5470 e065a9c9
...@@ -36,7 +36,10 @@ def get_enrollments(user_id): ...@@ -36,7 +36,10 @@ def get_enrollments(user_id):
"user": "Bob", "user": "Bob",
"course": { "course": {
"course_id": "edX/DemoX/2014T2", "course_id": "edX/DemoX/2014T2",
"enrollment_end": 2014-12-20T20:18:00Z, "enrollment_end": "2014-12-20T20:18:00Z",
"enrollment_start": "2014-10-15T20:18:00Z",
"course_start": "2015-02-03T00:00:00Z",
"course_end": "2015-05-06T00:00:00Z",
"course_modes": [ "course_modes": [
{ {
"slug": "honor", "slug": "honor",
...@@ -49,7 +52,6 @@ def get_enrollments(user_id): ...@@ -49,7 +52,6 @@ def get_enrollments(user_id):
"sku": null "sku": null
} }
], ],
"enrollment_start": 2014-10-15T20:18:00Z,
"invite_only": False "invite_only": False
} }
}, },
...@@ -60,7 +62,10 @@ def get_enrollments(user_id): ...@@ -60,7 +62,10 @@ def get_enrollments(user_id):
"user": "Bob", "user": "Bob",
"course": { "course": {
"course_id": "edX/edX-Insider/2014T2", "course_id": "edX/edX-Insider/2014T2",
"enrollment_end": 2014-12-20T20:18:00Z, "enrollment_end": "2014-12-20T20:18:00Z",
"enrollment_start": "2014-10-15T20:18:00Z",
"course_start": "2015-02-03T00:00:00Z",
"course_end": "2015-05-06T00:00:00Z",
"course_modes": [ "course_modes": [
{ {
"slug": "honor", "slug": "honor",
...@@ -73,7 +78,6 @@ def get_enrollments(user_id): ...@@ -73,7 +78,6 @@ def get_enrollments(user_id):
"sku": null "sku": null
} }
], ],
"enrollment_start": 2014-10-15T20:18:00Z,
"invite_only": True "invite_only": True
} }
} }
...@@ -104,7 +108,10 @@ def get_enrollment(user_id, course_id): ...@@ -104,7 +108,10 @@ def get_enrollment(user_id, course_id):
"user": "Bob", "user": "Bob",
"course": { "course": {
"course_id": "edX/DemoX/2014T2", "course_id": "edX/DemoX/2014T2",
"enrollment_end": 2014-12-20T20:18:00Z, "enrollment_end": "2014-12-20T20:18:00Z",
"enrollment_start": "2014-10-15T20:18:00Z",
"course_start": "2015-02-03T00:00:00Z",
"course_end": "2015-05-06T00:00:00Z",
"course_modes": [ "course_modes": [
{ {
"slug": "honor", "slug": "honor",
...@@ -117,7 +124,6 @@ def get_enrollment(user_id, course_id): ...@@ -117,7 +124,6 @@ def get_enrollment(user_id, course_id):
"sku": null "sku": null
} }
], ],
"enrollment_start": 2014-10-15T20:18:00Z,
"invite_only": False "invite_only": False
} }
} }
...@@ -151,7 +157,10 @@ def add_enrollment(user_id, course_id, mode='honor', is_active=True): ...@@ -151,7 +157,10 @@ def add_enrollment(user_id, course_id, mode='honor', is_active=True):
"user": "Bob", "user": "Bob",
"course": { "course": {
"course_id": "edX/DemoX/2014T2", "course_id": "edX/DemoX/2014T2",
"enrollment_end": 2014-12-20T20:18:00Z, "enrollment_end": "2014-12-20T20:18:00Z",
"enrollment_start": "2014-10-15T20:18:00Z",
"course_start": "2015-02-03T00:00:00Z",
"course_end": "2015-05-06T00:00:00Z",
"course_modes": [ "course_modes": [
{ {
"slug": "honor", "slug": "honor",
...@@ -164,7 +173,6 @@ def add_enrollment(user_id, course_id, mode='honor', is_active=True): ...@@ -164,7 +173,6 @@ def add_enrollment(user_id, course_id, mode='honor', is_active=True):
"sku": null "sku": null
} }
], ],
"enrollment_start": 2014-10-15T20:18:00Z,
"invite_only": False "invite_only": False
} }
} }
...@@ -196,7 +204,10 @@ def update_enrollment(user_id, course_id, mode=None, is_active=None): ...@@ -196,7 +204,10 @@ def update_enrollment(user_id, course_id, mode=None, is_active=None):
"user": "Bob", "user": "Bob",
"course": { "course": {
"course_id": "edX/DemoX/2014T2", "course_id": "edX/DemoX/2014T2",
"enrollment_end": 2014-12-20T20:18:00Z, "enrollment_end": "2014-12-20T20:18:00Z",
"enrollment_start": "2014-10-15T20:18:00Z",
"course_start": "2015-02-03T00:00:00Z",
"course_end": "2015-05-06T00:00:00Z",
"course_modes": [ "course_modes": [
{ {
"slug": "honor", "slug": "honor",
...@@ -209,7 +220,6 @@ def update_enrollment(user_id, course_id, mode=None, is_active=None): ...@@ -209,7 +220,6 @@ def update_enrollment(user_id, course_id, mode=None, is_active=None):
"sku": null "sku": null
} }
], ],
"enrollment_start": 2014-10-15T20:18:00Z,
"invite_only": False "invite_only": False
} }
} }
...@@ -239,7 +249,10 @@ def get_course_enrollment_details(course_id): ...@@ -239,7 +249,10 @@ def get_course_enrollment_details(course_id):
>>> get_course_enrollment_details("edX/DemoX/2014T2") >>> get_course_enrollment_details("edX/DemoX/2014T2")
{ {
"course_id": "edX/DemoX/2014T2", "course_id": "edX/DemoX/2014T2",
"enrollment_end": 2014-12-20T20:18:00Z, "enrollment_end": "2014-12-20T20:18:00Z",
"enrollment_start": "2014-10-15T20:18:00Z",
"course_start": "2015-02-03T00:00:00Z",
"course_end": "2015-05-06T00:00:00Z",
"course_modes": [ "course_modes": [
{ {
"slug": "honor", "slug": "honor",
...@@ -252,7 +265,6 @@ def get_course_enrollment_details(course_id): ...@@ -252,7 +265,6 @@ def get_course_enrollment_details(course_id):
"sku": null "sku": null
} }
], ],
"enrollment_start": 2014-10-15T20:18:00Z,
"invite_only": False "invite_only": False
} }
......
...@@ -46,6 +46,8 @@ class CourseField(serializers.RelatedField): ...@@ -46,6 +46,8 @@ class CourseField(serializers.RelatedField):
"course_id": course_id, "course_id": course_id,
"enrollment_start": course.enrollment_start, "enrollment_start": course.enrollment_start,
"enrollment_end": course.enrollment_end, "enrollment_end": course.enrollment_end,
"course_start": course.start,
"course_end": course.end,
"invite_only": course.invitation_only, "invite_only": course.invitation_only,
"course_modes": course_modes, "course_modes": course_modes,
} }
......
...@@ -3,6 +3,7 @@ Tests for user enrollment. ...@@ -3,6 +3,7 @@ Tests for user enrollment.
""" """
import json import json
import unittest import unittest
import datetime
import ddt import ddt
from django.core.cache import cache from django.core.cache import cache
...@@ -305,6 +306,46 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase): ...@@ -305,6 +306,46 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
self.assertEqual(mode['sku'], '123') self.assertEqual(mode['sku'], '123')
self.assertEqual(mode['name'], CourseMode.HONOR) self.assertEqual(mode['name'], CourseMode.HONOR)
@ddt.data(
# NOTE: Studio requires a start date, but this is not
# enforced at the data layer, so we need to handle the case
# in which no dates are specified.
(None, None, None, None),
(datetime.datetime(2015, 1, 2, 3, 4, 5), None, "2015-01-02T03:04:05Z", None),
(None, datetime.datetime(2015, 1, 2, 3, 4, 5), None, "2015-01-02T03:04:05Z"),
(datetime.datetime(2014, 6, 7, 8, 9, 10), datetime.datetime(2015, 1, 2, 3, 4, 5), "2014-06-07T08:09:10Z", "2015-01-02T03:04:05Z"),
)
@ddt.unpack
def test_get_course_details_course_dates(self, start_datetime, end_datetime, expected_start, expected_end):
course = CourseFactory.create(start=start_datetime, end=end_datetime)
self.assert_enrollment_status(course_id=unicode(course.id))
# Check course details
url = reverse('courseenrollmentdetails', kwargs={"course_id": unicode(course.id)})
resp = self.client.get(url)
self.assertEqual(resp.status_code, status.HTTP_200_OK)
data = json.loads(resp.content)
self.assertEqual(data['course_start'], expected_start)
self.assertEqual(data['course_end'], expected_end)
# Check enrollment course details
url = reverse('courseenrollment', kwargs={"course_id": unicode(course.id)})
resp = self.client.get(url)
self.assertEqual(resp.status_code, status.HTTP_200_OK)
data = json.loads(resp.content)
self.assertEqual(data['course_details']['course_start'], expected_start)
self.assertEqual(data['course_details']['course_end'], expected_end)
# Check enrollment list course details
resp = self.client.get(reverse('courseenrollments'))
self.assertEqual(resp.status_code, status.HTTP_200_OK)
data = json.loads(resp.content)
self.assertEqual(data[0]['course_details']['course_start'], expected_start)
self.assertEqual(data[0]['course_details']['course_end'], expected_end)
def test_with_invalid_course_id(self): def test_with_invalid_course_id(self):
self.assert_enrollment_status(course_id='entirely/fake/course', expected_status=status.HTTP_400_BAD_REQUEST) self.assert_enrollment_status(course_id='entirely/fake/course', expected_status=status.HTTP_400_BAD_REQUEST)
......
...@@ -86,7 +86,13 @@ class EnrollmentView(APIView, ApiKeyPermissionMixIn): ...@@ -86,7 +86,13 @@ class EnrollmentView(APIView, ApiKeyPermissionMixIn):
* course_id: The unique identifier for the course. * course_id: The unique identifier for the course.
* enrollment_end: The date and time after which users cannot enroll for the course. * enrollment_start: The date and time that users can begin enrolling in the course. If null, enrollment opens immediately when the course is created.
* enrollment_end: The date and time after which users cannot enroll for the course. If null, the enrollment period never ends.
* course_start: The date and time at which the course opens. If null, the course opens immediately when created.
* course_end: The date and time at which the course closes. If null, the course never ends.
* course_modes: An array of data about the enrollment modes supported for the course. Each enrollment mode collection includes: * course_modes: An array of data about the enrollment modes supported for the course. Each enrollment mode collection includes:
...@@ -98,8 +104,6 @@ class EnrollmentView(APIView, ApiKeyPermissionMixIn): ...@@ -98,8 +104,6 @@ class EnrollmentView(APIView, ApiKeyPermissionMixIn):
* expiration_datetime: The date and time after which users cannot enroll in the course in this mode. * expiration_datetime: The date and time after which users cannot enroll in the course in this mode.
* description: A description of this mode. * description: A description of this mode.
* enrollment_start: The date and time that users can begin enrolling in the course.
* invite_only: Whether students must be invited to enroll in the course; true or false. * invite_only: Whether students must be invited to enroll in the course; true or false.
* user: The ID of the user. * user: The ID of the user.
...@@ -170,7 +174,13 @@ class EnrollmentCourseDetailView(APIView): ...@@ -170,7 +174,13 @@ class EnrollmentCourseDetailView(APIView):
* course_id: The unique identifier of the course. * course_id: The unique identifier of the course.
* enrollment_end: The date and time after which users cannot enroll for the course. * enrollment_start: The date and time that users can begin enrolling in the course. If null, enrollment opens immediately when the course is created.
* enrollment_end: The date and time after which users cannot enroll for the course. If null, the enrollment period never ends.
* course_start: The date and time at which the course opens. If null, the course opens immediately when created.
* course_end: The date and time at which the course closes. If null, the course never ends.
* course_modes: An array of data about the enrollment modes supported for the course. Each enrollment mode collection includes: * course_modes: An array of data about the enrollment modes supported for the course. Each enrollment mode collection includes:
...@@ -182,8 +192,6 @@ class EnrollmentCourseDetailView(APIView): ...@@ -182,8 +192,6 @@ class EnrollmentCourseDetailView(APIView):
* expiration_datetime: The date and time after which users cannot enroll in the course in this mode. * expiration_datetime: The date and time after which users cannot enroll in the course in this mode.
* description: A description of this mode. * description: A description of this mode.
* enrollment_start: The date and time that users can begin enrolling in the course.
* invite_only: Whether students must be invited to enroll in the course; true or false. * invite_only: Whether students must be invited to enroll in the course; true or false.
""" """
...@@ -270,7 +278,13 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn): ...@@ -270,7 +278,13 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
* course_id: The unique identifier for the course. * course_id: The unique identifier for the course.
* enrollment_end: The date and time after which users cannot enroll for the course. * enrollment_start: The date and time that users can begin enrolling in the course. If null, enrollment opens immediately when the course is created.
* enrollment_end: The date and time after which users cannot enroll for the course. If null, the enrollment period never ends.
* course_start: The date and time at which the course opens. If null, the course opens immediately when created.
* course_end: The date and time at which the course closes. If null, the course never ends.
* course_modes: An array of data about the enrollment modes supported for the course. Each enrollment mode collection includes: * course_modes: An array of data about the enrollment modes supported for the course. Each enrollment mode collection includes:
...@@ -282,7 +296,6 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn): ...@@ -282,7 +296,6 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
* expiration_datetime: The date and time after which users cannot enroll in the course in this mode. * expiration_datetime: The date and time after which users cannot enroll in the course in this mode.
* description: A description of this mode. * description: A description of this mode.
* enrollment_start: The date and time that users can begin enrolling in the course.
* invite_only: Whether students must be invited to enroll in the course; true or false. * invite_only: Whether students must be invited to enroll in the course; true or false.
......
...@@ -8,6 +8,8 @@ from unittest import skip ...@@ -8,6 +8,8 @@ from unittest import skip
from nose.plugins.attrib import attr from nose.plugins.attrib import attr
from selenium.webdriver.support.ui import Select from selenium.webdriver.support.ui import Select
from flaky import flaky
from xmodule.partitions.partitions import Group from xmodule.partitions.partitions import Group
from bok_choy.promise import Promise, EmptyPromise from bok_choy.promise import Promise, EmptyPromise
...@@ -1044,6 +1046,7 @@ class GroupConfigurationsTest(ContainerBase, SplitTestMixin): ...@@ -1044,6 +1046,7 @@ class GroupConfigurationsTest(ContainerBase, SplitTestMixin):
rendered_group_names = self.get_select_options(page=courseware_page, selector=".split-test-select") rendered_group_names = self.get_select_options(page=courseware_page, selector=".split-test-select")
self.assertListEqual(group_names, rendered_group_names) self.assertListEqual(group_names, rendered_group_names)
@flaky # TODO fix this, see TNL-2035
def test_split_test_LMS_staff_view(self): def test_split_test_LMS_staff_view(self):
""" """
Scenario: Ensure that split test is correctly rendered in LMS staff mode as it is Scenario: Ensure that split test is correctly rendered in LMS staff mode as it is
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment