refactor: convert course_module term to course_block

This commit is contained in:
0x29a
2022-10-27 03:24:30 +02:00
committed by Piotr Surowiec
parent d3fee38a37
commit 83396ffb07
62 changed files with 335 additions and 335 deletions

View File

@@ -111,9 +111,9 @@ class AdvancedCourseSettingsView(DeveloperErrorViewMixin, APIView):
course_key = CourseKey.from_string(course_id)
if not has_studio_read_access(request.user, course_key):
self.permission_denied(request)
course_module = modulestore().get_course(course_key)
course_block = modulestore().get_course(course_key)
return Response(CourseMetadata.fetch_all(
course_module,
course_block,
filter_fields=filter_query_data.cleaned_data['filter_fields'],
))
@@ -174,6 +174,6 @@ class AdvancedCourseSettingsView(DeveloperErrorViewMixin, APIView):
course_key = CourseKey.from_string(course_id)
if not has_studio_write_access(request.user, course_key):
self.permission_denied(request)
course_module = modulestore().get_course(course_key)
updated_data = update_course_advanced_settings(course_module, request.data, request.user)
course_block = modulestore().get_course(course_key)
updated_data = update_course_advanced_settings(course_block, request.data, request.user)
return Response(updated_data)

View File

@@ -81,8 +81,8 @@ class CourseTabListView(DeveloperErrorViewMixin, APIView):
if not has_studio_read_access(request.user, course_key):
self.permission_denied(request)
course_module = modulestore().get_course(course_key)
tabs_to_render = get_course_tabs(course_module, request.user)
course_block = modulestore().get_course(course_key)
tabs_to_render = get_course_tabs(course_block, request.user)
return Response(CourseTabSerializer(tabs_to_render, many=True).data)
@@ -147,12 +147,12 @@ class CourseTabSettingsView(DeveloperErrorViewMixin, APIView):
tab_id_locator = TabIDLocatorSerializer(data=request.query_params)
tab_id_locator.is_valid(raise_exception=True)
course_module = modulestore().get_course(course_key)
course_block = modulestore().get_course(course_key)
serializer = CourseTabUpdateSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
edit_tab_handler(
course_module,
course_block,
{
"tab_id_locator": tab_id_locator.data,
**serializer.data,
@@ -216,11 +216,11 @@ class CourseTabReorderView(DeveloperErrorViewMixin, APIView):
if not has_studio_write_access(request.user, course_key):
self.permission_denied(request)
course_module = modulestore().get_course(course_key)
course_block = modulestore().get_course(course_key)
tab_id_locators = TabIDLocatorSerializer(data=request.data, many=True)
tab_id_locators.is_valid(raise_exception=True)
reorder_tabs_handler(
course_module,
course_block,
tab_id_locators.validated_data,
request.user,
)

View File

@@ -77,7 +77,7 @@ class ProctoringExamSettingsTestMixin():
response = self.make_request()
assert response.status_code == status.HTTP_403_FORBIDDEN
def test_404_no_course_module(self):
def test_404_no_course_block(self):
course_id = 'course-v1:edX+ToyX_Nonexistent_Course+Toy_Course'
self.client.login(username=self.global_staff, password=self.password)
response = self.make_request(course_id=course_id)

View File

@@ -92,8 +92,8 @@ class ProctoredExamSettingsView(APIView):
def get(self, request, course_id):
""" GET handler """
with modulestore().bulk_operations(CourseKey.from_string(course_id)):
course_module = self._get_and_validate_course_access(request.user, course_id)
course_metadata = CourseMetadata().fetch_all(course_module)
course_block = self._get_and_validate_course_access(request.user, course_id)
course_metadata = CourseMetadata().fetch_all(course_block)
proctored_exam_settings = self._get_proctored_exam_setting_values(course_metadata)
data = {}
@@ -123,8 +123,8 @@ class ProctoredExamSettingsView(APIView):
return Response(status=status.HTTP_403_FORBIDDEN)
with modulestore().bulk_operations(CourseKey.from_string(course_id)):
course_module = self._get_and_validate_course_access(request.user, course_id)
course_metadata = CourseMetadata().fetch_all(course_module)
course_block = self._get_and_validate_course_access(request.user, course_id)
course_metadata = CourseMetadata().fetch_all(course_block)
models_to_update = {}
for setting_key, value in exam_config.data.items():
@@ -133,9 +133,9 @@ class ProctoredExamSettingsView(APIView):
models_to_update[setting_key] = copy.deepcopy(model)
models_to_update[setting_key]['value'] = value
# validate data formats and update the course module object
# validate data formats and update the course block object
is_valid, errors, updated_data = CourseMetadata.validate_and_update_from_json(
course_module,
course_block,
models_to_update,
user=request.user,
)
@@ -148,7 +148,7 @@ class ProctoredExamSettingsView(APIView):
)
# save to mongo
modulestore().update_item(course_module, request.user.id)
modulestore().update_item(course_block, request.user.id)
# merge updated settings with all existing settings.
# do this because fields that could not be modified are excluded from the result
@@ -171,14 +171,14 @@ class ProctoredExamSettingsView(APIView):
"""
Check if course_id exists and is accessible by the user.
Returns a course_module object
Returns a course_block object
"""
course_key = CourseKey.from_string(course_id)
course_module = get_course_and_check_access(course_key, user)
course_block = get_course_and_check_access(course_key, user)
if not course_module:
if not course_block:
raise NotFound(
f'Course with course_id {course_id} does not exist.'
)
return course_module
return course_block

View File

@@ -167,7 +167,7 @@ def rerun_course(source_course_key_string, destination_course_key_string, user_i
# cleanup any remnants of the course
modulestore().delete_course(destination_course_key, user_id)
except ItemNotFoundError:
# it's possible there was an error even before the course module was created
# it's possible there was an error even before the course block was created
pass
return "exception: " + str(exc)
@@ -335,13 +335,13 @@ def export_olx(self, user_id, course_key_string, language):
return
def create_export_tarball(course_module, course_key, context, status=None):
def create_export_tarball(course_block, course_key, context, status=None):
"""
Generates the export tarball, or returns None if there was an error.
Updates the context with any error information if applicable.
"""
name = course_module.url_name
name = course_block.url_name
export_file = NamedTemporaryFile(prefix=name + '.', suffix=".tar.gz") # lint-amnesty, pylint: disable=consider-using-with
root_dir = path(mkdtemp())
@@ -349,7 +349,7 @@ def create_export_tarball(course_module, course_key, context, status=None):
if isinstance(course_key, LibraryLocator):
export_library_to_xml(modulestore(), contentstore(), course_key, root_dir, name)
else:
export_course_to_xml(modulestore(), contentstore(), course_module.id, root_dir, name)
export_course_to_xml(modulestore(), contentstore(), course_block.id, root_dir, name)
if status:
status.set_state('Compressing')

View File

@@ -348,7 +348,7 @@ class ImportRequiredTestCases(ContentStoreTestCase):
# check for policy.json
self.assertTrue(filesystem.exists('policy.json'))
# compare what's on disk to what we have in the course module
# compare what's on disk to what we have in the course block
with filesystem.open('policy.json', 'r') as course_policy:
on_disk = loads(course_policy.read())
self.assertIn('course/2012_Fall', on_disk)
@@ -1195,8 +1195,8 @@ class ContentStoreTest(ContentStoreTestCase):
"""Test new course creation and verify default language"""
test_course_data = self.assert_created_course()
course_id = _get_course_id(self.store, test_course_data)
course_module = self.store.get_course(course_id)
self.assertEqual(course_module.language, 'hr')
course_block = self.store.get_course(course_id)
self.assertEqual(course_block.language, 'hr')
def test_create_course_with_dots(self):
"""Test new course creation with dots in the name"""
@@ -1617,12 +1617,12 @@ class ContentStoreTest(ContentStoreTestCase):
#
# first check PDF textbooks, to make sure the url paths got updated
course_module = self.store.get_course(target_id)
course_block = self.store.get_course(target_id)
self.assertEqual(len(course_module.pdf_textbooks), 1)
self.assertEqual(len(course_module.pdf_textbooks[0]["chapters"]), 2)
self.assertEqual(course_module.pdf_textbooks[0]["chapters"][0]["url"], '/static/Chapter1.pdf')
self.assertEqual(course_module.pdf_textbooks[0]["chapters"][1]["url"], '/static/Chapter2.pdf')
self.assertEqual(len(course_block.pdf_textbooks), 1)
self.assertEqual(len(course_block.pdf_textbooks[0]["chapters"]), 2)
self.assertEqual(course_block.pdf_textbooks[0]["chapters"][0]["url"], '/static/Chapter1.pdf')
self.assertEqual(course_block.pdf_textbooks[0]["chapters"][1]["url"], '/static/Chapter2.pdf')
def test_import_into_new_course_id_wiki_slug_renamespacing(self):
# If reimporting into the same course do not change the wiki_slug.
@@ -1634,14 +1634,14 @@ class ContentStoreTest(ContentStoreTestCase):
'run': target_id.run
}
_create_course(self, target_id, course_data)
course_module = self.store.get_course(target_id)
course_module.wiki_slug = 'toy'
course_module.save()
course_block = self.store.get_course(target_id)
course_block.wiki_slug = 'toy'
course_block.save()
# Import a course with wiki_slug == location.course
import_course_from_xml(self.store, self.user.id, TEST_DATA_DIR, ['toy'], target_id=target_id)
course_module = self.store.get_course(target_id)
self.assertEqual(course_module.wiki_slug, 'toy')
course_block = self.store.get_course(target_id)
self.assertEqual(course_block.wiki_slug, 'toy')
# But change the wiki_slug if it is a different course.
target_id = self.store.make_course_key('MITx', '111', '2013_Spring')
@@ -1655,13 +1655,13 @@ class ContentStoreTest(ContentStoreTestCase):
# Import a course with wiki_slug == location.course
import_course_from_xml(self.store, self.user.id, TEST_DATA_DIR, ['toy'], target_id=target_id)
course_module = self.store.get_course(target_id)
self.assertEqual(course_module.wiki_slug, 'MITx.111.2013_Spring')
course_block = self.store.get_course(target_id)
self.assertEqual(course_block.wiki_slug, 'MITx.111.2013_Spring')
# Now try importing a course with wiki_slug == '{0}.{1}.{2}'.format(location.org, location.course, location.run)
import_course_from_xml(self.store, self.user.id, TEST_DATA_DIR, ['two_toys'], target_id=target_id)
course_module = self.store.get_course(target_id)
self.assertEqual(course_module.wiki_slug, 'MITx.111.2013_Spring')
course_block = self.store.get_course(target_id)
self.assertEqual(course_block.wiki_slug, 'MITx.111.2013_Spring')
def test_import_metadata_with_attempts_empty_string(self):
import_course_from_xml(self.store, self.user.id, TEST_DATA_DIR, ['simple'], create_if_not_present=True)
@@ -1797,8 +1797,8 @@ class ContentStoreTest(ContentStoreTestCase):
course_key = _get_course_id(self.store, self.course_data)
_create_course(self, course_key, self.course_data)
course_module = self.store.get_course(course_key)
self.assertEqual(course_module.wiki_slug, 'MITx.111.2013_Spring')
course_block = self.store.get_course(course_key)
self.assertEqual(course_block.wiki_slug, 'MITx.111.2013_Spring')
def test_course_handler_with_invalid_course_key_string(self):
"""Test viewing the course overview page with invalid course id"""

View File

@@ -850,7 +850,7 @@ class TestLibrarySearchIndexer(MixedWithOptionsTestCase):
class GroupConfigurationSearchSplit(CourseTestCase, MixedWithOptionsTestCase):
"""
Tests indexing of content groups on course modules using split modulestore.
Tests indexing of content groups on course blocks using split modulestore.
"""
CREATE_USER = True
INDEX_NAME = CoursewareSearchIndexer.INDEX_NAME

View File

@@ -33,7 +33,7 @@ class TestExportGit(CourseTestCase):
Setup test course, user, and url.
"""
super().setUp()
self.course_module = modulestore().get_course(self.course.id)
self.course_block = modulestore().get_course(self.course.id)
self.test_url = reverse_course_url('export_git', self.course.id)
def make_bare_repo_with_course(self, repo_name):
@@ -55,8 +55,8 @@ class TestExportGit(CourseTestCase):
subprocess.check_output(['git', '--bare', 'init', ], cwd=bare_repo_dir)
self.populate_course()
self.course_module.giturl = f'file://{bare_repo_dir}'
modulestore().update_item(self.course_module, self.user.id)
self.course_block.giturl = f'file://{bare_repo_dir}'
modulestore().update_item(self.course_block, self.user.id)
def test_giturl_missing(self):
"""
@@ -81,8 +81,8 @@ class TestExportGit(CourseTestCase):
"""
Test failed course export response.
"""
self.course_module.giturl = 'foobar'
modulestore().update_item(self.course_module, self.user.id)
self.course_block.giturl = 'foobar'
modulestore().update_item(self.course_block, self.user.id)
response = self.client.get(f'{self.test_url}?action=push')
self.assertContains(response, 'Export Failed:')
@@ -91,8 +91,8 @@ class TestExportGit(CourseTestCase):
"""
Regression test for making sure errors are properly stringified
"""
self.course_module.giturl = 'foobar'
modulestore().update_item(self.course_module, self.user.id)
self.course_block.giturl = 'foobar'
modulestore().update_item(self.course_block, self.user.id)
response = self.client.get(f'{self.test_url}?action=push')
self.assertNotContains(response, 'django.utils.functional.__proxy__')
@@ -123,11 +123,11 @@ class TestExportGit(CourseTestCase):
repo_name = 'dirty_repo1'
self.make_bare_repo_with_course(repo_name)
git_export_utils.export_to_git(self.course.id,
self.course_module.giturl, self.user)
self.course_block.giturl, self.user)
# Make arbitrary change to course to make diff
self.course_module.matlab_api_key = 'something'
modulestore().update_item(self.course_module, self.user.id)
self.course_block.matlab_api_key = 'something'
modulestore().update_item(self.course_block, self.user.id)
# Touch a file in the directory, export again, and make sure
# the test file is gone
repo_dir = os.path.join(
@@ -138,5 +138,5 @@ class TestExportGit(CourseTestCase):
open(test_file, 'a').close()
self.assertTrue(os.path.isfile(test_file))
git_export_utils.export_to_git(self.course.id,
self.course_module.giturl, self.user)
self.course_block.giturl, self.user)
self.assertFalse(os.path.isfile(test_file))

View File

@@ -102,11 +102,11 @@ def _asset_index(request, course_key):
Supports start (0-based index into the list of assets) and max query parameters.
'''
course_module = modulestore().get_course(course_key)
course_block = modulestore().get_course(course_key)
return render_to_response('asset_index.html', {
'language_code': request.LANGUAGE_CODE,
'context_course': course_module,
'context_course': course_block,
'max_file_size_in_mbs': settings.MAX_ASSET_UPLOAD_FILE_SIZE_IN_MB,
'chunk_size_in_mbs': settings.UPLOAD_CHUNK_SIZE_IN_MB,
'max_file_size_redirect_url': settings.MAX_ASSET_UPLOAD_FILE_SIZE_URL,

View File

@@ -63,12 +63,12 @@ LOGGER = logging.getLogger(__name__)
def _get_course_and_check_access(course_key, user, depth=0):
"""
Internal method used to calculate and return the locator and
course module for the view functions in this file.
course block for the view functions in this file.
"""
if not has_studio_write_access(user, course_key):
raise PermissionDenied()
course_module = modulestore().get_course(course_key, depth=depth)
return course_module
course_block = modulestore().get_course(course_key, depth=depth)
return course_block
def _delete_asset(course_key, asset_key_string):

View File

@@ -27,9 +27,9 @@ def checklists_handler(request, course_key_string=None):
if not has_course_author_access(request.user, course_key):
raise PermissionDenied()
course_module = modulestore().get_course(course_key)
course_block = modulestore().get_course(course_key)
return render_to_response('checklists.html', {
'language_code': request.LANGUAGE_CODE,
'context_course': course_module,
'mfe_proctored_exam_settings_url': get_proctored_exam_settings_url(course_module.id),
'context_course': course_block,
'mfe_proctored_exam_settings_url': get_proctored_exam_settings_url(course_block.id),
})

View File

@@ -149,13 +149,13 @@ class AccessListFallback(Exception):
def get_course_and_check_access(course_key, user, depth=0):
"""
Function used to calculate and return the locator and course module
Function used to calculate and return the locator and course block
for the view functions in this file.
"""
if not has_studio_read_access(user, course_key):
raise PermissionDenied()
course_module = modulestore().get_course(course_key, depth=depth)
return course_module
course_block = modulestore().get_course(course_key, depth=depth)
return course_block
def reindex_course_and_check_access(course_key, user):
@@ -285,8 +285,8 @@ def course_handler(request, course_key_string=None):
if request.method == 'GET':
course_key = CourseKey.from_string(course_key_string)
with modulestore().bulk_operations(course_key):
course_module = get_course_and_check_access(course_key, request.user, depth=None)
return JsonResponse(_course_outline_json(request, course_module))
course_block = get_course_and_check_access(course_key, request.user, depth=None)
return JsonResponse(_course_outline_json(request, course_block))
elif request.method == 'POST': # not sure if this is only post. If one will have ids, it goes after access
return _create_or_rerun_course(request)
elif not has_studio_write_access(request.user, CourseKey.from_string(course_key_string)):
@@ -322,11 +322,11 @@ def course_rerun_handler(request, course_key_string):
raise PermissionDenied()
course_key = CourseKey.from_string(course_key_string)
with modulestore().bulk_operations(course_key):
course_module = get_course_and_check_access(course_key, request.user, depth=3)
course_block = get_course_and_check_access(course_key, request.user, depth=3)
if request.method == 'GET':
return render_to_response('course-create-rerun.html', {
'source_course_key': course_key,
'display_name': course_module.display_name,
'display_name': course_block.display_name,
'user': request.user,
'course_creator_status': _get_course_creator_status(request.user),
'allow_unicode_course_id': settings.FEATURES.get('ALLOW_UNICODE_COURSE_ID', False)
@@ -362,16 +362,16 @@ def course_search_index_handler(request, course_key_string):
}), content_type=content_type, status=200)
def _course_outline_json(request, course_module):
def _course_outline_json(request, course_block):
"""
Returns a JSON representation of the course module and recursively all of its children.
Returns a JSON representation of the course block and recursively all of its children.
"""
is_concise = request.GET.get('format') == 'concise'
include_children_predicate = lambda xblock: not xblock.category == 'vertical'
if is_concise:
include_children_predicate = lambda xblock: xblock.has_children
return create_xblock_info(
course_module,
course_block,
include_child_info=True,
course_outline=False if is_concise else True, # lint-amnesty, pylint: disable=simplifiable-if-expression
include_children_predicate=include_children_predicate,
@@ -640,12 +640,12 @@ def _get_rerun_link_for_item(course_key):
return reverse_course_url('course_rerun_handler', course_key)
def _deprecated_blocks_info(course_module, deprecated_block_types):
def _deprecated_blocks_info(course_block, deprecated_block_types):
"""
Returns deprecation information about `deprecated_block_types`
Arguments:
course_module (CourseBlock): course object
course_block (CourseBlock): course object
deprecated_block_types (list): list of deprecated blocks types
Returns:
@@ -656,14 +656,14 @@ def _deprecated_blocks_info(course_module, deprecated_block_types):
"""
data = {
'deprecated_enabled_block_types': [
block_type for block_type in course_module.advanced_modules if block_type in deprecated_block_types
block_type for block_type in course_block.advanced_modules if block_type in deprecated_block_types
],
'blocks': [],
'advance_settings_url': reverse_course_url('advanced_settings_handler', course_module.id)
'advance_settings_url': reverse_course_url('advanced_settings_handler', course_block.id)
}
deprecated_blocks = modulestore().get_items(
course_module.id,
course_block.id,
qualifiers={
'category': re.compile('^' + '$|^'.join(deprecated_block_types) + '$')
}
@@ -689,21 +689,21 @@ def course_index(request, course_key):
# A depth of None implies the whole course. The course outline needs this in order to compute has_changes.
# A unit may not have a draft version, but one of its components could, and hence the unit itself has changes.
with modulestore().bulk_operations(course_key):
course_module = get_course_and_check_access(course_key, request.user, depth=None)
if not course_module:
course_block = get_course_and_check_access(course_key, request.user, depth=None)
if not course_block:
raise Http404
lms_link = get_lms_link_for_item(course_module.location)
lms_link = get_lms_link_for_item(course_block.location)
reindex_link = None
if settings.FEATURES.get('ENABLE_COURSEWARE_INDEX', False):
if GlobalStaff().has_user(request.user):
reindex_link = f"/course/{str(course_key)}/search_reindex"
sections = course_module.get_children()
course_structure = _course_outline_json(request, course_module)
sections = course_block.get_children()
course_structure = _course_outline_json(request, course_block)
locator_to_show = request.GET.get('show', None)
course_release_date = (
get_default_time_display(course_module.start)
if course_module.start != DEFAULT_START_DATE
get_default_time_display(course_block.start)
if course_block.start != DEFAULT_START_DATE
else _("Set Date")
)
@@ -715,16 +715,16 @@ def course_index(request, course_key):
current_action = None
deprecated_block_names = [block.name for block in deprecated_xblocks()]
deprecated_blocks_info = _deprecated_blocks_info(course_module, deprecated_block_names)
deprecated_blocks_info = _deprecated_blocks_info(course_block, deprecated_block_names)
frontend_app_publisher_url = configuration_helpers.get_value_for_org(
course_module.location.org,
course_block.location.org,
'FRONTEND_APP_PUBLISHER_URL',
settings.FEATURES.get('FRONTEND_APP_PUBLISHER_URL', False)
)
# gather any errors in the currently stored proctoring settings.
advanced_dict = CourseMetadata.fetch(course_module)
proctoring_errors = CourseMetadata.validate_proctoring_settings(course_module, advanced_dict, request.user)
advanced_dict = CourseMetadata.fetch(course_block)
proctoring_errors = CourseMetadata.validate_proctoring_settings(course_block, advanced_dict, request.user)
configuration = DiscussionsConfiguration.get(course_key)
provider = configuration.provider_type
@@ -733,7 +733,7 @@ def course_index(request, course_key):
return render_to_response('course_outline.html', {
'language_code': request.LANGUAGE_CODE,
'context_course': course_module,
'context_course': course_block,
'lms_link': lms_link,
'sections': sections,
'course_structure': course_structure,
@@ -751,8 +751,8 @@ def course_index(request, course_key):
},
) if current_action else None,
'frontend_app_publisher_url': frontend_app_publisher_url,
'mfe_proctored_exam_settings_url': get_proctored_exam_settings_url(course_module.id),
'advance_settings_url': reverse_course_url('advanced_settings_handler', course_module.id),
'mfe_proctored_exam_settings_url': get_proctored_exam_settings_url(course_block.id),
'advance_settings_url': reverse_course_url('advanced_settings_handler', course_block.id),
'proctoring_errors': proctoring_errors,
})
@@ -1068,17 +1068,17 @@ def course_info_handler(request, course_key_string):
raise Http404 # lint-amnesty, pylint: disable=raise-missing-from
with modulestore().bulk_operations(course_key):
course_module = get_course_and_check_access(course_key, request.user)
if not course_module:
course_block = get_course_and_check_access(course_key, request.user)
if not course_block:
raise Http404
if 'text/html' in request.META.get('HTTP_ACCEPT', 'text/html'):
return render_to_response(
'course_info.html',
{
'context_course': course_module,
'context_course': course_block,
'updates_url': reverse_course_url('course_info_update_handler', course_key),
'handouts_locator': course_key.make_usage_key('course_info', 'handouts'),
'base_asset_url': StaticContent.get_base_url_path_for_course_assets(course_module.id),
'base_asset_url': StaticContent.get_base_url_path_for_course_assets(course_block.id),
}
)
else:
@@ -1153,24 +1153,24 @@ def settings_handler(request, course_key_string): # lint-amnesty, pylint: disab
course_key = CourseKey.from_string(course_key_string)
credit_eligibility_enabled = settings.FEATURES.get('ENABLE_CREDIT_ELIGIBILITY', False)
with modulestore().bulk_operations(course_key):
course_module = get_course_and_check_access(course_key, request.user)
course_block = get_course_and_check_access(course_key, request.user)
if 'text/html' in request.META.get('HTTP_ACCEPT', '') and request.method == 'GET':
upload_asset_url = reverse_course_url('assets_handler', course_key)
# see if the ORG of this course can be attributed to a defined configuration . In that case, the
# course about page should be editable in Studio
publisher_enabled = configuration_helpers.get_value_for_org(
course_module.location.org,
course_block.location.org,
'ENABLE_PUBLISHER',
settings.FEATURES.get('ENABLE_PUBLISHER', False)
)
marketing_enabled = configuration_helpers.get_value_for_org(
course_module.location.org,
course_block.location.org,
'ENABLE_MKTG_SITE',
settings.FEATURES.get('ENABLE_MKTG_SITE', False)
)
enable_extended_course_details = configuration_helpers.get_value_for_org(
course_module.location.org,
course_block.location.org,
'ENABLE_EXTENDED_COURSE_DETAILS',
settings.FEATURES.get('ENABLE_EXTENDED_COURSE_DETAILS', False)
)
@@ -1178,7 +1178,7 @@ def settings_handler(request, course_key_string): # lint-amnesty, pylint: disab
about_page_editable = not publisher_enabled
enrollment_end_editable = GlobalStaff().has_user(request.user) or not publisher_enabled
short_description_editable = configuration_helpers.get_value_for_org(
course_module.location.org,
course_block.location.org,
'EDITABLE_SHORT_DESCRIPTION',
settings.FEATURES.get('EDITABLE_SHORT_DESCRIPTION', True)
)
@@ -1188,12 +1188,12 @@ def settings_handler(request, course_key_string): # lint-amnesty, pylint: disab
upgrade_deadline = (verified_mode and verified_mode.expiration_datetime and
verified_mode.expiration_datetime.isoformat())
settings_context = {
'context_course': course_module,
'context_course': course_block,
'course_locator': course_key,
'lms_link_for_about_page': get_link_for_about_page(course_module),
'course_image_url': course_image_url(course_module, 'course_image'),
'banner_image_url': course_image_url(course_module, 'banner_image'),
'video_thumbnail_image_url': course_image_url(course_module, 'video_thumbnail_image'),
'lms_link_for_about_page': get_link_for_about_page(course_block),
'course_image_url': course_image_url(course_block, 'course_image'),
'banner_image_url': course_image_url(course_block, 'banner_image'),
'video_thumbnail_image_url': course_image_url(course_block, 'video_thumbnail_image'),
'details_url': reverse_course_url('settings_handler', course_key),
'about_page_editable': about_page_editable,
'marketing_enabled': marketing_enabled,
@@ -1210,7 +1210,7 @@ def settings_handler(request, course_key_string): # lint-amnesty, pylint: disab
'is_entrance_exams_enabled': core_toggles.ENTRANCE_EXAMS.is_enabled(),
'enable_extended_course_details': enable_extended_course_details,
'upgrade_deadline': upgrade_deadline,
'mfe_proctored_exam_settings_url': get_proctored_exam_settings_url(course_module.id),
'mfe_proctored_exam_settings_url': get_proctored_exam_settings_url(course_block.id),
}
if is_prerequisite_courses_enabled():
courses, in_process_course_actions = get_courses_accessible_to_user(request)
@@ -1232,7 +1232,7 @@ def settings_handler(request, course_key_string): # lint-amnesty, pylint: disab
# if 'minimum_grade_credit' of a course is not set or 0 then
# show warning message to course author.
show_min_grade_warning = False if course_module.minimum_grade_credit > 0 else True # lint-amnesty, pylint: disable=simplifiable-if-expression
show_min_grade_warning = False if course_block.minimum_grade_credit > 0 else True # lint-amnesty, pylint: disable=simplifiable-if-expression
settings_context.update(
{
'is_credit_course': True,
@@ -1278,7 +1278,7 @@ def settings_handler(request, course_key_string): # lint-amnesty, pylint: disab
# We have to be careful that we're only executing the following logic if we actually
# need to create or delete an entrance exam from the specified course
if core_toggles.ENTRANCE_EXAMS.is_enabled():
course_entrance_exam_present = course_module.entrance_exam_enabled
course_entrance_exam_present = course_block.entrance_exam_enabled
entrance_exam_enabled = request.json.get('entrance_exam_enabled', '') == 'true'
ee_min_score_pct = request.json.get('entrance_exam_minimum_score_pct', None)
# If the entrance exam box on the settings screen has been checked...
@@ -1328,17 +1328,17 @@ def grading_handler(request, course_key_string, grader_index=None):
"""
course_key = CourseKey.from_string(course_key_string)
with modulestore().bulk_operations(course_key):
course_module = get_course_and_check_access(course_key, request.user)
course_block = get_course_and_check_access(course_key, request.user)
if 'text/html' in request.META.get('HTTP_ACCEPT', '') and request.method == 'GET':
course_details = CourseGradingModel.fetch(course_key)
return render_to_response('settings_graders.html', {
'context_course': course_module,
'context_course': course_block,
'course_locator': course_key,
'course_details': course_details,
'grading_url': reverse_course_url('grading_handler', course_key),
'is_credit_course': is_credit_course(course_key),
'mfe_proctored_exam_settings_url': get_proctored_exam_settings_url(course_module.id),
'mfe_proctored_exam_settings_url': get_proctored_exam_settings_url(course_block.id),
})
elif 'application/json' in request.META.get('HTTP_ACCEPT', ''):
if request.method == 'GET':
@@ -1371,7 +1371,7 @@ def grading_handler(request, course_key_string, grader_index=None):
return JsonResponse()
def _refresh_course_tabs(user: User, course_module: CourseBlock):
def _refresh_course_tabs(user: User, course_block: CourseBlock):
"""
Automatically adds/removes tabs if changes to the course require them.
@@ -1392,19 +1392,19 @@ def _refresh_course_tabs(user: User, course_module: CourseBlock):
elif not tab_enabled and has_tab:
tabs.remove(tab_panel)
course_tabs = copy.copy(course_module.tabs)
course_tabs = copy.copy(course_block.tabs)
# Additionally update any tabs that are provided by non-dynamic course views
for tab_type in CourseTabPluginManager.get_tab_types():
if not tab_type.is_dynamic and tab_type.is_default:
tab_enabled = tab_type.is_enabled(course_module, user=user)
tab_enabled = tab_type.is_enabled(course_block, user=user)
update_tab(course_tabs, tab_type, tab_enabled)
CourseTabList.validate_tabs(course_tabs)
# Save the tabs into the course if they have been changed
if course_tabs != course_module.tabs:
course_module.tabs = course_tabs
if course_tabs != course_block.tabs:
course_block.tabs = course_tabs
@login_required
@@ -1423,42 +1423,42 @@ def advanced_settings_handler(request, course_key_string):
"""
course_key = CourseKey.from_string(course_key_string)
with modulestore().bulk_operations(course_key):
course_module = get_course_and_check_access(course_key, request.user)
course_block = get_course_and_check_access(course_key, request.user)
advanced_dict = CourseMetadata.fetch(course_module)
advanced_dict = CourseMetadata.fetch(course_block)
if settings.FEATURES.get('DISABLE_MOBILE_COURSE_AVAILABLE', False):
advanced_dict.get('mobile_available')['deprecated'] = True
if 'text/html' in request.META.get('HTTP_ACCEPT', '') and request.method == 'GET':
publisher_enabled = configuration_helpers.get_value_for_org(
course_module.location.org,
course_block.location.org,
'ENABLE_PUBLISHER',
settings.FEATURES.get('ENABLE_PUBLISHER', False)
)
# gather any errors in the currently stored proctoring settings.
proctoring_errors = CourseMetadata.validate_proctoring_settings(course_module, advanced_dict, request.user)
proctoring_errors = CourseMetadata.validate_proctoring_settings(course_block, advanced_dict, request.user)
return render_to_response('settings_advanced.html', {
'context_course': course_module,
'context_course': course_block,
'advanced_dict': advanced_dict,
'advanced_settings_url': reverse_course_url('advanced_settings_handler', course_key),
'publisher_enabled': publisher_enabled,
'mfe_proctored_exam_settings_url': get_proctored_exam_settings_url(course_module.id),
'mfe_proctored_exam_settings_url': get_proctored_exam_settings_url(course_block.id),
'proctoring_errors': proctoring_errors,
})
elif 'application/json' in request.META.get('HTTP_ACCEPT', ''):
if request.method == 'GET':
return JsonResponse(CourseMetadata.fetch(course_module))
return JsonResponse(CourseMetadata.fetch(course_block))
else:
try:
return JsonResponse(
update_course_advanced_settings(course_module, request.json, request.user)
update_course_advanced_settings(course_block, request.json, request.user)
)
except ValidationError as err:
return JsonResponseBadRequest(err.detail)
def update_course_advanced_settings(course_module: CourseBlock, data: Dict, user: User) -> Dict:
def update_course_advanced_settings(course_block: CourseBlock, data: Dict, user: User) -> Dict:
"""
Helper function to update course advanced settings from API data.
@@ -1466,7 +1466,7 @@ def update_course_advanced_settings(course_module: CourseBlock, data: Dict, user
it to the course advanced settings.
Args:
course_module (CourseBlock): The course run object on which to operate.
course_block (CourseBlock): The course run object on which to operate.
data (Dict): JSON data as found the ``request.data``
user (User): The user performing the operation
@@ -1474,10 +1474,10 @@ def update_course_advanced_settings(course_module: CourseBlock, data: Dict, user
Dict: The updated data after applying changes based on supplied data.
"""
try:
# validate data formats and update the course module.
# validate data formats and update the course block.
# Note: don't update mongo yet, but wait until after any tabs are changed
is_valid, errors, updated_data = CourseMetadata.validate_and_update_from_json(
course_module,
course_block,
data,
user=user,
)
@@ -1487,7 +1487,7 @@ def update_course_advanced_settings(course_module: CourseBlock, data: Dict, user
try:
# update the course tabs if required by any setting changes
_refresh_course_tabs(user, course_module)
_refresh_course_tabs(user, course_block)
except InvalidTabsException as err:
log.exception(str(err))
response_message = [
@@ -1499,7 +1499,7 @@ def update_course_advanced_settings(course_module: CourseBlock, data: Dict, user
raise ValidationError(response_message) from err
# now update mongo
modulestore().update_item(course_module, user.id)
modulestore().update_item(course_block, user.id)
return updated_data
@@ -1665,8 +1665,8 @@ def textbooks_detail_handler(request, course_key_string, textbook_id):
course_key = CourseKey.from_string(course_key_string)
store = modulestore()
with store.bulk_operations(course_key):
course_module = get_course_and_check_access(course_key, request.user)
matching_id = [tb for tb in course_module.pdf_textbooks
course_block = get_course_and_check_access(course_key, request.user)
matching_id = [tb for tb in course_block.pdf_textbooks
if str(tb.get("id")) == str(textbook_id)]
if matching_id:
textbook = matching_id[0]
@@ -1684,23 +1684,23 @@ def textbooks_detail_handler(request, course_key_string, textbook_id):
return JsonResponse({"error": str(err)}, status=400)
new_textbook["id"] = textbook_id
if textbook:
i = course_module.pdf_textbooks.index(textbook)
new_textbooks = course_module.pdf_textbooks[0:i]
i = course_block.pdf_textbooks.index(textbook)
new_textbooks = course_block.pdf_textbooks[0:i]
new_textbooks.append(new_textbook)
new_textbooks.extend(course_module.pdf_textbooks[i + 1:])
course_module.pdf_textbooks = new_textbooks
new_textbooks.extend(course_block.pdf_textbooks[i + 1:])
course_block.pdf_textbooks = new_textbooks
else:
course_module.pdf_textbooks.append(new_textbook)
store.update_item(course_module, request.user.id)
course_block.pdf_textbooks.append(new_textbook)
store.update_item(course_block, request.user.id)
return JsonResponse(new_textbook, status=201)
elif request.method == 'DELETE':
if not textbook:
return JsonResponse(status=404)
i = course_module.pdf_textbooks.index(textbook)
remaining_textbooks = course_module.pdf_textbooks[0:i]
remaining_textbooks.extend(course_module.pdf_textbooks[i + 1:])
course_module.pdf_textbooks = remaining_textbooks
store.update_item(course_module, request.user.id)
i = course_block.pdf_textbooks.index(textbook)
remaining_textbooks = course_block.pdf_textbooks[0:i]
remaining_textbooks.extend(course_block.pdf_textbooks[i + 1:])
course_block.pdf_textbooks = remaining_textbooks
store.update_item(course_block, request.user.id)
return JsonResponse()

View File

@@ -30,18 +30,18 @@ def export_git(request, course_key_string):
if not has_course_author_access(request.user, course_key):
raise PermissionDenied()
course_module = modulestore().get_course(course_key)
course_block = modulestore().get_course(course_key)
failed = False
log.debug('export_git course_module=%s', course_module)
log.debug('export_git course_block=%s', course_block)
msg = ""
if 'action' in request.GET and course_module.giturl:
if 'action' in request.GET and course_block.giturl:
if request.GET['action'] == 'push':
try:
git_export_utils.export_to_git(
course_module.id,
course_module.giturl,
course_block.id,
course_block.giturl,
request.user,
)
msg = _('Course successfully exported to git repository')
@@ -50,7 +50,7 @@ def export_git(request, course_key_string):
msg = str(ex)
return render_to_response('export_git.html', {
'context_course': course_module,
'context_course': course_block,
'msg': msg,
'failed': failed,
})

View File

@@ -254,7 +254,7 @@ def create_xblock(parent_locator, user, category, display_name, boilerplate=None
user
)
# VS[compat] cdodge: This is a hack because static_tabs also have references from the course module, so
# VS[compat] cdodge: This is a hack because static_tabs also have references from the course block, so
# if we add one then we need to also add it to the policy information (i.e. metadata)
# we should remove this once we can break this reference from the course to static tabs
if category == 'static_tab':

View File

@@ -979,7 +979,7 @@ def _delete_item(usage_key, user):
store = modulestore()
with store.bulk_operations(usage_key.course_key):
# VS[compat] cdodge: This is a hack because static_tabs also have references from the course module, so
# VS[compat] cdodge: This is a hack because static_tabs also have references from the course block, so
# if we add one then we need to also add it to the policy information (i.e. metadata)
# we should remove this once we can break this reference from the course to static tabs
if usage_key.block_type == 'static_tab':
@@ -1105,7 +1105,7 @@ def _get_gating_info(course, xblock):
info = {}
if xblock.category == 'sequential' and course.enable_subsection_gating:
if not hasattr(course, 'gating_prerequisites'):
# Cache gating prerequisites on course module so that we are not
# Cache gating prerequisites on course block so that we are not
# hitting the database for every xblock in the course
course.gating_prerequisites = gating_api.get_prerequisites(course.id)
info["is_prereq"] = gating_api.is_prerequisite(course.id, xblock.location)

View File

@@ -106,7 +106,7 @@ def update_tabs_handler(course_item: CourseBlock, tabs_data: Dict, user: User) -
Helper to handle updates to course tabs based on API data.
Args:
course_item (CourseBlock): Course module whose tabs need to be updated
course_item (CourseBlock): Course block whose tabs need to be updated
tabs_data (Dict): JSON formatted data for updating or reordering tabs.
user (User): The user performing the operation.
"""

View File

@@ -525,9 +525,9 @@ class TestCourseOutline(CourseTestCase):
self.assert_correct_json_response(child_response, is_concise)
def test_course_outline_initial_state(self):
course_module = modulestore().get_item(self.course.location)
course_block = modulestore().get_item(self.course.location)
course_structure = create_xblock_info(
course_module,
course_block,
include_child_info=True,
include_children_predicate=lambda xblock: not xblock.category == 'vertical'
)
@@ -543,7 +543,7 @@ class TestCourseOutline(CourseTestCase):
self.assertIn(str(self.sequential.location), expanded_locators)
self.assertIn(str(self.vertical.location), expanded_locators)
def _create_test_data(self, course_module, create_blocks=False, publish=True, block_types=None):
def _create_test_data(self, course_block, create_blocks=False, publish=True, block_types=None):
"""
Create data for test.
"""
@@ -558,7 +558,7 @@ class TestCourseOutline(CourseTestCase):
if not publish:
self.store.unpublish(self.vertical.location, self.user.id)
course_module.advanced_modules.extend(block_types)
course_block.advanced_modules.extend(block_types)
def _verify_deprecated_info(self, course_id, advanced_modules, info, deprecated_block_types):
"""
@@ -594,12 +594,12 @@ class TestCourseOutline(CourseTestCase):
"""
Verify deprecated warning info.
"""
course_module = modulestore().get_item(self.course.location)
self._create_test_data(course_module, create_blocks=True, block_types=block_types, publish=publish)
info = _deprecated_blocks_info(course_module, block_types)
course_block = modulestore().get_item(self.course.location)
self._create_test_data(course_block, create_blocks=True, block_types=block_types, publish=publish)
info = _deprecated_blocks_info(course_block, block_types)
self._verify_deprecated_info(
course_module.id,
course_module.advanced_modules,
course_block.id,
course_block.advanced_modules,
info,
block_types
)
@@ -611,17 +611,17 @@ class TestCourseOutline(CourseTestCase):
(["a", "b", "c"], ["d", "e", "f"])
)
@ddt.unpack
def test_verify_warn_only_on_enabled_modules(self, enabled_block_types, deprecated_block_types):
def test_verify_warn_only_on_enabled_blocks(self, enabled_block_types, deprecated_block_types):
"""
Verify that we only warn about block_types that are both deprecated and enabled.
"""
expected_block_types = list(set(enabled_block_types) & set(deprecated_block_types))
course_module = modulestore().get_item(self.course.location)
self._create_test_data(course_module, create_blocks=True, block_types=enabled_block_types)
info = _deprecated_blocks_info(course_module, deprecated_block_types)
course_block = modulestore().get_item(self.course.location)
self._create_test_data(course_block, create_blocks=True, block_types=enabled_block_types)
info = _deprecated_blocks_info(course_block, deprecated_block_types)
self._verify_deprecated_info(
course_module.id,
course_module.advanced_modules,
course_block.id,
course_block.advanced_modules,
info,
expected_block_types
)

View File

@@ -79,7 +79,7 @@ def _manage_users(request, course_key):
if not user_perms & STUDIO_VIEW_USERS:
raise PermissionDenied()
course_module = modulestore().get_course(course_key)
course_block = modulestore().get_course(course_key)
instructors = set(CourseInstructorRole(course_key).users_with_role())
# the page only lists staff and assumes they're a superset of instructors. Do a union to ensure.
staff = set(CourseStaffRole(course_key).users_with_role()).union(instructors)
@@ -91,7 +91,7 @@ def _manage_users(request, course_key):
formatted_users.append(user_with_role(user, 'staff'))
return render_to_response('manage_users.html', {
'context_course': course_module,
'context_course': course_block,
'show_transfer_ownership_hint': request.user in instructors and len(instructors) == 1,
'users': formatted_users,
'allow_actions': bool(user_perms & STUDIO_EDIT_ROLES),

View File

@@ -34,7 +34,7 @@ class TestDumpToNeo4jCommandBase(SharedModuleStoreTestCase):
@classmethod
def setUpClass(cls):
r"""
Creates two courses; one that's just a course module, and one that
Creates two courses; one that's just a course block, and one that
looks like:
course
|

View File

@@ -78,7 +78,7 @@ def replace_course_urls(text, course_key):
Replace /course/$stuff urls with /courses/$course_id/$stuff urls
text: The text to replace
course_module: A CourseBlock
course_key: A CourseBlock
returns: text with the links replaced
"""

View File

@@ -51,11 +51,11 @@ def generate_proctoring_requirements_email_context(user, course_id):
user: Currently logged-in user
course_id: ID of the proctoring-enabled course the user is enrolled in
"""
course_module = modulestore().get_course(course_id)
course_block = modulestore().get_course(course_id)
return {
'user': user,
'course_name': course_module.display_name,
'proctoring_provider': capwords(course_module.proctoring_provider.replace('_', ' ')),
'course_name': course_block.display_name,
'proctoring_provider': capwords(course_block.proctoring_provider.replace('_', ' ')),
'proctoring_requirements_url': settings.PROCTORING_SETTINGS.get('LINK_URLS', {}).get('faq', ''),
'idv_required': not settings.FEATURES.get('ENABLE_INTEGRITY_SIGNATURE'),
'id_verification_url': IDVerificationService.get_verify_location(),

View File

@@ -284,8 +284,8 @@ class ProctoringRequirementsEmailTests(EmailTemplateTagMixin, ModuleStoreTestCas
"""
Provide a tuple of string[]s that should be (in, not_in) the email
"""
course_module = modulestore().get_course(self.course.id)
proctoring_provider = capwords(course_module.proctoring_provider.replace('_', ' '))
course_block = modulestore().get_course(self.course.id)
proctoring_provider = capwords(course_block.proctoring_provider.replace('_', ' '))
fragments = [
(
"You are enrolled in {} at {}. This course contains proctored exams.".format(

View File

@@ -49,6 +49,6 @@ class CCXCourseSerializer(serializers.ModelSerializer):
@staticmethod
def get_course_modules(obj):
"""
Getter for the Course Modules. The list is stored in a compressed field.
Getter for the Course Blocks. The list is stored in a compressed field.
"""
return obj.structure or []

View File

@@ -108,7 +108,7 @@ def has_access(user, action, obj, course_key=None):
- visible_to_staff_only for modules
- DISABLE_START_DATES
- different access for instructor, staff, course staff, and students.
- mobile_available flag for course modules
- mobile_available flag for course blocks
user: a Django user object. May be anonymous. If none is passed,
anonymous is assumed

View File

@@ -152,17 +152,17 @@ def toc_for_course(user, request, course, active_chapter, active_section, field_
NOTE: assumes that if we got this far, user has access to course. Returns
None if this is not the case.
field_data_cache must include data from the course module and 2 levels of its descendants
field_data_cache must include data from the course blocks and 2 levels of its descendants
'''
with modulestore().bulk_operations(course.id):
course_module = get_module_for_descriptor(
course_block = get_module_for_descriptor(
user, request, course, field_data_cache, course.id, course=course
)
if course_module is None:
if course_block is None:
return None, None, None
toc_chapters = []
chapters = course_module.get_display_items()
chapters = course_block.get_display_items()
# Check for content which needs to be completed
# before the rest of the content is made available

View File

@@ -42,14 +42,14 @@ class ProgressCourseApp(CourseApp):
@classmethod
def is_enabled(cls, course_key: CourseKey) -> bool:
"""
The progress course status is stored in the course module.
The progress course status is stored in the course block.
"""
return not CourseOverview.get_from_id(course_key).hide_progress_tab
@classmethod
def set_enabled(cls, course_key: CourseKey, enabled: bool, user: 'User') -> bool:
"""
The progress course enabled/disabled status is stored in the course module.
The progress course enabled/disabled status is stored in the course block.
"""
course = get_course_by_id(course_key)
course.hide_progress_tab = not enabled

View File

@@ -103,7 +103,7 @@ class AboutTestCase(LoginEnrollmentTestCase, SharedModuleStoreTestCase, EventTra
@override_settings(COURSE_ABOUT_VISIBILITY_PERMISSION="see_about_page")
def test_visible_about_page_settings(self):
"""
Verify that the About Page honors the permission settings in the course module
Verify that the About Page honors the permission settings in the course block
"""
url = reverse('about_course', args=[str(self.course_with_about.id)])
resp = self.client.get(url)

View File

@@ -367,7 +367,7 @@ class CourseInstantiationTests(ModuleStoreTestCase):
@ddt.data(*itertools.product(range(5), [None, 0, 5]))
@ddt.unpack
def test_repeated_course_module_instantiation(self, loops, course_depth):
def test_repeated_course_block_instantiation(self, loops, course_depth):
with modulestore().default_store(ModuleStoreEnum.Type.split):
course = CourseFactory.create()
@@ -385,7 +385,7 @@ class CourseInstantiationTests(ModuleStoreTestCase):
field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
course.id, self.user, course, depth=course_depth
)
course_module = get_module_for_descriptor(
course_block = get_module_for_descriptor(
self.user,
fake_request,
course,
@@ -393,7 +393,7 @@ class CourseInstantiationTests(ModuleStoreTestCase):
course.id,
course=course
)
for chapter in course_module.get_children():
for chapter in course_block.get_children():
for section in chapter.get_children():
for item in section.get_children():
assert item.graded

View File

@@ -312,7 +312,7 @@ class SplitTestPosition(SharedModuleStoreTestCase):
self.client.login(username=self.student.username, password='test')
def test_changing_position_works(self):
# Make a mock FieldDataCache for this course, so we can get the course module
# Make a mock FieldDataCache for this course, so we can get the course block
mock_field_data_cache = FieldDataCache([self.course], self.course.id, self.student)
course = get_module_for_descriptor(
self.student,

View File

@@ -1109,7 +1109,7 @@ class BaseDueDateTests(ModuleStoreTestCase):
def test_backwards_compatibility(self):
# The test course being used has show_timezone = False in the policy file
# (and no due_date_display_format set). This is to test our backwards compatibility--
# in course_module's init method, the date_display_format will be set accordingly to
# in course_block's init method, the date_display_format will be set accordingly to
# remove the timezone.
course = self.set_up_course(due_date_display_format=None, show_timezone=False)
response = self.get_response(course)

View File

@@ -1262,7 +1262,7 @@ def get_static_tab_fragment(request, course, tab):
request.user, request, loc, field_data_cache, static_asset_path=course.static_asset_path, course=course
)
logging.debug('course_module = %s', tab_module)
logging.debug('course_block = %s', tab_module)
fragment = Fragment()
if tab_module is not None:

View File

@@ -408,7 +408,7 @@ def get_internal_endpoint(path=""):
return get_endpoint(settings.EDXNOTES_INTERNAL_API, path)
def get_course_position(course_module):
def get_course_position(course_block):
"""
Return the user's current place in the course.
@@ -418,14 +418,14 @@ def get_course_position(course_module):
If there is no current position in the course or chapter, then selects
the first child.
"""
urlargs = {'course_id': str(course_module.id)}
chapter = get_current_child(course_module, min_depth=1)
urlargs = {'course_id': str(course_block.id)}
chapter = get_current_child(course_block, min_depth=1)
if chapter is None:
log.debug("No chapter found when loading current position in course")
return None
urlargs['chapter'] = chapter.url_name
if course_module.position is not None:
if course_block.position is not None:
return {
'display_name': Text(chapter.display_name_with_default),
'url': reverse('courseware_chapter', kwargs=urlargs),

View File

@@ -816,25 +816,25 @@ class EdxNotesHelpersTest(ModuleStoreTestCase):
"""
Returns `None` if no chapter found.
"""
mock_course_module = MagicMock()
mock_course_module.position = 3
mock_course_module.get_display_items.return_value = []
assert helpers.get_course_position(mock_course_module) is None
mock_course_block = MagicMock()
mock_course_block.position = 3
mock_course_block.get_display_items.return_value = []
assert helpers.get_course_position(mock_course_block) is None
def test_get_course_position_to_chapter(self):
"""
Returns a position that leads to COURSE/CHAPTER if this isn't the users's
first time.
"""
mock_course_module = MagicMock(id=self.course.id, position=3)
mock_course_block = MagicMock(id=self.course.id, position=3)
mock_chapter = MagicMock()
mock_chapter.url_name = 'chapter_url_name'
mock_chapter.display_name_with_default = 'Test Chapter Display Name'
mock_course_module.get_display_items.return_value = [mock_chapter]
mock_course_block.get_display_items.return_value = [mock_chapter]
assert helpers.get_course_position(mock_course_module) == {
assert helpers.get_course_position(mock_course_block) == {
'display_name': 'Test Chapter Display Name',
'url': f'/courses/{self.course.id}/courseware/chapter_url_name/',
}
@@ -843,20 +843,20 @@ class EdxNotesHelpersTest(ModuleStoreTestCase):
"""
Returns `None` if no section found.
"""
mock_course_module = MagicMock(id=self.course.id, position=None)
mock_course_module.get_display_items.return_value = [MagicMock()]
assert helpers.get_course_position(mock_course_module) is None
mock_course_block = MagicMock(id=self.course.id, position=None)
mock_course_block.get_display_items.return_value = [MagicMock()]
assert helpers.get_course_position(mock_course_block) is None
def test_get_course_position_to_section(self):
"""
Returns a position that leads to COURSE/CHAPTER/SECTION if this is the
user's first time.
"""
mock_course_module = MagicMock(id=self.course.id, position=None)
mock_course_block = MagicMock(id=self.course.id, position=None)
mock_chapter = MagicMock()
mock_chapter.url_name = 'chapter_url_name'
mock_course_module.get_display_items.return_value = [mock_chapter]
mock_course_block.get_display_items.return_value = [mock_chapter]
mock_section = MagicMock()
mock_section.url_name = 'section_url_name'
@@ -865,7 +865,7 @@ class EdxNotesHelpersTest(ModuleStoreTestCase):
mock_chapter.get_display_items.return_value = [mock_section]
mock_section.get_display_items.return_value = [MagicMock()]
assert helpers.get_course_position(mock_course_module) == {
assert helpers.get_course_position(mock_course_block) == {
'display_name': 'Test Section Display Name',
'url': f'/courses/{self.course.id}/courseware/chapter_url_name/section_url_name/',
}
@@ -956,9 +956,9 @@ class EdxNotesViewsTest(ModuleStoreTestCase):
self.get_token_url = reverse("get_token", args=[str(self.course.id)]) # lint-amnesty, pylint: disable=no-member
self.visibility_url = reverse("edxnotes_visibility", args=[str(self.course.id)]) # lint-amnesty, pylint: disable=no-member
def _get_course_module(self):
def _get_course_block(self):
"""
Returns the course module.
Returns the course block.
"""
field_data_cache = FieldDataCache([self.course], self.course.id, self.user) # lint-amnesty, pylint: disable=no-member
return get_module_for_descriptor(
@@ -1099,8 +1099,8 @@ class EdxNotesViewsTest(ModuleStoreTestCase):
content_type="application/json",
)
assert response.status_code == 200
course_module = self._get_course_module()
assert not course_module.edxnotes_visibility
course_block = self._get_course_block()
assert not course_block.edxnotes_visibility
@patch.dict("django.conf.settings.FEATURES", {"ENABLE_EDXNOTES": False})
def test_edxnotes_visibility_if_feature_is_disabled(self):

View File

@@ -74,10 +74,10 @@ def edxnotes(request, course_id):
field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
course.id, request.user, course, depth=2
)
course_module = get_module_for_descriptor(
course_block = get_module_for_descriptor(
request.user, request, course, field_data_cache, course_key, course=course
)
position = get_course_position(course_module)
position = get_course_position(course_block)
if position:
context.update({
'position': position,
@@ -195,7 +195,7 @@ def edxnotes_visibility(request, course_id):
course_key = CourseKey.from_string(course_id)
course = get_course_with_access(request.user, "load", course_key)
field_data_cache = FieldDataCache([course], course_key, request.user)
course_module = get_module_for_descriptor(
course_block = get_module_for_descriptor(
request.user, request, course, field_data_cache, course_key, course=course
)
@@ -204,8 +204,8 @@ def edxnotes_visibility(request, course_id):
try:
visibility = json.loads(request.body.decode('utf8'))["visibility"]
course_module.edxnotes_visibility = visibility
course_module.save()
course_block.edxnotes_visibility = visibility
course_block.save()
return JsonResponse(status=200)
except (ValueError, KeyError):
log.warning(

View File

@@ -57,7 +57,7 @@ def update_exam_completion_task(user_identifier: str, content_id: str, completio
return
# This logic has been copied over from openedx/core/djangoapps/schedules/content_highlights.py
# in the _get_course_module function.
# in the _get_course_block function.
# I'm not sure if this is an anti-pattern or not, so if you can avoid re-copying this, please do.
# We are using it here because we ran into issues with the User service being undefined when we
# encountered a split_test xblock.

View File

@@ -117,7 +117,7 @@ class UserCourseStatus(views.APIView):
* last_visited_module_id: The ID of the last module that the user
visited in the course.
* last_visited_module_path: The ID of the modules in the path from the
last visited module to the course module.
last visited module to the course block.
For version v1 GET request response includes the following values.
@@ -137,18 +137,18 @@ class UserCourseStatus(views.APIView):
def _last_visited_module_path(self, request, course):
"""
Returns the path from the last module visited by the current user in the given course up to
the course module. If there is no such visit, the first item deep enough down the course
the course block. If there is no such visit, the first item deep enough down the course
tree is used.
"""
field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
course.id, request.user, course, depth=2)
course_module = get_module_for_descriptor(
course_block = get_module_for_descriptor(
request.user, request, course, field_data_cache, course.id, course=course
)
path = [course_module] if course_module else []
chapter = get_current_child(course_module, min_depth=2)
path = [course_block] if course_block else []
chapter = get_current_child(course_block, min_depth=2)
if chapter is not None:
path.append(chapter)
section = get_current_child(chapter, min_depth=1)

View File

@@ -205,31 +205,31 @@ def has_specific_team_access(user, team):
)
def has_specific_teamset_access(user, course_module, teamset_id):
def has_specific_teamset_access(user, course_block, teamset_id):
"""
Staff have access to all teamsets.
All non-staff users have access to open and public_managed teamsets.
Non-staff users only have access to a private_managed teamset if they are in a team in that teamset
"""
return has_course_staff_privileges(user, course_module.id) or \
teamset_is_public_or_user_is_on_team_in_teamset(user, course_module, teamset_id)
return has_course_staff_privileges(user, course_block.id) or \
teamset_is_public_or_user_is_on_team_in_teamset(user, course_block, teamset_id)
def teamset_is_public_or_user_is_on_team_in_teamset(user, course_module, teamset_id):
def teamset_is_public_or_user_is_on_team_in_teamset(user, course_block, teamset_id):
"""
The only users who should be able to see private_managed teamsets
or recieve any information about them at all from the API are:
- Course staff
- Users who are enrolled in a team in a private_managed teamset
course_module is passed in because almost universally where we'll be calling this, we will already
course_block is passed in because almost universally where we'll be calling this, we will already
need to have looked up the course from modulestore to make sure that the topic we're interested in
exists in the course.
"""
teamset = course_module.teams_configuration.teamsets_by_id[teamset_id]
teamset = course_block.teams_configuration.teamsets_by_id[teamset_id]
if teamset.teamset_type != TeamsetType.private_managed:
return True
return CourseTeamMembership.user_in_team_for_teamset(user, course_module.id, topic_id=teamset_id)
return CourseTeamMembership.user_in_team_for_teamset(user, course_block.id, topic_id=teamset_id)
def user_on_team_or_team_is_public(user, team):
@@ -242,8 +242,8 @@ def user_on_team_or_team_is_public(user, team):
"""
if CourseTeamMembership.is_user_on_team(user, team):
return True
course_module = modulestore().get_course(team.course_id)
teamset = course_module.teams_configuration.teamsets_by_id[team.topic_id]
course_block = modulestore().get_course(team.course_id)
teamset = course_block.teams_configuration.teamsets_by_id[team.topic_id]
return teamset.teamset_type != TeamsetType.private_managed
@@ -289,8 +289,8 @@ def get_teams_accessible_by_user(user, topic_id_set, course_id, organization_pro
return CourseTeam.objects.filter(**filter_query)
# Private teams should be hidden unless the student is a member
course_module = modulestore().get_course(course_id)
private_teamset_ids = [ts.teamset_id for ts in course_module.teamsets if ts.is_private_managed]
course_block = modulestore().get_course(course_id)
private_teamset_ids = [ts.teamset_id for ts in course_block.teamsets if ts.is_private_managed]
return CourseTeam.objects.filter(**filter_query).exclude(
Q(topic_id__in=private_teamset_ids), ~Q(membership__user=user)
)

View File

@@ -26,7 +26,7 @@ def load_team_membership_csv(course, response):
Load a CSV detailing course membership.
Arguments:
course (CourseBlock): Course module for which CSV
course (CourseBlock): Course block for which CSV
download has been requested.
response (HttpResponse): Django response object to which
the CSV content will be written.

View File

@@ -418,7 +418,7 @@ class TeamsListView(ExpandableFieldViewMixin, GenericAPIView):
course_id_string = request.query_params['course_id']
try:
course_key = CourseKey.from_string(course_id_string)
course_module = modulestore().get_course(course_key)
course_block = modulestore().get_course(course_key)
except InvalidKeyError:
error = build_api_error(
gettext_noop("The supplied course id {course_id} is not valid."),
@@ -427,7 +427,7 @@ class TeamsListView(ExpandableFieldViewMixin, GenericAPIView):
return Response(error, status=status.HTTP_400_BAD_REQUEST)
# Ensure the course exists
if course_module is None:
if course_block is None:
return Response(status=status.HTTP_404_NOT_FOUND)
result_filter.update({'course_id': course_key})
@@ -446,7 +446,7 @@ class TeamsListView(ExpandableFieldViewMixin, GenericAPIView):
result_filter.update({'membership__user__username': username})
topic_id = request.query_params.get('topic_id', None)
if topic_id is not None:
if topic_id not in course_module.teamsets_by_id:
if topic_id not in course_block.teamsets_by_id:
error = build_api_error(
gettext_noop('The supplied topic id {topic_id} is not valid'),
topic_id=topic_id
@@ -485,7 +485,7 @@ class TeamsListView(ExpandableFieldViewMixin, GenericAPIView):
# Non-staff users should not be able to see private_managed teams that they are not on.
# Staff shouldn't have any excluded teams.
excluded_private_team_ids = self._get_private_team_ids_to_exclude(course_module)
excluded_private_team_ids = self._get_private_team_ids_to_exclude(course_block)
search_results['results'] = [
result for result in search_results['results']
@@ -516,7 +516,7 @@ class TeamsListView(ExpandableFieldViewMixin, GenericAPIView):
}
# hide private_managed courses from non-staff users that aren't members of those teams
excluded_private_team_ids = self._get_private_team_ids_to_exclude(course_module)
excluded_private_team_ids = self._get_private_team_ids_to_exclude(course_block)
queryset = CourseTeam.objects.filter(**result_filter).exclude(team_id__in=excluded_private_team_ids)
order_by_input = request.query_params.get('order_by', 'name')
@@ -552,8 +552,8 @@ class TeamsListView(ExpandableFieldViewMixin, GenericAPIView):
try:
course_key = CourseKey.from_string(course_id)
# Ensure the course exists
course_module = modulestore().get_course(course_key)
if not course_module:
course_block = modulestore().get_course(course_key)
if not course_block:
return Response(status=status.HTTP_404_NOT_FOUND)
except InvalidKeyError:
field_errors['course_id'] = build_api_error(
@@ -577,8 +577,8 @@ class TeamsListView(ExpandableFieldViewMixin, GenericAPIView):
if course_key and not has_team_api_access(request.user, course_key):
return Response(status=status.HTTP_403_FORBIDDEN)
if topic_id not in course_module.teams_configuration.teamsets_by_id or (
not has_specific_teamset_access(request.user, course_module, topic_id)
if topic_id not in course_block.teams_configuration.teamsets_by_id or (
not has_specific_teamset_access(request.user, course_block, topic_id)
):
return Response(status=status.HTTP_404_NOT_FOUND)
@@ -647,18 +647,18 @@ class TeamsListView(ExpandableFieldViewMixin, GenericAPIView):
page_query_param = self.request.query_params.get(self.paginator.page_query_param)
return page_kwarg or page_query_param or 1
def _get_private_team_ids_to_exclude(self, course_module):
def _get_private_team_ids_to_exclude(self, course_block):
"""
Get the list of team ids that should be excluded from the response.
Staff can see all private teams.
Users should not be able to see teams in private teamsets that they are not a member of.
"""
if has_access(self.request.user, 'staff', course_module.id):
if has_access(self.request.user, 'staff', course_block.id):
return set()
private_teamset_ids = [ts.teamset_id for ts in course_module.teamsets if ts.is_private_managed]
private_teamset_ids = [ts.teamset_id for ts in course_block.teamsets if ts.is_private_managed]
excluded_team_ids = CourseTeam.objects.filter(
course_id=course_module.id,
course_id=course_block.id,
topic_id__in=private_teamset_ids
).exclude(
membership__user=self.request.user
@@ -1013,8 +1013,8 @@ class TopicListView(GenericAPIView):
return Response(status=status.HTTP_404_NOT_FOUND)
# Ensure the course exists
course_module = modulestore().get_course(course_id)
if course_module is None: # course is None if not found
course_block = modulestore().get_course(course_id)
if course_block is None: # course is None if not found
return Response(status=status.HTTP_404_NOT_FOUND)
if not has_team_api_access(request.user, course_id):
@@ -1034,8 +1034,8 @@ class TopicListView(GenericAPIView):
# Always sort alphabetically, as it will be used as secondary sort
# in the case of "team_count".
organization_protection_status = user_organization_protection_status(request.user, course_id)
topics = get_alphabetical_topics(course_module)
topics = _filter_hidden_private_teamsets(request.user, topics, course_module)
topics = get_alphabetical_topics(course_block)
topics = _filter_hidden_private_teamsets(request.user, topics, course_block)
if ordering == 'team_count':
add_team_count(request.user, topics, course_id, organization_protection_status)
@@ -1065,17 +1065,17 @@ class TopicListView(GenericAPIView):
return response
def _filter_hidden_private_teamsets(user, teamsets, course_module):
def _filter_hidden_private_teamsets(user, teamsets, course_block):
"""
Return a filtered list of teamsets, removing any private teamsets that a user doesn't have access to.
Follows the same logic as `has_specific_teamset_access` but in bulk rather than for one teamset at a time
"""
if has_course_staff_privileges(user, course_module.id):
if has_course_staff_privileges(user, course_block.id):
return teamsets
private_teamset_ids = [teamset.teamset_id for teamset in course_module.teamsets if teamset.is_private_managed]
private_teamset_ids = [teamset.teamset_id for teamset in course_block.teamsets if teamset.is_private_managed]
teamset_ids_user_has_access_to = set(
CourseTeam.objects.filter(
course_id=course_module.id,
course_id=course_block.id,
topic_id__in=private_teamset_ids,
membership__user=user
).values_list('topic_id', flat=True)
@@ -1086,17 +1086,17 @@ def _filter_hidden_private_teamsets(user, teamsets, course_module):
]
def get_alphabetical_topics(course_module):
def get_alphabetical_topics(course_block):
"""Return a list of team topics sorted alphabetically.
Arguments:
course_module (xmodule): the course which owns the team topics
course_block (xblock): the course which owns the team topics
Returns:
list: a list of sorted team topics
"""
return sorted(
course_module.teams_configuration.cleaned_data['team_sets'],
course_block.teams_configuration.cleaned_data['team_sets'],
key=lambda t: t['name'].lower(),
)
@@ -1159,19 +1159,19 @@ class TopicDetailView(APIView):
return Response(status=status.HTTP_404_NOT_FOUND)
# Ensure the course exists
course_module = modulestore().get_course(course_id)
if course_module is None:
course_block = modulestore().get_course(course_id)
if course_block is None:
return Response(status=status.HTTP_404_NOT_FOUND)
if not has_team_api_access(request.user, course_id):
return Response(status=status.HTTP_403_FORBIDDEN)
try:
topic = course_module.teamsets_by_id[topic_id]
topic = course_block.teamsets_by_id[topic_id]
except KeyError:
return Response(status=status.HTTP_404_NOT_FOUND)
if not has_specific_teamset_access(request.user, course_module, topic_id):
if not has_specific_teamset_access(request.user, course_block, topic_id):
return Response(status=status.HTTP_404_NOT_FOUND)
organization_protection_status = user_organization_protection_status(request.user, course_id)
@@ -1371,11 +1371,11 @@ class MembershipListView(ExpandableFieldViewMixin, GenericAPIView):
if not has_team_api_access(request.user, requested_course_key):
return Response(status=status.HTTP_404_NOT_FOUND)
course_module = modulestore().get_course(requested_course_key)
if not course_module:
course_block = modulestore().get_course(requested_course_key)
if not course_block:
return Response(status=status.HTTP_404_NOT_FOUND)
specified_username_or_team = True
teamsets = course_module.teams_configuration.teamsets_by_id
teamsets = course_block.teams_configuration.teamsets_by_id
teamset_id = request.query_params['teamset_id']
teamset = teamsets.get(teamset_id, None)
if not teamset:
@@ -1462,9 +1462,9 @@ class MembershipListView(ExpandableFieldViewMixin, GenericAPIView):
except User.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
course_module = modulestore().get_course(team.course_id)
course_block = modulestore().get_course(team.course_id)
# This should use `calc_max_team_size` instead of `default_max_team_size` (TODO MST-32).
max_team_size = course_module.teams_configuration.default_max_team_size
max_team_size = course_block.teams_configuration.default_max_team_size
if max_team_size is not None and team.users.count() >= max_team_size:
return Response(
build_api_error(gettext_noop("This team is already full.")),
@@ -1709,7 +1709,7 @@ class MembershipBulkManagementView(GenericAPIView):
course_id = CourseKey.from_string(course_id_string)
except InvalidKeyError:
raise Http404(f'Invalid course key: {course_id_string}') # lint-amnesty, pylint: disable=raise-missing-from
course_module = modulestore().get_course(course_id)
if not course_module:
course_block = modulestore().get_course(course_id)
if not course_block:
raise Http404(f'Course not found: {course_id}')
return course_module
return course_block

View File

@@ -94,7 +94,7 @@ FEATURES = {
# .. toggle_name: FEATURES['DISPLAY_DEBUG_INFO_TO_STAFF']
# .. toggle_implementation: DjangoSetting
# .. toggle_default: True
# .. toggle_description: Add a "Staff Debug" button to course modules for debugging
# .. toggle_description: Add a "Staff Debug" button to course blocks for debugging
# by course staff.
# .. toggle_use_cases: open_edx
# .. toggle_creation_date: 2015-09-04

View File

@@ -161,7 +161,7 @@ class CourseOverviewTestCase(CatalogIntegrationMixin, ModuleStoreTestCase, Cache
time_field_accessor = lambda object, field_name: get_seconds_since_epoch(getattr(object, field_name))
# The course about fields are accessed through the CourseDetail
# class for the course module, and stored as attributes on the
# class for the course block, and stored as attributes on the
# CourseOverview objects.
course_about_accessor = lambda object, field_name: CourseDetails.fetch_about_attribute(object.id, field_name)

View File

@@ -35,7 +35,7 @@ def get_expected_duration(course_id):
def spaced_out_sections(course):
"""
Generator that returns sections of the course module with a suggested time to complete for each
Generator that returns sections of the course block with a suggested time to complete for each
Returns:
index (int): index of section

View File

@@ -238,7 +238,7 @@ class CourseCohortsSettings(models.Model):
# Note that although a default value is specified here for always_cohort_inline_discussions (False),
# in reality the default value at the time that cohorting is enabled for a course comes from
# course_module.always_cohort_inline_discussions (via `migrate_cohort_settings`).
# course_block.always_cohort_inline_discussions (via `migrate_cohort_settings`).
# DEPRECATED-- DO NOT USE: Instead use `CourseDiscussionSettings.always_divide_inline_discussions`
# via `CourseDiscussionSettings.get` or `CourseDiscussionSettings.update`.
always_cohort_inline_discussions = models.BooleanField(default=False)

View File

@@ -149,7 +149,7 @@ def permission_blacked_out(course, role_names, permission_name):
Returns true if a user in course with the given roles would have permission_name blacked out.
This will return true if it is a permission that the user might have normally had for the course, but does not have
right this moment because we are in a discussion blackout period (as defined by the settings on the course module).
right this moment because we are in a discussion blackout period (as defined by the settings on the course block).
Namely, they can still view, but they can't edit, update, or create anything. This only applies to students, as
moderators of any kind still have posting privileges during discussion blackouts.
"""

View File

@@ -582,8 +582,8 @@ def is_enrollment_valid_for_proctoring(username, course_id):
return False
# Check that the course has proctored exams enabled
course_module = modulestore().get_course(course_id)
if not course_module or not course_module.enable_proctored_exams:
course_block = modulestore().get_course(course_id)
if not course_block or not course_block.enable_proctored_exams:
return False
# Only allow verified modes
@@ -592,7 +592,7 @@ def is_enrollment_valid_for_proctoring(username, course_id):
]
# If the proctoring provider allows learners in honor mode to take exams, include it
if settings.PROCTORING_BACKENDS.get(course_module.proctoring_provider, {}).get('allow_honor_mode'):
if settings.PROCTORING_BACKENDS.get(course_block.proctoring_provider, {}).get('allow_honor_mode'):
appropriate_modes.append(CourseMode.HONOR)
if enrollment['mode'] not in appropriate_modes:

View File

@@ -83,8 +83,8 @@ def get_week_highlights(user, course_key, week_num):
the requested week_num.
"""
course_descriptor = _get_course_with_highlights(course_key)
course_module = _get_course_module(course_descriptor, user)
sections_with_highlights = _get_sections_with_highlights(course_module)
course_block = _get_course_block(course_descriptor, user)
sections_with_highlights = _get_sections_with_highlights(course_block)
highlights = _get_highlights_for_week(
sections_with_highlights,
week_num,
@@ -101,8 +101,8 @@ def get_next_section_highlights(user, course_key, start_date, target_date):
CourseUpdateDoeNotExist: if highlights do not exist for the requested date
"""
course_descriptor = _get_course_with_highlights(course_key)
course_module = _get_course_module(course_descriptor, user)
return _get_highlights_for_next_section(course_module, start_date, target_date)
course_block = _get_course_block(course_descriptor, user)
return _get_highlights_for_next_section(course_block, start_date, target_date)
def _get_course_with_highlights(course_key):
@@ -126,8 +126,8 @@ def _get_course_descriptor(course_key):
return course_descriptor
def _get_course_module(course_descriptor, user):
""" Gets course module that takes into account user state and permissions """
def _get_course_block(course_descriptor, user):
""" Gets course block that takes into account user state and permissions """
# Adding courseware imports here to insulate other apps (e.g. schedules) to
# avoid import errors.
from lms.djangoapps.courseware.model_data import FieldDataCache
@@ -142,12 +142,12 @@ def _get_course_module(course_descriptor, user):
field_data_cache = FieldDataCache.cache_for_descriptor_descendents(
course_descriptor.id, user, course_descriptor, depth=1, read_only=True,
)
course_module = get_module_for_descriptor(
course_block = get_module_for_descriptor(
user, request, course_descriptor, field_data_cache, course_descriptor.id, course=course_descriptor,
)
if not course_module:
raise CourseUpdateDoesNotExist(f'Course module {course_descriptor.id} not found')
return course_module
if not course_block:
raise CourseUpdateDoesNotExist(f'Course block {course_descriptor.id} not found')
return course_block
def _section_has_highlights(section):
@@ -155,9 +155,9 @@ def _section_has_highlights(section):
return section.highlights and not section.hide_from_toc
def _get_sections_with_highlights(course_module):
def _get_sections_with_highlights(course_block):
""" Returns all sections that have highlights in a course """
return list(filter(_section_has_highlights, course_module.get_children()))
return list(filter(_section_has_highlights, course_block.get_children()))
def _get_highlights_for_week(sections, week_num, course_key):

View File

@@ -168,10 +168,10 @@ class TestContentHighlights(ModuleStoreTestCase): # lint-amnesty, pylint: disab
with self.store.bulk_operations(self.course_key):
self._create_chapter(highlights=['Test highlight'])
with self.assertRaisesRegex(CourseUpdateDoesNotExist, 'Course module .* not found'):
with self.assertRaisesRegex(CourseUpdateDoesNotExist, 'Course block .* not found'):
get_week_highlights(self.user, self.course_key, 1)
yesterday = datetime.datetime.utcnow() - datetime.timedelta(days=1)
today = datetime.datetime.utcnow()
with self.assertRaisesRegex(CourseUpdateDoesNotExist, 'Course module .* not found'):
with self.assertRaisesRegex(CourseUpdateDoesNotExist, 'Course block .* not found'):
get_next_section_highlights(self.user, self.course_key, yesterday, today.date())

View File

@@ -30,7 +30,7 @@ class ShowAnswerFieldOverrideTest(ModuleStoreTestCase):
inject_field_overrides((course,), course, self.user)
return course
def get_course_module(self, course):
def get_course_block(self, course):
request = RequestFactory().request()
field_data_cache = FieldDataCache([], course.id, self.user)
return get_module(self.user, request, course.location, field_data_cache, course=course)
@@ -40,18 +40,18 @@ class ShowAnswerFieldOverrideTest(ModuleStoreTestCase):
with override_waffle_flag(RELATIVE_DATES_FLAG, active=active):
# Instructor paced course will just have the default value
ip_course = self.setup_course()
course_module = self.get_course_module(ip_course)
assert course_module.showanswer == SHOWANSWER.FINISHED
course_block = self.get_course_block(ip_course)
assert course_block.showanswer == SHOWANSWER.FINISHED
# This should be updated to not explicitly add in the showanswer so it can test the
# default case of never touching showanswer. Reference ticket AA-307 (if that's closed,
# this can be updated!)
sp_course = self.setup_course(self_paced=True, showanswer=SHOWANSWER.FINISHED)
course_module = self.get_course_module(sp_course)
course_block = self.get_course_block(sp_course)
if active:
assert course_module.showanswer == SHOWANSWER.AFTER_ALL_ATTEMPTS_OR_CORRECT
assert course_block.showanswer == SHOWANSWER.AFTER_ALL_ATTEMPTS_OR_CORRECT
else:
assert course_module.showanswer == SHOWANSWER.FINISHED
assert course_block.showanswer == SHOWANSWER.FINISHED
@ddt.data(
(SHOWANSWER.ATTEMPTED, SHOWANSWER.ATTEMPTED_NO_PAST_DUE),
@@ -67,5 +67,5 @@ class ShowAnswerFieldOverrideTest(ModuleStoreTestCase):
@override_waffle_flag(RELATIVE_DATES_FLAG, active=True)
def test_get(self, initial_value, expected_final_value):
course = self.setup_course(self_paced=True, showanswer=initial_value)
course_module = self.get_course_module(course)
assert course_module.showanswer == expected_final_value
course_block = self.get_course_block(course)
assert course_block.showanswer == expected_final_value

View File

@@ -117,7 +117,7 @@ class CompletionServiceTestCase(CompletionWaffleTestMixin, SharedModuleStoreTest
completion=0.75,
)
def _bind_course_module(self, module):
def _bind_course_block(self, module):
"""
Bind a module (part of self.course) so we can access student-specific data.
"""
@@ -222,7 +222,7 @@ class CompletionServiceTestCase(CompletionWaffleTestMixin, SharedModuleStoreTest
library_content_block.refresh_children()
lib_vertical = self.store.get_item(lib_vertical.location)
self._bind_course_module(lib_vertical)
self._bind_course_block(lib_vertical)
# We need to refetch the library_content_block to retrieve the
# fresh version from the call to get_item for lib_vertical
library_content_block = [child for child in lib_vertical.get_children()
@@ -230,7 +230,7 @@ class CompletionServiceTestCase(CompletionWaffleTestMixin, SharedModuleStoreTest
## Ensure the library_content_block is properly set up
# This is needed so we can call get_child_descriptors
self._bind_course_module(library_content_block)
self._bind_course_block(library_content_block)
# Make sure the runtime knows that the block's children vary per-user:
assert library_content_block.has_dynamic_children()
assert len(library_content_block.children) == 3

View File

@@ -1,5 +1,5 @@
"""
Django module container for classes and operations related to the "Course Module" content type
Django module container for classes and operations related to the "Course Block" content type
"""
@@ -131,7 +131,7 @@ class Textbook: # lint-amnesty, pylint: disable=missing-class-docstring
toc_url = self.book_url + 'toc.xml'
# cdodge: I've added this caching of TOC because in Mongo-backed instances (but not Filesystem stores)
# course modules have a very short lifespan and are constantly being created and torn down.
# course blocks have a very short lifespan and are constantly being created and torn down.
# Since this module in the __init__() method does a synchronous call to AWS to get the TOC
# this is causing a big performance problem. So let's be a bit smarter about this and cache
# each fetch and store in-mem for 10 minutes.

View File

@@ -392,7 +392,7 @@ class MixedModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase):
@strip_key
def get_course(self, course_key, depth=0, **kwargs): # lint-amnesty, pylint: disable=arguments-differ
"""
returns the course module associated with the course_id. If no such course exists,
returns the course block associated with the course_id. If no such course exists,
it returns None
:param course_key: must be a CourseKey

View File

@@ -419,7 +419,7 @@ class ItemFactory(XModuleFactory):
module.submission_end = submission_end
store.update_item(module, user_id)
# VS[compat] cdodge: This is a hack because static_tabs also have references from the course module, so
# VS[compat] cdodge: This is a hack because static_tabs also have references from the course block, so
# if we add one then we need to also add it to the policy information (i.e. metadata)
# we should remove this once we can break this reference from the course to static tabs
if category == 'static_tab':

View File

@@ -1308,9 +1308,9 @@ class TestItemCrud(SplitModuleTest):
)
# add new child to old parent in continued (leave off version_guid)
course_module_locator = new_course.location.version_agnostic()
course_block_locator = new_course.location.version_agnostic()
new_ele = modulestore().create_child(
user, course_module_locator, 'chapter',
user, course_block_locator, 'chapter',
fields={'display_name': 'chapter 4'},
)
assert new_ele.update_version != course_block_update_version

View File

@@ -325,7 +325,7 @@ class LibraryExportManager(ExportManager):
def post_process(self, root, export_fs):
"""
Because Libraries are XBlocks, they aren't exported in the same way Course Modules
Because Libraries are XBlocks, they aren't exported in the same way Course Blocks
are, but instead use the standard XBlock serializers. Accordingly, we need to
create our own index file to act as the equivalent to the root course.xml file,
called library.xml.

View File

@@ -342,7 +342,7 @@ class ImportManager:
# No matter what do_import_static is, import "static_import" directory.
# This is needed because the "about" pages (eg "overview") are
# loaded via load_extra_content, and do not inherit the lms
# metadata from the course module, and thus do not get
# metadata from the course block, and thus do not get
# "static_content_store" properly defined. Static content
# referenced in those extra pages thus need to come through the
# c4x:// contentstore, unfortunately. Tell users to copy that
@@ -411,8 +411,8 @@ class ImportManager:
if self.verbose:
log.debug("Scanning %s for courselike module...", courselike_key)
# Quick scan to get course module as we need some info from there.
# Also we need to make sure that the course module is committed
# Quick scan to get course block as we need some info from there.
# Also we need to make sure that the course block is committed
# first into the store
course_data_path = path(self.data_dir) / source_courselike.data_dir
@@ -589,7 +589,7 @@ class CourseImportManager(ImportManager):
from the temporary modulestore.
"""
source_course = self.xml_module_store.get_course(courselike_key)
# STEP 1: find and import course module
# STEP 1: find and import course block
course, course_data_path = self.import_courselike(
runtime, courselike_key, dest_id, source_course,
)

View File

@@ -104,7 +104,7 @@ class SequenceFields: # lint-amnesty, pylint: disable=missing-class-docstring
is_entrance_exam = Boolean(
display_name=_("Is Entrance Exam"),
help=_(
"Tag this course module as an Entrance Exam. "
"Tag this course block as an Entrance Exam. "
"Note, you must enable Entrance Exams for this course setting to take effect."
),
default=False,

View File

@@ -712,9 +712,9 @@ class SplitTestBlock( # lint-amnesty, pylint: disable=abstract-method
assert hasattr(self.system, 'modulestore') and hasattr(self.system.modulestore, 'get_course'), \
"modulestore has to be available"
course_module = self.system.modulestore.get_course(self.location.course_key)
course_block = self.system.modulestore.get_course(self.location.course_key)
group_configuration_url = None
if 'split_test' in course_module.advanced_modules:
if 'split_test' in course_block.advanced_modules:
user_partition = self.get_selected_partition()
if user_partition:
group_configuration_url = "{url}#{configuration_id}".format(

View File

@@ -1,4 +1,4 @@
"""Tests the course modules and their functions"""
"""Tests the course blocks and their functions"""
import itertools

View File

@@ -288,7 +288,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
# pylint: disable=protected-access
assert original_unwrapped is not descriptor._unwrapped_field_data
compute_inherited_metadata(descriptor)
# Check the course module, since it has inheritance
# Check the course block, since it has inheritance
descriptor = descriptor.get_children()[0]
self.course_descriptor_inheritance_check(descriptor, from_date_string, unicorn_color)

View File

@@ -24,7 +24,7 @@ from xmodule.validation import StudioValidationMessage
from xmodule.x_module import AUTHOR_VIEW
from xmodule.capa_block import ProblemBlock
from .test_course_module import DummySystem as TestImportSystem
from .test_course_block import DummySystem as TestImportSystem
dummy_render = lambda block, _: Fragment(block.data) # pylint: disable=invalid-name
@@ -54,7 +54,7 @@ class LibraryContentTest(MixedSplitTestCase):
source_library_id=str(self.library.location.library_key)
)
def _bind_course_module(self, module):
def _bind_course_block(self, module):
"""
Bind a module (part of self.course) so we can access student-specific data.
"""
@@ -219,7 +219,7 @@ class LibraryContentBlockTestMixin:
"""
self.lc_block.refresh_children()
self.lc_block = self.store.get_item(self.lc_block.location)
self._bind_course_module(self.lc_block)
self._bind_course_block(self.lc_block)
# Make sure the runtime knows that the block's children vary per-user:
assert self.lc_block.has_dynamic_children()
@@ -360,7 +360,7 @@ class LibraryContentBlockTestMixin:
self.lc_block.refresh_children()
self.lc_block = self.store.get_item(self.lc_block.location)
self._bind_course_module(self.lc_block)
self._bind_course_block(self.lc_block)
# Eventually, we should see every child block selected
while len(blocks_seen) != len(self.lib_blocks):
@@ -475,7 +475,7 @@ class TestLibraryContentRender(LibraryContentTest):
self.lc_block.refresh_children()
self.lc_block = self.store.get_item(self.lc_block.location)
assert len(self.lc_block.children) == len(self.lib_blocks)
self._bind_course_module(self.lc_block)
self._bind_course_block(self.lc_block)
rendered = self.lc_block.render(AUTHOR_VIEW, {'root_xblock': self.lc_block})
assert 'Hello world from block 1' in rendered.content
@@ -484,7 +484,7 @@ class TestLibraryContentRender(LibraryContentTest):
self.lc_block.refresh_children()
self.lc_block = self.store.get_item(self.lc_block.location)
assert len(self.lc_block.children) == len(self.lib_blocks)
self._bind_course_module(self.lc_block)
self._bind_course_block(self.lc_block)
rendered = self.lc_block.render(AUTHOR_VIEW, {})
assert '' == rendered.content
# content should be empty
@@ -502,7 +502,7 @@ class TestLibraryContentAnalytics(LibraryContentTest):
self.publisher = Mock()
self.lc_block.refresh_children()
self.lc_block = self.store.get_item(self.lc_block.location)
self._bind_course_module(self.lc_block)
self._bind_course_block(self.lc_block)
self.lc_block.xmodule_runtime.publish = self.publisher
def _assert_event_was_published(self, event_type):
@@ -556,7 +556,7 @@ class TestLibraryContentAnalytics(LibraryContentTest):
self.store.publish(self.course.location, self.user_id)
with self.store.branch_setting(ModuleStoreEnum.Branch.published_only):
self.lc_block = self.store.get_item(self.lc_block.location)
self._bind_course_module(self.lc_block)
self._bind_course_block(self.lc_block)
self.lc_block.xmodule_runtime.publish = self.publisher
self.test_assigned_event()
@@ -575,7 +575,7 @@ class TestLibraryContentAnalytics(LibraryContentTest):
# Reload lc_block and set it up for a student:
self.lc_block = self.store.get_item(self.lc_block.location)
self._bind_course_module(self.lc_block)
self._bind_course_block(self.lc_block)
self.lc_block.xmodule_runtime.publish = self.publisher
# Get the keys of each of our blocks, as they appear in the course:

View File

@@ -11,7 +11,7 @@ from xmodule.modulestore.tests.utils import MixedSplitTestCase
from xmodule.randomize_block import RandomizeBlock
from xmodule.tests import get_test_system
from .test_course_module import DummySystem as TestImportSystem
from .test_course_block import DummySystem as TestImportSystem
class RandomizeBlockTest(MixedSplitTestCase):

View File

@@ -19,7 +19,7 @@ from xmodule.split_test_block import (
user_partition_values,
)
from xmodule.tests import get_test_system
from xmodule.tests.test_course_module import DummySystem as TestImportSystem
from xmodule.tests.test_course_block import DummySystem as TestImportSystem
from xmodule.tests.xml import XModuleXmlImportTest
from xmodule.tests.xml import factories as xml
from xmodule.validation import StudioValidationMessage