def test_start_greater_than_end(self):
     # Handle the special case in which the problem's release
     # date is after the problem's start date, and we've
     # specified only one deadline.
     resolve_dates("2040-01-01", "2013-01-02", [(None, "2014-08-01"),
                                                (None, None), (None, None)],
                   STUB_I18N)
Example #2
0
 def test_due_before_step_start(self):
     # Bugfix: this should not raise a validation error
     resolve_dates(
         None, "2001-01-01",
         [
             (None, None),
             ("2014-02-03", None),
             (None, None)
         ]
     )
Example #3
0
 def test_start_after_step_due(self):
     # Bugfix: this should not raise a validation error
     resolve_dates(
         "2040-01-01", None,
         [
             (None, "2014-08-01"),
             (None, None),
             (None, None)
         ]
     )
Example #4
0
 def test_start_after_step_due(self):
     # Bugfix: this should not raise a validation error
     resolve_dates(
         "2040-01-01", None,
         [
             (None, "2014-08-01"),
             (None, None),
             (None, None)
         ],
         STUB_I18N
     )
Example #5
0
 def test_due_before_step_start(self):
     # Bugfix: this should not raise a validation error
     resolve_dates(
         None, "2001-01-01",
         [
             (None, None),
             ("2014-02-03", None),
             (None, None)
         ],
         STUB_I18N
     )
Example #6
0
 def test_start_greater_than_end(self):
     # Handle the special case in which the problem's release
     # date is after the problem's start date, and we've
     # specified only one deadline.
     resolve_dates(
         "2040-01-01", "2013-01-02",
         [
             (None, "2014-08-01"),
             (None, None),
             (None, None)
         ]
     )
Example #7
0
    def is_closed(self, step=None):
        """
        Checks if the question is closed.

        Determines if the start date is in the future or the end date has
            passed.  Optionally limited to a particular step in the workflow.

        Kwargs:
            step (str): The step in the workflow to check.  Options are:
                None: check whether the problem as a whole is open.
                "submission": check whether the submission section is open.
                "peer-assessment": check whether the peer-assessment section is open.
                "self-assessment": check whether the self-assessment section is open.

        Returns:
            tuple of the form (is_closed, reason, date), where
                is_closed (bool): indicates whether the step is closed.
                reason (str or None): specifies the reason the step is closed ("start" or "due")
                date (datetime or None): is the start/due date.

        Examples:
            >>> is_closed()
            False, None, None
            >>> is_closed(step="submission")
            True, "due", datetime.datetime(2014, 3, 27, 22, 7, 38, 788861)
            >>> is_closed(step="self-assessment")
            True, "start", datetime.datetime(2014, 3, 27, 22, 7, 38, 788861)

        """
        submission_range = (self.start, self.submission_due)
        assessment_ranges = [
            (asmnt.get('start'), asmnt.get('due'))
            for asmnt in self.rubric_assessments
        ]

        # Resolve unspecified dates and date strings to datetimes
        start, due, date_ranges = resolve_dates(self.start, self.due, [submission_range] + assessment_ranges)

        # Based on the step, choose the date range to consider
        # We hard-code this to the submission -> peer -> self workflow for now;
        # later, we can revisit to make this more flexible.
        open_range = (start, due)
        if step == "submission":
            open_range = date_ranges[0]
        if step == "peer-assessment":
            open_range = date_ranges[1]
        if step == "self-assessment":
            open_range = date_ranges[2]

        # Check if we are in the open date range
        now = dt.datetime.now().replace(tzinfo=pytz.utc)

        if now < open_range[0]:
            return True, "start", open_range[0]
        elif now >= open_range[1]:
            return True, "due", open_range[1]
        else:
            return False, None, None
Example #8
0
    def editor_context(self):
        """
        Update the XBlock's XML.

        Args:
            data (dict): Data from the request; should have a value for the key 'xml'
                containing the XML for this XBlock.

        Keyword Arguments:
            suffix (str): Not used

        Returns:
            dict with keys
                'rubric' (unicode), 'prompt' (unicode), 'title' (unicode),
                'submission_start' (unicode),  'submission_due' (unicode),
                'assessments (dict)

        """
        # In the authoring GUI, date and time fields should never be null.
        # Therefore, we need to resolve all "default" dates to datetime objects
        # before displaying them in the editor.
        __, __, date_ranges = resolve_dates(
            self.start, self.due,
            [(self.submission_start, self.submission_due)] +
            [(asmnt.get('start'), asmnt.get('due')) for asmnt in self.valid_assessments],
            self._
        )

        submission_start, submission_due = date_ranges[0]
        assessments = self._assessments_editor_context(date_ranges[1:])
        editor_assessments_order = self._editor_assessments_order_context()

        # Every rubric requires one criterion. If there is no criteria
        # configured for the XBlock, return one empty default criterion, with
        # an empty default option.
        criteria = copy.deepcopy(self.rubric_criteria_with_labels)
        if not criteria:
            criteria = self.DEFAULT_CRITERIA

        return {
            'prompt': self.prompt,
            'title': self.title,
            'submission_due': submission_due,
            'submission_start': submission_start,
            'assessments': assessments,
            'criteria': criteria,
            'feedbackprompt': self.rubric_feedback_prompt,
            'allow_file_upload': self.allow_file_upload,
            'leaderboard_show': self.leaderboard_show,
            'editor_assessments_order': [
                make_django_template_key(asmnt)
                for asmnt in editor_assessments_order
            ],
        }
Example #9
0
def validate_dates(start, end, date_ranges):
    """
    Check that start and due dates are valid.

    Args:
        start (str): ISO-formatted date string indicating when the problem opens.
        end (str): ISO-formatted date string indicating when the problem closes.
        date_ranges (list of tuples): List of (start, end) pair for each submission / assessment.

    Returns:
        tuple (is_valid, msg) where
            is_valid is a boolean indicating whether the assessment is semantically valid
            and msg describes any validation errors found.
    """
    try:
        resolve_dates(start, end, date_ranges)
    except (DateValidationError, InvalidDateFormat) as ex:
        return (False, ex.message)
    else:
        return (True, u'')
Example #10
0
def validate_dates(start, end, date_ranges, _):
    """
    Check that start and due dates are valid.

    Args:
        start (str): ISO-formatted date string indicating when the problem opens.
        end (str): ISO-formatted date string indicating when the problem closes.
        date_ranges (list of tuples): List of (start, end) pair for each submission / assessment.
        _ (function): The service function used to get the appropriate i18n text

    Returns:
        tuple (is_valid, msg) where
            is_valid is a boolean indicating whether the assessment is semantically valid
            and msg describes any validation errors found.
    """
    try:
        resolve_dates(start, end, date_ranges, _)
    except (DateValidationError, InvalidDateFormat) as ex:
        return False, six.text_type(ex)
    else:
        return True, u''
    def test_resolve_dates(self, data):

        # Test data provides indices into our date dictionaries
        resolved_start, resolved_end, resolved_ranges = resolve_dates(
            self.DATE_STRINGS[data['start']], self.DATE_STRINGS[data['end']],
            [(self.DATE_STRINGS[start], self.DATE_STRINGS[end])
             for start, end in tuple(data['date_ranges'])], STUB_I18N)
        self.assertEqual(resolved_start, self.DATES[data['resolved_start']])
        self.assertEqual(resolved_end, self.DATES[data['resolved_end']])
        self.assertEqual(resolved_ranges,
                         [(self.DATES[start], self.DATES[end])
                          for start, end in tuple(data['resolved_ranges'])])
Example #12
0
def validate_dates(start, end, date_ranges, _):
    """
    Check that start and due dates are valid.

    Args:
        start (str): ISO-formatted date string indicating when the problem opens.
        end (str): ISO-formatted date string indicating when the problem closes.
        date_ranges (list of tuples): List of (start, end) pair for each submission / assessment.
        _ (function): The service function used to get the appropriate i18n text

    Returns:
        tuple (is_valid, msg) where
            is_valid is a boolean indicating whether the assessment is semantically valid
            and msg describes any validation errors found.
    """
    try:
        resolve_dates(start, end, date_ranges, _)
    except (DateValidationError, InvalidDateFormat) as ex:
        return False, unicode(ex)
    else:
        return True, u''
