Skip to content

Commit ced9784

Browse files
tomaszgypomegranited
authored andcommitted
Simplify the content enrollment tab in the CCX Dashboard.
Signed-off-by: Tomasz Gargas <[email protected]>
1 parent d8fe63c commit ced9784

File tree

6 files changed

+39
-198
lines changed

6 files changed

+39
-198
lines changed

lms/djangoapps/ccx/tests/test_views.py

Lines changed: 15 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -592,10 +592,8 @@ def test_save_without_min_count(self):
592592
self.assertEqual(response.status_code, 200)
593593

594594
@ddt.data(
595-
('ccx_invite', True, 1, 'student-ids', ('enrollment-button', 'Enroll')),
596-
('ccx_invite', False, 0, 'student-ids', ('enrollment-button', 'Enroll')),
597-
('ccx_manage_student', True, 1, 'student-id', ('student-action', 'add')),
598-
('ccx_manage_student', False, 0, 'student-id', ('student-action', 'add')),
595+
('ccx-manage-students', True, 1, 'student-ids', ('enrollment-button', 'Enroll')),
596+
('ccx-manage-students', False, 0, 'student-ids', ('enrollment-button', 'Enroll')),
599597
)
600598
@ddt.unpack
601599
def test_enroll_member_student(self, view_name, send_email, outbox_count, student_form_input_name, button_tuple):
@@ -656,7 +654,7 @@ def test_ccx_invite_enroll_up_to_limit(self):
656654
]
657655

658656
url = reverse(
659-
'ccx_invite',
657+
'ccx-manage-students',
660658
kwargs={'course_id': ccx_course_key}
661659
)
662660
data = {
@@ -687,81 +685,11 @@ def test_ccx_invite_enroll_up_to_limit(self):
687685
CourseEnrollment.objects.filter(course_id=ccx_course_key, user=students[5]).exists()
688686
)
689687

690-
def test_manage_student_enrollment_limit(self):
691-
"""
692-
Enroll students up to the enrollment limit.
693-
694-
This test is specific to one of the enrollment views: the reason is because
695-
the view used in this test cannot perform bulk enrollments.
696-
"""
697-
students_limit = 1
698-
self.make_coach()
699-
staff = self.make_staff()
700-
ccx = self.make_ccx(max_students_allowed=students_limit)
701-
ccx_course_key = CCXLocator.from_course_locator(self.course.id, ccx.id)
702-
students = [
703-
UserFactory.create(is_staff=False) for _ in range(2)
704-
]
705-
706-
url = reverse(
707-
'ccx_manage_student',
708-
kwargs={'course_id': CCXLocator.from_course_locator(self.course.id, ccx.id)}
709-
)
710-
# enroll the first student
711-
data = {
712-
'student-action': 'add',
713-
'student-id': students[0].email,
714-
}
715-
response = self.client.post(url, data=data, follow=True)
716-
self.assertEqual(response.status_code, 200)
717-
# a CcxMembership exists for this student
718-
self.assertTrue(
719-
CourseEnrollment.objects.filter(course_id=ccx_course_key, user=students[0]).exists()
720-
)
721-
722-
# try to enroll the second student without success
723-
# enroll the first student
724-
data = {
725-
'student-action': 'add',
726-
'student-id': students[1].email,
727-
}
728-
response = self.client.post(url, data=data, follow=True)
729-
self.assertEqual(response.status_code, 200)
730-
# a CcxMembership does not exist for this student
731-
self.assertFalse(
732-
CourseEnrollment.objects.filter(course_id=ccx_course_key, user=students[1]).exists()
733-
)
734-
error_message = 'The course is full: the limit is {students_limit}'.format(
735-
students_limit=students_limit
736-
)
737-
self.assertContains(response, error_message, status_code=200)
738-
739-
# try to enroll the 3rd student which is staff
740-
data = {
741-
'student-action': 'add',
742-
'student-id': staff.email,
743-
}
744-
response = self.client.post(url, data=data, follow=True)
745-
self.assertEqual(response.status_code, 200)
746-
# staff gets enroll
747-
self.assertTrue(
748-
CourseEnrollment.objects.filter(course_id=ccx_course_key, user=staff).exists()
749-
)
750-
751-
self.assertEqual(CourseEnrollment.objects.num_enrolled_in_exclude_admins(ccx_course_key), 1)
752-
753-
# asert that number of enroll is still 0 because staff and instructor do not count.
754-
CourseEnrollment.enroll(staff, self.course.id)
755-
self.assertEqual(CourseEnrollment.objects.num_enrolled_in_exclude_admins(self.course.id), 0)
756-
# assert that handles wrong ccx id code
757-
ccx_course_key_fake = CCXLocator.from_course_locator(self.course.id, 55)
758-
self.assertEqual(CourseEnrollment.objects.num_enrolled_in_exclude_admins(ccx_course_key_fake), 0)
759-
760688
@ddt.data(
761-
('ccx_invite', True, 1, 'student-ids', ('enrollment-button', 'Unenroll')),
762-
('ccx_invite', False, 0, 'student-ids', ('enrollment-button', 'Unenroll')),
763-
('ccx_manage_student', True, 1, 'student-id', ('student-action', 'revoke')),
764-
('ccx_manage_student', False, 0, 'student-id', ('student-action', 'revoke')),
689+
('ccx-manage-students', True, 1, 'student-ids', ('enrollment-button', 'Unenroll')),
690+
('ccx-manage-students', False, 0, 'student-ids', ('enrollment-button', 'Unenroll')),
691+
('ccx-manage-students', True, 1, 'student-id', ('student-action', 'revoke')),
692+
('ccx-manage-students', False, 0, 'student-id', ('student-action', 'revoke')),
765693
)
766694
@ddt.unpack
767695
def test_unenroll_member_student(self, view_name, send_email, outbox_count, student_form_input_name, button_tuple):
@@ -803,14 +731,10 @@ def test_unenroll_member_student(self, view_name, send_email, outbox_count, stud
803731
)
804732

