Merge pull request #9335 from mitocw/error_message_student_notfound_ccx_coach_dashboard
Added error message in enrollment tab inside CCX coach dashboard
This commit is contained in:
@@ -79,6 +79,7 @@ def ccx_dummy_request():
|
||||
|
||||
|
||||
@attr('shard_1')
|
||||
@ddt.ddt
|
||||
class TestCoachDashboard(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
|
||||
"""
|
||||
Tests for Custom Courses views.
|
||||
@@ -387,6 +388,35 @@ class TestCoachDashboard(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
|
||||
).exists()
|
||||
)
|
||||
|
||||
@ddt.data("dummy_student_id", "xyz@gmail.com")
|
||||
def test_manage_add_single_invalid_student(self, student_id):
|
||||
"""enroll a single non valid student
|
||||
"""
|
||||
self.make_coach()
|
||||
ccx = self.make_ccx()
|
||||
course_key = CCXLocator.from_course_locator(self.course.id, ccx.id)
|
||||
url = reverse(
|
||||
'ccx_manage_student',
|
||||
kwargs={'course_id': course_key}
|
||||
)
|
||||
redirect_url = reverse(
|
||||
'ccx_coach_dashboard',
|
||||
kwargs={'course_id': course_key}
|
||||
)
|
||||
data = {
|
||||
'student-action': 'add',
|
||||
'student-id': u','.join([student_id, ]), # pylint: disable=no-member
|
||||
}
|
||||
response = self.client.post(url, data=data, follow=True)
|
||||
|
||||
error_message = 'Could not find a user with name or email "{student_id}" '.format(
|
||||
student_id=student_id
|
||||
)
|
||||
self.assertContains(response, error_message, status_code=200)
|
||||
|
||||
# we were redirected to our current location
|
||||
self.assertRedirects(response, redirect_url, status_code=302)
|
||||
|
||||
def test_manage_add_single_student(self):
|
||||
"""enroll a single student who is a member of the class already
|
||||
"""
|
||||
|
||||
@@ -131,7 +131,7 @@ def dashboard(request, course, ccx=None):
|
||||
context['schedule'] = json.dumps(schedule, indent=4)
|
||||
context['save_url'] = reverse(
|
||||
'save_ccx', kwargs={'course_id': ccx_locator})
|
||||
context['ccx_members'] = CourseEnrollment.objects.filter(course_id=ccx_locator)
|
||||
context['ccx_members'] = CourseEnrollment.objects.filter(course_id=ccx_locator, is_active=True)
|
||||
context['gradebook_url'] = reverse(
|
||||
'ccx_gradebook', kwargs={'course_id': ccx_locator})
|
||||
context['grades_csv_url'] = reverse(
|
||||
@@ -440,6 +440,30 @@ def ccx_invite(request, course, ccx=None):
|
||||
return redirect(url)
|
||||
|
||||
|
||||
def validate_student_email(email):
|
||||
"""
|
||||
validate student's email id
|
||||
"""
|
||||
error_message = None
|
||||
try:
|
||||
validate_email(email)
|
||||
except ValidationError:
|
||||
log.info(
|
||||
'Invalid user name or email when trying to enroll student: %s',
|
||||
email
|
||||
)
|
||||
if email:
|
||||
error_message = _(
|
||||
'Could not find a user with name or email "{email}" '
|
||||
).format(email=email)
|
||||
else:
|
||||
error_message = _(
|
||||
'Please enter a valid username or email.'
|
||||
)
|
||||
|
||||
return error_message
|
||||
|
||||
|
||||
@ensure_csrf_cookie
|
||||
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
|
||||
@coach_dashboard
|
||||
@@ -452,29 +476,32 @@ def ccx_student_management(request, course, ccx=None):
|
||||
action = request.POST.get('student-action', None)
|
||||
student_id = request.POST.get('student-id', '')
|
||||
user = email = None
|
||||
error_message = ""
|
||||
course_key = CCXLocator.from_course_locator(course.id, ccx.id)
|
||||
try:
|
||||
user = get_student_from_identifier(student_id)
|
||||
except User.DoesNotExist:
|
||||
email = student_id
|
||||
error_message = validate_student_email(email)
|
||||
if email and not error_message:
|
||||
error_message = _(
|
||||
'Could not find a user with name or email "{email}" '
|
||||
).format(email=email)
|
||||
else:
|
||||
email = user.email
|
||||
error_message = validate_student_email(email)
|
||||
|
||||
course_key = CCXLocator.from_course_locator(course.id, ccx.id)
|
||||
try:
|
||||
validate_email(email)
|
||||
if error_message is None:
|
||||
if action == 'add':
|
||||
# by decree, no emails sent to students added this way
|
||||
# by decree, any students added this way are auto_enrolled
|
||||
enroll_email(course_key, email, auto_enroll=True, email_students=False)
|
||||
elif action == 'revoke':
|
||||
unenroll_email(course_key, email, email_students=False)
|
||||
except ValidationError:
|
||||
log.info('Invalid user name or email when trying to enroll student: %s', email)
|
||||
else:
|
||||
messages.error(request, error_message)
|
||||
|
||||
url = reverse(
|
||||
'ccx_coach_dashboard',
|
||||
kwargs={'course_id': course_key}
|
||||
)
|
||||
url = reverse('ccx_coach_dashboard', kwargs={'course_id': course_key})
|
||||
return redirect(url)
|
||||
|
||||
|
||||
|
||||
@@ -22,27 +22,26 @@ from django.core.urlresolvers import reverse
|
||||
<section class="instructor-dashboard-content-2" id="ccx-coach-dashboard-content">
|
||||
<h1>${_("CCX Coach Dashboard")}</h1>
|
||||
|
||||
% if messages:
|
||||
<ul class="messages">
|
||||
% for message in messages:
|
||||
% if message.tags:
|
||||
<li class="${message.tags}">${message}</li>
|
||||
% else:
|
||||
<li>${message}</li>
|
||||
% endif
|
||||
% endfor
|
||||
</ul>
|
||||
% endif
|
||||
|
||||
%if not ccx:
|
||||
<section>
|
||||
<form action="${create_ccx_url}" method="POST">
|
||||
<input type="hidden" name="csrfmiddlewaretoken" value="${csrf_token}"/>
|
||||
<label class="sr" for="ccx_name">${_('Name your CCX')}</label>
|
||||
<input name="name" id="ccx_name" placeholder="${_('Name your CCX')}"/><br/>
|
||||
<button id="create-ccx">Coach a new Custom Course for EdX</button>
|
||||
</form>
|
||||
</section>
|
||||
% if messages:
|
||||
<ul class="messages">
|
||||
% for message in messages:
|
||||
% if message.tags:
|
||||
<li class="${message.tags}">${message}</li>
|
||||
% else:
|
||||
<li>${message}</li>
|
||||
% endif
|
||||
% endfor
|
||||
</ul>
|
||||
% endif
|
||||
<section>
|
||||
<form action="${create_ccx_url}" method="POST">
|
||||
<input type="hidden" name="csrfmiddlewaretoken" value="${csrf_token}"/>
|
||||
<label class="sr" for="ccx_name">${_('Name your CCX')}</label>
|
||||
<input name="name" id="ccx_name" placeholder="${_('Name your CCX')}"/><br/>
|
||||
<button id="create-ccx">Coach a new Custom Course for EdX</button>
|
||||
</form>
|
||||
</section>
|
||||
%endif
|
||||
|
||||
%if ccx:
|
||||
@@ -151,5 +150,9 @@ from django.core.urlresolvers import reverse
|
||||
|
||||
$(setup_tabs);
|
||||
$(setup_management_form)
|
||||
|
||||
$( document ).ready(function() {
|
||||
if ($('#ccx_std_list_messages').length) {
|
||||
$('#ccx_std_list_messages')[0].focus();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -46,13 +46,21 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="member-lists-management" style="float:left;width:50%" aria-live="polite">
|
||||
<div class="member-lists-management" style="float:left;width:50%">
|
||||
<form method="POST" action="ccx_manage_student">
|
||||
<input type="hidden" name="csrfmiddlewaretoken" value="${ csrf_token }">
|
||||
<div class="auth-list-container active">
|
||||
<div class="member-list-widget">
|
||||
<div class="member-list">
|
||||
<h2> ${_("Student List Management")}</h2>
|
||||
%if messages:
|
||||
<label for="ccx_std_list_messages" class="sr">${_("CCX student list management response message")}</label>
|
||||
<div id="ccx_std_list_messages" tabindex="-1" class="request-response-error">
|
||||
%for message in messages:
|
||||
${message}
|
||||
%endfor
|
||||
</div>
|
||||
%endif
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -66,7 +74,7 @@
|
||||
<tr>
|
||||
<td>${member.user}</td>
|
||||
<td>${member.user.email}</td>
|
||||
<td><div class="revoke"><i class="fa fa-times-circle" aria-hidden="true"></i> Revoke access</div></td>
|
||||
<td><a class="revoke"><i class="fa fa-times-circle" aria-hidden="true"></i> ${_("Revoke access")}</a></td>
|
||||
</tr>
|
||||
%endfor
|
||||
</tbody>
|
||||
|
||||
Reference in New Issue
Block a user