Пример #1
0
    def publish_completion(self, data, dispatch):  # pylint: disable=unused-argument
        """
        Entry point for completion for student_view.

        Parameters:
            data: JSON dict:
                key: "completion"
                value: float in range [0.0, 1.0]

            dispatch: Ignored.
        Return value: JSON response (200 on success, 400 for malformed data)
        """
        completion_service = self.runtime.service(self, 'completion')
        if completion_service is None:
            raise JsonHandlerError(500, u"No completion service found")
        elif not completion_service.completion_tracking_enabled():
            raise JsonHandlerError(404, u"Completion tracking is not enabled and API calls are unexpected")
        if not isinstance(data['completion'], (int, float)):
            message = u"Invalid completion value {}. Must be a float in range [0.0, 1.0]"
            raise JsonHandlerError(400, message.format(data['completion']))
        elif not 0.0 <= data['completion'] <= 1.0:
            message = u"Invalid completion value {}. Must be in range [0.0, 1.0]"
            raise JsonHandlerError(400, message.format(data['completion']))
        self.runtime.publish(self, "completion", data)
        return {"result": "ok"}
Пример #2
0
 def submit_studio_edits(self, data, suffix=''):
     """
     AJAX handler for studio_view() Save button
     """
     values = {}  # dict of new field values we are updating
     to_reset = []  # list of field names to delete from this XBlock
     for field_name in self.editable_fields:
         field = self.fields[field_name]
         if field_name in data['values']:
             if isinstance(field, JSONField):
                 values[field_name] = field.from_json(
                     data['values'][field_name])
             else:
                 raise JsonHandlerError(
                     400, "Unsupported field type: {}".format(field_name))
         elif field_name in data['defaults'] and field.is_set_on(self):
             to_reset.append(field_name)
     self.clean_studio_edits(values)
     validation = Validation(self.scope_ids.usage_id)
     # We cannot set the fields on self yet, because even if validation fails, studio is going to save any changes we
     # make. So we create a "fake" object that has all the field values we are about to set.
     preview_data = FutureFields(new_fields_dict=values,
                                 newly_removed_fields=to_reset,
                                 fallback_obj=self)
     self.validate_field_data(validation, preview_data)
     if validation:
         for field_name, value in six.iteritems(values):
             setattr(self, field_name, value)
         for field_name in to_reset:
             self.fields[field_name].delete_from(self)
         return {'result': 'success'}
     else:
         raise JsonHandlerError(400, validation.to_json())
Пример #3
0
    def share_results(self, data, suffix=''):
        target_usernames = data.get('usernames')
        target_usernames = [username.strip().lower() for username in target_usernames if username.strip()]
        current_user = User.objects.get(username=self.current_user_key)

        failed_users = []
        if not target_usernames:
            raise JsonHandlerError(400, _('Usernames not provided.'))
        for target_username in target_usernames:
            try:
                target_user = User.objects.get(username=target_username)
            except User.DoesNotExist:
                failed_users.append(target_username)
                continue
            if current_user == target_user:
                continue
            try:
                Share.objects.get(shared_by=current_user, shared_with=target_user, block_id=self.block_id)
            except Share.DoesNotExist:
                Share(
                    shared_by=current_user, submission_uid=self.runtime.anonymous_student_id, shared_with=target_user,
                    block_id=self.block_id,
                ).save()

        if failed_users:
            raise JsonHandlerError(
                400,
                _('Some users could not be shared with. Please check these usernames: {}').format(
                    ', '.join(failed_users)
                )
            )
        return {}
Пример #4
0
    def get_submission_info(self, submission_uuid, _, suffix=''):  # pylint: disable=unused-argument
        """
        Return a dict representation of a submission in the form
        {
            'text': <list of strings representing the raw response for each prompt>
            'files': <list of:>
                {
                    'download_url': <file url>
                    'description': <file description>
                    'name': <file name>
                }
        }
        """
        try:
            if self.is_team_assignment():
                submission = get_team_submission(submission_uuid)
            else:
                submission = get_submission(submission_uuid)
            answer = OraSubmissionAnswerFactory.parse_submission_raw_answer(
                submission.get('answer'))
        except SubmissionError as err:
            raise JsonHandlerError(404, str(err)) from err
        except VersionNotFoundException as err:
            raise JsonHandlerError(500, str(err)) from err

        return {
            'files': [
                SubmissionDetailFileSerilaizer(file_data).data for file_data in
                self.get_download_urls_from_submission(submission)
            ],
            'text':
            answer.get_text_responses()
        }
Пример #5
0
    def save_sga(self, data, suffix=''):
        # pylint: disable=unused-argument
        """
        Persist block data when updating settings in studio.
        """
        self.display_name = data.get('display_name', self.display_name)

        # Validate points before saving
        points = data.get('points', self.points)
        # Check that we are an int
        try:
            points = int(points)
        except ValueError:
            raise JsonHandlerError(400, 'Points must be an integer')
        # Check that we are positive
        if points < 0:
            raise JsonHandlerError(400, 'Points must be a positive integer')
        self.points = points

        # Validate weight before saving
        weight = data.get('weight', self.weight)
        # Check that weight is a float.
        if weight:
            try:
                weight = float(weight)
            except ValueError:
                raise JsonHandlerError(400, 'Weight must be a decimal number')
            # Check that we are positive
            if weight < 0:
                raise JsonHandlerError(
                    400, 'Weight must be a positive decimal number'
                )
        self.weight = weight
Пример #6
0
    def refresh_other_answers(self, data, suffix=''):
        """
        Refresh other answers shown, if possible
        """
        if 'option' not in data:
            raise JsonHandlerError(400, 'Missing option')
        the_option = int(data['option'])
        if the_option < 0 or the_option >= len(self.options):
            raise JsonHandlerError(400, 'Invalid option')

        student_item = self.get_student_item_dict()
        if not student_item or not student_item['student_id']:
            raise JsonHandlerError(400, 'Missing student info')

        # can refresh only after intial submission and before final submission
        answers = self.get_answers_for_student()
        if not(answers.has_revision(0) and not answers.has_revision(1)):
            return self.get_persisted_data(self.other_answers_shown)

        seeded_first = self._over_answers_shown_refresh_limit(the_option)
        self.other_answers_shown = \
            refresh_answers(self.other_answers_shown, the_option, self.sys_selected_answers, self.seeds, self.get_student_item_dict, seeded_first)

        self._incr_answers_shown_refresh_count(the_option)
        self._record_answers_shown(self.other_answers_shown)

        return self.get_persisted_data(self.other_answers_shown)
Пример #7
0
    def fe_submit_studio_edits(self, data, suffix=''):
        """
        AJAX handler for studio edit submission
        """

        if self.xblock_id is None:
            self.xblock_id = unicode(
                self.location.replace(branch=None, version=None))

        updated_question_template = data['question_template']
        updated_variables = data['variables']
        updated_answer_template = data['answer_template']

        qgb_db_service.update_question_template(self.xblock_id,
                                                updated_question_template,
                                                updated_variables,
                                                updated_answer_template)

        # "refresh" XBlock's values
        self.question_template = updated_question_template
        self.variables = updated_variables
        self.answer_template = updated_answer_template

        # call parent method
        # StudioEditableXBlockMixin.submit_studio_edits(self, data, suffix)
        # self.submit_studio_edits(data, suffix)
        # super(FormulaExerciseXBlock, self).submit_studio_edits(data, suffix)

        # copy from StudioEditableXBlockMixin (can not call parent method)
        values = {}  # dict of new field values we are updating
        to_reset = []  # list of field names to delete from this XBlock
        for field_name in self.editable_fields:
            field = self.fields[field_name]
            if field_name in data['values']:
                if isinstance(field, JSONField):
                    values[field_name] = field.from_json(
                        data['values'][field_name])
                else:
                    raise JsonHandlerError(
                        400, "Unsupported field type: {}".format(field_name))
            elif field_name in data['defaults'] and field.is_set_on(self):
                to_reset.append(field_name)
        self.clean_studio_edits(values)
        validation = Validation(self.scope_ids.usage_id)
        # We cannot set the fields on self yet, because even if validation fails, studio is going to save any changes we
        # make. So we create a "fake" object that has all the field values we are about to set.
        preview_data = FutureFields(new_fields_dict=values,
                                    newly_removed_fields=to_reset,
                                    fallback_obj=self)
        self.validate_field_data(validation, preview_data)
        if validation:
            for field_name, value in values.iteritems():
                setattr(self, field_name, value)
            for field_name in to_reset:
                self.fields[field_name].delete_from(self)
            return {'result': 'success'}
        else:
            raise JsonHandlerError(400, validation.to_json())
