def test_get_the_cancelled_workflow(self): # Create the submission and assessment workflow. submission = sub_api.create_submission(ITEM_1, ANSWER_1) workflow = workflow_api.create_workflow(submission["uuid"], ["peer"]) requirements = {"peer": {"must_grade": 1, "must_be_graded_by": 1}} # Check the workflow is not cancelled. self.assertFalse(workflow_api.is_workflow_cancelled( submission["uuid"])) # Check the status is not cancelled. self.assertNotEqual(workflow.get('status'), 'cancelled') # Check the points_earned are not 0 self.assertNotEqual(workflow['score'], 0) cancelled_workflow = workflow_api.get_assessment_workflow_cancellation( submission["uuid"]) self.assertIsNone(cancelled_workflow) # Cancel the workflow for submission. workflow_api.cancel_workflow(submission_uuid=submission["uuid"], comments="Inappropriate language", cancelled_by_id=ITEM_2['student_id'], assessment_requirements=requirements) # Check workflow is cancelled. self.assertTrue(workflow_api.is_workflow_cancelled(submission["uuid"])) workflow = workflow_api.get_assessment_workflow_cancellation( submission["uuid"]) self.assertIsNotNone(workflow)
def get_workflow_cancellation_info(self, submission_uuid): """ Returns cancellation information for a particular submission. :param submission_uuid: The submission to return information for. :return: The cancellation information, or None if the submission has not been cancelled. """ cancellation_info = workflow_api.get_assessment_workflow_cancellation( submission_uuid) if not cancellation_info: return None # Add the username of the staff member who cancelled the submission cancellation_info['cancelled_by'] = self.get_username( cancellation_info['cancelled_by_id']) # Add the date that the workflow was cancelled (in preference to the serialized date string) del cancellation_info['created_at'] cancellation_model = AssessmentWorkflowCancellation.get_latest_workflow_cancellation( submission_uuid) if cancellation_model: cancellation_info['cancelled_at'] = cancellation_model.created_at return cancellation_info
def test_get_the_cancelled_workflow(self): # Create the submission and assessment workflow. submission = sub_api.create_submission(ITEM_1, ANSWER_1) workflow = workflow_api.create_workflow(submission["uuid"], ["peer"]) requirements = { "peer": { "must_grade": 1, "must_be_graded_by": 1 } } # Check the workflow is not cancelled. self.assertFalse(workflow_api.is_workflow_cancelled(submission["uuid"])) # Check the status is not cancelled. self.assertNotEqual(workflow.get('status'), 'cancelled') # Check the points_earned are not 0 self.assertNotEqual(workflow['score'], 0) cancelled_workflow = workflow_api.get_assessment_workflow_cancellation(submission["uuid"]) self.assertIsNone(cancelled_workflow) # Cancel the workflow for submission. workflow_api.cancel_workflow( submission_uuid=submission["uuid"], comments="Inappropriate language", cancelled_by_id=ITEM_2['student_id'], assessment_requirements=requirements ) # Check workflow is cancelled. self.assertTrue(workflow_api.is_workflow_cancelled(submission["uuid"])) workflow = workflow_api.get_assessment_workflow_cancellation(submission["uuid"]) self.assertIsNotNone(workflow)
def get_workflow_cancellation_info(self, submission_uuid): """ Returns cancellation information for a particular submission. :param submission_uuid: The submission to return information for. :return: The cancellation information, or None if the submission has not been cancelled. """ cancellation_info = workflow_api.get_assessment_workflow_cancellation(submission_uuid) if not cancellation_info: return None # Add the username of the staff member who cancelled the submission cancellation_info['cancelled_by'] = self.get_username(cancellation_info['cancelled_by_id']) # Add the date that the workflow was cancelled (in preference to the serialized date string) del cancellation_info['created_at'] cancellation_model = AssessmentWorkflowCancellation.get_latest_workflow_cancellation(submission_uuid) if cancellation_model: cancellation_info['cancelled_at'] = cancellation_model.created_at return cancellation_info
def submission_path_and_context(self): """ Determine the template path and context to use when rendering the response (submission) step. Returns: tuple of `(path, context)`, where `path` (str) is the path to the template, and `context` (dict) is the template context. """ workflow = self.get_workflow_info() problem_closed, reason, start_date, due_date = self.is_closed("submission") path = "openassessmentblock/response/oa_response.html" context = {} # Due dates can default to the distant future, in which case # there's effectively no due date. # If we don't add the date to the context, the template won't display it. if due_date < DISTANT_FUTURE: context["submission_due"] = due_date context["file_upload_type"] = self.file_upload_type context["allow_latex"] = self.allow_latex context["has_peer"] = "peer-assessment" in self.assessment_steps context["has_self"] = "self-assessment" in self.assessment_steps if self.file_upload_type: context["file_url"] = self._get_download_url() if self.file_upload_type == "custom": context["white_listed_file_types"] = self.white_listed_file_types if not workflow and problem_closed: if reason == "due": path = "openassessmentblock/response/oa_response_closed.html" elif reason == "start": context["submission_start"] = start_date path = "openassessmentblock/response/oa_response_unavailable.html" elif not workflow: # For backwards compatibility. Initially, problems had only one prompt # and a string answer. We convert it to the appropriate dict. try: json.loads(self.saved_response) saved_response = {"answer": json.loads(self.saved_response)} except ValueError: saved_response = {"answer": {"text": self.saved_response}} context["saved_response"] = create_submission_dict(saved_response, self.prompts) context["save_status"] = self.save_status context["submit_enabled"] = self.saved_response != "" path = "openassessmentblock/response/oa_response.html" elif workflow["status"] == "cancelled": workflow_cancellation = workflow_api.get_assessment_workflow_cancellation(self.submission_uuid) if workflow_cancellation: workflow_cancellation["cancelled_by"] = self.get_username(workflow_cancellation["cancelled_by_id"]) context["workflow_cancellation"] = workflow_cancellation context["student_submission"] = self.get_user_submission(workflow["submission_uuid"]) path = "openassessmentblock/response/oa_response_cancelled.html" elif workflow["status"] == "done": student_submission = self.get_user_submission(workflow["submission_uuid"]) context["student_submission"] = create_submission_dict(student_submission, self.prompts) path = "openassessmentblock/response/oa_response_graded.html" else: student_submission = self.get_user_submission(workflow["submission_uuid"]) context["student_submission"] = create_submission_dict(student_submission, self.prompts) path = "openassessmentblock/response/oa_response_submitted.html" return path, context
def get_student_info_path_and_context(self, student_username): """ Get the proper path and context for rendering the the student info section of the staff debug panel. Args: student_username (unicode): The username of the student to report. """ submission_uuid = None submission = None assessment_steps = self.assessment_steps anonymous_user_id = None submissions = None student_item = None if student_username: anonymous_user_id = self.get_anonymous_user_id(student_username, self.course_id) student_item = self.get_student_item_dict(anonymous_user_id=anonymous_user_id) if anonymous_user_id: # If there is a submission available for the requested student, present # it. If not, there will be no other information to collect. submissions = submission_api.get_submissions(student_item, 1) if submissions: submission_uuid = submissions[0]['uuid'] submission = submissions[0] if 'file_key' in submission.get('answer', {}): file_key = submission['answer']['file_key'] try: submission['image_url'] = file_api.get_download_url(file_key) except file_api.FileUploadError: # Log the error, but do not prevent the rest of the student info # from being displayed. msg = ( u"Could not retrieve image URL for staff debug page. " u"The student username is '{student_username}', and the file key is {file_key}" ).format(student_username=student_username, file_key=file_key) logger.exception(msg) example_based_assessment = None self_assessment = None peer_assessments = [] submitted_assessments = [] if "peer-assessment" in assessment_steps: peer_assessments = peer_api.get_assessments(submission_uuid) submitted_assessments = peer_api.get_submitted_assessments(submission_uuid, scored_only=False) if "self-assessment" in assessment_steps: self_assessment = self_api.get_assessment(submission_uuid) if "example-based-assessment" in assessment_steps: example_based_assessment = ai_api.get_latest_assessment(submission_uuid) workflow_cancellation = workflow_api.get_assessment_workflow_cancellation(submission_uuid) if workflow_cancellation: workflow_cancellation['cancelled_by'] = self.get_username(workflow_cancellation['cancelled_by_id']) context = { 'submission': submission, 'workflow_cancellation': workflow_cancellation, 'peer_assessments': peer_assessments, 'submitted_assessments': submitted_assessments, 'self_assessment': self_assessment, 'example_based_assessment': example_based_assessment, 'rubric_criteria': copy.deepcopy(self.rubric_criteria_with_labels), } if peer_assessments or self_assessment or example_based_assessment: max_scores = peer_api.get_rubric_max_scores(submission_uuid) for criterion in context["rubric_criteria"]: criterion["total_value"] = max_scores[criterion["name"]] path = 'openassessmentblock/staff_debug/student_info.html' return path, context
def submission_path_and_context(self): """ Determine the template path and context to use when rendering the response (submission) step. Returns: tuple of `(path, context)`, where `path` (str) is the path to the template, and `context` (dict) is the template context. """ workflow = self.get_workflow_info() problem_closed, reason, start_date, due_date = self.is_closed( 'submission') path = 'openassessmentblock/response/oa_response.html' context = {} # Due dates can default to the distant future, in which case # there's effectively no due date. # If we don't add the date to the context, the template won't display it. if due_date < DISTANT_FUTURE: context["submission_due"] = due_date context['file_upload_type'] = self.file_upload_type context['allow_latex'] = self.allow_latex context['has_peer'] = 'peer-assessment' in self.assessment_steps context['has_self'] = 'self-assessment' in self.assessment_steps if self.file_upload_type: context['file_url'] = self._get_download_url() if self.file_upload_type == 'custom': context['white_listed_file_types'] = self.white_listed_file_types if not workflow and problem_closed: if reason == 'due': path = 'openassessmentblock/response/oa_response_closed.html' elif reason == 'start': context['submission_start'] = start_date path = 'openassessmentblock/response/oa_response_unavailable.html' elif not workflow: # For backwards compatibility. Initially, problems had only one prompt # and a string answer. We convert it to the appropriate dict. try: json.loads(self.saved_response) saved_response = { 'answer': json.loads(self.saved_response), } except ValueError: saved_response = { 'answer': { 'text': self.saved_response, }, } context['saved_response'] = create_submission_dict( saved_response, self.prompts) context['save_status'] = self.save_status context['submit_enabled'] = self.saved_response != '' path = "openassessmentblock/response/oa_response.html" elif workflow["status"] == "cancelled": workflow_cancellation = workflow_api.get_assessment_workflow_cancellation( self.submission_uuid) if workflow_cancellation: workflow_cancellation['cancelled_by'] = self.get_username( workflow_cancellation['cancelled_by_id']) context['workflow_cancellation'] = workflow_cancellation context["student_submission"] = self.get_user_submission( workflow["submission_uuid"]) path = 'openassessmentblock/response/oa_response_cancelled.html' elif workflow["status"] == "done": student_submission = self.get_user_submission( workflow["submission_uuid"]) context["student_submission"] = create_submission_dict( student_submission, self.prompts) path = 'openassessmentblock/response/oa_response_graded.html' else: student_submission = self.get_user_submission( workflow["submission_uuid"]) context["student_submission"] = create_submission_dict( student_submission, self.prompts) path = 'openassessmentblock/response/oa_response_submitted.html' return path, context
def get_student_info_path_and_context(self, student_username): """ Get the proper path and context for rendering the the student info section of the staff debug panel. Args: student_username (unicode): The username of the student to report. """ submission_uuid = None submission = None assessment_steps = self.assessment_steps anonymous_user_id = None submissions = None student_item = None if student_username: anonymous_user_id = self.get_anonymous_user_id( student_username, self.course_id) student_item = self.get_student_item_dict( anonymous_user_id=anonymous_user_id) if anonymous_user_id: # If there is a submission available for the requested student, present # it. If not, there will be no other information to collect. submissions = submission_api.get_submissions(student_item, 1) if submissions: submission_uuid = submissions[0]['uuid'] submission = submissions[0] if 'file_key' in submission.get('answer', {}): file_key = submission['answer']['file_key'] try: submission['file_url'] = file_api.get_download_url( file_key) except file_exceptions.FileUploadError: # Log the error, but do not prevent the rest of the student info # from being displayed. msg = ( u"Could not retrieve image URL for staff debug page. " u"The learner username is '{student_username}', and the file key is {file_key}" ).format(student_username=student_username, file_key=file_key) logger.exception(msg) example_based_assessment = None self_assessment = None peer_assessments = [] submitted_assessments = [] if "peer-assessment" in assessment_steps: peer_assessments = peer_api.get_assessments(submission_uuid) submitted_assessments = peer_api.get_submitted_assessments( submission_uuid, scored_only=False) if "self-assessment" in assessment_steps: self_assessment = self_api.get_assessment(submission_uuid) if "example-based-assessment" in assessment_steps: example_based_assessment = ai_api.get_latest_assessment( submission_uuid) workflow_cancellation = workflow_api.get_assessment_workflow_cancellation( submission_uuid) if workflow_cancellation: workflow_cancellation['cancelled_by'] = self.get_username( workflow_cancellation['cancelled_by_id']) context = { 'submission': create_submission_dict(submission, self.prompts) if submission else None, 'workflow_cancellation': workflow_cancellation, 'peer_assessments': peer_assessments, 'submitted_assessments': submitted_assessments, 'self_assessment': self_assessment, 'example_based_assessment': example_based_assessment, 'rubric_criteria': copy.deepcopy(self.rubric_criteria_with_labels), } if peer_assessments or self_assessment or example_based_assessment: max_scores = peer_api.get_rubric_max_scores(submission_uuid) for criterion in context["rubric_criteria"]: criterion["total_value"] = max_scores[criterion["name"]] path = 'openassessmentblock/staff_area/student_info.html' return path, context
def submission_path_and_context(self): """ Determine the template path and context to use when rendering the response (submission) step. Returns: tuple of `(path, context)`, where `path` (str) is the path to the template, and `context` (dict) is the template context. """ workflow = self.get_workflow_info() problem_closed, reason, start_date, due_date = self.is_closed('submission') path = 'openassessmentblock/response/oa_response.html' context = {} # Due dates can default to the distant future, in which case # there's effectively no due date. # If we don't add the date to the context, the template won't display it. if due_date < DISTANT_FUTURE: context["submission_due"] = due_date context['allow_file_upload'] = self.allow_file_upload context['allow_latex'] = self.allow_latex context['has_peer'] = 'peer-assessment' in self.assessment_steps context['has_self'] = 'self-assessment' in self.assessment_steps if self.allow_file_upload: context['file_url'] = self._get_download_url() if not workflow and problem_closed: if reason == 'due': path = 'openassessmentblock/response/oa_response_closed.html' elif reason == 'start': context['submission_start'] = start_date path = 'openassessmentblock/response/oa_response_unavailable.html' elif not workflow: # For backwards compatibility. Initially, problems had only one prompt # and a string answer. We convert it to the appropriate dict. try: json.loads(self.saved_response) saved_response = { 'answer': json.loads(self.saved_response), } except ValueError: saved_response = { 'answer': { 'text': self.saved_response, }, } context['saved_response'] = create_submission_dict(saved_response, self.prompts) context['save_status'] = self.save_status context['submit_enabled'] = self.saved_response != '' path = "openassessmentblock/response/oa_response.html" elif workflow["status"] == "cancelled": workflow_cancellation = workflow_api.get_assessment_workflow_cancellation(self.submission_uuid) if workflow_cancellation: workflow_cancellation['cancelled_by'] = self.get_username(workflow_cancellation['cancelled_by_id']) context['workflow_cancellation'] = workflow_cancellation context["student_submission"] = self.get_user_submission( workflow["submission_uuid"] ) path = 'openassessmentblock/response/oa_response_cancelled.html' elif workflow["status"] == "done": student_submission = self.get_user_submission( workflow["submission_uuid"] ) context["student_submission"] = create_submission_dict(student_submission, self.prompts) path = 'openassessmentblock/response/oa_response_graded.html' else: student_submission = self.get_user_submission( workflow["submission_uuid"] ) context["student_submission"] = create_submission_dict(student_submission, self.prompts) path = 'openassessmentblock/response/oa_response_submitted.html' return path, context
def submission_path_and_context(self): """ Determine the template path and context to use when rendering the response (submission) step. Returns: tuple of `(path, context)`, where `path` (str) is the path to the template, and `context` (dict) is the template context. """ workflow = self.get_workflow_info() problem_closed, reason, start_date, due_date = self.is_closed('submission') path = 'openassessmentblock/response/oa_response.html' context = {} # Due dates can default to the distant future, in which case # there's effectively no due date. # If we don't add the date to the context, the template won't display it. if due_date < DISTANT_FUTURE: context["submission_due"] = due_date context['allow_file_upload'] = self.allow_file_upload context['allow_latex'] = self.allow_latex context['has_peer'] = 'peer-assessment' in self.assessment_steps context['has_self'] = 'self-assessment' in self.assessment_steps if self.allow_file_upload: context['file_url'] = self._get_download_url() if not workflow and problem_closed: if reason == 'due': path = 'openassessmentblock/response/oa_response_closed.html' elif reason == 'start': context['submission_start'] = start_date path = 'openassessmentblock/response/oa_response_unavailable.html' elif not workflow: context['saved_response'] = self.saved_response context['save_status'] = self.save_status context['submit_enabled'] = self.saved_response != '' path = "openassessmentblock/response/oa_response.html" elif workflow["status"] == "cancelled": workflow_cancellation = workflow_api.get_assessment_workflow_cancellation(self.submission_uuid) if workflow_cancellation: workflow_cancellation['cancelled_by'] = self.get_username(workflow_cancellation['cancelled_by_id']) context['workflow_cancellation'] = workflow_cancellation context["student_submission"] = self.get_user_submission( workflow["submission_uuid"] ) path = 'openassessmentblock/response/oa_response_cancelled.html' elif workflow["status"] == "done": student_submission = self.get_user_submission( workflow["submission_uuid"] ) context["student_submission"] = student_submission path = 'openassessmentblock/response/oa_response_graded.html' else: context["student_submission"] = self.get_user_submission( workflow["submission_uuid"] ) path = 'openassessmentblock/response/oa_response_submitted.html' return path, context