Example #13
0
    def test_min_start_date(self):
        # Start date should resolve to the min of all start dates
        # See the detailed comment in the docstring of `resolve_dates`
        # for the reasoning behind this.
        resolved_start, __, __ = resolve_dates("2013-01-01", None, [
            ("1999-01-01", "1999-02-03"),
            ("2003-01-01", "2003-02-03"),
            ("3234-01-01", "3234-02-03"),
        ])

        # Should default to the min of all specified start dates
        self.assertEqual(
            resolved_start,
            datetime.datetime(1999, 1, 1).replace(tzinfo=pytz.UTC))
Example #14
0
    def test_max_due_date(self):
        # End date should resolve to the max of all end dates
        # See the detailed comment in the docstring of `resolve_dates`
        # for the reasoning behind this.
        __, resolved_end, __ = resolve_dates(None, "2013-01-01", [
            ("1999-01-01", "1999-02-03"),
            ("2003-01-01", "2003-02-03"),
            ("3234-01-01", "3234-02-03"),
        ])

        # Should default to the max of all specified end dates
        self.assertEqual(
            resolved_end,
            datetime.datetime(3234, 2, 3).replace(tzinfo=pytz.UTC))
Example #15
0
    def test_max_due_date(self):
        # End date should resolve to the max of all end dates
        # See the detailed comment in the docstring of `resolve_dates`
        # for the reasoning behind this.
        __, resolved_end, __ = resolve_dates(
            None, "2013-01-01",
            [
                ("1999-01-01", "1999-02-03"),
                ("2003-01-01", "2003-02-03"),
                ("3234-01-01", "3234-02-03"),
            ]
        )

        # Should default to the max of all specified end dates
        self.assertEqual(
            resolved_end,
            datetime.datetime(3234, 2, 3).replace(tzinfo=pytz.UTC)
        )
Example #16
0
    def test_min_start_date(self):
        # Start date should resolve to the min of all start dates
        # See the detailed comment in the docstring of `resolve_dates`
        # for the reasoning behind this.
        resolved_start, __, __ = resolve_dates(
            "2013-01-01", None,
            [
                ("1999-01-01", "1999-02-03"),
                ("2003-01-01", "2003-02-03"),
                ("3234-01-01", "3234-02-03"),
            ]
        )

        # Should default to the min of all specified start dates
        self.assertEqual(
            resolved_start,
            datetime.datetime(1999, 1, 1).replace(tzinfo=pytz.UTC)
        )
Example #17
0
    def test_resolve_dates(self, data):

        # Test data provides indices into our date dictionaries
        resolved_start, resolved_end, resolved_ranges = resolve_dates(
            self.DATE_STRINGS[data['start']],
            self.DATE_STRINGS[data['end']],
            [
                (self.DATE_STRINGS[start], self.DATE_STRINGS[end])
                for start, end in tuple(data['date_ranges'])
            ]
        )
        self.assertEqual(resolved_start, self.DATES[data['resolved_start']])
        self.assertEqual(resolved_end, self.DATES[data['resolved_end']])
        self.assertEqual(
            resolved_ranges,
            [
                (self.DATES[start], self.DATES[end])
                for start, end in tuple(data['resolved_ranges'])
            ]
        )