Пример #8
0
    def save_agea(self, data, suffix=''):
        """
        Persist block data when updating settings in studio.
        """
        self.title = data.get('title', self.title)
        self.question = data.get('question', self.question)
        self.raw_question = data.get('raw_question', self.raw_question)
        self.raw_solution = data.get('raw_solution', self.raw_solution)
        self.max_attempts = data.get('max_attempts', self.max_attempts)
        # Validate points before saving
        points = data.get('points', self.points)
        # Check that we are an int
        try:
            points = int(points)
        except ValueError:
            raise JsonHandlerError(
                400, '"Score to be graded out of" must be an integer')

        # Check that we are positive
        if points < 0:
            raise JsonHandlerError(
                400, '"Score to be graded out of" must be a positive integer')
        self.points = points

        # Validate weight before saving

        weight = data.get('weight', self.weight)
        # Check that weight is a float.
        if weight:
            try:
                weight = float(weight)
            except ValueError:
                raise JsonHandlerError(400, 'Weight must be a decimal number')
            # Check that we are positive
            if weight < 0:
                raise JsonHandlerError(
                    400, 'Weight must be a positive decimal number')
        self.weight = weight
        submission = self.get_question()
        if submission:
            uploaded_submission = submission.get("question").get(
                "filename", None)
            if uploaded_submission:
                question = self._question_storage_path(
                    self.raw_question['sha1'], self.raw_question['filename'])
                question = os.path.join(IMAGEDIFF_ROOT, question)
                actual = total_marks(question)
                if actual < points:
                    raise JsonHandlerError(
                        400,
                        '"Score to be graded out of" should be less than equal to the maximum attainable score for the question paper you uploaded'
                    )

        self.save()
        log.info(self)
Пример #9
0
    def _validated_student_answer_data(self, data: dict) -> dict:
        """
        Take the `data` that is the submitted student answer,
        and either:

        - return a validated and cleaned copy of it
        - raise an informative JsonHandlerError
        """

        if self.question_data["type"] == "optionresponse":
            index = data.get("index")
            n_options = len(self.question_data["options"])
            if index is None:
                raise JsonHandlerError(400, "`index` field missing")
            try:
                index = int(index)
            except ValueError:
                raise JsonHandlerError(
                    400, "`index` field must be an integer") from None
            if index < 0 or index >= n_options:
                raise JsonHandlerError(
                    400, "`index` field must be >= 0 and < number of options")
            return {"index": index}

        elif self.question_data["type"] == "stringresponse":
            response = data.get("response")
            if response is None:
                raise JsonHandlerError(400, "`response` field missing")
            if not isinstance(response, str):
                raise JsonHandlerError(400, "`response` field must be string")
            return {"response": response}

        elif self.question_data["type"] == "choiceresponse":
            selected = data.get("selected")
            n_choices = len(self.question_data["choices"])
            if selected is None:
                raise JsonHandlerError(400, "`selected` field missing")
            if not isinstance(selected, list):
                raise JsonHandlerError(400, "`selected` field must be list")
            for i in selected:
                if not isinstance(i, int):
                    raise JsonHandlerError(
                        400, "`selected` field list values must be integers")
                if i < 0 or i >= n_choices:
                    raise JsonHandlerError(
                        400,
                        "`selected` field list values must be an index >= 0 and index < number of choices",
                    )
            return {"selected": selected}

        else:
            raise JsonHandlerError(
                500, "Question is broken: invalid question type")
Пример #10
0
    def select_part(self, data, suffix=''):
        """
        Get the state of this XBlock - i.e. all the user-specific data
        """
        if self.student_has_answered:
            raise JsonHandlerError(400, "This student already answered.")
        part_index = data.get("part_index")
        if part_index not in range(0, len(self.text_parts)):
            raise JsonHandlerError(400, "Invalid part_index.")

        # Save the student's selection:
        self.part_selected = part_index

        return self.get_current_state()
 def _validate_do_attempt(self):
     """
     Validates if `do_attempt` handler should be executed
     """
     if self.mode != Constants.ASSESSMENT_MODE:
         raise JsonHandlerError(
             400,
             self.i18n_service.gettext("do_attempt handler should only be called for assessment mode")
         )
     if not self.attempts_remain:
         raise JsonHandlerError(
             409,
             self.i18n_service.gettext("Max number of attempts reached")
         )
Пример #12
0
 def publish_completion(self, data, suffix=''):  # pylint: disable=unused-argument
     """
     Publish data from the front end.
     """
     block_key = UsageKey.from_string(data.pop('block_key')).map_into_course(self.course_id)
     block = self.find_descendent(block_key)
     if block is None:
         message = "Invalid block: {} not found in {}"
         raise JsonHandlerError(400, message.format(block_key, self.location))  # pylint: disable=no-member
     elif not is_completable_by_viewing(block):
         message = "Invalid block type: {} in block {} not configured for completion by viewing"
         raise JsonHandlerError(400, message.format(type(block), block_key))
     self.runtime.publish(block, "completion", data)
     return {'result': 'ok'}
