Merge pull request #26978 from edx/ciduarte/AA-213
AA-213: create progress tab mfe waffle flag
This commit is contained in:
@@ -6,11 +6,17 @@ from rest_framework.reverse import reverse
|
||||
|
||||
|
||||
class CourseGradeSerializer(serializers.Serializer):
|
||||
"""
|
||||
Serializer for course grade
|
||||
"""
|
||||
percent = serializers.FloatField()
|
||||
is_passing = serializers.BooleanField(source='passed')
|
||||
|
||||
|
||||
class SubsectionScoresSerializer(serializers.Serializer):
|
||||
"""
|
||||
Serializer for subsections in section_scores
|
||||
"""
|
||||
assignment_type = serializers.CharField(source='format')
|
||||
display_name = serializers.CharField()
|
||||
has_graded_assignment = serializers.BooleanField(source='graded')
|
||||
@@ -32,13 +38,16 @@ class SubsectionScoresSerializer(serializers.Serializer):
|
||||
|
||||
class SectionScoresSerializer(serializers.Serializer):
|
||||
"""
|
||||
Serializer for chapters in courseware_summary
|
||||
Serializer for sections in section_scores
|
||||
"""
|
||||
display_name = serializers.CharField()
|
||||
subsections = SubsectionScoresSerializer(source='sections', many=True)
|
||||
|
||||
|
||||
class GradingPolicySerializer(serializers.Serializer):
|
||||
"""
|
||||
Serializer for grading policy
|
||||
"""
|
||||
assignment_policies = serializers.SerializerMethodField()
|
||||
grade_range = serializers.DictField(source='GRADE_CUTOFFS')
|
||||
|
||||
@@ -50,6 +59,9 @@ class GradingPolicySerializer(serializers.Serializer):
|
||||
|
||||
|
||||
class CertificateDataSerializer(serializers.Serializer):
|
||||
"""
|
||||
Serializer for certificate data
|
||||
"""
|
||||
cert_status = serializers.CharField()
|
||||
cert_web_view_url = serializers.CharField()
|
||||
download_url = serializers.CharField()
|
||||
|
||||
@@ -10,7 +10,8 @@ from common.djangoapps.course_modes.models import CourseMode
|
||||
from common.djangoapps.student.models import CourseEnrollment
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from lms.djangoapps.course_home_api.tests.utils import BaseCourseHomeTests
|
||||
from lms.djangoapps.course_home_api.toggles import COURSE_HOME_MICROFRONTEND
|
||||
from lms.djangoapps.course_home_api.toggles import COURSE_HOME_MICROFRONTEND, COURSE_HOME_MICROFRONTEND_PROGRESS_TAB
|
||||
from lms.djangoapps.experiments.testutils import override_experiment_waffle_flag
|
||||
from lms.djangoapps.verify_student.models import ManualVerification
|
||||
from openedx.core.djangoapps.user_api.preferences.api import set_user_preference
|
||||
|
||||
@@ -27,6 +28,8 @@ class ProgressTabTestViews(BaseCourseHomeTests):
|
||||
super().setUp()
|
||||
self.url = reverse('course-home-progress-tab', args=[self.course.id])
|
||||
|
||||
@override_experiment_waffle_flag(COURSE_HOME_MICROFRONTEND, active=True)
|
||||
@override_waffle_flag(COURSE_HOME_MICROFRONTEND_PROGRESS_TAB, active=True)
|
||||
@ddt.data(CourseMode.AUDIT, CourseMode.VERIFIED)
|
||||
def test_get_authenticated_enrolled_user(self, enrollment_mode):
|
||||
CourseEnrollment.enroll(self.user, self.course.id, enrollment_mode)
|
||||
@@ -47,21 +50,35 @@ class ProgressTabTestViews(BaseCourseHomeTests):
|
||||
elif enrollment_mode == CourseMode.AUDIT:
|
||||
assert response.data['certificate_data']['cert_status'] == 'audit_passing'
|
||||
|
||||
@override_experiment_waffle_flag(COURSE_HOME_MICROFRONTEND, active=True)
|
||||
@override_waffle_flag(COURSE_HOME_MICROFRONTEND_PROGRESS_TAB, active=True)
|
||||
def test_get_authenticated_user_not_enrolled(self):
|
||||
response = self.client.get(self.url)
|
||||
# expecting a redirect
|
||||
assert response.status_code == 302
|
||||
|
||||
@override_experiment_waffle_flag(COURSE_HOME_MICROFRONTEND, active=True)
|
||||
@override_waffle_flag(COURSE_HOME_MICROFRONTEND_PROGRESS_TAB, active=True)
|
||||
def test_get_unauthenticated_user(self):
|
||||
self.client.logout()
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 401
|
||||
|
||||
@override_experiment_waffle_flag(COURSE_HOME_MICROFRONTEND, active=True)
|
||||
@override_waffle_flag(COURSE_HOME_MICROFRONTEND_PROGRESS_TAB, active=True)
|
||||
def test_get_unknown_course(self):
|
||||
url = reverse('course-home-progress-tab', args=['course-v1:unknown+course+2T2020'])
|
||||
response = self.client.get(url)
|
||||
assert response.status_code == 404
|
||||
|
||||
@override_experiment_waffle_flag(COURSE_HOME_MICROFRONTEND, active=True)
|
||||
@override_waffle_flag(COURSE_HOME_MICROFRONTEND_PROGRESS_TAB, active=False)
|
||||
@ddt.data(CourseMode.AUDIT, CourseMode.VERIFIED)
|
||||
def test_waffle_flag_disabled(self, enrollment_mode):
|
||||
CourseEnrollment.enroll(self.user, self.course.id, enrollment_mode)
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 404
|
||||
|
||||
# TODO: (AA-212) implement masquerade
|
||||
# def test_masquerade(self):
|
||||
# user = UserFactory()
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Progress Tab Views
|
||||
"""
|
||||
|
||||
from django.http.response import Http404
|
||||
from edx_django_utils import monitoring as monitoring_utils
|
||||
from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
|
||||
from edx_rest_framework_extensions.auth.session.authentication import SessionAuthenticationAllowInactiveUser
|
||||
@@ -13,6 +14,7 @@ from rest_framework.response import Response
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from common.djangoapps.student.models import CourseEnrollment
|
||||
from lms.djangoapps.course_home_api.progress.v1.serializers import ProgressTabSerializer
|
||||
from lms.djangoapps.course_home_api.toggles import course_home_mfe_progress_tab_is_active
|
||||
from lms.djangoapps.courseware.access import has_access
|
||||
from lms.djangoapps.courseware.courses import get_course_blocks_completion_summary, get_course_with_access, get_studio_url
|
||||
from lms.djangoapps.courseware.masquerade import setup_masquerade
|
||||
@@ -49,7 +51,7 @@ class ProgressTabView(RetrieveAPIView):
|
||||
course_grade: Object containing the following fields:
|
||||
percent: (float) the user's total graded percent in the course
|
||||
is_passing: (bool) whether the user's grade is above the passing grade cutoff
|
||||
graded_course_blocks: List of serialized Chapters. Each Chapter has the following fields:
|
||||
section_scores: List of serialized Chapters. Each Chapter has the following fields:
|
||||
display_name: (str) a str of what the name of the Chapter is for displaying on the site
|
||||
subsections: List of serialized Subsections, each has the following fields:
|
||||
assignment_type: (str) the format, if any, of the Subsection (Homework, Exam, etc)
|
||||
@@ -97,6 +99,9 @@ class ProgressTabView(RetrieveAPIView):
|
||||
course_key_string = kwargs.get('course_key_string')
|
||||
course_key = CourseKey.from_string(course_key_string)
|
||||
|
||||
if not course_home_mfe_progress_tab_is_active(course_key):
|
||||
raise Http404
|
||||
|
||||
# Enable NR tracing for this view based on course
|
||||
monitoring_utils.set_custom_attribute('course_id', course_key_string)
|
||||
monitoring_utils.set_custom_attribute('user_id', request.user.id)
|
||||
|
||||
@@ -15,6 +15,9 @@ COURSE_HOME_MICROFRONTEND_DATES_TAB = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'c
|
||||
|
||||
COURSE_HOME_MICROFRONTEND_OUTLINE_TAB = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'course_home_mfe_outline_tab', __name__)
|
||||
|
||||
COURSE_HOME_MICROFRONTEND_PROGRESS_TAB = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'course_home_mfe_progress_tab',
|
||||
__name__)
|
||||
|
||||
|
||||
def course_home_mfe_is_active(course_key):
|
||||
return (
|
||||
@@ -35,3 +38,10 @@ def course_home_mfe_outline_tab_is_active(course_key):
|
||||
course_home_mfe_is_active(course_key) and
|
||||
COURSE_HOME_MICROFRONTEND_OUTLINE_TAB.is_enabled(course_key)
|
||||
)
|
||||
|
||||
|
||||
def course_home_mfe_progress_tab_is_active(course_key):
|
||||
return (
|
||||
course_home_mfe_is_active(course_key) and
|
||||
COURSE_HOME_MICROFRONTEND_PROGRESS_TAB.is_enabled(course_key)
|
||||
)
|
||||
|
||||
@@ -10,7 +10,7 @@ from django.utils.translation import ugettext_noop
|
||||
|
||||
from lms.djangoapps.courseware.access import has_access
|
||||
from lms.djangoapps.courseware.entrance_exams import user_can_skip_entrance_exam
|
||||
from lms.djangoapps.course_home_api.toggles import course_home_mfe_dates_tab_is_active, course_home_mfe_outline_tab_is_active # lint-amnesty, pylint: disable=line-too-long
|
||||
from lms.djangoapps.course_home_api.toggles import course_home_mfe_dates_tab_is_active, course_home_mfe_outline_tab_is_active, course_home_mfe_progress_tab_is_active # lint-amnesty, pylint: disable=line-too-long
|
||||
from openedx.core.lib.course_tabs import CourseTabPluginManager
|
||||
from openedx.features.course_experience import RELATIVE_DATES_FLAG, DISABLE_UNIFIED_COURSE_TAB_FLAG, default_course_url_name # lint-amnesty, pylint: disable=line-too-long
|
||||
from openedx.features.course_experience.url_helpers import get_learning_mfe_home_url
|
||||
@@ -109,6 +109,16 @@ class ProgressTab(EnrolledTab):
|
||||
is_hideable = True
|
||||
is_default = False
|
||||
|
||||
def __init__(self, tab_dict):
|
||||
def link_func(course, reverse_func):
|
||||
if course_home_mfe_progress_tab_is_active(course.id):
|
||||
return get_learning_mfe_home_url(course_key=course.id, view_name=self.view_name)
|
||||
else:
|
||||
return reverse_func(self.view_name, args=[six.text_type(course.id)])
|
||||
|
||||
tab_dict['link_func'] = link_func
|
||||
super(ProgressTab, self).__init__(tab_dict) # pylint: disable=super-with-arguments
|
||||
|
||||
@classmethod
|
||||
def is_enabled(cls, course, user=None):
|
||||
if not super().is_enabled(course, user=user):
|
||||
|
||||
@@ -54,7 +54,10 @@ from lms.djangoapps.ccx.custom_exception import CCXLocatorValidationException
|
||||
from lms.djangoapps.certificates import api as certs_api
|
||||
from lms.djangoapps.certificates.models import CertificateStatuses
|
||||
from lms.djangoapps.commerce.utils import EcommerceService
|
||||
from lms.djangoapps.course_home_api.toggles import course_home_mfe_dates_tab_is_active
|
||||
from lms.djangoapps.course_home_api.toggles import (
|
||||
course_home_mfe_dates_tab_is_active,
|
||||
course_home_mfe_progress_tab_is_active
|
||||
)
|
||||
from openedx.features.course_experience.url_helpers import get_learning_mfe_home_url, is_request_from_learning_mfe
|
||||
from lms.djangoapps.courseware.access import has_access, has_ccx_coach_role
|
||||
from lms.djangoapps.courseware.access_utils import check_course_open_for_learner, check_public_access
|
||||
@@ -1087,8 +1090,14 @@ def dates(request, course_id):
|
||||
@data_sharing_consent_required
|
||||
def progress(request, course_id, student_id=None):
|
||||
""" Display the progress page. """
|
||||
from lms.urls import COURSE_PROGRESS_NAME
|
||||
|
||||
course_key = CourseKey.from_string(course_id)
|
||||
|
||||
if course_home_mfe_progress_tab_is_active(course_key) and not request.user.is_staff:
|
||||
microfrontend_url = get_learning_mfe_home_url(course_key=course_key, view_name=COURSE_PROGRESS_NAME)
|
||||
raise Redirect(microfrontend_url)
|
||||
|
||||
with modulestore().bulk_operations(course_key):
|
||||
return _progress(request, course_key, student_id)
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ from common.djangoapps.util import views as util_views
|
||||
RESET_COURSE_DEADLINES_NAME = 'reset_course_deadlines'
|
||||
RENDER_XBLOCK_NAME = 'render_xblock'
|
||||
COURSE_DATES_NAME = 'dates'
|
||||
COURSE_PROGRESS_NAME = 'progress'
|
||||
|
||||
if settings.DEBUG or settings.FEATURES.get('ENABLE_DJANGO_ADMIN_SITE'):
|
||||
django_autodiscover()
|
||||
@@ -498,7 +499,7 @@ urlpatterns += [
|
||||
settings.COURSE_ID_PATTERN,
|
||||
),
|
||||
courseware_views.progress,
|
||||
name='progress',
|
||||
name=COURSE_PROGRESS_NAME,
|
||||
),
|
||||
|
||||
# dates page
|
||||
|
||||
Reference in New Issue
Block a user