805733
@ddt.data(
806-
('ccx_invite', True, 1, 'student-ids', ('enrollment-button', 'Enroll'), '[email protected]'),
807-
('ccx_invite', False, 0, 'student-ids', ('enrollment-button', 'Enroll'), '[email protected]'),
808-
('ccx_invite', True, 0, 'student-ids', ('enrollment-button', 'Enroll'), 'nobody'),
809-
('ccx_invite', False, 0, 'student-ids', ('enrollment-button', 'Enroll'), 'nobody'),
810-
('ccx_manage_student', True, 0, 'student-id', ('student-action', 'add'), 'dummy_student_id'),
811-
('ccx_manage_student', False, 0, 'student-id', ('student-action', 'add'), 'dummy_student_id'),
812-
('ccx_manage_student', True, 1, 'student-id', ('student-action', 'add'), '[email protected]'),
813-
('ccx_manage_student', False, 0, 'student-id', ('student-action', 'add'), '[email protected]'),
734+
('ccx-manage-students', True, 1, 'student-ids', ('enrollment-button', 'Enroll'), '[email protected]'),
735+
('ccx-manage-students', False, 0, 'student-ids', ('enrollment-button', 'Enroll'), '[email protected]'),
736+
('ccx-manage-students', True, 0, 'student-ids', ('enrollment-button', 'Enroll'), 'nobody'),
737+
('ccx-manage-students', False, 0, 'student-ids', ('enrollment-button', 'Enroll'), 'nobody'),
814738
)
815739
@ddt.unpack
816740
def test_enroll_non_user_student(
@@ -860,10 +784,10 @@ def test_enroll_non_user_student(
860784
)
861785

862786
@ddt.data(
863-
('ccx_invite', True, 0, 'student-ids', ('enrollment-button', 'Unenroll'), '[email protected]'),
864-
('ccx_invite', False, 0, 'student-ids', ('enrollment-button', 'Unenroll'), '[email protected]'),
865-
('ccx_invite', True, 0, 'student-ids', ('enrollment-button', 'Unenroll'), 'nobody'),
866-
('ccx_invite', False, 0, 'student-ids', ('enrollment-button', 'Unenroll'), 'nobody'),
787+
('ccx-manage-students', True, 0, 'student-ids', ('enrollment-button', 'Unenroll'), '[email protected]'),
788+
('ccx-manage-students', False, 0, 'student-ids', ('enrollment-button', 'Unenroll'), '[email protected]'),
789+
('ccx-manage-students', True, 0, 'student-ids', ('enrollment-button', 'Unenroll'), 'nobody'),
790+
('ccx-manage-students', False, 0, 'student-ids', ('enrollment-button', 'Unenroll'), 'nobody'),
867791
)
868792
@ddt.unpack
869793
def test_unenroll_non_user_student(

lms/djangoapps/ccx/urls.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,10 @@
1111
'ccx.views.create_ccx', name='create_ccx'),
1212
url(r'^save_ccx$',
1313
'ccx.views.save_ccx', name='save_ccx'),
14-
url(r'^ccx_invite$',
15-
'ccx.views.ccx_invite', name='ccx_invite'),
1614
url(r'^ccx_schedule$',
1715
'ccx.views.ccx_schedule', name='ccx_schedule'),
18-
url(r'^ccx_manage_student$',
19-
'ccx.views.ccx_student_management', name='ccx_manage_student'),
16+
url(r'^ccx-manage-students$',
17+
'ccx.views.ccx_students_management', name='ccx-manage-students'),
2018

2119
# Grade book
2220
url(r'^ccx_gradebook$',

lms/djangoapps/ccx/utils.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -208,16 +208,10 @@ def get_valid_student_with_email(identifier):
208208

209209
def ccx_students_enrolling_center(action, identifiers, email_students, course_key, email_params, coach):
210210
"""
211-
Function to enroll/add or unenroll/revoke students.
212-
213-
This function exists for backwards compatibility: in CCX there are
214-
two different views to manage students that used to implement
215-
a different logic. Now the logic has been reconciled at the point that
216-
this function can be used by both.
217-
The two different views can be merged after some UI refactoring.
211+
Function to enroll or unenroll/revoke students.
218212
219213
Arguments:
220-
action (str): type of action to perform (add, Enroll, revoke, Unenroll)
214+
action (str): type of action to perform (Enroll, Unenroll/revoke)
221215
identifiers (list): list of students username/email
222216
email_students (bool): Flag to send an email to students
223217
course_key (CCXLocator): a CCX course key
@@ -229,7 +223,7 @@ def ccx_students_enrolling_center(action, identifiers, email_students, course_ke
229223
"""
230224
errors = []
231225

232-
if action == 'Enroll' or action == 'add':
226+
if action == 'Enroll':
233227
ccx_course_overview = CourseOverview.get_from_id(course_key)
234228
course_locator = course_key.to_course_locator()
235229
staff = CourseStaffRole(course_locator).users_with_role()

lms/djangoapps/ccx/views.py

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -460,40 +460,26 @@ def ccx_schedule(request, course, ccx=None): # pylint: disable=unused-argument
460460
@ensure_csrf_cookie
461461
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
462462
@coach_dashboard
463-
def ccx_invite(request, course, ccx=None):
463+
def ccx_students_management(request, course, ccx=None):
464464
"""
465-
Invite users to new ccx
465+
Manage the enrollment of the students in a CCX
466466
"""
467467
if not ccx:
468468
raise Http404
469469

470-
action = request.POST.get('enrollment-button')
471-
identifiers_raw = request.POST.get('student-ids')
472-
identifiers = _split_input_list(identifiers_raw)
473-
email_students = 'email-students' in request.POST
474-
course_key = CCXLocator.from_course_locator(course.id, unicode(ccx.id))
475-
email_params = get_email_params(course, auto_enroll=True, course_key=course_key, display_name=ccx.display_name)
476-
477-
ccx_students_enrolling_center(action, identifiers, email_students, course_key, email_params, ccx.coach)
478-
479-
url = reverse('ccx_coach_dashboard', kwargs={'course_id': course_key})
480-
return redirect(url)
481-
470+
list_action = request.POST.get('student-action', None)
471+
batch_action = request.POST.get('enrollment-button', None)
482472

483-
@ensure_csrf_cookie
484-
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
485-
@coach_dashboard
486-
def ccx_student_management(request, course, ccx=None):
487-
"""
488-
Manage the enrollment of individual students in a CCX
489-
"""
490-
if not ccx:
491-
raise Http404
473+
if list_action:
474+
action = list_action
475+
student_id = request.POST.get('student-id', '')
476+
identifiers = [student_id]
477+
elif batch_action:
478+
action = batch_action
479+
identifiers_raw = request.POST.get('student-ids')
480+
identifiers = _split_input_list(identifiers_raw)
492481

493-
action = request.POST.get('student-action', None)
494-
student_id = request.POST.get('student-id', '')
495482
email_students = 'email-students' in request.POST
496-
identifiers = [student_id]
497483
course_key = CCXLocator.from_course_locator(course.id, unicode(ccx.id))
498484
email_params = get_email_params(course, auto_enroll=True, course_key=course_key, display_name=ccx.display_name)
499485

lms/templates/ccx/coach_dashboard.html

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -112,34 +112,12 @@ <h2 class="hd hd-2" id="header-ccx-dashboard">${_("CCX Coach Dashboard")}</h2>
112112

113113
function setup_management_form() {
114114

115-
$(".member-lists-management form").on("submit", function (event) {
116-
var target, action;
117-
target = $(event.target);
118-
if (target.serialize().indexOf('student-action') < 0) {
119-
action = $('<input />', {
120-
type: 'hidden',
121-
name: 'student-action',
122-
value: 'add'
123-
});
124-
target.append(action);
125-
}
126-
});
127-
128-
$(".member-lists-management form .add, .member-lists-management form .revoke").on("click", function(event) {
115+
$(".member-lists-management form .revoke").on("click", function(event) {
129116
var target, form, action, studentId, selectedStudent;
130117
event.preventDefault();
131118
target = $(event.target);
132119
form = target.parents('form').first();
133-
if (target.hasClass('add')) {
134-
// adding a new student, add the student-action input and submit
135-
action = $('<input />', {
136-
type: 'hidden',
137-
name: 'student-action',
138-
// this is untenable, tied to a translated value. Fix it.
139-
value: 'add'
140-
});
141-
form.append(action).submit();
142-
} else if (target.hasClass('revoke')) {
120+
if (target.hasClass('revoke')) {
143121
// revoking access for a student, get set form values and submit
144122
// get the email address of the student, since they might not be 'enrolled' yet.
145123
selectedStudent = target.parent('td').siblings().last().text();

lms/templates/ccx/enrollment.html

Lines changed: 5 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
%>
66

77
<h2 class="hd hd-2">${_("Batch Enrollment")}</h2>
8-
<div class="batch-enrollment" style="float:left;width:50%">
9-
<form method="POST" action="ccx_invite">
8+
<div class="batch-enrollment" style="float:left;width:100%">
9+
<form method="POST" action="ccx-manage-students">
1010
<input type="hidden" name="csrfmiddlewaretoken" value="${ csrf_token }">
1111
<label for="student-ids" class="sr">${_("Email Addresses/Usernames")}</label>
1212
<p id="label_student_ids" class="text-helper">
1313
${_("Enter email addresses and/or usernames separated by new lines or commas.")}
1414
${_("You will not get notification for emails that bounce, so please double-check spelling.")}
1515
</p>
16-
<textarea rows="6" name="student-ids" id="student-ids" aria-describedby="label_student_ids" placeholder="${_("Email Addresses/Usernames")}" spellcheck="false"></textarea>
16+
<textarea rows="6" name="student-ids" id="student-ids" aria-describedby="label_student_ids" placeholder="${_("Email Addresses/Usernames")}" spellcheck="false" style="width:100%;"></textarea>
1717

1818

1919
<div class="enroll-option">
@@ -61,8 +61,8 @@ <h2 class="hd hd-2">${_("Batch Enrollment")}</h2>
6161
</form>
6262
</div>
6363

64-
<div class="member-lists-management" style="float:left;width:50%">
65-
<form method="POST" action="ccx_manage_student" class="ccx-manage-student-form">
64+
<div class="member-lists-management" style="float:left;width:100%">
65+
<form method="POST" action="ccx-manage-students" class="ccx-manage-student-form">
6666
<input type="hidden" name="csrfmiddlewaretoken" value="${ csrf_token }">
6767
<div class="auth-list-container active">
6868
<div class="member-list-widget">
@@ -95,45 +95,6 @@ <h2 class="hd hd-2">${_("Student List Management")}</h2>
9595
</tbody>
9696
</table>
9797
</div>
98-
<div class="bottom-bar">
99-
<label for="student-id" class="sr">${_("Enter username or email")}</label>
100-
<input name="student-id" id="student-id" class="add-field" placeholder="${_("Enter username or email")}" type="text">
101-
<input name="student-action" class="add" value="${_("Add Student")}" type="button">
102-
<div class="enroll-option">
103-
<input type="checkbox" name="auto-enroll" id="auto-enroll" value="Auto-Enroll" checked="yes" aria-describedby="auto-enroll-helper" disabled>
104-
<label style="display:inline" for="auto-enroll">${_("Auto Enroll")}</label>
105-
<div class="hint auto-enroll-hint">
106-
<span class="hint-caret"></span>
107-
<p class="text-helper" id="auto-enroll-helper">
108-
${Text(_("If this option is {em_start}checked{em_end}, users who have not yet registered for {platform_name} will be automatically enrolled.")).format(
109-
em_start=HTML('<em>'),
110-
em_end=HTML('</em>'),
111-
platform_name=settings.PLATFORM_NAME,
112-
)}
113-
${Text(_("If this option is left {em_start}unchecked{em_end}, users who have not yet registered for {platform_name} will not be enrolled, but will be allowed to enroll once they make an account.")).format(
114-
em_start=HTML('<em>'),
115-
em_end=HTML('</em>'),
116-
platform_name=settings.PLATFORM_NAME,
117-
)}
118-
<br /><br />
119-
${_("Checking this box has no effect if 'Revoke' is clicked.")}
120-
</p>
121-
</div>
122-
</div>
123-
<div class="enroll-option ccx-notify-user">
124-
<input type="checkbox" name="email-students" id="email-students" value="Notify-students-by-email" checked="yes" aria-describedby="email-students-helper">
125-
<label style="display:inline" for="email-students">${_("Notify users by email")}</label>
126-
<div class="hint email-students-hint">
127-
<span class="hint-caret"></span>
128-
<p class="text-helper" id="email-students-helper">
129-
${Text(_("If this option is {em_start}checked{em_end}, users will receive an email notification.")).format(
130-
em_start=HTML('<em>'),
131-
em_end=HTML('</em>'),
132-
)}
133-
</p>
134-
</div>
135-
</div>
136-
</div>
13798
</div>
13899
</div>
139100
</form>

0 commit comments

Comments
 (0)