diff --git a/lms/djangoapps/instructor/tests/test_api.py b/lms/djangoapps/instructor/tests/test_api.py index 227d26c15e..25a28cd4b5 100644 --- a/lms/djangoapps/instructor/tests/test_api.py +++ b/lms/djangoapps/instructor/tests/test_api.py @@ -702,9 +702,7 @@ class TestInstructorAPIBulkBetaEnrollment(ModuleStoreTestCase, LoginEnrollmentTe response = self.client.get(url, {'emails': self.beta_tester.email, 'action': action}) self.assertEqual(response.status_code, 400) - def test_add_notenrolled(self): - url = reverse('bulk_beta_modify_access', kwargs={'course_id': self.course.id}) - response = self.client.get(url, {'emails': self.notenrolled_student.email, 'action': 'add', 'email_students': False}) + def add_notenrolled(self, url, response, identifier): self.assertEqual(response.status_code, 200) self.assertTrue(CourseBetaTesterRole(self.course.location).has_user(self.notenrolled_student)) @@ -713,7 +711,7 @@ class TestInstructorAPIBulkBetaEnrollment(ModuleStoreTestCase, LoginEnrollmentTe "action": "add", "results": [ { - "email": self.notenrolled_student.email, + "email": identifier, "error": False, "userDoesNotExist": False } @@ -726,6 +724,16 @@ class TestInstructorAPIBulkBetaEnrollment(ModuleStoreTestCase, LoginEnrollmentTe # Check the outbox self.assertEqual(len(mail.outbox), 0) + def test_add_notenrolled_email(self): + url = reverse('bulk_beta_modify_access', kwargs={'course_id': self.course.id}) + response = self.client.get(url, {'emails': self.notenrolled_student.email, 'action': 'add', 'email_students': False}) + self.add_notenrolled(url, response, self.notenrolled_student.email) + + def test_add_notenrolled_username(self): + url = reverse('bulk_beta_modify_access', kwargs={'course_id': self.course.id}) + response = self.client.get(url, {'emails': self.notenrolled_student.username, 'action': 'add', 'email_students': False}) + self.add_notenrolled(url, response, self.notenrolled_student.username) + def test_add_notenrolled_with_email(self): url = reverse('bulk_beta_modify_access', kwargs={'course_id': self.course.id}) response = self.client.get(url, {'emails': self.notenrolled_student.email, 'action': 'add', 'email_students': True}) diff --git a/lms/djangoapps/instructor/views/api.py b/lms/djangoapps/instructor/views/api.py index 3e8c618194..56761d2c82 100644 --- a/lms/djangoapps/instructor/views/api.py +++ b/lms/djangoapps/instructor/views/api.py @@ -306,7 +306,7 @@ def students_update_enrollment(request, course_id): @require_level('instructor') @common_exceptions_400 @require_query_params( - emails="stringified list of emails", + emails="stringified list of emails or usernames", action="add or remove", ) def bulk_beta_modify_access(request, course_id): @@ -314,7 +314,8 @@ def bulk_beta_modify_access(request, course_id): Enroll or unenroll users in beta testing program. Query parameters: - - emails is string containing a list of emails separated by anything split_input_list can handle. + - emails is string containing a list of emails or usernames separated by + anything split_input_list can handle. - action is one of ['add', 'remove'] """ action = request.GET.get('action') @@ -333,7 +334,7 @@ def bulk_beta_modify_access(request, course_id): try: error = False user_does_not_exist = False - user = User.objects.get(email=email) + user = get_student_from_identifier(email) if action == 'add': allow_access(course, user, rolename) @@ -539,8 +540,9 @@ def get_students_features(request, course_id, csv=False): # pylint: disable=W06 student_data = analytics.basic.enrolled_students_features(course_id, query_features) - # Scrape the query features for i18n - can't translate here because it breaks further queries - # and how the coffeescript works. The actual translation will be done in data_download.coffee + # Provide human-friendly and translatable names for these features. These names + # will be displayed in the table generated in data_download.coffee. It is not (yet) + # used as the header row in the CSV, but could be in the future. query_features_names = { 'username': _('Username'), 'name': _('Name'), @@ -1078,7 +1080,7 @@ def update_forum_role_membership(request, course_id): target_is_instructor = has_access(user, course, 'instructor') # cannot revoke instructor if target_is_instructor and action == 'revoke' and rolename == FORUM_ROLE_ADMINISTRATOR: - return HttpResponseBadRequest("Cannot revoke instructor forum admin privelages.") + return HttpResponseBadRequest("Cannot revoke instructor forum admin privileges.") try: update_forum_role(course_id, user, rolename, action) diff --git a/lms/static/coffee/src/instructor_dashboard/membership.coffee b/lms/static/coffee/src/instructor_dashboard/membership.coffee index 78311441e0..d4708ab661 100644 --- a/lms/static/coffee/src/instructor_dashboard/membership.coffee +++ b/lms/static/coffee/src/instructor_dashboard/membership.coffee @@ -250,8 +250,8 @@ class BetaTesterBulkAddition if no_users.length no_users.push gettext("Users must create and activate their account before they can be promoted to beta tester.") - `// Translators: A list of email addresses appears after this sentence` - render_list gettext("Could not find users associated with the following email addresses:"), (sr.email for sr in no_users) + `// Translators: A list of identifiers (which are email addresses and/or usernames) appears after this sentence` + render_list gettext("Could not find users associated with the following identifiers:"), (sr.email for sr in no_users) # Wrapper for the batch enrollment subsection. # This object handles buttons, success and failure reporting, diff --git a/lms/templates/instructor/instructor_dashboard_2/membership.html b/lms/templates/instructor/instructor_dashboard_2/membership.html index df639a37d6..09b24ffa47 100644 --- a/lms/templates/instructor/instructor_dashboard_2/membership.html +++ b/lms/templates/instructor/instructor_dashboard_2/membership.html @@ -73,11 +73,11 @@
- +