Skip to content

Commit

Permalink
feat: ora date config reflected in dates tab (openedx#33118)
Browse files Browse the repository at this point in the history
* feat: ora date config reflected in dates tab

* docs: update docstrings

* style: quality

* feat: Upgrade Python dependency ora2 (openedx#33119)

temp upgrade so tests pass

Commit generated by workflow `openedx/edx-platform/.github/workflows/upgrade-one-python-dependency.yml@refs/heads/master`

Co-authored-by: jansenk <[email protected]>

* fix: unbound variable

* fix: don't show dates for steps with no concept of due

* feat: Upgrade Python dependency ora2 (openedx#33176)

bump to ora version to include ora date config changes

Commit generated by workflow `openedx/edx-platform/.github/workflows/upgrade-one-python-dependency.yml@refs/heads/master`

Co-authored-by: jansenk <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: jansenk <[email protected]>
  • Loading branch information
3 people authored Sep 5, 2023
1 parent 9bae5cd commit cac1159
Show file tree
Hide file tree
Showing 8 changed files with 357 additions and 74 deletions.
199 changes: 131 additions & 68 deletions lms/djangoapps/courseware/courses.py
Original file line number Diff line number Diff line change
Expand Up @@ -629,78 +629,141 @@ def get_course_assignments(course_key, user, include_access=False): # lint-amne
subsection_key, title, url, due, contains_gated_content,
complete, past_due, assignment_type, None, first_component_block_id
))
assignments.extend(get_ora_blocks_as_assignments(block_data, subsection_key))
return assignments


def get_ora_blocks_as_assignments(block_data, subsection_key):
"""
Given a subsection key, navigate through descendents and find open response assessments.
For each graded ORA, return a list of "Assignment" tuples that map to the individual steps
of the ORA
"""
ora_assignments = []
descendents = block_data.get_children(subsection_key)
while descendents:
descendent = descendents.pop()
descendents.extend(block_data.get_children(descendent))
if block_data.get_xblock_field(descendent, 'category', None) == 'openassessment':
ora_assignments.extend(get_ora_as_assignments(block_data, descendent))
return ora_assignments


def get_ora_as_assignments(block_data, ora_block):
"""
Given an individual ORA, return the list of individual ORA steps as Assignment tuples
"""
graded = block_data.get_xblock_field(ora_block, 'graded', False)
has_score = block_data.get_xblock_field(ora_block, 'has_score', False)
weight = block_data.get_xblock_field(ora_block, 'weight', 1)

if not (graded and has_score and (weight is None or weight > 0)):
return []

# Load all dates for ORA blocks as separate assignments
descendents = block_data.get_children(subsection_key)
while descendents:
descendent = descendents.pop()
descendents.extend(block_data.get_children(descendent))
if block_data.get_xblock_field(descendent, 'category', None) == 'openassessment':
graded = block_data.get_xblock_field(descendent, 'graded', False)
has_score = block_data.get_xblock_field(descendent, 'has_score', False)
weight = block_data.get_xblock_field(descendent, 'weight', 1)
if not (graded and has_score and (weight is None or weight > 0)):
continue

all_assessments = [{
'name': 'submission',
'due': block_data.get_xblock_field(descendent, 'submission_due'),
'start': block_data.get_xblock_field(descendent, 'submission_start'),
'required': True
}]

valid_assessments = block_data.get_xblock_field(descendent, 'valid_assessments')
if valid_assessments:
all_assessments.extend(valid_assessments)

assignment_type = block_data.get_xblock_field(descendent, 'format', None)
complete = is_block_structure_complete_for_assignments(block_data, descendent)

block_title = block_data.get_xblock_field(descendent, 'title', _('Open Response Assessment'))

for assessment in all_assessments:
due = parse_date(assessment.get('due')).replace(tzinfo=pytz.UTC) if assessment.get('due') else None # lint-amnesty, pylint: disable=line-too-long
if due is None:
continue

assessment_name = assessment.get('name')
if assessment_name is None:
continue

if assessment_name == 'self-assessment':
assessment_type = _("Self Assessment")
elif assessment_name == 'peer-assessment':
assessment_type = _("Peer Assessment")
elif assessment_name == 'staff-assessment':
assessment_type = _("Staff Assessment")
elif assessment_name == 'submission':
assessment_type = _("Submission")
else:
assessment_type = assessment_name
title = f"{block_title} ({assessment_type})"
url = ''
start = parse_date(assessment.get('start')).replace(tzinfo=pytz.UTC) if assessment.get('start') else None # lint-amnesty, pylint: disable=line-too-long
assignment_released = not start or start < now
if assignment_released:
url = reverse('jump_to', args=[course_key, descendent])

past_due = not complete and due and due < now
first_component_block_id = str(descendent)
assignments.append(_Assignment(
descendent,
title,
url,
due,
False,
complete,
past_due,
assignment_type,
_("Open Response Assessment due dates are set by your instructor and can't be shifted."),
first_component_block_id,
))
complete = is_block_structure_complete_for_assignments(block_data, ora_block)

# Put all ora 'steps' (response, peer, self, etc) into a single list in a common format
all_assessments = [{
'name': 'submission',
'due': block_data.get_xblock_field(ora_block, 'submission_due'),
'start': block_data.get_xblock_field(ora_block, 'submission_start'),
'required': True
}]
valid_assessments = block_data.get_xblock_field(ora_block, 'valid_assessments')
if valid_assessments:
all_assessments.extend(valid_assessments)

# Loop through all steps and construct Assignment tuples from them
assignments = []
for assessment in all_assessments:
assignment = _ora_assessment_to_assignment(
block_data,
ora_block,
complete,
assessment
)
if assignment is not None:
assignments.append(assignment)
return assignments


def _ora_assessment_to_assignment(
block_data,
ora_block,
complete,
assessment
):
"""
Create an assignment from an ORA assessment dict
"""
date_config_type = block_data.get_xblock_field(ora_block, 'date_config_type', 'manual')
assignment_type = block_data.get_xblock_field(ora_block, 'format', None)
block_title = block_data.get_xblock_field(ora_block, 'title', _('Open Response Assessment'))
course_key = block_data.root_block_usage_key

# Steps with no "due" date, like staff or training, should not show up here
assessment_step_due = assessment.get('start')
if assessment_step_due is None:
return None

if date_config_type == 'subsection':
assessment_start = block_data.get_xblock_field(ora_block, 'start')
assessment_due = block_data.get_xblock_field(ora_block, 'due')
extra_info = None
elif date_config_type == 'course_end':
assessment_start = None
assessment_due = block_data.get_xblock_field(course_key, 'end')
extra_info = None
else:
assessment_start, assessment_due = None, None
if assessment.get('start'):
assessment_start = parse_date(assessment.get('start')).replace(tzinfo=pytz.UTC)
if assessment.get('due'):
assessment_due = parse_date(assessment.get('due')).replace(tzinfo=pytz.UTC)
extra_info = _(
"This Open Response Assessment's due dates are set by your instructor and can't be shifted."
)

if assessment_due is None:
return None

assessment_name = assessment.get('name')
if assessment_name is None:
return None

if assessment_name == 'self-assessment':
assessment_type = _("Self Assessment")
elif assessment_name == 'peer-assessment':
assessment_type = _("Peer Assessment")
elif assessment_name == 'staff-assessment':
assessment_type = _("Staff Assessment")
elif assessment_name == 'submission':
assessment_type = _("Submission")
else:
assessment_type = assessment_name
title = f"{block_title} ({assessment_type})"
url = ''
now = datetime.now(pytz.UTC)
assignment_released = not assessment_start or assessment_start < now
if assignment_released:
url = reverse('jump_to', args=[course_key, ora_block])

past_due = not complete and assessment_due and assessment_due < now
first_component_block_id = str(ora_block)
return _Assignment(
ora_block,
title,
url,
assessment_due,
False,
complete,
past_due,
assignment_type,
extra_info,
first_component_block_id,
)


def get_first_component_of_block(block_key, block_data):
"""
This function returns the first leaf block of a section(block_key)
Expand Down
Loading

0 comments on commit cac1159

Please sign in to comment.