Merge pull request #27323 from edx/AA-719
[AA-721] Add necessary data for new progress page
This commit is contained in:
@@ -86,6 +86,9 @@ class ProgressTabSerializer(serializers.Serializer):
|
||||
certificate_data = CertificateDataSerializer()
|
||||
completion_summary = serializers.DictField()
|
||||
course_grade = CourseGradeSerializer()
|
||||
end = serializers.DateTimeField()
|
||||
user_has_passing_grade = serializers.BooleanField()
|
||||
has_scheduled_content = serializers.BooleanField()
|
||||
section_scores = SectionScoresSerializer(many=True)
|
||||
enrollment_mode = serializers.CharField()
|
||||
grading_policy = GradingPolicySerializer()
|
||||
|
||||
@@ -2,8 +2,14 @@
|
||||
Tests for Progress Tab API in the Course Home API
|
||||
"""
|
||||
|
||||
import dateutil
|
||||
import ddt
|
||||
import mock
|
||||
from datetime import timedelta
|
||||
from pytz import UTC
|
||||
from unittest.mock import patch
|
||||
from django.urls import reverse
|
||||
from django.utils.timezone import now
|
||||
from edx_toggles.toggles.testutils import override_waffle_flag
|
||||
|
||||
from common.djangoapps.course_modes.models import CourseMode
|
||||
@@ -14,6 +20,7 @@ from lms.djangoapps.course_home_api.toggles import COURSE_HOME_MICROFRONTEND, CO
|
||||
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
|
||||
from xmodule.modulestore.tests.factories import ItemFactory
|
||||
|
||||
CREDIT_SUPPORT_URL = 'https://support.edx.org/hc/en-us/sections/115004154688-Purchasing-Academic-Credit'
|
||||
|
||||
@@ -97,3 +104,36 @@ class ProgressTabTestViews(BaseCourseHomeTests):
|
||||
# Masquerade as verified user
|
||||
self.update_masquerade(username=verified_user.username)
|
||||
assert self.client.get(self.url).data.get('enrollment_mode') == 'verified'
|
||||
|
||||
@patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False})
|
||||
@override_experiment_waffle_flag(COURSE_HOME_MICROFRONTEND, active=True)
|
||||
@override_waffle_flag(COURSE_HOME_MICROFRONTEND_PROGRESS_TAB, active=True)
|
||||
def test_has_scheduled_content_data(self):
|
||||
CourseEnrollment.enroll(self.user, self.course.id)
|
||||
future = now() + timedelta(days=30)
|
||||
chapter = ItemFactory(parent=self.course, category='chapter', start=future)
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 200
|
||||
assert response.json()['has_scheduled_content']
|
||||
|
||||
@override_experiment_waffle_flag(COURSE_HOME_MICROFRONTEND, active=True)
|
||||
@override_waffle_flag(COURSE_HOME_MICROFRONTEND_PROGRESS_TAB, active=True)
|
||||
def test_end(self):
|
||||
CourseEnrollment.enroll(self.user, self.course.id)
|
||||
future = now() + timedelta(days=30)
|
||||
self.course.end = future
|
||||
self.update_course(self.course, self.user.id)
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 200
|
||||
end = dateutil.parser.parse(response.json()['end']).replace(tzinfo=UTC)
|
||||
assert end.date() == future.date()
|
||||
|
||||
@override_experiment_waffle_flag(COURSE_HOME_MICROFRONTEND, active=True)
|
||||
@override_waffle_flag(COURSE_HOME_MICROFRONTEND_PROGRESS_TAB, active=True)
|
||||
def test_user_has_passing_grade(self):
|
||||
CourseEnrollment.enroll(self.user, self.course.id)
|
||||
self.course._grading_policy['GRADE_CUTOFFS']['Pass'] = 0
|
||||
self.update_course(self.course, self.user.id)
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 200
|
||||
assert response.json()['user_has_passing_grade']
|
||||
|
||||
@@ -16,12 +16,17 @@ 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.course_blocks.api import get_course_blocks
|
||||
from lms.djangoapps.course_blocks.transformers import start_date
|
||||
|
||||
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
|
||||
from lms.djangoapps.courseware.views.views import get_cert_data
|
||||
|
||||
from lms.djangoapps.grades.api import CourseGradeFactory
|
||||
from lms.djangoapps.verify_student.services import IDVerificationService
|
||||
from openedx.core.djangoapps.content.block_structure.transformers import BlockStructureTransformers
|
||||
from openedx.core.djangoapps.content.block_structure.api import get_block_structure_manager
|
||||
from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser
|
||||
|
||||
|
||||
@@ -39,6 +44,9 @@ class ProgressTabView(RetrieveAPIView):
|
||||
|
||||
Body consists of the following fields:
|
||||
|
||||
end: (date) end date of the course
|
||||
user_has_passing_grade: (bool) boolean on if the user has a passing grade in the course
|
||||
has_scheduled_content: (bool) boolean on if the course has content scheduled with a release date in the future
|
||||
certificate_data: Object containing information about the user's certificate status
|
||||
cert_status: (str) the status of a user's certificate (full list of statuses are defined in
|
||||
lms/djangoapps/certificates/models.py)
|
||||
@@ -122,11 +130,32 @@ class ProgressTabView(RetrieveAPIView):
|
||||
|
||||
enrollment_mode, _ = CourseEnrollment.enrollment_mode_for_user(request.user, course_key)
|
||||
|
||||
course_grade = CourseGradeFactory().read(request.user, course)\
|
||||
# The block structure is used for both the course_grade and has_scheduled content fields
|
||||
# So it is called upfront and reused for optimization purposes
|
||||
collected_block_structure = get_block_structure_manager(course_key).get_collected()
|
||||
course_grade = CourseGradeFactory().read(request.user, collected_block_structure=collected_block_structure)
|
||||
|
||||
# Get has_scheduled_content data
|
||||
transformers = BlockStructureTransformers()
|
||||
transformers += [start_date.StartDateTransformer()]
|
||||
usage_key = collected_block_structure.root_block_usage_key
|
||||
course_blocks = get_course_blocks(
|
||||
request.user,
|
||||
usage_key,
|
||||
transformers=transformers,
|
||||
collected_block_structure=collected_block_structure,
|
||||
include_has_scheduled_content=True
|
||||
)
|
||||
has_scheduled_content = course_blocks.get_xblock_field(usage_key, 'has_scheduled_content')
|
||||
|
||||
# Get user_has_passing_grade data
|
||||
user_has_passing_grade = False
|
||||
if not request.user.is_anonymous:
|
||||
user_grade = course_grade.percent
|
||||
user_has_passing_grade = user_grade >= course.lowest_passing_grade
|
||||
|
||||
descriptor = modulestore().get_course(course_key)
|
||||
grading_policy = descriptor.grading_policy
|
||||
|
||||
verification_status = IDVerificationService.user_status(request.user)
|
||||
verification_link = None
|
||||
if verification_status['status'] is None or verification_status['status'] == 'expired':
|
||||
@@ -140,9 +169,12 @@ class ProgressTabView(RetrieveAPIView):
|
||||
}
|
||||
|
||||
data = {
|
||||
'end': course.end,
|
||||
'user_has_passing_grade': user_has_passing_grade,
|
||||
'certificate_data': get_cert_data(request.user, course, enrollment_mode, course_grade),
|
||||
'completion_summary': get_course_blocks_completion_summary(course_key, request.user),
|
||||
'course_grade': course_grade,
|
||||
'has_scheduled_content': has_scheduled_content,
|
||||
'section_scores': course_grade.chapter_grades.values(),
|
||||
'enrollment_mode': enrollment_mode,
|
||||
'grading_policy': grading_policy,
|
||||
|
||||
Reference in New Issue
Block a user