From b96a8bf6ff2c357f95b902b16bf47300654c8dfb Mon Sep 17 00:00:00 2001 From: Peter Fogg Date: Tue, 29 Dec 2015 11:08:35 -0500 Subject: [PATCH] Allow searching enrollments by email as well as username. This brings the enrollment support tool's UI in line with the other support tools. --- .../support/templates/enrollment.underscore | 2 +- lms/djangoapps/support/tests/test_views.py | 20 ++++++++++++---- lms/djangoapps/support/urls.py | 6 ++++- lms/djangoapps/support/views/enrollments.py | 23 ++++++++++++------- 4 files changed, 36 insertions(+), 15 deletions(-) diff --git a/lms/djangoapps/support/static/support/templates/enrollment.underscore b/lms/djangoapps/support/static/support/templates/enrollment.underscore index b2553d1d56..f4baabacca 100644 --- a/lms/djangoapps/support/static/support/templates/enrollment.underscore +++ b/lms/djangoapps/support/static/support/templates/enrollment.underscore @@ -6,7 +6,7 @@ type="text" name="query" value="<%- user %>" - placeholder="<%- gettext('Username') %>"> + placeholder="<%- gettext('Username or email address') %>"> diff --git a/lms/djangoapps/support/tests/test_views.py b/lms/djangoapps/support/tests/test_views.py index 3114a0b3af..d637821451 100644 --- a/lms/djangoapps/support/tests/test_views.py +++ b/lms/djangoapps/support/tests/test_views.py @@ -170,7 +170,7 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase CourseEnrollmentFactory.create(mode=CourseMode.AUDIT, user=self.student, course_id=self.course.id) # pylint: disable=no-member - self.url = reverse('support:enrollment_list', kwargs={'username': self.student.username}) + self.url = reverse('support:enrollment_list', kwargs={'username_or_email': self.student.username}) def assert_enrollment(self, mode): """ @@ -179,8 +179,13 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase enrollment = CourseEnrollment.get_enrollment(self.student, self.course.id) # pylint: disable=no-member self.assertEqual(enrollment.mode, mode) - def test_get_enrollments(self): - response = self.client.get(self.url) + @ddt.data('username', 'email') + def test_get_enrollments(self, search_string_type): + url = reverse( + 'support:enrollment_list', + kwargs={'username_or_email': getattr(self.student, search_string_type)} + ) + response = self.client.get(url) self.assertEqual(response.status_code, 200) data = json.loads(response.content) self.assertEqual(len(data), 1) @@ -212,9 +217,14 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase 'reason': 'Financial Assistance', }, json.loads(response.content)[0]['manual_enrollment']) - def test_change_enrollment(self): + @ddt.data('username', 'email') + def test_change_enrollment(self, search_string_type): self.assertIsNone(ManualEnrollmentAudit.get_manual_enrollment_by_email(self.student.email)) - response = self.client.post(self.url, data={ + url = reverse( + 'support:enrollment_list', + kwargs={'username_or_email': getattr(self.student, search_string_type)} + ) + response = self.client.post(url, data={ 'course_id': unicode(self.course.id), # pylint: disable=no-member 'old_mode': CourseMode.AUDIT, 'new_mode': CourseMode.VERIFIED, diff --git a/lms/djangoapps/support/urls.py b/lms/djangoapps/support/urls.py index d972caf0cf..50ebe6021c 100644 --- a/lms/djangoapps/support/urls.py +++ b/lms/djangoapps/support/urls.py @@ -11,5 +11,9 @@ urlpatterns = patterns( url(r'^certificates/?$', views.CertificatesSupportView.as_view(), name="certificates"), url(r'^refund/?$', views.RefundSupportView.as_view(), name="refund"), url(r'^enrollment/?$', views.EnrollmentSupportView.as_view(), name="enrollment"), - url(r'^enrollment/(?P[\w.@+-]+)?$', views.EnrollmentSupportListView.as_view(), name="enrollment_list"), + url( + r'^enrollment/(?P[\w.@+-]+)?$', + views.EnrollmentSupportListView.as_view(), + name="enrollment_list" + ), ) diff --git a/lms/djangoapps/support/views/enrollments.py b/lms/djangoapps/support/views/enrollments.py index 5efc5a4fdc..46420606a1 100644 --- a/lms/djangoapps/support/views/enrollments.py +++ b/lms/djangoapps/support/views/enrollments.py @@ -4,6 +4,7 @@ Support tool for changing course enrollments. from django.contrib.auth.models import User from django.core.urlresolvers import reverse from django.db import transaction +from django.db.models import Q from django.http import HttpResponseBadRequest from django.utils.decorators import method_decorator from django.views.generic import View @@ -45,12 +46,17 @@ class EnrollmentSupportListView(GenericAPIView): """ @method_decorator(require_support_permission) - def get(self, request, username): + def get(self, request, username_or_email): """ Returns a list of enrollments for the given user, along with information about previous manual enrollment changes. """ - enrollments = get_enrollments(username) + try: + user = User.objects.get(Q(username=username_or_email) | Q(email=username_or_email)) + except User.DoesNotExist: + return JsonResponse([]) + + enrollments = get_enrollments(user.username) for enrollment in enrollments: # Folds the course_details field up into the main JSON object. enrollment.update(**enrollment.pop('course_details')) @@ -62,28 +68,29 @@ class EnrollmentSupportListView(GenericAPIView): return JsonResponse(enrollments) @method_decorator(require_support_permission) - def post(self, request, username): + def post(self, request, username_or_email): """Allows support staff to alter a user's enrollment.""" try: + user = User.objects.get(Q(username=username_or_email) | Q(email=username_or_email)) course_id = request.data['course_id'] course_key = CourseKey.from_string(course_id) old_mode = request.data['old_mode'] new_mode = request.data['new_mode'] reason = request.data['reason'] - enrollment = CourseEnrollment.objects.get(course_id=course_key, user__username=username) + enrollment = CourseEnrollment.objects.get(user=user, course_id=course_key) if enrollment.mode != old_mode: return HttpResponseBadRequest(u'User {username} is not enrolled with mode {old_mode}.'.format( - username=username, + username=user.username, old_mode=old_mode )) except KeyError as err: return HttpResponseBadRequest(u'The field {} is required.'.format(err.message)) except InvalidKeyError: return HttpResponseBadRequest(u'Could not parse course key.') - except CourseEnrollment.DoesNotExist: + except (CourseEnrollment.DoesNotExist, User.DoesNotExist): return HttpResponseBadRequest( u'Could not find enrollment for user {username} in course {course}.'.format( - username=username, + username=username_or_email, course=unicode(course_key) ) ) @@ -91,7 +98,7 @@ class EnrollmentSupportListView(GenericAPIView): # Wrapped in a transaction so that we can be sure the # ManualEnrollmentAudit record is always created correctly. with transaction.atomic(): - update_enrollment(username, course_id, mode=new_mode) + update_enrollment(user.username, course_id, mode=new_mode) manual_enrollment = ManualEnrollmentAudit.create_manual_enrollment_audit( request.user, enrollment.user.email,