diff --git a/lms/djangoapps/course_home_api/progress/v1/serializers.py b/lms/djangoapps/course_home_api/progress/v1/serializers.py index 977a6b34dd..13586fc0fc 100644 --- a/lms/djangoapps/course_home_api/progress/v1/serializers.py +++ b/lms/djangoapps/course_home_api/progress/v1/serializers.py @@ -1,8 +1,12 @@ """ Progress Tab Serializers """ +from datetime import datetime + from rest_framework import serializers from rest_framework.reverse import reverse +from pytz import UTC + from lms.djangoapps.course_home_api.mixins import VerifiedModeSerializerMixin @@ -20,8 +24,8 @@ class SubsectionScoresSerializer(serializers.Serializer): Serializer for subsections in section_scores """ assignment_type = serializers.CharField(source='format') - display_name = serializers.CharField() block_key = serializers.SerializerMethodField() + display_name = serializers.CharField() has_graded_assignment = serializers.BooleanField(source='graded') learner_has_access = serializers.SerializerMethodField() num_points_earned = serializers.FloatField(source='graded_total.earned') @@ -46,6 +50,15 @@ class SubsectionScoresSerializer(serializers.Serializer): return problem_scores def get_url(self, subsection): + """ + Returns the URL for the subsection while taking into account if the course team has + marked the subsection's visibility as hide after due. + """ + hide_url_date = (subsection.self_paced and subsection.end) or subsection.due + if (not self.context['staff_access'] and subsection.hide_after_due and hide_url_date + and datetime.now(UTC) > hide_url_date): + return None + relative_path = reverse('jump_to', args=[self.context['course_key'], subsection.location]) request = self.context['request'] return request.build_absolute_uri(relative_path) diff --git a/lms/djangoapps/course_home_api/progress/v1/tests/test_views.py b/lms/djangoapps/course_home_api/progress/v1/tests/test_views.py index 33145249a7..9100299826 100644 --- a/lms/djangoapps/course_home_api/progress/v1/tests/test_views.py +++ b/lms/djangoapps/course_home_api/progress/v1/tests/test_views.py @@ -208,3 +208,22 @@ class ProgressTabTestViews(BaseCourseHomeTests): response = self.client.get(self.url) assert response.data['username'] == other_user.username + + @override_waffle_flag(COURSE_HOME_MICROFRONTEND_PROGRESS_TAB, active=True) + def test_url_hidden_if_subsection_hide_after_due(self): + chapter = ItemFactory(parent=self.course, category='chapter') + yesterday = now() - timedelta(days=1) + hide_after_due_subsection = ItemFactory( + parent=chapter, category='sequential', hide_after_due=True, due=yesterday + ) + + CourseEnrollment.enroll(self.user, self.course.id) + + response = self.client.get(self.url) + assert response.status_code == 200 + + sections = response.data['section_scores'] + regular_subsection = sections[0]['subsections'][0] # default sequence that parent class gives us + hide_after_due_subsection = sections[1]['subsections'][0] + assert regular_subsection['url'] is not None + assert hide_after_due_subsection['url'] is None diff --git a/lms/djangoapps/course_home_api/progress/v1/views.py b/lms/djangoapps/course_home_api/progress/v1/views.py index a1b6985d7c..e8e2e31c19 100644 --- a/lms/djangoapps/course_home_api/progress/v1/views.py +++ b/lms/djangoapps/course_home_api/progress/v1/views.py @@ -86,7 +86,8 @@ class ProgressTabView(RetrieveAPIView): ('always', 'never', 'past_due', values defined in common/lib/xmodule/xmodule/modulestore/inheritance.py) show_grades: (bool) a bool for whether to show grades based on the access the user has - url: (str) the absolute path url to the Subsection + url: (str or None) the absolute path url to the Subsection or None if the Subsection is no longer accessible + to the learner due to a hide_after_due course team setting enrollment_mode: (str) a str representing the enrollment the user has ('audit', 'verified', ...) grading_policy: assignment_policies: List of serialized assignment grading policy objects, each has the following fields: diff --git a/lms/djangoapps/grades/subsection_grade.py b/lms/djangoapps/grades/subsection_grade.py index 72b3f4e7aa..70d7fbfaa5 100644 --- a/lms/djangoapps/grades/subsection_grade.py +++ b/lms/djangoapps/grades/subsection_grade.py @@ -27,9 +27,14 @@ class SubsectionGradeBase(metaclass=ABCMeta): self.display_name = block_metadata_utils.display_name_with_default(subsection) self.url_name = block_metadata_utils.url_name_for_block(subsection) - self.format = getattr(subsection, 'format', '') self.due = getattr(subsection, 'due', None) + self.end = getattr(subsection, 'end', None) + self.format = getattr(subsection, 'format', '') self.graded = getattr(subsection, 'graded', False) + transformer_data = getattr(subsection, 'transformer_data', None) + hidden_content_data = transformer_data and subsection.transformer_data.get('hidden_content') + self.hide_after_due = hidden_content_data and hidden_content_data.fields.get('merged_hide_after_due') + self.self_paced = subsection.self_paced self.show_correctness = getattr(subsection, 'show_correctness', '') self.course_version = getattr(subsection, 'course_version', None) diff --git a/lms/templates/courseware/progress.html b/lms/templates/courseware/progress.html index 037a36b3e1..63b340c1e4 100644 --- a/lms/templates/courseware/progress.html +++ b/lms/templates/courseware/progress.html @@ -3,16 +3,18 @@ <%namespace name='static' file='/static_content.html'/> <%def name="online_help_token()"><% return "progress" %>%def> <%! +from datetime import datetime + +from django.conf import settings +from django.urls import reverse +from django.utils.http import urlquote_plus +from django.utils.translation import ugettext as _ +from pytz import UTC + from common.djangoapps.course_modes.models import CourseMode from lms.djangoapps.certificates.data import CertificateStatuses from lms.djangoapps.grades.api import constants as grades_constants -from django.utils.translation import ugettext as _ from openedx.core.djangolib.markup import HTML, Text -from django.urls import reverse -from django.conf import settings -from django.utils.http import urlquote_plus -from six import text_type - from openedx.features.enterprise_support.utils import get_enterprise_learner_generic_name %> @@ -73,7 +75,7 @@ username = get_enterprise_learner_generic_name(request) or student.username %if certificate_data: