diff --git a/lms/djangoapps/instructor/tests/test_api.py b/lms/djangoapps/instructor/tests/test_api.py index c5b1b21b52..a32217ab30 100644 --- a/lms/djangoapps/instructor/tests/test_api.py +++ b/lms/djangoapps/instructor/tests/test_api.py @@ -512,7 +512,7 @@ class TestInstructorAPILevelsDataDump(ModuleStoreTestCase, LoginEnrollmentTestCa def test_get_student_progress_url(self): """ Test that progress_url is in the successful response. """ url = reverse('get_student_progress_url', kwargs={'course_id': self.course.id}) - url += "?student_email={}".format( + url += "?unique_student_identifier={}".format( quote(self.students[0].email.encode("utf-8")) ) print url @@ -522,6 +522,19 @@ class TestInstructorAPILevelsDataDump(ModuleStoreTestCase, LoginEnrollmentTestCa res_json = json.loads(response.content) self.assertIn('progress_url', res_json) + def test_get_student_progress_url_from_uname(self): + """ Test that progress_url is in the successful response. """ + url = reverse('get_student_progress_url', kwargs={'course_id': self.course.id}) + url += "?unique_student_identifier={}".format( + quote(self.students[0].username.encode("utf-8")) + ) + print url + response = self.client.get(url) + print response + self.assertEqual(response.status_code, 200) + res_json = json.loads(response.content) + self.assertIn('progress_url', res_json) + def test_get_student_progress_url_noparams(self): """ Test that the endpoint 404's without the required query params. """ url = reverse('get_student_progress_url', kwargs={'course_id': self.course.id}) @@ -579,7 +592,7 @@ class TestInstructorAPIRegradeTask(ModuleStoreTestCase, LoginEnrollmentTestCase) url = reverse('reset_student_attempts', kwargs={'course_id': self.course.id}) response = self.client.get(url, { 'problem_to_reset': self.problem_urlname, - 'student_email': self.student.email, + 'unique_student_identifier': self.student.email, }) print response.content self.assertEqual(response.status_code, 200) @@ -608,7 +621,7 @@ class TestInstructorAPIRegradeTask(ModuleStoreTestCase, LoginEnrollmentTestCase) url = reverse('reset_student_attempts', kwargs={'course_id': self.course.id}) response = self.client.get(url, { 'problem_to_reset': 'robot-not-a-real-module', - 'student_email': self.student.email, + 'unique_student_identifier': self.student.email, }) print response.content self.assertEqual(response.status_code, 400) @@ -618,7 +631,7 @@ class TestInstructorAPIRegradeTask(ModuleStoreTestCase, LoginEnrollmentTestCase) url = reverse('reset_student_attempts', kwargs={'course_id': self.course.id}) response = self.client.get(url, { 'problem_to_reset': self.problem_urlname, - 'student_email': self.student.email, + 'unique_student_identifier': self.student.email, 'delete_module': True, }) print response.content @@ -634,11 +647,11 @@ class TestInstructorAPIRegradeTask(ModuleStoreTestCase, LoginEnrollmentTestCase) ) def test_reset_student_attempts_nonsense(self): - """ Test failure with both student_email and all_students. """ + """ Test failure with both unique_student_identifier and all_students. """ url = reverse('reset_student_attempts', kwargs={'course_id': self.course.id}) response = self.client.get(url, { 'problem_to_reset': self.problem_urlname, - 'student_email': self.student.email, + 'unique_student_identifier': self.student.email, 'all_students': True, }) print response.content @@ -650,7 +663,19 @@ class TestInstructorAPIRegradeTask(ModuleStoreTestCase, LoginEnrollmentTestCase) url = reverse('rescore_problem', kwargs={'course_id': self.course.id}) response = self.client.get(url, { 'problem_to_reset': self.problem_urlname, - 'student_email': self.student.email, + 'unique_student_identifier': self.student.email, + }) + print response.content + self.assertEqual(response.status_code, 200) + self.assertTrue(act.called) + + @patch.object(instructor_task.api, 'submit_rescore_problem_for_student') + def test_rescore_problem_single_from_uname(self, act): + """ Test rescoring of a single student. """ + url = reverse('rescore_problem', kwargs={'course_id': self.course.id}) + response = self.client.get(url, { + 'problem_to_reset': self.problem_urlname, + 'unique_student_identifier': self.student.username, }) print response.content self.assertEqual(response.status_code, 200) @@ -747,7 +772,7 @@ class TestInstructorAPITaskLists(ModuleStoreTestCase, LoginEnrollmentTestCase): url = reverse('list_instructor_tasks', kwargs={'course_id': self.course.id}) response = self.client.get(url, { 'problem_urlname': self.problem_urlname, - 'student_email': self.student.email, + 'unique_student_identifier': self.student.email, }) print response.content self.assertEqual(response.status_code, 200) diff --git a/lms/djangoapps/instructor/views/api.py b/lms/djangoapps/instructor/views/api.py index 8a552feb66..e0b047604e 100644 --- a/lms/djangoapps/instructor/views/api.py +++ b/lms/djangoapps/instructor/views/api.py @@ -33,7 +33,7 @@ import instructor_task.api from instructor_task.api_helper import AlreadyRunningError import instructor.enrollment as enrollment from instructor.enrollment import enroll_email, unenroll_email -from instructor.views.tools import strip_if_string +from instructor.views.tools import strip_if_string, get_student_from_identifier import instructor.access as access import analytics.basic import analytics.distributions @@ -456,20 +456,19 @@ def get_distribution(request, course_id): @common_exceptions_400 @require_level('staff') @require_query_params( - student_email="email of student for whom to get progress url" + unique_student_identifier="email or username of student for whom to get progress url" ) def get_student_progress_url(request, course_id): """ Get the progress url of a student. Limited to staff access. - Takes query paremeter student_email and if the student exists + Takes query paremeter unique_student_identifier and if the student exists returns e.g. { 'progress_url': '/../...' } """ - student_email = strip_if_string(request.GET.get('student_email')) - user = User.objects.get(email=student_email) + user = get_student_from_identifier(request.GET.get('unique_student_identifier')) progress_url = reverse('student_progress', kwargs={'course_id': course_id, 'student_id': user.id}) @@ -496,7 +495,7 @@ def reset_student_attempts(request, course_id): Takes some of the following query paremeters - problem_to_reset is a urlname of a problem - - student_email is an email + - unique_student_identifier is an email or username - all_students is a boolean requires instructor access mutually exclusive with delete_module @@ -510,14 +509,17 @@ def reset_student_attempts(request, course_id): ) problem_to_reset = strip_if_string(request.GET.get('problem_to_reset')) - student_email = strip_if_string(request.GET.get('student_email')) + student_identifier = request.GET.get('unique_student_identifier', None) + student = None + if student_identifier is not None: + student = get_student_from_identifier(student_identifier) all_students = request.GET.get('all_students', False) in ['true', 'True', True] delete_module = request.GET.get('delete_module', False) in ['true', 'True', True] # parameter combinations - if all_students and student_email: + if all_students and student: return HttpResponseBadRequest( - "all_students and student_email are mutually exclusive." + "all_students and unique_student_identifier are mutually exclusive." ) if all_students and delete_module: return HttpResponseBadRequest( @@ -534,15 +536,16 @@ def reset_student_attempts(request, course_id): response_payload = {} response_payload['problem_to_reset'] = problem_to_reset - if student_email: + if student: try: - student = User.objects.get(email=student_email) enrollment.reset_student_attempts(course_id, student, module_state_key, delete_module=delete_module) except StudentModule.DoesNotExist: return HttpResponseBadRequest("Module does not exist.") + response_payload['student'] = student_identifier elif all_students: instructor_task.api.submit_reset_problem_attempts_for_all_students(request, course_id, module_state_key) response_payload['task'] = 'created' + response_payload['student'] = 'All Students' else: return HttpResponseBadRequest() @@ -561,21 +564,25 @@ def rescore_problem(request, course_id): Takes either of the following query paremeters - problem_to_reset is a urlname of a problem - - student_email is an email + - unique_student_identifier is an email or username - all_students is a boolean - all_students and student_email cannot both be present. + all_students and unique_student_identifier cannot both be present. """ problem_to_reset = strip_if_string(request.GET.get('problem_to_reset')) - student_email = strip_if_string(request.GET.get('student_email', False)) + student_identifier = request.GET.get('unique_student_identifier', None) + student = None + if student_identifier is not None: + student = get_student_from_identifier(student_identifier) + all_students = request.GET.get('all_students') in ['true', 'True', True] - if not (problem_to_reset and (all_students or student_email)): + if not (problem_to_reset and (all_students or student)): return HttpResponseBadRequest("Missing query parameters.") - if all_students and student_email: + if all_students and student: return HttpResponseBadRequest( - "Cannot rescore with all_students and student_email." + "Cannot rescore with all_students and unique_student_identifier." ) module_state_key = _msk_from_problem_urlname(course_id, problem_to_reset) @@ -583,9 +590,8 @@ def rescore_problem(request, course_id): response_payload = {} response_payload['problem_to_reset'] = problem_to_reset - if student_email: - response_payload['student_email'] = student_email - student = User.objects.get(email=student_email) + if student: + response_payload['student'] = student_identifier instructor_task.api.submit_rescore_problem_for_student(request, course_id, module_state_key, student) response_payload['task'] = 'created' elif all_students: @@ -608,21 +614,22 @@ def list_instructor_tasks(request, course_id): Takes optional query paremeters. - With no arguments, lists running tasks. - `problem_urlname` lists task history for problem - - `problem_urlname` and `student_email` lists task + - `problem_urlname` and `unique_student_identifier` lists task history for problem AND student (intersection) """ problem_urlname = strip_if_string(request.GET.get('problem_urlname', False)) - student_email = strip_if_string(request.GET.get('student_email', False)) + student = request.GET.get('unique_student_identifier', None) + if student is not None: + student = get_student_from_identifier(student) - if student_email and not problem_urlname: + if student and not problem_urlname: return HttpResponseBadRequest( - "student_email must accompany problem_urlname" + "unique_student_identifier must accompany problem_urlname" ) if problem_urlname: module_state_key = _msk_from_problem_urlname(course_id, problem_urlname) - if student_email: - student = User.objects.get(email=student_email) + if student: tasks = instructor_task.api.get_instructor_task_history(course_id, module_state_key, student) else: tasks = instructor_task.api.get_instructor_task_history(course_id, module_state_key) diff --git a/lms/djangoapps/instructor/views/instructor_dashboard.py b/lms/djangoapps/instructor/views/instructor_dashboard.py index 031eac266b..e248d47a59 100644 --- a/lms/djangoapps/instructor/views/instructor_dashboard.py +++ b/lms/djangoapps/instructor/views/instructor_dashboard.py @@ -38,7 +38,7 @@ def instructor_dashboard_2(request, course_id): raise Http404() sections = [ - _section_course_info(course_id), + _section_course_info(course_id, access), _section_membership(course_id, access), _section_student_admin(course_id, access), _section_data_download(course_id), @@ -67,18 +67,21 @@ section_display_name will be used to generate link titles in the nav bar. """ # pylint: disable=W0105 -def _section_course_info(course_id): +def _section_course_info(course_id, access): """ Provide data for the corresponding dashboard section """ course = get_course_by_id(course_id, depth=None) - section_data = {} - section_data['section_key'] = 'course_info' - section_data['section_display_name'] = _('Course Info') - section_data['course_id'] = course_id - section_data['course_display_name'] = course.display_name - section_data['enrollment_count'] = CourseEnrollment.objects.filter(course_id=course_id).count() - section_data['has_started'] = course.has_started() - section_data['has_ended'] = course.has_ended() + section_data = { + 'section_key': 'course_info', + 'section_display_name': _('Course Info'), + 'course_id': course_id, + 'access': access, + 'course_display_name': course.display_name, + 'enrollment_count': CourseEnrollment.objects.filter(course_id=course_id).count(), + 'has_started': course.has_started(), + 'has_ended': course.has_ended(), + 'list_instructor_tasks_url': reverse('list_instructor_tasks', kwargs={'course_id': course_id}), + } try: advance = lambda memo, (letter, score): "{}: {}, ".format(letter, score) + memo diff --git a/lms/djangoapps/instructor/views/tools.py b/lms/djangoapps/instructor/views/tools.py index 11fc135976..cbf6b6468a 100644 --- a/lms/djangoapps/instructor/views/tools.py +++ b/lms/djangoapps/instructor/views/tools.py @@ -1,7 +1,25 @@ """ Tools for the instructor dashboard """ +from django.contrib.auth.models import User + def strip_if_string(value): if isinstance(value, basestring): return value.strip() return value + + +def get_student_from_identifier(unique_student_identifier): + """ + Gets a student object using either an email address or username. + + Returns the student object associated with `unique_student_identifier` + + Raises User.DoesNotExist if no user object can be found. + """ + unique_student_identifier = strip_if_string(unique_student_identifier) + if "@" in unique_student_identifier: + student = User.objects.get(email=unique_student_identifier) + else: + student = User.objects.get(username=unique_student_identifier) + return student diff --git a/lms/static/coffee/src/instructor_dashboard/student_admin.coffee b/lms/static/coffee/src/instructor_dashboard/student_admin.coffee index 7e40eb98d4..3e5c8c27c2 100644 --- a/lms/static/coffee/src/instructor_dashboard/student_admin.coffee +++ b/lms/static/coffee/src/instructor_dashboard/student_admin.coffee @@ -80,12 +80,13 @@ class StudentAdmin # gather buttons # some buttons are optional because they can be flipped by the instructor task feature switch # student-specific - @$field_student_select = find_and_assert @$section, "input[name='student-select']" + @$field_student_select_progress = find_and_assert @$section, "input[name='student-select-progress']" + @$field_student_select_grade = find_and_assert @$section, "input[name='student-select-grade']" @$progress_link = find_and_assert @$section, "a.progress-link" - @$btn_enroll = find_and_assert @$section, "input[name='enroll']" - @$btn_unenroll = find_and_assert @$section, "input[name='unenroll']" @$field_problem_select_single = find_and_assert @$section, "input[name='problem-select-single']" @$btn_reset_attempts_single = find_and_assert @$section, "input[name='reset-attempts-single']" + @$btn_enroll = @$section.find "input[name='enroll']" + @$btn_unenroll = @$section.find "input[name='unenroll']" @$btn_delete_state_single = @$section.find "input[name='delete-state-single']" @$btn_rescore_problem_single = @$section.find "input[name='rescore-problem-single']" @$btn_task_history_single = @$section.find "input[name='task-history-single']" @@ -100,7 +101,8 @@ class StudentAdmin @$table_running_tasks = @$section.find ".running-tasks-table" # response areas - @$request_response_error_single = find_and_assert @$section, ".student-specific-container .request-response-error" + @$request_response_error_progress = find_and_assert @$section, ".student-specific-container .request-response-error" + @$request_response_error_grade = find_and_assert @$section, ".student-grade-container .request-response-error" @$request_response_error_all = @$section.find ".course-specific-container .request-response-error" # start polling for task list @@ -117,21 +119,23 @@ class StudentAdmin # go to student progress page @$progress_link.click (e) => e.preventDefault() - email = @$field_student_select.val() + unique_student_identifier = @$field_student_select_progress.val() + if not unique_student_identifier + return @$request_response_error_progress.text "Please enter a student email address or username." $.ajax dataType: 'json' url: @$progress_link.data 'endpoint' - data: student_email: email + data: unique_student_identifier: unique_student_identifier success: @clear_errors_then (data) -> window.location = data.progress_url - error: std_ajax_err => @$request_response_error_single.text "Error getting student progress url for '#{email}'." + error: std_ajax_err => @$request_response_error_progress.text "Error getting student progress url for '#{unique_student_identifier}'." # enroll student @$btn_enroll.click => send_data = action: 'enroll' - emails: @$field_student_select.val() + emails: @$field_student_select_progress.val() auto_enroll: false $.ajax @@ -139,74 +143,95 @@ class StudentAdmin url: @$btn_enroll.data 'endpoint' data: send_data success: @clear_errors_then -> console.log "student #{send_data.emails} enrolled" - error: std_ajax_err => @$request_response_error_single.text "Error enrolling student '#{send_data.emails}'." + error: std_ajax_err => @$request_response_error_progress.text "Error enrolling student '#{send_data.emails}'." # unenroll student @$btn_unenroll.click => send_data = action: 'unenroll' - emails: @$field_student_select.val() + emails: @$field_student_select_progress.val() $.ajax dataType: 'json' url: @$btn_unenroll.data 'endpoint' data: send_data success: @clear_errors_then -> console.log "student #{send_data.emails} unenrolled" - error: std_ajax_err => @$request_response_error_single.text "Error unenrolling student '#{send_data.emails}'." + error: std_ajax_err => @$request_response_error_progress.text "Error unenrolling student '#{send_data.emails}'." # reset attempts for student on problem @$btn_reset_attempts_single.click => + unique_student_identifier = @$field_student_select_grade.val() + problem_to_reset = @$field_problem_select_single.val() + if not unique_student_identifier + return @$request_response_error_grade.text "Please enter a student email address or username." + if not problem_to_reset + return @$request_response_error_grade.text "Please enter a problem urlname." send_data = - student_email: @$field_student_select.val() - problem_to_reset: @$field_problem_select_single.val() + unique_student_identifier: unique_student_identifier + problem_to_reset: problem_to_reset delete_module: false $.ajax dataType: 'json' url: @$btn_reset_attempts_single.data 'endpoint' data: send_data - success: @clear_errors_then -> console.log 'problem attempts reset' - error: std_ajax_err => @$request_response_error_single.text "Error resetting problem attempts." + success: @clear_errors_then -> alert "Success! Problem attempts reset for problem '#{problem_to_reset}' and student '#{unique_student_identifier}'." + error: std_ajax_err => @$request_response_error_grade.text "Error resetting problem attempts for problem '#{problem_to_reset}' and student '#{unique_student_identifier}'." # delete state for student on problem - @$btn_delete_state_single.click => confirm_then - msg: "Delete student '#{@$field_student_select.val()}'s state on problem '#{@$field_problem_select_single.val()}'?" - ok: => + @$btn_delete_state_single.click => + unique_student_identifier = @$field_student_select_grade.val() + problem_to_reset = @$field_problem_select_single.val() + if not unique_student_identifier + return @$request_response_error_grade.text "Please enter a student email address or username." + if not problem_to_reset + return @$request_response_error_grade.text "Please enter a problem urlname." + + if window.confirm "Delete student '#{unique_student_identifier}'s state on problem '#{problem_to_reset}'?" send_data = - student_email: @$field_student_select.val() - problem_to_reset: @$field_problem_select_single.val() + unique_student_identifier: unique_student_identifier + problem_to_reset: problem_to_reset delete_module: true $.ajax dataType: 'json' url: @$btn_delete_state_single.data 'endpoint' data: send_data - success: @clear_errors_then -> console.log 'module state deleted' - error: std_ajax_err => @$request_response_error_single.text "Error deleting problem state." + success: @clear_errors_then -> alert 'Module state successfully deleted.' + error: std_ajax_err => @$request_response_error_grade.text "Error deleting problem state." + else + @clear_errors() # start task to rescore problem for student @$btn_rescore_problem_single.click => + unique_student_identifier = @$field_student_select_grade.val() + problem_to_reset = @$field_problem_select_single.val() + if not unique_student_identifier + return @$request_response_error_grade.text "Please enter a student email address or username." + if not problem_to_reset + return @$request_response_error_grade.text "Please enter a problem urlname." send_data = - student_email: @$field_student_select.val() - problem_to_reset: @$field_problem_select_single.val() + unique_student_identifier: unique_student_identifier + problem_to_reset: problem_to_reset $.ajax dataType: 'json' url: @$btn_rescore_problem_single.data 'endpoint' data: send_data - success: @clear_errors_then -> console.log 'started rescore problem task' - error: std_ajax_err => @$request_response_error_single.text "Error starting a task to rescore student's problem." + success: @clear_errors_then -> alert "Started rescore problem task for problem '#{problem_to_reset}' and student '#{unique_student_identifier}'. Click the 'Show Background Task History for Student' button to see the status of the task." + error: std_ajax_err => @$request_response_error_grade.text "Error starting a task to rescore problem '#{problem_to_reset}' for student '#{unique_student_identifier}'." # list task history for student+problem @$btn_task_history_single.click => + unique_student_identifier = @$field_student_select_grade.val() + problem_to_reset = @$field_problem_select_single.val() + if not unique_student_identifier + return @$request_response_error_grade.text "Please enter a student email address or username." + if not problem_to_reset + return @$request_response_error_grade.text "Please enter a problem urlname." send_data = - student_email: @$field_student_select.val() - problem_urlname: @$field_problem_select_single.val() - - if not send_data.student_email - return @$request_response_error_single.text "Enter a student email." - if not send_data.problem_urlname - return @$request_response_error_single.text "Enter a problem urlname." + unique_student_identifier: unique_student_identifier + problem_urlname: problem_to_reset $.ajax dataType: 'json' @@ -214,37 +239,45 @@ class StudentAdmin data: send_data success: @clear_errors_then (data) => create_task_list_table @$table_task_history_single, data.tasks - error: std_ajax_err => @$request_response_error_single.text "Error getting task history for student+problem" + error: std_ajax_err => @$request_response_error_grade.text "Error getting task history for student '#{unique_student_identifier}' and problem '#{problem_to_reset}'." # start task to reset attempts on problem for all students - @$btn_reset_attempts_all.click => confirm_then - msg: "Reset attempts for all students on problem '#{@$field_problem_select_all.val()}'?" - ok: => + @$btn_reset_attempts_all.click => + problem_to_reset = @$field_problem_select_all.val() + if not problem_to_reset + return @$request_response_error_all.text "Please enter a problem urlname." + if window.confirm "Reset attempts for all students on problem '#{@$field_problem_select_all.val()}'?" send_data = all_students: true - problem_to_reset: @$field_problem_select_all.val() + problem_to_reset: problem_to_reset $.ajax dataType: 'json' url: @$btn_reset_attempts_all.data 'endpoint' data: send_data - success: @clear_errors_then -> console.log 'started reset attempts task' + success: @clear_errors_then -> alert "Successfully started task to reset attempts for problem '#{problem_to_reset}'. Click the 'Show Background Task History for Problem' button to see the status of the task." error: std_ajax_err => @$request_response_error_all.text "Error starting a task to reset attempts for all students on this problem." + else + @clear_errors() # start task to rescore problem for all students - @$btn_rescore_problem_all.click => confirm_then - msg: "Rescore problem '#{@$field_problem_select_all.val()}' for all students?" - ok: => + @$btn_rescore_problem_all.click => + problem_to_reset = @$field_problem_select_all.val() + if not problem_to_reset + return @$request_response_error_all.text "Please enter a problem urlname." + if window.confirm "Rescore problem '#{@$field_problem_select_all.val()}' for all students?" send_data = all_students: true - problem_to_reset: @$field_problem_select_all.val() + problem_to_reset: problem_to_reset $.ajax dataType: 'json' url: @$btn_rescore_problem_all.data 'endpoint' data: send_data - success: @clear_errors_then -> console.log 'started rescore problem task' + success: @clear_errors_then -> alert "Successfully started task to rescore problem '#{problem_to_reset}' for all students. Click the 'Show Background Task History for Problem' button to see the status of the task." error: std_ajax_err => @$request_response_error_all.text "Error starting a task to rescore this problem for all students." + else + @clear_errors() # list task history for problem @$btn_task_history_all.click => @@ -252,7 +285,7 @@ class StudentAdmin problem_urlname: @$field_problem_select_all.val() if not send_data.problem_urlname - return @$request_response_error_all.text "Enter a problem urlname." + return @$request_response_error_all.text "Please enter a problem urlname." $.ajax dataType: 'json' @@ -272,11 +305,18 @@ class StudentAdmin # wraps a function, but first clear the error displays clear_errors_then: (cb) -> - @$request_response_error_single.empty() + @$request_response_error_progress.empty() + @$request_response_error_grade.empty() @$request_response_error_all.empty() -> cb?.apply this, arguments + + clear_errors: -> + @$request_response_error_progress.empty() + @$request_response_error_grade.empty() + @$request_response_error_all.empty() + # handler for when the section title is clicked. onClickTitle: -> @task_poller?.start() diff --git a/lms/templates/courseware/instructor_dashboard.html b/lms/templates/courseware/instructor_dashboard.html index 7f41c82c9d..7b06d8e309 100644 --- a/lms/templates/courseware/instructor_dashboard.html +++ b/lms/templates/courseware/instructor_dashboard.html @@ -240,7 +240,7 @@ function goto( mode)
%endif -

${_("Student-specific grade inspection and adjustment")}

+

${_("Student-specific grade inspection and adjustment")}

${_("Specify the {platform_name} email address or username of a student here:").format(platform_name=settings.PLATFORM_NAME)} diff --git a/lms/templates/instructor/instructor_dashboard_2/course_info.html b/lms/templates/instructor/instructor_dashboard_2/course_info.html index 9b4114d95c..cb113e1846 100644 --- a/lms/templates/instructor/instructor_dashboard_2/course_info.html +++ b/lms/templates/instructor/instructor_dashboard_2/course_info.html @@ -38,8 +38,21 @@ ## ${ section_data['offline_grades'] } ## +%if settings.MITX_FEATURES.get('ENABLE_INSTRUCTOR_BACKGROUND_TASKS') and section_data['access']['instructor']: +

+
+

${_("Pending Instructor Tasks")}

+

${_("The status for any active tasks appears in a table below.")}

+ +
+
+ +%endif + %if len(section_data['course_errors']):
+
+

${_("Course Warnings")}:

@@ -52,5 +65,10 @@
%endfor
+

+
%endif + + + diff --git a/lms/templates/instructor/instructor_dashboard_2/student_admin.html b/lms/templates/instructor/instructor_dashboard_2/student_admin.html index 6b6da617f6..f3fc7b6054 100644 --- a/lms/templates/instructor/instructor_dashboard_2/student_admin.html +++ b/lms/templates/instructor/instructor_dashboard_2/student_admin.html @@ -2,25 +2,49 @@ <%page args="section_data"/>

-

${_("Student-specific grade adjustment")}

+

${_("Student-specific grade inspection")}

- - +

+ + ${_("Specify the {platform_name} email address or username of a student here:").format(platform_name=settings.PLATFORM_NAME)} + +


+

+ ${_("Click this link to view the student's progress page:")} + ${_("Student Progress Page")} +

+

+ + -

${_('Specify a particular problem in the course here by its url:')}

+
+ + +
+

${_("Student-specific grade adjustment")}

+
+

+ + ${_("Specify the {platform_name} email address or username of a student here:").format(platform_name=settings.PLATFORM_NAME)} + +

+
+ +

${_('Specify a particular problem in the course here by its url:')} +

+

${_('You may use just the "urlname" if a problem, or "modulename/urlname" if not. (For example, if the location is {location1}, then just provide the {urlname1}. If the location is {location2}, then provide {urlname2}.)').format( location1="i4x://university/course/problem/problemname", @@ -29,20 +53,31 @@ urlname2="notaproblem/someothername") }

- - %if section_data['access']['instructor']: -

${_('You may also delete the entire state of a student for the specified module:')}

- - %endif +

+ ${_("Next, select an action to perform for the given user and problem:")} +

+ +

+ + %if settings.MITX_FEATURES.get('ENABLE_INSTRUCTOR_BACKGROUND_TASKS') and section_data['access']['instructor']: %endif +

+ +

+ %if section_data['access']['instructor']: +

${_('You may also delete the entire state of a student for the specified problem:')}

+ + %endif +

+ %if settings.MITX_FEATURES.get('ENABLE_INSTRUCTOR_BACKGROUND_TASKS') and section_data['access']['instructor']:

- ${_("Rescoring runs in the background, and status for active tasks will appear in a table below. " + ${_("Rescoring runs in the background, and status for active tasks will appear in a table on the Course Info tab. " "To see status for all tasks submitted for this problem and student, click on this button:")}

@@ -76,18 +111,11 @@

- ${_("These actions run in the background, and status for active tasks will appear in a table below. " + ${_("These actions run in the background, and status for active tasks will appear in a table on the Course Info tab. " "To see status for all tasks submitted for this problem, click on this button")}:

- - -
-
-

${_("Pending Instructor Tasks")}

-
-
%endif