Skip to content

Commit

Permalink
fix: date config for mfe (#2176)
Browse files Browse the repository at this point in the history
* fix: date config should work correctly on the mfe

* chore: version
  • Loading branch information
jansenk committed Feb 14, 2024
1 parent 7c33111 commit 6556a53
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 66 deletions.
129 changes: 68 additions & 61 deletions openassessment/xblock/ui_mixins/mfe/ora_config_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
These are the response shapes that power the MFE implementation of the ORA UI.
"""
# pylint: disable=abstract-method

from rest_framework.serializers import (
BooleanField,
DateTimeField,
Expand All @@ -13,6 +12,8 @@
CharField,
SerializerMethodField,
)

from openassessment.xblock.utils.resolve_dates import DISTANT_FUTURE, DISTANT_PAST
from openassessment.xblock.apis.workflow_api import WorkflowStep

from openassessment.xblock.ui_mixins.mfe.serializer_utils import (
Expand Down Expand Up @@ -61,14 +62,31 @@ def get_teamsetName(self, block):


class SubmissionConfigSerializer(Serializer):
startDatetime = DateTimeField(source="submission_start")
endDatetime = DateTimeField(source="submission_due")
startDatetime = SerializerMethodField()
endDatetime = SerializerMethodField()
_date_range = None

textResponseConfig = TextResponseConfigSerializer(source="*")
fileResponseConfig = FileResponseConfigSerializer(source="*")

teamsConfig = TeamsConfigSerializer(source="*")

def _get_start_end_date(self, xblock):
""" Cached calculation of step due dates """
if self._date_range is None:
_, _, start, end = xblock.is_closed(step='submission')
self._date_range = (
start.isoformat() if start > DISTANT_PAST else None,
end.isoformat() if end < DISTANT_FUTURE else None,
)
return self._date_range

def get_startDatetime(self, xblock):
return self._get_start_end_date(xblock)[0]

def get_endDatetime(self, xblock):
return self._get_start_end_date(xblock)[1]


class RubricFeedbackConfigSerializer(Serializer):
description = CharField(source="rubric_feedback_prompt") # is this this field?
Expand Down Expand Up @@ -111,43 +129,14 @@ class RubricConfigSerializer(Serializer):
)


class SelfSettingsSerializer(Serializer):
required = BooleanField(default=True)

startDatetime = DateTimeField(source="start")
endDatetime = DateTimeField(source="due")


class StudentTrainingSettingsSerializer(Serializer):
required = BooleanField(default=True)

numberOfExamples = SerializerMethodField(source="*", default=0)

def get_numberOfExamples(self, assessment):
return len(assessment["examples"])


class PeerSettingsSerializer(Serializer):
required = BooleanField(default=True)

startDatetime = DateTimeField(source="start")
endDatetime = DateTimeField(source="due")

minNumberToGrade = IntegerField(source="must_grade")
minNumberToBeGradedBy = IntegerField(source="must_be_graded_by")

enableFlexibleGrading = BooleanField(
source="enable_flexible_grading", required=False
)


class AssessmentStepSettingsSerializer(Serializer):
"""
Generic Assessments step, where we just need to know if the step is
required given the ora.rubric_assessments source.
"""

required = BooleanField(default=True)
STEP_NAME = None # Overridden by child classes

def _get_step(self, rubric_assessments, step_name):
"""Get the assessment step config for a given step_name"""
Expand All @@ -156,42 +145,60 @@ def _get_step(self, rubric_assessments, step_name):
return step
return None

def __init__(self, *args, **kwargs):
self.step_name = kwargs.pop("step_name")
super().__init__(*args, **kwargs)

def to_representation(self, instance):
assessment_step = self._get_step(instance, self.step_name)

# Special handling for the peer step which includes extra fields
if assessment_step and self.step_name == "peer-assessment":
return PeerSettingsSerializer(assessment_step).data
elif assessment_step and self.step_name == "self-assessment":
return SelfSettingsSerializer(assessment_step).data
elif assessment_step and self.step_name == "student-training":
return StudentTrainingSettingsSerializer(assessment_step).data

# pylint: disable=arguments-renamed
def to_representation(self, xblock):
assessment_step = self._get_step(xblock.rubric_assessments, self.STEP_NAME)
# If we didn't find a step, it is not required
if assessment_step is None:
assessment_step = {"required": False}
return {"required": False}

assessment_step = dict(assessment_step)
# Add overridden start and due dates for peer assessment and self assessment
if self.STEP_NAME in ('peer-assessment', 'self-assessment'):
_, _, start, due = xblock.is_closed(step=self.STEP_NAME)
assessment_step['start'] = start.isoformat()
assessment_step['due'] = due.isoformat()

return super().to_representation(assessment_step)


class AssessmentStepsSettingsSerializer(Serializer):
studentTraining = AssessmentStepSettingsSerializer(
step_name="student-training", source="rubric_assessments"
)
peer = AssessmentStepSettingsSerializer(
step_name="peer-assessment", source="rubric_assessments"
class SelfSettingsSerializer(AssessmentStepSettingsSerializer):
STEP_NAME = 'self-assessment'
startDatetime = DateTimeField(source='start')
endDatetime = DateTimeField(source='due')


class StudentTrainingSettingsSerializer(AssessmentStepSettingsSerializer):
STEP_NAME = 'student-training'
numberOfExamples = SerializerMethodField(source="*", default=0)

def get_numberOfExamples(self, assessment):
return len(assessment["examples"])


class PeerSettingsSerializer(AssessmentStepSettingsSerializer):
STEP_NAME = 'peer-assessment'
minNumberToGrade = IntegerField(source="must_grade")
minNumberToBeGradedBy = IntegerField(source="must_be_graded_by")

startDatetime = DateTimeField(source='start')
endDatetime = DateTimeField(source='due')

enableFlexibleGrading = BooleanField(
source="enable_flexible_grading", required=False
)


class StaffSettingsSerializer(AssessmentStepSettingsSerializer):
STEP_NAME = 'staff-assessment'


class AssessmentStepsSettingsSerializer(Serializer):
studentTraining = StudentTrainingSettingsSerializer(source="*")
peer = PeerSettingsSerializer(source="*")
# Workaround to allow reserved keyword in serializer key
vars()["self"] = AssessmentStepSettingsSerializer(
step_name="self-assessment", source="rubric_assessments"
)
staff = AssessmentStepSettingsSerializer(
step_name="staff-assessment", source="rubric_assessments"
)
vars()["self"] = SelfSettingsSerializer(source='*')
staff = StaffSettingsSerializer(source='*')


class AssessmentStepsSerializer(Serializer):
Expand Down
12 changes: 7 additions & 5 deletions openassessment/xblock/ui_mixins/mfe/test_serializers.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""
Tests for data layer of ORA XBlock
"""

from datetime import datetime
from unittest.mock import MagicMock
import ddt
import pytz


from openassessment.xblock.ui_mixins.mfe.ora_config_serializer import (
Expand Down Expand Up @@ -36,8 +37,9 @@ def test_dates(self, xblock):
submission_config = SubmissionConfigSerializer(xblock).data

# Then I get the expected values
expected_start = xblock.submission_start
expected_due = xblock.submission_due
expected_start = pytz.utc.localize(datetime.fromisoformat(xblock.submission_start)).isoformat()
expected_due = pytz.utc.localize(datetime.fromisoformat(xblock.submission_due)).isoformat()

self.assertEqual(submission_config["startDatetime"], expected_start)
self.assertEqual(submission_config["endDatetime"], expected_due)

Expand Down Expand Up @@ -291,8 +293,8 @@ def test_peer_settings(self, xblock):
@scenario("data/dates_scenario.xml")
def test_peer_dates(self, xblock):
# Given a basic setup
expected_start = "2015-01-02T00:00:00"
expected_due = "2015-04-01T00:00:00"
expected_start = "2015-01-02T00:00:00+00:00"
expected_due = "2015-04-01T00:00:00+00:00"

# When I ask for peer step config
peer_config = AssessmentStepsSerializer(xblock).data["settings"][
Expand Down

0 comments on commit 6556a53

Please sign in to comment.