Return content type gate for staff users when masquerading as the Learner in Audit or Learner in Limited Access Roles

This is necessary to display the content type gate in the UI
AA-613
This commit is contained in:
Matthew Piatetsky
2021-02-01 22:15:42 -05:00
parent 71b15df66c
commit ae7d0a1ed8
6 changed files with 117 additions and 91 deletions

View File

@@ -479,6 +479,13 @@ class SequenceMetadata(DeveloperErrorViewMixin, APIView):
except InvalidKeyError:
raise NotFound("Invalid usage key: '{}'.".format(usage_key_string))
_, request.user = setup_masquerade(
request,
usage_key.course_key,
staff_access=has_access(request.user, 'staff', usage_key.course_key),
reset_masquerade_data=True,
)
sequence, _ = get_module_by_usage_id(
self.request,
str(usage_key.course_key),

View File

@@ -1,8 +1,13 @@
"""
Content Type Gating service.
"""
import crum
from lms.djangoapps.courseware.access import has_access
from lms.djangoapps.courseware.masquerade import (
is_masquerading_as_limited_access, is_masquerading_as_audit_enrollment,
)
from openedx.core.lib.graph_traversals import get_children, leaf_filter, traverse_pre_order
from openedx.features.content_type_gating.models import ContentTypeGatingConfig
@@ -12,13 +17,23 @@ class ContentTypeGatingService(object):
and field overrides to gate course content.
This service was created as a helper class for handling timed exams that contain content type gated problems.
"""
def enabled_for_enrollment(self, **kwargs):
def _enabled_for_enrollment(self, **kwargs):
"""
Returns whether content type gating is enabled for a given user/course pair
"""
return ContentTypeGatingConfig.enabled_for_enrollment(**kwargs)
def content_type_gate_for_block(self, user, block, course_id):
def _is_masquerading_as_audit_or_limited_access(self, user, course_id):
return (is_masquerading_as_limited_access(user, course_id) or
is_masquerading_as_audit_enrollment(user, course_id))
def _get_user(self):
"""
Return the current request user.
"""
return crum.get_current_user()
def _content_type_gate_for_block(self, user, block, course_id):
"""
Returns a Fragment of the content type gate (if any) that would appear for a given block
"""
@@ -29,4 +44,33 @@ class ContentTypeGatingService(object):
access = has_access(user, 'load', block, course_id)
if (not access and access.error_code == 'incorrect_user_group'):
return access.user_fragment
return None
def check_children_for_content_type_gating_paywall(self, item, course_id):
"""
Arguments:
item (xblock such as a sequence or vertical block)
course_id (CourseLocator)
If:
This xblock contains problems which this user cannot load due to content type gating
Then:
Return the first content type gating paywall (Fragment)
Else:
Return None
"""
user = self._get_user()
if not user:
return None
if not self._enabled_for_enrollment(user=user, course_key=course_id):
return None
# Check children for content type gated content
for block in traverse_pre_order(item, get_children, leaf_filter):
gate_fragment = self._content_type_gate_for_block(user, block, course_id)
if gate_fragment is not None:
return gate_fragment.content
return None

View File

@@ -1156,7 +1156,7 @@ class TestContentTypeGatingService(ModuleStoreTestCase):
# The method returns a content type gate for blocks that should be gated
self.assertIn(
'content-paywall',
ContentTypeGatingService().content_type_gate_for_block(
ContentTypeGatingService()._content_type_gate_for_block(
self.user, blocks_dict['graded_1'], course['course'].id
).content
)
@@ -1164,7 +1164,47 @@ class TestContentTypeGatingService(ModuleStoreTestCase):
# The method returns None for blocks that should not be gated
self.assertEquals(
None,
ContentTypeGatingService().content_type_gate_for_block(
ContentTypeGatingService()._content_type_gate_for_block(
self.user, blocks_dict['not_graded_1'], course['course'].id
)
)
@patch.object(ContentTypeGatingService, '_get_user', return_value=UserFactory.build())
def test_check_children_for_content_type_gating_paywall(self, mocked_user): # pylint: disable=unused-argument
''' Verify that the method returns a content type gate when appropriate '''
course = self._create_course()
blocks_dict = course['blocks']
CourseEnrollmentFactory.create(
user=self.user,
course_id=course['course'].id,
mode='audit'
)
blocks_dict['not_graded_1'] = ItemFactory.create(
parent=blocks_dict['vertical'],
category='problem',
graded=False,
metadata=METADATA,
)
# The method returns a content type gate for blocks that should be gated
self.assertEquals(
None,
ContentTypeGatingService().check_children_for_content_type_gating_paywall(
blocks_dict['vertical'], course['course'].id
)
)
blocks_dict['graded_1'] = ItemFactory.create(
parent=blocks_dict['vertical'],
category='problem',
graded=True,
metadata=METADATA,
)
# The method returns None for blocks that should not be gated
self.assertIn(
'content-paywall',
ContentTypeGatingService().check_children_for_content_type_gating_paywall(
blocks_dict['vertical'], course['course'].id
)
)