Commit bbf4471d by Sarina Canelake

Merge pull request #2992 from edx/sarina/fix-beta-batch-enrollment

Simple email checking for batch enrollment on inst dash
parents 05ea675f 066d04f5
...@@ -294,6 +294,28 @@ class TestInstructorAPIEnrollment(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -294,6 +294,28 @@ class TestInstructorAPIEnrollment(ModuleStoreTestCase, LoginEnrollmentTestCase):
response = self.client.get(url, {'emails': self.enrolled_student.email, 'action': action}) response = self.client.get(url, {'emails': self.enrolled_student.email, 'action': action})
self.assertEqual(response.status_code, 400) self.assertEqual(response.status_code, 400)
def test_enroll_with_username(self):
# Test with an invalid email address (eg, a username).
url = reverse('students_update_enrollment', kwargs={'course_id': self.course.id})
response = self.client.get(url, {'emails': self.notenrolled_student.username, 'action': 'enroll', 'email_students': False})
self.assertEqual(response.status_code, 200)
# test the response data
expected = {
"action": "enroll",
'auto_enroll': False,
"results": [
{
"email": self.notenrolled_student.username,
"error": True,
"invalidEmail": True
}
]
}
res_json = json.loads(response.content)
self.assertEqual(res_json, expected)
def test_enroll_without_email(self): def test_enroll_without_email(self):
url = reverse('students_update_enrollment', kwargs={'course_id': self.course.id}) url = reverse('students_update_enrollment', kwargs={'course_id': self.course.id})
response = self.client.get(url, {'emails': self.notenrolled_student.email, 'action': 'enroll', 'email_students': False}) response = self.client.get(url, {'emails': self.notenrolled_student.email, 'action': 'enroll', 'email_students': False})
......
...@@ -13,7 +13,9 @@ import requests ...@@ -13,7 +13,9 @@ import requests
from django.conf import settings from django.conf import settings
from django_future.csrf import ensure_csrf_cookie from django_future.csrf import ensure_csrf_cookie
from django.views.decorators.cache import cache_control from django.views.decorators.cache import cache_control
from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.core.validators import validate_email
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseForbidden
from django.utils.html import strip_tags from django.utils.html import strip_tags
...@@ -251,6 +253,21 @@ def students_update_enrollment(request, course_id): ...@@ -251,6 +253,21 @@ def students_update_enrollment(request, course_id):
results = [] results = []
for email in emails: for email in emails:
try: try:
# Use django.core.validators.validate_email to check email address
# validity (obviously, cannot check if email actually /exists/,
# simply that it is plausibly valid)
validate_email(email)
except ValidationError:
# Flag this email as an error if invalid, but continue checking
# the remaining in the list
results.append({
'email': email,
'error': True,
'invalidEmail': True,
})
continue
try:
if action == 'enroll': if action == 'enroll':
before, after = enroll_email(course_id, email, auto_enroll, email_students, email_params) before, after = enroll_email(course_id, email, auto_enroll, email_students, email_params)
elif action == 'unenroll': elif action == 'unenroll':
...@@ -273,6 +290,7 @@ def students_update_enrollment(request, course_id): ...@@ -273,6 +290,7 @@ def students_update_enrollment(request, course_id):
results.append({ results.append({
'email': email, 'email': email,
'error': True, 'error': True,
'invalidEmail': False,
}) })
response_payload = { response_payload = {
......
...@@ -182,7 +182,7 @@ class BetaTesterBulkAddition ...@@ -182,7 +182,7 @@ class BetaTesterBulkAddition
url: @$btn_beta_testers.data 'endpoint' url: @$btn_beta_testers.data 'endpoint'
data: send_data data: send_data
success: (data) => @display_response data success: (data) => @display_response data
error: std_ajax_err => @fail_with_error gettext "Error adding/removing user(s) as beta tester(s)." error: std_ajax_err => @fail_with_error gettext "Error adding/removing users as beta testers."
fail_with_error: (msg) -> fail_with_error: (msg) ->
console.warn msg console.warn msg
...@@ -219,19 +219,19 @@ class BetaTesterBulkAddition ...@@ -219,19 +219,19 @@ class BetaTesterBulkAddition
if successes.length and data_from_server.action is 'add' if successes.length and data_from_server.action is 'add'
`// Translators: A list of users appears after this sentence` `// Translators: A list of users appears after this sentence`
render_list gettext("These user(s) were successfully added as beta tester(s):"), (sr.email for sr in successes) render_list gettext("These users were successfully added as beta testers:"), (sr.email for sr in successes)
if successes.length and data_from_server.action is 'remove' if successes.length and data_from_server.action is 'remove'
`// Translators: A list of users appears after this sentence` `// Translators: A list of users appears after this sentence`
render_list gettext("These user(s) were successfully removed as beta tester(s):"), (sr.email for sr in successes) render_list gettext("These users were successfully removed as beta testers:"), (sr.email for sr in successes)
if errors.length and data_from_server.action is 'add' if errors.length and data_from_server.action is 'add'
`// Translators: A list of users appears after this sentence` `// Translators: A list of users appears after this sentence`
render_list gettext("These user(s) were not added as beta tester(s):"), (sr.email for sr in errors) render_list gettext("These users were not added as beta testers:"), (sr.email for sr in errors)
if errors.length and data_from_server.action is 'remove' if errors.length and data_from_server.action is 'remove'
`// Translators: A list of users appears after this sentence` `// Translators: A list of users appears after this sentence`
render_list gettext("These user(s) were not removed as beta tester(s):"), (sr.email for sr in errors) render_list gettext("These users were not removed as beta testers:"), (sr.email for sr in errors)
if no_users.length if no_users.length
no_users.push gettext("Users must create and activate their account before they can be promoted to beta tester.") no_users.push gettext("Users must create and activate their account before they can be promoted to beta tester.")
...@@ -265,7 +265,7 @@ class BatchEnrollment ...@@ -265,7 +265,7 @@ class BatchEnrollment
url: $(event.target).data 'endpoint' url: $(event.target).data 'endpoint'
data: send_data data: send_data
success: (data) => @display_response data success: (data) => @display_response data
error: std_ajax_err => @fail_with_error gettext "Error enrolling/unenrolling user(s)." error: std_ajax_err => @fail_with_error gettext "Error enrolling/unenrolling users."
fail_with_error: (msg) -> fail_with_error: (msg) ->
...@@ -281,6 +281,8 @@ class BatchEnrollment ...@@ -281,6 +281,8 @@ class BatchEnrollment
# these results arrays contain student_results # these results arrays contain student_results
# only populated arrays will be rendered # only populated arrays will be rendered
# #
# invalid email addresses
invalid_email = []
# students for which there was an error during the action # students for which there was an error during the action
errors = [] errors = []
# students who are now enrolled in the course # students who are now enrolled in the course
...@@ -317,9 +319,13 @@ class BatchEnrollment ...@@ -317,9 +319,13 @@ class BatchEnrollment
# student_results is of the form { # student_results is of the form {
# 'email': email, # 'email': email,
# 'error': True, # 'error': True,
# 'invalidEmail': True, # if email doesn't match "[^@]+@[^@]+\.[^@]+"
# } # }
if student_results.error if student_results.invalidEmail
invalid_email.push student_results
else if student_results.error
errors.push student_results errors.push student_results
else if student_results.after.enrollment else if student_results.after.enrollment
...@@ -354,6 +360,9 @@ class BatchEnrollment ...@@ -354,6 +360,9 @@ class BatchEnrollment
@$task_response.append task_res_section @$task_response.append task_res_section
if invalid_email.length
render_list gettext("The following email addresses are invalid:"), (sr.email for sr in invalid_email)
if errors.length if errors.length
errors_label = do -> errors_label = do ->
if data_from_server.action is 'enroll' if data_from_server.action is 'enroll'
...@@ -368,49 +377,49 @@ class BatchEnrollment ...@@ -368,49 +377,49 @@ class BatchEnrollment
render_list errors_label, (sr.email for sr in errors) render_list errors_label, (sr.email for sr in errors)
if enrolled.length and emailStudents if enrolled.length and emailStudents
render_list gettext("Successfully enrolled and sent email to the following user(s):"), (sr.email for sr in enrolled) render_list gettext("Successfully enrolled and sent email to the following users:"), (sr.email for sr in enrolled)
if enrolled.length and not emailStudents if enrolled.length and not emailStudents
`// Translators: A list of users appears after this sentence` `// Translators: A list of users appears after this sentence`
render_list gettext("Successfully enrolled the following user(s):"), (sr.email for sr in enrolled) render_list gettext("Successfully enrolled the following users:"), (sr.email for sr in enrolled)
# Student hasn't registered so we allow them to enroll # Student hasn't registered so we allow them to enroll
if allowed.length and emailStudents if allowed.length and emailStudents
`// Translators: A list of users appears after this sentence` `// Translators: A list of users appears after this sentence`
render_list gettext("Successfully sent enrollment emails to the following user(s). They will be allowed to enroll once they register:"), render_list gettext("Successfully sent enrollment emails to the following users. They will be allowed to enroll once they register:"),
(sr.email for sr in allowed) (sr.email for sr in allowed)
# Student hasn't registered so we allow them to enroll # Student hasn't registered so we allow them to enroll
if allowed.length and not emailStudents if allowed.length and not emailStudents
`// Translators: A list of users appears after this sentence` `// Translators: A list of users appears after this sentence`
render_list gettext("These user(s) will be allowed to enroll once they register:"), render_list gettext("These users will be allowed to enroll once they register:"),
(sr.email for sr in allowed) (sr.email for sr in allowed)
# Student hasn't registered so we allow them to enroll with autoenroll # Student hasn't registered so we allow them to enroll with autoenroll
if autoenrolled.length and emailStudents if autoenrolled.length and emailStudents
`// Translators: A list of users appears after this sentence` `// Translators: A list of users appears after this sentence`
render_list gettext("Successfully sent enrollment emails to the following user(s). They will be enrolled once they register:"), render_list gettext("Successfully sent enrollment emails to the following users. They will be enrolled once they register:"),
(sr.email for sr in autoenrolled) (sr.email for sr in autoenrolled)
# Student hasn't registered so we allow them to enroll with autoenroll # Student hasn't registered so we allow them to enroll with autoenroll
if autoenrolled.length and not emailStudents if autoenrolled.length and not emailStudents
`// Translators: A list of users appears after this sentence` `// Translators: A list of users appears after this sentence`
render_list gettext("These user(s) will be enrolled once they register:"), render_list gettext("These users will be enrolled once they register:"),
(sr.email for sr in autoenrolled) (sr.email for sr in autoenrolled)
if notenrolled.length and emailStudents if notenrolled.length and emailStudents
`// Translators: A list of users appears after this sentence` `// Translators: A list of users appears after this sentence`
render_list gettext("Emails successfully sent. The following user(s) are no longer enrolled in the course:"), render_list gettext("Emails successfully sent. The following users are no longer enrolled in the course:"),
(sr.email for sr in notenrolled) (sr.email for sr in notenrolled)
if notenrolled.length and not emailStudents if notenrolled.length and not emailStudents
`// Translators: A list of users appears after this sentence` `// Translators: A list of users appears after this sentence`
render_list gettext("The following user(s) are no longer enrolled in the course:"), render_list gettext("The following users are no longer enrolled in the course:"),
(sr.email for sr in notenrolled) (sr.email for sr in notenrolled)
if notunenrolled.length if notunenrolled.length
`// Translators: A list of users appears after this sentence` `// Translators: A list of users appears after this sentence`
render_list gettext("These user(s) were not affliliated with the course so could not be unenrolled:"), render_list gettext("These users were not affiliated with the course so could not be unenrolled:"),
(sr.email for sr in notunenrolled) (sr.email for sr in notunenrolled)
# Wrapper for auth list subsection. # Wrapper for auth list subsection.
......
...@@ -30,7 +30,8 @@ ...@@ -30,7 +30,8 @@
<div class="batch-enrollment"> <div class="batch-enrollment">
<h2> ${_("Batch Enrollment")} </h2> <h2> ${_("Batch Enrollment")} </h2>
<p> <p>
<label for="student-emails">${_("Enter email addresses separated by new lines or commas.")} </label> <label for="student-emails">${_("Enter email addresses separated by new lines or commas.")}
${_("You will not get notification for emails that bounce, so please double-check spelling.")} </label>
<textarea rows="6" name="student-emails" placeholder="${_("Email Addresses")}" spellcheck="false"></textarea> <textarea rows="6" name="student-emails" placeholder="${_("Email Addresses")}" spellcheck="false"></textarea>
</p> </p>
......
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