Пример #1
0
    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)
Пример #2
0
    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
Пример #3
0
    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)
Пример #4
0
    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
Пример #5
0
    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
Пример #6
0
    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
Пример #7
0
    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
Пример #8
0
    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
Пример #9
0
    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
Пример #10
0
    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