New optional parameters for course blocks API: lti_url, block_types
This commit is contained in:
@@ -20,6 +20,7 @@ def get_blocks(
|
||||
block_counts=None,
|
||||
student_view_data=None,
|
||||
return_type='dict',
|
||||
block_types=None
|
||||
):
|
||||
"""
|
||||
Return a serialized representation of the course blocks.
|
||||
@@ -61,6 +62,18 @@ def get_blocks(
|
||||
# transform
|
||||
blocks = get_course_blocks(user, usage_key, transformers)
|
||||
|
||||
# filter blocks by types
|
||||
if block_types and len(block_types) == 0:
|
||||
block_types = None
|
||||
if block_types:
|
||||
block_keys_to_remove = []
|
||||
for block_key in blocks:
|
||||
block_type = blocks.get_xblock_field(block_key, 'category')
|
||||
if not block_type in block_types:
|
||||
block_keys_to_remove.append(block_key)
|
||||
for block_key in block_keys_to_remove:
|
||||
blocks.remove_block(block_key, True)
|
||||
|
||||
# serialize
|
||||
serializer_context = {
|
||||
'request': request,
|
||||
|
||||
@@ -31,6 +31,7 @@ class BlockListGetForm(Form):
|
||||
student_view_data = MultiValueField(required=False)
|
||||
usage_key = CharField(required=True)
|
||||
username = CharField(required=False)
|
||||
block_types = MultiValueField(required=False)
|
||||
|
||||
def clean_depth(self):
|
||||
"""
|
||||
@@ -88,6 +89,7 @@ class BlockListGetForm(Form):
|
||||
'student_view_data',
|
||||
'block_counts',
|
||||
'nav_depth',
|
||||
'block_types',
|
||||
]
|
||||
for additional_field in additional_requested_fields:
|
||||
field_value = cleaned_data.get(additional_field)
|
||||
|
||||
@@ -44,6 +44,13 @@ class BlockSerializer(serializers.Serializer): # pylint: disable=abstract-metho
|
||||
),
|
||||
}
|
||||
|
||||
if 'lti_url' in self.context['requested_fields']:
|
||||
data['lti_url'] = reverse(
|
||||
'lti_provider_launch',
|
||||
kwargs={'course_id': unicode(block_key.course_key), 'usage_id': unicode(block_key)},
|
||||
request=self.context['request'],
|
||||
)
|
||||
|
||||
# add additional requested fields that are supported by the various transformers
|
||||
for supported_field in SUPPORTED_FIELDS:
|
||||
if supported_field.requested_field_name in self.context['requested_fields']:
|
||||
@@ -70,7 +77,6 @@ class BlockDictSerializer(serializers.Serializer): # pylint: disable=abstract-m
|
||||
Serializer that formats a BlockStructure object to a dictionary, rather
|
||||
than a list, of blocks
|
||||
"""
|
||||
root = serializers.CharField(source='root_block_usage_key')
|
||||
blocks = serializers.SerializerMethodField()
|
||||
|
||||
def get_blocks(self, structure):
|
||||
|
||||
@@ -35,7 +35,6 @@ class TestGetBlocks(EnableTransformerRegistryMixin, SharedModuleStoreTestCase):
|
||||
|
||||
def test_basic(self):
|
||||
blocks = get_blocks(self.request, self.course.location, self.user)
|
||||
self.assertEquals(blocks['root'], unicode(self.course.location))
|
||||
|
||||
# subtract for (1) the orphaned course About block and (2) the hidden Html block
|
||||
self.assertEquals(len(blocks['blocks']), len(self.store.get_items(self.course.id)) - 2)
|
||||
@@ -63,7 +62,6 @@ class TestGetBlocks(EnableTransformerRegistryMixin, SharedModuleStoreTestCase):
|
||||
sequential_block = self.store.get_item(self.course.id.make_usage_key('sequential', 'sequential_y1'))
|
||||
|
||||
blocks = get_blocks(self.request, sequential_block.location, self.user)
|
||||
self.assertEquals(blocks['root'], unicode(sequential_block.location))
|
||||
self.assertEquals(len(blocks['blocks']), 5)
|
||||
|
||||
for block_type, block_name, is_inside_of_structure in (
|
||||
@@ -77,3 +75,17 @@ class TestGetBlocks(EnableTransformerRegistryMixin, SharedModuleStoreTestCase):
|
||||
self.assertIn(unicode(block.location), blocks['blocks'])
|
||||
else:
|
||||
self.assertNotIn(unicode(block.location), blocks['blocks'])
|
||||
|
||||
def test_filtering_by_block_types(self):
|
||||
sequential_block = self.store.get_item(self.course.id.make_usage_key('sequential', 'sequential_y1'))
|
||||
|
||||
block_types = ['problem']
|
||||
blocks = get_blocks(self.request, sequential_block.location, self.user, block_types=block_types)
|
||||
|
||||
for block_type, block_name in (
|
||||
('problem', 'problem_y1a_1'),
|
||||
('problem', 'problem_y1a_2'),
|
||||
('problem', 'problem_y1a_3'),
|
||||
):
|
||||
block = self.store.get_item(self.course.id.make_usage_key(block_type, block_name))
|
||||
self.assertIn(unicode(block.location), blocks['blocks'])
|
||||
|
||||
@@ -60,6 +60,7 @@ class TestBlockListGetForm(EnableTransformerRegistryMixin, FormTestMixin, Shared
|
||||
'usage_key': usage_key,
|
||||
'username': self.student.username,
|
||||
'user': self.student,
|
||||
'block_types': set(),
|
||||
}
|
||||
|
||||
def assert_raises_permission_denied(self):
|
||||
|
||||
@@ -70,6 +70,7 @@ class TestBlockSerializerBase(EnableTransformerRegistryMixin, SharedModuleStoreT
|
||||
'block_counts',
|
||||
'student_view_data',
|
||||
'student_view_multi_device',
|
||||
'lti_url',
|
||||
])
|
||||
|
||||
def assert_extended_block(self, serialized_block):
|
||||
@@ -81,6 +82,7 @@ class TestBlockSerializerBase(EnableTransformerRegistryMixin, SharedModuleStoreT
|
||||
'id', 'type', 'lms_web_url', 'student_view_url',
|
||||
'display_name', 'graded',
|
||||
'block_counts', 'student_view_multi_device',
|
||||
'lti_url',
|
||||
},
|
||||
set(serialized_block.iterkeys()),
|
||||
)
|
||||
@@ -136,9 +138,6 @@ class TestBlockDictSerializer(TestBlockSerializerBase):
|
||||
def test_basic(self):
|
||||
serializer = self.create_serializer()
|
||||
|
||||
# verify root
|
||||
self.assertEquals(serializer.data['root'], unicode(self.block_structure.root_block_usage_key))
|
||||
|
||||
# verify blocks
|
||||
for block_key_string, serialized_block in serializer.data['blocks'].iteritems():
|
||||
self.assertEquals(serialized_block['id'], block_key_string)
|
||||
|
||||
@@ -30,9 +30,10 @@ class BlocksView(DeveloperErrorViewMixin, ListAPIView):
|
||||
GET /api/courses/v1/blocks/<usage_id>/?
|
||||
username=anjali
|
||||
&depth=all
|
||||
&requested_fields=graded,format,student_view_multi_device
|
||||
&requested_fields=graded,format,student_view_multi_device,lti_url
|
||||
&block_counts=video
|
||||
&student_view_data=video
|
||||
&block_types=problem,html
|
||||
|
||||
**Parameters**:
|
||||
|
||||
@@ -85,6 +86,11 @@ class BlocksView(DeveloperErrorViewMixin, ListAPIView):
|
||||
|
||||
Example: return_type=dict
|
||||
|
||||
* block_types: (list) Requested types of blocks. Possible values include sequential,
|
||||
vertical, html, problem, video, and discussion.
|
||||
|
||||
Example: block_types=vertical,html
|
||||
|
||||
**Response Values**
|
||||
|
||||
The following fields are returned with a successful response.
|
||||
@@ -147,6 +153,7 @@ class BlocksView(DeveloperErrorViewMixin, ListAPIView):
|
||||
if the student_view_url and the student_view_data fields are not
|
||||
supported.
|
||||
|
||||
* lti_url: The block URL for an LTI consumer.
|
||||
"""
|
||||
|
||||
def list(self, request, usage_key_string): # pylint: disable=arguments-differ
|
||||
@@ -177,7 +184,8 @@ class BlocksView(DeveloperErrorViewMixin, ListAPIView):
|
||||
params.cleaned_data['requested_fields'],
|
||||
params.cleaned_data.get('block_counts', []),
|
||||
params.cleaned_data.get('student_view_data', []),
|
||||
params.cleaned_data['return_type']
|
||||
params.cleaned_data['return_type'],
|
||||
params.cleaned_data.get('block_types', None),
|
||||
)
|
||||
)
|
||||
except ItemNotFoundError as exception:
|
||||
@@ -198,9 +206,10 @@ class BlocksInCourseView(BlocksView):
|
||||
GET /api/courses/v1/blocks/?course_id=<course_id>
|
||||
&username=anjali
|
||||
&depth=all
|
||||
&requested_fields=graded,format,student_view_multi_device
|
||||
&requested_fields=graded,format,student_view_multi_device,lti_url
|
||||
&block_counts=video
|
||||
&student_view_data=video
|
||||
&block_types=problem,html
|
||||
|
||||
**Parameters**:
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ class BlockStructure(object):
|
||||
traversal since it's the more common case and we currently
|
||||
need to support DAGs.
|
||||
"""
|
||||
return self.topological_traversal()
|
||||
return self.get_block_keys()
|
||||
|
||||
#--- Block structure relation methods ---#
|
||||
|
||||
|
||||
Reference in New Issue
Block a user