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:
jawad khan
2021-02-02 19:51:14 +05:00
committed by GitHub
parent ad3ab3712e
commit 8529e433b8
2 changed files with 99 additions and 2 deletions

View File

@@ -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'))

View File

@@ -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))