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:
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user