Example #18
0
    def is_closed(self, step=None, course_staff=None):
        """
        Checks if the question is closed.

        Determines if the start date is in the future or the end date has
            passed.  Optionally limited to a particular step in the workflow.

        Start/due dates do NOT apply to course staff, since course staff may need to get to
        the peer grading step AFTER the submission deadline has passed.
        This may not be necessary when we implement a grading interface specifically for course staff.

        Keyword Arguments:
            step (str): The step in the workflow to check.  Options are:
                None: check whether the problem as a whole is open.
                "submission": check whether the submission section is open.
                "peer-assessment": check whether the peer-assessment section is open.
                "self-assessment": check whether the self-assessment section is open.

            course_staff (bool): Whether to treat the user as course staff (disable start/due dates).
                If not specified, default to the current user's status.

        Returns:
            tuple of the form (is_closed, reason, start_date, due_date), where
                is_closed (bool): indicates whether the step is closed.
                reason (str or None): specifies the reason the step is closed ("start" or "due")
                start_date (datetime): is the start date of the step/problem.
                due_date (datetime): is the due date of the step/problem.

        Examples:
            >>> is_closed()
            False, None, datetime.datetime(2014, 3, 27, 22, 7, 38, 788861),
            datetime.datetime(2015, 3, 27, 22, 7, 38, 788861)
            >>> is_closed(step="submission")
            True, "due", datetime.datetime(2014, 3, 27, 22, 7, 38, 788861),
            datetime.datetime(2015, 3, 27, 22, 7, 38, 788861)
            >>> is_closed(step="self-assessment")
            True, "start", datetime.datetime(2014, 3, 27, 22, 7, 38, 788861),
            datetime.datetime(2015, 3, 27, 22, 7, 38, 788861)

        """
        submission_range = (self.submission_start, self.submission_due)
        assessment_ranges = [
            (asmnt.get('start'), asmnt.get('due'))
            for asmnt in self.valid_assessments
        ]

        # Resolve unspecified dates and date strings to datetimes
        start, due, date_ranges = resolve_dates(
            self.start, self.due, [submission_range] + assessment_ranges, self._
        )

        open_range = (start, due)
        assessment_steps = self.assessment_steps
        if step == 'submission':
            open_range = date_ranges[0]
        elif step in assessment_steps:
            step_index = assessment_steps.index(step)
            open_range = date_ranges[1 + step_index]

        # Course staff always have access to the problem
        if course_staff is None:
            course_staff = self.is_course_staff
        if course_staff:
            return False, None, DISTANT_PAST, DISTANT_FUTURE

        if self.is_beta_tester:
            beta_start = self._adjust_start_date_for_beta_testers(open_range[0])
            open_range = (beta_start, open_range[1])

        # Check if we are in the open date range
        now = dt.datetime.utcnow().replace(tzinfo=pytz.utc)

        if now < open_range[0]:
            return True, "start", open_range[0], open_range[1]
        elif now >= open_range[1]:
            return True, "due", open_range[0], open_range[1]
        else:
            return False, None, open_range[0], open_range[1]
Example #19
0
    def is_closed(self, step=None, course_staff=None):
        """
        Checks if the question is closed.

        Determines if the start date is in the future or the end date has
            passed.  Optionally limited to a particular step in the workflow.

        Start/due dates do NOT apply to course staff, since course staff may need to get to
        the peer grading step AFTER the submission deadline has passed.
        This may not be necessary when we implement a grading interface specifically for course staff.

        Kwargs:
            step (str): The step in the workflow to check.  Options are:
                None: check whether the problem as a whole is open.
                "submission": check whether the submission section is open.
                "peer-assessment": check whether the peer-assessment section is open.
                "self-assessment": check whether the self-assessment section is open.

            course_staff (bool): Whether to treat the user as course staff (disable start/due dates).
                If not specified, default to the current user's status.

        Returns:
            tuple of the form (is_closed, reason, start_date, due_date), where
                is_closed (bool): indicates whether the step is closed.
                reason (str or None): specifies the reason the step is closed ("start" or "due")
                start_date (datetime): is the start date of the step/problem.
                due_date (datetime): is the due date of the step/problem.

        Examples:
            >>> is_closed()
            False, None, datetime.datetime(2014, 3, 27, 22, 7, 38, 788861), datetime.datetime(2015, 3, 27, 22, 7, 38, 788861)
            >>> is_closed(step="submission")
            True, "due", datetime.datetime(2014, 3, 27, 22, 7, 38, 788861), datetime.datetime(2015, 3, 27, 22, 7, 38, 788861)
            >>> is_closed(step="self-assessment")
            True, "start", datetime.datetime(2014, 3, 27, 22, 7, 38, 788861), datetime.datetime(2015, 3, 27, 22, 7, 38, 788861)

        """
        submission_range = (self.submission_start, self.submission_due)
        assessment_ranges = [
            (asmnt.get('start'), asmnt.get('due'))
            for asmnt in self.valid_assessments
        ]

        # Resolve unspecified dates and date strings to datetimes
        start, due, date_ranges = resolve_dates(
            self.start, self.due, [submission_range] + assessment_ranges
        )

        open_range = (start, due)
        assessment_steps = self.assessment_steps
        if step == 'submission':
            open_range = date_ranges[0]
        elif step in assessment_steps:
            step_index = assessment_steps.index(step)
            open_range = date_ranges[1 + step_index]

        # Course staff always have access to the problem
        if course_staff is None:
            course_staff = self.is_course_staff
        if course_staff:
            return False, None, DISTANT_PAST, DISTANT_FUTURE

        # Check if we are in the open date range
        now = dt.datetime.utcnow().replace(tzinfo=pytz.utc)

        if now < open_range[0]:
            return True, "start", open_range[0], open_range[1]
        elif now >= open_range[1]:
            return True, "due", open_range[0], open_range[1]
        else:
            return False, None, open_range[0], open_range[1]
