diff --git a/lms/djangoapps/instructor/views/api.py b/lms/djangoapps/instructor/views/api.py index f3f4d8ea55..533c5c5c51 100644 --- a/lms/djangoapps/instructor/views/api.py +++ b/lms/djangoapps/instructor/views/api.py @@ -1457,20 +1457,9 @@ def get_proctored_exam_results(request, course_id): """ get the proctored exam resultsreport for the particular course. """ - query_features = [ - 'user_email', - 'exam_name', - 'attempt_code', - 'allowed_time_limit_mins', - 'is_sample_attempt', - 'started_at', - 'completed_at', - 'status', - ] - course_key = CourseKey.from_string(course_id) report_type = _('proctored exam results') - lms.djangoapps.instructor_task.api.submit_proctored_exam_results_report(request, course_key, query_features) + lms.djangoapps.instructor_task.api.submit_proctored_exam_results_report(request, course_key) success_status = SUCCESS_MESSAGE_TEMPLATE.format(report_type=report_type) return JsonResponse({"status": success_status}) diff --git a/lms/djangoapps/instructor_analytics/basic.py b/lms/djangoapps/instructor_analytics/basic.py index 4622b55589..7123fc46a1 100644 --- a/lms/djangoapps/instructor_analytics/basic.py +++ b/lms/djangoapps/instructor_analytics/basic.py @@ -12,7 +12,7 @@ from django.core.exceptions import ObjectDoesNotExist from django.core.serializers.json import DjangoJSONEncoder from django.core.urlresolvers import reverse from django.db.models import Count, Q -from edx_proctoring.api import get_all_exam_attempts +from edx_proctoring.api import get_exam_violation_report from opaque_keys.edx.keys import UsageKey import xmodule.graders as xmgraders @@ -326,20 +326,30 @@ def get_proctored_exam_results(course_key, features): """ Return info about proctored exam results in a course as a dict. """ - def extract_student(exam_attempt, features): + comment_statuses = ['Rules Violation', 'Suspicious'] + + def extract_details(exam_attempt, features): """ Build dict containing information about a single student exam_attempt. """ proctored_exam = dict( (feature, exam_attempt.get(feature)) for feature in features if feature in exam_attempt ) - proctored_exam.update({'exam_name': exam_attempt.get('proctored_exam').get('exam_name')}) - proctored_exam.update({'user_email': exam_attempt.get('user').get('email')}) + + for status in comment_statuses: + comment_list = exam_attempt.get( + '{status} Comments'.format(status=status), + [] + ) + proctored_exam.update({ + '{status} Count'.format(status=status): len(comment_list), + '{status} Comments'.format(status=status): '; '.join(comment_list), + }) return proctored_exam - exam_attempts = get_all_exam_attempts(course_key) - return [extract_student(exam_attempt, features) for exam_attempt in exam_attempts] + exam_attempts = get_exam_violation_report(course_key) + return [extract_details(exam_attempt, features) for exam_attempt in exam_attempts] def coupon_codes_features(features, coupons_list, course_id): diff --git a/lms/djangoapps/instructor_analytics/tests/test_basic.py b/lms/djangoapps/instructor_analytics/tests/test_basic.py index ceb738800c..bb6c2b83fb 100644 --- a/lms/djangoapps/instructor_analytics/tests/test_basic.py +++ b/lms/djangoapps/instructor_analytics/tests/test_basic.py @@ -238,13 +238,17 @@ class TestAnalyticsBasic(ModuleStoreTestCase): def test_get_student_exam_attempt_features(self): query_features = [ - 'user_email', + 'email', 'exam_name', 'allowed_time_limit_mins', 'is_sample_attempt', 'started_at', 'completed_at', 'status', + 'Suspicious Count', + 'Suspicious Comments', + 'Rules Violation Count', + 'Rules Violation Comments', ] proctored_exam_id = create_exam(self.course_key, 'Test Content', 'Test Exam', 1) diff --git a/lms/djangoapps/instructor_task/api.py b/lms/djangoapps/instructor_task/api.py index 39c5a848b8..da7ac434ed 100644 --- a/lms/djangoapps/instructor_task/api.py +++ b/lms/djangoapps/instructor_task/api.py @@ -431,7 +431,7 @@ def submit_course_survey_report(request, course_key): return submit_task(request, task_type, task_class, course_key, task_input, task_key) -def submit_proctored_exam_results_report(request, course_key, features): # pylint: disable=invalid-name +def submit_proctored_exam_results_report(request, course_key): # pylint: disable=invalid-name """ Submits a task to generate a HTML File containing the executive summary report. @@ -439,7 +439,7 @@ def submit_proctored_exam_results_report(request, course_key, features): # pyli """ task_type = 'proctored_exam_results_report' task_class = proctored_exam_results_csv - task_input = {'features': features} + task_input = {} task_key = "" return submit_task(request, task_type, task_class, course_key, task_input, task_key) diff --git a/lms/djangoapps/instructor_task/tasks_helper/misc.py b/lms/djangoapps/instructor_task/tasks_helper/misc.py index 77d769fed9..be277fbdc0 100644 --- a/lms/djangoapps/instructor_task/tasks_helper/misc.py +++ b/lms/djangoapps/instructor_task/tasks_helper/misc.py @@ -100,7 +100,23 @@ def upload_proctored_exam_results_report(_xmodule_instance_args, _entry_id, cour task_progress.update_task_state(extra_meta=current_step) # Compute result table and format it - query_features = _task_input.get('features') + query_features = [ + 'course_id', + 'exam_name', + 'username', + 'email', + 'attempt_code', + 'allowed_time_limit_mins', + 'is_sample_attempt', + 'started_at', + 'completed_at', + 'status', + 'review_status', + 'Suspicious Count', + 'Suspicious Comments', + 'Rules Violation Count', + 'Rules Violation Comments' + ] student_data = get_proctored_exam_results(course_id, query_features) header, rows = format_dictlist(student_data, query_features) diff --git a/requirements/edx/github.txt b/requirements/edx/github.txt index b5543ff249..4180bf47e8 100644 --- a/requirements/edx/github.txt +++ b/requirements/edx/github.txt @@ -96,7 +96,7 @@ git+https://github.com/edx/xblock-utils.git@v1.0.5#egg=xblock-utils==1.0.5 -e git+https://github.com/edx-solutions/xblock-google-drive.git@138e6fa0bf3a2013e904a085b9fed77dab7f3f21#egg=xblock-google-drive git+https://github.com/edx/edx-user-state-client.git@1.0.1#egg=edx-user-state-client==1.0.1 git+https://github.com/edx/xblock-lti-consumer.git@v1.1.5#egg=lti_consumer-xblock==1.1.5 -git+https://github.com/edx/edx-proctoring.git@1.1.0#egg=edx-proctoring==1.1.0 +git+https://github.com/edx/edx-proctoring.git@1.2.0#egg=edx-proctoring==1.2.0 # Third Party XBlocks git+https://github.com/open-craft/xblock-poll@7ba819b968fe8faddb78bb22e1fe7637005eb414#egg=xblock-poll==1.2.7