diff --git a/cms/djangoapps/api/v1/serializers/course_runs.py b/cms/djangoapps/api/v1/serializers/course_runs.py index 098919afb1..be2c37b43c 100644 --- a/cms/djangoapps/api/v1/serializers/course_runs.py +++ b/cms/djangoapps/api/v1/serializers/course_runs.py @@ -1,6 +1,7 @@ import six from django.contrib.auth import get_user_model from django.db import transaction +from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers from rest_framework.fields import empty @@ -34,6 +35,15 @@ class CourseRunScheduleSerializer(serializers.Serializer): class CourseRunTeamSerializer(serializers.Serializer): def to_internal_value(self, data): + """Overriding this to support deserialization, for write operations.""" + for member in data: + try: + User.objects.get(username=member['user']) + except User.DoesNotExist: + raise serializers.ValidationError( + _('Course team user does not exist') + ) + return CourseAccessRoleSerializer(data=data, many=True).to_internal_value(data) def to_representation(self, instance): diff --git a/cms/djangoapps/api/v1/tests/test_views/test_course_runs.py b/cms/djangoapps/api/v1/tests/test_views/test_course_runs.py index e1eb16858e..be6c4b6f2e 100644 --- a/cms/djangoapps/api/v1/tests/test_views/test_course_runs.py +++ b/cms/djangoapps/api/v1/tests/test_views/test_course_runs.py @@ -6,6 +6,7 @@ from django.core.files.uploadedfile import SimpleUploadedFile from django.core.urlresolvers import reverse from django.test import RequestFactory from opaque_keys.edx.keys import CourseKey +from openedx.core.lib.courses import course_image_url from rest_framework.test import APIClient from xmodule.contentstore.content import StaticContent from xmodule.contentstore.django import contentstore @@ -14,7 +15,6 @@ from xmodule.modulestore.django import modulestore from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory, ToyCourseFactory -from openedx.core.lib.courses import course_image_url from student.models import CourseAccessRole from student.tests.factories import AdminFactory, TEST_PASSWORD, UserFactory from ..utils import serialize_datetime @@ -23,6 +23,9 @@ from ...serializers.course_runs import CourseRunSerializer @ddt.ddt class CourseRunViewSetTests(ModuleStoreTestCase): + """ + Tests for creating course runs + """ list_url = reverse('api:v1:course_run-list') def setUp(self): @@ -31,6 +34,27 @@ class CourseRunViewSetTests(ModuleStoreTestCase): user = AdminFactory() self.client.login(username=user.username, password=TEST_PASSWORD) + def get_course_run_data(self, user, start, end, enrollment_start, enrollment_end, pacing_type, role='instructor'): + return { + 'title': 'Testing 101', + 'org': 'TestingX', + 'number': 'Testing101x', + 'run': '3T2017', + 'schedule': { + 'start': serialize_datetime(start), + 'end': serialize_datetime(end), + 'enrollment_start': serialize_datetime(enrollment_start), + 'enrollment_end': serialize_datetime(enrollment_end), + }, + 'team': [ + { + 'user': user.username, + 'role': role, + } + ], + 'pacing_type': pacing_type, + } + def assert_course_run_schedule(self, course_run, start, end, enrollment_start, enrollment_end): assert course_run.start == start assert course_run.end == end @@ -137,7 +161,7 @@ class CourseRunViewSetTests(ModuleStoreTestCase): } response = self.client.put(url, data, format='json') assert response.status_code == 400 - assert response.data == {'team': [{'user': ['Object with username=test-user does not exist.']}]} + assert response.data == {'team': ['Course team user does not exist']} def test_update_with_pacing_type(self): """ @@ -231,45 +255,45 @@ class CourseRunViewSetTests(ModuleStoreTestCase): ) @ddt.unpack def test_create(self, pacing_type, expected_self_paced_value): + """Tests successful course run creation""" + user = UserFactory() start = datetime.datetime.now(pytz.UTC).replace(microsecond=0) end = start + datetime.timedelta(days=30) enrollment_start = start - datetime.timedelta(days=7) enrollment_end = end - datetime.timedelta(days=14) - user = UserFactory() role = 'staff' - data = { - 'title': 'Testing 101', - 'org': 'TestingX', - 'number': 'Testing101x', - 'run': '3T2017', - 'schedule': { - 'start': serialize_datetime(start), - 'end': serialize_datetime(end), - 'enrollment_start': serialize_datetime(enrollment_start), - 'enrollment_end': serialize_datetime(enrollment_end), - }, - 'team': [ - { - 'user': user.username, - 'role': role, - } - ], - 'pacing_type': pacing_type, - } + data = self.get_course_run_data(user, start, end, enrollment_start, enrollment_end, pacing_type, role) + response = self.client.post(self.list_url, data, format='json') - assert response.status_code == 201 + self.assertEqual(response.status_code, 201) course_run_key = CourseKey.from_string(response.data['id']) course_run = modulestore().get_course(course_run_key) - assert course_run.display_name == data['title'] - assert course_run.id.org == data['org'] - assert course_run.id.course == data['number'] - assert course_run.id.run == data['run'] - assert course_run.self_paced is expected_self_paced_value + self.assertEqual(course_run.display_name, data['title']) + self.assertEqual(course_run.id.org, data['org']) + self.assertEqual(course_run.id.course, data['number']) + self.assertEqual(course_run.id.run, data['run']) + self.assertEqual(course_run.self_paced, expected_self_paced_value) self.assert_course_run_schedule(course_run, start, end, enrollment_start, enrollment_end) self.assert_access_role(course_run, user, role) self.assert_course_access_role_count(course_run, 1) + def test_create_with_invalid_course_team(self): + """ + Tests that if the course team user is invalid, it returns bad request status + with expected validation message + """ + user = UserFactory() + start = datetime.datetime.now(pytz.UTC).replace(microsecond=0) + end = start + datetime.timedelta(days=30) + enrollment_start = start - datetime.timedelta(days=7) + enrollment_end = end - datetime.timedelta(days=14) + data = self.get_course_run_data(user, start, end, enrollment_start, enrollment_end, 'self-paced') + data['team'] = [{'user': 'invalid-username'}] + response = self.client.post(self.list_url, data, format='json') + self.assertEqual(response.status_code, 400) + self.assertDictContainsSubset({'team': ['Course team user does not exist']}, response.data) + def test_images_upload(self): # http://www.django-rest-framework.org/api-guide/parsers/#fileuploadparser course_run = CourseFactory()