def collect_ora2_data(cls, course_id): """ Query database for aggregated ora2 response data. Args: course_id (string) - the course id of the course whose data we would like to return Returns: A tuple containing two lists: headers and data. headers is a list containing strings corresponding to the column headers of the data. data is a list of lists, where each sub-list corresponds to a row in the table of all the data for this course. """ all_submission_information = sub_api.get_all_course_submission_information( course_id, 'openassessment') rows = [] for student_item, submission, score in all_submission_information: row = [] assessments = cls._use_read_replica( Assessment.objects.prefetch_related('parts').prefetch_related( 'rubric').filter(submission_uuid=submission['uuid'])) assessments_cell = cls._build_assessments_cell(assessments) assessments_parts_cell = cls._build_assessments_parts_cell( assessments) feedback_options_cell = cls._build_feedback_options_cell( assessments) feedback_cell = cls._build_feedback_cell(submission['uuid']) row = [ submission['uuid'], submission['student_item'], student_item['student_id'], submission['submitted_at'], submission['answer'], assessments_cell, assessments_parts_cell, score.get('created_at', ''), score.get('points_earned', ''), score.get('points_possible', ''), feedback_options_cell, feedback_cell ] rows.append(row) header = [ 'Submission ID', 'Item ID', 'Anonymized Student ID', 'Date/Time Response Submitted', 'Response', 'Assessment Details', 'Assessment Scores', 'Date/Time Final Score Given', 'Final Score Points Earned', 'Final Score Points Possible', 'Feedback Statements Selected', 'Feedback on Peer Assessments' ] return header, rows
def test_get_course_submissions(self, set_scores): submission1 = api.create_submission(STUDENT_ITEM, ANSWER_ONE) submission2 = api.create_submission(STUDENT_ITEM, ANSWER_TWO) submission3 = api.create_submission(SECOND_STUDENT_ITEM, ANSWER_ONE) submission4 = api.create_submission(SECOND_STUDENT_ITEM, ANSWER_TWO) if set_scores: api.set_score(submission1['uuid'], 1, 4) api.set_score(submission2['uuid'], 2, 4) api.set_score(submission3['uuid'], 3, 4) api.set_score(submission4['uuid'], 4, 4) submissions_and_scores = list( api.get_all_course_submission_information( STUDENT_ITEM['course_id'], STUDENT_ITEM['item_type'], read_replica=False, )) student_item1 = self._get_student_item(STUDENT_ITEM) student_item2 = self._get_student_item(SECOND_STUDENT_ITEM) self.assertDictEqual(SECOND_STUDENT_ITEM, submissions_and_scores[0][0]) self._assert_submission(submissions_and_scores[0][1], submission4['answer'], student_item2.pk, 2) self.assertDictEqual(SECOND_STUDENT_ITEM, submissions_and_scores[1][0]) self._assert_submission(submissions_and_scores[1][1], submission3['answer'], student_item2.pk, 1) self.assertDictEqual(STUDENT_ITEM, submissions_and_scores[2][0]) self._assert_submission(submissions_and_scores[2][1], submission2['answer'], student_item1.pk, 2) self.assertDictEqual(STUDENT_ITEM, submissions_and_scores[3][0]) self._assert_submission(submissions_and_scores[3][1], submission1['answer'], student_item1.pk, 1) # These scores will always be empty self.assertEqual(submissions_and_scores[1][2], {}) self.assertEqual(submissions_and_scores[3][2], {}) if set_scores: self._assert_score(submissions_and_scores[0][2], 4, 4) self._assert_score(submissions_and_scores[2][2], 2, 4) else: self.assertEqual(submissions_and_scores[0][2], {}) self.assertEqual(submissions_and_scores[2][2], {})
def test_get_course_submissions(self, set_scores): submission1 = api.create_submission(STUDENT_ITEM, ANSWER_ONE) submission2 = api.create_submission(STUDENT_ITEM, ANSWER_TWO) submission3 = api.create_submission(SECOND_STUDENT_ITEM, ANSWER_ONE) submission4 = api.create_submission(SECOND_STUDENT_ITEM, ANSWER_TWO) if set_scores: api.set_score(submission1['uuid'], 1, 4) api.set_score(submission2['uuid'], 2, 4) api.set_score(submission3['uuid'], 3, 4) api.set_score(submission4['uuid'], 4, 4) submissions_and_scores = list(api.get_all_course_submission_information( STUDENT_ITEM['course_id'], STUDENT_ITEM['item_type'], read_replica=False, )) student_item1 = self._get_student_item(STUDENT_ITEM) student_item2 = self._get_student_item(SECOND_STUDENT_ITEM) self.assertDictEqual(SECOND_STUDENT_ITEM, submissions_and_scores[0][0]) self._assert_submission(submissions_and_scores[0][1], submission4['answer'], student_item2.pk, 2) self.assertDictEqual(SECOND_STUDENT_ITEM, submissions_and_scores[1][0]) self._assert_submission(submissions_and_scores[1][1], submission3['answer'], student_item2.pk, 1) self.assertDictEqual(STUDENT_ITEM, submissions_and_scores[2][0]) self._assert_submission(submissions_and_scores[2][1], submission2['answer'], student_item1.pk, 2) self.assertDictEqual(STUDENT_ITEM, submissions_and_scores[3][0]) self._assert_submission(submissions_and_scores[3][1], submission1['answer'], student_item1.pk, 1) # These scores will always be empty self.assertEqual(submissions_and_scores[1][2], {}) self.assertEqual(submissions_and_scores[3][2], {}) if set_scores: self._assert_score(submissions_and_scores[0][2], 4, 4) self._assert_score(submissions_and_scores[2][2], 2, 4) else: self.assertEqual(submissions_and_scores[0][2], {}) self.assertEqual(submissions_and_scores[2][2], {})
def collect_ora2_data(cls, course_id): """ Query database for aggregated ora2 response data. Args: course_id (string) - the course id of the course whose data we would like to return Returns: A tuple containing two lists: headers and data. headers is a list containing strings corresponding to the column headers of the data. data is a list of lists, where each sub-list corresponds to a row in the table of all the data for this course. """ all_submission_information = sub_api.get_all_course_submission_information(course_id, 'openassessment') rows = [] for student_item, submission, score in all_submission_information: row = [] assessments = cls._use_read_replica( Assessment.objects.prefetch_related('parts'). prefetch_related('rubric'). filter( submission_uuid=submission['uuid'] ) ) assessments_cell = cls._build_assessments_cell(assessments) assessments_parts_cell = cls._build_assessments_parts_cell(assessments) feedback_options_cell = cls._build_feedback_options_cell(assessments) feedback_cell = cls._build_feedback_cell(submission['uuid']) row = [ submission['uuid'], submission['student_item'], student_item['student_id'], submission['submitted_at'], submission['answer'], assessments_cell, assessments_parts_cell, score.get('created_at', ''), score.get('points_earned', ''), score.get('points_possible', ''), feedback_options_cell, feedback_cell ] rows.append(row) header = [ 'Submission ID', 'Item ID', 'Anonymized Student ID', 'Date/Time Response Submitted', 'Response', 'Assessment Details', 'Assessment Scores', 'Date/Time Final Score Given', 'Final Score Points Earned', 'Final Score Points Possible', 'Feedback Statements Selected', 'Feedback on Peer Assessments' ] return header, rows
def collect_ora2_data(cls, course_id): """ Query database for aggregated ora2 response data. Args: course_id (string) - the course id of the course whose data we would like to return Returns: A tuple containing two lists: headers and data. headers is a list containing strings corresponding to the column headers of the data. data is a list of lists, where each sub-list corresponds to a row in the table of all the data for this course. """ all_submission_information = list(sub_api.get_all_course_submission_information(course_id, 'openassessment')) usernames_enabled = cls._usernames_enabled() usernames_map = ( cls._map_sudents_and_scorers_ids_to_usernames(all_submission_information) if usernames_enabled else {} ) block_display_names_map = cls._map_block_usage_keys_to_display_names(course_id) rows = [] for student_item, submission, score in all_submission_information: assessments = cls._use_read_replica( Assessment.objects.prefetch_related('parts'). prefetch_related('rubric'). filter( submission_uuid=submission['uuid'] ) ) assessments_cell = cls._build_assessments_cell(assessments, usernames_map) assessments_parts_cell = cls._build_assessments_parts_cell(assessments) feedback_options_cell = cls._build_feedback_options_cell(assessments) feedback_cell = cls._build_feedback_cell(submission['uuid']) row_username_cell = ( [usernames_map.get(student_item["student_id"], "")] if usernames_enabled else [] ) problem_name = block_display_names_map.get(student_item['item_id']) row = [ submission['uuid'], student_item['item_id'], problem_name, submission['student_item'], ] + row_username_cell + [ student_item['student_id'], submission['submitted_at'], # Dumping required to render special characters in CSV json.dumps(submission['answer'], ensure_ascii=False), assessments_cell, assessments_parts_cell, score.get('created_at', ''), score.get('points_earned', ''), score.get('points_possible', ''), feedback_options_cell, feedback_cell ] rows.append(row) header_username_cell = ( ['Username'] if usernames_enabled else [] ) header = [ 'Submission ID', 'Location', 'Problem Name', 'Item ID' ] + header_username_cell + [ 'Anonymized Student ID', 'Date/Time Response Submitted', 'Response', 'Assessment Details', 'Assessment Scores', 'Date/Time Final Score Given', 'Final Score Points Earned', 'Final Score Points Possible', 'Feedback Statements Selected', 'Feedback on Peer Assessments' ] return header, rows
def collect_ora2_submission_files(cls, course_id): """ Generator, that yields dictionaries with information about submission attachment or answer text. """ all_submission_information = sub_api.get_all_course_submission_information( course_id, 'openassessment') for student, submission, _ in all_submission_information: raw_answer = submission.get('answer', dict()) answer = OraSubmissionAnswerFactory.parse_submission_raw_answer( raw_answer) for uploaded_file in answer.get_file_uploads(): yield { 'type': cls.ATTACHMENT, 'course_id': course_id, 'block_id': student['item_id'], 'student_id': student['student_id'], 'key': uploaded_file.key, 'name': uploaded_file.name, 'description': uploaded_file.description, 'size': uploaded_file.size, 'file_path': os.path.join( str(course_id), student['item_id'], student['student_id'], 'attachments', uploaded_file.name, ) } # collecting submission answer texts for index, text_response in enumerate(answer.get_text_responses()): file_name = 'part_{}.txt'.format(index) yield { 'type': cls.TEXT, 'course_id': course_id, 'block_id': student['item_id'], 'student_id': student['student_id'], 'key': '', 'name': file_name, 'description': 'Submission text.', 'content': text_response, 'size': len(text_response), 'file_path': os.path.join( str(course_id), student['item_id'], student['student_id'], file_name, ) }
def collect_ora2_submission_files(cls, course_id): """ Generator, that yields dictionaries with information about submission attachment or answer text. """ all_submission_information = sub_api.get_all_course_submission_information( course_id, 'openassessment') for student, submission, _ in all_submission_information: answer = submission.get('answer', dict()) # collecting submission attachments with metadata for index, file_key in enumerate(answer.get('file_keys', [])): # Old submissions (approx. pre-2020) have file names under the key "files_name", # and even older ones don't have file names at all file_names = answer.get('files_names', answer.get('files_name', [])) try: file_name = file_names[index] except IndexError: file_name = "File_" + str(index + 1) # 'files_sizes' was added sometime around the beginning of 2020, so older submissions # will not have it file_size = 0 file_sizes = answer.get('files_sizes') if file_sizes: file_size = file_sizes[index] yield { 'type': cls.ATTACHMENT, 'course_id': course_id, 'block_id': student['item_id'], 'student_id': student['student_id'], 'key': file_key, 'name': file_name, 'description': answer['files_descriptions'][index], 'size': file_size, 'file_path': os.path.join( str(course_id), student['item_id'], student['student_id'], 'attachments', file_name, ) } # collecting submission answer texts for index, part in enumerate(answer.get('parts', [])): content = part['text'] file_name = 'part_{}.txt'.format(index) yield { 'type': cls.TEXT, 'course_id': course_id, 'block_id': student['item_id'], 'student_id': student['student_id'], 'key': '', 'name': file_name, 'description': 'Submission text.', 'content': content, 'size': len(content), 'file_path': os.path.join( str(course_id), student['item_id'], student['student_id'], file_name, ) }