Пример #13
0
 def wrapper(self, request, suffix=''):
     """The wrapper function `json_handler` returns."""
     if request.method != "POST":
         return JsonHandlerError(
             405, "Method must be POST").get_response(allow=["POST"])
     try:
         request_json = json.loads(request.body)
     except ValueError:
         return JsonHandlerError(400, "Invalid JSON").get_response()
     try:
         response_json = json.dumps(func(self, request_json, suffix))
     except JsonHandlerError as e:
         return e.get_response()
     return Response(response_json, content_type='application/json')
Пример #14
0
    def save_sga(self, data, suffix=''):
        self.display_name = data.get('display_name', self.display_name)
        self.weight = data.get('weight', self.weight)

        # Validate points before saving
        points = data.get('points', self.points)
        # Check that we are an int
        try:
            points = int(points)
        except ValueError:
            raise JsonHandlerError(400, 'Points must be an integer')
        # Check that we are positive
        if points < 0:
            raise JsonHandlerError(400, 'Points must be a positive integer')
        self.points = points
Пример #15
0
 def check_answer(self, data, suffix=''):  # pylint: disable=unused-argument
     """
     Check and persist student's answer to this vector drawing problem.
     """
     # Validate data
     try:
         self._validate_check_answer_data(data)
     except ValueError:
         raise JsonHandlerError(400, "Invalid data")
     # Save answer
     self.answer = dict(
         vectors=data["vectors"],
         points=data["points"]
     )
     # Compute result
     grader = Grader()
     result = grader.grade(data)
     # Save result
     self.result = result
     # Publish grade data
     score = 1 if result["correct"] else 0
     self.runtime.publish(self, 'grade', dict(value=score, max_value=1))
     return {
         "result": result,
     }
Пример #16
0
 def staff_upload_annotated(self, request, suffix=''):
     # pylint: disable=unused-argument
     """
     Save annotated assignment from staff.
     """
     require(self.is_course_staff())
     upload = request.params['annotated']
     sha1 = get_sha1(upload.file)
     if self.file_size_over_limit(upload.file):
         raise JsonHandlerError(
             413, 'Unable to upload file. Max size limit is {size}'.format(
                 size=self.student_upload_max_size()))
     module = self.get_student_module(request.params['module_id'])
     state = json.loads(module.state)
     state['annotated_sha1'] = sha1
     state['annotated_filename'] = filename = upload.file.name
     state['annotated_mimetype'] = mimetypes.guess_type(upload.file.name)[0]
     state['annotated_timestamp'] = utcnow().strftime(
         DateTime.DATETIME_FORMAT)
     path = self.file_storage_path(sha1, filename)
     if not default_storage.exists(path):
         default_storage.save(path, File(upload.file))
     module.state = json.dumps(state)
     module.save()
     log.info("staff_upload_annotated for course:%s module:%s student:%s ",
              module.course_id, module.module_state_key,
              module.student.username)
     return Response(json_body=self.staff_grading_data())
Пример #17
0
 def upload_assignment(self, request, suffix=''):
     # pylint: disable=unused-argument
     """
     Save a students submission file.
     """
     require(self.upload_allowed())
     user = self.get_real_user()
     require(user)
     upload = request.params['assignment']
     sha1 = get_sha1(upload.file)
     if self.file_size_over_limit(upload.file):
         raise JsonHandlerError(
             413, 'Unable to upload file. Max size limit is {size}'.format(
                 size=self.student_upload_max_size()))
     # Uploading an assignment represents a change of state with this user in this block,
     # so we need to ensure that the user has a StudentModule record, which represents that state.
     self.get_or_create_student_module(user)
     answer = {
         "sha1": sha1,
         "filename": upload.file.name,
         "mimetype": mimetypes.guess_type(upload.file.name)[0],
         "finalized": False
     }
     student_item_dict = self.get_student_item_dict()
     submissions_api.create_submission(student_item_dict, answer)
     path = self.file_storage_path(sha1, upload.file.name)
     log.info("Saving file: %s at path: %s for user: %s", upload.file.name,
              path, user.username)
     if default_storage.exists(path):
         # save latest submission
         default_storage.delete(path)
     default_storage.save(path, File(upload.file))
     return Response(json_body=self.student_state())
