Commit d7c9491f by Adam Palay Committed by Sarina Canelake

Bulk beta tester add/remove on instructor dashboard

LMS-1287
parent 2d6bfbad
...@@ -283,6 +283,54 @@ def students_update_enrollment(request, course_id): ...@@ -283,6 +283,54 @@ def students_update_enrollment(request, course_id):
@require_level('instructor') @require_level('instructor')
@common_exceptions_400 @common_exceptions_400
@require_query_params( @require_query_params(
emails="stringified list of emails",
action="add or remove",
)
def bulk_modify_access(request, course_id):
action = request.GET.get('action')
emails_raw = request.GET.get('emails')
emails = _split_input_list(emails_raw)
results = []
rolename = 'beta'
course = get_course_by_id(course_id)
for email in emails:
try:
user = User.objects.get(email=email)
if action == 'add':
allow_access(course, user, rolename)
elif action == 'remove':
revoke_access(course, user, rolename)
else:
return HttpResponseBadRequest(strip_tags(
"Unrecognized action '{}'".format(action)
))
results.append({
'email': email,
'error': False,
})
# catch and log any exceptions
# so that one error doesn't cause a 500.
except Exception as exc: # pylint: disable=W0703
log.exception("Error while #{}ing student")
log.exception(exc)
results.append({
'email': email,
'error': True,
})
response_payload = {
'action': action,
'results': results,
}
return JsonResponse(response_payload)
@ensure_csrf_cookie
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
@require_level('instructor')
@common_exceptions_400
@require_query_params(
unique_student_identifier="email or username of user to change access", unique_student_identifier="email or username of user to change access",
rolename="'instructor', 'staff', or 'beta'", rolename="'instructor', 'staff', or 'beta'",
action="'allow' or 'revoke'" action="'allow' or 'revoke'"
......
...@@ -11,6 +11,8 @@ urlpatterns = patterns('', # nopep8 ...@@ -11,6 +11,8 @@ urlpatterns = patterns('', # nopep8
'instructor.views.api.list_course_role_members', name="list_course_role_members"), 'instructor.views.api.list_course_role_members', name="list_course_role_members"),
url(r'^modify_access$', url(r'^modify_access$',
'instructor.views.api.modify_access', name="modify_access"), 'instructor.views.api.modify_access', name="modify_access"),
url(r'^bulk_modify_access$',
'instructor.views.api.bulk_modify_access', name="bulk_modify_access"),
url(r'^get_grading_config$', url(r'^get_grading_config$',
'instructor.views.api.get_grading_config', name="get_grading_config"), 'instructor.views.api.get_grading_config', name="get_grading_config"),
url(r'^get_students_features(?P<csv>/csv)?$', url(r'^get_students_features(?P<csv>/csv)?$',
......
...@@ -146,6 +146,7 @@ def _section_membership(course_id, access): ...@@ -146,6 +146,7 @@ def _section_membership(course_id, access):
'access': access, 'access': access,
'enroll_button_url': reverse('students_update_enrollment', kwargs={'course_id': course_id}), 'enroll_button_url': reverse('students_update_enrollment', kwargs={'course_id': course_id}),
'unenroll_button_url': reverse('students_update_enrollment', kwargs={'course_id': course_id}), 'unenroll_button_url': reverse('students_update_enrollment', kwargs={'course_id': course_id}),
'modify_beta_testers_button_url': reverse('bulk_modify_access', kwargs={'course_id': course_id}),
'list_course_role_members_url': reverse('list_course_role_members', kwargs={'course_id': course_id}), 'list_course_role_members_url': reverse('list_course_role_members', kwargs={'course_id': course_id}),
'modify_access_url': reverse('modify_access', kwargs={'course_id': course_id}), 'modify_access_url': reverse('modify_access', kwargs={'course_id': course_id}),
'list_forum_members_url': reverse('list_forum_members', kwargs={'course_id': course_id}), 'list_forum_members_url': reverse('list_forum_members', kwargs={'course_id': course_id}),
......
...@@ -160,50 +160,90 @@ class AuthListWidget extends MemberListWidget ...@@ -160,50 +160,90 @@ class AuthListWidget extends MemberListWidget
error: std_ajax_err => cb? gettext "Error changing user's permissions." error: std_ajax_err => cb? gettext "Error changing user's permissions."
# Wrapper for the batch enrollment subsection. class BetaTesterBulkAddition
# This object handles buttons, success and failure reporting,
# and server communication.
class BatchEnrollment
constructor: (@$container) -> constructor: (@$container) ->
# gather elements # gather elements
@$emails_input = @$container.find("textarea[name='student-emails']'") @$emails_input = @$container.find("textarea[name='student-emails-for-beta']")
@$btn_enroll = @$container.find("input[name='enroll']'") @$btn_beta_testers = @$container.find("input[name='beta-testers']")
@$btn_unenroll = @$container.find("input[name='unenroll']'") # @$checkbox_emailstudents = @$container.find("input[name='email-students']")
@$checkbox_autoenroll = @$container.find("input[name='auto-enroll']'")
@$checkbox_emailstudents = @$container.find("input[name='email-students']'")
@$task_response = @$container.find(".request-response") @$task_response = @$container.find(".request-response")
@$request_response_error = @$container.find(".request-response-error") @$request_response_error = @$container.find(".request-response-error")
# attach click handlers # click handlers
@$btn_beta_testers.click =>
@$btn_enroll.click => # emailStudents = @$checkbox_emailstudents.is(':checked')
emailStudents = @$checkbox_emailstudents.is(':checked') send_data =
action: $(event.target).data('action')
send_data =
action: 'enroll'
emails: @$emails_input.val() emails: @$emails_input.val()
auto_enroll: @$checkbox_autoenroll.is(':checked')
email_students: emailStudents email_students: emailStudents
$.ajax $.ajax
dataType: 'json' dataType: 'json'
url: @$btn_enroll.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 "Error enrolling/unenrolling students." # error: std_ajax_err => @fail_with_error "Error enrolling/unenrolling students."
# success: (data) => @display_response data
# fail_with_error: (msg) ->
# console.warn msg
# @$task_response.empty()
# @$request_response_error.empty()
# @$request_response_error.text msg
@$btn_unenroll.click => display_response: (data_from_server) ->
emailStudents = @$checkbox_emailstudents.is(':checked') @$task_response.empty()
# @$request_response_error.empty()
errors = []
sucesses = []
for student_results in data_from_server.results
if student_results.error
errors.push student_results
else
sucesses.push student_results
console.log(sr.email for sr in sucesses)
render_list = (label, emails) =>
task_res_section = $ '<div/>', class: 'request-res-section'
task_res_section.append $ '<h3/>', text: label
email_list = $ '<ul/>'
task_res_section.append email_list
for email in emails
email_list.append $ '<li/>', text: email
@$task_response.append task_res_section
render_list gettext("these students were added as beta testers"), (sr.email for sr in sucesses)
render_list gettext("these students were not added as beta testers"), (sr.email for sr in errors)
# Wrapper for the batch enrollment subsection.
# This object handles buttons, success and failure reporting,
# and server communication.
class BatchEnrollment
constructor: (@$container) ->
# gather elements
@$emails_input = @$container.find("textarea[name='student-emails']")
@$enrollment_button = @$container.find(".enrollment-button")
@$checkbox_autoenroll = @$container.find("input[name='auto-enroll']")
@$checkbox_emailstudents = @$container.find("input[name='email-students']")
@$task_response = @$container.find(".request-response")
@$request_response_error = @$container.find(".request-response-error")
# attach click handler for enrollment buttons
@$enrollment_button.click =>
emailStudents: @$checkbox_emailstudents.is(':checked')
send_data = send_data =
action: 'unenroll' action: $(event.target).data('action') # 'enroll' or 'unenroll'
emails: @$emails_input.val() emails: @$emails_input.val()
auto_enroll: @$checkbox_autoenroll.is(':checked') auto_enroll: @$checkbox_autoenroll.is(':checked')
email_students: emailStudents email_students: emailStudents
$.ajax $.ajax
dataType: 'json' dataType: 'json'
url: @$btn_unenroll.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 students." error: std_ajax_err => @fail_with_error gettext "Error enrolling/unenrolling students."
...@@ -475,6 +515,9 @@ class Membership ...@@ -475,6 +515,9 @@ class Membership
# isolate # initialize BatchEnrollment subsection # isolate # initialize BatchEnrollment subsection
plantTimeout 0, => new BatchEnrollment @$section.find '.batch-enrollment' plantTimeout 0, => new BatchEnrollment @$section.find '.batch-enrollment'
# initialize BetaTesterBulkAddition subsection
plantTimeout 0, => new BetaTesterBulkAddition @$section.find '.batch-beta-testers'
# gather elements # gather elements
@$list_selector = @$section.find 'select#member-lists-selector' @$list_selector = @$section.find 'select#member-lists-selector'
......
...@@ -292,7 +292,7 @@ section.instructor-dashboard-content-2 { ...@@ -292,7 +292,7 @@ section.instructor-dashboard-content-2 {
margin-right: 0; margin-right: 0;
} }
.batch-enrollment { .batch-enrollment, .batch-beta-testers {
textarea { textarea {
margin-top: 0.2em; margin-top: 0.2em;
height: auto; height: auto;
......
...@@ -26,7 +26,8 @@ ...@@ -26,7 +26,8 @@
</div> </div>
</script> </script>
<div class="vert-left batch-enrollment"> <div class="vert-left">
<div class="batch-enrollment">
<h2> ${_("Batch Enrollment")} </h2> <h2> ${_("Batch Enrollment")} </h2>
<p> <p>
<label for="student-emails">${_("Enter student emails separated by new lines or commas.")} </label> <label for="student-emails">${_("Enter student emails separated by new lines or commas.")} </label>
...@@ -51,15 +52,41 @@ ...@@ -51,15 +52,41 @@
<p> ${_("If email students is <em>checked</em> students will receive an email notification.")}</p> <p> ${_("If email students is <em>checked</em> students will receive an email notification.")}</p>
</div> </div>
</div> </div>
<div>
<input type="button" name="enrollment-button" class="enrollment-button" value="${_("Enroll")}" data-endpoint="${ section_data['enroll_button_url'] }" data-action="enroll" >
<input type="button" name="enrollment-button" class="enrollment-button" value="${_("Unenroll")}" data-endpoint="${ section_data['unenroll_button_url'] }" data-action="unenroll" >
</div>
<div class="request-response"></div>
<div class="request-response-error"></div>
</div>
<div class="enroll-actions actions"> %if section_data['access']['instructor']:
<input type="button" name="enroll" value="${_("Enroll")}" data-endpoint="${ section_data['enroll_button_url'] }" > <div class="batch-beta-testers">
<input type="button" name="unenroll" value="${_("Unenroll")}" data-endpoint="${ section_data['unenroll_button_url'] }" > <h2> ${_("Add Beta Testers")} </h2>
<p> ${_("Enter student emails separated by new lines or commas.")} </p>
<textarea rows="6" cols="50" name="student-emails-for-beta" placeholder="${_("Student Emails")}" spellcheck="false"></textarea>
<br>
<div>
<input type="checkbox" name="email-students" value="Notify-students-by-email">
<label for="email-students">${_("Notify students by email")}</label>
<div class="email-students-hint">
<p> ${_("If email students is <em>checked</em> students will receive an email notification.")}
</p>
</div>
</div>
<div>
<input type="button" name="beta-testers" class="" value="${_("Add students as beta testers")}" data-endpoint="${ section_data['modify_beta_testers_button_url'] }" data-action="add" >
<input type="button" name="beta-testers" class="" value="${_("Remove students as beta testers")}" data-endpoint="${ section_data['modify_beta_testers_button_url'] }" data-action="remove" >
</div> </div>
<div class="request-response"></div> <div class="request-response"></div>
<div class="request-response-error"></div> <div class="request-response-error"></div>
</div> </div>
%endif
</div>
<div class="vert-right member-lists-management"> <div class="vert-right member-lists-management">
<h2> ${_("Administration List Management")} </h2> <h2> ${_("Administration List Management")} </h2>
......
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