|
|
|
|
@@ -11,7 +11,6 @@ from django.urls import reverse
|
|
|
|
|
from django.utils import timezone
|
|
|
|
|
from mock import patch
|
|
|
|
|
|
|
|
|
|
from course_api.blocks.api import get_blocks
|
|
|
|
|
from django_comment_common.models import (
|
|
|
|
|
FORUM_ROLE_ADMINISTRATOR,
|
|
|
|
|
FORUM_ROLE_MODERATOR,
|
|
|
|
|
@@ -62,13 +61,6 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedMo
|
|
|
|
|
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
METADATA = {
|
|
|
|
|
'group_access': {
|
|
|
|
|
CONTENT_GATING_PARTITION_ID: [CONTENT_TYPE_GATE_GROUP_IDS['full_access']]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@patch("crum.get_current_request")
|
|
|
|
|
def _get_fragment_from_block(block, user_id, course, request_factory, mock_get_current_request):
|
|
|
|
|
"""
|
|
|
|
|
@@ -93,23 +85,24 @@ def _get_fragment_from_block(block, user_id, course, request_factory, mock_get_c
|
|
|
|
|
|
|
|
|
|
# This method of fetching the block from the descriptor bypassess access checks
|
|
|
|
|
problem_block = runtime.get_module(block)
|
|
|
|
|
|
|
|
|
|
# Attempt to render the block, this should return different fragments if the content is gated or not.
|
|
|
|
|
frag = runtime.render(problem_block, 'student_view')
|
|
|
|
|
return frag
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _assert_block_is_gated(block, is_gated, user, course, request_factory, has_upgrade_link=True):
|
|
|
|
|
def _assert_block_is_gated(block, is_gated, user_id, course, request_factory, has_upgrade_link=True):
|
|
|
|
|
"""
|
|
|
|
|
Asserts that a block in a specific course is gated for a specific user
|
|
|
|
|
Arguments:
|
|
|
|
|
block: some sort of xblock descriptor, must implement .scope_ids.usage_id
|
|
|
|
|
is_gated (bool): if True, this user is expected to be gated from this block
|
|
|
|
|
user (int): user
|
|
|
|
|
user_id (int): id of user
|
|
|
|
|
course_id (CourseLocator): id of course
|
|
|
|
|
"""
|
|
|
|
|
checkout_link = '#' if has_upgrade_link else None
|
|
|
|
|
with patch.object(ContentTypeGatingPartition, '_get_checkout_link', return_value=checkout_link):
|
|
|
|
|
frag = _get_fragment_from_block(block, user.id, course, request_factory)
|
|
|
|
|
frag = _get_fragment_from_block(block, user_id, course, request_factory)
|
|
|
|
|
if is_gated:
|
|
|
|
|
assert 'content-paywall' in frag.content
|
|
|
|
|
if has_upgrade_link:
|
|
|
|
|
@@ -119,15 +112,6 @@ def _assert_block_is_gated(block, is_gated, user, course, request_factory, has_u
|
|
|
|
|
else:
|
|
|
|
|
assert 'content-paywall' not in frag.content
|
|
|
|
|
|
|
|
|
|
fake_request = request_factory.get('')
|
|
|
|
|
with patch('lms.djangoapps.course_api.blocks.api.is_request_from_mobile_app', return_value=True):
|
|
|
|
|
blocks = get_blocks(fake_request, course.location, user=user)
|
|
|
|
|
course_api_block = blocks['blocks'][str(block.location)]
|
|
|
|
|
if is_gated:
|
|
|
|
|
assert 'authorization_denial_reason' in course_api_block
|
|
|
|
|
else:
|
|
|
|
|
assert 'authorization_denial_reason' not in course_api_block
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _assert_block_is_empty(block, user_id, course, request_factory):
|
|
|
|
|
"""
|
|
|
|
|
@@ -199,7 +183,6 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase):
|
|
|
|
|
display_name=case_name,
|
|
|
|
|
graded=graded,
|
|
|
|
|
weight=weight,
|
|
|
|
|
metadata=METADATA if (graded and has_score and weight) else {},
|
|
|
|
|
)
|
|
|
|
|
cls.graded_score_weight_blocks[(graded, has_score, weight)] = block
|
|
|
|
|
|
|
|
|
|
@@ -210,7 +193,6 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase):
|
|
|
|
|
display_name='lti_consumer',
|
|
|
|
|
has_score=True,
|
|
|
|
|
graded=True,
|
|
|
|
|
metadata=METADATA,
|
|
|
|
|
)
|
|
|
|
|
cls.blocks_dict['lti_block_not_scored'] = ItemFactory.create(
|
|
|
|
|
parent=cls.blocks_dict['vertical'],
|
|
|
|
|
@@ -225,7 +207,6 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase):
|
|
|
|
|
category='problem',
|
|
|
|
|
display_name='graded_problem',
|
|
|
|
|
graded=True,
|
|
|
|
|
metadata=METADATA,
|
|
|
|
|
)
|
|
|
|
|
cls.blocks_dict['ungraded_problem'] = ItemFactory.create(
|
|
|
|
|
parent=cls.blocks_dict['vertical'],
|
|
|
|
|
@@ -341,22 +322,22 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase):
|
|
|
|
|
blocks_dict = {}
|
|
|
|
|
chapter = ItemFactory.create(
|
|
|
|
|
parent=course,
|
|
|
|
|
display_name='Overview',
|
|
|
|
|
display_name='Overview'
|
|
|
|
|
)
|
|
|
|
|
blocks_dict['chapter'] = ItemFactory.create(
|
|
|
|
|
parent=course,
|
|
|
|
|
category='chapter',
|
|
|
|
|
display_name='Week 1',
|
|
|
|
|
display_name='Week 1'
|
|
|
|
|
)
|
|
|
|
|
blocks_dict['sequential'] = ItemFactory.create(
|
|
|
|
|
parent=chapter,
|
|
|
|
|
category='sequential',
|
|
|
|
|
display_name='Lesson 1',
|
|
|
|
|
display_name='Lesson 1'
|
|
|
|
|
)
|
|
|
|
|
blocks_dict['vertical'] = ItemFactory.create(
|
|
|
|
|
parent=blocks_dict['sequential'],
|
|
|
|
|
category='vertical',
|
|
|
|
|
display_name='Lesson 1 Vertical - Unit 1',
|
|
|
|
|
display_name='Lesson 1 Vertical - Unit 1'
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
for component_type in component_types:
|
|
|
|
|
@@ -365,7 +346,6 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase):
|
|
|
|
|
category=component_type,
|
|
|
|
|
display_name=component_type,
|
|
|
|
|
graded=True,
|
|
|
|
|
metadata={} if component_type == 'html' else METADATA
|
|
|
|
|
)
|
|
|
|
|
blocks_dict[component_type] = block
|
|
|
|
|
|
|
|
|
|
@@ -389,14 +369,14 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase):
|
|
|
|
|
def test_access_to_problems(self, prob_type, is_gated):
|
|
|
|
|
_assert_block_is_gated(
|
|
|
|
|
block=self.blocks_dict[prob_type],
|
|
|
|
|
user=self.users['audit'],
|
|
|
|
|
user_id=self.users['audit'].id,
|
|
|
|
|
course=self.course,
|
|
|
|
|
is_gated=is_gated,
|
|
|
|
|
request_factory=self.factory,
|
|
|
|
|
)
|
|
|
|
|
_assert_block_is_gated(
|
|
|
|
|
block=self.blocks_dict[prob_type],
|
|
|
|
|
user=self.users['verified'],
|
|
|
|
|
user_id=self.users['verified'].id,
|
|
|
|
|
course=self.course,
|
|
|
|
|
is_gated=False,
|
|
|
|
|
request_factory=self.factory,
|
|
|
|
|
@@ -411,7 +391,7 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase):
|
|
|
|
|
block = self.graded_score_weight_blocks[(graded, has_score, weight)]
|
|
|
|
|
_assert_block_is_gated(
|
|
|
|
|
block=block,
|
|
|
|
|
user=self.audit_user,
|
|
|
|
|
user_id=self.audit_user.id,
|
|
|
|
|
course=self.course,
|
|
|
|
|
is_gated=is_gated,
|
|
|
|
|
request_factory=self.factory,
|
|
|
|
|
@@ -446,7 +426,7 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase):
|
|
|
|
|
"""
|
|
|
|
|
_assert_block_is_gated(
|
|
|
|
|
block=self.courses[course]['blocks'][component_type],
|
|
|
|
|
user=self.users[user_track],
|
|
|
|
|
user_id=self.users[user_track].id,
|
|
|
|
|
course=self.courses[course]['course'],
|
|
|
|
|
is_gated=is_gated,
|
|
|
|
|
request_factory=self.factory,
|
|
|
|
|
@@ -459,7 +439,7 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase):
|
|
|
|
|
"""
|
|
|
|
|
_assert_block_is_gated(
|
|
|
|
|
block=self.courses['default']['blocks']['problem'],
|
|
|
|
|
user=self.users['audit'],
|
|
|
|
|
user_id=self.users['audit'].id,
|
|
|
|
|
course=self.courses['default']['course'],
|
|
|
|
|
is_gated=True,
|
|
|
|
|
request_factory=self.factory,
|
|
|
|
|
@@ -516,7 +496,7 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase):
|
|
|
|
|
# assert that course team members have access to graded content
|
|
|
|
|
_assert_block_is_gated(
|
|
|
|
|
block=self.blocks_dict['problem'],
|
|
|
|
|
user=user,
|
|
|
|
|
user_id=user.id,
|
|
|
|
|
course=self.course,
|
|
|
|
|
is_gated=False,
|
|
|
|
|
request_factory=self.factory,
|
|
|
|
|
@@ -538,7 +518,7 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase):
|
|
|
|
|
|
|
|
|
|
_assert_block_is_gated(
|
|
|
|
|
block=self.blocks_dict['problem'],
|
|
|
|
|
user=user,
|
|
|
|
|
user_id=user.id,
|
|
|
|
|
course=self.course,
|
|
|
|
|
is_gated=False,
|
|
|
|
|
request_factory=self.factory,
|
|
|
|
|
@@ -568,7 +548,7 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase):
|
|
|
|
|
block = self.graded_score_weight_blocks[(graded, has_score, weight)]
|
|
|
|
|
_assert_block_is_gated(
|
|
|
|
|
block=block,
|
|
|
|
|
user=user,
|
|
|
|
|
user_id=user.id,
|
|
|
|
|
course=self.course,
|
|
|
|
|
is_gated=is_gated,
|
|
|
|
|
request_factory=self.factory,
|
|
|
|
|
@@ -691,7 +671,7 @@ class TestProblemTypeAccess(SharedModuleStoreTestCase):
|
|
|
|
|
|
|
|
|
|
_assert_block_is_gated(
|
|
|
|
|
block=self.blocks_dict['problem'],
|
|
|
|
|
user=user,
|
|
|
|
|
user_id=user.id,
|
|
|
|
|
course=self.course,
|
|
|
|
|
is_gated=False,
|
|
|
|
|
request_factory=self.factory,
|
|
|
|
|
@@ -734,26 +714,24 @@ class TestConditionalContentAccess(TestConditionalContent):
|
|
|
|
|
user=self.student_verified_a,
|
|
|
|
|
course_id=self.course.id,
|
|
|
|
|
key='xblock.partition_service.partition_{0}'.format(self.partition.id),
|
|
|
|
|
value=str('0'),
|
|
|
|
|
value=str('user_course_tag_a'),
|
|
|
|
|
)
|
|
|
|
|
UserCourseTagFactory(
|
|
|
|
|
user=self.student_verified_b,
|
|
|
|
|
course_id=self.course.id,
|
|
|
|
|
key='xblock.partition_service.partition_{0}'.format(self.partition.id),
|
|
|
|
|
value=str('1'),
|
|
|
|
|
value=str('user_course_tag_b'),
|
|
|
|
|
)
|
|
|
|
|
# Create blocks to go into the verticals
|
|
|
|
|
self.block_a = ItemFactory.create(
|
|
|
|
|
category='problem',
|
|
|
|
|
parent=self.vertical_a,
|
|
|
|
|
display_name='problem_a',
|
|
|
|
|
metadata=METADATA,
|
|
|
|
|
)
|
|
|
|
|
self.block_b = ItemFactory.create(
|
|
|
|
|
category='problem',
|
|
|
|
|
parent=self.vertical_b,
|
|
|
|
|
display_name='problem_b',
|
|
|
|
|
metadata=METADATA,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def test_access_based_on_conditional_content(self):
|
|
|
|
|
@@ -765,14 +743,14 @@ class TestConditionalContentAccess(TestConditionalContent):
|
|
|
|
|
# Make sure that all audit enrollments are gated regardless of if they see vertical a or vertical b
|
|
|
|
|
_assert_block_is_gated(
|
|
|
|
|
block=self.block_a,
|
|
|
|
|
user=self.student_audit_a,
|
|
|
|
|
user_id=self.student_audit_a.id,
|
|
|
|
|
course=self.course,
|
|
|
|
|
is_gated=True,
|
|
|
|
|
request_factory=self.factory,
|
|
|
|
|
)
|
|
|
|
|
_assert_block_is_gated(
|
|
|
|
|
block=self.block_b,
|
|
|
|
|
user=self.student_audit_b,
|
|
|
|
|
user_id=self.student_audit_b.id,
|
|
|
|
|
course=self.course,
|
|
|
|
|
is_gated=True,
|
|
|
|
|
request_factory=self.factory,
|
|
|
|
|
@@ -781,14 +759,14 @@ class TestConditionalContentAccess(TestConditionalContent):
|
|
|
|
|
# Make sure that all verified enrollments are not gated regardless of if they see vertical a or vertical b
|
|
|
|
|
_assert_block_is_gated(
|
|
|
|
|
block=self.block_a,
|
|
|
|
|
user=self.student_verified_a,
|
|
|
|
|
user_id=self.student_verified_a.id,
|
|
|
|
|
course=self.course,
|
|
|
|
|
is_gated=False,
|
|
|
|
|
request_factory=self.factory,
|
|
|
|
|
)
|
|
|
|
|
_assert_block_is_gated(
|
|
|
|
|
block=self.block_b,
|
|
|
|
|
user=self.student_verified_b,
|
|
|
|
|
user_id=self.student_verified_b.id,
|
|
|
|
|
course=self.course,
|
|
|
|
|
is_gated=False,
|
|
|
|
|
request_factory=self.factory,
|
|
|
|
|
@@ -858,11 +836,10 @@ class TestMessageDeduplication(ModuleStoreTestCase):
|
|
|
|
|
category='problem',
|
|
|
|
|
display_name='graded_problem',
|
|
|
|
|
graded=True,
|
|
|
|
|
metadata=METADATA,
|
|
|
|
|
)
|
|
|
|
|
_assert_block_is_gated(
|
|
|
|
|
block=blocks_dict['graded_1'],
|
|
|
|
|
user=self.user,
|
|
|
|
|
user_id=self.user.id,
|
|
|
|
|
course=course['course'],
|
|
|
|
|
is_gated=True,
|
|
|
|
|
request_factory=self.request_factory,
|
|
|
|
|
@@ -877,14 +854,12 @@ class TestMessageDeduplication(ModuleStoreTestCase):
|
|
|
|
|
category='problem',
|
|
|
|
|
display_name='graded_problem',
|
|
|
|
|
graded=True,
|
|
|
|
|
metadata=METADATA,
|
|
|
|
|
)
|
|
|
|
|
blocks_dict['graded_2'] = ItemFactory.create(
|
|
|
|
|
parent=blocks_dict['vertical'],
|
|
|
|
|
category='problem',
|
|
|
|
|
display_name='graded_problem',
|
|
|
|
|
graded=True,
|
|
|
|
|
metadata=METADATA,
|
|
|
|
|
)
|
|
|
|
|
CourseEnrollmentFactory.create(
|
|
|
|
|
user=self.user,
|
|
|
|
|
@@ -893,7 +868,7 @@ class TestMessageDeduplication(ModuleStoreTestCase):
|
|
|
|
|
)
|
|
|
|
|
_assert_block_is_gated(
|
|
|
|
|
block=blocks_dict['graded_1'],
|
|
|
|
|
user=self.user,
|
|
|
|
|
user_id=self.user.id,
|
|
|
|
|
course=course['course'],
|
|
|
|
|
is_gated=True,
|
|
|
|
|
request_factory=self.request_factory,
|
|
|
|
|
@@ -914,28 +889,24 @@ class TestMessageDeduplication(ModuleStoreTestCase):
|
|
|
|
|
category='problem',
|
|
|
|
|
display_name='graded_problem',
|
|
|
|
|
graded=True,
|
|
|
|
|
metadata=METADATA,
|
|
|
|
|
)
|
|
|
|
|
blocks_dict['graded_2'] = ItemFactory.create(
|
|
|
|
|
parent=blocks_dict['vertical'],
|
|
|
|
|
category='problem',
|
|
|
|
|
display_name='graded_problem',
|
|
|
|
|
graded=True,
|
|
|
|
|
metadata=METADATA,
|
|
|
|
|
)
|
|
|
|
|
blocks_dict['graded_3'] = ItemFactory.create(
|
|
|
|
|
parent=blocks_dict['vertical'],
|
|
|
|
|
category='problem',
|
|
|
|
|
display_name='graded_problem',
|
|
|
|
|
graded=True,
|
|
|
|
|
metadata=METADATA,
|
|
|
|
|
)
|
|
|
|
|
blocks_dict['graded_4'] = ItemFactory.create(
|
|
|
|
|
parent=blocks_dict['vertical'],
|
|
|
|
|
category='problem',
|
|
|
|
|
display_name='graded_problem',
|
|
|
|
|
graded=True,
|
|
|
|
|
metadata=METADATA,
|
|
|
|
|
)
|
|
|
|
|
CourseEnrollmentFactory.create(
|
|
|
|
|
user=self.user,
|
|
|
|
|
@@ -944,7 +915,7 @@ class TestMessageDeduplication(ModuleStoreTestCase):
|
|
|
|
|
)
|
|
|
|
|
_assert_block_is_gated(
|
|
|
|
|
block=blocks_dict['graded_1'],
|
|
|
|
|
user=self.user,
|
|
|
|
|
user_id=self.user.id,
|
|
|
|
|
course=course['course'],
|
|
|
|
|
is_gated=True,
|
|
|
|
|
request_factory=self.request_factory,
|
|
|
|
|
@@ -977,7 +948,6 @@ class TestMessageDeduplication(ModuleStoreTestCase):
|
|
|
|
|
category='problem',
|
|
|
|
|
display_name='graded_problem',
|
|
|
|
|
graded=True,
|
|
|
|
|
metadata=METADATA,
|
|
|
|
|
)
|
|
|
|
|
blocks_dict['ungraded_2'] = ItemFactory.create(
|
|
|
|
|
parent=blocks_dict['vertical'],
|
|
|
|
|
@@ -990,7 +960,6 @@ class TestMessageDeduplication(ModuleStoreTestCase):
|
|
|
|
|
category='problem',
|
|
|
|
|
display_name='graded_problem',
|
|
|
|
|
graded=True,
|
|
|
|
|
metadata=METADATA,
|
|
|
|
|
)
|
|
|
|
|
CourseEnrollmentFactory.create(
|
|
|
|
|
user=self.user,
|
|
|
|
|
@@ -999,21 +968,21 @@ class TestMessageDeduplication(ModuleStoreTestCase):
|
|
|
|
|
)
|
|
|
|
|
_assert_block_is_gated(
|
|
|
|
|
block=blocks_dict['graded_1'],
|
|
|
|
|
user=self.user,
|
|
|
|
|
user_id=self.user.id,
|
|
|
|
|
course=course['course'],
|
|
|
|
|
is_gated=True,
|
|
|
|
|
request_factory=self.request_factory,
|
|
|
|
|
)
|
|
|
|
|
_assert_block_is_gated(
|
|
|
|
|
block=blocks_dict['ungraded_2'],
|
|
|
|
|
user=self.user,
|
|
|
|
|
user_id=self.user.id,
|
|
|
|
|
course=course['course'],
|
|
|
|
|
is_gated=False,
|
|
|
|
|
request_factory=self.request_factory,
|
|
|
|
|
)
|
|
|
|
|
_assert_block_is_gated(
|
|
|
|
|
block=blocks_dict['graded_3'],
|
|
|
|
|
user=self.user,
|
|
|
|
|
user_id=self.user.id,
|
|
|
|
|
course=course['course'],
|
|
|
|
|
is_gated=True,
|
|
|
|
|
request_factory=self.request_factory,
|
|
|
|
|
|