Пример #18
0
    def studio_submit(self, data, suffix=''):
        try:
            count = int(data.get('count', LeaderboardXBlock.count.default))
            if not count > 0:
                raise ValueError
        except ValueError:
            raise JsonHandlerError(
                400, "'count' must be an integer and greater than 0.")

        discussion_id = data.get('discussion_id', '').strip()
        if not isinstance(discussion_id, basestring):
            raise JsonHandlerError(400, "'discussion_id' must be a string.")

        self.count = count
        self.discussion_id = discussion_id
        return {}
Пример #19
0
    def table_render(self, data, suffix=''):
        context = {}
        header_values = []
        content_values = []
        target_username = data.get('target_username')
        try:
            if target_username and target_username != self.current_user_key:
                share = Share.objects.get(
                    shared_by__username=target_username,
                    shared_with__username=self.current_user_key,
                    block_id=self.block_id,
                )
                context['student_submissions_key'] = share.submission_uid
        except Share.DoesNotExist:
            raise JsonHandlerError(
                403, _("You are not permitted to view this student's table."))

        for child_id in self.children:
            child = self.runtime.get_block(child_id)
            # Child should be an instance of MentoringTableColumn
            header = child.header
            # Make sure /jump_to_id/ URLs are expanded correctly
            if getattr(self.runtime, 'replace_jump_to_id_urls', None):
                header = self.runtime.replace_jump_to_id_urls(header)
            header_values.append(header)
            child_frag = child.render('mentoring_view', context)
            content_values.append(child_frag.content)
        context['header_values'] = header_values if any(
            header_values) else None
        context['content_values'] = content_values
        html = loader.render_template('templates/html/mentoring-table.html',
                                      context)
        return {'content': html}
Пример #20
0
 def _validate_drop_item(self, item):
     """
     Validates `drop_item` parameters
     """
     zone = self._get_zone_by_uid(item['zone'])
     if not zone:
         raise JsonHandlerError(400, "Item zone data invalid.")
Пример #21
0
    def validate_form(self, data, suffix=''):
        """
        Validate edit form from studio.

        This will check if all the parameters set up for peer instruction question satisfy all the constrains defined
        by the algorithm. E.g. we need at least one seed for each option for simple algorithm.

        Args:
            data (dict): form data
            suffix (str): not sure

        Returns:
            dict: {success: true} if there is no problem

        Raises:
            JsonHandlerError: with 400 error code, if there is any problem. This is necessary for angular async form
                validation to be able to tell if the async validation success or failed
        """
        msg = validate_seeded_answers(data['seeds'], data['options'], data['algo'])
        options_msg = validate_options(data)
        if msg is None and options_msg is None:
            return {'success': 'true'}
        else:
            msg = msg if msg else {}
            options_msg = options_msg if options_msg else {}
            msg.update(options_msg)
            raise JsonHandlerError(400, msg)
Пример #22
0
    def publish_completion(self, data, suffix=''):  # pylint: disable=unused-argument
        """
        Allow the frontend app that's rendering this XBlock to mark it as
        completed when the user views it, if appropriate.

        Copied from lms.djangoapps.lms_xblock.mixin.LmsBlockMixin
        """
        completion_service = self.runtime.service(self, 'completion')
        if completion_service is None:
            raise JsonHandlerError(500, u"No completion service found")
        elif not completion_service.completion_tracking_enabled():
            raise JsonHandlerError(404, u"Completion tracking is not enabled and API calls are unexpected")
        if not completion_service.can_mark_block_complete_on_view(self):
            raise JsonHandlerError(400, u"Block not configured for completion on view.")
        self.runtime.publish(self, "completion", data)
        return {'result': 'ok'}
Пример #23
0
    def submit_answer(self, data, suffix=""):  # pylint: disable=unused-argument
        """
        Save and submit the student answer.
        Return information about correctness,
        and any applicable hints if enabled.
        """
        if self.max_attempts > 0 and self.student_attempts >= self.max_attempts:
            raise JsonHandlerError(400, "No more attempts remaining")

        if self._is_correct():
            raise JsonHandlerError(
                400, "You have already correctly answered this question.")

        self.student_answer = self._validated_student_answer_data(data)
        self.student_attempts += 1

        return self._student_view_user_state_data()
