Skip to content

Commit 47c5078

Browse files
authored
fix: avoid anonymous completion lookup in navigation (#38024)
Return empty completions_dict for AnonymousUser in CourseNavigationBlocksView to prevent 500 on /api/course_home/v1/navigation/{course_key} for public anonymous access. Keeps existing outline access filtering unchanged.
1 parent abe6ffa commit 47c5078

2 files changed

Lines changed: 21 additions & 0 deletions

File tree

lms/djangoapps/course_home_api/outline/tests/test_view.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import ddt
1111
from completion.models import BlockCompletion
1212
from django.conf import settings
13+
from django.contrib.auth.models import AnonymousUser
1314
from django.test import override_settings
1415
from django.urls import reverse
1516
from edx_toggles.toggles.testutils import override_waffle_flag
@@ -20,6 +21,7 @@
2021
from common.djangoapps.student.models import CourseEnrollment
2122
from common.djangoapps.student.roles import CourseInstructorRole
2223
from common.djangoapps.student.tests.factories import UserFactory
24+
from lms.djangoapps.course_home_api.outline.views import CourseNavigationBlocksView
2325
from lms.djangoapps.course_home_api.tests.utils import BaseCourseHomeTests
2426
from lms.djangoapps.course_home_api.toggles import COURSE_HOME_SEND_COURSE_PROGRESS_ANALYTICS_FOR_STUDENT
2527
from lms.djangoapps.grades.course_grade_factory import CourseGradeFactory
@@ -584,6 +586,20 @@ def test_get_unauthenticated_user(self):
584586
assert response.status_code == 200
585587
assert response.data.get('blocks') is None
586588

589+
def test_anonymous_user_completion_dict_does_not_lookup_completions(self):
590+
"""
591+
Test that anonymous users do not query completion data.
592+
"""
593+
view = CourseNavigationBlocksView()
594+
view.request = Mock(user=AnonymousUser())
595+
view.kwargs = {'course_key_string': str(self.course.id)}
596+
597+
with patch('lms.djangoapps.course_home_api.outline.views.BlockCompletion.objects.filter') as mock_filter:
598+
completions = view.completions_dict
599+
600+
assert completions == {}
601+
mock_filter.assert_not_called()
602+
587603
def test_course_staff_can_see_non_user_specific_content_in_masquerade(self):
588604
"""
589605
Test that course staff can see the outline and other non-user-specific content when masquerading as a learner

lms/djangoapps/course_home_api/outline/views.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,11 @@ def completions_dict(self):
613613
Dictionary keys are block keys and values are int values
614614
representing the completion status of the block.
615615
"""
616+
# Anonymous users have no completion rows; return empty data to avoid
617+
# querying BlockCompletion with AnonymousUser for public course navigation.
618+
if self.request.user.is_anonymous:
619+
return {}
620+
616621
course_key_string = self.kwargs.get('course_key_string')
617622
course_key = CourseKey.from_string(course_key_string)
618623
completions = BlockCompletion.objects.filter(user=self.request.user, context_key=course_key).values_list(

0 commit comments

Comments
 (0)