Example #20
0
    def editor_context(self):
        """
        Update the XBlock's XML.

        Args:
            data (dict): Data from the request; should have a value for the key 'xml'
                containing the XML for this XBlock.

        Keyword Arguments:
            suffix (str): Not used

        Returns:
            dict with keys
                'rubric' (unicode), 'prompt' (unicode), 'title' (unicode),
                'submission_start' (unicode),  'submission_due' (unicode),
                'assessments (dict)

        """
        # In the authoring GUI, date and time fields should never be null.
        # Therefore, we need to resolve all "default" dates to datetime objects
        # before displaying them in the editor.
        __, __, date_ranges = resolve_dates(
            self.start, self.due,
            [(self.submission_start, self.submission_due)] +
            [(asmnt.get('start'), asmnt.get('due'))
             for asmnt in self.valid_assessments], self._)

        submission_start, submission_due = date_ranges[0]
        assessments = self._assessments_editor_context(date_ranges[1:])
        self.editor_assessments_order = self._editor_assessments_order_context(
        )

        # Every rubric requires one criterion. If there is no criteria
        # configured for the XBlock, return one empty default criterion, with
        # an empty default option.
        criteria = copy.deepcopy(self.rubric_criteria_with_labels)
        if not criteria:
            criteria = self.DEFAULT_CRITERIA

        # To maintain backwards compatibility, if there is no
        # feedback_default_text configured for the xblock, use the default text
        feedback_default_text = copy.deepcopy(
            self.rubric_feedback_default_text)
        if not feedback_default_text:
            feedback_default_text = DEFAULT_RUBRIC_FEEDBACK_TEXT
        course_id = self.location.course_key if hasattr(self,
                                                        'location') else None

        return {
            'prompts':
            self.prompts,
            'prompts_type':
            self.prompts_type,
            'title':
            self.title,
            'submission_due':
            submission_due,
            'submission_start':
            submission_start,
            'assessments':
            assessments,
            'criteria':
            criteria,
            'feedbackprompt':
            self.rubric_feedback_prompt,
            'feedback_default_text':
            feedback_default_text,
            'text_response':
            self.text_response if self.text_response else '',
            'file_upload_response':
            self.file_upload_response if self.file_upload_response else '',
            'necessity_options':
            self.NECESSITY_OPTIONS,
            'file_upload_type':
            self.file_upload_type,
            'white_listed_file_types':
            self.white_listed_file_types_string,
            'allow_latex':
            self.allow_latex,
            'leaderboard_show':
            self.leaderboard_show,
            'editor_assessments_order': [
                make_django_template_key(asmnt)
                for asmnt in self.editor_assessments_order
            ],
            'base_asset_url':
            self._get_base_url_path_for_course_assets(course_id),
            'is_released':
            self.is_released(),
        }
Example #21
0
    def editor_context(self):
        """
        Update the XBlock's XML.

        Args:
            data (dict): Data from the request; should have a value for the key 'xml'
                containing the XML for this XBlock.

        Keyword Arguments:
            suffix (str): Not used

        Returns:
            dict with keys
                'rubric' (unicode), 'prompt' (unicode), 'title' (unicode),
                'submission_start' (unicode),  'submission_due' (unicode),
                'assessments (dict)

        """
        # In the authoring GUI, date and time fields should never be null.
        # Therefore, we need to resolve all "default" dates to datetime objects
        # before displaying them in the editor.
        __, __, date_ranges = resolve_dates(
            self.start, self.due,
            [(self.submission_start, self.submission_due)] +
            [(asmnt.get('start'), asmnt.get('due'))
             for asmnt in self.valid_assessments], self._)

        submission_start, submission_due = date_ranges[0]
        assessments = self._assessments_editor_context(date_ranges[1:])
        editor_assessments_order = self._editor_assessments_order_context()

        # Every rubric requires one criterion. If there is no criteria
        # configured for the XBlock, return one empty default criterion, with
        # an empty default option.
        criteria = copy.deepcopy(self.rubric_criteria_with_labels)
        if not criteria:
            criteria = self.DEFAULT_CRITERIA

        return {
            'prompt':
            self.prompt,
            'title':
            self.title,
            'submission_due':
            submission_due,
            'submission_start':
            submission_start,
            'assessments':
            assessments,
            'criteria':
            criteria,
            'feedbackprompt':
            self.rubric_feedback_prompt,
            'allow_file_upload':
            self.allow_file_upload,
            'leaderboard_show':
            self.leaderboard_show,
            'editor_assessments_order': [
                make_django_template_key(asmnt)
                for asmnt in editor_assessments_order
            ],
        }
Example #22
0
    def editor_context(self):
        """
        Update the XBlock's XML.

        Args:
            data (dict): Data from the request; should have a value for the key 'xml'
                containing the XML for this XBlock.

        Keyword Arguments:
            suffix (str): Not used

        Returns:
            dict with keys
                'rubric' (unicode), 'prompt' (unicode), 'title' (unicode),
                'submission_start' (unicode),  'submission_due' (unicode),
                'assessments (dict)

        """
        # In the authoring GUI, date and time fields should never be null.
        # Therefore, we need to resolve all "default" dates to datetime objects
        # before displaying them in the editor.
        __, __, date_ranges = resolve_dates(
            self.start, self.due,
            [(self.submission_start, self.submission_due)] +
            [(asmnt.get('start'), asmnt.get('due')) for asmnt in self.valid_assessments],
            self._
        )

        submission_start, submission_due = date_ranges[0]
        assessments = self._assessments_editor_context(date_ranges[1:])
        self.editor_assessments_order = self._editor_assessments_order_context()

        # Every rubric requires one criterion. If there is no criteria
        # configured for the XBlock, return one empty default criterion, with
        # an empty default option.
        criteria = copy.deepcopy(self.rubric_criteria_with_labels)
        if not criteria:
            criteria = self.DEFAULT_CRITERIA

        # To maintain backwards compatibility, if there is no
        # feedback_default_text configured for the xblock, use the default text
        feedback_default_text = copy.deepcopy(self.rubric_feedback_default_text)
        if not feedback_default_text:
            feedback_default_text = DEFAULT_RUBRIC_FEEDBACK_TEXT
        course_id = self.location.course_key if hasattr(self, 'location') else None

        return {
            'prompts': self.prompts,
            'prompts_type': self.prompts_type,
            'title': self.title,
            'submission_due': submission_due,
            'submission_start': submission_start,
            'assessments': assessments,
            'criteria': criteria,
            'feedbackprompt': self.rubric_feedback_prompt,
            'feedback_default_text': feedback_default_text,
            'text_response': self.text_response if self.text_response  else '',
            'file_upload_response': self.file_upload_response if self.file_upload_response else '',
            'necessity_options': self.NECESSITY_OPTIONS,
            'file_upload_type': self.file_upload_type,
            'white_listed_file_types': self.white_listed_file_types_string,
            'allow_latex': self.allow_latex,
            'leaderboard_show': self.leaderboard_show,
            'editor_assessments_order': [
                make_django_template_key(asmnt)
                for asmnt in self.editor_assessments_order
            ],
            'base_asset_url': self._get_base_url_path_for_course_assets(course_id),
            'is_released': self.is_released(),
        }
Example #23
0
    def editor_context(self):
        """
        Update the XBlock's XML.

        Returns:
            dict with keys
                'rubric' (unicode), 'prompt' (unicode), 'title' (unicode),
                'submission_start' (unicode),  'submission_due' (unicode),
                'assessments (dict)

        """
        # In the authoring GUI, date and time fields should never be null.
        # Therefore, we need to resolve all "default" dates to datetime objects
        # before displaying them in the editor.
        __, __, date_ranges = resolve_dates(  # pylint: disable=redeclared-assigned-name
            self.start, self.due,
            [(self.submission_start, self.submission_due)] +
            [(asmnt.get('start'), asmnt.get('due'))
             for asmnt in self.valid_assessments], self._)

        submission_start, submission_due = date_ranges[0]
        assessments = self._assessments_editor_context(date_ranges[1:])
        self.editor_assessments_order = self._editor_assessments_order_context(
        )

        # Every rubric requires one criterion. If there is no criteria
        # configured for the XBlock, return one empty default criterion, with
        # an empty default option.
        criteria = copy.deepcopy(self.rubric_criteria_with_labels)
        if not criteria:
            criteria = self.DEFAULT_CRITERIA

        # To maintain backwards compatibility, if there is no
        # feedback_default_text configured for the xblock, use the default text
        feedback_default_text = copy.deepcopy(
            self.rubric_feedback_default_text)
        if not feedback_default_text:
            feedback_default_text = DEFAULT_RUBRIC_FEEDBACK_TEXT
        course_id = self.location.course_key if hasattr(self,
                                                        'location') else None

        # If allowed file types haven't been explicitly set, load from a preset
        white_listed_file_types = self.get_allowed_file_types_or_preset()
        white_listed_file_types_string = ','.join(
            white_listed_file_types) if white_listed_file_types else ''

        return {
            'prompts':
            self.prompts,
            'prompts_type':
            self.prompts_type,
            'title':
            self.title,
            'submission_due':
            submission_due,
            'submission_start':
            submission_start,
            'assessments':
            assessments,
            'criteria':
            criteria,
            'feedbackprompt':
            self.rubric_feedback_prompt,
            'feedback_default_text':
            feedback_default_text,
            'text_response':
            self.text_response if self.text_response else '',
            'text_response_editor':
            self.text_response_editor if self.text_response_editor else 'text',
            'file_upload_response':
            self.file_upload_response if self.file_upload_response else '',
            'necessity_options':
            self.NECESSITY_OPTIONS,
            'available_editor_options':
            self.AVAILABLE_EDITOR_OPTIONS,
            'file_upload_type':
            self.file_upload_type,
            'allow_multiple_files':
            self.allow_multiple_files,
            'white_listed_file_types':
            white_listed_file_types_string,
            'allow_latex':
            self.allow_latex,
            'leaderboard_show':
            self.leaderboard_show,
            'editor_assessments_order': [
                make_django_template_key(asmnt)
                for asmnt in self.editor_assessments_order
            ],
            'teams_feature_enabled':
            self.team_submissions_enabled,
            'teams_enabled':
            self.teams_enabled,
            'base_asset_url':
            self._get_base_url_path_for_course_assets(course_id),
            'is_released':
            self.is_released(),
            'teamsets':
            self.get_teamsets(course_id),
            'selected_teamset_id':
            self.selected_teamset_id,
            'show_rubric_during_response':
            self.show_rubric_during_response
        }