Пример #24
0
 def publish_completion(self, data, suffix=''):  # pylint: disable=unused-argument
     """
     Publish completion data from the front end.
     """
     completion_service = self.runtime.service(self, 'completion')
     if completion_service is None:
         raise JsonHandlerError(500, u"No completion service found")
     elif not completion_service.completion_tracking_enabled():
         raise JsonHandlerError(
             404,
             u"Completion tracking is not enabled and API calls are unexpected"
         )
     if not completion_service.can_mark_block_complete_on_view(self):
         raise JsonHandlerError(
             400, u"Block not configured for completion on view.")
     self.runtime.publish(self, "completion", data)
     return {'result': 'ok'}
 def _validate_drop_item(self, item):
     """
     Validates `drop_item` parameters. Assessment mode allows returning
     items to the bank, so validation is unnecessary.
     """
     if self.mode != Constants.ASSESSMENT_MODE:
         zone = self._get_zone_by_uid(item['zone'])
         if not zone:
             raise JsonHandlerError(400, "Item zone data invalid.")
 def raise_error(self, code, message):
     """
     Raises an error and marks the block with a simulated failed task dict.
     """
     self.last_export_result = {
         'error': message,
     }
     self.display_data = None
     raise JsonHandlerError(code, message)
Пример #27
0
 def _check_location_input(self, url, event_name, result):
     """
     Check whether the submitted location url resource is invalid. If true, raise an
     exception and return a HTTP status code for the error.
     """
     if not url:
         result['error'] = self.ugettext('Invalid location URL provided')
         tracker.emit(event_name, result)
         raise JsonHandlerError(400, result['error'])
Пример #28
0
 def clear_notification(self, data, suffix=''):
     """
     Clear out notifications for users who shared with this user on the last page load.
     Since more users might share with them while they're viewing the page, only remove the ones
     that they had at the time.
     """
     usernames = data.get('usernames')
     if not usernames:
         raise JsonHandlerError(400, "No usernames sent.")
     try:
         isinstance(usernames, list)
     except ValueError:
         raise JsonHandlerError(400, "Usernames must be a list.")
     Share.objects.filter(
         shared_with__username=self.current_user_key,
         shared_by__username__in=usernames,
         block_id=self.block_id,
     ).update(notified=True)
Пример #29
0
    def get_assessment_info(self, submission_uuid, _, suffix=''):  # pylint: disable=unused-argument
        """
        Returns a dict representation of a staff assessment in the form
        {
            'feedback': <submission-level feedback>
            'points_earned': <earned points>
            'points_possible': <maximum possible points>
            'criteria': list of {
                'name': <criterion name>
                'option': <name of selected option> This may be blank.
                          If so, there are no options defined for the given criterion and it is feedback-only
                'feedback': <feedback for criterion>
            }
        }
        """
        student_item_dict = self.get_student_item_dict()
        course_id = student_item_dict['course_id']
        item_id = student_item_dict['item_id']

        try:
            if self.is_team_assignment():
                workflow = TeamStaffWorkflow.get_team_staff_workflow(
                    course_id, item_id, submission_uuid)
            else:
                workflow = StaffWorkflow.get_staff_workflow(
                    course_id, item_id, submission_uuid)
        except StaffWorkflow.DoesNotExist as ex:
            msg = f"No gradeable submission found with uuid={submission_uuid} in course={course_id} item={item_id}"
            raise JsonHandlerError(404, msg) from ex

        if not workflow.assessment:
            return {}

        assessments = self.bulk_deep_fetch_assessments([workflow.assessment])
        if len(assessments) != 1 or submission_uuid not in assessments:
            log.error((
                "[%s] Error looking up assessments. Submission UUID = %s, "
                "Staff Workflow Id = %d, Staff Workflow Assessment = %s, Assessments = %s"
            ), item_id, submission_uuid, workflow.id, workflow.assessment,
                      assessments)
            raise JsonHandlerError(500, "Error looking up assessments")

        assessment = assessments[submission_uuid]
        return AssessmentSerializer(assessment).data
    def show_answer(self, data, suffix=''):
        """
        Returns correct answer in assessment mode.

        Raises:
             * JsonHandlerError with 400 error code in standard mode.
             * JsonHandlerError with 409 error code if there are still attempts left
        """
        if self.mode != Constants.ASSESSMENT_MODE:
            raise JsonHandlerError(
                400,
                self.i18n_service.gettext(
                    "show_answer handler should only be called for assessment mode"
                ))
        if self.attempts_remain:
            raise JsonHandlerError(
                409, self.i18n_service.gettext("There are attempts remaining"))

        return self._get_correct_state()