Added completion from root to child blocks api and increased version
* Added completion from root to child blocks api and increased version Learner-8158
This commit is contained in:
@@ -11,6 +11,7 @@ from urllib.parse import urlencode, urlunparse
|
||||
from django.conf import settings
|
||||
from django.urls import reverse
|
||||
from opaque_keys.edx.locator import CourseLocator
|
||||
from completion.test_utils import CompletionWaffleTestMixin, submit_completions_for_testing
|
||||
|
||||
from common.djangoapps.student.models import CourseEnrollment
|
||||
from common.djangoapps.student.tests.factories import AdminFactory, CourseEnrollmentFactory, UserFactory
|
||||
@@ -395,7 +396,7 @@ class TestBlocksView(SharedModuleStoreTestCase):
|
||||
self.verify_response_with_requested_fields(response)
|
||||
|
||||
|
||||
class TestBlocksInCourseView(TestBlocksView): # pylint: disable=test-inherits-tests
|
||||
class TestBlocksInCourseView(TestBlocksView, CompletionWaffleTestMixin): # pylint: disable=test-inherits-tests
|
||||
"""
|
||||
Test class for BlocksInCourseView
|
||||
"""
|
||||
@@ -404,6 +405,13 @@ class TestBlocksInCourseView(TestBlocksView): # pylint: disable=test-inherits-t
|
||||
super(TestBlocksInCourseView, self).setUp()
|
||||
self.url = reverse('blocks_in_course')
|
||||
self.query_params['course_id'] = str(self.course_key)
|
||||
self.override_waffle_switch(True)
|
||||
self.non_orphaned_raw_block_usage_keys = set(
|
||||
item.location
|
||||
for item in self.store.get_items(self.course_key)
|
||||
# remove all orphaned items in the course, except for the root 'course' block
|
||||
if self.store.get_parent_location(item.location) or item.category == 'course'
|
||||
)
|
||||
|
||||
def test_no_course_id(self):
|
||||
self.query_params.pop('course_id')
|
||||
@@ -419,3 +427,42 @@ class TestBlocksInCourseView(TestBlocksView): # pylint: disable=test-inherits-t
|
||||
self.client.logout()
|
||||
self.query_params['username'] = ''
|
||||
self.verify_response(403, params={'course_id': str(CourseLocator('non', 'existent', 'course'))})
|
||||
|
||||
def test_completion_one_unit(self):
|
||||
for item in self.store.get_items(self.course_key):
|
||||
if item.category == 'html':
|
||||
block_usage_key = item.location
|
||||
break
|
||||
|
||||
submit_completions_for_testing(self.user, [block_usage_key])
|
||||
response = self.verify_response(params={
|
||||
'depth': 'all',
|
||||
'requested_fields': ['completion', 'children'],
|
||||
})
|
||||
|
||||
completion = response.data['blocks'][str(block_usage_key)].get('completion')
|
||||
self.assertTrue(completion)
|
||||
|
||||
def test_completion_all_course(self):
|
||||
for block in self.non_orphaned_raw_block_usage_keys:
|
||||
submit_completions_for_testing(self.user, [block])
|
||||
|
||||
response = self.verify_response(params={
|
||||
'depth': 'all',
|
||||
'requested_fields': ['completion', 'children'],
|
||||
})
|
||||
for block_id in self.non_orphaned_block_usage_keys:
|
||||
self.assertTrue(response.data['blocks'][block_id].get('completion'))
|
||||
|
||||
def test_completion_all_course_with_list_return_type(self):
|
||||
for block in self.non_orphaned_raw_block_usage_keys:
|
||||
submit_completions_for_testing(self.user, [block])
|
||||
|
||||
response = self.verify_response(params={
|
||||
'depth': 'all',
|
||||
'return_type': 'list',
|
||||
'requested_fields': ['completion', 'children'],
|
||||
})
|
||||
for block in response.data:
|
||||
if block['block_id'] in self.non_orphaned_block_usage_keys:
|
||||
self.assertTrue(block.get('completion'))
|
||||
|
||||
@@ -302,4 +302,54 @@ class BlocksInCourseView(BlocksView):
|
||||
course_usage_key = modulestore().make_course_usage_key(course_key)
|
||||
except InvalidKeyError:
|
||||
raise ValidationError(u"'{}' is not a valid course key.".format(six.text_type(course_key_string)))
|
||||
return super(BlocksInCourseView, self).list(request, course_usage_key, hide_access_denials=hide_access_denials)
|
||||
response = super().list(request, course_usage_key,
|
||||
hide_access_denials=hide_access_denials)
|
||||
|
||||
if 'completion' not in request.query_params.getlist('requested_fields', ''):
|
||||
return response
|
||||
|
||||
course_blocks = {}
|
||||
root = None
|
||||
if request.query_params.get('return_type') == 'list':
|
||||
for course_block in response.data:
|
||||
course_blocks[course_block['id']] = course_block
|
||||
|
||||
if course_block.get('type') == 'course':
|
||||
root = course_block['id']
|
||||
else:
|
||||
root = response.data['root']
|
||||
course_blocks = response.data['blocks']
|
||||
|
||||
if not root:
|
||||
raise ValueError("Unable to find course block in {}".format(course_key_string))
|
||||
|
||||
recurse_mark_complete(root, course_blocks)
|
||||
return response
|
||||
|
||||
|
||||
def recurse_mark_complete(block_id, blocks):
|
||||
"""
|
||||
Helper function to walk course tree dict,
|
||||
marking completion as 1 or 0
|
||||
|
||||
If all blocks are complete, mark parent block complete
|
||||
|
||||
:param blocks: dict of all blocks
|
||||
:param block_id: root or child block id
|
||||
|
||||
:return:
|
||||
block: course_outline_root_block block object or child block
|
||||
"""
|
||||
block = blocks.get(block_id, {})
|
||||
if block.get('completion') == 1:
|
||||
return
|
||||
|
||||
child_blocks = block.get('children', block.get('descendents'))
|
||||
# Unit blocks(blocks with no children) completion is being marked by patch call to completion service.
|
||||
if child_blocks:
|
||||
for child_block in child_blocks:
|
||||
recurse_mark_complete(child_block, blocks)
|
||||
|
||||
completable_blocks = [blocks[child_block_id] for child_block_id in child_blocks
|
||||
if blocks[child_block_id].get('type') != 'discussion']
|
||||
block['completion'] = int(all(child.get('completion') == 1 for child in completable_blocks))
|
||||
|
||||
Reference in New Issue
Block a user