Skip to content

Commit 845773f

Browse files
feat: first attempt at course outline changes
1 parent 1c44ca0 commit 845773f

File tree

4 files changed

+66
-12
lines changed

4 files changed

+66
-12
lines changed

lms/djangoapps/course_home_api/outline/serializers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ class OutlineTabSerializer(DatesBannerSerializer, VerifiedModeSerializer):
156156
"""
157157
Serializer for the Outline Tab
158158
"""
159+
accessible_sequences = serializers.ListField()
159160
access_expiration = serializers.DictField()
160161
cert_data = CertificateDataSerializer()
161162
course_blocks = CourseBlockSerializer()

lms/djangoapps/course_home_api/outline/views.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ def get(self, request, *args, **kwargs): # pylint: disable=too-many-statements
346346
user_has_passing_grade = user_grade.passed
347347

348348
data = {
349+
"accessible_sequences": [str(seq) for seq in user_course_outline.accessible_sequences],
349350
'access_expiration': access_expiration,
350351
'cert_data': cert_data,
351352
'course_blocks': course_blocks,

lms/djangoapps/course_home_api/toggles.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,21 @@
5151
)
5252

5353

54+
# Waffle flag to enable audit learner preview of course structure visible to verified learners.
55+
#
56+
# .. toggle_name: course_home.audit_learner_verified_preview
57+
# .. toggle_implementation: CourseWaffleFlag
58+
# .. toggle_default: False
59+
# .. toggle_description: This toggle controls whether the the audit learners can see a preview of the course structure
60+
# that is visible to verified learners.
61+
# .. toggle_use_cases: open_edx
62+
# .. toggle_creation_date: 2025-11-07
63+
# .. toggle_target_removal_date: None
64+
COURSE_HOME_AUDIT_LEARNER_VERIFIED_PREVIEW = CourseWaffleFlag(
65+
f'{WAFFLE_FLAG_NAMESPACE}.audit_learner_verified_preview', __name__
66+
)
67+
68+
5469
def course_home_mfe_progress_tab_is_active(course_key):
5570
# Avoiding a circular dependency
5671
from .models import DisableProgressPageStackedConfig
@@ -73,3 +88,10 @@ def send_course_progress_analytics_for_student_is_enabled(course_key):
7388
Returns True if the course completion analytics feature is enabled for a given course.
7489
"""
7590
return COURSE_HOME_SEND_COURSE_PROGRESS_ANALYTICS_FOR_STUDENT.is_enabled(course_key)
91+
92+
93+
def audit_learner_verified_preview_is_enabled(course_key):
94+
"""
95+
Returns True if the course completion analytics feature is enabled for a given course.
96+
"""
97+
return COURSE_HOME_AUDIT_LEARNER_VERIFIED_PREVIEW.is_enabled(course_key)

openedx/core/djangoapps/content/learning_sequences/api/processors/enrollment_track_partition_groups.py

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
# lint-amnesty, pylint: disable=missing-module-docstring
22
import logging
33
from datetime import datetime
4+
from django.conf import settings
45
from typing import Dict
56

67
from opaque_keys.edx.keys import CourseKey
78
from openedx.core import types
89

10+
from common.djangoapps.course_modes.models import CourseMode
11+
from lms.djangoapps.course_home_api.toggles import audit_learner_verified_preview_is_enabled
12+
913
from xmodule.partitions.enrollment_track_partition_generator import ( # lint-amnesty, pylint: disable=wrong-import-order
1014
create_enrollment_track_partition_with_course_id
1115
)
@@ -47,23 +51,34 @@ def load_data(self, full_course_outline) -> None:
4751
# TODO: fix type annotation: https://github.com/openedx/tcril-engineering/issues/313
4852
self.user_group = self.enrollment_track_groups.get(ENROLLMENT_TRACK_PARTITION_ID) # type: ignore
4953

50-
def _is_user_excluded_by_partition_group(self, user_partition_groups):
54+
def _get_user_partition_group_access(self, user_partition_groups):
5155
"""
52-
Is the user part of the group to which the block is restricting content?
56+
Get the user's partition group access for the enrollment track partition.
5357
"""
58+
is_accessible, is_removed = False, False
59+
5460
if not user_partition_groups:
55-
return False
61+
return is_accessible, is_removed
5662

5763
groups = user_partition_groups.get(ENROLLMENT_TRACK_PARTITION_ID)
5864
if not groups:
59-
return False
65+
return is_accessible, is_removed
6066

6167
if self.user_group and self.user_group.id not in groups:
6268
# If the user's partition group, say Masters,
6369
# does not belong to the partition of the block, say [verified],
6470
# the block should be removed
65-
return True
66-
return False
71+
is_removed = True
72+
73+
if audit_learner_verified_preview_is_enabled(self.course_key):
74+
contains_verified_mode = settings.COURSE_ENROLLMENT_MODES.get(CourseMode.VERIFIED).get('id') in groups
75+
is_audit_mode = self.user_group and self.user_group.id == settings.COURSE_ENROLLMENT_MODES.get(CourseMode.AUDIT).get('id')
76+
77+
if is_audit_mode and contains_verified_mode:
78+
is_accessible = True
79+
is_removed = False
80+
81+
return is_accessible, is_removed
6782

6883
def usage_keys_to_remove(self, full_course_outline):
6984
"""
@@ -77,14 +92,29 @@ def usage_keys_to_remove(self, full_course_outline):
7792
removed_usage_keys = set()
7893
for section in full_course_outline.sections:
7994
remove_all_children = False
80-
if self._is_user_excluded_by_partition_group(
81-
section.user_partition_groups
82-
):
95+
_, should_remove_section = self._get_user_partition_group_access(section.user_partition_groups)
96+
if should_remove_section:
8397
removed_usage_keys.add(section.usage_key)
8498
remove_all_children = True
8599
for seq in section.sequences:
86-
if remove_all_children or self._is_user_excluded_by_partition_group(
87-
seq.user_partition_groups
88-
):
100+
_, should_remove_sequence = self._get_user_partition_group_access(seq.user_partition_groups)
101+
if remove_all_children or should_remove_sequence:
89102
removed_usage_keys.add(seq.usage_key)
90103
return removed_usage_keys
104+
105+
def inaccessible_sequences(self, full_course_outline):
106+
"""
107+
TODO
108+
"""
109+
inaccessible_usage_keys = set()
110+
for section in full_course_outline.sections:
111+
remove_all_children = False
112+
is_section_inaccessible, _ = self._get_user_partition_group_access(section.user_partition_groups)
113+
if is_section_inaccessible:
114+
inaccessible_usage_keys.add(section.usage_key)
115+
remove_all_children = True
116+
for seq in section.sequences:
117+
_, is_sequence_inacessible = self._get_user_partition_group_access(seq.user_partition_groups)
118+
if remove_all_children or is_sequence_inacessible:
119+
inaccessible_usage_keys.add(seq.usage_key)
120+
return inaccessible_usage_keys

0 commit comments

Comments
 (0)