Skip to content
Snippets Groups Projects
Unverified Commit 229a2e39 authored by Calen Pennington's avatar Calen Pennington Committed by GitHub
Browse files

Merge pull request #22043 from cpennington/graded-markers-course-outline

Add graded and scored markers to the course outline
parents e258fab1 7ceb0e30
No related merge requests found
......@@ -1614,6 +1614,8 @@ class CourseEnrollment(models.Model):
else:
enrollments = cls.enrollments_for_user(user)
enrollments.select_related('schedule')
overviews = CourseOverview.get_from_ids_if_exists(
enrollment.course_id for enrollment in enrollments
)
......
......@@ -44,6 +44,8 @@ SUPPORTED_FIELDS = [
SupportedFieldType('graded'),
SupportedFieldType('format'),
SupportedFieldType('due'),
SupportedFieldType('has_score'),
SupportedFieldType('weight'),
SupportedFieldType('show_correctness'),
# 'student_view_data'
SupportedFieldType(StudentViewTransformer.STUDENT_VIEW_DATA, StudentViewTransformer),
......
......@@ -19,6 +19,7 @@ from entitlements.models import CourseEntitlement
from lms.djangoapps.commerce.utils import EcommerceService
from openedx.core.djangoapps.catalog.utils import get_programs
from openedx.core.djangoapps.django_comment_common.models import Role
from openedx.core.djangoapps.schedules.models import Schedule
from openedx.core.djangoapps.waffle_utils import WaffleFlag, WaffleFlagNamespace
from openedx.features.course_duration_limits.access import get_user_course_expiration_date
from openedx.features.course_duration_limits.models import CourseDurationLimitConfig
......@@ -261,11 +262,11 @@ def get_experiment_user_metadata_context(course, user):
audit_enrollments = None
has_non_audit_enrollments = False
try:
user_enrollments = CourseEnrollment.objects.select_related('course').filter(user_id=user.id)
user_enrollments = CourseEnrollment.objects.select_related('course', 'schedule').filter(user_id=user.id)
has_non_audit_enrollments = user_enrollments.exclude(mode__in=CourseMode.UPSELL_TO_VERIFIED_MODES).exists()
# TODO: clean up as part of REVO-28 (END)
enrollment = CourseEnrollment.objects.select_related(
'course'
'course', 'schedule'
).get(user_id=user.id, course_id=course.id)
except CourseEnrollment.DoesNotExist:
pass # Not enrolled, use the default values
......@@ -305,20 +306,28 @@ def get_base_experiment_metadata_context(course, user, enrollment, user_enrollme
# TODO: clean up as part of REVEM-199 (START)
program_key = get_program_context(course, user_enrollments)
# TODO: clean up as part of REVEM-199 (END)
schedule_start = None
if enrollment and enrollment.is_active:
enrollment_mode = enrollment.mode
enrollment_time = enrollment.created
try:
schedule_start = enrollment.schedule.start
except Schedule.DoesNotExist:
pass
# upgrade_link, dynamic_upgrade_deadline and course_upgrade_deadline should be None
# if user has passed their dynamic pacing deadline.
upgrade_link, dynamic_upgrade_deadline, course_upgrade_deadline = check_and_get_upgrade_link_and_date(
user, enrollment, course)
user, enrollment, course
)
return {
'upgrade_link': upgrade_link,
'upgrade_price': six.text_type(get_cosmetic_verified_display_price(course)),
'enrollment_mode': enrollment_mode,
'enrollment_time': enrollment_time,
'schedule_start': schedule_start,
'pacing_type': 'self_paced' if course.self_paced else 'instructor_paced',
'dynamic_upgrade_deadline': dynamic_upgrade_deadline,
'course_upgrade_deadline': course_upgrade_deadline,
......
......@@ -31,8 +31,9 @@ self_paced = context.get('self_paced', False)
% for section in course_sections:
<%
section_is_auto_opened = section.get('resume_block') is True
scored = 'scored' if section.get('scored', False) else ''
%>
<li class="outline-item section">
<li class="outline-item section ${scored}">
<button class="section-name accordion-trigger"
aria-expanded="${ 'true' if section_is_auto_opened else 'false' }"
aria-controls="${ section['id'] }_contents"
......@@ -52,8 +53,10 @@ self_paced = context.get('self_paced', False)
gated_subsection = subsection['id'] in gated_content
completed_prereqs = gated_content[subsection['id']]['completed_prereqs'] if gated_subsection else False
subsection_is_auto_opened = subsection.get('resume_block') is True
scored = 'scored' if subsection.get('scored', False) else ''
graded = 'graded' if subsection.get('graded') else ''
%>
<li class="subsection accordion ${ 'current' if subsection.get('resume_block') else '' }">
<li class="subsection accordion ${ 'current' if subsection.get('resume_block') else '' } ${graded} ${scored}">
% if gated_subsection and not completed_prereqs:
<a href="${ subsection['lms_web_url'] }">
<button class="subsection-text prerequisite-button"
......@@ -140,7 +143,7 @@ self_paced = context.get('self_paced', False)
></span>
% if subsection.get('graded'):
<span class="sr">&nbsp;${_("This content is graded")}</span>
<span class="sr">&nbsp;${_("This content is graded")}</span>
% endif
% endif
</span>
......@@ -160,8 +163,9 @@ self_paced = context.get('self_paced', False)
vertical_is_access_denied = vertical.get('authorization_denial_reason')
if vertical_is_access_denied:
continue
scored = 'scored' if vertical.get('scored', False) else ''
%>
<li class="vertical outline-item focusable">
<li class="vertical outline-item focusable ${scored}">
<a class="outline-item focusable"
% if enable_links:
href="${ vertical['lms_web_url'] }"
......
......@@ -131,6 +131,21 @@ def get_course_outline_block_tree(request, course_id, user=None):
# we'll use the last child.
block['children'][-1]['resume_block'] = True
def recurse_mark_scored(block):
"""
Mark this block as 'scored' if any of its descendents are 'scored' (that is, 'has_score' and 'weight' > 0).
"""
is_scored = block.get('has_score', False) and block.get('weight', 1) > 0
# Use a list comprehension to force the recursion over all children, rather than just stopping
# at the first child that is scored.
children_scored = any([recurse_mark_scored(child) for child in block.get('children', [])])
if is_scored or children_scored:
block['scored'] = True
return True
else:
block['scored'] = False
return False
course_key = CourseKey.from_string(course_id)
course_usage_key = modulestore().make_course_usage_key(course_key)
......@@ -160,6 +175,8 @@ def get_course_outline_block_tree(request, course_id, user=None):
'type',
'due',
'graded',
'has_score',
'weight',
'special_exam_info',
'show_gated_sections',
'format'
......@@ -170,6 +187,7 @@ def get_course_outline_block_tree(request, course_id, user=None):
course_outline_root_block = all_blocks['blocks'].get(all_blocks['root'], None)
if course_outline_root_block:
populate_children(course_outline_root_block, all_blocks['blocks'])
recurse_mark_scored(course_outline_root_block)
if user:
set_last_accessed_default(course_outline_root_block)
mark_blocks_completed(
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment