Commit 4921ec48 by Nimisha Asthagiri

MA-792 Course Blocks and Navigation API (user-specific)

parent 037ef3be
...@@ -3,7 +3,7 @@ Utility library containing operations used/shared by multiple courseware modules ...@@ -3,7 +3,7 @@ Utility library containing operations used/shared by multiple courseware modules
""" """
def yield_dynamic_descriptor_descendents(descriptor, module_creator): # pylint: disable=invalid-name def yield_dynamic_descriptor_descendants(descriptor, user_id, module_creator): # pylint: disable=invalid-name
""" """
This returns all of the descendants of a descriptor. If the descriptor This returns all of the descendants of a descriptor. If the descriptor
has dynamic children, the module will be created using module_creator has dynamic children, the module will be created using module_creator
...@@ -13,17 +13,21 @@ def yield_dynamic_descriptor_descendents(descriptor, module_creator): # pylint: ...@@ -13,17 +13,21 @@ def yield_dynamic_descriptor_descendents(descriptor, module_creator): # pylint:
while len(stack) > 0: while len(stack) > 0:
next_descriptor = stack.pop() next_descriptor = stack.pop()
stack.extend(get_dynamic_descriptor_children(next_descriptor, module_creator)) stack.extend(get_dynamic_descriptor_children(next_descriptor, user_id, module_creator))
yield next_descriptor yield next_descriptor
def get_dynamic_descriptor_children(descriptor, module_creator, usage_key_filter=None): def get_dynamic_descriptor_children(descriptor, user_id, module_creator=None, usage_key_filter=None):
""" """
Returns the children of the given descriptor, while supporting descriptors with dynamic children. Returns the children of the given descriptor, while supporting descriptors with dynamic children.
""" """
module_children = [] module_children = []
if descriptor.has_dynamic_children(): if descriptor.has_dynamic_children():
module = module_creator(descriptor) # do not rebind the module if it's already bound to a user.
if descriptor.scope_ids.user_id and user_id == descriptor.scope_ids.user_id:
module = descriptor
else:
module = module_creator(descriptor)
if module is not None: if module is not None:
module_children = module.get_child_descriptors() module_children = module.get_child_descriptors()
else: else:
......
...@@ -755,7 +755,8 @@ class VideoDescriptor(VideoFields, VideoTranscriptsMixin, VideoStudioViewHandler ...@@ -755,7 +755,8 @@ class VideoDescriptor(VideoFields, VideoTranscriptsMixin, VideoStudioViewHandler
Returns a JSON representation of the student_view of this XModule. Returns a JSON representation of the student_view of this XModule.
The contract of the JSON content is between the caller and the particular XModule. The contract of the JSON content is between the caller and the particular XModule.
""" """
# Honor only_on_web # If the "only_on_web" field is set on this video, do not return the rest of the video's data
# in this json view, since this video is to be accessed only through its web view."
if self.only_on_web: if self.only_on_web:
return {"only_on_web": True} return {"only_on_web": True}
......
...@@ -14,5 +14,33 @@ urlpatterns = patterns( ...@@ -14,5 +14,33 @@ urlpatterns = patterns(
url(r'^courses/$', views.CourseList.as_view(), name='list'), url(r'^courses/$', views.CourseList.as_view(), name='list'),
url(r'^courses/{}/$'.format(COURSE_ID_PATTERN), views.CourseDetail.as_view(), name='detail'), url(r'^courses/{}/$'.format(COURSE_ID_PATTERN), views.CourseDetail.as_view(), name='detail'),
url(r'^course_structures/{}/$'.format(COURSE_ID_PATTERN), views.CourseStructure.as_view(), name='structure'), url(r'^course_structures/{}/$'.format(COURSE_ID_PATTERN), views.CourseStructure.as_view(), name='structure'),
url(r'^grading_policies/{}/$'.format(COURSE_ID_PATTERN), views.CourseGradingPolicy.as_view(), name='grading_policy') url(
r'^grading_policies/{}/$'.format(COURSE_ID_PATTERN),
views.CourseGradingPolicy.as_view(),
name='grading_policy'
),
) )
if settings.FEATURES.get('ENABLE_COURSE_BLOCKS_NAVIGATION_API'):
# TODO (MA-789) This endpoint still needs to be approved by the arch council.
# TODO (MA-704) This endpoint still needs to be made performant.
urlpatterns += (
url(
r'^courses/{}/blocks/$'.format(COURSE_ID_PATTERN),
views.CourseBlocksAndNavigation.as_view(),
{'return_blocks': True, 'return_nav': False},
name='blocks'
),
url(
r'^courses/{}/navigation/$'.format(COURSE_ID_PATTERN),
views.CourseBlocksAndNavigation.as_view(),
{'return_blocks': False, 'return_nav': True},
name='navigation'
),
url(
r'^courses/{}/blocks\+navigation/$'.format(COURSE_ID_PATTERN),
views.CourseBlocksAndNavigation.as_view(),
{'return_blocks': True, 'return_nav': True},
name='blocks+navigation'
),
)
...@@ -9,7 +9,7 @@ from courseware.models import StudentModule ...@@ -9,7 +9,7 @@ from courseware.models import StudentModule
from opaque_keys.edx.keys import UsageKey from opaque_keys.edx.keys import UsageKey
from student.models import EntranceExamConfiguration from student.models import EntranceExamConfiguration
from util.milestones_helpers import get_required_content from util.milestones_helpers import get_required_content
from util.module_utils import yield_dynamic_descriptor_descendents from util.module_utils import yield_dynamic_descriptor_descendants
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
...@@ -147,8 +147,9 @@ def get_entrance_exam_score(request, course): ...@@ -147,8 +147,9 @@ def get_entrance_exam_score(request, course):
course.id course.id
) )
exam_module_generators = yield_dynamic_descriptor_descendents( exam_module_generators = yield_dynamic_descriptor_descendants(
exam_descriptor, exam_descriptor,
request.user.id,
inner_get_module inner_get_module
) )
exam_modules = [module for module in exam_module_generators] exam_modules = [module for module in exam_module_generators]
......
...@@ -15,7 +15,7 @@ import dogstats_wrapper as dog_stats_api ...@@ -15,7 +15,7 @@ import dogstats_wrapper as dog_stats_api
from courseware import courses from courseware import courses
from courseware.model_data import FieldDataCache from courseware.model_data import FieldDataCache
from student.models import anonymous_id_for_user from student.models import anonymous_id_for_user
from util.module_utils import yield_dynamic_descriptor_descendents from util.module_utils import yield_dynamic_descriptor_descendants
from xmodule import graders from xmodule import graders
from xmodule.graders import Score from xmodule.graders import Score
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
...@@ -209,7 +209,9 @@ def _grade(student, request, course, keep_raw_scores): ...@@ -209,7 +209,9 @@ def _grade(student, request, course, keep_raw_scores):
field_data_cache = FieldDataCache([descriptor], course.id, student) field_data_cache = FieldDataCache([descriptor], course.id, student)
return get_module_for_descriptor(student, request, descriptor, field_data_cache, course.id) return get_module_for_descriptor(student, request, descriptor, field_data_cache, course.id)
for module_descriptor in yield_dynamic_descriptor_descendents(section_descriptor, create_module): for module_descriptor in yield_dynamic_descriptor_descendants(
section_descriptor, student.id, create_module
):
(correct, total) = get_score( (correct, total) = get_score(
course.id, student, module_descriptor, create_module, scores_cache=submissions_scores course.id, student, module_descriptor, create_module, scores_cache=submissions_scores
...@@ -364,7 +366,9 @@ def _progress_summary(student, request, course): ...@@ -364,7 +366,9 @@ def _progress_summary(student, request, course):
module_creator = section_module.xmodule_runtime.get_module module_creator = section_module.xmodule_runtime.get_module
for module_descriptor in yield_dynamic_descriptor_descendents(section_module, module_creator): for module_descriptor in yield_dynamic_descriptor_descendants(
section_module, student.id, module_creator
):
course_id = course.id course_id = course.id
(correct, total) = get_score( (correct, total) = get_score(
course_id, student, module_descriptor, module_creator, scores_cache=submissions_scores course_id, student, module_descriptor, module_creator, scores_cache=submissions_scores
......
...@@ -86,6 +86,7 @@ class BlockOutline(object): ...@@ -86,6 +86,7 @@ class BlockOutline(object):
if curr_block.has_children: if curr_block.has_children:
children = get_dynamic_descriptor_children( children = get_dynamic_descriptor_children(
curr_block, curr_block,
self.request.user.id,
create_module, create_module,
usage_key_filter=parent_or_requested_block_type usage_key_filter=parent_or_requested_block_type
) )
......
...@@ -321,7 +321,10 @@ FEATURES = { ...@@ -321,7 +321,10 @@ FEATURES = {
# ENABLE_OAUTH2_PROVIDER to True # ENABLE_OAUTH2_PROVIDER to True
'ENABLE_MOBILE_REST_API': False, 'ENABLE_MOBILE_REST_API': False,
'ENABLE_MOBILE_SOCIAL_FACEBOOK_FEATURES': False, 'ENABLE_MOBILE_SOCIAL_FACEBOOK_FEATURES': False,
# Enable APIs required for xBlocks on Mobile, and supported in general
'ENABLE_RENDER_XBLOCK_API': False, 'ENABLE_RENDER_XBLOCK_API': False,
'ENABLE_COURSE_BLOCKS_NAVIGATION_API': False,
# Enable the combined login/registration form # Enable the combined login/registration form
'ENABLE_COMBINED_LOGIN_REGISTRATION': False, 'ENABLE_COMBINED_LOGIN_REGISTRATION': False,
......
...@@ -268,6 +268,8 @@ FEATURES['ENABLE_OAUTH2_PROVIDER'] = True ...@@ -268,6 +268,8 @@ FEATURES['ENABLE_OAUTH2_PROVIDER'] = True
FEATURES['ENABLE_MOBILE_REST_API'] = True FEATURES['ENABLE_MOBILE_REST_API'] = True
FEATURES['ENABLE_MOBILE_SOCIAL_FACEBOOK_FEATURES'] = True FEATURES['ENABLE_MOBILE_SOCIAL_FACEBOOK_FEATURES'] = True
FEATURES['ENABLE_VIDEO_ABSTRACTION_LAYER_API'] = True FEATURES['ENABLE_VIDEO_ABSTRACTION_LAYER_API'] = True
FEATURES['ENABLE_COURSE_BLOCKS_NAVIGATION_API'] = True
FEATURES['ENABLE_RENDER_XBLOCK_API'] = True
###################### Payment ##############################3 ###################### Payment ##############################3
# Enable fake payment processing page # Enable fake payment processing page
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment