Skip to content

Commit f42c069

Browse files
committed
tests: add authorization tests for about page visibility and access
1 parent 033d56b commit f42c069

2 files changed

Lines changed: 140 additions & 1 deletion

File tree

lms/djangoapps/courseware/tests/test_about.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from common.djangoapps.student.tests.factories import CourseEnrollmentAllowedFactory, UserFactory
2020
from common.djangoapps.track.tests import EventTrackingTestCase
2121
from common.djangoapps.util.milestones_helpers import get_prerequisite_courses_display, set_prerequisite_courses
22+
from openedx.core.djangoapps.authz.tests.mixins import CourseAuthoringAuthzTestMixin
2223
from openedx.core.djangoapps.models.course_details import CourseDetails
2324
from openedx.features.course_experience import COURSE_ENABLE_UNENROLLED_ACCESS_FLAG, course_home_url
2425
from openedx.features.course_experience.waffle import ENABLE_COURSE_ABOUT_SIDEBAR_HTML
@@ -223,6 +224,33 @@ def test_about_page_public_view(self, course_visibility):
223224
self.assertContains(resp, "Enroll Now")
224225

225226

227+
class AuthzAboutPageTestCase(CourseAuthoringAuthzTestMixin, LoginEnrollmentTestCase, SharedModuleStoreTestCase):
228+
"""
229+
About page HTTP access when AuthZ course authoring is enabled.
230+
"""
231+
232+
@classmethod
233+
def setUpClass(cls):
234+
super().setUpClass()
235+
cls.course_without_about = CourseFactory.create(catalog_visibility=CATALOG_VISIBILITY_NONE)
236+
cls.course_with_about = CourseFactory.create(catalog_visibility=CATALOG_VISIBILITY_ABOUT)
237+
CourseDetails.update_about_item(cls.course_without_about, "overview", "WITHOUT ABOUT", None)
238+
CourseDetails.update_about_item(cls.course_with_about, "overview", "WITH ABOUT", None)
239+
240+
@override_settings(COURSE_ABOUT_VISIBILITY_PERMISSION="see_about_page")
241+
def test_about_page_honors_catalog_visibility_without_authz_role(self):
242+
"""A learner without AuthZ roles can view catalog-visible about pages."""
243+
self.client.force_login(self.unauthorized_user)
244+
245+
url = reverse("about_course", args=[str(self.course_with_about.id)])
246+
resp = self.client.get(url)
247+
self.assertContains(resp, "WITH ABOUT")
248+
249+
url = reverse("about_course", args=[str(self.course_without_about.id)])
250+
resp = self.client.get(url)
251+
self.assertRedirects(resp, reverse("dashboard"), fetch_redirect_response=False)
252+
253+
226254
class AboutTestCaseXML(LoginEnrollmentTestCase, ModuleStoreTestCase):
227255
"""
228256
Tests for the course about page

lms/djangoapps/courseware/tests/test_access.py

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@
2222
from enterprise.api.v1.serializers import EnterpriseCustomerSerializer
2323
from milestones.tests.utils import MilestonesTestCaseMixin
2424
from opaque_keys.edx.locator import CourseLocator
25+
from openedx_authz.constants.roles import COURSE_EDITOR
2526

2627
import lms.djangoapps.courseware.access as access
2728
import lms.djangoapps.courseware.access_response as access_response
29+
from common.djangoapps.student.auth import add_users
2830
from common.djangoapps.student.models import CourseEnrollment
29-
from common.djangoapps.student.roles import CourseCcxCoachRole, CourseStaffRole
31+
from common.djangoapps.student.roles import CourseCcxCoachRole, CourseLimitedStaffRole, CourseStaffRole
3032
from common.djangoapps.student.tests.factories import (
3133
AdminFactory,
3234
AnonymousUserFactory,
@@ -43,6 +45,8 @@
4345
from lms.djangoapps.courseware.masquerade import CourseMasquerade
4446
from lms.djangoapps.courseware.tests.helpers import LoginEnrollmentTestCase, masquerade_as_group_member
4547
from lms.djangoapps.courseware.toggles import course_is_invitation_only
48+
from openedx.core import toggles as core_toggles
49+
from openedx.core.djangoapps.authz.tests.mixins import CourseAuthoringAuthzTestMixin
4650
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
4751
from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory
4852
from openedx.core.djangoapps.waffle_utils.testutils import WAFFLE_TABLES
@@ -1019,3 +1023,110 @@ def test_course_catalog_access_num_queries_enterprise(self, user_attr_name, cour
10191023
course_overview = CourseOverview.get_from_id(course.id)
10201024
with self.assertNumQueries(num_queries, table_ignorelist=QUERY_COUNT_TABLE_IGNORELIST):
10211025
bool(access.has_access(user, 'see_exists', course_overview, course_key=course.id))
1026+
1027+
1028+
class AuthzSeeAboutPageAccessTestCase(CourseAuthoringAuthzTestMixin, SharedModuleStoreTestCase):
1029+
"""
1030+
see_about_page access when AuthZ course authoring is enabled for the course.
1031+
"""
1032+
1033+
@classmethod
1034+
def setUpClass(cls):
1035+
super().setUpClass()
1036+
cls.course_public = CourseFactory.create(
1037+
catalog_visibility=CATALOG_VISIBILITY_CATALOG_AND_ABOUT,
1038+
course="authzpublic",
1039+
)
1040+
cls.course_about_only = CourseFactory.create(
1041+
catalog_visibility=CATALOG_VISIBILITY_ABOUT,
1042+
course="authzabout",
1043+
)
1044+
cls.course_hidden = CourseFactory.create(
1045+
catalog_visibility=CATALOG_VISIBILITY_NONE,
1046+
course="authzhidden",
1047+
)
1048+
1049+
def _see_about_page_response(self, user, course):
1050+
course_overview = CourseOverview.get_from_id(course.id)
1051+
return access.has_access(user, "see_about_page", course_overview, course_key=course.id)
1052+
1053+
def test_learner_granted_via_catalog_visibility_both(self):
1054+
"""Learners without AuthZ roles can view the about page when catalog allows it."""
1055+
response = self._see_about_page_response(self.unauthorized_user, self.course_public)
1056+
self.assertTrue(response) # noqa: PT009
1057+
1058+
def test_learner_granted_via_catalog_visibility_about_only(self):
1059+
"""Learners without AuthZ roles can view about-only courses."""
1060+
response = self._see_about_page_response(self.unauthorized_user, self.course_about_only)
1061+
self.assertTrue(response) # noqa: PT009
1062+
1063+
def test_enrolled_learner_denied_when_catalog_hidden(self):
1064+
"""Enrollment alone does not grant about-page access when catalog is hidden."""
1065+
CourseEnrollmentFactory(user=self.unauthorized_user, course_id=self.course_hidden.id)
1066+
1067+
response = self._see_about_page_response(self.unauthorized_user, self.course_hidden)
1068+
1069+
self.assertFalse(response) # noqa: PT009
1070+
self.assertIsInstance(response, access_response.CatalogVisibilityError) # noqa: PT009
1071+
1072+
def test_beta_tester_granted_via_catalog_about(self):
1073+
"""Beta testers rely on catalog visibility, not AuthZ authoring permissions."""
1074+
beta_tester = BetaTesterFactory.create(course_key=self.course_about_only.id)
1075+
1076+
response = self._see_about_page_response(beta_tester, self.course_about_only)
1077+
1078+
self.assertTrue(response) # noqa: PT009
1079+
1080+
def test_course_staff_bypass_when_catalog_hidden(self):
1081+
"""Course staff can preview the about page when catalog visibility is none."""
1082+
course_staff = StaffFactory.create(course_key=self.course_hidden.id)
1083+
1084+
response = self._see_about_page_response(course_staff, self.course_hidden)
1085+
1086+
self.assertTrue(response) # noqa: PT009
1087+
1088+
def test_limited_staff_bypass_when_catalog_hidden(self):
1089+
"""Limited staff inherit staff bypass for about-page access."""
1090+
course_staff = StaffFactory.create(course_key=self.course_hidden.id)
1091+
limited_staff = UserFactory.create()
1092+
add_users(course_staff, CourseLimitedStaffRole(self.course_hidden.id), limited_staff)
1093+
1094+
response = self._see_about_page_response(limited_staff, self.course_hidden)
1095+
1096+
self.assertTrue(response) # noqa: PT009
1097+
1098+
def test_authz_role_grants_access_when_catalog_hidden(self):
1099+
"""Users with COURSES_VIEW_COURSE can access hidden about pages."""
1100+
self.add_user_to_role_in_course(self.unauthorized_user, COURSE_EDITOR.external_key, self.course_hidden.id)
1101+
1102+
response = self._see_about_page_response(self.unauthorized_user, self.course_hidden)
1103+
1104+
self.assertTrue(response) # noqa: PT009
1105+
1106+
def test_anonymous_user_uses_legacy_path(self):
1107+
"""Anonymous users are routed to the legacy path and follow catalog visibility."""
1108+
anonymous_user = AnonymousUserFactory.create()
1109+
1110+
response = self._see_about_page_response(anonymous_user, self.course_public)
1111+
1112+
self.assertTrue(response) # noqa: PT009
1113+
1114+
def test_denied_returns_catalog_visibility_error(self):
1115+
"""AuthZ path returns CatalogVisibilityError when all checks fail."""
1116+
response = self._see_about_page_response(self.unauthorized_user, self.course_hidden)
1117+
1118+
self.assertFalse(response) # noqa: PT009
1119+
self.assertIsInstance(response, access_response.CatalogVisibilityError) # noqa: PT009
1120+
self.assertEqual(response.error_code, "not_visible_in_catalog") # noqa: PT009
1121+
1122+
def test_legacy_path_when_authz_disabled(self):
1123+
"""When AuthZ is off, catalog visibility rules still apply."""
1124+
with patch.object(core_toggles.AUTHZ_COURSE_AUTHORING_FLAG, "is_enabled", return_value=False):
1125+
response = self._see_about_page_response(self.unauthorized_user, self.course_public)
1126+
1127+
self.assertTrue(response) # noqa: PT009
1128+
1129+
hidden_response = self._see_about_page_response(self.unauthorized_user, self.course_hidden)
1130+
1131+
self.assertFalse(hidden_response) # noqa: PT009
1132+
self.assertIsInstance(hidden_response, access_response.CatalogVisibilityError) # noqa: PT009

0 commit comments

Comments
 (0)