Commit c0fa05e2 by Peter Fogg

Merge pull request #11107 from edx/peter-fogg/enrollment-support-email

Allow searching enrollments by email as well as username.
parents 74ab0df0 b96a8bf6
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
type="text" type="text"
name="query" name="query"
value="<%- user %>" value="<%- user %>"
placeholder="<%- gettext('Username') %>"> placeholder="<%- gettext('Username or email address') %>">
</input> </input>
<input type="submit" value="<%- gettext('Search') %>" class="btn-disable-on-submit"></input> <input type="submit" value="<%- gettext('Search') %>" class="btn-disable-on-submit"></input>
</form> </form>
......
...@@ -170,7 +170,7 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase ...@@ -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 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): def assert_enrollment(self, mode):
""" """
...@@ -179,8 +179,13 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase ...@@ -179,8 +179,13 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase
enrollment = CourseEnrollment.get_enrollment(self.student, self.course.id) # pylint: disable=no-member enrollment = CourseEnrollment.get_enrollment(self.student, self.course.id) # pylint: disable=no-member
self.assertEqual(enrollment.mode, mode) self.assertEqual(enrollment.mode, mode)
def test_get_enrollments(self): @ddt.data('username', 'email')
response = self.client.get(self.url) 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) self.assertEqual(response.status_code, 200)
data = json.loads(response.content) data = json.loads(response.content)
self.assertEqual(len(data), 1) self.assertEqual(len(data), 1)
...@@ -212,9 +217,14 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase ...@@ -212,9 +217,14 @@ class SupportViewEnrollmentsTests(SharedModuleStoreTestCase, SupportViewTestCase
'reason': 'Financial Assistance', 'reason': 'Financial Assistance',
}, json.loads(response.content)[0]['manual_enrollment']) }, 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)) 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 'course_id': unicode(self.course.id), # pylint: disable=no-member
'old_mode': CourseMode.AUDIT, 'old_mode': CourseMode.AUDIT,
'new_mode': CourseMode.VERIFIED, 'new_mode': CourseMode.VERIFIED,
......
...@@ -11,5 +11,9 @@ urlpatterns = patterns( ...@@ -11,5 +11,9 @@ urlpatterns = patterns(
url(r'^certificates/?$', views.CertificatesSupportView.as_view(), name="certificates"), url(r'^certificates/?$', views.CertificatesSupportView.as_view(), name="certificates"),
url(r'^refund/?$', views.RefundSupportView.as_view(), name="refund"), url(r'^refund/?$', views.RefundSupportView.as_view(), name="refund"),
url(r'^enrollment/?$', views.EnrollmentSupportView.as_view(), name="enrollment"), url(r'^enrollment/?$', views.EnrollmentSupportView.as_view(), name="enrollment"),
url(r'^enrollment/(?P<username>[\w.@+-]+)?$', views.EnrollmentSupportListView.as_view(), name="enrollment_list"), url(
r'^enrollment/(?P<username_or_email>[\w.@+-]+)?$',
views.EnrollmentSupportListView.as_view(),
name="enrollment_list"
),
) )
...@@ -4,6 +4,7 @@ Support tool for changing course enrollments. ...@@ -4,6 +4,7 @@ Support tool for changing course enrollments.
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db import transaction from django.db import transaction
from django.db.models import Q
from django.http import HttpResponseBadRequest from django.http import HttpResponseBadRequest
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.views.generic import View from django.views.generic import View
...@@ -45,12 +46,17 @@ class EnrollmentSupportListView(GenericAPIView): ...@@ -45,12 +46,17 @@ class EnrollmentSupportListView(GenericAPIView):
""" """
@method_decorator(require_support_permission) @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 Returns a list of enrollments for the given user, along with
information about previous manual enrollment changes. 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: for enrollment in enrollments:
# Folds the course_details field up into the main JSON object. # Folds the course_details field up into the main JSON object.
enrollment.update(**enrollment.pop('course_details')) enrollment.update(**enrollment.pop('course_details'))
...@@ -62,28 +68,29 @@ class EnrollmentSupportListView(GenericAPIView): ...@@ -62,28 +68,29 @@ class EnrollmentSupportListView(GenericAPIView):
return JsonResponse(enrollments) return JsonResponse(enrollments)
@method_decorator(require_support_permission) @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.""" """Allows support staff to alter a user's enrollment."""
try: try:
user = User.objects.get(Q(username=username_or_email) | Q(email=username_or_email))
course_id = request.data['course_id'] course_id = request.data['course_id']
course_key = CourseKey.from_string(course_id) course_key = CourseKey.from_string(course_id)
old_mode = request.data['old_mode'] old_mode = request.data['old_mode']
new_mode = request.data['new_mode'] new_mode = request.data['new_mode']
reason = request.data['reason'] 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: if enrollment.mode != old_mode:
return HttpResponseBadRequest(u'User {username} is not enrolled with mode {old_mode}.'.format( return HttpResponseBadRequest(u'User {username} is not enrolled with mode {old_mode}.'.format(
username=username, username=user.username,
old_mode=old_mode old_mode=old_mode
)) ))
except KeyError as err: except KeyError as err:
return HttpResponseBadRequest(u'The field {} is required.'.format(err.message)) return HttpResponseBadRequest(u'The field {} is required.'.format(err.message))
except InvalidKeyError: except InvalidKeyError:
return HttpResponseBadRequest(u'Could not parse course key.') return HttpResponseBadRequest(u'Could not parse course key.')
except CourseEnrollment.DoesNotExist: except (CourseEnrollment.DoesNotExist, User.DoesNotExist):
return HttpResponseBadRequest( return HttpResponseBadRequest(
u'Could not find enrollment for user {username} in course {course}.'.format( u'Could not find enrollment for user {username} in course {course}.'.format(
username=username, username=username_or_email,
course=unicode(course_key) course=unicode(course_key)
) )
) )
...@@ -91,7 +98,7 @@ class EnrollmentSupportListView(GenericAPIView): ...@@ -91,7 +98,7 @@ class EnrollmentSupportListView(GenericAPIView):
# Wrapped in a transaction so that we can be sure the # Wrapped in a transaction so that we can be sure the
# ManualEnrollmentAudit record is always created correctly. # ManualEnrollmentAudit record is always created correctly.
with transaction.atomic(): 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( manual_enrollment = ManualEnrollmentAudit.create_manual_enrollment_audit(
request.user, request.user,
enrollment.user.email, enrollment.user.email,
......
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