Commit 8a5782eb by Clinton Blackburn

Updated Studio API to expose course run pacing type

The pacing type can now be read and updated.

EDUCATOR-1464
parent 612c99ba
...@@ -85,6 +85,14 @@ class CourseRunImageField(serializers.ImageField): ...@@ -85,6 +85,14 @@ class CourseRunImageField(serializers.ImageField):
return request.build_absolute_uri(value) return request.build_absolute_uri(value)
class CourseRunPacingTypeField(serializers.ChoiceField):
def to_representation(self, value):
return 'self_paced' if value else 'instructor_paced'
def to_internal_value(self, data):
return data == 'self_paced'
class CourseRunImageSerializer(serializers.Serializer): class CourseRunImageSerializer(serializers.Serializer):
# We set an empty default to prevent the parent serializer from attempting # We set an empty default to prevent the parent serializer from attempting
# to save this value to the Course object. # to save this value to the Course object.
...@@ -100,10 +108,15 @@ class CourseRunImageSerializer(serializers.Serializer): ...@@ -100,10 +108,15 @@ class CourseRunImageSerializer(serializers.Serializer):
return instance return instance
class CourseRunSerializer(CourseRunTeamSerializerMixin, serializers.Serializer): class CourseRunSerializerCommonFieldsMixin(serializers.Serializer):
schedule = CourseRunScheduleSerializer(source='*', required=False)
pacing_type = CourseRunPacingTypeField(source='self_paced', required=False,
choices=(('instructor_paced', False), ('self_paced', True),))
class CourseRunSerializer(CourseRunSerializerCommonFieldsMixin, CourseRunTeamSerializerMixin, serializers.Serializer):
id = serializers.CharField(read_only=True) id = serializers.CharField(read_only=True)
title = serializers.CharField(source='display_name') title = serializers.CharField(source='display_name')
schedule = CourseRunScheduleSerializer(source='*', required=False)
images = CourseRunImageSerializer(source='*', required=False) images = CourseRunImageSerializer(source='*', required=False)
def update(self, instance, validated_data): def update(self, instance, validated_data):
...@@ -135,10 +148,10 @@ class CourseRunCreateSerializer(CourseRunSerializer): ...@@ -135,10 +148,10 @@ class CourseRunCreateSerializer(CourseRunSerializer):
return instance return instance
class CourseRunRerunSerializer(CourseRunTeamSerializerMixin, serializers.Serializer): class CourseRunRerunSerializer(CourseRunSerializerCommonFieldsMixin, CourseRunTeamSerializerMixin,
serializers.Serializer):
title = serializers.CharField(source='display_name', required=False) title = serializers.CharField(source='display_name', required=False)
run = serializers.CharField(source='id.run') run = serializers.CharField(source='id.run')
schedule = CourseRunScheduleSerializer(source='*', required=False)
def validate_run(self, value): def validate_run(self, value):
course_run_key = self.instance.id course_run_key = self.instance.id
......
import datetime import datetime
import ddt
import pytz import pytz
from django.test import RequestFactory from django.test import RequestFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
...@@ -12,14 +13,27 @@ from ..utils import serialize_datetime ...@@ -12,14 +13,27 @@ from ..utils import serialize_datetime
from ...serializers.course_runs import CourseRunSerializer from ...serializers.course_runs import CourseRunSerializer
@ddt.ddt
class CourseRunSerializerTests(ModuleStoreTestCase): class CourseRunSerializerTests(ModuleStoreTestCase):
def test_data(self):
@ddt.data(
('instructor_paced', False),
('self_paced', True),
)
@ddt.unpack
def test_data(self, expected_pacing_type, self_paced):
start = datetime.datetime.now(pytz.UTC) start = datetime.datetime.now(pytz.UTC)
end = start + datetime.timedelta(days=30) end = start + datetime.timedelta(days=30)
enrollment_start = start - datetime.timedelta(days=7) enrollment_start = start - datetime.timedelta(days=7)
enrollment_end = end - datetime.timedelta(days=14) enrollment_end = end - datetime.timedelta(days=14)
course = CourseFactory(start=start, end=end, enrollment_start=enrollment_start, enrollment_end=enrollment_end) course = CourseFactory(
start=start,
end=end,
enrollment_start=enrollment_start,
enrollment_end=enrollment_end,
self_paced=self_paced
)
instructor = UserFactory() instructor = UserFactory()
CourseInstructorRole(course.id).add_users(instructor) CourseInstructorRole(course.id).add_users(instructor)
staff = UserFactory() staff = UserFactory()
...@@ -48,6 +62,7 @@ class CourseRunSerializerTests(ModuleStoreTestCase): ...@@ -48,6 +62,7 @@ class CourseRunSerializerTests(ModuleStoreTestCase):
], ],
'images': { 'images': {
'card_image': request.build_absolute_uri(course_image_url(course)), 'card_image': request.build_absolute_uri(course_image_url(course)),
} },
'pacing_type': expected_pacing_type,
} }
assert serializer.data == expected assert serializer.data == expected
import datetime import datetime
import ddt
import pytz import pytz
from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
...@@ -20,6 +21,7 @@ from ..utils import serialize_datetime ...@@ -20,6 +21,7 @@ from ..utils import serialize_datetime
from ...serializers.course_runs import CourseRunSerializer from ...serializers.course_runs import CourseRunSerializer
@ddt.ddt
class CourseRunViewSetTests(ModuleStoreTestCase): class CourseRunViewSetTests(ModuleStoreTestCase):
list_url = reverse('api:v1:course_run-list') list_url = reverse('api:v1:course_run-list')
...@@ -139,7 +141,7 @@ class CourseRunViewSetTests(ModuleStoreTestCase): ...@@ -139,7 +141,7 @@ class CourseRunViewSetTests(ModuleStoreTestCase):
def test_partial_update(self): def test_partial_update(self):
role = 'staff' role = 'staff'
start = datetime.datetime.now(pytz.UTC).replace(microsecond=0) start = datetime.datetime.now(pytz.UTC).replace(microsecond=0)
course_run = CourseFactory(start=start, end=None, enrollment_start=None, enrollment_end=None) course_run = CourseFactory(start=start, end=None, enrollment_start=None, enrollment_end=None, self_paced=False)
# The request should only update or create new team members # The request should only update or create new team members
existing_user = UserFactory() existing_user = UserFactory()
...@@ -159,6 +161,7 @@ class CourseRunViewSetTests(ModuleStoreTestCase): ...@@ -159,6 +161,7 @@ class CourseRunViewSetTests(ModuleStoreTestCase):
'role': role, 'role': role,
}, },
], ],
'pacing_type': 'self_paced',
} }
url = reverse('api:v1:course_run-detail', kwargs={'pk': str(course_run.id)}) url = reverse('api:v1:course_run-detail', kwargs={'pk': str(course_run.id)})
...@@ -169,9 +172,15 @@ class CourseRunViewSetTests(ModuleStoreTestCase): ...@@ -169,9 +172,15 @@ class CourseRunViewSetTests(ModuleStoreTestCase):
self.assert_course_access_role_count(course_run, 2) self.assert_course_access_role_count(course_run, 2)
course_run = modulestore().get_course(course_run.id) course_run = modulestore().get_course(course_run.id)
assert course_run.self_paced is True
self.assert_course_run_schedule(course_run, start, None, None, None) self.assert_course_run_schedule(course_run, start, None, None, None)
def test_create(self): @ddt.data(
('instructor_paced', False),
('self_paced', True),
)
@ddt.unpack
def test_create(self, pacing_type, expected_self_paced_value):
start = datetime.datetime.now(pytz.UTC).replace(microsecond=0) start = datetime.datetime.now(pytz.UTC).replace(microsecond=0)
end = start + datetime.timedelta(days=30) end = start + datetime.timedelta(days=30)
enrollment_start = start - datetime.timedelta(days=7) enrollment_start = start - datetime.timedelta(days=7)
...@@ -195,6 +204,7 @@ class CourseRunViewSetTests(ModuleStoreTestCase): ...@@ -195,6 +204,7 @@ class CourseRunViewSetTests(ModuleStoreTestCase):
'role': role, 'role': role,
} }
], ],
'pacing_type': pacing_type,
} }
response = self.client.post(self.list_url, data, format='json') response = self.client.post(self.list_url, data, format='json')
assert response.status_code == 201 assert response.status_code == 201
...@@ -205,6 +215,7 @@ class CourseRunViewSetTests(ModuleStoreTestCase): ...@@ -205,6 +215,7 @@ class CourseRunViewSetTests(ModuleStoreTestCase):
assert course_run.id.org == data['org'] assert course_run.id.org == data['org']
assert course_run.id.course == data['number'] assert course_run.id.course == data['number']
assert course_run.id.run == data['run'] assert course_run.id.run == data['run']
assert course_run.self_paced is expected_self_paced_value
self.assert_course_run_schedule(course_run, start, end, enrollment_start, enrollment_end) self.assert_course_run_schedule(course_run, start, end, enrollment_start, enrollment_end)
self.assert_access_role(course_run, user, role) self.assert_access_role(course_run, user, role)
self.assert_course_access_role_count(course_run, 1) self.assert_course_access_role_count(course_run, 1)
...@@ -242,7 +253,12 @@ class CourseRunViewSetTests(ModuleStoreTestCase): ...@@ -242,7 +253,12 @@ class CourseRunViewSetTests(ModuleStoreTestCase):
# There should now be an image stored # There should now be an image stored
contentstore().find(content_key) contentstore().find(content_key)
def test_rerun(self): @ddt.data(
('instructor_paced', False),
('self_paced', True),
)
@ddt.unpack
def test_rerun(self, pacing_type, expected_self_paced_value):
course_run = ToyCourseFactory() course_run = ToyCourseFactory()
start = datetime.datetime.now(pytz.UTC).replace(microsecond=0) start = datetime.datetime.now(pytz.UTC).replace(microsecond=0)
end = start + datetime.timedelta(days=30) end = start + datetime.timedelta(days=30)
...@@ -264,6 +280,7 @@ class CourseRunViewSetTests(ModuleStoreTestCase): ...@@ -264,6 +280,7 @@ class CourseRunViewSetTests(ModuleStoreTestCase):
'role': role, 'role': role,
} }
], ],
'pacing_type': pacing_type,
} }
response = self.client.post(url, data, format='json') response = self.client.post(url, data, format='json')
assert response.status_code == 201 assert response.status_code == 201
...@@ -271,6 +288,7 @@ class CourseRunViewSetTests(ModuleStoreTestCase): ...@@ -271,6 +288,7 @@ class CourseRunViewSetTests(ModuleStoreTestCase):
course_run_key = CourseKey.from_string(response.data['id']) course_run_key = CourseKey.from_string(response.data['id'])
course_run = modulestore().get_course(course_run_key) course_run = modulestore().get_course(course_run_key)
assert course_run.id.run == run assert course_run.id.run == run
assert course_run.self_paced is expected_self_paced_value
self.assert_course_run_schedule(course_run, start, end, None, None) self.assert_course_run_schedule(course_run, start, end, None, None)
self.assert_access_role(course_run, user, role) self.assert_access_role(course_run, user, role)
self.assert_course_access_role_count(course_run, 1) self.assert_course_access_role_count(course_run, 1)
......
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