Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions lms/djangoapps/course_home_api/outline/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
from lms.djangoapps.course_home_api.dates.serializers import DateSummarySerializer
from lms.djangoapps.course_home_api.progress.serializers import CertificateDataSerializer
from lms.djangoapps.course_home_api.serializers import DatesBannerSerializer, VerifiedModeSerializer

from lms.djangoapps.course_blocks.api import get_course_blocks
from opaque_keys.edx.keys import UsageKey

class CourseBlockSerializer(serializers.Serializer):
"""
Expand All @@ -28,6 +29,7 @@ def get_blocks(self, block): # pylint: disable=missing-function-docstring
icon = None
num_graded_problems = block.get('num_graded_problems', 0)
scored = block.get('scored')
block_data = set(get_course_blocks(self.context['request'].user, UsageKey.from_string(block_key)).get_block_keys())

if num_graded_problems and block_type == 'sequential':
questions = ngettext('({number} Question)', '({number} Questions)', num_graded_problems)
Expand All @@ -37,7 +39,7 @@ def get_blocks(self, block): # pylint: disable=missing-function-docstring
icon = 'fa-pencil-square-o'

if block_type == 'vertical':
icon = self.get_vertical_icon_class(block)
icon = self.get_vertical_icon_class(block, block_data)

if 'special_exam_info' in block:
description = block['special_exam_info'].get('short_description')
Expand Down Expand Up @@ -74,7 +76,7 @@ def get_blocks(self, block): # pylint: disable=missing-function-docstring
return serialized

@staticmethod
def get_vertical_icon_class(block):
def get_vertical_icon_class(block, block_data):
"""
Get the icon class for a vertical block based priority of child blocks types.
Currently, the priority for the icon is as follows:
Expand All @@ -87,6 +89,8 @@ def get_vertical_icon_class(block):
for child in children
for value in (child.get('type'), child.get('icon_class'))
}
if not block_data:
return 'lock'
if 'problem' in child_classes:
return 'problem'
if 'video' in child_classes:
Expand Down
13 changes: 9 additions & 4 deletions lms/djangoapps/course_home_api/outline/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,8 @@ def get(self, request, *args, **kwargs): # pylint: disable=too-many-statements
#
# The long term goal is to remove the Course Blocks API call entirely,
# so this is a tiny first step in that migration.
if course_blocks:
user_is_audit = getattr(enrollment, 'mode', '') == 'audit'
if course_blocks and not user_is_audit:
user_course_outline = get_user_course_outline(
course_key, request.user, datetime.now(tz=timezone.utc)
)
Expand Down Expand Up @@ -451,6 +452,8 @@ def get(self, request, *args, **kwargs):
allow_public_outline = allow_anonymous and course.course_visibility == COURSE_VISIBILITY_PUBLIC_OUTLINE
enrollment = CourseEnrollment.get_enrollment(request.user, course_key)

user_is_audit = getattr(enrollment, 'mode', '') == 'audit'

try:
user_cohort = get_cohort(request.user, course_key, use_cached=True)
except ValueError:
Expand All @@ -472,15 +475,17 @@ def get(self, request, *args, **kwargs):
course_blocks = cache.get(cache_key)

if not course_blocks:
if getattr(enrollment, 'is_active', False) or bool(staff_access):
if bool(staff_access) or user_is_audit:
course_blocks = get_course_outline_block_tree(request, course_key_string, None)
elif getattr(enrollment, 'is_active', False):
course_blocks = get_course_outline_block_tree(request, course_key_string, request.user)
elif allow_public_outline or allow_public or user_is_masquerading:
course_blocks = get_course_outline_block_tree(request, course_key_string, None)

if not navigation_sidebar_caching_is_disabled:
cache.set(cache_key, course_blocks, self.COURSE_BLOCKS_CACHE_TIMEOUT)

course_blocks = self.filter_inaccessible_blocks(course_blocks, course_key)
if not user_is_audit:
course_blocks = self.filter_inaccessible_blocks(course_blocks, course_key)
course_blocks = self.mark_complete_recursive(course_blocks)

context = self.get_serializer_context()
Expand Down
6 changes: 4 additions & 2 deletions openedx/core/djangoapps/courseware_api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -815,9 +815,11 @@ def get(self, request, usage_key_string, *args, **kwargs): # lint-amnesty, pyli
view = STUDENT_VIEW
if request.user.is_anonymous:
view = PUBLIC_VIEW

enrollment = CourseEnrollment.get_enrollment(request.user, usage_key.course_key)
user_is_audit = getattr(enrollment, 'mode', '') == 'audit'
context = {
'specific_masquerade': is_masquerading_as_specific_student(request.user, usage_key.course_key)
'specific_masquerade': is_masquerading_as_specific_student(request.user, usage_key.course_key),
'user_is_audit': user_is_audit
}
return Response(sequence.get_metadata(view=view, context=context))

Expand Down
25 changes: 21 additions & 4 deletions xmodule/seq_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,22 +348,31 @@ def get_metadata(self, view=STUDENT_VIEW, context=None):
prereq_met = True
prereq_meta_info = {}
banner_text = None
children = self.get_children()
course = self._get_course()
is_hidden_after_due = False

children = list(self.get_children())

if not children and getattr(self, "children", None) and context.get("user_is_audit", False):
all_children = []
for child_locator in self.children:
try:
child_block = self.runtime.modulestore.get_item(child_locator)
setattr(child_block, "access_restricted", True)
all_children.append(child_block)
except Exception as e:
continue
if all_children:
children = all_children
if self._required_prereq():
if self.runtime.service(self, 'user').get_current_user().opt_attrs.get(ATTR_KEY_USER_IS_STAFF):
banner_text = _(
'This subsection is unlocked for learners when they meet the prerequisite requirements.'
)
else:
# check if prerequisite has been met
prereq_met, prereq_meta_info = self._compute_is_prereq_met(True)

if prereq_met and view == STUDENT_VIEW and not self._can_user_view_content(course):
if context.get('specific_masquerade', False):
# Still show the content, but flag to the staff user that the learner wouldn't be able to see it
banner_text = self._hidden_content_banner_text(course)
else:
is_hidden_after_due = True
Expand Down Expand Up @@ -570,6 +579,14 @@ def _get_render_metadata(self, context, children, prereq_met, prereq_meta_info,
'is_gated': True, # Mark as blocked
'content': '', # Real content not included
})
for block in blocks:
for child in children:
# Match block by usage ID
if str(child.scope_ids.usage_id) == str(block.get('id')):
# Check if child has the flag
if getattr(child, "access_restricted", False):
block['access_restricted'] = True
break # stop inner loop once matched

params = {
'items': blocks,
Expand Down
Loading