Merge remote-tracking branch 'edx/master' into opaque-keys-merge-master
Conflicts: cms/djangoapps/contentstore/views/item.py cms/djangoapps/contentstore/views/tests/test_container.py cms/djangoapps/contentstore/views/tests/test_tabs.py common/lib/xmodule/xmodule/modulestore/mongo/draft.py lms/djangoapps/certificates/management/commands/gen_cert_report.py lms/djangoapps/certificates/queue.py lms/djangoapps/certificates/views.py lms/djangoapps/courseware/module_render.py lms/djangoapps/courseware/tests/test_module_render.py lms/djangoapps/instructor/views/api.py lms/djangoapps/instructor/views/instructor_dashboard.py lms/djangoapps/instructor/views/legacy.py lms/djangoapps/shoppingcart/tests/test_models.py lms/djangoapps/verify_student/views.py
This commit is contained in:
@@ -65,6 +65,13 @@ XQUEUE_INTERFACE = XQueueInterface(
|
||||
# This should be fixed after the jellyfish merge, before merge into master.
|
||||
|
||||
|
||||
class LmsModuleRenderError(Exception):
|
||||
"""
|
||||
An exception class for exceptions thrown by module_render that don't fit well elsewhere
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def make_track_function(request):
|
||||
'''
|
||||
Make a tracking function that logs what happened.
|
||||
@@ -214,25 +221,39 @@ def get_module_for_descriptor(user, request, descriptor, field_data_cache, cours
|
||||
static_asset_path)
|
||||
|
||||
|
||||
def get_module_for_descriptor_internal(user, descriptor, field_data_cache, course_id,
|
||||
track_function, xqueue_callback_url_prefix,
|
||||
position=None, wrap_xmodule_display=True, grade_bucket_type=None,
|
||||
static_asset_path=''):
|
||||
def get_module_system_for_user(user, field_data_cache,
|
||||
# Arguments preceding this comment have user binding, those following don't
|
||||
descriptor, course_id, track_function, xqueue_callback_url_prefix,
|
||||
position=None, wrap_xmodule_display=True, grade_bucket_type=None,
|
||||
static_asset_path=''):
|
||||
"""
|
||||
Actually implement get_module, without requiring a request.
|
||||
Helper function that returns a module system and student_data bound to a user and a descriptor.
|
||||
|
||||
See get_module() docstring for further details.
|
||||
"""
|
||||
The purpose of this function is to factor out everywhere a user is implicitly bound when creating a module,
|
||||
to allow an existing module to be re-bound to a user. Most of the user bindings happen when creating the
|
||||
closures that feed the instantiation of ModuleSystem.
|
||||
|
||||
<<<<<<< HEAD
|
||||
# Do not check access when it's a noauth request.
|
||||
if getattr(user, 'known', True):
|
||||
# Short circuit--if the user shouldn't have access, bail without doing any work
|
||||
if not has_access(user, 'load', descriptor, course_id):
|
||||
return None
|
||||
=======
|
||||
The arguments fall into two categories: those that have explicit or implicit user binding, which are user
|
||||
and field_data_cache, and those don't and are just present so that ModuleSystem can be instantiated, which
|
||||
are all the other arguments. Ultimately, this isn't too different than how get_module_for_descriptor_internal
|
||||
was before refactoring.
|
||||
>>>>>>> edx/master
|
||||
|
||||
Arguments:
|
||||
see arguments for get_module()
|
||||
|
||||
Returns:
|
||||
(LmsModuleSystem, KvsFieldData): (module system, student_data) bound to, primarily, the user and descriptor
|
||||
"""
|
||||
student_data = KvsFieldData(DjangoKeyValueStore(field_data_cache))
|
||||
|
||||
|
||||
def make_xqueue_callback(dispatch='score_update'):
|
||||
# Fully qualified callback URL for external queueing system
|
||||
relative_xqueue_callback_url = reverse(
|
||||
@@ -335,6 +356,49 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours
|
||||
else:
|
||||
track_function(event_type, event)
|
||||
|
||||
def rebind_noauth_module_to_user(module, real_user):
|
||||
"""
|
||||
A function that allows a module to get re-bound to a real user if it was previously bound to an AnonymousUser.
|
||||
|
||||
Will only work within a module bound to an AnonymousUser, e.g. one that's instantiated by the noauth_handler.
|
||||
|
||||
Arguments:
|
||||
module (any xblock type): the module to rebind
|
||||
real_user (django.contrib.auth.models.User): the user to bind to
|
||||
|
||||
Returns:
|
||||
nothing (but the side effect is that module is re-bound to real_user)
|
||||
"""
|
||||
if user.is_authenticated():
|
||||
err_msg = ("rebind_noauth_module_to_user can only be called from a module bound to "
|
||||
"an anonymous user")
|
||||
log.error(err_msg)
|
||||
raise LmsModuleRenderError(err_msg)
|
||||
|
||||
field_data_cache_real_user = FieldDataCache.cache_for_descriptor_descendents(
|
||||
course_id,
|
||||
real_user,
|
||||
module.descriptor
|
||||
)
|
||||
|
||||
(inner_system, inner_student_data) = get_module_system_for_user(
|
||||
real_user, field_data_cache_real_user, # These have implicit user bindings, rest of args considered not to
|
||||
module.descriptor, course_id, track_function, xqueue_callback_url_prefix, position, wrap_xmodule_display,
|
||||
grade_bucket_type, static_asset_path
|
||||
)
|
||||
# rebinds module to a different student. We'll change system, student_data, and scope_ids
|
||||
module.descriptor.bind_for_student(
|
||||
inner_system,
|
||||
LmsFieldData(module.descriptor._field_data, inner_student_data) # pylint: disable=protected-access
|
||||
)
|
||||
module.descriptor.scope_ids = (
|
||||
module.descriptor.scope_ids._replace(user_id=real_user.id) # pylint: disable=protected-access
|
||||
)
|
||||
module.scope_ids = module.descriptor.scope_ids # this is needed b/c NamedTuples are immutable
|
||||
# now bind the module to the new ModuleSystem instance and vice-versa
|
||||
module.runtime = inner_system
|
||||
inner_system.xmodule_instance = module
|
||||
|
||||
# Build a list of wrapping functions that will be applied in order
|
||||
# to the Fragment content coming out of the xblocks that are about to be rendered.
|
||||
block_wrappers = []
|
||||
@@ -439,6 +503,7 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours
|
||||
},
|
||||
get_user_role=lambda: get_user_role(user, course_id),
|
||||
descriptor_runtime=descriptor.runtime,
|
||||
rebind_noauth_module_to_user=rebind_noauth_module_to_user,
|
||||
)
|
||||
|
||||
# pass position specified in URL to module through ModuleSystem
|
||||
@@ -457,6 +522,31 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours
|
||||
else:
|
||||
system.error_descriptor_class = NonStaffErrorDescriptor
|
||||
|
||||
return system, student_data
|
||||
|
||||
|
||||
def get_module_for_descriptor_internal(user, descriptor, field_data_cache, course_id, # pylint: disable=invalid-name
|
||||
track_function, xqueue_callback_url_prefix,
|
||||
position=None, wrap_xmodule_display=True, grade_bucket_type=None,
|
||||
static_asset_path=''):
|
||||
"""
|
||||
Actually implement get_module, without requiring a request.
|
||||
|
||||
See get_module() docstring for further details.
|
||||
"""
|
||||
|
||||
# Do not check access when it's a noauth request.
|
||||
if getattr(user, 'known', True):
|
||||
# Short circuit--if the user shouldn't have access, bail without doing any work
|
||||
if not has_access(user, descriptor, 'load', course_id):
|
||||
return None
|
||||
|
||||
(system, student_data) = get_module_system_for_user(
|
||||
user, field_data_cache, # These have implicit user bindings, the rest of args are considered not to
|
||||
descriptor, course_id, track_function, xqueue_callback_url_prefix, position, wrap_xmodule_display,
|
||||
grade_bucket_type, static_asset_path
|
||||
)
|
||||
|
||||
descriptor.bind_for_student(system, LmsFieldData(descriptor._field_data, student_data)) # pylint: disable=protected-access
|
||||
descriptor.scope_ids = descriptor.scope_ids._replace(user_id=user.id) # pylint: disable=protected-access
|
||||
return descriptor
|
||||
|
||||
Reference in New Issue
Block a user