refactor: rename descriptor -> block within lms/djangoapps/courseware

Co-authored-by: Agrendalath <piotr@surowiec.it>
This commit is contained in:
Pooja Kulkarni
2023-01-04 13:55:45 -05:00
committed by Agrendalath
parent 79f67b9ce3
commit c80fba689a
22 changed files with 701 additions and 732 deletions

View File

@@ -73,7 +73,7 @@ def has_ccx_coach_role(user, course_key):
Check if user is a coach on this ccx.
Arguments:
user (User): the user whose descriptor access we are checking.
user (User): the user whose course access we are checking.
course_key (CCXLocator): Key to CCX.
Returns:
@@ -113,7 +113,7 @@ def has_access(user, action, obj, course_key=None):
user: a Django user object. May be anonymous. If none is passed,
anonymous is assumed
obj: The object to check access for. A block, descriptor, location, or
obj: The object to check access for. A block, location, or
certain special strings (e.g. 'global')
action: A string specifying the action that the client is trying to perform.
@@ -146,11 +146,11 @@ def has_access(user, action, obj, course_key=None):
return _has_access_course(user, action, obj)
if isinstance(obj, ErrorBlock):
return _has_access_error_desc(user, action, obj, course_key)
return _has_access_error_block(user, action, obj, course_key)
# NOTE: any descriptor access checkers need to go above this
# NOTE: any block access checkers need to go above this
if isinstance(obj, XBlock):
return _has_access_descriptor(user, action, obj, course_key)
return _has_access_to_block(user, action, obj, course_key)
if isinstance(obj, CourseKey):
return _has_access_course_key(user, action, obj)
@@ -200,7 +200,7 @@ def _can_view_courseware_with_prerequisites(user, course):
return (
_is_prerequisites_disabled()
or _has_staff_access_to_descriptor(user, course, course.id)
or _has_staff_access_to_block(user, course, course.id)
or user.is_anonymous
or _has_fulfilled_prerequisites(user, [course.id])
)
@@ -226,7 +226,7 @@ def _can_load_course_on_mobile(user, course):
return (
is_mobile_available_for_user(user, course) and
(
_has_staff_access_to_descriptor(user, course, course.id) or
_has_staff_access_to_block(user, course, course.id) or
_has_fulfilled_all_milestones(user, course.id)
)
)
@@ -244,13 +244,13 @@ def _can_enroll_courselike(user, courselike):
Returns:
AccessResponse, indicating whether the user can enroll.
"""
# Courselike objects (e.g., course descriptors and CourseOverviews) have an attribute named `id`
# Courselike objects (CourseBlock and CourseOverview) have an attribute named `id`
# which actually points to a CourseKey. Sigh.
course_key = courselike.id
course_enrollment_open = courselike.is_enrollment_open()
user_has_staff_access = _has_staff_access_to_descriptor(user, courselike, course_key)
user_has_staff_access = _has_staff_access_to_block(user, courselike, course_key)
# If the user appears in CourseEnrollmentAllowed paired with the given course key,
# they may enroll, except if the CEA has already been used by a different user.
@@ -331,14 +331,14 @@ def _has_access_course(user, action, courselike):
# _can_view_courseware_with_prerequisites, user, courselike
# )
# ).or(
# _has_staff_access_to_descriptor, user, courselike, courselike.id
# _has_staff_access_to_block, user, courselike, courselike.id
# )
if courselike.id.deprecated: # we no longer support accessing Old Mongo courses
return OldMongoAccessError(courselike)
visible_to_nonstaff = _visible_to_nonstaff_users(courselike)
if not visible_to_nonstaff:
staff_access = _has_staff_access_to_descriptor(user, courselike, courselike.id)
staff_access = _has_staff_access_to_block(user, courselike, courselike.id)
if staff_access:
return staff_access
else:
@@ -346,7 +346,7 @@ def _has_access_course(user, action, courselike):
open_for_learner = check_course_open_for_learner(user, courselike)
if not open_for_learner:
staff_access = _has_staff_access_to_descriptor(user, courselike, courselike.id)
staff_access = _has_staff_access_to_block(user, courselike, courselike.id)
if staff_access:
return staff_access
else:
@@ -354,7 +354,7 @@ def _has_access_course(user, action, courselike):
view_with_prereqs = _can_view_courseware_with_prerequisites(user, courselike)
if not view_with_prereqs:
staff_access = _has_staff_access_to_descriptor(user, courselike, courselike.id)
staff_access = _has_staff_access_to_block(user, courselike, courselike.id)
if staff_access:
return staff_access
else:
@@ -362,7 +362,7 @@ def _has_access_course(user, action, courselike):
has_not_expired = check_course_expired(user, courselike)
if not has_not_expired:
staff_access = _has_staff_access_to_descriptor(user, courselike, courselike.id)
staff_access = _has_staff_access_to_block(user, courselike, courselike.id)
if staff_access:
return staff_access
else:
@@ -389,25 +389,25 @@ def _has_access_course(user, action, courselike):
def can_see_in_catalog():
"""
Implements the "can see course in catalog" logic if a course should be visible in the main course catalog
In this case we use the catalog_visibility property on the course descriptor
In this case we use the catalog_visibility property on the course block
but also allow course staff to see this.
"""
return (
_has_catalog_visibility(courselike, CATALOG_VISIBILITY_CATALOG_AND_ABOUT)
or _has_staff_access_to_descriptor(user, courselike, courselike.id)
or _has_staff_access_to_block(user, courselike, courselike.id)
)
@function_trace('can_see_about_page')
def can_see_about_page():
"""
Implements the "can see course about page" logic if a course about page should be visible
In this case we use the catalog_visibility property on the course descriptor
In this case we use the catalog_visibility property on the course block
but also allow course staff to see this.
"""
return (
_has_catalog_visibility(courselike, CATALOG_VISIBILITY_CATALOG_AND_ABOUT)
or _has_catalog_visibility(courselike, CATALOG_VISIBILITY_ABOUT)
or _has_staff_access_to_descriptor(user, courselike, courselike.id)
or _has_staff_access_to_block(user, courselike, courselike.id)
)
checkers = {
@@ -415,8 +415,8 @@ def _has_access_course(user, action, courselike):
'load_mobile': lambda: can_load() and _can_load_course_on_mobile(user, courselike),
'enroll': can_enroll,
'see_exists': see_exists,
'staff': lambda: _has_staff_access_to_descriptor(user, courselike, courselike.id),
'instructor': lambda: _has_instructor_access_to_descriptor(user, courselike, courselike.id),
'staff': lambda: _has_staff_access_to_block(user, courselike, courselike.id),
'instructor': lambda: _has_instructor_access_to_block(user, courselike, courselike.id),
'see_in_catalog': can_see_in_catalog,
'see_about_page': can_see_about_page,
}
@@ -424,30 +424,30 @@ def _has_access_course(user, action, courselike):
return _dispatch(checkers, action, user, courselike)
def _has_access_error_desc(user, action, descriptor, course_key):
def _has_access_error_block(user, action, block, course_key):
"""
Only staff should see error descriptors.
Only staff should see error blocks.
Valid actions:
'load' -- load this descriptor, showing it to the user.
'staff' -- staff access to descriptor.
'load' -- load this block, showing it to the user.
'staff' -- staff access to block.
"""
def check_for_staff():
return _has_staff_access_to_descriptor(user, descriptor, course_key)
return _has_staff_access_to_block(user, block, course_key)
checkers = {
'load': check_for_staff,
'staff': check_for_staff,
'instructor': lambda: _has_instructor_access_to_descriptor(user, descriptor, course_key)
'instructor': lambda: _has_instructor_access_to_block(user, block, course_key)
}
return _dispatch(checkers, action, user, descriptor)
return _dispatch(checkers, action, user, block)
def _has_group_access(descriptor, user, course_key):
def _has_group_access(block, user, course_key):
"""
This function returns a boolean indicating whether or not `user` has
sufficient group memberships to "load" a block (the `descriptor`)
sufficient group memberships to "load" a block
"""
# Allow staff and instructors roles group access, as they are not masquerading as a student.
if get_user_role(user, course_key) in ['staff', 'instructor']:
@@ -455,7 +455,7 @@ def _has_group_access(descriptor, user, course_key):
# use merged_group_access which takes group access on the block's
# parents / ancestors into account
merged_access = descriptor.merged_group_access
merged_access = block.merged_group_access
# resolve the partition IDs in group_access to actual
# partition objects, skipping those which contain empty group directives.
@@ -465,7 +465,7 @@ def _has_group_access(descriptor, user, course_key):
partitions = []
for partition_id, group_ids in merged_access.items():
try:
partition = descriptor._get_user_partition(partition_id) # pylint: disable=protected-access
partition = block._get_user_partition(partition_id) # pylint: disable=protected-access
# check for False in merged_access, which indicates that at least one
# partition's group list excludes all students.
@@ -509,7 +509,7 @@ def _has_group_access(descriptor, user, course_key):
# If missing_groups is empty, the user is granted access.
# If missing_groups is NOT empty, we generate an error based on one of the particular groups they are missing.
missing_groups = []
block_key = descriptor.scope_ids.usage_id
block_key = block.scope_ids.usage_id
for partition, groups in partition_groups:
user_group = partition.scheme.get_group_for_user(
course_key,
@@ -522,7 +522,7 @@ def _has_group_access(descriptor, user, course_key):
user_group,
groups,
partition.access_denied_message(block_key, user, user_group, groups),
partition.access_denied_fragment(descriptor, user, user_group, groups),
partition.access_denied_fragment(block, user, user_group, groups),
))
if missing_groups:
@@ -542,15 +542,15 @@ def _has_group_access(descriptor, user, course_key):
return ACCESS_GRANTED
def _has_access_descriptor(user, action, descriptor, course_key=None):
def _has_access_to_block(user, action, block, course_key=None):
"""
Check if user has access to this descriptor.
Check if user has access to this block.
Valid actions:
'load' -- load this descriptor, showing it to the user.
'staff' -- staff access to descriptor.
'load' -- load this block, showing it to the user.
'staff' -- staff access to block.
NOTE: This is the fallback logic for descriptors that don't have custom policy
NOTE: This is the fallback logic for blocks that don't have custom policy
(e.g. courses). If you call this method directly instead of going through
has_access(), it will not do the right thing.
"""
@@ -562,26 +562,26 @@ def _has_access_descriptor(user, action, descriptor, course_key=None):
don't have to hit the enrollments table on every block load.
"""
# If the user (or the role the user is currently masquerading as) does not have
# access to this content, then deny access. The problem with calling _has_staff_access_to_descriptor
# before this method is that _has_staff_access_to_descriptor short-circuits and returns True
# access to this content, then deny access. The problem with calling _has_staff_access_to_block
# before this method is that _has_staff_access_to_block short-circuits and returns True
# for staff users in preview mode.
group_access_response = _has_group_access(descriptor, user, course_key)
group_access_response = _has_group_access(block, user, course_key)
if not group_access_response:
return group_access_response
# If the user has staff access, they can load the block and checks below are not needed.
staff_access_response = _has_staff_access_to_descriptor(user, descriptor, course_key)
staff_access_response = _has_staff_access_to_block(user, block, course_key)
if staff_access_response:
return staff_access_response
return (
_visible_to_nonstaff_users(descriptor, display_error_to_user=False) and
_visible_to_nonstaff_users(block, display_error_to_user=False) and
(
_has_detached_class_tag(descriptor) or
_has_detached_class_tag(block) or
check_start_date(
user,
descriptor.days_early_for_beta,
descriptor.start,
block.days_early_for_beta,
block.start,
course_key,
display_error_to_user=False
)
@@ -590,11 +590,11 @@ def _has_access_descriptor(user, action, descriptor, course_key=None):
checkers = {
'load': can_load,
'staff': lambda: _has_staff_access_to_descriptor(user, descriptor, course_key),
'instructor': lambda: _has_instructor_access_to_descriptor(user, descriptor, course_key)
'staff': lambda: _has_staff_access_to_block(user, block, course_key),
'instructor': lambda: _has_instructor_access_to_block(user, block, course_key)
}
return _dispatch(checkers, action, user, descriptor)
return _dispatch(checkers, action, user, block)
def _has_access_location(user, action, location, course_key):
@@ -762,53 +762,53 @@ def administrative_accesses_to_course_for_user(user, course_key):
return global_staff, staff_access, instructor_access
@function_trace('_has_instructor_access_to_descriptor')
def _has_instructor_access_to_descriptor(user, descriptor, course_key):
@function_trace('_has_instructor_access_to_block')
def _has_instructor_access_to_block(user, block, course_key):
"""Helper method that checks whether the user has staff access to
the course of the location.
descriptor: something that has a location attribute
block: something that has a location attribute
"""
return _has_instructor_access_to_location(user, descriptor.location, course_key)
return _has_instructor_access_to_location(user, block.location, course_key)
@function_trace('_has_staff_access_to_descriptor')
def _has_staff_access_to_descriptor(user, descriptor, course_key):
@function_trace('_has_staff_access_to_block')
def _has_staff_access_to_block(user, block, course_key):
"""Helper method that checks whether the user has staff access to
the course of the location.
descriptor: something that has a location attribute
block: something that has a location attribute
"""
return _has_staff_access_to_location(user, descriptor.location, course_key)
return _has_staff_access_to_location(user, block.location, course_key)
def _visible_to_nonstaff_users(descriptor, display_error_to_user=True):
def _visible_to_nonstaff_users(block, display_error_to_user=True):
"""
Returns if the object is visible to nonstaff users.
Arguments:
descriptor: object to check
block: object to check
display_error_to_user: If True, show an error message to the user say the content was hidden. Otherwise,
hide the content silently.
"""
if descriptor.visible_to_staff_only:
if block.visible_to_staff_only:
return VisibilityError(display_error_to_user=display_error_to_user)
else:
return ACCESS_GRANTED
def _can_access_descriptor_with_milestones(user, descriptor, course_key):
def _can_access_block_with_milestones(user, block, course_key):
"""
Returns if the object is blocked by an unfulfilled milestone.
Args:
user: the user trying to access this content
descriptor: the object being accessed
course_key: key for the course for this descriptor
block: the object being accessed
course_key: key for the course
"""
if milestones_helpers.get_course_content_milestones(
course_key,
str(descriptor.location),
str(block.location),
'requires',
user.id
):
@@ -818,14 +818,14 @@ def _can_access_descriptor_with_milestones(user, descriptor, course_key):
return ACCESS_GRANTED
def _has_detached_class_tag(descriptor):
def _has_detached_class_tag(block):
"""
Returns if the given descriptor's type is marked as detached.
Returns if the given block's type is marked as detached.
Arguments:
descriptor: object to check
block: object to check
"""
return ACCESS_GRANTED if 'detached' in descriptor._class_tags else ACCESS_DENIED # pylint: disable=protected-access
return ACCESS_GRANTED if 'detached' in block._class_tags else ACCESS_DENIED # pylint: disable=protected-access
def _has_fulfilled_all_milestones(user, course_id):
@@ -859,29 +859,29 @@ def _has_catalog_visibility(course, visibility_type):
return ACCESS_GRANTED if course.catalog_visibility == visibility_type else ACCESS_DENIED
def _is_descriptor_mobile_available(descriptor):
def _is_block_mobile_available(block):
"""
Returns if descriptor is available on mobile.
Returns if block is available on mobile.
"""
if IgnoreMobileAvailableFlagConfig.is_enabled() or descriptor.mobile_available:
if IgnoreMobileAvailableFlagConfig.is_enabled() or block.mobile_available:
return ACCESS_GRANTED
else:
return MobileAvailabilityError()
def is_mobile_available_for_user(user, descriptor):
def is_mobile_available_for_user(user, block):
"""
Returns whether the given course is mobile_available for the given user.
Checks:
mobile_available flag on the course
Beta User and staff access overrides the mobile_available flag
Arguments:
descriptor (CourseBlock|CourseOverview): course or overview of course in question
block (CourseBlock|CourseOverview): course or overview of course in question
"""
return (
auth.user_has_role(user, CourseBetaTesterRole(descriptor.id))
or _has_staff_access_to_descriptor(user, descriptor, descriptor.id)
or _is_descriptor_mobile_available(descriptor)
auth.user_has_role(user, CourseBetaTesterRole(block.id))
or _has_staff_access_to_block(user, block, block.id)
or _is_block_mobile_available(block)
)

View File

@@ -297,7 +297,7 @@ def get_block(user, request, usage_key, field_data_cache, position=None, log_if_
XModule javascript to be bound correctly
- depth : number of levels of descendents to cache when loading this module.
None means cache all descendents
- static_asset_path : static asset path to use (overrides descriptor's value); needed
- static_asset_path : static asset path to use (overrides block's value); needed
by get_course_info_section, because info section modules
do not have a course as the parent module, and thus do not
inherit this lms key value.
@@ -310,8 +310,8 @@ def get_block(user, request, usage_key, field_data_cache, position=None, log_if_
if possible. If not possible, return None.
"""
try:
descriptor = modulestore().get_item(usage_key, depth=depth)
return get_block_for_descriptor(user, request, descriptor, field_data_cache, usage_key.course_key,
block = modulestore().get_item(usage_key, depth=depth)
return get_block_for_descriptor(user, request, block, field_data_cache, usage_key.course_key,
position=position,
wrap_xblock_display=wrap_xblock_display,
grade_bucket_type=grade_bucket_type,
@@ -365,7 +365,7 @@ def display_access_messages(user, block, view, frag, context): # pylint: disabl
# pylint: disable=too-many-statements
def get_block_for_descriptor(user, request, descriptor, field_data_cache, course_key,
def get_block_for_descriptor(user, request, block, field_data_cache, course_key,
position=None, wrap_xblock_display=True, grade_bucket_type=None,
static_asset_path='', disable_staff_debug_info=False,
course=None, will_recheck_access=False):
@@ -387,7 +387,7 @@ def get_block_for_descriptor(user, request, descriptor, field_data_cache, course
return get_block_for_descriptor_internal(
user=user,
descriptor=descriptor,
block=block,
student_data=student_data,
course_id=course_key,
track_function=track_function,
@@ -469,17 +469,17 @@ def prepare_runtime_for_user(
waittime=settings.XQUEUE_WAITTIME_BETWEEN_REQUESTS,
)
def inner_get_block(descriptor):
def inner_get_block(block):
"""
Delegate to get_block_for_descriptor_internal() with all values except `descriptor` set.
Delegate to get_block_for_descriptor_internal() with all values except `block` set.
Because it does an access check, it may return None.
"""
# TODO: fix this so that make_xqueue_callback uses the descriptor passed into
# TODO: fix this so that make_xqueue_callback uses the block passed into
# inner_get_block, not the parent's callback. Add it as an argument....
return get_block_for_descriptor_internal(
user=user,
descriptor=descriptor,
block=block,
student_data=student_data,
course_id=course_id,
track_function=track_function,
@@ -648,7 +648,7 @@ def prepare_runtime_for_user(
# TODO: Find all the places that this method is called and figure out how to
# get a loaded course passed into it
def get_block_for_descriptor_internal(user, descriptor, student_data, course_id, track_function, request_token,
def get_block_for_descriptor_internal(user, block, student_data, course_id, track_function, request_token,
position=None, wrap_xblock_display=True, grade_bucket_type=None,
static_asset_path='', user_location=None, disable_staff_debug_info=False,
course=None, will_recheck_access=False):
@@ -664,7 +664,7 @@ def get_block_for_descriptor_internal(user, descriptor, student_data, course_id,
student_data = prepare_runtime_for_user(
user=user,
student_data=student_data, # These have implicit user bindings, the rest of args are considered not to
block=descriptor,
block=block,
course_id=course_id,
track_function=track_function,
position=position,
@@ -678,7 +678,7 @@ def get_block_for_descriptor_internal(user, descriptor, student_data, course_id,
will_recheck_access=will_recheck_access,
)
descriptor.bind_for_student(
block.bind_for_student(
user.id,
[
partial(DateLookupFieldData, course_id=course_id, user=user),
@@ -687,16 +687,16 @@ def get_block_for_descriptor_internal(user, descriptor, student_data, course_id,
],
)
descriptor.scope_ids = descriptor.scope_ids._replace(user_id=user.id)
block.scope_ids = block.scope_ids._replace(user_id=user.id)
# Do not check access when it's a noauth request.
# Not that the access check needs to happen after the descriptor is bound
# Not that the access check needs to happen after the block is bound
# for the student, since there may be field override data for the student
# that affects xblock visibility.
user_needs_access_check = getattr(user, 'known', True) and not isinstance(user, SystemUser)
if user_needs_access_check:
access = has_access(user, 'load', descriptor, course_id)
# A descriptor should only be returned if either the user has access, or the user doesn't have access, but
access = has_access(user, 'load', block, course_id)
# A block should only be returned if either the user has access, or the user doesn't have access, but
# the failed access has a message for the user and the caller of this function specifies it will check access
# again. This allows blocks to show specific error message or upsells when access is denied.
caller_will_handle_access_error = (
@@ -705,10 +705,10 @@ def get_block_for_descriptor_internal(user, descriptor, student_data, course_id,
and (access.user_message or access.user_fragment)
)
if access or caller_will_handle_access_error:
descriptor.has_access_error = bool(caller_will_handle_access_error)
return descriptor
block.has_access_error = bool(caller_will_handle_access_error)
return block
return None
return descriptor
return block
def load_single_xblock(request, user_id, course_id, usage_key_string, course=None, will_recheck_access=False):
@@ -719,7 +719,7 @@ def load_single_xblock(request, user_id, course_id, usage_key_string, course=Non
course_key = CourseKey.from_string(course_id)
usage_key = usage_key.map_into_course(course_key)
user = User.objects.get(id=user_id)
field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
field_data_cache = FieldDataCache.cache_for_block_descendents(
course_key,
user,
modulestore().get_item(usage_key),
@@ -873,15 +873,15 @@ def _get_usage_key_for_course(course_key, usage_id) -> UsageKey:
raise Http404("Invalid location") from exc
def _get_descriptor_by_usage_key(usage_key):
def _get_block_by_usage_key(usage_key):
"""
Gets a descriptor instance based on a mapped-to-course usage_key
Gets a block instance based on a mapped-to-course usage_key
Returns (instance, tracking_context)
"""
try:
descriptor = modulestore().get_item(usage_key)
descriptor_orig_usage_key, descriptor_orig_version = modulestore().get_block_original_usage(usage_key)
block = modulestore().get_item(usage_key)
block_orig_usage_key, block_orig_version = modulestore().get_block_original_usage(usage_key)
except ItemNotFoundError as exc:
log.warning(
"Invalid location for course id %s: %s",
@@ -893,17 +893,17 @@ def _get_descriptor_by_usage_key(usage_key):
tracking_context = {
'module': {
# xss-lint: disable=python-deprecated-display-name
'display_name': descriptor.display_name_with_default_escaped,
'usage_key': str(descriptor.location),
'display_name': block.display_name_with_default_escaped,
'usage_key': str(block.location),
}
}
# For blocks that are inherited from a content library, we add some additional metadata:
if descriptor_orig_usage_key is not None:
tracking_context['module']['original_usage_key'] = str(descriptor_orig_usage_key)
tracking_context['module']['original_usage_version'] = str(descriptor_orig_version)
if block_orig_usage_key is not None:
tracking_context['module']['original_usage_key'] = str(block_orig_usage_key)
tracking_context['module']['original_usage_version'] = str(block_orig_version)
return descriptor, tracking_context
return block, tracking_context
def get_block_by_usage_id(request, course_id, usage_id, disable_staff_debug_info=False, course=None,
@@ -915,19 +915,19 @@ def get_block_by_usage_id(request, course_id, usage_id, disable_staff_debug_info
"""
course_key = CourseKey.from_string(course_id)
usage_key = _get_usage_key_for_course(course_key, usage_id)
descriptor, tracking_context = _get_descriptor_by_usage_key(usage_key)
block, tracking_context = _get_block_by_usage_key(usage_key)
_, user = setup_masquerade(request, course_key, has_access(request.user, 'staff', descriptor, course_key))
field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
_, user = setup_masquerade(request, course_key, has_access(request.user, 'staff', block, course_key))
field_data_cache = FieldDataCache.cache_for_block_descendents(
course_key,
user,
descriptor,
block,
read_only=CrawlersConfig.is_crawler(request),
)
instance = get_block_for_descriptor(
user,
request,
descriptor,
block,
field_data_cache,
usage_key.course_key,
disable_staff_debug_info=disable_staff_debug_info,
@@ -978,13 +978,13 @@ def _invoke_xblock_handler(request, course_id, usage_id, handler, suffix, course
block_usage_key = usage_key
# Peek at the handler method to see if it actually wants to check access itself. (The handler may not want
# inaccessible blocks stripped from the tree.) This ends up doing two modulestore lookups for the descriptor,
# inaccessible blocks stripped from the tree.) This ends up doing two modulestore lookups for the block,
# but the blocks should be available in the request cache the second time.
# At the time of writing, this is only used by one handler. If this usage grows, we may want to re-evaluate
# how we do this to something more elegant. If you are the author of a third party block that decides it wants
# to set this too, please let us know so we can consider making this easier / better-documented.
descriptor, _ = _get_descriptor_by_usage_key(block_usage_key)
handler_method = getattr(descriptor, handler, False)
block, _ = _get_block_by_usage_key(block_usage_key)
handler_method = getattr(block, handler, False)
will_recheck_access = handler_method and getattr(handler_method, 'will_recheck_access', False)
instance, tracking_context = get_block_by_usage_id(

View File

@@ -76,7 +76,7 @@ _Assignment = namedtuple(
def get_course(course_id, depth=0):
"""
Given a course id, return the corresponding course descriptor.
Given a course id, return the corresponding course block.
If the course does not exist, raises a CourseRunNotFound. This is appropriate
for internal use.
@@ -92,9 +92,9 @@ def get_course(course_id, depth=0):
def get_course_with_access(user, action, course_key, depth=0, check_if_enrolled=False, check_survey_complete=True, check_if_authenticated=False): # lint-amnesty, pylint: disable=line-too-long
"""
Given a course_key, look up the corresponding course descriptor,
Given a course_key, look up the corresponding course block,
check that the user has the access to perform the specified action
on the course, and return the descriptor.
on the course, and return the block.
Raises a 404 if the course_key is invalid, or the user doesn't have access.
@@ -857,26 +857,26 @@ def get_problems_in_section(section):
"""
This returns a dict having problems in a section.
Returning dict has problem location as keys and problem
descriptor as values.
block as values.
"""
problem_descriptors = defaultdict()
problem_blocks = defaultdict()
if not isinstance(section, UsageKey):
section_key = UsageKey.from_string(section)
else:
section_key = section
# it will be a Mongo performance boost, if you pass in a depth=3 argument here
# as it will optimize round trips to the database to fetch all children for the current node
section_descriptor = modulestore().get_item(section_key, depth=3)
section_block = modulestore().get_item(section_key, depth=3)
# iterate over section, sub-section, vertical
for subsection in section_descriptor.get_children():
for subsection in section_block.get_children():
for vertical in subsection.get_children():
for component in vertical.get_children():
if component.location.block_type == 'problem' and getattr(component, 'has_score', False):
problem_descriptors[str(component.location)] = component
problem_blocks[str(component.location)] = component
return problem_descriptors
return problem_blocks
def get_current_child(xblock, min_depth=None, requested_child=None):

View File

@@ -17,7 +17,7 @@ from xmodule.modulestore.xml import XMLModuleStore
def traverse_tree(course):
"""
Load every descriptor in course. Return bool success value.
Load every block in course. Return bool success value.
"""
queue = [course]
while len(queue) > 0:

View File

@@ -112,8 +112,8 @@ class MasqueradeView(View):
group_id=None,
user_name=None,
)
descriptor = modulestore().get_course(course_key)
partitions = get_all_partitions_for_course(descriptor, active_only=True)
block = modulestore().get_course(course_key)
partitions = get_all_partitions_for_course(block, active_only=True)
data = {
'success': True,
'active': {

View File

@@ -51,30 +51,30 @@ class InvalidWriteError(Exception):
"""
def _all_usage_keys(descriptors, aside_types):
def _all_usage_keys(blocks, aside_types):
"""
Return a set of all usage_ids for the `descriptors` and for
as all asides in `aside_types` for those descriptors.
Return a set of all usage_ids for the `blocks` and for
as all asides in `aside_types` for those blocks.
"""
usage_ids = set()
for descriptor in descriptors:
usage_ids.add(descriptor.scope_ids.usage_id)
for block in blocks:
usage_ids.add(block.scope_ids.usage_id)
for aside_type in aside_types:
usage_ids.add(AsideUsageKeyV1(descriptor.scope_ids.usage_id, aside_type))
usage_ids.add(AsideUsageKeyV2(descriptor.scope_ids.usage_id, aside_type))
usage_ids.add(AsideUsageKeyV1(block.scope_ids.usage_id, aside_type))
usage_ids.add(AsideUsageKeyV2(block.scope_ids.usage_id, aside_type))
return usage_ids
def _all_block_types(descriptors, aside_types):
def _all_block_types(blocks, aside_types):
"""
Return a set of all block_types for the supplied `descriptors` and for
the asides types in `aside_types` associated with those descriptors.
Return a set of all block_types for the supplied `blocks` and for
the asides types in `aside_types` associated with those blocks.
"""
block_types = set()
for descriptor in descriptors:
block_types.add(BlockTypeKeyV1(descriptor.entry_point, descriptor.scope_ids.block_type))
for block in blocks:
block_types.add(BlockTypeKeyV1(block.entry_point, block.scope_ids.block_type))
for aside_type in aside_types:
block_types.add(BlockTypeKeyV1(XBlockAside.entry_point, aside_type))
@@ -665,15 +665,15 @@ class FieldDataCache:
A cache of django model objects needed to supply the data
for a block and its descendants
"""
def __init__(self, descriptors, course_id, user, asides=None, read_only=False):
def __init__(self, blocks, course_id, user, asides=None, read_only=False):
"""
Find any courseware.models objects that are needed by any descriptor
in descriptors. Attempts to minimize the number of queries to the database.
Find any courseware.models objects that are needed by any block
in blocks. Attempts to minimize the number of queries to the database.
Note: Only blocks that have store_state = True or have shared
state will have a StudentModule.
Arguments
descriptors: A list of XModuleDescriptors.
blocks: A list of XBlocks.
course_id: The id of the current course
user: The user for which to cache data
asides: The list of aside types to load, or None to prefetch no asides.
@@ -705,84 +705,84 @@ class FieldDataCache:
),
}
self.scorable_locations = set()
self.add_descriptors_to_cache(descriptors)
self.add_blocks_to_cache(blocks)
def add_descriptors_to_cache(self, descriptors):
def add_blocks_to_cache(self, blocks):
"""
Add all `descriptors` to this FieldDataCache.
Add all `blocks` to this FieldDataCache.
"""
if self.user.is_authenticated:
self.scorable_locations.update(desc.location for desc in descriptors if desc.has_score)
for scope, fields in self._fields_to_cache(descriptors).items():
self.scorable_locations.update(block.location for block in blocks if block.has_score)
for scope, fields in self._fields_to_cache(blocks).items():
if scope not in self.cache:
continue
self.cache[scope].cache_fields(fields, descriptors, self.asides)
self.cache[scope].cache_fields(fields, blocks, self.asides)
def add_descriptor_descendents(self, descriptor, depth=None, descriptor_filter=lambda descriptor: True):
def add_block_descendents(self, block, depth=None, block_filter=lambda block: True):
"""
Add all descendants of `descriptor` to this FieldDataCache.
Add all descendants of `block` to this FieldDataCache.
Arguments:
descriptor: An XModuleDescriptor
block: An XBlock
depth is the number of levels of descendant blocks to load StudentModules for, in addition to
the supplied descriptor. If depth is None, load all descendant StudentModules
descriptor_filter is a function that accepts a descriptor and return whether the field data
the supplied block. If depth is None, load all descendant StudentModules
block_filter is a function that accepts a block and return whether the field data
should be cached
"""
def get_child_descriptors(descriptor, depth, descriptor_filter):
def get_child_blocks(block, depth, block_filter):
"""
Return a list of all child descriptors down to the specified depth
that match the descriptor filter. Includes `descriptor`
Return a list of all child blocks down to the specified depth
that match the block filter. Includes `block`
descriptor: The parent to search inside
block: The parent to search inside
depth: The number of levels to descend, or None for infinite depth
descriptor_filter(descriptor): A function that returns True
if descriptor should be included in the results
block_filter(block): A function that returns True
if block should be included in the results
"""
if descriptor_filter(descriptor):
descriptors = [descriptor]
if block_filter(block):
blocks = [block]
else:
descriptors = []
blocks = []
if depth is None or depth > 0:
new_depth = depth - 1 if depth is not None else depth
for child in descriptor.get_children() + descriptor.get_required_block_descriptors():
descriptors.extend(get_child_descriptors(child, new_depth, descriptor_filter))
for child in block.get_children() + block.get_required_block_descriptors():
blocks.extend(get_child_blocks(child, new_depth, block_filter))
return descriptors
return blocks
with modulestore().bulk_operations(descriptor.location.course_key):
descriptors = get_child_descriptors(descriptor, depth, descriptor_filter)
with modulestore().bulk_operations(block.location.course_key):
blocks = get_child_blocks(block, depth, block_filter)
self.add_descriptors_to_cache(descriptors)
self.add_blocks_to_cache(blocks)
@classmethod
def cache_for_descriptor_descendents(cls, course_id, user, descriptor, depth=None,
descriptor_filter=lambda descriptor: True,
asides=None, read_only=False):
def cache_for_block_descendents(cls, course_id, user, block, depth=None,
block_filter=lambda block: True,
asides=None, read_only=False):
"""
course_id: the course in the context of which we want StudentModules.
user: the django user for whom to load modules.
descriptor: An XModuleDescriptor
block: An XBlock
depth is the number of levels of descendant blocks to load StudentModules for, in addition to
the supplied descriptor. If depth is None, load all descendant StudentModules
descriptor_filter is a function that accepts a descriptor and return whether the field data
the supplied block. If depth is None, load all descendant StudentModules
block_filter is a function that accepts a block and return whether the field data
should be cached
"""
cache = FieldDataCache([], course_id, user, asides=asides, read_only=read_only)
cache.add_descriptor_descendents(descriptor, depth, descriptor_filter)
cache.add_block_descendents(block, depth, block_filter)
return cache
def _fields_to_cache(self, descriptors):
def _fields_to_cache(self, blocks):
"""
Returns a map of scopes to fields in that scope that should be cached
"""
scope_map = defaultdict(set)
for descriptor in descriptors:
for field in descriptor.fields.values():
for block in blocks:
for field in block.fields.values():
scope_map[field.scope].add(field)
return scope_map

View File

@@ -85,20 +85,20 @@ class BaseTestXmodule(ModuleStoreTestCase):
'category': self.CATEGORY
})
self.item_descriptor = BlockFactory.create(**kwargs)
self.block = BlockFactory.create(**kwargs)
self.runtime = self.new_descriptor_runtime()
field_data = {}
field_data.update(self.MODEL_DATA)
student_data = DictFieldData(field_data)
self.item_descriptor._field_data = LmsFieldData(self.item_descriptor._field_data, student_data) # lint-amnesty, pylint: disable=protected-access
self.block._field_data = LmsFieldData(self.block._field_data, student_data) # lint-amnesty, pylint: disable=protected-access
if runtime_kwargs is None:
runtime_kwargs = {}
self.new_module_runtime(runtime=self.item_descriptor.runtime, **runtime_kwargs)
self.new_module_runtime(runtime=self.block.runtime, **runtime_kwargs)
self.item_url = str(self.item_descriptor.location)
self.item_url = str(self.block.location)
def setup_course(self): # lint-amnesty, pylint: disable=missing-function-docstring
self.course = CourseFactory.create(data=self.COURSE_DATA)

View File

@@ -182,15 +182,15 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
self.staff = GlobalStaffFactory()
def verify_access(self, mock_unit, student_should_have_access, expected_error_type=None):
""" Verify the expected result from _has_access_descriptor """
response = access._has_access_descriptor(self.anonymous_user, 'load', mock_unit, course_key=self.course.id)
""" Verify the expected result from _has_access_to_block """
response = access._has_access_to_block(self.anonymous_user, 'load', mock_unit, course_key=self.course.id)
assert student_should_have_access == bool(response)
if expected_error_type is not None:
assert isinstance(response, expected_error_type)
assert response.to_json()['error_code'] is not None
assert access._has_access_descriptor(self.course_staff, 'load', mock_unit, course_key=self.course.id)
assert access._has_access_to_block(self.course_staff, 'load', mock_unit, course_key=self.course.id)
def test_has_staff_access_to_preview_mode(self):
"""
@@ -356,31 +356,31 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
('instructor', False, False, True)
)
@ddt.unpack
def test__has_access_error_desc(self, action, expected_student, expected_staff, expected_instructor):
descriptor = Mock()
def test__has_access_error_block(self, action, expected_student, expected_staff, expected_instructor):
block = Mock()
for (user, expected_response) in (
(self.student, expected_student),
(self.course_staff, expected_staff),
(self.course_instructor, expected_instructor)
):
assert bool(access._has_access_error_desc(user, action, descriptor, self.course.id)) == expected_response
assert bool(access._has_access_error_block(user, action, block, self.course.id)) == expected_response
with pytest.raises(ValueError):
access._has_access_error_desc(self.course_instructor, 'not_load_or_staff', descriptor, self.course.id)
access._has_access_error_block(self.course_instructor, 'not_load_or_staff', block, self.course.id)
def test__has_access_descriptor(self):
def test__has_access_to_block(self):
# TODO: override DISABLE_START_DATES and test the start date branch of the method
user = Mock()
descriptor = Mock(user_partitions=[])
descriptor._class_tags = {}
descriptor.merged_group_access = {}
block = Mock(user_partitions=[])
block._class_tags = {}
block.merged_group_access = {}
# Always returns true because DISABLE_START_DATES is set in test.py
assert access._has_access_descriptor(user, 'load', descriptor)
assert access._has_access_descriptor(user, 'instructor', descriptor)
assert access._has_access_to_block(user, 'load', block)
assert access._has_access_to_block(user, 'instructor', block)
with pytest.raises(ValueError):
access._has_access_descriptor(user, 'not_load_or_staff', descriptor)
access._has_access_to_block(user, 'not_load_or_staff', block)
@ddt.data(
(True, None, access_response.VisibilityError),
@@ -392,20 +392,20 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
)
@ddt.unpack
@patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False})
def test__has_access_descriptor_staff_lock(self, visible_to_staff_only, start, expected_error_type=None):
def test__has_access_to_block_staff_lock(self, visible_to_staff_only, start, expected_error_type=None):
"""
Tests that "visible_to_staff_only" overrides start date.
"""
expected_access = expected_error_type is None
mock_unit = Mock(location=self.course.location, user_partitions=[])
mock_unit._class_tags = {} # Needed for detached check in _has_access_descriptor
mock_unit._class_tags = {} # Needed for detached check in _has_access_to_block
mock_unit.visible_to_staff_only = visible_to_staff_only
mock_unit.start = self.DATES[start]
mock_unit.merged_group_access = {}
self.verify_access(mock_unit, expected_access, expected_error_type)
def test__has_access_descriptor_beta_user(self):
def test__has_access_to_block_beta_user(self):
mock_unit = Mock(user_partitions=[])
mock_unit._class_tags = {}
mock_unit.days_early_for_beta = 2
@@ -413,7 +413,7 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
mock_unit.visible_to_staff_only = False
mock_unit.merged_group_access = {}
assert bool(access._has_access_descriptor(self.beta_user, 'load', mock_unit, course_key=self.course.id))
assert bool(access._has_access_to_block(self.beta_user, 'load', mock_unit, course_key=self.course.id))
@ddt.data(None, YESTERDAY, TOMORROW)
@patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False})
@@ -421,12 +421,12 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
'lms.djangoapps.courseware.access_utils.get_current_request_hostname',
Mock(return_value='preview.localhost')
)
def test__has_access_descriptor_in_preview_mode(self, start):
def test__has_access_to_block_in_preview_mode(self, start):
"""
Tests that descriptor has access in preview mode.
Tests that block has access in preview mode.
"""
mock_unit = Mock(location=self.course.location, user_partitions=[])
mock_unit._class_tags = {} # Needed for detached check in _has_access_descriptor
mock_unit._class_tags = {} # Needed for detached check in _has_access_to_block
mock_unit.visible_to_staff_only = False
mock_unit.start = self.DATES[start]
mock_unit.merged_group_access = {}
@@ -441,13 +441,13 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
@ddt.unpack
@patch.dict('django.conf.settings.FEATURES', {'DISABLE_START_DATES': False})
@patch('lms.djangoapps.courseware.access_utils.get_current_request_hostname', Mock(return_value='localhost'))
def test__has_access_descriptor_when_not_in_preview_mode(self, start, expected_error_type):
def test__has_access_to_block_when_not_in_preview_mode(self, start, expected_error_type):
"""
Tests that descriptor has no access when start date in future & without preview.
Tests that block has no access when start date in future & without preview.
"""
expected_access = expected_error_type is None
mock_unit = Mock(location=self.course.location, user_partitions=[])
mock_unit._class_tags = {} # Needed for detached check in _has_access_descriptor
mock_unit._class_tags = {} # Needed for detached check in _has_access_to_block
mock_unit.visible_to_staff_only = False
mock_unit.start = self.DATES[start]
mock_unit.merged_group_access = {}
@@ -663,12 +663,12 @@ class AccessTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, MilestonesTes
"""
Test course access on mobile for staff and students.
"""
descriptor = CourseFactory()
descriptor.visible_to_staff_only = False
descriptor.mobile_available = mobile_available
course = CourseFactory()
course.visible_to_staff_only = False
course.mobile_available = mobile_available
assert bool(access._has_access_course(self.student, 'load_mobile', descriptor)) == student_expected
assert bool(access._has_access_course(self.staff, 'load_mobile', descriptor)) == staff_expected
assert bool(access._has_access_course(self.student, 'load_mobile', course)) == student_expected
assert bool(access._has_access_course(self.staff, 'load_mobile', course)) == staff_expected
@patch.dict("django.conf.settings.FEATURES", {'ENABLE_PREREQUISITE_COURSES': True, 'MILESTONES_APP': True})
def test_courseware_page_unfulfilled_prereqs(self):

View File

@@ -251,7 +251,7 @@ class BlockRenderTestCase(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
course = get_course_with_access(self.mock_user, 'load', self.course_key)
field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
field_data_cache = FieldDataCache.cache_for_block_descendents(
self.course_key, self.mock_user, course, depth=2)
block = render.get_block(
@@ -411,14 +411,14 @@ class BlockRenderTestCase(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
request = self.request_factory.get('')
request.user = self.mock_user
course = CourseFactory()
descriptor = BlockFactory(category=block_type, parent=course)
field_data_cache = FieldDataCache([self.toy_course, descriptor], self.toy_course.id, self.mock_user)
block = BlockFactory(category=block_type, parent=course)
field_data_cache = FieldDataCache([self.toy_course, block], self.toy_course.id, self.mock_user)
# This is verifying that caching doesn't cause an error during get_block_for_descriptor, which
# is why it calls the method twice identically.
render.get_block_for_descriptor(
self.mock_user,
request,
descriptor,
block,
field_data_cache,
self.toy_course.id,
course=self.toy_course
@@ -426,7 +426,7 @@ class BlockRenderTestCase(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
render.get_block_for_descriptor(
self.mock_user,
request,
descriptor,
block,
field_data_cache,
self.toy_course.id,
course=self.toy_course
@@ -442,7 +442,7 @@ class BlockRenderTestCase(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
@ddt.data('regular', 'test_aside')
def test_rebind_different_users(self, block_category):
"""
This tests the rebinding a descriptor to a student does not result
This tests the rebinding a block to a student does not result
in overly nested _field_data.
"""
def create_aside(item, block_type):
@@ -467,33 +467,33 @@ class BlockRenderTestCase(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
request.user = self.mock_user
course = CourseFactory.create()
descriptor = BlockFactory(category="html", parent=course)
block = BlockFactory(category="html", parent=course)
if block_category == 'test_aside':
descriptor = create_aside(descriptor, "test_aside")
block = create_aside(block, "test_aside")
field_data_cache = FieldDataCache(
[course, descriptor], course.id, self.mock_user
[course, block], course.id, self.mock_user
)
# grab what _field_data was originally set to
original_field_data = descriptor._field_data # lint-amnesty, pylint: disable=no-member, protected-access
original_field_data = block._field_data # lint-amnesty, pylint: disable=no-member, protected-access
render.get_block_for_descriptor(
self.mock_user, request, descriptor, field_data_cache, course.id, course=course
self.mock_user, request, block, field_data_cache, course.id, course=course
)
# check that _unwrapped_field_data is the same as the original
# _field_data, but now _field_data as been reset.
# pylint: disable=protected-access
assert descriptor._unwrapped_field_data is original_field_data # lint-amnesty, pylint: disable=no-member
assert descriptor._unwrapped_field_data is not descriptor._field_data # lint-amnesty, pylint: disable=no-member
assert block._unwrapped_field_data is original_field_data # lint-amnesty, pylint: disable=no-member
assert block._unwrapped_field_data is not block._field_data # lint-amnesty, pylint: disable=no-member
# now bind this block to a few other students
for user in [UserFactory(), UserFactory(), self.mock_user]:
render.get_block_for_descriptor(
user,
request,
descriptor,
block,
field_data_cache,
course.id,
course=course
@@ -501,14 +501,14 @@ class BlockRenderTestCase(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
# _field_data should now be wrapped by LmsFieldData
# pylint: disable=protected-access
assert isinstance(descriptor._field_data, LmsFieldData) # lint-amnesty, pylint: disable=no-member
assert isinstance(block._field_data, LmsFieldData) # lint-amnesty, pylint: disable=no-member
# the LmsFieldData should now wrap OverrideFieldData
assert isinstance(descriptor._field_data._authored_data._source, OverrideFieldData) # lint-amnesty, pylint: disable=no-member, line-too-long
assert isinstance(block._field_data._authored_data._source, OverrideFieldData) # lint-amnesty, pylint: disable=no-member, line-too-long
# the OverrideFieldData should point to the date FieldData
assert isinstance(descriptor._field_data._authored_data._source.fallback, DateLookupFieldData) # lint-amnesty, pylint: disable=no-member, line-too-long
assert descriptor._field_data._authored_data._source.fallback._defaults is descriptor._unwrapped_field_data # lint-amnesty, pylint: disable=no-member, line-too-long
assert isinstance(block._field_data._authored_data._source.fallback, DateLookupFieldData) # lint-amnesty, pylint: disable=no-member, line-too-long
assert block._field_data._authored_data._source.fallback._defaults is block._unwrapped_field_data # lint-amnesty, pylint: disable=no-member, line-too-long
def test_hash_resource(self):
"""
@@ -903,17 +903,17 @@ class TestHandleXBlockCallback(SharedModuleStoreTestCase, LoginEnrollmentTestCas
@patch('xmodule.services.grades_signals.SCORE_PUBLISHED.send')
def test_anonymous_user_not_be_graded(self, mock_score_signal):
course = CourseFactory.create()
descriptor_kwargs = {
block_kwargs = {
'category': 'problem',
}
request = self.request_factory.get('/')
request.user = AnonymousUser()
descriptor = BlockFactory.create(**descriptor_kwargs)
block = BlockFactory.create(**block_kwargs)
render.handle_xblock_callback(
request,
str(course.id),
quote_slashes(str(descriptor.location)),
quote_slashes(str(block.location)),
'xmodule_handler',
'problem_check',
)
@@ -929,12 +929,12 @@ class TestHandleXBlockCallback(SharedModuleStoreTestCase, LoginEnrollmentTestCas
def test_will_recheck_access_handler_attribute(self, handler, will_recheck_access, mock_get_block):
"""Confirm that we pay attention to any 'will_recheck_access' attributes on handler methods"""
course = CourseFactory.create()
descriptor_kwargs = {
block_kwargs = {
'category': 'sequential',
'parent': course,
}
descriptor = BlockFactory.create(**descriptor_kwargs)
usage_id = str(descriptor.location)
block = BlockFactory.create(**block_kwargs)
usage_id = str(block.location)
# Send no special parameters, which will be invalid, but we don't care
request = self.request_factory.post('/', data='{}', content_type='application/json')
@@ -1021,7 +1021,7 @@ class TestTOC(ModuleStoreTestCase):
with self.modulestore.bulk_operations(self.course_key):
with check_mongo_calls(num_finds, num_sends):
self.toy_course = self.store.get_course(self.course_key, depth=2) # pylint: disable=attribute-defined-outside-init
self.field_data_cache = FieldDataCache.cache_for_descriptor_descendents( # lint-amnesty, pylint: disable=attribute-defined-outside-init
self.field_data_cache = FieldDataCache.cache_for_block_descendents( # lint-amnesty, pylint: disable=attribute-defined-outside-init
self.course_key, self.request.user, self.toy_course, depth=2
)
@@ -1113,7 +1113,7 @@ class TestProctoringRendering(ModuleStoreTestCase):
self.modulestore = self.store._get_modulestore_for_courselike(self.course_key) # pylint: disable=protected-access
with self.modulestore.bulk_operations(self.course_key):
self.toy_course = self.store.get_course(self.course_key, depth=2)
self.field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
self.field_data_cache = FieldDataCache.cache_for_block_descendents(
self.course_key, self.request.user, self.toy_course, depth=2
)
@@ -1348,7 +1348,7 @@ class TestProctoringRendering(ModuleStoreTestCase):
self.toy_course = self.update_course(self.toy_course, self.user.id)
# refresh cache after update
self.field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
self.field_data_cache = FieldDataCache.cache_for_block_descendents(
self.course_key, self.request.user, self.toy_course, depth=2
)
@@ -1440,7 +1440,7 @@ class TestGatedSubsectionRendering(ModuleStoreTestCase, MilestonesTestCaseMixin)
self.request = RequestFactoryNoCsrf().get(f'/courses/{self.course.id}/{self.chapter.display_name}')
self.request.user = UserFactory()
self.field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
self.field_data_cache = FieldDataCache.cache_for_block_descendents(
self.course.id, self.request.user, self.course, depth=2
)
gating_api.add_prerequisite(self.course.id, self.open_seq.location)
@@ -1504,15 +1504,15 @@ class TestHtmlModifiers(ModuleStoreTestCase):
self.rewrite_link = '<a href="/static/foo/content">Test rewrite</a>'
self.rewrite_bad_link = '<img src="/static//file.jpg" />'
self.course_link = '<a href="/course/bar/content">Test course rewrite</a>'
self.descriptor = BlockFactory.create(
self.block = BlockFactory.create(
category='html',
data=self.content_string + self.rewrite_link + self.rewrite_bad_link + self.course_link
)
self.location = self.descriptor.location
self.field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
self.location = self.block.location
self.field_data_cache = FieldDataCache.cache_for_block_descendents(
self.course.id,
self.user,
self.descriptor
self.block
)
def test_xblock_display_wrapper_enabled(self):
@@ -1649,12 +1649,12 @@ class JsonInitDataTest(ModuleStoreTestCase):
mock_request = MagicMock()
mock_request.user = mock_user
course = CourseFactory()
descriptor = BlockFactory(category='withjson', parent=course)
field_data_cache = FieldDataCache([course, descriptor], course.id, mock_user)
block = BlockFactory(category='withjson', parent=course)
field_data_cache = FieldDataCache([course, block], course.id, mock_user)
block = render.get_block_for_descriptor(
mock_user,
mock_request,
descriptor,
block,
field_data_cache,
course.id,
course=course
@@ -1704,17 +1704,17 @@ class TestStaffDebugInfo(SharedModuleStoreTestCase):
options=['Correct', 'Incorrect'],
correct_option='Correct'
)
self.descriptor = BlockFactory.create(
self.block = BlockFactory.create(
category='problem',
data=problem_xml,
display_name='Option Response Problem'
)
self.location = self.descriptor.location
self.field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
self.location = self.block.location
self.field_data_cache = FieldDataCache.cache_for_block_descendents(
self.course.id,
self.user,
self.descriptor
self.block
)
@patch.dict('django.conf.settings.FEATURES', {'DISPLAY_DEBUG_INFO_TO_STAFF': False})
@@ -1757,14 +1757,14 @@ class TestStaffDebugInfo(SharedModuleStoreTestCase):
</optionresponse>
</problem>
"""
problem_descriptor = BlockFactory.create(
problem_block = BlockFactory.create(
category='problem',
data=problem_xml
)
block = render.get_block(
self.user,
self.request,
problem_descriptor.location,
problem_block.location,
self.field_data_cache
)
html_fragment = block.render(STUDENT_VIEW)
@@ -1774,26 +1774,26 @@ class TestStaffDebugInfo(SharedModuleStoreTestCase):
<label for="sd_fs_{block_id}"> / 0</label>
</div>""")
assert expected_score_override_html.format(block_id=problem_descriptor.location.block_id) in\
assert expected_score_override_html.format(block_id=problem_block.location.block_id) in\
html_fragment.content
@XBlock.register_temp_plugin(DetachedXBlock, identifier='detached-block')
def test_staff_debug_info_disabled_for_detached_blocks(self):
"""Staff markup should not be present on detached blocks."""
descriptor = BlockFactory.create(
detached_block = BlockFactory.create(
category='detached-block',
display_name='Detached Block'
)
field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
field_data_cache = FieldDataCache.cache_for_block_descendents(
self.course.id,
self.user,
descriptor
detached_block
)
block = render.get_block(
self.user,
self.request,
descriptor.location,
detached_block.location,
field_data_cache,
)
result_fragment = block.render(STUDENT_VIEW)
@@ -1813,21 +1813,21 @@ class TestStaffDebugInfo(SharedModuleStoreTestCase):
def test_histogram_enabled_for_unscored_xblocks(self):
"""Histograms should not display for xblocks which are not scored."""
html_descriptor = BlockFactory.create(
html_block = BlockFactory.create(
category='html',
data='Here are some course details.'
)
field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
field_data_cache = FieldDataCache.cache_for_block_descendents(
self.course.id,
self.user,
self.descriptor
self.block
)
with patch('openedx.core.lib.xblock_utils.grade_histogram') as mock_grade_histogram:
mock_grade_histogram.return_value = []
block = render.get_block(
self.user,
self.request,
html_descriptor.location,
html_block.location,
field_data_cache,
)
block.render(STUDENT_VIEW)
@@ -1888,7 +1888,7 @@ class TestAnonymousStudentId(SharedModuleStoreTestCase, LoginEnrollmentTestCase)
@patch('lms.djangoapps.courseware.block_render.has_access', Mock(return_value=True, autospec=True))
def _get_anonymous_id(self, course_id, xblock_class): # lint-amnesty, pylint: disable=missing-function-docstring
location = course_id.make_usage_key('dummy_category', 'dummy_name')
descriptor = Mock(
block = Mock(
spec=xblock_class,
_field_data=Mock(spec=FieldData, name='field_data'),
location=location,
@@ -1901,36 +1901,36 @@ class TestAnonymousStudentId(SharedModuleStoreTestCase, LoginEnrollmentTestCase)
name='runtime',
),
scope_ids=Mock(spec=ScopeIds),
name='descriptor',
name='block',
_field_data_cache={},
_dirty_fields={},
fields={},
days_early_for_beta=None,
)
descriptor.runtime = DescriptorSystem(None, None, None)
block.runtime = DescriptorSystem(None, None, None)
# Use the xblock_class's bind_for_student method
descriptor.bind_for_student = partial(xblock_class.bind_for_student, descriptor)
block.bind_for_student = partial(xblock_class.bind_for_student, block)
if hasattr(xblock_class, 'module_class'):
descriptor.module_class = xblock_class.module_class
block.module_class = xblock_class.module_class
block = render.get_block_for_descriptor_internal(
rendered_block = render.get_block_for_descriptor_internal(
user=self.user,
descriptor=descriptor,
block=block,
student_data=Mock(spec=FieldData, name='student_data'),
course_id=course_id,
track_function=Mock(name='track_function'), # Track Function
request_token='request_token',
course=self.course,
)
current_user = block.runtime.service(block, 'user').get_current_user()
current_user = rendered_block.runtime.service(rendered_block, 'user').get_current_user()
return current_user.opt_attrs.get(ATTR_KEY_ANONYMOUS_USER_ID)
@ddt.data(*PER_STUDENT_ANONYMIZED_XBLOCKS)
def test_per_student_anonymized_id(self, descriptor_class):
def test_per_student_anonymized_id(self, block_class):
for course_id in ('MITx/6.00x/2012_Fall', 'MITx/6.00x/2013_Spring'):
assert 'de619ab51c7f4e9c7216b4644c24f3b5' == \
self._get_anonymous_id(CourseKey.from_string(course_id), descriptor_class)
self._get_anonymous_id(CourseKey.from_string(course_id), block_class)
@ddt.data(*PER_COURSE_ANONYMIZED_XBLOCKS)
def test_per_course_anonymized_id(self, xblock_class):
@@ -2014,14 +2014,14 @@ class TestModuleTrackingContext(SharedModuleStoreTestCase):
metadata from the emitted problem_check event.
"""
descriptor_kwargs = {
block_kwargs = {
'category': 'problem',
'data': self.problem_xml
}
if problem_display_name:
descriptor_kwargs['display_name'] = problem_display_name
block_kwargs['display_name'] = problem_display_name
descriptor = BlockFactory.create(**descriptor_kwargs)
block = BlockFactory.create(**block_kwargs)
mock_tracker_for_context = MagicMock()
with patch('lms.djangoapps.courseware.block_render.tracker', mock_tracker_for_context), patch(
'xmodule.services.tracker', mock_tracker_for_context
@@ -2029,7 +2029,7 @@ class TestModuleTrackingContext(SharedModuleStoreTestCase):
render.handle_xblock_callback(
self.request,
str(self.course.id),
quote_slashes(str(descriptor.location)),
quote_slashes(str(block.location)),
'xmodule_handler',
'problem_check',
)
@@ -2096,7 +2096,7 @@ class TestXBlockRuntimeEvent(TestSubmittingProblems):
"""Helper function to get useful block at self.location in self.course_id for user"""
mock_request = MagicMock()
mock_request.user = user
field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
field_data_cache = FieldDataCache.cache_for_block_descendents(
self.course.id, user, self.course, depth=2)
return render.get_block(
@@ -2167,7 +2167,7 @@ class TestRebindBlock(TestSubmittingProblems):
"""Helper function to get useful block at self.location in self.course_id for user"""
mock_request = MagicMock()
mock_request.user = user
field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
field_data_cache = FieldDataCache.cache_for_block_descendents(
self.course.id, user, self.course, depth=2)
if item is None:
@@ -2248,9 +2248,9 @@ class TestEventPublishing(ModuleStoreTestCase, LoginEnrollmentTestCase):
request = self.request_factory.get('')
request.user = self.mock_user
course = CourseFactory()
descriptor = BlockFactory(category='xblock', parent=course)
field_data_cache = FieldDataCache([course, descriptor], course.id, self.mock_user)
block = render.get_block(self.mock_user, request, descriptor.location, field_data_cache)
block = BlockFactory(category='xblock', parent=course)
field_data_cache = FieldDataCache([course, block], course.id, self.mock_user)
block = render.get_block(self.mock_user, request, block.location, field_data_cache)
event_type = 'event_type'
event = {'event': 'data'}
@@ -2273,7 +2273,7 @@ class LMSXBlockServiceMixin(SharedModuleStoreTestCase):
_ = render.prepare_runtime_for_user(
self.user,
self.student_data,
self.descriptor,
self.block,
self.course.id,
self.track_function,
self.request_token,
@@ -2291,7 +2291,7 @@ class LMSXBlockServiceMixin(SharedModuleStoreTestCase):
self.student_data = Mock()
self.track_function = Mock()
self.request_token = Mock()
self.descriptor = BlockFactory(category="pure", parent=self.course)
self.block = BlockFactory(category="pure", parent=self.course)
self._prepare_runtime()
@@ -2334,19 +2334,19 @@ class LMSXBlockServiceBindingTest(LMSXBlockServiceMixin):
"""
Tests that the 'user', 'i18n', and 'fs' services are provided by the LMS runtime.
"""
service = self.descriptor.runtime.service(self.descriptor, expected_service)
service = self.block.runtime.service(self.block, expected_service)
assert service is not None
def test_beta_tester_fields_added(self):
"""
Tests that the beta tester fields are set on LMS runtime.
"""
self.descriptor.days_early_for_beta = 5
self.block.days_early_for_beta = 5
self._prepare_runtime()
# pylint: disable=no-member
assert not self.descriptor.runtime.user_is_beta_tester
assert self.descriptor.runtime.days_early_for_beta == 5
assert not self.block.runtime.user_is_beta_tester
assert self.block.runtime.days_early_for_beta == 5
def test_get_set_tag(self):
"""
@@ -2356,23 +2356,23 @@ class LMSXBlockServiceBindingTest(LMSXBlockServiceMixin):
key = 'key1'
# test for when we haven't set the tag yet
tag = self.descriptor.runtime.service(self.descriptor, 'user_tags').get_tag(scope, key)
tag = self.block.runtime.service(self.block, 'user_tags').get_tag(scope, key)
assert tag is None
# set the tag
set_value = 'value'
self.descriptor.runtime.service(self.descriptor, 'user_tags').set_tag(scope, key, set_value)
tag = self.descriptor.runtime.service(self.descriptor, 'user_tags').get_tag(scope, key)
self.block.runtime.service(self.block, 'user_tags').set_tag(scope, key, set_value)
tag = self.block.runtime.service(self.block, 'user_tags').get_tag(scope, key)
assert tag == set_value
# Try to set tag in wrong scope
with pytest.raises(ValueError):
self.descriptor.runtime.service(self.descriptor, 'user_tags').set_tag('fake_scope', key, set_value)
self.block.runtime.service(self.block, 'user_tags').set_tag('fake_scope', key, set_value)
# Try to get tag in wrong scope
with pytest.raises(ValueError):
self.descriptor.runtime.service(self.descriptor, 'user_tags').get_tag('fake_scope', key)
self.block.runtime.service(self.block, 'user_tags').get_tag('fake_scope', key)
@ddt.ddt
@@ -2382,23 +2382,23 @@ class TestBadgingService(LMSXBlockServiceMixin):
@patch.dict(settings.FEATURES, {'ENABLE_OPENBADGES': True})
def test_service_rendered(self):
self._prepare_runtime()
assert self.descriptor.runtime.service(self.descriptor, 'badging')
assert self.block.runtime.service(self.block, 'badging')
def test_no_service_rendered(self):
with pytest.raises(NoSuchServiceError):
self.descriptor.runtime.service(self.descriptor, 'badging')
self.block.runtime.service(self.block, 'badging')
@ddt.data(True, False)
@patch.dict(settings.FEATURES, {'ENABLE_OPENBADGES': True})
def test_course_badges_toggle(self, toggle):
self.course = CourseFactory.create(metadata={'issue_badges': toggle})
self._prepare_runtime()
assert self.descriptor.runtime.service(self.descriptor, 'badging').course_badges_enabled is toggle
assert self.block.runtime.service(self.block, 'badging').course_badges_enabled is toggle
@patch.dict(settings.FEATURES, {'ENABLE_OPENBADGES': True})
def test_get_badge_class(self):
self._prepare_runtime()
badge_service = self.descriptor.runtime.service(self.descriptor, 'badging')
badge_service = self.block.runtime.service(self.block, 'badging')
premade_badge_class = BadgeClassFactory.create()
# Ignore additional parameters. This class already exists.
# We should get back the first class we created, rather than a new one.
@@ -2422,7 +2422,7 @@ class TestI18nService(LMSXBlockServiceMixin):
"""
Test: module i18n service in LMS
"""
i18n_service = self.descriptor.runtime.service(self.descriptor, 'i18n')
i18n_service = self.block.runtime.service(self.block, 'i18n')
assert i18n_service is not None
assert isinstance(i18n_service, XBlockI18nService)
@@ -2430,32 +2430,32 @@ class TestI18nService(LMSXBlockServiceMixin):
"""
Test: NoSuchServiceError should be raised block declaration returns none
"""
self.descriptor.service_declaration = Mock(return_value=None)
self.block.service_declaration = Mock(return_value=None)
with pytest.raises(NoSuchServiceError):
self.descriptor.runtime.service(self.descriptor, 'i18n')
self.block.runtime.service(self.block, 'i18n')
def test_no_service_exception_(self):
"""
Test: NoSuchServiceError should be raised if i18n service is none.
"""
i18nService = self.descriptor.runtime._services['i18n'] # pylint: disable=protected-access
self.descriptor.runtime._runtime_services['i18n'] = None # pylint: disable=protected-access
self.descriptor.runtime._services['i18n'] = None # pylint: disable=protected-access
i18nService = self.block.runtime._services['i18n'] # pylint: disable=protected-access
self.block.runtime._runtime_services['i18n'] = None # pylint: disable=protected-access
self.block.runtime._services['i18n'] = None # pylint: disable=protected-access
with pytest.raises(NoSuchServiceError):
self.descriptor.runtime.service(self.descriptor, 'i18n')
self.descriptor.runtime._services['i18n'] = i18nService # pylint: disable=protected-access
self.block.runtime.service(self.block, 'i18n')
self.block.runtime._services['i18n'] = i18nService # pylint: disable=protected-access
def test_i18n_service_callable(self):
"""
Test: _services dict should contain the callable i18n service in LMS.
"""
assert callable(self.descriptor.runtime._services.get('i18n')) # pylint: disable=protected-access
assert callable(self.block.runtime._services.get('i18n')) # pylint: disable=protected-access
def test_i18n_service_not_callable(self):
"""
Test: i18n service should not be callable in LMS after initialization.
"""
assert not callable(self.descriptor.runtime.service(self.descriptor, 'i18n'))
assert not callable(self.block.runtime.service(self.block, 'i18n'))
class PureXBlockWithChildren(PureXBlock):
@@ -2490,15 +2490,6 @@ class TestFilteredChildren(SharedModuleStoreTestCase):
block = self._load_block()
self.assertUnboundChildren(block)
@ddt.data(*USER_NUMBERS)
@XBlock.register_temp_plugin(PureXBlockWithChildren, identifier='xblock')
def test_unbound_then_bound_as_descriptor(self, user_number):
user = self.users[user_number]
block = self._load_block()
self.assertUnboundChildren(block)
self._bind_block(block, user)
self.assertBoundChildren(block, user)
@ddt.data(*USER_NUMBERS)
@XBlock.register_temp_plugin(PureXBlockWithChildren, identifier='xblock')
def test_unbound_then_bound_as_xblock(self, user_number):
@@ -2508,14 +2499,6 @@ class TestFilteredChildren(SharedModuleStoreTestCase):
self._bind_block(block, user)
self.assertBoundChildren(block, user)
@ddt.data(*USER_NUMBERS)
@XBlock.register_temp_plugin(PureXBlockWithChildren, identifier='xblock')
def test_bound_only_as_descriptor(self, user_number):
user = self.users[user_number]
block = self._load_block()
self._bind_block(block, user)
self.assertBoundChildren(block, user)
@ddt.data(*USER_NUMBERS)
@XBlock.register_temp_plugin(PureXBlockWithChildren, identifier='xblock')
def test_bound_only_as_xblock(self, user_number):
@@ -2545,7 +2528,7 @@ class TestFilteredChildren(SharedModuleStoreTestCase):
Bind `block` to the supplied `user`.
"""
course_id = self.course.id
field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
field_data_cache = FieldDataCache.cache_for_block_descendents(
course_id,
user,
block,
@@ -2606,25 +2589,25 @@ class TestDisabledXBlockTypes(ModuleStoreTestCase):
def test_get_item(self):
course = CourseFactory()
self._verify_descriptor('video', course, 'HiddenBlockWithMixins')
self._verify_block('video', course, 'HiddenBlockWithMixins')
def test_dynamic_updates(self):
"""Tests that the list of disabled xblocks can dynamically update."""
course = CourseFactory()
item_usage_id = self._verify_descriptor('problem', course, 'ProblemBlockWithMixins')
item_usage_id = self._verify_block('problem', course, 'ProblemBlockWithMixins')
XBlockConfiguration(name='problem', enabled=False).save()
# First verify that the cached value is used until there is a new request cache.
self._verify_descriptor('problem', course, 'ProblemBlockWithMixins', item_usage_id)
self._verify_block('problem', course, 'ProblemBlockWithMixins', item_usage_id)
# Now simulate a new request cache.
self.store.request_cache.data.clear()
self._verify_descriptor('problem', course, 'HiddenBlockWithMixins', item_usage_id)
self._verify_block('problem', course, 'HiddenBlockWithMixins', item_usage_id)
def _verify_descriptor(self, category, course, descriptor, item_id=None):
def _verify_block(self, category, course, block, item_id=None):
"""
Helper method that gets an item with the specified category from the
modulestore and verifies that it has the expected descriptor name.
modulestore and verifies that it has the expected block name.
Returns the item's usage_id.
"""
@@ -2633,7 +2616,7 @@ class TestDisabledXBlockTypes(ModuleStoreTestCase):
item_id = item.scope_ids.usage_id # lint-amnesty, pylint: disable=no-member
item = self.store.get_item(item_id)
assert item.__class__.__name__ == descriptor
assert item.__class__.__name__ == block
return item_id
@@ -2650,15 +2633,15 @@ class LmsModuleSystemShimTest(SharedModuleStoreTestCase):
@classmethod
def setUpClass(cls):
"""
Set up the course and descriptor used to instantiate the runtime.
Set up the course and block used to instantiate the runtime.
"""
super().setUpClass()
org = 'edX'
number = 'LmsModuleShimTest'
run = '2021_Fall'
cls.course = CourseFactory.create(org=org, number=number, run=run)
cls.descriptor = BlockFactory(category="vertical", parent=cls.course)
cls.problem_descriptor = BlockFactory(category="problem", parent=cls.course)
cls.block = BlockFactory(category="vertical", parent=cls.course)
cls.problem_block = BlockFactory(category="problem", parent=cls.course)
def setUp(self):
"""
@@ -2673,7 +2656,7 @@ class LmsModuleSystemShimTest(SharedModuleStoreTestCase):
_ = render.prepare_runtime_for_user(
self.user,
self.student_data,
self.descriptor,
self.block,
self.course.id,
self.track_function,
self.request_token,
@@ -2690,37 +2673,37 @@ class LmsModuleSystemShimTest(SharedModuleStoreTestCase):
"""
Tests that the deprecated attributes provided by the user service match expected values.
"""
assert getattr(self.descriptor.runtime, attribute) == expected_value
assert getattr(self.block.runtime, attribute) == expected_value
@patch('lms.djangoapps.courseware.block_render.has_access', Mock(return_value=True, autospec=True))
def test_user_is_staff(self):
_ = render.prepare_runtime_for_user(
self.user,
self.student_data,
self.descriptor,
self.block,
self.course.id,
self.track_function,
self.request_token,
course=self.course,
)
assert self.descriptor.runtime.user_is_staff
assert self.descriptor.runtime.get_user_role() == 'student'
assert self.block.runtime.user_is_staff
assert self.block.runtime.get_user_role() == 'student'
@patch('lms.djangoapps.courseware.block_render.get_user_role', Mock(return_value='instructor', autospec=True))
def test_get_user_role(self):
_ = render.prepare_runtime_for_user(
self.user,
self.student_data,
self.descriptor,
self.block,
self.course.id,
self.track_function,
self.request_token,
course=self.course,
)
assert self.descriptor.runtime.get_user_role() == 'instructor'
assert self.block.runtime.get_user_role() == 'instructor'
def test_anonymous_student_id(self):
assert self.descriptor.runtime.anonymous_student_id == anonymous_id_for_user(self.user, self.course.id)
assert self.block.runtime.anonymous_student_id == anonymous_id_for_user(self.user, self.course.id)
def test_anonymous_student_id_bug(self):
"""
@@ -2730,76 +2713,76 @@ class LmsModuleSystemShimTest(SharedModuleStoreTestCase):
_ = render.prepare_runtime_for_user(
self.user,
self.student_data,
self.problem_descriptor,
self.problem_block,
self.course.id,
self.track_function,
self.request_token,
course=self.course,
)
# Ensure the problem block returns a per-user anonymous id
assert self.problem_descriptor.runtime.anonymous_student_id == anonymous_id_for_user(self.user, None)
assert self.problem_block.runtime.anonymous_student_id == anonymous_id_for_user(self.user, None)
_ = render.prepare_runtime_for_user(
self.user,
self.student_data,
self.descriptor,
self.block,
self.course.id,
self.track_function,
self.request_token,
course=self.course,
)
# Ensure the vertical block returns a per-course+user anonymous id
assert self.descriptor.runtime.anonymous_student_id == anonymous_id_for_user(self.user, self.course.id)
assert self.block.runtime.anonymous_student_id == anonymous_id_for_user(self.user, self.course.id)
# Ensure the problem runtime's anonymous student ID is unchanged after the above call.
assert self.problem_descriptor.runtime.anonymous_student_id == anonymous_id_for_user(self.user, None)
assert self.problem_block.runtime.anonymous_student_id == anonymous_id_for_user(self.user, None)
def test_user_service_with_anonymous_user(self):
_ = render.prepare_runtime_for_user(
AnonymousUser(),
self.student_data,
self.descriptor,
self.block,
self.course.id,
self.track_function,
self.request_token,
course=self.course,
)
assert self.descriptor.runtime.anonymous_student_id is None
assert self.descriptor.runtime.seed == 0
assert self.descriptor.runtime.user_id is None
assert not self.descriptor.runtime.user_is_staff
assert not self.descriptor.runtime.get_user_role()
assert self.block.runtime.anonymous_student_id is None
assert self.block.runtime.seed == 0
assert self.block.runtime.user_id is None
assert not self.block.runtime.user_is_staff
assert not self.block.runtime.get_user_role()
def test_get_real_user(self):
_ = render.prepare_runtime_for_user(
self.user,
self.student_data,
self.descriptor,
self.block,
self.course.id,
self.track_function,
self.request_token,
course=self.course,
)
course_anonymous_student_id = anonymous_id_for_user(self.user, self.course.id)
assert self.descriptor.runtime.get_real_user(course_anonymous_student_id) == self.user # pylint: disable=not-callable
assert self.block.runtime.get_real_user(course_anonymous_student_id) == self.user # pylint: disable=not-callable
no_course_anonymous_student_id = anonymous_id_for_user(self.user, None)
assert self.descriptor.runtime.get_real_user(no_course_anonymous_student_id) == self.user # pylint: disable=not-callable
assert self.block.runtime.get_real_user(no_course_anonymous_student_id) == self.user # pylint: disable=not-callable
# Tests that the default is to use the user service's anonymous_student_id
assert self.descriptor.runtime.get_real_user() == self.user # pylint: disable=not-callable
assert self.block.runtime.get_real_user() == self.user # pylint: disable=not-callable
def test_render_template(self):
rendered = self.descriptor.runtime.render_template('templates/edxmako.html', {'element_id': 'hi'}) # pylint: disable=not-callable
rendered = self.block.runtime.render_template('templates/edxmako.html', {'element_id': 'hi'}) # pylint: disable=not-callable
assert rendered == '<div id="hi" ns="main">Testing the MakoService</div>\n'
def test_xqueue(self):
xqueue = self.descriptor.runtime.xqueue
xqueue = self.block.runtime.xqueue
assert isinstance(xqueue['interface'], XQueueInterface)
assert xqueue['interface'].url == 'http://sandbox-xqueue.edx.org'
assert xqueue['default_queuename'] == 'edX-LmsModuleShimTest'
assert xqueue['waittime'] == 5
callback_url = f'http://localhost:8000/courses/{self.course.id}/xqueue/232/{self.descriptor.location}'
callback_url = f'http://localhost:8000/courses/{self.course.id}/xqueue/232/{self.block.location}'
assert xqueue['construct_callback']() == f'{callback_url}/score_update'
assert xqueue['construct_callback']('mock_dispatch') == f'{callback_url}/mock_dispatch'
@@ -2819,31 +2802,31 @@ class LmsModuleSystemShimTest(SharedModuleStoreTestCase):
_ = render.prepare_runtime_for_user(
self.user,
self.student_data,
self.descriptor,
self.block,
self.course.id,
self.track_function,
self.request_token,
course=self.course,
)
xqueue = self.descriptor.runtime.xqueue
xqueue = self.block.runtime.xqueue
assert isinstance(xqueue['interface'], XQueueInterface)
assert xqueue['interface'].url == 'http://xqueue.url'
assert xqueue['default_queuename'] == 'edX-LmsModuleShimTest'
assert xqueue['waittime'] == 15
callback_url = f'http://alt.url/courses/{self.course.id}/xqueue/232/{self.descriptor.location}'
callback_url = f'http://alt.url/courses/{self.course.id}/xqueue/232/{self.block.location}'
assert xqueue['construct_callback']() == f'{callback_url}/score_update'
assert xqueue['construct_callback']('mock_dispatch') == f'{callback_url}/mock_dispatch'
@override_settings(COURSES_WITH_UNSAFE_CODE=[r'course-v1:edX\+LmsModuleShimTest\+2021_Fall'])
def test_can_execute_unsafe_code_when_allowed(self):
assert self.descriptor.runtime.can_execute_unsafe_code()
assert self.block.runtime.can_execute_unsafe_code()
@override_settings(COURSES_WITH_UNSAFE_CODE=[r'course-v1:edX\+full\+2021_Fall'])
def test_cannot_execute_unsafe_code_when_disallowed(self):
assert not self.descriptor.runtime.can_execute_unsafe_code()
assert not self.block.runtime.can_execute_unsafe_code()
def test_cannot_execute_unsafe_code(self):
assert not self.descriptor.runtime.can_execute_unsafe_code()
assert not self.block.runtime.can_execute_unsafe_code()
@override_settings(PYTHON_LIB_FILENAME=PYTHON_LIB_FILENAME)
def test_get_python_lib_zip(self):
@@ -2853,7 +2836,7 @@ class LmsModuleSystemShimTest(SharedModuleStoreTestCase):
source_file=self.PYTHON_LIB_SOURCE_FILE,
target_filename=self.PYTHON_LIB_FILENAME,
)
assert self.descriptor.runtime.get_python_lib_zip() == zipfile
assert self.block.runtime.get_python_lib_zip() == zipfile
def test_no_get_python_lib_zip(self):
zipfile = upload_file_to_course(
@@ -2862,32 +2845,32 @@ class LmsModuleSystemShimTest(SharedModuleStoreTestCase):
source_file=self.PYTHON_LIB_SOURCE_FILE,
target_filename=self.PYTHON_LIB_FILENAME,
)
assert self.descriptor.runtime.get_python_lib_zip() is None
assert self.block.runtime.get_python_lib_zip() is None
def test_cache(self):
assert hasattr(self.descriptor.runtime.cache, 'get')
assert hasattr(self.descriptor.runtime.cache, 'set')
assert hasattr(self.block.runtime.cache, 'get')
assert hasattr(self.block.runtime.cache, 'set')
def test_replace_urls(self):
html = '<a href="/static/id">'
assert self.descriptor.runtime.replace_urls(html) == \
assert self.block.runtime.replace_urls(html) == \
static_replace.replace_static_urls(html, course_id=self.course.id)
def test_replace_course_urls(self):
html = '<a href="/course/id">'
assert self.descriptor.runtime.replace_course_urls(html) == \
assert self.block.runtime.replace_course_urls(html) == \
static_replace.replace_course_urls(html, course_key=self.course.id)
def test_replace_jump_to_id_urls(self):
html = '<a href="/jump_to_id/id">'
jump_to_id_base_url = reverse('jump_to_id', kwargs={'course_id': str(self.course.id), 'module_id': ''})
assert self.descriptor.runtime.replace_jump_to_id_urls(html) == \
assert self.block.runtime.replace_jump_to_id_urls(html) == \
static_replace.replace_jump_to_id_urls(html, self.course.id, jump_to_id_base_url)
@XBlock.register_temp_plugin(PureXBlock, 'pure')
@XBlock.register_temp_plugin(PureXBlockWithChildren, identifier='xblock')
def test_course_id(self):
descriptor = BlockFactory(category="pure", parent=self.course)
block = BlockFactory(category="pure", parent=self.course)
block = render.get_block(self.user, Mock(), descriptor.location, None)
assert str(block.runtime.course_id) == self.COURSE_ID
rendered_block = render.get_block(self.user, Mock(), block.location, None)
assert str(rendered_block.runtime.course_id) == self.COURSE_ID

View File

@@ -382,7 +382,7 @@ class CourseInstantiationTests(ModuleStoreTestCase):
course = modulestore().get_course(course.id, depth=course_depth)
for _ in range(loops):
field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
field_data_cache = FieldDataCache.cache_for_block_descendents(
course.id, self.user, course, depth=course_depth
)
course_block = get_block_for_descriptor(

View File

@@ -295,7 +295,7 @@ class TestXBlockInCourse(SharedModuleStoreTestCase):
"""
discussion_xblock = get_block_for_descriptor_internal(
user=self.user,
descriptor=self.discussion,
block=self.discussion,
student_data=mock.Mock(name='student_data'),
course_id=self.course.id,
track_function=mock.Mock(name='track_function'),
@@ -335,10 +335,10 @@ class TestXBlockInCourse(SharedModuleStoreTestCase):
assert orphan_sequential.location.block_type == root.location.block_type
assert orphan_sequential.location.block_id == root.location.block_id
# Get xblock bound to a user and a descriptor.
# Get xblock bound to a user and a block.
discussion_xblock = get_block_for_descriptor_internal(
user=self.user,
descriptor=discussion,
block=discussion,
student_data=mock.Mock(name='student_data'),
course_id=self.course.id,
track_function=mock.Mock(name='track_function'),
@@ -388,7 +388,7 @@ class TestXBlockInCourse(SharedModuleStoreTestCase):
discussion_xblock = get_block_for_descriptor_internal(
user=self.user,
descriptor=self.discussion,
block=self.discussion,
student_data=mock.Mock(name='student_data'),
course_id=self.course.id,
track_function=mock.Mock(name='track_function'),
@@ -438,7 +438,7 @@ class TestXBlockQueryLoad(SharedModuleStoreTestCase):
for discussion in discussions:
discussion_xblock = get_block_for_descriptor_internal(
user=user,
descriptor=discussion,
block=discussion,
student_data=mock.Mock(name='student_data'),
course_id=course.id,
track_function=mock.Mock(name='track_function'),

View File

@@ -340,7 +340,7 @@ class EntranceExamTestCases(LoginEnrollmentTestCase, ModuleStoreTestCase, Milest
Returns the table of contents for course self.course, for chapter
self.entrance_exam, and for section self.exam1
"""
self.field_data_cache = FieldDataCache.cache_for_descriptor_descendents( # pylint: disable=attribute-defined-outside-init
self.field_data_cache = FieldDataCache.cache_for_block_descendents( # pylint: disable=attribute-defined-outside-init
self.course.id,
self.request.user,
self.entrance_exam
@@ -372,7 +372,7 @@ def answer_entrance_exam_problem(course, request, problem, user=None, value=1, m
user = request.user
grade_dict = {'value': value, 'max_value': max_value, 'user_id': user.id}
field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
field_data_cache = FieldDataCache.cache_for_block_descendents(
course.id,
user,
course,

View File

@@ -40,11 +40,11 @@ class TestLTI(BaseTestXmodule):
mocked_decoded_signature = 'my_signature='
# Note: this course_id is actually a course_key
context_id = str(self.item_descriptor.course_id)
user_service = self.item_descriptor.runtime.service(self.item_descriptor, 'user')
context_id = str(self.block.course_id)
user_service = self.block.runtime.service(self.block, 'user')
user_id = str(user_service.get_current_user().opt_attrs.get(ATTR_KEY_ANONYMOUS_USER_ID))
hostname = settings.LMS_BASE
resource_link_id = str(urllib.parse.quote(f'{hostname}-{self.item_descriptor.location.html_id()}'))
resource_link_id = str(urllib.parse.quote(f'{hostname}-{self.block.location.html_id()}'))
sourcedId = "{context}:{resource_link}:{user_id}".format(
context=urllib.parse.quote(context_id),
@@ -75,14 +75,14 @@ class TestLTI(BaseTestXmodule):
saved_sign = oauthlib.oauth1.Client.sign
self.expected_context = {
'display_name': self.item_descriptor.display_name,
'display_name': self.block.display_name,
'input_fields': self.correct_headers,
'element_class': self.item_descriptor.category,
'element_id': self.item_descriptor.location.html_id(),
'element_class': self.block.category,
'element_id': self.block.location.html_id(),
'launch_url': 'http://www.example.com', # default value
'open_in_a_new_page': True,
'form_url': self.item_descriptor.runtime.handler_url(
self.item_descriptor,
'form_url': self.block.runtime.handler_url(
self.block,
'preview_handler'
).rstrip('/?'),
'hide_launch': False,
@@ -90,11 +90,11 @@ class TestLTI(BaseTestXmodule):
'module_score': None,
'comment': '',
'weight': 1.0,
'ask_to_send_username': self.item_descriptor.ask_to_send_username,
'ask_to_send_email': self.item_descriptor.ask_to_send_email,
'description': self.item_descriptor.description,
'button_text': self.item_descriptor.button_text,
'accept_grades_past_due': self.item_descriptor.accept_grades_past_due,
'ask_to_send_username': self.block.ask_to_send_username,
'ask_to_send_email': self.block.ask_to_send_email,
'description': self.block.description,
'button_text': self.block.button_text,
'accept_grades_past_due': self.block.accept_grades_past_due,
}
def mocked_sign(self, *args, **kwargs):
@@ -117,12 +117,12 @@ class TestLTI(BaseTestXmodule):
self.addCleanup(patcher.stop)
def test_lti_constructor(self):
generated_content = self.item_descriptor.render(STUDENT_VIEW).content
generated_content = self.block.render(STUDENT_VIEW).content
expected_content = self.runtime.render_template('lti.html', self.expected_context)
assert generated_content == expected_content
def test_lti_preview_handler(self):
generated_content = self.item_descriptor.preview_handler(None, None).body
generated_content = self.block.preview_handler(None, None).body
expected_content = self.runtime.render_template('lti_form.html', self.expected_context)
assert generated_content.decode('utf-8') == expected_content

View File

@@ -35,13 +35,13 @@ def mock_field(scope, name):
return field
def mock_descriptor(fields=[]): # lint-amnesty, pylint: disable=dangerous-default-value, missing-function-docstring
descriptor = Mock(entry_point=XBlock.entry_point)
descriptor.scope_ids = ScopeIds('user1', 'mock_problem', LOCATION('def_id'), LOCATION('usage_id'))
descriptor.module_class.fields.values.return_value = fields
descriptor.fields.values.return_value = fields
descriptor.module_class.__name__ = 'MockProblemModule'
return descriptor
def mock_block(fields=[]): # lint-amnesty, pylint: disable=dangerous-default-value, missing-function-docstring
block = Mock(entry_point=XBlock.entry_point)
block.scope_ids = ScopeIds('user1', 'mock_problem', LOCATION('def_id'), LOCATION('usage_id'))
block.module_class.fields.values.return_value = fields
block.fields.values.return_value = fields
block.module_class.__name__ = 'MockProblemModule'
return block
# The user ids here are 1 because we make a student in the setUp functions, and
# they get an id of 1. There's an assertion in setUp to ensure that assumption
@@ -63,7 +63,7 @@ class TestInvalidScopes(TestCase): # lint-amnesty, pylint: disable=missing-clas
super().setUp()
self.user = UserFactory.create(username='user')
self.field_data_cache = FieldDataCache(
[mock_descriptor([mock_field(Scope.user_state, 'a_field')])],
[mock_block([mock_field(Scope.user_state, 'a_field')])],
COURSE_KEY,
self.user,
)
@@ -120,10 +120,10 @@ class TestStudentModuleStorage(OtherUserFailureTestMixin, TestCase):
assert self.user.id == 1
# check our assumption hard-coded in the key functions above.
# There should be only one query to load a single descriptor with a single user_state field
# There should be only one query to load a single block with a single user_state field
with self.assertNumQueries(1):
self.field_data_cache = FieldDataCache(
[mock_descriptor([mock_field(Scope.user_state, 'a_field')])],
[mock_block([mock_field(Scope.user_state, 'a_field')])],
COURSE_KEY,
self.user,
)
@@ -250,10 +250,10 @@ class TestMissingStudentModule(TestCase): # lint-amnesty, pylint: disable=missi
assert self.user.id == 1
# check our assumption hard-coded in the key functions above.
# The descriptor has no fields, so FDC shouldn't send any queries
# The block has no fields, so FDC shouldn't send any queries
with self.assertNumQueries(0):
self.field_data_cache = FieldDataCache(
[mock_descriptor()],
[mock_block()],
COURSE_KEY,
self.user,
)
@@ -318,14 +318,14 @@ class StorageTestBase:
self.user = field_storage.student
else:
self.user = UserFactory.create()
self.mock_descriptor = mock_descriptor([
self.mock_block = mock_block([
mock_field(self.scope, 'existing_field'),
mock_field(self.scope, 'other_existing_field')])
# Each field is stored as a separate row in the table,
# but we can query them in a single query
with self.assertNumQueries(1):
self.field_data_cache = FieldDataCache(
[self.mock_descriptor],
[self.mock_block],
COURSE_KEY,
self.user,
)

View File

@@ -172,12 +172,12 @@ class TestVideo(BaseTestVideoXBlock):
assert status_codes.pop() == 404
def test_handle_ajax_for_speed_with_nan(self):
self.item_descriptor.handle_ajax('save_user_state', {'speed': json.dumps(1.0)})
assert self.item_descriptor.speed == 1.0
assert self.item_descriptor.global_speed == 1.0
self.block.handle_ajax('save_user_state', {'speed': json.dumps(1.0)})
assert self.block.speed == 1.0
assert self.block.global_speed == 1.0
# try to set NaN value for speed.
response = self.item_descriptor.handle_ajax(
response = self.block.handle_ajax(
'save_user_state', {'speed': json.dumps(float('NaN'))}
)
@@ -186,8 +186,8 @@ class TestVideo(BaseTestVideoXBlock):
assert json.loads(response)['error'] == expected_error
# verify that the speed and global speed are still 1.0
assert self.item_descriptor.speed == 1.0
assert self.item_descriptor.global_speed == 1.0
assert self.block.speed == 1.0
assert self.block.global_speed == 1.0
def test_handle_ajax(self):
@@ -206,41 +206,41 @@ class TestVideo(BaseTestVideoXBlock):
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
assert response.status_code == 200
assert self.item_descriptor.speed is None
self.item_descriptor.handle_ajax('save_user_state', {'speed': json.dumps(2.0)})
assert self.item_descriptor.speed == 2.0
assert self.item_descriptor.global_speed == 2.0
assert self.block.speed is None
self.block.handle_ajax('save_user_state', {'speed': json.dumps(2.0)})
assert self.block.speed == 2.0
assert self.block.global_speed == 2.0
assert self.item_descriptor.saved_video_position == timedelta(0)
self.item_descriptor.handle_ajax('save_user_state', {'saved_video_position': "00:00:10"})
assert self.item_descriptor.saved_video_position == timedelta(0, 10)
assert self.block.saved_video_position == timedelta(0)
self.block.handle_ajax('save_user_state', {'saved_video_position': "00:00:10"})
assert self.block.saved_video_position == timedelta(0, 10)
assert self.item_descriptor.transcript_language == 'en'
self.item_descriptor.handle_ajax('save_user_state', {'transcript_language': "uk"})
assert self.item_descriptor.transcript_language == 'uk'
assert self.block.transcript_language == 'en'
self.block.handle_ajax('save_user_state', {'transcript_language': "uk"})
assert self.block.transcript_language == 'uk'
assert self.item_descriptor.bumper_do_not_show_again is False
self.item_descriptor.handle_ajax('save_user_state', {'bumper_do_not_show_again': True})
assert self.item_descriptor.bumper_do_not_show_again is True
assert self.block.bumper_do_not_show_again is False
self.block.handle_ajax('save_user_state', {'bumper_do_not_show_again': True})
assert self.block.bumper_do_not_show_again is True
with freezegun.freeze_time(now()):
assert self.item_descriptor.bumper_last_view_date is None
self.item_descriptor.handle_ajax('save_user_state', {'bumper_last_view_date': True})
assert self.item_descriptor.bumper_last_view_date == now()
assert self.block.bumper_last_view_date is None
self.block.handle_ajax('save_user_state', {'bumper_last_view_date': True})
assert self.block.bumper_last_view_date == now()
response = self.item_descriptor.handle_ajax('save_user_state', {'demoo<EFBFBD>': "sample"})
response = self.block.handle_ajax('save_user_state', {'demoo<EFBFBD>': "sample"})
assert json.loads(response)['success'] is True
def get_handler_url(self, handler, suffix):
"""
Return the URL for the specified handler on self.item_descriptor.
Return the URL for the specified handler on self.block.
"""
return self.item_descriptor.runtime.handler_url(
self.item_descriptor, handler, suffix
return self.block.runtime.handler_url(
self.block, handler, suffix
).rstrip('/?')
def tearDown(self):
_clear_assets(self.item_descriptor.location)
_clear_assets(self.block.location)
super().tearDown()
@@ -268,24 +268,23 @@ class TestTranscriptAvailableTranslationsDispatch(TestVideo): # lint-amnesty, p
def setUp(self):
super().setUp()
self.item_descriptor.render(STUDENT_VIEW)
self.item = self.item_descriptor
self.block.render(STUDENT_VIEW)
self.subs = {"start": [10], "end": [100], "text": ["Hi, welcome to Edx."]}
def test_available_translation_en(self):
good_sjson = _create_file(json.dumps(self.subs))
_upload_sjson_file(good_sjson, self.item_descriptor.location)
self.item.sub = _get_subs_id(good_sjson.name)
_upload_sjson_file(good_sjson, self.block.location)
self.block.sub = _get_subs_id(good_sjson.name)
request = Request.blank('/available_translations')
response = self.item.transcript(request=request, dispatch='available_translations')
response = self.block.transcript(request=request, dispatch='available_translations')
assert json.loads(response.body.decode('utf-8')) == ['en']
def test_available_translation_non_en(self):
_upload_file(_create_srt_file(), self.item_descriptor.location, os.path.split(self.srt_file.name)[1])
_upload_file(_create_srt_file(), self.block.location, os.path.split(self.srt_file.name)[1])
request = Request.blank('/available_translations')
response = self.item.transcript(request=request, dispatch='available_translations')
response = self.block.transcript(request=request, dispatch='available_translations')
assert json.loads(response.body.decode('utf-8')) == ['uk']
@patch('xmodule.video_block.transcripts_utils.get_video_transcript_content')
@@ -302,16 +301,16 @@ class TestTranscriptAvailableTranslationsDispatch(TestVideo): # lint-amnesty, p
good_sjson = _create_file(json.dumps(self.subs))
# Upload english transcript.
_upload_sjson_file(good_sjson, self.item_descriptor.location)
_upload_sjson_file(good_sjson, self.block.location)
# Upload non-english transcript.
_upload_file(self.srt_file, self.item_descriptor.location, os.path.split(self.srt_file.name)[1])
_upload_file(self.srt_file, self.block.location, os.path.split(self.srt_file.name)[1])
self.item.sub = _get_subs_id(good_sjson.name)
self.item.edx_video_id = 'an-edx-video-id'
self.block.sub = _get_subs_id(good_sjson.name)
self.block.edx_video_id = 'an-edx-video-id'
request = Request.blank('/available_translations')
response = self.item.transcript(request=request, dispatch='available_translations')
response = self.block.transcript(request=request, dispatch='available_translations')
assert sorted(json.loads(response.body.decode('utf-8'))) == sorted(['en', 'uk'])
@patch('xmodule.video_block.transcripts_utils.get_video_transcript_content')
@@ -365,13 +364,13 @@ class TestTranscriptAvailableTranslationsDispatch(TestVideo): # lint-amnesty, p
for lang_code, in_content_store in dict(transcripts).items():
if in_content_store:
file_name, __ = os.path.split(self.srt_file.name)
_upload_file(self.srt_file, self.item_descriptor.location, file_name)
_upload_file(self.srt_file, self.block.location, file_name)
transcripts[lang_code] = file_name
else:
transcripts[lang_code] = 'non_existent.srt.sjson'
if sub:
sjson_transcript = _create_file(json.dumps(self.subs))
_upload_sjson_file(sjson_transcript, self.item_descriptor.location)
_upload_sjson_file(sjson_transcript, self.block.location)
sub = _get_subs_id(sjson_transcript.name)
mock_get_video_transcript_content.return_value = {
@@ -383,12 +382,12 @@ class TestTranscriptAvailableTranslationsDispatch(TestVideo): # lint-amnesty, p
'file_name': 'edx.sjson'
}
mock_get_transcript_languages.return_value = val_transcripts
self.item.transcripts = transcripts
self.item.sub = sub
self.item.edx_video_id = 'an-edx-video-id'
self.block.transcripts = transcripts
self.block.sub = sub
self.block.edx_video_id = 'an-edx-video-id'
# Make request to available translations dispatch.
request = Request.blank('/available_translations')
response = self.item.transcript(request=request, dispatch='available_translations')
response = self.block.transcript(request=request, dispatch='available_translations')
self.assertCountEqual(json.loads(response.body.decode('utf-8')), result)
@patch('xmodule.video_block.transcripts_utils.edxval_api.get_available_transcript_languages')
@@ -398,7 +397,7 @@ class TestTranscriptAvailableTranslationsDispatch(TestVideo): # lint-amnesty, p
"""
mock_get_available_transcript_languages.return_value = ['en', 'de', 'ro']
request = Request.blank('/available_translations')
response = self.item.transcript(request=request, dispatch='available_translations')
response = self.block.transcript(request=request, dispatch='available_translations')
assert response.status_code == 404
@@ -426,19 +425,18 @@ class TestTranscriptAvailableTranslationsBumperDispatch(TestVideo): # lint-amne
def setUp(self):
super().setUp()
self.item_descriptor.render(STUDENT_VIEW)
self.item = self.item_descriptor
self.block.render(STUDENT_VIEW)
self.dispatch = "available_translations/?is_bumper=1"
self.item.video_bumper = {"transcripts": {"en": ""}}
self.block.video_bumper = {"transcripts": {"en": ""}}
@ddt.data("en", "uk")
def test_available_translation_en_and_non_en(self, lang):
filename = os.path.split(self.srt_file.name)[1]
_upload_file(self.srt_file, self.item_descriptor.location, filename)
self.item.video_bumper["transcripts"][lang] = filename
_upload_file(self.srt_file, self.block.location, filename)
self.block.video_bumper["transcripts"][lang] = filename
request = Request.blank('/' + self.dispatch)
response = self.item.transcript(request=request, dispatch=self.dispatch)
response = self.block.transcript(request=request, dispatch=self.dispatch)
assert json.loads(response.body.decode('utf-8')) == [lang]
@patch('xmodule.video_block.transcripts_utils.get_available_transcript_languages')
@@ -453,16 +451,16 @@ class TestTranscriptAvailableTranslationsBumperDispatch(TestVideo): # lint-amne
en_translation_filename = os.path.split(en_translation.name)[1]
uk_translation_filename = os.path.split(self.srt_file.name)[1]
# Upload english transcript.
_upload_file(en_translation, self.item_descriptor.location, en_translation_filename)
_upload_file(en_translation, self.block.location, en_translation_filename)
# Upload non-english transcript.
_upload_file(self.srt_file, self.item_descriptor.location, uk_translation_filename)
_upload_file(self.srt_file, self.block.location, uk_translation_filename)
self.item.video_bumper["transcripts"]["en"] = en_translation_filename
self.item.video_bumper["transcripts"]["uk"] = uk_translation_filename
self.block.video_bumper["transcripts"]["en"] = en_translation_filename
self.block.video_bumper["transcripts"]["uk"] = uk_translation_filename
request = Request.blank('/' + self.dispatch)
response = self.item.transcript(request=request, dispatch=self.dispatch)
response = self.block.transcript(request=request, dispatch=self.dispatch)
# Assert that bumper only get its own translations.
assert sorted(json.loads(response.body.decode('utf-8'))) == sorted(['en', 'uk'])
@@ -492,12 +490,11 @@ class TestTranscriptDownloadDispatch(TestVideo): # lint-amnesty, pylint: disabl
def setUp(self):
super().setUp()
self.item_descriptor.render(STUDENT_VIEW)
self.item = self.item_descriptor
self.block.render(STUDENT_VIEW)
def test_download_transcript_not_exist(self):
request = Request.blank('/download')
response = self.item.transcript(request=request, dispatch='download')
response = self.block.transcript(request=request, dispatch='download')
assert response.status == '404 Not Found'
@patch(
@@ -506,7 +503,7 @@ class TestTranscriptDownloadDispatch(TestVideo): # lint-amnesty, pylint: disabl
)
def test_download_srt_exist(self, __):
request = Request.blank('/download')
response = self.item.transcript(request=request, dispatch='download')
response = self.block.transcript(request=request, dispatch='download')
assert response.body.decode('utf-8') == 'Subs!'
assert response.headers['Content-Type'] == 'application/x-subrip; charset=utf-8'
assert response.headers['Content-Language'] == 'en'
@@ -516,19 +513,19 @@ class TestTranscriptDownloadDispatch(TestVideo): # lint-amnesty, pylint: disabl
return_value=('Subs!', 'txt', 'text/plain; charset=utf-8')
)
def test_download_txt_exist(self, __):
self.item.transcript_format = 'txt'
self.block.transcript_format = 'txt'
request = Request.blank('/download')
response = self.item.transcript(request=request, dispatch='download')
response = self.block.transcript(request=request, dispatch='download')
assert response.body.decode('utf-8') == 'Subs!'
assert response.headers['Content-Type'] == 'text/plain; charset=utf-8'
assert response.headers['Content-Language'] == 'en'
def test_download_en_no_sub(self):
request = Request.blank('/download')
response = self.item.transcript(request=request, dispatch='download')
response = self.block.transcript(request=request, dispatch='download')
assert response.status == '404 Not Found'
with pytest.raises(NotFoundError):
get_transcript(self.item)
get_transcript(self.block)
@patch(
'xmodule.video_block.transcripts_utils.get_transcript_for_video',
@@ -536,7 +533,7 @@ class TestTranscriptDownloadDispatch(TestVideo): # lint-amnesty, pylint: disabl
)
def test_download_non_en_non_ascii_filename(self, __):
request = Request.blank('/download')
response = self.item.transcript(request=request, dispatch='download')
response = self.block.transcript(request=request, dispatch='download')
assert response.body.decode('utf-8') == 'Subs!'
assert response.headers['Content-Type'] == 'application/x-subrip; charset=utf-8'
assert response.headers['Content-Disposition'] == 'attachment; filename="en_塞.srt"'
@@ -558,7 +555,7 @@ class TestTranscriptDownloadDispatch(TestVideo): # lint-amnesty, pylint: disabl
# Make request to XModule transcript handler
request = Request.blank('/download')
response = self.item.transcript(request=request, dispatch='download')
response = self.block.transcript(request=request, dispatch='download')
# Expected response
expected_content = '0\n00:00:00,010 --> 00:00:00,100\nHi, welcome to Edx.\n\n'
@@ -602,9 +599,8 @@ class TestTranscriptTranslationGetDispatch(TestVideo): # lint-amnesty, pylint:
def setUp(self):
super().setUp()
self.item_descriptor.render(STUDENT_VIEW)
self.item = self.item_descriptor
self.item.video_bumper = {"transcripts": {"en": ""}}
self.block.render(STUDENT_VIEW)
self.block.video_bumper = {"transcripts": {"en": ""}}
@ddt.data(
# No language
@@ -623,7 +619,7 @@ class TestTranscriptTranslationGetDispatch(TestVideo): # lint-amnesty, pylint:
@ddt.unpack
def test_translation_fails(self, url, dispatch, status_code):
request = Request.blank(url)
response = self.item.transcript(request=request, dispatch=dispatch)
response = self.block.transcript(request=request, dispatch=dispatch)
assert response.status == status_code
@ddt.data(
@@ -633,12 +629,12 @@ class TestTranscriptTranslationGetDispatch(TestVideo): # lint-amnesty, pylint:
def test_translaton_en_youtube_success(self, url, dispatch, attach):
subs = {"start": [10], "end": [100], "text": ["Hi, welcome to Edx."]}
good_sjson = _create_file(json.dumps(subs))
_upload_sjson_file(good_sjson, self.item_descriptor.location)
_upload_sjson_file(good_sjson, self.block.location)
subs_id = _get_subs_id(good_sjson.name)
attach(self.item, subs_id)
attach(self.block, subs_id)
request = Request.blank(url.format(subs_id))
response = self.item.transcript(request=request, dispatch=dispatch)
response = self.block.transcript(request=request, dispatch=dispatch)
self.assertDictEqual(json.loads(response.body.decode('utf-8')), subs)
def test_translation_non_en_youtube_success(self):
@@ -650,20 +646,20 @@ class TestTranscriptTranslationGetDispatch(TestVideo): # lint-amnesty, pylint:
]
}
self.srt_file.seek(0)
_upload_file(self.srt_file, self.item_descriptor.location, os.path.split(self.srt_file.name)[1])
_upload_file(self.srt_file, self.block.location, os.path.split(self.srt_file.name)[1])
subs_id = _get_subs_id(self.srt_file.name)
# youtube 1_0 request, will generate for all speeds for existing ids
self.item.youtube_id_1_0 = subs_id
self.item.youtube_id_0_75 = '0_75'
self.store.update_item(self.item, self.user.id)
self.block.youtube_id_1_0 = subs_id
self.block.youtube_id_0_75 = '0_75'
self.store.update_item(self.block, self.user.id)
request = Request.blank(f'/translation/uk?videoId={subs_id}')
response = self.item.transcript(request=request, dispatch='translation/uk')
response = self.block.transcript(request=request, dispatch='translation/uk')
self.assertDictEqual(json.loads(response.body.decode('utf-8')), subs)
# 0_75 subs are exist
request = Request.blank('/translation/uk?videoId={}'.format('0_75'))
response = self.item.transcript(request=request, dispatch='translation/uk')
response = self.block.transcript(request=request, dispatch='translation/uk')
calculated_0_75 = {
'end': [75],
'start': [9],
@@ -674,10 +670,10 @@ class TestTranscriptTranslationGetDispatch(TestVideo): # lint-amnesty, pylint:
self.assertDictEqual(json.loads(response.body.decode('utf-8')), calculated_0_75)
# 1_5 will be generated from 1_0
self.item.youtube_id_1_5 = '1_5'
self.store.update_item(self.item, self.user.id)
self.block.youtube_id_1_5 = '1_5'
self.store.update_item(self.block, self.user.id)
request = Request.blank('/translation/uk?videoId={}'.format('1_5'))
response = self.item.transcript(request=request, dispatch='translation/uk')
response = self.block.transcript(request=request, dispatch='translation/uk')
calculated_1_5 = {
'end': [150],
'start': [18],
@@ -693,13 +689,13 @@ class TestTranscriptTranslationGetDispatch(TestVideo): # lint-amnesty, pylint:
@ddt.unpack
def test_translaton_en_html5_success(self, url, dispatch, attach):
good_sjson = _create_file(json.dumps(TRANSCRIPT))
_upload_sjson_file(good_sjson, self.item_descriptor.location)
_upload_sjson_file(good_sjson, self.block.location)
subs_id = _get_subs_id(good_sjson.name)
attach(self.item, subs_id)
self.store.update_item(self.item, self.user.id)
attach(self.block, subs_id)
self.store.update_item(self.block, self.user.id)
request = Request.blank(url)
response = self.item.transcript(request=request, dispatch=dispatch)
response = self.block.transcript(request=request, dispatch=dispatch)
self.assertDictEqual(json.loads(response.body.decode('utf-8')), TRANSCRIPT)
def test_translaton_non_en_html5_success(self):
@@ -711,12 +707,12 @@ class TestTranscriptTranslationGetDispatch(TestVideo): # lint-amnesty, pylint:
]
}
self.srt_file.seek(0)
_upload_file(self.srt_file, self.item_descriptor.location, os.path.split(self.srt_file.name)[1])
_upload_file(self.srt_file, self.block.location, os.path.split(self.srt_file.name)[1])
# manually clean youtube_id_1_0, as it has default value
self.item.youtube_id_1_0 = ""
self.block.youtube_id_1_0 = ""
request = Request.blank('/translation/uk')
response = self.item.transcript(request=request, dispatch='translation/uk')
response = self.block.transcript(request=request, dispatch='translation/uk')
self.assertDictEqual(json.loads(response.body.decode('utf-8')), subs)
def test_translation_static_transcript_xml_with_data_dirc(self):
@@ -730,25 +726,25 @@ class TestTranscriptTranslationGetDispatch(TestVideo): # lint-amnesty, pylint:
test_modulestore = MagicMock()
attrs = {'get_course.return_value': Mock(data_dir='dummy/static', static_asset_path='')}
test_modulestore.configure_mock(**attrs)
self.item_descriptor.runtime.modulestore = test_modulestore
self.block.runtime.modulestore = test_modulestore
# Test youtube style en
request = Request.blank('/translation/en?videoId=12345')
response = self.item.transcript(request=request, dispatch='translation/en')
response = self.block.transcript(request=request, dispatch='translation/en')
assert response.status == '307 Temporary Redirect'
assert ('Location', '/static/dummy/static/subs_12345.srt.sjson') in response.headerlist
# Test HTML5 video style
self.item.sub = 'OEoXaMPEzfM'
self.block.sub = 'OEoXaMPEzfM'
request = Request.blank('/translation/en')
response = self.item.transcript(request=request, dispatch='translation/en')
response = self.block.transcript(request=request, dispatch='translation/en')
assert response.status == '307 Temporary Redirect'
assert ('Location', '/static/dummy/static/subs_OEoXaMPEzfM.srt.sjson') in response.headerlist
# Test different language to ensure we are just ignoring it since we can't
# translate with static fallback
request = Request.blank('/translation/uk')
response = self.item.transcript(request=request, dispatch='translation/uk')
response = self.block.transcript(request=request, dispatch='translation/uk')
assert response.status == '404 Not Found'
@ddt.data(
@@ -774,9 +770,9 @@ class TestTranscriptTranslationGetDispatch(TestVideo): # lint-amnesty, pylint:
self._set_static_asset_path()
if attach:
attach(self.item, sub)
attach(self.block, sub)
request = Request.blank(url)
response = self.item.transcript(request=request, dispatch=dispatch)
response = self.block.transcript(request=request, dispatch=dispatch)
assert response.status == status_code
if sub:
assert ('Location', f'/static/dummy/static/subs_{sub}.srt.sjson') in response.headerlist
@@ -791,7 +787,7 @@ class TestTranscriptTranslationGetDispatch(TestVideo): # lint-amnesty, pylint:
# When course_id is not mocked out, these values would result in 307, as tested above.
request = Request.blank('/translation/en?videoId=12345')
response = self.item.transcript(request=request, dispatch='translation/en')
response = self.block.transcript(request=request, dispatch='translation/en')
assert response.status == '404 Not Found'
def _set_static_asset_path(self):
@@ -821,7 +817,7 @@ class TestTranscriptTranslationGetDispatch(TestVideo): # lint-amnesty, pylint:
mock_get_video_transcript_data.return_value = transcript
# Make request to XModule transcript handler
response = self.item.transcript(request=Request.blank('/translation/en'), dispatch='translation/en')
response = self.block.transcript(request=Request.blank('/translation/en'), dispatch='translation/en')
# Expected headers
expected_headers = {
@@ -842,7 +838,7 @@ class TestTranscriptTranslationGetDispatch(TestVideo): # lint-amnesty, pylint:
Verify that val transcript is not returned when its feature is disabled.
"""
# Make request to XModule transcript handler
response = self.item.transcript(request=Request.blank('/translation/en'), dispatch='translation/en')
response = self.block.transcript(request=Request.blank('/translation/en'), dispatch='translation/en')
# Assert the actual response
assert response.status_code == 404
@@ -870,20 +866,20 @@ class TestStudioTranscriptTranslationGetDispatch(TestVideo): # lint-amnesty, py
def test_translation_fails(self):
# No language
request = Request.blank("")
response = self.item_descriptor.studio_transcript(request=request, dispatch="translation")
response = self.block.studio_transcript(request=request, dispatch="translation")
assert response.status == '400 Bad Request'
# No language_code param in request.GET
request = Request.blank("")
response = self.item_descriptor.studio_transcript(request=request, dispatch="translation")
response = self.block.studio_transcript(request=request, dispatch="translation")
assert response.status == '400 Bad Request'
assert response.json['error'] == 'Language is required.'
# Correct case:
filename = os.path.split(self.srt_file.name)[1]
_upload_file(self.srt_file, self.item_descriptor.location, filename)
_upload_file(self.srt_file, self.block.location, filename)
request = Request.blank("translation?language_code=uk")
response = self.item_descriptor.studio_transcript(request=request, dispatch="translation?language_code=uk")
response = self.block.studio_transcript(request=request, dispatch="translation?language_code=uk")
self.srt_file.seek(0)
assert response.body == self.srt_file.read()
assert response.headers['Content-Type'] == 'application/x-subrip; charset=utf-8'
@@ -892,9 +888,9 @@ class TestStudioTranscriptTranslationGetDispatch(TestVideo): # lint-amnesty, py
# Non ascii file name download:
self.srt_file.seek(0)
_upload_file(self.srt_file, self.item_descriptor.location, "塞.srt")
_upload_file(self.srt_file, self.block.location, "塞.srt")
request = Request.blank("translation?language_code=zh")
response = self.item_descriptor.studio_transcript(request=request, dispatch="translation?language_code=zh")
response = self.block.studio_transcript(request=request, dispatch="translation?language_code=zh")
self.srt_file.seek(0)
assert response.body == self.srt_file.read()
assert response.headers['Content-Type'] == 'application/x-subrip; charset=utf-8'
@@ -945,9 +941,9 @@ class TestStudioTranscriptTranslationPostDispatch(TestVideo): # lint-amnesty, p
Verify that POST request validations works as expected.
"""
# mock available_translations method
self.item_descriptor.available_translations = lambda transcripts, verify_assets: ['ur']
self.block.available_translations = lambda transcripts, verify_assets: ['ur']
request = Request.blank('/translation', POST=post_data)
response = self.item_descriptor.studio_transcript(request=request, dispatch='translation')
response = self.block.studio_transcript(request=request, dispatch='translation')
assert response.json['error'] == error_message
@ddt.data(
@@ -981,11 +977,11 @@ class TestStudioTranscriptTranslationPostDispatch(TestVideo): # lint-amnesty, p
})
request = Request.blank('/translation', POST=post_data)
response = self.item_descriptor.studio_transcript(request=request, dispatch='translation')
response = self.block.studio_transcript(request=request, dispatch='translation')
assert response.status == '201 Created'
response = json.loads(response.text)
assert response['language_code'], 'uk'
self.assertDictEqual(self.item_descriptor.transcripts, {})
self.assertDictEqual(self.block.transcripts, {})
assert edxval_api.get_video_transcript_data(video_id=response['edx_video_id'], language_code='uk')
def test_studio_transcript_post_bad_content(self):
@@ -1000,7 +996,7 @@ class TestStudioTranscriptTranslationPostDispatch(TestVideo): # lint-amnesty, p
}
request = Request.blank("/translation", POST=post_data)
response = self.item_descriptor.studio_transcript(request=request, dispatch="translation")
response = self.block.studio_transcript(request=request, dispatch="translation")
assert response.status_code == 400
assert response.json['error'] == 'There is a problem with this transcript file. Try to upload a different file.'
@@ -1033,7 +1029,7 @@ class TestStudioTranscriptTranslationDeleteDispatch(TestVideo): # lint-amnesty,
Verify that DELETE dispatch works as expected when required args are missing from request
"""
request = Request(self.REQUEST_META, body=json.dumps(params).encode('utf-8'))
response = self.item_descriptor.studio_transcript(request=request, dispatch='translation')
response = self.block.studio_transcript(request=request, dispatch='translation')
assert response.status_code == 400
def test_translation_delete_w_edx_video_id(self):
@@ -1060,8 +1056,8 @@ class TestStudioTranscriptTranslationDeleteDispatch(TestVideo): # lint-amnesty,
assert api.get_video_transcript_data(video_id=self.EDX_VIDEO_ID, language_code=self.LANGUAGE_CODE_UK)
request = Request(self.REQUEST_META, body=request_body.encode('utf-8'))
self.item_descriptor.edx_video_id = self.EDX_VIDEO_ID
response = self.item_descriptor.studio_transcript(request=request, dispatch='translation')
self.block.edx_video_id = self.EDX_VIDEO_ID
response = self.block.studio_transcript(request=request, dispatch='translation')
assert response.status_code == 200
# verify that a video transcript dose not exist for expected data
@@ -1076,20 +1072,20 @@ class TestStudioTranscriptTranslationDeleteDispatch(TestVideo): # lint-amnesty,
request = Request(self.REQUEST_META, body=request_body.encode('utf-8'))
# upload and verify that srt file exists in assets
_upload_file(self.SRT_FILE, self.item_descriptor.location, srt_file_name_uk)
assert _check_asset(self.item_descriptor.location, srt_file_name_uk)
_upload_file(self.SRT_FILE, self.block.location, srt_file_name_uk)
assert _check_asset(self.block.location, srt_file_name_uk)
# verify transcripts field
assert self.item_descriptor.transcripts != {}
assert self.LANGUAGE_CODE_UK in self.item_descriptor.transcripts
assert self.block.transcripts != {}
assert self.LANGUAGE_CODE_UK in self.block.transcripts
# make request and verify response
response = self.item_descriptor.studio_transcript(request=request, dispatch='translation')
response = self.block.studio_transcript(request=request, dispatch='translation')
assert response.status_code == 200
# verify that srt file is deleted
assert self.item_descriptor.transcripts == {}
assert not _check_asset(self.item_descriptor.location, srt_file_name_uk)
assert self.block.transcripts == {}
assert not _check_asset(self.block.location, srt_file_name_uk)
def test_translation_delete_w_english_lang(self):
"""
@@ -1097,45 +1093,45 @@ class TestStudioTranscriptTranslationDeleteDispatch(TestVideo): # lint-amnesty,
"""
request_body = json.dumps({'lang': self.LANGUAGE_CODE_EN, 'edx_video_id': ''})
srt_file_name_en = subs_filename('english_translation.srt', lang=self.LANGUAGE_CODE_EN)
self.item_descriptor.transcripts['en'] = 'english_translation.srt'
self.block.transcripts['en'] = 'english_translation.srt'
request = Request(self.REQUEST_META, body=request_body.encode('utf-8'))
# upload and verify that srt file exists in assets
_upload_file(self.SRT_FILE, self.item_descriptor.location, srt_file_name_en)
assert _check_asset(self.item_descriptor.location, srt_file_name_en)
_upload_file(self.SRT_FILE, self.block.location, srt_file_name_en)
assert _check_asset(self.block.location, srt_file_name_en)
# make request and verify response
response = self.item_descriptor.studio_transcript(request=request, dispatch='translation')
response = self.block.studio_transcript(request=request, dispatch='translation')
assert response.status_code == 200
# verify that srt file is deleted
assert self.LANGUAGE_CODE_EN not in self.item_descriptor.transcripts
assert not _check_asset(self.item_descriptor.location, srt_file_name_en)
assert self.LANGUAGE_CODE_EN not in self.block.transcripts
assert not _check_asset(self.block.location, srt_file_name_en)
def test_translation_delete_w_sub(self):
"""
Verify that DELETE dispatch works as expected when translation is present against `sub` field
"""
request_body = json.dumps({'lang': self.LANGUAGE_CODE_EN, 'edx_video_id': ''})
sub_file_name = subs_filename(self.item_descriptor.sub, lang=self.LANGUAGE_CODE_EN)
sub_file_name = subs_filename(self.block.sub, lang=self.LANGUAGE_CODE_EN)
request = Request(self.REQUEST_META, body=request_body.encode('utf-8'))
# sub should not be empy
assert not self.item_descriptor.sub == ''
assert not self.block.sub == ''
# lint-amnesty, pylint: disable=wrong-assert-type
# upload and verify that srt file exists in assets
_upload_file(self.SRT_FILE, self.item_descriptor.location, sub_file_name)
assert _check_asset(self.item_descriptor.location, sub_file_name)
_upload_file(self.SRT_FILE, self.block.location, sub_file_name)
assert _check_asset(self.block.location, sub_file_name)
# make request and verify response
response = self.item_descriptor.studio_transcript(request=request, dispatch='translation')
response = self.block.studio_transcript(request=request, dispatch='translation')
assert response.status_code == 200
# verify that sub is empty and transcript is deleted also
assert self.item_descriptor.sub == ''
assert self.block.sub == ''
# lint-amnesty, pylint: disable=wrong-assert-type
assert not _check_asset(self.item_descriptor.location, sub_file_name)
assert not _check_asset(self.block.location, sub_file_name)
class TestGetTranscript(TestVideo): # lint-amnesty, pylint: disable=test-inherits-tests
@@ -1161,8 +1157,7 @@ class TestGetTranscript(TestVideo): # lint-amnesty, pylint: disable=test-inheri
def setUp(self):
super().setUp()
self.item_descriptor.render(STUDENT_VIEW)
self.item = self.item_descriptor
self.block.render(STUDENT_VIEW)
def test_good_transcript(self):
"""
@@ -1185,10 +1180,10 @@ class TestGetTranscript(TestVideo): # lint-amnesty, pylint: disable=test-inheri
}
"""))
_upload_sjson_file(good_sjson, self.item.location)
self.item.sub = _get_subs_id(good_sjson.name)
_upload_sjson_file(good_sjson, self.block.location)
self.block.sub = _get_subs_id(good_sjson.name)
text, filename, mime_type = get_transcript(self.item)
text, filename, mime_type = get_transcript(self.block)
expected_text = textwrap.dedent("""\
0
@@ -1202,7 +1197,7 @@ class TestGetTranscript(TestVideo): # lint-amnesty, pylint: disable=test-inheri
""")
assert text == expected_text
assert filename[:(- 4)] == ('en_' + self.item.sub)
assert filename[:(- 4)] == ('en_' + self.block.sub)
assert mime_type == 'application/x-subrip; charset=utf-8'
def test_good_txt_transcript(self):
@@ -1223,29 +1218,29 @@ class TestGetTranscript(TestVideo): # lint-amnesty, pylint: disable=test-inheri
}
"""))
_upload_sjson_file(good_sjson, self.item.location)
self.item.sub = _get_subs_id(good_sjson.name)
text, filename, mime_type = get_transcript(self.item, output_format=Transcript.TXT)
_upload_sjson_file(good_sjson, self.block.location)
self.block.sub = _get_subs_id(good_sjson.name)
text, filename, mime_type = get_transcript(self.block, output_format=Transcript.TXT)
expected_text = textwrap.dedent("""\
Hi, welcome to Edx.
Let's start with what is on your screen right now.""")
assert text == expected_text
assert filename == (('en_' + self.item.sub) + '.txt')
assert filename == (('en_' + self.block.sub) + '.txt')
assert mime_type == 'text/plain; charset=utf-8'
def test_en_with_empty_sub(self):
self.item.sub = ""
self.item.transcripts = None
self.block.sub = ""
self.block.transcripts = None
# no self.sub, self.youttube_1_0 exist, but no file in assets
with pytest.raises(NotFoundError):
get_transcript(self.item)
get_transcript(self.block)
# no self.sub and no self.youtube_1_0, no non-en transcritps
self.item.youtube_id_1_0 = None
self.block.youtube_id_1_0 = None
with pytest.raises(NotFoundError):
get_transcript(self.item)
get_transcript(self.block)
# no self.sub but youtube_1_0 exists with file in assets
good_sjson = _create_file(content=textwrap.dedent("""\
@@ -1264,10 +1259,10 @@ class TestGetTranscript(TestVideo): # lint-amnesty, pylint: disable=test-inheri
]
}
"""))
_upload_sjson_file(good_sjson, self.item.location)
self.item.youtube_id_1_0 = _get_subs_id(good_sjson.name)
_upload_sjson_file(good_sjson, self.block.location)
self.block.youtube_id_1_0 = _get_subs_id(good_sjson.name)
text, filename, mime_type = get_transcript(self.item)
text, filename, mime_type = get_transcript(self.block)
expected_text = textwrap.dedent("""\
0
00:00:00,270 --> 00:00:02,720
@@ -1280,16 +1275,16 @@ class TestGetTranscript(TestVideo): # lint-amnesty, pylint: disable=test-inheri
""")
assert text == expected_text
assert filename == (('en_' + self.item.youtube_id_1_0) + '.srt')
assert filename == (('en_' + self.block.youtube_id_1_0) + '.srt')
assert mime_type == 'application/x-subrip; charset=utf-8'
def test_non_en_with_non_ascii_filename(self):
self.item.transcript_language = 'zh'
self.block.transcript_language = 'zh'
self.srt_file.seek(0)
_upload_file(self.srt_file, self.item_descriptor.location, "塞.srt")
_upload_file(self.srt_file, self.block.location, "塞.srt")
transcripts = self.item.get_transcripts_info() # lint-amnesty, pylint: disable=unused-variable
text, filename, mime_type = get_transcript(self.item)
transcripts = self.block.get_transcripts_info() # lint-amnesty, pylint: disable=unused-variable
text, filename, mime_type = get_transcript(self.block)
expected_text = textwrap.dedent("""
0
00:00:00,12 --> 00:00:00,100
@@ -1302,12 +1297,12 @@ class TestGetTranscript(TestVideo): # lint-amnesty, pylint: disable=test-inheri
def test_value_error_handled(self):
good_sjson = _create_file(content='bad content')
_upload_sjson_file(good_sjson, self.item.location)
self.item.sub = _get_subs_id(good_sjson.name)
_upload_sjson_file(good_sjson, self.block.location)
self.block.sub = _get_subs_id(good_sjson.name)
transcripts = self.item.get_transcripts_info() # lint-amnesty, pylint: disable=unused-variable
transcripts = self.block.get_transcripts_info() # lint-amnesty, pylint: disable=unused-variable
error_transcript = {"start": [], "end": [], "text": ["An error occured obtaining the transcript."]}
content, _, _ = get_transcript(self.item)
content, _, _ = get_transcript(self.block)
assert error_transcript["text"][0] in content
def test_key_error(self):
@@ -1324,9 +1319,9 @@ class TestGetTranscript(TestVideo): # lint-amnesty, pylint: disable=test-inheri
}
""")
_upload_sjson_file(good_sjson, self.item.location)
self.item.sub = _get_subs_id(good_sjson.name)
_upload_sjson_file(good_sjson, self.block.location)
self.block.sub = _get_subs_id(good_sjson.name)
transcripts = self.item.get_transcripts_info() # lint-amnesty, pylint: disable=unused-variable
transcripts = self.block.get_transcripts_info() # lint-amnesty, pylint: disable=unused-variable
with pytest.raises(KeyError):
get_transcript(self.item)
get_transcript(self.block)

View File

@@ -81,7 +81,7 @@ class TestVideoYouTube(TestVideo): # lint-amnesty, pylint: disable=missing-clas
def test_video_constructor(self):
"""Make sure that all parameters extracted correctly from xml"""
context = self.item_descriptor.render(STUDENT_VIEW).content
context = self.block.render(STUDENT_VIEW).content
sources = ['example.mp4', 'example.webm']
expected_context = {
@@ -95,12 +95,12 @@ class TestVideoYouTube(TestVideo): # lint-amnesty, pylint: disable=missing-clas
'download_video_link': 'example.mp4',
'handout': None,
'hide_downloads': False,
'id': self.item_descriptor.location.html_id(),
'id': self.block.location.html_id(),
'is_embed': False,
'metadata': json.dumps(OrderedDict({
'autoAdvance': False,
'saveStateEnabled': True,
'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'saveStateUrl': self.block.ajax_url + '/save_user_state',
'autoplay': False,
'streams': '0.75:jNCf2gIqpeE,1.00:ZwkTiUPN0mg,1.25:rsq9auxASqI,1.50:kMyNdzVHHgg',
'sources': sources,
@@ -138,7 +138,7 @@ class TestVideoYouTube(TestVideo): # lint-amnesty, pylint: disable=missing-clas
'public_video_url': None,
}
mako_service = self.item_descriptor.runtime.service(self.item_descriptor, 'mako')
mako_service = self.block.runtime.service(self.block, 'mako')
assert get_context_dict_from_string(context) ==\
get_context_dict_from_string(mako_service.render_template('video.html', expected_context))
@@ -165,7 +165,7 @@ class TestVideoNonYouTube(TestVideo): # pylint: disable=test-inherits-tests
"""Make sure that if the 'youtube' attribute is omitted in XML, then
the template generates an empty string for the YouTube streams.
"""
context = self.item_descriptor.render(STUDENT_VIEW).content
context = self.block.render(STUDENT_VIEW).content
sources = ['example.mp4', 'example.webm']
expected_context = {
@@ -180,11 +180,11 @@ class TestVideoNonYouTube(TestVideo): # pylint: disable=test-inherits-tests
'handout': None,
'hide_downloads': False,
'is_embed': False,
'id': self.item_descriptor.location.html_id(),
'id': self.block.location.html_id(),
'metadata': json.dumps(OrderedDict({
'autoAdvance': False,
'saveStateEnabled': True,
'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'saveStateUrl': self.block.ajax_url + '/save_user_state',
'autoplay': False,
'streams': '1.00:3_yD_cEKoCk',
'sources': sources,
@@ -222,7 +222,7 @@ class TestVideoNonYouTube(TestVideo): # pylint: disable=test-inherits-tests
'public_video_url': None,
}
mako_service = self.item_descriptor.runtime.service(self.item_descriptor, 'mako')
mako_service = self.block.runtime.service(self.block, 'mako')
expected_result = get_context_dict_from_string(
mako_service.render_template('video.html', expected_context)
)
@@ -249,11 +249,11 @@ class TestVideoPublicAccess(BaseTestVideoXBlock):
@ddt.unpack
def test_public_video_url(self, is_lms_platform, enable_public_share):
"""Test public video url."""
assert self.item_descriptor.public_access is True
assert self.block.public_access is True
if not is_lms_platform:
self.item_descriptor.runtime.is_author_mode = True
self.block.runtime.is_author_mode = True
with patch.object(PUBLIC_VIDEO_SHARE, 'is_enabled', return_value=enable_public_share):
context = self.item_descriptor.render(STUDENT_VIEW).content
context = self.block.render(STUDENT_VIEW).content
# public video url iif PUBLIC_VIDEO_SHARE waffle and is_lms_platform, public_access are true
assert bool(get_context_dict_from_string(context)['public_video_url']) \
is (is_lms_platform and enable_public_share)
@@ -307,10 +307,10 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
def get_handler_url(self, handler, suffix):
"""
Return the URL for the specified handler on the block represented by
self.item_descriptor.
self.block.
"""
return self.item_descriptor.runtime.handler_url(
self.item_descriptor, handler, suffix
return self.block.runtime.handler_url(
self.block, handler, suffix
).rstrip('/?')
def test_get_html_track(self):
@@ -379,7 +379,7 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
'download_video_link': 'example.mp4',
'handout': None,
'hide_downloads': False,
'id': self.item_descriptor.location.html_id(),
'id': self.block.location.html_id(),
'is_embed': False,
'metadata': '',
'track': None,
@@ -406,27 +406,27 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
self.initialize_block(data=DATA)
track_url = self.get_handler_url('transcript', 'download')
context = self.item_descriptor.render(STUDENT_VIEW).content
context = self.block.render(STUDENT_VIEW).content
metadata.update({
'transcriptLanguages': {"en": "English"} if not data['transcripts'] else {"uk": 'Українська'},
'transcriptLanguage': 'en' if not data['transcripts'] or data.get('sub') else 'uk',
'transcriptTranslationUrl': self.get_handler_url('transcript', 'translation/__lang__'),
'transcriptAvailableTranslationsUrl': self.get_handler_url('transcript', 'available_translations'),
'publishCompletionUrl': self.get_handler_url('publish_completion', ''),
'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'saveStateUrl': self.block.ajax_url + '/save_user_state',
})
expected_context.update({
'transcript_download_format': (
None if self.item_descriptor.track and self.item_descriptor.download_track else 'srt'
None if self.block.track and self.block.download_track else 'srt'
),
'track': (
track_url if data['expected_track_url'] == 'a_sub_file.srt.sjson' else data['expected_track_url']
),
'id': self.item_descriptor.location.html_id(),
'id': self.block.location.html_id(),
'metadata': json.dumps(metadata)
})
mako_service = self.item_descriptor.runtime.service(self.item_descriptor, 'mako')
mako_service = self.block.runtime.service(self.block, 'mako')
assert get_context_dict_from_string(context) ==\
get_context_dict_from_string(mako_service.render_template('video.html', expected_context))
@@ -500,7 +500,7 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
'download_video_link': 'example.mp4',
'handout': None,
'hide_downloads': False,
'id': self.item_descriptor.location.html_id(),
'id': self.block.location.html_id(),
'is_embed': False,
'metadata': self.default_metadata_dict,
'track': None,
@@ -521,23 +521,23 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
sources=data['sources']
)
self.initialize_block(data=DATA)
context = self.item_descriptor.render(STUDENT_VIEW).content
context = self.block.render(STUDENT_VIEW).content
expected_context = dict(initial_context)
expected_context['metadata'].update({
'transcriptTranslationUrl': self.get_handler_url('transcript', 'translation/__lang__'),
'transcriptAvailableTranslationsUrl': self.get_handler_url('transcript', 'available_translations'),
'publishCompletionUrl': self.get_handler_url('publish_completion', ''),
'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'saveStateUrl': self.block.ajax_url + '/save_user_state',
'sources': data['result'].get('sources', []),
})
expected_context.update({
'id': self.item_descriptor.location.html_id(),
'id': self.block.location.html_id(),
'download_video_link': data['result'].get('download_video_link'),
'metadata': json.dumps(expected_context['metadata'])
})
mako_service = self.item_descriptor.runtime.service(self.item_descriptor, 'mako')
mako_service = self.block.runtime.service(self.block, 'mako')
assert get_context_dict_from_string(context) ==\
get_context_dict_from_string(mako_service.render_template('video.html', expected_context))
@@ -581,7 +581,7 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
# Referencing a non-existent VAL ID in courseware won't cause an error --
# it'll just fall back to the values in the VideoBlock.
assert 'example.mp4' in self.item_descriptor.render(STUDENT_VIEW).content
assert 'example.mp4' in self.block.render(STUDENT_VIEW).content
def test_get_html_with_mocked_edx_video_id(self):
# lint-amnesty, pylint: disable=invalid-name, redefined-outer-name
@@ -629,7 +629,7 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
'handout': None,
'hide_downloads': False,
'is_embed': False,
'id': self.item_descriptor.location.html_id(),
'id': self.block.location.html_id(),
'track': None,
'transcript_download_format': 'srt',
'transcript_download_formats_list': [
@@ -664,23 +664,23 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
}
]
}
context = self.item_descriptor.render(STUDENT_VIEW).content
context = self.block.render(STUDENT_VIEW).content
expected_context = dict(initial_context)
expected_context['metadata'].update({
'transcriptTranslationUrl': self.get_handler_url('transcript', 'translation/__lang__'),
'transcriptAvailableTranslationsUrl': self.get_handler_url('transcript', 'available_translations'),
'publishCompletionUrl': self.get_handler_url('publish_completion', ''),
'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'saveStateUrl': self.block.ajax_url + '/save_user_state',
'sources': data['result']['sources'],
})
expected_context.update({
'id': self.item_descriptor.location.html_id(),
'id': self.block.location.html_id(),
'download_video_link': data['result']['download_video_link'],
'metadata': json.dumps(expected_context['metadata'])
})
mako_service = self.item_descriptor.runtime.service(self.item_descriptor, 'mako')
mako_service = self.block.runtime.service(self.block, 'mako')
assert get_context_dict_from_string(context) ==\
get_context_dict_from_string(mako_service.render_template('video.html', expected_context))
@@ -708,7 +708,7 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
# context returned by get_html when provided with above data
# expected_context, a dict to assert with context
context, expected_context = self.helper_get_html_with_edx_video_id(data)
mako_service = self.item_descriptor.runtime.service(self.item_descriptor, 'mako')
mako_service = self.block.runtime.service(self.block, 'mako')
assert get_context_dict_from_string(context) ==\
get_context_dict_from_string(mako_service.render_template('video.html', expected_context))
@@ -739,7 +739,7 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
# expected_context, a dict to assert with context
context, expected_context = self.helper_get_html_with_edx_video_id(data)
mako_service = self.item_descriptor.runtime.service(self.item_descriptor, 'mako')
mako_service = self.block.runtime.service(self.block, 'mako')
assert get_context_dict_from_string(context) ==\
get_context_dict_from_string(mako_service.render_template('video.html', expected_context))
@@ -803,7 +803,7 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
'handout': None,
'hide_downloads': False,
'is_embed': False,
'id': self.item_descriptor.location.html_id(),
'id': self.block.location.html_id(),
'track': None,
'transcript_download_format': 'srt',
'transcript_download_formats_list': [
@@ -824,7 +824,7 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
)
self.initialize_block(data=DATA)
# context returned by get_html
context = self.item_descriptor.render(STUDENT_VIEW).content
context = self.block.render(STUDENT_VIEW).content
# expected_context, expected context to be returned by get_html
expected_context = dict(initial_context)
@@ -832,11 +832,11 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
'transcriptTranslationUrl': self.get_handler_url('transcript', 'translation/__lang__'),
'transcriptAvailableTranslationsUrl': self.get_handler_url('transcript', 'available_translations'),
'publishCompletionUrl': self.get_handler_url('publish_completion', ''),
'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'saveStateUrl': self.block.ajax_url + '/save_user_state',
'sources': data['result']['sources'],
})
expected_context.update({
'id': self.item_descriptor.location.html_id(),
'id': self.block.location.html_id(),
'download_video_link': data['result']['download_video_link'],
'metadata': json.dumps(expected_context['metadata'])
})
@@ -940,25 +940,25 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
self.initialize_block(data=DATA, runtime_kwargs={
'user_location': 'CN',
})
user_service = self.item_descriptor.runtime.service(self.item_descriptor, 'user')
user_service = self.block.runtime.service(self.block, 'user')
user_location = user_service.get_current_user().opt_attrs[ATTR_KEY_REQUEST_COUNTRY_CODE]
assert user_location == 'CN'
context = self.item_descriptor.render('student_view').content
context = self.block.render('student_view').content
expected_context = dict(initial_context)
expected_context['metadata'].update({
'transcriptTranslationUrl': self.get_handler_url('transcript', 'translation/__lang__'),
'transcriptAvailableTranslationsUrl': self.get_handler_url('transcript', 'available_translations'),
'publishCompletionUrl': self.get_handler_url('publish_completion', ''),
'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'saveStateUrl': self.block.ajax_url + '/save_user_state',
'sources': data['result'].get('sources', []),
})
expected_context.update({
'id': self.item_descriptor.location.html_id(),
'id': self.block.location.html_id(),
'download_video_link': data['result'].get('download_video_link'),
'metadata': json.dumps(expected_context['metadata'])
})
mako_service = self.item_descriptor.runtime.service(self.item_descriptor, 'mako')
mako_service = self.block.runtime.service(self.block, 'mako')
assert get_context_dict_from_string(context) ==\
get_context_dict_from_string(mako_service.render_template('video.html', expected_context))
@@ -1048,22 +1048,22 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
'client_video_id': 'external video',
'encoded_videos': {}
}
context = self.item_descriptor.render(STUDENT_VIEW).content
context = self.block.render(STUDENT_VIEW).content
expected_context = dict(initial_context)
expected_context['metadata'].update({
'transcriptTranslationUrl': self.get_handler_url('transcript', 'translation/__lang__'),
'transcriptAvailableTranslationsUrl': self.get_handler_url('transcript', 'available_translations'),
'publishCompletionUrl': self.get_handler_url('publish_completion', ''),
'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'saveStateUrl': self.block.ajax_url + '/save_user_state',
'sources': data['result'].get('sources', []),
})
expected_context.update({
'id': self.item_descriptor.location.html_id(),
'id': self.block.location.html_id(),
'download_video_link': data['result'].get('download_video_link'),
'metadata': json.dumps(expected_context['metadata'])
})
mako_service = self.item_descriptor.runtime.service(self.item_descriptor, 'mako')
mako_service = self.block.runtime.service(self.block, 'mako')
assert get_context_dict_from_string(context) ==\
get_context_dict_from_string(mako_service.render_template('video.html', expected_context))
@@ -1087,9 +1087,9 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
feature_enabled.return_value = hls_feature_enabled
video_xml = '<video display_name="Video" download_video="true" edx_video_id="12345-67890">[]</video>'
self.initialize_block(data=video_xml)
self.item_descriptor.render(STUDENT_VIEW)
self.block.render(STUDENT_VIEW)
get_urls_for_profiles.assert_called_with(
self.item_descriptor.edx_video_id,
self.block.edx_video_id,
expected_val_profiles,
)
@@ -1112,7 +1112,7 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
}
self.initialize_block(data=video_xml)
context = self.item_descriptor.render(STUDENT_VIEW).content
context = self.block.render(STUDENT_VIEW).content
assert "'download_video_link': 'https://mp4.com/dm.mp4'" in context
assert '"streams": "1.00:https://yt.com/?v=v0TFmdO4ZP0"' in context
@@ -1130,7 +1130,7 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
"""
self.initialize_block(data=video_xml)
context = self.item_descriptor.render(STUDENT_VIEW).content
context = self.block.render(STUDENT_VIEW).content
assert "'download_video_link': None" in context
def test_get_html_non_hls_video_download(self):
@@ -1146,7 +1146,7 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
"""
self.initialize_block(data=video_xml)
context = self.item_descriptor.render(STUDENT_VIEW).content
context = self.block.render(STUDENT_VIEW).content
assert "'download_video_link': 'http://example.com/example.mp4'" in context
def test_html_student_public_view(self):
@@ -1160,9 +1160,9 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
"""
self.initialize_block(data=video_xml)
context = self.item_descriptor.render(STUDENT_VIEW).content
context = self.block.render(STUDENT_VIEW).content
assert '"saveStateEnabled": true' in context
context = self.item_descriptor.render(PUBLIC_VIEW).content
context = self.block.render(PUBLIC_VIEW).content
assert '"saveStateEnabled": false' in context
@patch('xmodule.video_block.video_block.edxval_api.get_course_video_image_url')
@@ -1174,7 +1174,7 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
get_course_video_image_url.return_value = '/media/video-images/poster.png'
self.initialize_block(data=video_xml)
context = self.item_descriptor.render(STUDENT_VIEW).content
context = self.block.render(STUDENT_VIEW).content
assert '"poster": "/media/video-images/poster.png"' in context
@@ -1187,7 +1187,7 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
get_course_video_image_url.return_value = '/media/video-images/poster.png'
self.initialize_block(data=video_xml)
context = self.item_descriptor.render(STUDENT_VIEW).content
context = self.block.render(STUDENT_VIEW).content
assert "'poster': 'null'" in context
@@ -1198,7 +1198,7 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
"""
video_xml = '<video display_name="Video" download_video="true" edx_video_id="12345-67890">[]</video>'
self.initialize_block(data=video_xml)
context = self.item_descriptor.render(STUDENT_VIEW).content
context = self.block.render(STUDENT_VIEW).content
assert '"prioritizeHls": false' in context
@ddt.data(
@@ -1252,7 +1252,7 @@ class TestGetHtmlMethod(BaseTestVideoXBlock):
with patch.object(WaffleFlagCourseOverrideModel, 'override_value', return_value=data['course_override']):
with override_waffle_flag(DEPRECATE_YOUTUBE, active=data['waffle_enabled']):
self.initialize_block(data=video_xml, metadata=metadata)
context = self.item_descriptor.render(STUDENT_VIEW).content
context = self.block.render(STUDENT_VIEW).content
assert '"prioritizeHls": {}'.format(data['result']) in context
@@ -1316,7 +1316,7 @@ class TestVideoBlockInitialization(BaseTestVideoXBlock):
self.initialize_block(
data='<video display_name="Video" download_video="true" edx_video_id="12345-67890">[]</video>'
)
context = self.item_descriptor.get_context()
context = self.block.get_context()
assert context['transcripts_basic_tab_metadata']['video_url']['value'] == video_url
@ddt.data(
@@ -1354,7 +1354,7 @@ class TestVideoBlockInitialization(BaseTestVideoXBlock):
self.initialize_block(
data='<video display_name="Video" youtube_id_1_0="" download_video="true" edx_video_id="12345-67890">[]</video>'
)
context = self.item_descriptor.get_context()
context = self.block.get_context()
assert context['transcripts_basic_tab_metadata']['video_url']['value'] == video_url
@@ -1388,7 +1388,7 @@ class TestEditorSavedMethod(BaseTestVideoXBlock):
"""
self.MODULESTORE = MODULESTORES[default_store] # pylint: disable=invalid-name
self.initialize_block(metadata=self.metadata)
item = self.store.get_item(self.item_descriptor.location)
item = self.store.get_item(self.block.location)
with open(self.file_path, "rb") as myfile: # lint-amnesty, pylint: disable=bad-option-value, open-builtin
save_to_store(myfile.read(), self.file_name, 'text/sjson', item.location)
item.sub = "3_yD_cEKoCk"
@@ -1408,7 +1408,7 @@ class TestEditorSavedMethod(BaseTestVideoXBlock):
"""
self.MODULESTORE = MODULESTORES[default_store]
self.initialize_block(metadata=self.metadata)
item = self.store.get_item(self.item_descriptor.location)
item = self.store.get_item(self.block.location)
with open(self.file_path, "rb") as myfile: # lint-amnesty, pylint: disable=bad-option-value, open-builtin
save_to_store(myfile.read(), self.file_name, 'text/sjson', item.location)
save_to_store(myfile.read(), 'subs_video.srt.sjson', 'text/sjson', item.location)
@@ -1433,7 +1433,7 @@ class TestEditorSavedMethod(BaseTestVideoXBlock):
'edx_video_id': unstripped_video_id
})
self.initialize_block(metadata=self.metadata)
item = self.store.get_item(self.item_descriptor.location)
item = self.store.get_item(self.block.location)
assert item.edx_video_id == unstripped_video_id
# Now, modifying and saving the video block should strip the video id.
@@ -1451,7 +1451,7 @@ class TestEditorSavedMethod(BaseTestVideoXBlock):
"""
self.MODULESTORE = MODULESTORES[default_store]
self.initialize_block(metadata=self.metadata)
item = self.store.get_item(self.item_descriptor.location)
item = self.store.get_item(self.block.location)
assert item.youtube_id_1_0 == '3_yD_cEKoCk'
# Now, modify `edx_video_id` and save should override `youtube_id_1_0`.
@@ -1493,7 +1493,7 @@ class TestVideoBlockStudentViewJson(BaseTestVideoXBlock, CacheIsolationTestCase)
)
self.transcript_url = "transcript_url"
self.initialize_block(data=sample_xml)
self.video = self.item_descriptor
self.video = self.block
self.video.runtime.handler_url = Mock(return_value=self.transcript_url)
def setup_val_video(self, associate_course_in_val=False):
@@ -1595,7 +1595,7 @@ class TestVideoBlockStudentViewJson(BaseTestVideoXBlock, CacheIsolationTestCase)
])
self.transcript_url = "transcript_url"
self.initialize_block(data=sample_xml)
self.video = self.item_descriptor
self.video = self.block
self.video.runtime.handler_url = Mock(return_value=self.transcript_url)
result = self.get_result()
self.verify_result_with_youtube_url(result)
@@ -1659,11 +1659,11 @@ class TestVideoBlockStudentViewJson(BaseTestVideoXBlock, CacheIsolationTestCase)
@ddt.ddt
class VideoBlockTest(TestCase, VideoBlockTestBase):
"""
Tests for video descriptor that requires access to django settings.
Tests for video block that requires access to django settings.
"""
def setUp(self):
super().setUp()
self.descriptor.runtime.handler_url = MagicMock()
self.block.runtime.handler_url = MagicMock()
self.temp_dir = mkdtemp()
file_system = OSFS(self.temp_dir)
self.file_system = file_system.makedir(EXPORT_IMPORT_COURSE_DIR, recreate=True)
@@ -1695,12 +1695,12 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
'template': 'tabs/metadata-edit-tab.html'
}
]
rendered_context = self.descriptor.get_context()
rendered_context = self.block.get_context()
self.assertListEqual(rendered_context['tabs'], correct_tabs)
# Assert that the Video ID field is present in basic tab metadata context.
assert rendered_context['transcripts_basic_tab_metadata']['edx_video_id'] ==\
self.descriptor.editable_metadata_fields['edx_video_id']
self.block.editable_metadata_fields['edx_video_id']
def test_export_val_data_with_internal(self):
"""
@@ -1712,11 +1712,11 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
combine(self.temp_dir, EXPORT_IMPORT_COURSE_DIR),
combine(EXPORT_IMPORT_STATIC_DIR, transcript_file_name)
)
self.descriptor.edx_video_id = 'test_edx_video_id'
self.block.edx_video_id = 'test_edx_video_id'
create_profile('mobile')
create_video({
'edx_video_id': self.descriptor.edx_video_id,
'edx_video_id': self.block.edx_video_id,
'client_video_id': 'test_client_video_id',
'duration': 111.0,
'status': 'dummy',
@@ -1728,7 +1728,7 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
}],
})
create_or_update_video_transcript(
video_id=self.descriptor.edx_video_id,
video_id=self.block.edx_video_id,
language_code=language_code,
metadata={
'provider': 'Cielo24',
@@ -1737,7 +1737,7 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
file_data=ContentFile(TRANSCRIPT_FILE_SRT_DATA)
)
actual = self.descriptor.definition_to_xml(resource_fs=self.file_system)
actual = self.block.definition_to_xml(resource_fs=self.file_system)
expected_str = """
<video youtube="1.00:3_yD_cEKoCk" url_name="SampleProblem" transcripts='{transcripts}'>
<video_asset client_video_id="test_client_video_id" duration="111.0" image="">
@@ -1763,7 +1763,7 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
# Also verify the content of created transcript file.
with open(expected_transcript_path) as transcript_path:
expected_transcript_content = File(transcript_path).read()
transcript = get_video_transcript_data(video_id=self.descriptor.edx_video_id, language_code=language_code)
transcript = get_video_transcript_data(video_id=self.block.edx_video_id, language_code=language_code)
assert transcript['content'].decode('utf-8') == expected_transcript_content
@ddt.data(
@@ -1775,13 +1775,13 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
"""
Tests new transcripts export for backward compatibility.
"""
self.descriptor.edx_video_id = 'test_video_id'
self.descriptor.sub = sub
self.block.edx_video_id = 'test_video_id'
self.block.sub = sub
# Setup VAL encode profile, video and transcripts
create_profile('mobile')
create_video({
'edx_video_id': self.descriptor.edx_video_id,
'edx_video_id': self.block.edx_video_id,
'client_video_id': 'test_client_video_id',
'duration': 111.0,
'status': 'dummy',
@@ -1795,21 +1795,21 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
for language in languages:
create_video_transcript(
video_id=self.descriptor.edx_video_id,
video_id=self.block.edx_video_id,
language_code=language,
file_format=Transcript.SRT,
content=ContentFile(TRANSCRIPT_FILE_SRT_DATA)
)
# Export the video block into xml
video_xml = self.descriptor.definition_to_xml(resource_fs=self.file_system)
video_xml = self.block.definition_to_xml(resource_fs=self.file_system)
# Assert `sub` and `transcripts` attribute in the xml
assert video_xml.get('sub') == expected_sub
expected_transcripts = {
language: "{edx_video_id}-{language}.srt".format(
edx_video_id=self.descriptor.edx_video_id,
edx_video_id=self.block.edx_video_id,
language=language
)
for language in languages
@@ -1824,15 +1824,15 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
)
with open(expected_transcript_path) as transcript_path:
expected_transcript_content = File(transcript_path).read()
transcript = get_video_transcript_data(video_id=self.descriptor.edx_video_id, language_code=language)
transcript = get_video_transcript_data(video_id=self.block.edx_video_id, language_code=language)
assert transcript['content'].decode('utf-8') == expected_transcript_content
def test_export_val_data_not_found(self):
"""
Tests that external video export works as expected.
"""
self.descriptor.edx_video_id = 'nonexistent'
actual = self.descriptor.definition_to_xml(resource_fs=self.file_system)
self.block.edx_video_id = 'nonexistent'
actual = self.block.definition_to_xml(resource_fs=self.file_system)
expected_str = """<video youtube="1.00:3_yD_cEKoCk" url_name="SampleProblem"/>"""
parser = etree.XMLParser(remove_blank_text=True)
expected = etree.XML(expected_str, parser=parser)
@@ -1845,7 +1845,7 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
"""
mock_get_video_ids_info.return_value = True, []
actual = self.descriptor.definition_to_xml(resource_fs=self.file_system)
actual = self.block.definition_to_xml(resource_fs=self.file_system)
expected_str = '<video youtube="1.00:3_yD_cEKoCk" url_name="SampleProblem"></video>'
parser = etree.XMLParser(remove_blank_text=True)
@@ -1883,7 +1883,7 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
# Create self.sub and self.transcripts transcript.
create_file_in_fs(
TRANSCRIPT_FILE_SRT_DATA,
subs_filename(sub_id, self.descriptor.transcript_language),
subs_filename(sub_id, self.block.transcript_language),
module_system.resources_fs,
EXPORT_IMPORT_STATIC_DIR
)
@@ -1913,7 +1913,7 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
xml_object = etree.fromstring(xml_data)
id_generator = Mock()
id_generator.target_course_id = "test_course_id"
video = self.descriptor.parse_xml(xml_object, module_system, None, id_generator)
video = self.block.parse_xml(xml_object, module_system, None, id_generator)
assert video.edx_video_id == 'test_edx_video_id'
video_data = get_video_info(video.edx_video_id)
@@ -1940,9 +1940,9 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
self.assertDictContainsSubset(
self.get_video_transcript_data(
edx_video_id,
language_code=self.descriptor.transcript_language
language_code=self.block.transcript_language
),
get_video_transcript(video.edx_video_id, self.descriptor.transcript_language)
get_video_transcript(video.edx_video_id, self.block.transcript_language)
)
# Verify that transcript from transcript field is imported.
@@ -1964,9 +1964,9 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
id_generator = Mock()
# Verify edx_video_id is empty before.
assert self.descriptor.edx_video_id == ''
assert self.block.edx_video_id == ''
video = self.descriptor.parse_xml(xml_object, module_system, None, id_generator)
video = self.block.parse_xml(xml_object, module_system, None, id_generator)
# Verify edx_video_id is populated after the import.
assert video.edx_video_id != ''
@@ -2012,9 +2012,9 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
)
# Verify edx_video_id is empty before.
assert self.descriptor.edx_video_id == ''
assert self.block.edx_video_id == ''
video = self.descriptor.parse_xml(xml_object, module_system, None, id_generator)
video = self.block.parse_xml(xml_object, module_system, None, id_generator)
# Verify edx_video_id is populated after the import.
assert video.edx_video_id != ''
@@ -2154,9 +2154,9 @@ class VideoBlockTest(TestCase, VideoBlockTestBase):
xml_object = etree.fromstring(xml_data)
# Verify edx_video_id is empty before import.
assert self.descriptor.edx_video_id == ''
assert self.block.edx_video_id == ''
video = self.descriptor.parse_xml(xml_object, module_system, None, id_generator)
video = self.block.parse_xml(xml_object, module_system, None, id_generator)
# Verify edx_video_id is not empty after import.
assert video.edx_video_id != ''
@@ -2215,12 +2215,12 @@ class TestVideoWithBumper(TestVideo): # pylint: disable=test-inherits-tests
"transcripts": {},
}
with override_settings(FEATURES=self.FEATURES):
assert bumper_utils.is_bumper_enabled(self.item_descriptor)
assert bumper_utils.is_bumper_enabled(self.block)
self.FEATURES.update({"ENABLE_VIDEO_BUMPER": False})
with override_settings(FEATURES=self.FEATURES):
assert not bumper_utils.is_bumper_enabled(self.item_descriptor)
assert not bumper_utils.is_bumper_enabled(self.block)
@patch('xmodule.video_block.bumper_utils.is_bumper_enabled')
@patch('xmodule.video_block.bumper_utils.get_bumper_settings')
@@ -2241,14 +2241,14 @@ class TestVideoWithBumper(TestVideo): # pylint: disable=test-inherits-tests
is_bumper_enabled.return_value = True
content = self.item_descriptor.render(STUDENT_VIEW).content
content = self.block.render(STUDENT_VIEW).content
sources = ['example.mp4', 'example.webm']
expected_context = {
'autoadvance_enabled': False,
'branding_info': None,
'license': None,
'bumper_metadata': json.dumps(OrderedDict({
'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'saveStateUrl': self.block.ajax_url + '/save_user_state',
'showCaptions': 'true',
'sources': ['http://test_bumper.mp4'],
'streams': '',
@@ -2271,11 +2271,11 @@ class TestVideoWithBumper(TestVideo): # pylint: disable=test-inherits-tests
'handout': None,
'hide_downloads': False,
'is_embed': False,
'id': self.item_descriptor.location.html_id(),
'id': self.block.location.html_id(),
'metadata': json.dumps(OrderedDict({
'autoAdvance': False,
'saveStateEnabled': True,
'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'saveStateUrl': self.block.ajax_url + '/save_user_state',
'autoplay': False,
'streams': '0.75:jNCf2gIqpeE,1.00:ZwkTiUPN0mg,1.25:rsq9auxASqI,1.50:kMyNdzVHHgg',
'sources': sources,
@@ -2316,7 +2316,7 @@ class TestVideoWithBumper(TestVideo): # pylint: disable=test-inherits-tests
}))
}
mako_service = self.item_descriptor.runtime.service(self.item_descriptor, 'mako')
mako_service = self.block.runtime.service(self.block, 'mako')
expected_content = mako_service.render_template('video.html', expected_context)
assert get_context_dict_from_string(content) == get_context_dict_from_string(expected_content)
@@ -2348,12 +2348,12 @@ class TestAutoAdvanceVideo(TestVideo): # lint-amnesty, pylint: disable=test-inh
'handout': None,
'hide_downloads': False,
'is_embed': False,
'id': self.item_descriptor.location.html_id(),
'id': self.block.location.html_id(),
'bumper_metadata': 'null',
'metadata': json.dumps(OrderedDict({
'autoAdvance': autoadvance_flag,
'saveStateEnabled': True,
'saveStateUrl': self.item_descriptor.ajax_url + '/save_user_state',
'saveStateUrl': self.block.ajax_url + '/save_user_state',
'autoplay': False,
'streams': '0.75:jNCf2gIqpeE,1.00:ZwkTiUPN0mg,1.25:rsq9auxASqI,1.50:kMyNdzVHHgg',
'sources': ['example.mp4', 'example.webm'],
@@ -2372,11 +2372,11 @@ class TestAutoAdvanceVideo(TestVideo): # lint-amnesty, pylint: disable=test-inh
'ytTestTimeout': 1500,
'ytApiUrl': 'https://www.youtube.com/iframe_api',
'lmsRootURL': settings.LMS_ROOT_URL,
'transcriptTranslationUrl': self.item_descriptor.runtime.handler_url(
self.item_descriptor, 'transcript', 'translation/__lang__'
'transcriptTranslationUrl': self.block.runtime.handler_url(
self.block, 'transcript', 'translation/__lang__'
).rstrip('/?'),
'transcriptAvailableTranslationsUrl': self.item_descriptor.runtime.handler_url(
self.item_descriptor, 'transcript', 'available_translations'
'transcriptAvailableTranslationsUrl': self.block.runtime.handler_url(
self.block, 'transcript', 'available_translations'
).rstrip('/?'),
'autohideHtml5': False,
'recordedYoutubeIsAvailable': True,
@@ -2404,14 +2404,14 @@ class TestAutoAdvanceVideo(TestVideo): # lint-amnesty, pylint: disable=test-inh
"""
with override_settings(FEATURES=self.FEATURES):
content = self.item_descriptor.render(STUDENT_VIEW).content
content = self.block.render(STUDENT_VIEW).content
expected_context = self.prepare_expected_context(
autoadvanceenabled_flag=autoadvanceenabled_must_be,
autoadvance_flag=autoadvance_must_be,
)
mako_service = self.item_descriptor.runtime.service(self.item_descriptor, 'mako')
mako_service = self.block.runtime.service(self.block, 'mako')
with override_settings(FEATURES=self.FEATURES):
expected_content = mako_service.render_template('video.html', expected_context)
@@ -2424,11 +2424,11 @@ class TestAutoAdvanceVideo(TestVideo): # lint-amnesty, pylint: disable=test-inh
Based on test code for video_bumper setting.
"""
# This first render is done to initialize the instance
self.item_descriptor.render(STUDENT_VIEW)
self.item_descriptor.video_auto_advance = new_value
self.item_descriptor._reset_dirty_field(self.item_descriptor.fields['video_auto_advance']) # pylint: disable=protected-access
self.block.render(STUDENT_VIEW)
self.block.video_auto_advance = new_value
self.block._reset_dirty_field(self.block.fields['video_auto_advance']) # pylint: disable=protected-access
# After this step, render() should see the new value
# e.g. use self.item_descriptor.render(STUDENT_VIEW).content
# e.g. use self.block.render(STUDENT_VIEW).content
@ddt.data(
(False, False),

View File

@@ -1936,7 +1936,7 @@ class ProgressPageShowCorrectnessTests(ProgressPageBaseTests):
Submit the given score to the problem on behalf of the user
"""
# Get the block for the problem, as viewed by the user
field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
field_data_cache = FieldDataCache.cache_for_block_descendents(
self.course.id,
self.user,
self.course,

View File

@@ -18,15 +18,6 @@ class TestWordCloud(BaseTestXmodule):
"""Integration test for Word Cloud Block."""
CATEGORY = "word_cloud"
def _get_resource_url(self, item):
"""
Creates a resource URL for a given asset that is compatible with this old XModule testing stuff.
"""
display_name = self.item_descriptor.display_name.replace(' ', '_')
return "resource/i4x://{}/{}/word_cloud/{}/{}".format(
self.course.id.org, self.course.id.course, display_name, item
)
def _get_users_state(self):
"""Return current state for each user:
@@ -227,13 +218,13 @@ class TestWordCloud(BaseTestXmodule):
"""
Make sure that all parameters extracted correctly from xml.
"""
fragment = self.runtime.render(self.item_descriptor, STUDENT_VIEW)
fragment = self.runtime.render(self.block, STUDENT_VIEW)
expected_context = {
'ajax_url': self.item_descriptor.ajax_url,
'display_name': self.item_descriptor.display_name,
'instructions': self.item_descriptor.instructions,
'element_class': self.item_descriptor.location.block_type,
'element_id': self.item_descriptor.location.html_id(),
'ajax_url': self.block.ajax_url,
'display_name': self.block.display_name,
'instructions': self.block.instructions,
'element_class': self.block.location.block_type,
'element_id': self.block.location.html_id(),
'num_inputs': 5, # default value
'submitted': False, # default value,
}

View File

@@ -63,32 +63,32 @@ class PageLoaderTestCase(LoginEnrollmentTestCase):
self.fail('Could not retrieve any items from course')
# Try to load each item in the course
for descriptor in items:
for block in items:
if descriptor.location.category == 'about':
if block.location.category == 'about':
self._assert_loads('about_course',
{'course_id': str(course_key)},
descriptor)
block)
elif descriptor.location.category == 'static_tab':
elif block.location.category == 'static_tab':
kwargs = {'course_id': str(course_key),
'tab_slug': descriptor.location.name}
self._assert_loads('static_tab', kwargs, descriptor)
'tab_slug': block.location.name}
self._assert_loads('static_tab', kwargs, block)
elif descriptor.location.category == 'course_info':
elif block.location.category == 'course_info':
self._assert_loads('info', {'course_id': str(course_key)},
descriptor)
block)
else:
kwargs = {'course_id': str(course_key),
'location': str(descriptor.location)}
'location': str(block.location)}
self._assert_loads('jump_to', kwargs, descriptor,
self._assert_loads('jump_to', kwargs, block,
expect_redirect=True,
check_content=True)
def _assert_loads(self, django_url, kwargs, descriptor,
def _assert_loads(self, django_url, kwargs, block,
expect_redirect=False,
check_content=False):
"""
@@ -103,14 +103,14 @@ class PageLoaderTestCase(LoginEnrollmentTestCase):
if response.status_code != 200:
self.fail('Status %d for page %s' %
(response.status_code, descriptor.location))
(response.status_code, block.location))
if expect_redirect:
assert response.redirect_chain[0][1] == 302
if check_content:
self.assertNotContains(response, "this module is temporarily unavailable")
assert not isinstance(descriptor, ErrorBlock)
assert not isinstance(block, ErrorBlock)
class TestMongoCoursesLoad(ModuleStoreTestCase, PageLoaderTestCase):
@@ -156,7 +156,7 @@ class TestLmsFieldData(TestCase):
# Verify that if an LmsFieldData is passed into LmsFieldData as the
# authored_data, that it doesn't produced a nested field data.
#
# This fixes a bug where re-use of the same descriptor for many modules
# This fixes a bug where re-use of the same block for many modules
# would cause more and more nesting, until the recursion depth would be
# reached on any attribute access

View File

@@ -107,7 +107,7 @@ class DjangoXBlockUserStateClient(XBlockUserStateClient):
def _nr_attribute_name(self, function_name, stat_name, block_type=None):
"""
Return an attribute name (string) representing the provided descriptors.
Return an attribute name (string) representing the provided blocks.
The return value is directly usable for New Relic custom attributes.
"""
if block_type is None:

View File

@@ -349,7 +349,7 @@ class CoursewareIndex(View):
Prefetches all descendant data for the requested section and
sets up the runtime, which binds the request user to the section.
"""
self.field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
self.field_data_cache = FieldDataCache.cache_for_block_descendents(
self.course_key,
self.effective_user,
self.course,
@@ -374,7 +374,7 @@ class CoursewareIndex(View):
"""
# Pre-fetch all descendant data
self.section = modulestore().get_item(self.section.location, depth=None, lazy=False)
self.field_data_cache.add_descriptor_descendents(self.section, depth=None)
self.field_data_cache.add_block_descendents(self.section, depth=None)
# Bind section to user
self.section = get_block_for_descriptor(
@@ -585,11 +585,11 @@ def save_positions_recursively_up(user, request, field_data_cache, xmodule, cour
parent_location = modulestore().get_parent_location(current_block.location)
parent = None
if parent_location:
parent_descriptor = modulestore().get_item(parent_location)
parent_block = modulestore().get_item(parent_location)
parent = get_block_for_descriptor(
user,
request,
parent_descriptor,
parent_block,
field_data_cache,
current_block.location.course_key,
course=course

View File

@@ -1262,7 +1262,7 @@ def get_static_tab_fragment(request, course, tab):
tab.type,
tab.url_slug,
)
field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
field_data_cache = FieldDataCache.cache_for_block_descendents(
course.id, request.user, modulestore().get_item(loc), depth=0
)
tab_block = get_block(
@@ -1309,23 +1309,23 @@ def get_course_lti_endpoints(request, course_id):
anonymous_user = AnonymousUser()
anonymous_user.known = False # make these "noauth" requests like block_render.handle_xblock_callback_noauth
lti_descriptors = modulestore().get_items(course.id, qualifiers={'category': 'lti'})
lti_descriptors.extend(modulestore().get_items(course.id, qualifiers={'category': 'lti_consumer'}))
lti_blocks = modulestore().get_items(course.id, qualifiers={'category': 'lti'})
lti_blocks.extend(modulestore().get_items(course.id, qualifiers={'category': 'lti_consumer'}))
lti_noauth_blocks = [
get_block_for_descriptor(
anonymous_user,
request,
descriptor,
FieldDataCache.cache_for_descriptor_descendents(
block,
FieldDataCache.cache_for_block_descendents(
course_key,
anonymous_user,
descriptor
block
),
course_key,
course=course
)
for descriptor in lti_descriptors
for block in lti_blocks
]
endpoints = [