diff --git a/lms/djangoapps/course_api/blocks/tests/test_api.py b/lms/djangoapps/course_api/blocks/tests/test_api.py index c0d2749513ed..a3b6080ca024 100644 --- a/lms/djangoapps/course_api/blocks/tests/test_api.py +++ b/lms/djangoapps/course_api/blocks/tests/test_api.py @@ -222,12 +222,12 @@ def test_query_counts_cached(self, store_type, with_storage_backing): self._get_blocks( course, expected_mongo_queries=0, - expected_sql_queries=14 if with_storage_backing else 13, + expected_sql_queries=22 if with_storage_backing else 21, ) @ddt.data( - (ModuleStoreEnum.Type.split, 2, True, 23), - (ModuleStoreEnum.Type.split, 2, False, 13), + (ModuleStoreEnum.Type.split, 2, True, 31), + (ModuleStoreEnum.Type.split, 2, False, 21), ) @ddt.unpack def test_query_counts_uncached(self, store_type, expected_mongo_queries, with_storage_backing, num_sql_queries): diff --git a/lms/djangoapps/grades/tests/test_tasks.py b/lms/djangoapps/grades/tests/test_tasks.py index 4c4f60d731ea..b5c0d5b6ff17 100644 --- a/lms/djangoapps/grades/tests/test_tasks.py +++ b/lms/djangoapps/grades/tests/test_tasks.py @@ -153,8 +153,8 @@ def test_block_structure_created_only_once(self): assert mock_block_structure_create.call_count == 1 @ddt.data( - (ModuleStoreEnum.Type.split, 2, 41, True), - (ModuleStoreEnum.Type.split, 2, 41, False), + (ModuleStoreEnum.Type.split, 2, 49, True), + (ModuleStoreEnum.Type.split, 2, 49, False), ) @ddt.unpack def test_query_counts(self, default_store, num_mongo_calls, num_sql_calls, create_multiple_subsections): @@ -165,7 +165,7 @@ def test_query_counts(self, default_store, num_mongo_calls, num_sql_calls, creat self._apply_recalculate_subsection_grade() @ddt.data( - (ModuleStoreEnum.Type.split, 2, 41), + (ModuleStoreEnum.Type.split, 2, 49), ) @ddt.unpack def test_query_counts_dont_change_with_more_content(self, default_store, num_mongo_calls, num_sql_calls): @@ -210,7 +210,7 @@ def test_other_inaccessible_subsection(self, mock_subsection_signal): ) @ddt.data( - (ModuleStoreEnum.Type.split, 2, 41), + (ModuleStoreEnum.Type.split, 2, 49), ) @ddt.unpack def test_persistent_grades_on_course(self, default_store, num_mongo_queries, num_sql_queries): diff --git a/openedx/core/djangoapps/course_roles/rules.py b/openedx/core/djangoapps/course_roles/rules.py index 51f615ac8fa6..2767be8e29f0 100644 --- a/openedx/core/djangoapps/course_roles/rules.py +++ b/openedx/core/djangoapps/course_roles/rules.py @@ -70,7 +70,7 @@ class HasForumsRolesRule(CourseRolesRule): # lint-amnesty, pylint: disable=abst Rule to check if a user has a forum role for a course. """ def __init__(self, *roles): - self.role = roles + self.roles = roles def check(self, user, instance=None): if not use_permission_checks(): diff --git a/openedx/core/djangoapps/schedules/tests/test_resolvers.py b/openedx/core/djangoapps/schedules/tests/test_resolvers.py index 5881861b2282..36bc8beacd32 100644 --- a/openedx/core/djangoapps/schedules/tests/test_resolvers.py +++ b/openedx/core/djangoapps/schedules/tests/test_resolvers.py @@ -274,7 +274,7 @@ def create_resolver(self, user_start_date_offset=8): def test_schedule_context(self): resolver = self.create_resolver() # using this to make sure the select_related stays intact - with self.assertNumQueries(30): + with self.assertNumQueries(38): sc = resolver.get_schedules() schedules = list(sc) apple_logo_url = 'http://email-media.s3.amazonaws.com/edX/2021/store_apple_229x78.jpg' diff --git a/openedx/features/content_type_gating/helpers.py b/openedx/features/content_type_gating/helpers.py index 05323d7c57f8..f8b341c6138c 100644 --- a/openedx/features/content_type_gating/helpers.py +++ b/openedx/features/content_type_gating/helpers.py @@ -7,6 +7,7 @@ from django.utils import timezone from common.djangoapps.course_modes.models import CourseMode +from openedx.core.djangoapps.course_roles.data import CourseRolesPermission from openedx.core.djangoapps.config_model_utils.utils import is_in_holdback from common.djangoapps.student.models import CourseEnrollment from common.djangoapps.student.role_helpers import has_staff_roles @@ -114,7 +115,20 @@ def enrollment_date_for_fbe(user, course_key=None, course=None): elif full_access_masquerade is False: user = None # we are masquerading as a generic user, not a specific one -- avoid all user checks below - if user and user.id and has_staff_roles(user, course_key): + permissions = [ + CourseRolesPermission.MODERATE_DISCUSSION_FORUMS.perm_name, + CourseRolesPermission.MODERATE_DISCUSSION_FORUMS_FOR_A_COHORT.perm_name, + CourseRolesPermission.VIEW_ALL_CONTENT.perm_name, + CourseRolesPermission.VIEW_LIVE_PUBLISHED_CONTENT.perm_name, + CourseRolesPermission.VIEW_ALL_PUBLISHED_CONTENT.perm_name, + ] + if user: + has_permission = any(user.has_perm(permission, course_key) for permission in permissions) + else: + has_permission = False + # TODO: remove role checks once course_roles is fully impelented and data is migrated + if user and user.id and (has_staff_roles(user, course_key) or + has_permission): return None enrollment = user and CourseEnrollment.get_enrollment(user, course_key, ['fbeenrollmentexclusion']) diff --git a/openedx/features/content_type_gating/tests/test_models.py b/openedx/features/content_type_gating/tests/test_models.py index 673ce805a750..64c7a5761514 100644 --- a/openedx/features/content_type_gating/tests/test_models.py +++ b/openedx/features/content_type_gating/tests/test_models.py @@ -9,12 +9,16 @@ import pytz from django.utils import timezone from edx_django_utils.cache import RequestCache +from edx_toggles.toggles.testutils import override_waffle_flag from unittest.mock import Mock # lint-amnesty, pylint: disable=wrong-import-order from opaque_keys.edx.locator import CourseLocator from common.djangoapps.course_modes.tests.factories import CourseModeFactory from openedx.core.djangoapps.config_model_utils.models import Provenance from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory +from openedx.core.djangoapps.course_roles.data import CourseRolesPermission +from openedx.core.djangoapps.course_roles.models import Role, Permission, UserRole +from openedx.core.djangoapps.course_roles.toggles import USE_PERMISSION_CHECKS_FLAG from openedx.core.djangoapps.site_configuration.tests.factories import SiteConfigurationFactory from openedx.core.djangolib.testing.utils import CacheIsolationTestCase from openedx.features.content_type_gating.models import ContentTypeGatingConfig @@ -71,7 +75,7 @@ def test_enabled_for_enrollment( user = self.user course_key = self.course_overview.id - query_count = 7 + query_count = 15 with self.assertNumQueries(query_count): enabled = ContentTypeGatingConfig.enabled_for_enrollment( @@ -88,6 +92,26 @@ def test_enabled_for_enrollment_failure(self): with pytest.raises(ValueError): ContentTypeGatingConfig.enabled_for_enrollment(None, Mock(name='course_key')) + @ddt.data( + CourseRolesPermission.MODERATE_DISCUSSION_FORUMS.value.name, + CourseRolesPermission.MODERATE_DISCUSSION_FORUMS_FOR_A_COHORT.value.name, + CourseRolesPermission.VIEW_ALL_CONTENT.value.name, + CourseRolesPermission.VIEW_LIVE_PUBLISHED_CONTENT.value.name, + CourseRolesPermission.VIEW_ALL_PUBLISHED_CONTENT.value.name, + ) + @override_waffle_flag(USE_PERMISSION_CHECKS_FLAG, active=True) + def test_enabled_for_enrollment_fails_if_user_has_content_or_discussion_permissions(self, permission_name): + role = Role.objects.create(name="test_role_1") + permission = Permission.objects.create(name=permission_name) + role.permissions.add(permission) + UserRole.objects.create( + user=self.user, + role=role, + course_id=self.course_overview.id, + ) + enabled = ContentTypeGatingConfig.enabled_for_enrollment(self.user, self.course_overview.id) + assert not enabled + @ddt.data(True, False) def test_enabled_for_course( self, diff --git a/openedx/features/course_duration_limits/tests/test_models.py b/openedx/features/course_duration_limits/tests/test_models.py index 0473faefd330..7f17e95e281d 100644 --- a/openedx/features/course_duration_limits/tests/test_models.py +++ b/openedx/features/course_duration_limits/tests/test_models.py @@ -11,12 +11,16 @@ import pytz from django.utils import timezone from edx_django_utils.cache import RequestCache +from edx_toggles.toggles.testutils import override_waffle_flag from opaque_keys.edx.locator import CourseLocator from common.djangoapps.course_modes.tests.factories import CourseModeFactory from common.djangoapps.student.tests.factories import CourseEnrollmentFactory, UserFactory from openedx.core.djangoapps.config_model_utils.models import Provenance from openedx.core.djangoapps.content.course_overviews.tests.factories import CourseOverviewFactory +from openedx.core.djangoapps.course_roles.data import CourseRolesPermission +from openedx.core.djangoapps.course_roles.models import Role, Permission, UserRole +from openedx.core.djangoapps.course_roles.toggles import USE_PERMISSION_CHECKS_FLAG from openedx.core.djangoapps.site_configuration.tests.factories import SiteConfigurationFactory from openedx.core.djangolib.testing.utils import CacheIsolationTestCase from openedx.features.course_duration_limits.models import CourseDurationLimitConfig @@ -74,7 +78,7 @@ def test_enabled_for_enrollment( user = self.user course_key = self.course_overview.id # lint-amnesty, pylint: disable=unused-variable - query_count = 7 + query_count = 15 with self.assertNumQueries(query_count): enabled = CourseDurationLimitConfig.enabled_for_enrollment(user, self.course_overview) @@ -94,6 +98,26 @@ def test_enabled_for_enrollment_failure(self): Mock(name='course_key') ) + @ddt.data( + CourseRolesPermission.MODERATE_DISCUSSION_FORUMS.value.name, + CourseRolesPermission.MODERATE_DISCUSSION_FORUMS_FOR_A_COHORT.value.name, + CourseRolesPermission.VIEW_ALL_CONTENT.value.name, + CourseRolesPermission.VIEW_LIVE_PUBLISHED_CONTENT.value.name, + CourseRolesPermission.VIEW_ALL_PUBLISHED_CONTENT.value.name, + ) + @override_waffle_flag(USE_PERMISSION_CHECKS_FLAG, active=True) + def test_enabled_for_enrollment_fails_if_user_has_content_or_discussion_permissions(self, permission_name): + role = Role.objects.create(name="test_role_1") + permission = Permission.objects.create(name=permission_name) + role.permissions.add(permission) + UserRole.objects.create( + user=self.user, + role=role, + course_id=self.course_overview.id, + ) + enabled = CourseDurationLimitConfig.enabled_for_enrollment(self.user, self.course_overview) + assert not enabled + @ddt.data(True, False) def test_enabled_for_course( self,