Commit f5f24fcc by Don Mitchell

Merge pull request #2022 from edx/dhm/locator_course_id

Change course_id to package_id
parents c3fbdd68 b7368ef6
...@@ -37,23 +37,21 @@ def get_all_course_role_groupnames(location, role, use_filter=True): ...@@ -37,23 +37,21 @@ def get_all_course_role_groupnames(location, role, use_filter=True):
''' '''
location = Locator.to_locator_or_location(location) location = Locator.to_locator_or_location(location)
# hack: check for existence of a group name in the legacy LMS format <role>_<course>
# if it exists, then use that one, otherwise use a <role>_<course_id> which contains
# more information
groupnames = [] groupnames = []
try:
groupnames.append('{0}_{1}'.format(role, location.course_id))
except InvalidLocationError: # will occur on old locations where location is not of category course
pass
if isinstance(location, Location): if isinstance(location, Location):
# least preferred role_course format try:
groupnames.append('{0}_{1}'.format(role, location.course)) groupnames.append('{0}_{1}'.format(role, location.course_id))
except InvalidLocationError: # will occur on old locations where location is not of category course
pass
try: try:
locator = loc_mapper().translate_location(location.course_id, location, False, False) locator = loc_mapper().translate_location(location.course_id, location, False, False)
groupnames.append('{0}_{1}'.format(role, locator.course_id)) groupnames.append('{0}_{1}'.format(role, locator.package_id))
except (InvalidLocationError, ItemNotFoundError): except (InvalidLocationError, ItemNotFoundError):
pass pass
# least preferred role_course format for legacy reasons
groupnames.append('{0}_{1}'.format(role, location.course))
elif isinstance(location, CourseLocator): elif isinstance(location, CourseLocator):
groupnames.append('{0}_{1}'.format(role, location.package_id))
old_location = loc_mapper().translate_locator_to_location(location, get_course=True) old_location = loc_mapper().translate_locator_to_location(location, get_course=True)
if old_location: if old_location:
# the slashified version of the course_id (myu/mycourse/myrun) # the slashified version of the course_id (myu/mycourse/myrun)
......
...@@ -136,13 +136,13 @@ class TemplateTests(unittest.TestCase): ...@@ -136,13 +136,13 @@ class TemplateTests(unittest.TestCase):
persistent_factories.ItemFactory.create(display_name='chapter 1', persistent_factories.ItemFactory.create(display_name='chapter 1',
parent_location=test_course.location) parent_location=test_course.location)
id_locator = CourseLocator(course_id=test_course.location.course_id, branch='draft') id_locator = CourseLocator(package_id=test_course.location.package_id, branch='draft')
guid_locator = CourseLocator(version_guid=test_course.location.version_guid) guid_locator = CourseLocator(version_guid=test_course.location.version_guid)
# verify it can be retireved by id # verify it can be retireved by id
self.assertIsInstance(modulestore('split').get_course(id_locator), CourseDescriptor) self.assertIsInstance(modulestore('split').get_course(id_locator), CourseDescriptor)
# and by guid # and by guid
self.assertIsInstance(modulestore('split').get_course(guid_locator), CourseDescriptor) self.assertIsInstance(modulestore('split').get_course(guid_locator), CourseDescriptor)
modulestore('split').delete_course(id_locator.course_id) modulestore('split').delete_course(id_locator.package_id)
# test can no longer retrieve by id # test can no longer retrieve by id
self.assertRaises(ItemNotFoundError, modulestore('split').get_course, id_locator) self.assertRaises(ItemNotFoundError, modulestore('split').get_course, id_locator)
# but can by guid # but can by guid
......
...@@ -90,7 +90,7 @@ class TestCourseAccess(ModuleStoreTestCase): ...@@ -90,7 +90,7 @@ class TestCourseAccess(ModuleStoreTestCase):
# first check the groupname for the course creator. # first check the groupname for the course creator.
self.assertTrue( self.assertTrue(
self.user.groups.filter( self.user.groups.filter(
name="{}_{}".format(INSTRUCTOR_ROLE_NAME, self.course_locator.course_id) name="{}_{}".format(INSTRUCTOR_ROLE_NAME, self.course_locator.package_id)
).exists(), ).exists(),
"Didn't add creator as instructor." "Didn't add creator as instructor."
) )
...@@ -124,4 +124,4 @@ class TestCourseAccess(ModuleStoreTestCase): ...@@ -124,4 +124,4 @@ class TestCourseAccess(ModuleStoreTestCase):
for role in [INSTRUCTOR_ROLE_NAME, STAFF_ROLE_NAME]: for role in [INSTRUCTOR_ROLE_NAME, STAFF_ROLE_NAME]:
for user in user_by_role[role]: for user in user_by_role[role]:
self.assertTrue(has_access(user, copy_course_locator), "{} no copy access".format(user)) self.assertTrue(has_access(user, copy_course_locator), "{} no copy access".format(user))
self.assertTrue(has_access(user, copy_course_location), "{} no copy access".format(user)) self.assertTrue(has_access(user, copy_course_location), "{} no copy access".format(user))
\ No newline at end of file
...@@ -34,7 +34,7 @@ __all__ = ['assets_handler'] ...@@ -34,7 +34,7 @@ __all__ = ['assets_handler']
@login_required @login_required
@ensure_csrf_cookie @ensure_csrf_cookie
def assets_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None, asset_id=None): def assets_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None, asset_id=None):
""" """
The restful handler for assets. The restful handler for assets.
It allows retrieval of all the assets (as an HTML page), as well as uploading new assets, It allows retrieval of all the assets (as an HTML page), as well as uploading new assets,
...@@ -51,7 +51,7 @@ def assets_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -51,7 +51,7 @@ def assets_handler(request, tag=None, course_id=None, branch=None, version_guid=
DELETE DELETE
json: delete an asset json: delete an asset
""" """
location = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) location = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
if not has_access(request.user, location): if not has_access(request.user, location):
raise PermissionDenied() raise PermissionDenied()
......
...@@ -26,7 +26,7 @@ __all__ = ['checklists_handler'] ...@@ -26,7 +26,7 @@ __all__ = ['checklists_handler']
@require_http_methods(("GET", "POST", "PUT")) @require_http_methods(("GET", "POST", "PUT"))
@login_required @login_required
@ensure_csrf_cookie @ensure_csrf_cookie
def checklists_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None, checklist_index=None): def checklists_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None, checklist_index=None):
""" """
The restful handler for checklists. The restful handler for checklists.
...@@ -36,7 +36,7 @@ def checklists_handler(request, tag=None, course_id=None, branch=None, version_g ...@@ -36,7 +36,7 @@ def checklists_handler(request, tag=None, course_id=None, branch=None, version_g
POST or PUT POST or PUT
json: updates the checked state for items within a particular checklist. checklist_index is required. json: updates the checked state for items within a particular checklist. checklist_index is required.
""" """
location = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) location = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
if not has_access(request.user, location): if not has_access(request.user, location):
raise PermissionDenied() raise PermissionDenied()
......
...@@ -56,7 +56,7 @@ ADVANCED_COMPONENT_POLICY_KEY = 'advanced_modules' ...@@ -56,7 +56,7 @@ ADVANCED_COMPONENT_POLICY_KEY = 'advanced_modules'
@require_http_methods(["GET"]) @require_http_methods(["GET"])
@login_required @login_required
def subsection_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): def subsection_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
""" """
The restful handler for subsection-specific requests. The restful handler for subsection-specific requests.
...@@ -65,7 +65,7 @@ def subsection_handler(request, tag=None, course_id=None, branch=None, version_g ...@@ -65,7 +65,7 @@ def subsection_handler(request, tag=None, course_id=None, branch=None, version_g
json: not currently supported json: not currently supported
""" """
if 'text/html' in request.META.get('HTTP_ACCEPT', 'text/html'): if 'text/html' in request.META.get('HTTP_ACCEPT', 'text/html'):
locator = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) locator = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
try: try:
old_location, course, item, lms_link = _get_item_in_course(request, locator) old_location, course, item, lms_link = _get_item_in_course(request, locator)
except ItemNotFoundError: except ItemNotFoundError:
...@@ -145,7 +145,7 @@ def _load_mixed_class(category): ...@@ -145,7 +145,7 @@ def _load_mixed_class(category):
@require_http_methods(["GET"]) @require_http_methods(["GET"])
@login_required @login_required
def unit_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): def unit_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
""" """
The restful handler for unit-specific requests. The restful handler for unit-specific requests.
...@@ -154,7 +154,7 @@ def unit_handler(request, tag=None, course_id=None, branch=None, version_guid=No ...@@ -154,7 +154,7 @@ def unit_handler(request, tag=None, course_id=None, branch=None, version_guid=No
json: not currently supported json: not currently supported
""" """
if 'text/html' in request.META.get('HTTP_ACCEPT', 'text/html'): if 'text/html' in request.META.get('HTTP_ACCEPT', 'text/html'):
locator = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) locator = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
try: try:
old_location, course, item, lms_link = _get_item_in_course(request, locator) old_location, course, item, lms_link = _get_item_in_course(request, locator)
except ItemNotFoundError: except ItemNotFoundError:
......
...@@ -60,12 +60,12 @@ __all__ = ['course_info_handler', 'course_handler', 'course_info_update_handler' ...@@ -60,12 +60,12 @@ __all__ = ['course_info_handler', 'course_handler', 'course_info_update_handler'
'textbooks_list_handler', 'textbooks_detail_handler'] 'textbooks_list_handler', 'textbooks_detail_handler']
def _get_locator_and_course(course_id, branch, version_guid, block_id, user, depth=0): def _get_locator_and_course(package_id, branch, version_guid, block_id, user, depth=0):
""" """
Internal method used to calculate and return the locator and course module Internal method used to calculate and return the locator and course module
for the view functions in this file. for the view functions in this file.
""" """
locator = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block_id) locator = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block_id)
if not has_access(user, locator): if not has_access(user, locator):
raise PermissionDenied() raise PermissionDenied()
course_location = loc_mapper().translate_locator_to_location(locator) course_location = loc_mapper().translate_locator_to_location(locator)
...@@ -75,7 +75,7 @@ def _get_locator_and_course(course_id, branch, version_guid, block_id, user, dep ...@@ -75,7 +75,7 @@ def _get_locator_and_course(course_id, branch, version_guid, block_id, user, dep
# pylint: disable=unused-argument # pylint: disable=unused-argument
@login_required @login_required
def course_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): def course_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
""" """
The restful handler for course specific requests. The restful handler for course specific requests.
It provides the course tree with the necessary information for identifying and labeling the parts. The root It provides the course tree with the necessary information for identifying and labeling the parts. The root
...@@ -93,7 +93,7 @@ def course_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -93,7 +93,7 @@ def course_handler(request, tag=None, course_id=None, branch=None, version_guid=
index entry. index entry.
PUT PUT
json: update this course (index entry not xblock) such as repointing head, changing display name, org, json: update this course (index entry not xblock) such as repointing head, changing display name, org,
course_id, prettyid. Return same json as above. package_id, prettyid. Return same json as above.
DELETE DELETE
json: delete this branch from this course (leaving off /branch/draft would imply delete the course) json: delete this branch from this course (leaving off /branch/draft would imply delete the course)
""" """
...@@ -104,7 +104,7 @@ def course_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -104,7 +104,7 @@ def course_handler(request, tag=None, course_id=None, branch=None, version_guid=
return create_new_course(request) return create_new_course(request)
elif not has_access( elif not has_access(
request.user, request.user,
BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
): ):
raise PermissionDenied() raise PermissionDenied()
elif request.method == 'PUT': elif request.method == 'PUT':
...@@ -114,10 +114,10 @@ def course_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -114,10 +114,10 @@ def course_handler(request, tag=None, course_id=None, branch=None, version_guid=
else: else:
return HttpResponseBadRequest() return HttpResponseBadRequest()
elif request.method == 'GET': # assume html elif request.method == 'GET': # assume html
if course_id is None: if package_id is None:
return course_listing(request) return course_listing(request)
else: else:
return course_index(request, course_id, branch, version_guid, block) return course_index(request, package_id, branch, version_guid, block)
else: else:
return HttpResponseNotFound() return HttpResponseNotFound()
...@@ -157,9 +157,7 @@ def course_listing(request): ...@@ -157,9 +157,7 @@ def course_listing(request):
course.display_name, course.display_name,
# note, couldn't get django reverse to work; so, wrote workaround # note, couldn't get django reverse to work; so, wrote workaround
course_loc.url_reverse('course/', ''), course_loc.url_reverse('course/', ''),
get_lms_link_for_item( get_lms_link_for_item(course.location),
course.location
),
course.display_org_with_default, course.display_org_with_default,
course.display_number_with_default, course.display_number_with_default,
course.location.name course.location.name
...@@ -175,14 +173,14 @@ def course_listing(request): ...@@ -175,14 +173,14 @@ def course_listing(request):
@login_required @login_required
@ensure_csrf_cookie @ensure_csrf_cookie
def course_index(request, course_id, branch, version_guid, block): def course_index(request, package_id, branch, version_guid, block):
""" """
Display an editable course overview. Display an editable course overview.
org, course, name: Attributes of the Location for the item to edit org, course, name: Attributes of the Location for the item to edit
""" """
locator, course = _get_locator_and_course( locator, course = _get_locator_and_course(
course_id, branch, version_guid, block, request.user, depth=3 package_id, branch, version_guid, block, request.user, depth=3
) )
lms_link = get_lms_link_for_item(course.location) lms_link = get_lms_link_for_item(course.location)
sections = course.get_children() sections = course.get_children()
...@@ -315,13 +313,13 @@ def create_new_course(request): ...@@ -315,13 +313,13 @@ def create_new_course(request):
@login_required @login_required
@ensure_csrf_cookie @ensure_csrf_cookie
@require_http_methods(["GET"]) @require_http_methods(["GET"])
def course_info_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): def course_info_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
""" """
GET GET
html: return html for editing the course info handouts and updates. html: return html for editing the course info handouts and updates.
""" """
__, course_module = _get_locator_and_course( __, course_module = _get_locator_and_course(
course_id, branch, version_guid, block, request.user package_id, branch, version_guid, block, request.user
) )
if 'text/html' in request.META.get('HTTP_ACCEPT', 'text/html'): if 'text/html' in request.META.get('HTTP_ACCEPT', 'text/html'):
handouts_old_location = course_module.location.replace(category='course_info', name='handouts') handouts_old_location = course_module.location.replace(category='course_info', name='handouts')
...@@ -352,7 +350,7 @@ def course_info_handler(request, tag=None, course_id=None, branch=None, version_ ...@@ -352,7 +350,7 @@ def course_info_handler(request, tag=None, course_id=None, branch=None, version_
@ensure_csrf_cookie @ensure_csrf_cookie
@require_http_methods(("GET", "POST", "PUT", "DELETE")) @require_http_methods(("GET", "POST", "PUT", "DELETE"))
@expect_json @expect_json
def course_info_update_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None, def course_info_update_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None,
provided_id=None): provided_id=None):
""" """
restful CRUD operations on course_info updates. restful CRUD operations on course_info updates.
...@@ -366,7 +364,7 @@ def course_info_update_handler(request, tag=None, course_id=None, branch=None, v ...@@ -366,7 +364,7 @@ def course_info_update_handler(request, tag=None, course_id=None, branch=None, v
""" """
if 'application/json' not in request.META.get('HTTP_ACCEPT', 'application/json'): if 'application/json' not in request.META.get('HTTP_ACCEPT', 'application/json'):
return HttpResponseBadRequest("Only supports json requests") return HttpResponseBadRequest("Only supports json requests")
updates_locator = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) updates_locator = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
updates_location = loc_mapper().translate_locator_to_location(updates_locator) updates_location = loc_mapper().translate_locator_to_location(updates_locator)
if provided_id == '': if provided_id == '':
provided_id = None provided_id = None
...@@ -400,7 +398,7 @@ def course_info_update_handler(request, tag=None, course_id=None, branch=None, v ...@@ -400,7 +398,7 @@ def course_info_update_handler(request, tag=None, course_id=None, branch=None, v
@ensure_csrf_cookie @ensure_csrf_cookie
@require_http_methods(("GET", "PUT", "POST")) @require_http_methods(("GET", "PUT", "POST"))
@expect_json @expect_json
def settings_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): def settings_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
""" """
Course settings for dates and about pages Course settings for dates and about pages
GET GET
...@@ -410,7 +408,7 @@ def settings_handler(request, tag=None, course_id=None, branch=None, version_gui ...@@ -410,7 +408,7 @@ def settings_handler(request, tag=None, course_id=None, branch=None, version_gui
json: update the Course and About xblocks through the CourseDetails model json: update the Course and About xblocks through the CourseDetails model
""" """
locator, course_module = _get_locator_and_course( locator, course_module = _get_locator_and_course(
course_id, branch, version_guid, block, request.user package_id, branch, version_guid, block, request.user
) )
if 'text/html' in request.META.get('HTTP_ACCEPT', '') and request.method == 'GET': if 'text/html' in request.META.get('HTTP_ACCEPT', '') and request.method == 'GET':
upload_asset_url = locator.url_reverse('assets/') upload_asset_url = locator.url_reverse('assets/')
...@@ -444,7 +442,7 @@ def settings_handler(request, tag=None, course_id=None, branch=None, version_gui ...@@ -444,7 +442,7 @@ def settings_handler(request, tag=None, course_id=None, branch=None, version_gui
@ensure_csrf_cookie @ensure_csrf_cookie
@require_http_methods(("GET", "POST", "PUT", "DELETE")) @require_http_methods(("GET", "POST", "PUT", "DELETE"))
@expect_json @expect_json
def grading_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None, grader_index=None): def grading_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None, grader_index=None):
""" """
Course Grading policy configuration Course Grading policy configuration
GET GET
...@@ -456,7 +454,7 @@ def grading_handler(request, tag=None, course_id=None, branch=None, version_guid ...@@ -456,7 +454,7 @@ def grading_handler(request, tag=None, course_id=None, branch=None, version_guid
json w/ grader_index: create or update the specific grader (create if index out of range) json w/ grader_index: create or update the specific grader (create if index out of range)
""" """
locator, course_module = _get_locator_and_course( locator, course_module = _get_locator_and_course(
course_id, branch, version_guid, block, request.user package_id, branch, version_guid, block, request.user
) )
if 'text/html' in request.META.get('HTTP_ACCEPT', '') and request.method == 'GET': if 'text/html' in request.META.get('HTTP_ACCEPT', '') and request.method == 'GET':
...@@ -550,7 +548,7 @@ def _config_course_advanced_components(request, course_module): ...@@ -550,7 +548,7 @@ def _config_course_advanced_components(request, course_module):
@ensure_csrf_cookie @ensure_csrf_cookie
@require_http_methods(("GET", "POST", "PUT")) @require_http_methods(("GET", "POST", "PUT"))
@expect_json @expect_json
def advanced_settings_handler(request, course_id=None, branch=None, version_guid=None, block=None, tag=None): def advanced_settings_handler(request, package_id=None, branch=None, version_guid=None, block=None, tag=None):
""" """
Course settings configuration Course settings configuration
GET GET
...@@ -562,7 +560,7 @@ def advanced_settings_handler(request, course_id=None, branch=None, version_guid ...@@ -562,7 +560,7 @@ def advanced_settings_handler(request, course_id=None, branch=None, version_guid
of keys whose values to unset: i.e., revert to default of keys whose values to unset: i.e., revert to default
""" """
locator, course_module = _get_locator_and_course( locator, course_module = _get_locator_and_course(
course_id, branch, version_guid, block, request.user package_id, branch, version_guid, block, request.user
) )
if 'text/html' in request.META.get('HTTP_ACCEPT', '') and request.method == 'GET': if 'text/html' in request.META.get('HTTP_ACCEPT', '') and request.method == 'GET':
...@@ -652,7 +650,7 @@ def assign_textbook_id(textbook, used_ids=()): ...@@ -652,7 +650,7 @@ def assign_textbook_id(textbook, used_ids=()):
@require_http_methods(("GET", "POST", "PUT")) @require_http_methods(("GET", "POST", "PUT"))
@login_required @login_required
@ensure_csrf_cookie @ensure_csrf_cookie
def textbooks_list_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): def textbooks_list_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
""" """
A RESTful handler for textbook collections. A RESTful handler for textbook collections.
...@@ -665,7 +663,7 @@ def textbooks_list_handler(request, tag=None, course_id=None, branch=None, versi ...@@ -665,7 +663,7 @@ def textbooks_list_handler(request, tag=None, course_id=None, branch=None, versi
json: overwrite all textbooks in the course with the given list json: overwrite all textbooks in the course with the given list
""" """
locator, course = _get_locator_and_course( locator, course = _get_locator_and_course(
course_id, branch, version_guid, block, request.user package_id, branch, version_guid, block, request.user
) )
store = get_modulestore(course.location) store = get_modulestore(course.location)
...@@ -729,7 +727,7 @@ def textbooks_list_handler(request, tag=None, course_id=None, branch=None, versi ...@@ -729,7 +727,7 @@ def textbooks_list_handler(request, tag=None, course_id=None, branch=None, versi
@login_required @login_required
@ensure_csrf_cookie @ensure_csrf_cookie
@require_http_methods(("GET", "POST", "PUT", "DELETE")) @require_http_methods(("GET", "POST", "PUT", "DELETE"))
def textbooks_detail_handler(request, tid, tag=None, course_id=None, branch=None, version_guid=None, block=None): def textbooks_detail_handler(request, tid, tag=None, package_id=None, branch=None, version_guid=None, block=None):
""" """
JSON API endpoint for manipulating a textbook via its internal ID. JSON API endpoint for manipulating a textbook via its internal ID.
Used by the Backbone application. Used by the Backbone application.
...@@ -742,7 +740,7 @@ def textbooks_detail_handler(request, tid, tag=None, course_id=None, branch=None ...@@ -742,7 +740,7 @@ def textbooks_detail_handler(request, tid, tag=None, course_id=None, branch=None
json: remove textbook json: remove textbook
""" """
__, course = _get_locator_and_course( __, course = _get_locator_and_course(
course_id, branch, version_guid, block, request.user package_id, branch, version_guid, block, request.user
) )
store = get_modulestore(course.location) store = get_modulestore(course.location)
matching_id = [tb for tb in course.pdf_textbooks matching_id = [tb for tb in course.pdf_textbooks
......
...@@ -50,7 +50,7 @@ CONTENT_RE = re.compile(r"(?P<start>\d{1,11})-(?P<stop>\d{1,11})/(?P<end>\d{1,11 ...@@ -50,7 +50,7 @@ CONTENT_RE = re.compile(r"(?P<start>\d{1,11})-(?P<stop>\d{1,11})/(?P<end>\d{1,11
@login_required @login_required
@ensure_csrf_cookie @ensure_csrf_cookie
@require_http_methods(("GET", "POST", "PUT")) @require_http_methods(("GET", "POST", "PUT"))
def import_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): def import_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
""" """
The restful handler for importing a course. The restful handler for importing a course.
...@@ -60,7 +60,7 @@ def import_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -60,7 +60,7 @@ def import_handler(request, tag=None, course_id=None, branch=None, version_guid=
POST or PUT POST or PUT
json: import a course via the .tar.gz file specified in request.FILES json: import a course via the .tar.gz file specified in request.FILES
""" """
location = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) location = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
if not has_access(request.user, location): if not has_access(request.user, location):
raise PermissionDenied() raise PermissionDenied()
...@@ -148,7 +148,7 @@ def import_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -148,7 +148,7 @@ def import_handler(request, tag=None, course_id=None, branch=None, version_guid=
# Use sessions to keep info about import progress # Use sessions to keep info about import progress
session_status = request.session.setdefault("import_status", {}) session_status = request.session.setdefault("import_status", {})
key = location.course_id + filename key = location.package_id + filename
session_status[key] = 1 session_status[key] = 1
request.session.modified = True request.session.modified = True
...@@ -261,7 +261,7 @@ def import_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -261,7 +261,7 @@ def import_handler(request, tag=None, course_id=None, branch=None, version_guid=
@require_GET @require_GET
@ensure_csrf_cookie @ensure_csrf_cookie
@login_required @login_required
def import_status_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None, filename=None): def import_status_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None, filename=None):
""" """
Returns an integer corresponding to the status of a file import. These are: Returns an integer corresponding to the status of a file import. These are:
...@@ -271,13 +271,13 @@ def import_status_handler(request, tag=None, course_id=None, branch=None, versio ...@@ -271,13 +271,13 @@ def import_status_handler(request, tag=None, course_id=None, branch=None, versio
3 : Importing to mongo 3 : Importing to mongo
""" """
location = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) location = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
if not has_access(request.user, location): if not has_access(request.user, location):
raise PermissionDenied() raise PermissionDenied()
try: try:
session_status = request.session["import_status"] session_status = request.session["import_status"]
status = session_status[location.course_id + filename] status = session_status[location.package_id + filename]
except KeyError: except KeyError:
status = 0 status = 0
...@@ -287,7 +287,7 @@ def import_status_handler(request, tag=None, course_id=None, branch=None, versio ...@@ -287,7 +287,7 @@ def import_status_handler(request, tag=None, course_id=None, branch=None, versio
@ensure_csrf_cookie @ensure_csrf_cookie
@login_required @login_required
@require_http_methods(("GET",)) @require_http_methods(("GET",))
def export_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): def export_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
""" """
The restful handler for exporting a course. The restful handler for exporting a course.
...@@ -302,7 +302,7 @@ def export_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -302,7 +302,7 @@ def export_handler(request, tag=None, course_id=None, branch=None, version_guid=
If the tar.gz file has been requested but the export operation fails, an HTML page will be returned If the tar.gz file has been requested but the export operation fails, an HTML page will be returned
which describes the error. which describes the error.
""" """
location = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) location = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
if not has_access(request.user, location): if not has_access(request.user, location):
raise PermissionDenied() raise PermissionDenied()
......
...@@ -47,7 +47,7 @@ CREATE_IF_NOT_FOUND = ['course_info'] ...@@ -47,7 +47,7 @@ CREATE_IF_NOT_FOUND = ['course_info']
@require_http_methods(("DELETE", "GET", "PUT", "POST")) @require_http_methods(("DELETE", "GET", "PUT", "POST"))
@login_required @login_required
@expect_json @expect_json
def xblock_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): def xblock_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
""" """
The restful handler for xblock requests. The restful handler for xblock requests.
...@@ -78,8 +78,8 @@ def xblock_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -78,8 +78,8 @@ def xblock_handler(request, tag=None, course_id=None, branch=None, version_guid=
:boilerplate: template name for populating fields, optional :boilerplate: template name for populating fields, optional
The locator (and old-style id) for the created xblock (minus children) is returned. The locator (and old-style id) for the created xblock (minus children) is returned.
""" """
if course_id is not None: if package_id is not None:
locator = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) locator = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
if not has_access(request.user, locator): if not has_access(request.user, locator):
raise PermissionDenied() raise PermissionDenied()
old_location = loc_mapper().translate_locator_to_location(locator) old_location = loc_mapper().translate_locator_to_location(locator)
...@@ -117,7 +117,7 @@ def xblock_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -117,7 +117,7 @@ def xblock_handler(request, tag=None, course_id=None, branch=None, version_guid=
delete_all_versions = str_to_bool(request.REQUEST.get('all_versions', 'False')) delete_all_versions = str_to_bool(request.REQUEST.get('all_versions', 'False'))
return _delete_item_at_location(old_location, delete_children, delete_all_versions) return _delete_item_at_location(old_location, delete_children, delete_all_versions)
else: # Since we have a course_id, we are updating an existing xblock. else: # Since we have a package_id, we are updating an existing xblock.
return _save_item( return _save_item(
request, request,
locator, locator,
...@@ -133,7 +133,7 @@ def xblock_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -133,7 +133,7 @@ def xblock_handler(request, tag=None, course_id=None, branch=None, version_guid=
return _create_item(request) return _create_item(request)
else: else:
return HttpResponseBadRequest( return HttpResponseBadRequest(
"Only instance creation is supported without a course_id.", "Only instance creation is supported without a package_id.",
content_type="text/plain" content_type="text/plain"
) )
...@@ -319,7 +319,7 @@ def _delete_item_at_location(item_location, delete_children=False, delete_all_ve ...@@ -319,7 +319,7 @@ def _delete_item_at_location(item_location, delete_children=False, delete_all_ve
# pylint: disable=W0613 # pylint: disable=W0613
@login_required @login_required
@require_http_methods(("GET", "DELETE")) @require_http_methods(("GET", "DELETE"))
def orphan_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): def orphan_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
""" """
View for handling orphan related requests. GET gets all of the current orphans. View for handling orphan related requests. GET gets all of the current orphans.
DELETE removes all orphans (requires is_staff access) DELETE removes all orphans (requires is_staff access)
...@@ -328,9 +328,9 @@ def orphan_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -328,9 +328,9 @@ def orphan_handler(request, tag=None, course_id=None, branch=None, version_guid=
from the root via children from the root via children
:param request: :param request:
:param course_id: Locator syntax course_id :param package_id: Locator syntax package_id
""" """
location = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) location = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
# DHM: when split becomes back-end, move or conditionalize this conversion # DHM: when split becomes back-end, move or conditionalize this conversion
old_location = loc_mapper().translate_locator_to_location(location) old_location = loc_mapper().translate_locator_to_location(location)
if request.method == 'GET': if request.method == 'GET':
......
...@@ -48,7 +48,7 @@ def initialize_course_tabs(course): ...@@ -48,7 +48,7 @@ def initialize_course_tabs(course):
@login_required @login_required
@ensure_csrf_cookie @ensure_csrf_cookie
@require_http_methods(("GET", "POST", "PUT")) @require_http_methods(("GET", "POST", "PUT"))
def tabs_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): def tabs_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
""" """
The restful handler for static tabs. The restful handler for static tabs.
...@@ -62,7 +62,7 @@ def tabs_handler(request, tag=None, course_id=None, branch=None, version_guid=No ...@@ -62,7 +62,7 @@ def tabs_handler(request, tag=None, course_id=None, branch=None, version_guid=No
Creating a tab, deleting a tab, or changing its contents is not supported through this method. Creating a tab, deleting a tab, or changing its contents is not supported through this method.
Instead use the general xblock URL (see item.xblock_handler). Instead use the general xblock URL (see item.xblock_handler).
""" """
locator = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) locator = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
if not has_access(request.user, locator): if not has_access(request.user, locator):
raise PermissionDenied() raise PermissionDenied()
......
...@@ -40,7 +40,7 @@ def request_course_creator(request): ...@@ -40,7 +40,7 @@ def request_course_creator(request):
@login_required @login_required
@ensure_csrf_cookie @ensure_csrf_cookie
@require_http_methods(("GET", "POST", "PUT", "DELETE")) @require_http_methods(("GET", "POST", "PUT", "DELETE"))
def course_team_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None, email=None): def course_team_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None, email=None):
""" """
The restful handler for course team users. The restful handler for course team users.
...@@ -52,7 +52,7 @@ def course_team_handler(request, tag=None, course_id=None, branch=None, version_ ...@@ -52,7 +52,7 @@ def course_team_handler(request, tag=None, course_id=None, branch=None, version_
DELETE: DELETE:
json: remove a particular course team member from the course team (email is required). json: remove a particular course team member from the course team (email is required).
""" """
location = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) location = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
if not has_access(request.user, location): if not has_access(request.user, location):
raise PermissionDenied() raise PermissionDenied()
......
...@@ -17,7 +17,6 @@ from xblock.fields import Scope, List, String, Dict, Boolean ...@@ -17,7 +17,6 @@ from xblock.fields import Scope, List, String, Dict, Boolean
from .fields import Date from .fields import Date
from xmodule.modulestore.locator import CourseLocator from xmodule.modulestore.locator import CourseLocator
from django.utils.timezone import UTC from django.utils.timezone import UTC
from xmodule.util import date_utils
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -400,7 +399,7 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): ...@@ -400,7 +399,7 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
if isinstance(self.location, Location): if isinstance(self.location, Location):
self.wiki_slug = self.location.course self.wiki_slug = self.location.course
elif isinstance(self.location, CourseLocator): elif isinstance(self.location, CourseLocator):
self.wiki_slug = self.location.course_id or self.display_name self.wiki_slug = self.location.package_id or self.display_name
if self.due_date_display_format is None and self.show_timezone is False: if self.due_date_display_format is None and self.show_timezone is False:
# For existing courses with show_timezone set to False (and no due_date_display_format specified), # For existing courses with show_timezone set to False (and no due_date_display_format specified),
......
...@@ -51,21 +51,21 @@ class LocMapperStore(object): ...@@ -51,21 +51,21 @@ class LocMapperStore(object):
self.cache = cache self.cache = cache
# location_map functions # location_map functions
def create_map_entry(self, course_location, course_id=None, draft_branch='draft', prod_branch='published', def create_map_entry(self, course_location, package_id=None, draft_branch='draft', prod_branch='published',
block_map=None): block_map=None):
""" """
Add a new entry to map this course_location to the new style CourseLocator.course_id. If course_id is not Add a new entry to map this course_location to the new style CourseLocator.package_id. If package_id is not
provided, it creates the default map of using org.course.name from the location (just like course_id) if provided, it creates the default map of using org.course.name from the location if
the location.category = 'course'; otherwise, it uses org.course. the location.category = 'course'; otherwise, it uses org.course.
You can create more than one mapping to the You can create more than one mapping to the
same course_id target. In that case, the reverse translate will be arbitrary (no guarantee of which wins). same package_id target. In that case, the reverse translate will be arbitrary (no guarantee of which wins).
The use The use
case for more than one mapping is to map both org/course/run and org/course to the same new course_id thus case for more than one mapping is to map both org/course/run and org/course to the same new package_id thus
making a default for org/course. When querying for just org/course, the translator will prefer any entry making a default for org/course. When querying for just org/course, the translator will prefer any entry
which does not have a name in the _id; otherwise, it will return an arbitrary match. which does not have a name in the _id; otherwise, it will return an arbitrary match.
Note: the opposite is not true. That is, it never makes sense to use 2 different CourseLocator.course_id Note: the opposite is not true. That is, it never makes sense to use 2 different CourseLocator.package_id
keys to index the same old Locator org/course/.. pattern. There's no checking to ensure you don't do this. keys to index the same old Locator org/course/.. pattern. There's no checking to ensure you don't do this.
NOTE: if there's already an entry w the given course_location, this may either overwrite that entry or NOTE: if there's already an entry w the given course_location, this may either overwrite that entry or
...@@ -74,8 +74,8 @@ class LocMapperStore(object): ...@@ -74,8 +74,8 @@ class LocMapperStore(object):
:param course_location: a Location preferably whose category is 'course'. Unlike the other :param course_location: a Location preferably whose category is 'course'. Unlike the other
map methods, this one doesn't take the old-style course_id. It should be called with map methods, this one doesn't take the old-style course_id. It should be called with
a course location not a block location; however, if called w/ a non-course Location, it creates a course location not a block location; however, if called w/ a non-course Location, it creates
a "default" map for the org/course pair to a new course_id. a "default" map for the org/course pair to a new package_id.
:param course_id: the CourseLocator style course_id :param package_id: the CourseLocator style package_id
:param draft_branch: the branch name to assign for drafts. This is hardcoded because old mongo had :param draft_branch: the branch name to assign for drafts. This is hardcoded because old mongo had
a fixed notion that there was 2 and only 2 versions for modules: draft and production. The old mongo a fixed notion that there was 2 and only 2 versions for modules: draft and production. The old mongo
did not, however, require that a draft version exist. The new one, however, does require a draft to did not, however, require that a draft version exist. The new one, however, does require a draft to
...@@ -86,11 +86,11 @@ class LocMapperStore(object): ...@@ -86,11 +86,11 @@ class LocMapperStore(object):
:param block_map: an optional map to specify preferred names for blocks where the keys are the :param block_map: an optional map to specify preferred names for blocks where the keys are the
Location block names and the values are the BlockUsageLocator.block_id. Location block names and the values are the BlockUsageLocator.block_id.
""" """
if course_id is None: if package_id is None:
if course_location.category == 'course': if course_location.category == 'course':
course_id = "{0.org}.{0.course}.{0.name}".format(course_location) package_id = "{0.org}.{0.course}.{0.name}".format(course_location)
else: else:
course_id = "{0.org}.{0.course}".format(course_location) package_id = "{0.org}.{0.course}".format(course_location)
# very like _interpret_location_id but w/o the _id # very like _interpret_location_id but w/o the _id
location_id = self._construct_location_son( location_id = self._construct_location_son(
course_location.org, course_location.course, course_location.org, course_location.course,
...@@ -99,12 +99,12 @@ class LocMapperStore(object): ...@@ -99,12 +99,12 @@ class LocMapperStore(object):
self.location_map.insert({ self.location_map.insert({
'_id': location_id, '_id': location_id,
'course_id': course_id, 'course_id': package_id,
'draft_branch': draft_branch, 'draft_branch': draft_branch,
'prod_branch': prod_branch, 'prod_branch': prod_branch,
'block_map': block_map or {}, 'block_map': block_map or {},
}) })
return course_id return package_id
def translate_location(self, old_style_course_id, location, published=True, add_entry_if_missing=True): def translate_location(self, old_style_course_id, location, published=True, add_entry_if_missing=True):
""" """
...@@ -174,9 +174,9 @@ class LocMapperStore(object): ...@@ -174,9 +174,9 @@ class LocMapperStore(object):
raise InvalidLocationError() raise InvalidLocationError()
published_usage = BlockUsageLocator( published_usage = BlockUsageLocator(
course_id=entry['course_id'], branch=entry['prod_branch'], block_id=block_id) package_id=entry['course_id'], branch=entry['prod_branch'], block_id=block_id)
draft_usage = BlockUsageLocator( draft_usage = BlockUsageLocator(
course_id=entry['course_id'], branch=entry['draft_branch'], block_id=block_id) package_id=entry['course_id'], branch=entry['draft_branch'], block_id=block_id)
if published: if published:
result = published_usage result = published_usage
else: else:
...@@ -199,13 +199,13 @@ class LocMapperStore(object): ...@@ -199,13 +199,13 @@ class LocMapperStore(object):
If there are no matches, it returns None. If there are no matches, it returns None.
If there's more than one location to locator mapping to the same course_id, it looks for the first If there's more than one location to locator mapping to the same package_id, it looks for the first
one with a mapping for the block block_id and picks that arbitrary course location. one with a mapping for the block block_id and picks that arbitrary course location.
:param locator: a BlockUsageLocator :param locator: a BlockUsageLocator
""" """
if get_course: if get_course:
cached_value = self._get_course_location_from_cache(locator.course_id) cached_value = self._get_course_location_from_cache(locator.package_id)
else: else:
cached_value = self._get_location_from_cache(locator) cached_value = self._get_location_from_cache(locator)
if cached_value: if cached_value:
...@@ -213,7 +213,7 @@ class LocMapperStore(object): ...@@ -213,7 +213,7 @@ class LocMapperStore(object):
# This does not require that the course exist in any modulestore # This does not require that the course exist in any modulestore
# only that it has a mapping entry. # only that it has a mapping entry.
maps = self.location_map.find({'course_id': locator.course_id}) maps = self.location_map.find({'course_id': locator.package_id})
# look for one which maps to this block block_id # look for one which maps to this block block_id
if maps.count() == 0: if maps.count() == 0:
return None return None
...@@ -365,12 +365,12 @@ class LocMapperStore(object): ...@@ -365,12 +365,12 @@ class LocMapperStore(object):
""" """
return self.cache.get(unicode(locator)) return self.cache.get(unicode(locator))
def _get_course_location_from_cache(self, locator_course_id): def _get_course_location_from_cache(self, locator_package_id):
""" """
See if the course_id is in the cache. If so, return the mapped location to the See if the package_id is in the cache. If so, return the mapped location to the
course root. course root.
""" """
return self.cache.get('courseId+{}'.format(locator_course_id)) return self.cache.get('courseId+{}'.format(locator_package_id))
def _cache_location_map_entry(self, old_course_id, location, published_usage, draft_usage): def _cache_location_map_entry(self, old_course_id, location, published_usage, draft_usage):
""" """
...@@ -380,7 +380,7 @@ class LocMapperStore(object): ...@@ -380,7 +380,7 @@ class LocMapperStore(object):
""" """
setmany = {} setmany = {}
if location.category == 'course': if location.category == 'course':
setmany['courseId+{}'.format(published_usage.course_id)] = location setmany['courseId+{}'.format(published_usage.package_id)] = location
setmany[unicode(published_usage)] = location setmany[unicode(published_usage)] = location
setmany[unicode(draft_usage)] = location setmany[unicode(draft_usage)] = location
setmany['{}+{}'.format(old_course_id, location.url())] = (published_usage, draft_usage) setmany['{}+{}'.format(old_course_id, location.url())] = (published_usage, draft_usage)
......
...@@ -12,7 +12,7 @@ from bson.errors import InvalidId ...@@ -12,7 +12,7 @@ from bson.errors import InvalidId
from xmodule.modulestore.exceptions import InsufficientSpecificationError, OverSpecificationError from xmodule.modulestore.exceptions import InsufficientSpecificationError, OverSpecificationError
from .parsers import parse_url, parse_course_id, parse_block_ref from .parsers import parse_url, parse_package_id, parse_block_ref
from .parsers import BRANCH_PREFIX, BLOCK_PREFIX, VERSION_PREFIX from .parsers import BRANCH_PREFIX, BLOCK_PREFIX, VERSION_PREFIX
import re import re
from xmodule.modulestore import Location from xmodule.modulestore import Location
...@@ -149,15 +149,15 @@ class CourseLocator(Locator): ...@@ -149,15 +149,15 @@ class CourseLocator(Locator):
""" """
Examples of valid CourseLocator specifications: Examples of valid CourseLocator specifications:
CourseLocator(version_guid=ObjectId('519665f6223ebd6980884f2b')) CourseLocator(version_guid=ObjectId('519665f6223ebd6980884f2b'))
CourseLocator(course_id='mit.eecs.6002x') CourseLocator(package_id='mit.eecs.6002x')
CourseLocator(course_id='mit.eecs.6002x/branch/published') CourseLocator(package_id='mit.eecs.6002x/branch/published')
CourseLocator(course_id='mit.eecs.6002x', branch='published') CourseLocator(package_id='mit.eecs.6002x', branch='published')
CourseLocator(url='edx://version/519665f6223ebd6980884f2b') CourseLocator(url='edx://version/519665f6223ebd6980884f2b')
CourseLocator(url='edx://mit.eecs.6002x') CourseLocator(url='edx://mit.eecs.6002x')
CourseLocator(url='edx://mit.eecs.6002x/branch/published') CourseLocator(url='edx://mit.eecs.6002x/branch/published')
CourseLocator(url='edx://mit.eecs.6002x/branch/published/version/519665f6223ebd6980884f2b') CourseLocator(url='edx://mit.eecs.6002x/branch/published/version/519665f6223ebd6980884f2b')
Should have at lease a specific course_id (id for the course as if it were a project w/ Should have at lease a specific package_id (id for the course as if it were a project w/
versions) with optional 'branch', versions) with optional 'branch',
or version_guid (which points to a specific version). Can contain both in which case or version_guid (which points to a specific version). Can contain both in which case
the persistence layer may raise exceptions if the given version != the current such version the persistence layer may raise exceptions if the given version != the current such version
...@@ -166,47 +166,47 @@ class CourseLocator(Locator): ...@@ -166,47 +166,47 @@ class CourseLocator(Locator):
# Default values # Default values
version_guid = None version_guid = None
course_id = None package_id = None
branch = None branch = None
def __init__(self, url=None, version_guid=None, course_id=None, branch=None): def __init__(self, url=None, version_guid=None, package_id=None, branch=None):
""" """
Construct a CourseLocator Construct a CourseLocator
Caller may provide url (but no other parameters). Caller may provide url (but no other parameters).
Caller may provide version_guid (but no other parameters). Caller may provide version_guid (but no other parameters).
Caller may provide course_id (optionally provide branch). Caller may provide package_id (optionally provide branch).
Resulting CourseLocator will have either a version_guid property Resulting CourseLocator will have either a version_guid property
or a course_id (with optional branch) property, or both. or a package_id (with optional branch) property, or both.
version_guid must be an instance of bson.objectid.ObjectId or None version_guid must be an instance of bson.objectid.ObjectId or None
url, course_id, and branch must be strings or None url, package_id, and branch must be strings or None
""" """
self._validate_args(url, version_guid, course_id) self._validate_args(url, version_guid, package_id)
if url: if url:
self.init_from_url(url) self.init_from_url(url)
if version_guid: if version_guid:
self.init_from_version_guid(version_guid) self.init_from_version_guid(version_guid)
if course_id or branch: if package_id or branch:
self.init_from_course_id(course_id, branch) self.init_from_package_id(package_id, branch)
if self.version_guid is None and self.course_id is None: if self.version_guid is None and self.package_id is None:
raise ValueError("Either version_guid or course_id should be set: {}".format(url)) raise ValueError("Either version_guid or package_id should be set: {}".format(url))
def __unicode__(self): def __unicode__(self):
""" """
Return a string representing this location. Return a string representing this location.
""" """
if self.course_id: if self.package_id:
result = self.course_id result = self.package_id
if self.branch: if self.branch:
result += '/' + BRANCH_PREFIX + self.branch result += '/' + BRANCH_PREFIX + self.branch
return result return result
elif self.version_guid: elif self.version_guid:
return VERSION_PREFIX + str(self.version_guid) return VERSION_PREFIX + str(self.version_guid)
else: else:
# raise InsufficientSpecificationError("missing course_id or version_guid") # raise InsufficientSpecificationError("missing package_id or version_guid")
return '<InsufficientSpecificationError: missing course_id or version_guid>' return '<InsufficientSpecificationError: missing package_id or version_guid>'
def url(self): def url(self):
""" """
...@@ -214,29 +214,29 @@ class CourseLocator(Locator): ...@@ -214,29 +214,29 @@ class CourseLocator(Locator):
""" """
return 'edx://' + unicode(self) return 'edx://' + unicode(self)
def _validate_args(self, url, version_guid, course_id): def _validate_args(self, url, version_guid, package_id):
""" """
Validate provided arguments. Internal use only which is why it checks for each Validate provided arguments. Internal use only which is why it checks for each
arg and doesn't use keyword arg and doesn't use keyword
""" """
if not any((url, version_guid, course_id)): if not any((url, version_guid, package_id)):
raise InsufficientSpecificationError("Must provide one of url, version_guid, course_id") raise InsufficientSpecificationError("Must provide one of url, version_guid, package_id")
def is_fully_specified(self): def is_fully_specified(self):
""" """
Returns True if either version_guid is specified, or course_id+branch Returns True if either version_guid is specified, or package_id+branch
are specified. are specified.
This should always return True, since this should be validated in the constructor. This should always return True, since this should be validated in the constructor.
""" """
return (self.version_guid is not None or return (self.version_guid is not None or
(self.course_id is not None and self.branch is not None)) (self.package_id is not None and self.branch is not None))
def set_course_id(self, new): def set_package_id(self, new):
""" """
Initialize course_id to new value. Initialize package_id to new value.
If course_id has already been initialized to a different value, raise an exception. If package_id has already been initialized to a different value, raise an exception.
""" """
self.set_property('course_id', new) self.set_property('package_id', new)
def set_branch(self, new): def set_branch(self, new):
""" """
...@@ -259,7 +259,7 @@ class CourseLocator(Locator): ...@@ -259,7 +259,7 @@ class CourseLocator(Locator):
The copy does not include subclass information, such as The copy does not include subclass information, such as
a block_id (a property of BlockUsageLocator). a block_id (a property of BlockUsageLocator).
""" """
return CourseLocator(course_id=self.course_id, return CourseLocator(package_id=self.package_id,
version_guid=self.version_guid, version_guid=self.version_guid,
branch=self.branch) branch=self.branch)
...@@ -285,7 +285,7 @@ class CourseLocator(Locator): ...@@ -285,7 +285,7 @@ class CourseLocator(Locator):
def init_from_url(self, url): def init_from_url(self, url):
""" """
url must be a string beginning with 'edx://' and containing url must be a string beginning with 'edx://' and containing
either a valid version_guid or course_id (with optional branch), or both. either a valid version_guid or package_id (with optional branch), or both.
""" """
if isinstance(url, Locator): if isinstance(url, Locator):
parse = url.__dict__ parse = url.__dict__
...@@ -298,7 +298,7 @@ class CourseLocator(Locator): ...@@ -298,7 +298,7 @@ class CourseLocator(Locator):
self._set_value( self._set_value(
parse, 'version_guid', lambda (new_guid): self.set_version_guid(self.as_object_id(new_guid)) parse, 'version_guid', lambda (new_guid): self.set_version_guid(self.as_object_id(new_guid))
) )
self._set_value(parse, 'course_id', self.set_course_id) self._set_value(parse, 'package_id', self.set_package_id)
self._set_value(parse, 'branch', self.set_branch) self._set_value(parse, 'branch', self.set_branch)
def init_from_version_guid(self, version_guid): def init_from_version_guid(self, version_guid):
...@@ -313,29 +313,29 @@ class CourseLocator(Locator): ...@@ -313,29 +313,29 @@ class CourseLocator(Locator):
raise TypeError('%s is not an instance of ObjectId' % version_guid) raise TypeError('%s is not an instance of ObjectId' % version_guid)
self.set_version_guid(version_guid) self.set_version_guid(version_guid)
def init_from_course_id(self, course_id, explicit_branch=None): def init_from_package_id(self, package_id, explicit_branch=None):
""" """
Course_id is a CourseLocator or a string like 'mit.eecs.6002x' or 'mit.eecs.6002x/branch/published'. package_id is a CourseLocator or a string like 'mit.eecs.6002x' or 'mit.eecs.6002x/branch/published'.
Revision (optional) is a string like 'published'. Revision (optional) is a string like 'published'.
It may be provided explicitly (explicit_branch) or embedded into course_id. It may be provided explicitly (explicit_branch) or embedded into package_id.
If branch is part of course_id (".../branch/published"), parse it out separately. If branch is part of package_id (".../branch/published"), parse it out separately.
If branch is provided both ways, that's ok as long as they are the same value. If branch is provided both ways, that's ok as long as they are the same value.
If a block ('/block/HW3') is a part of course_id, it is ignored. If a block ('/block/HW3') is a part of package_id, it is ignored.
""" """
if course_id: if package_id:
if isinstance(course_id, CourseLocator): if isinstance(package_id, CourseLocator):
course_id = course_id.course_id package_id = package_id.package_id
if not course_id: if not package_id:
raise ValueError("%s does not have a valid course_id" % course_id) raise ValueError("%s does not have a valid package_id" % package_id)
parse = parse_course_id(course_id) parse = parse_package_id(package_id)
if not parse or parse['course_id'] is None: if not parse or parse['package_id'] is None:
raise ValueError('Could not parse "%s" as a course_id' % course_id) raise ValueError('Could not parse "%s" as a package_id' % package_id)
self.set_course_id(parse['course_id']) self.set_package_id(parse['package_id'])
rev = parse['branch'] rev = parse['branch']
if rev: if rev:
self.set_branch(rev) self.set_branch(rev)
...@@ -357,7 +357,7 @@ class CourseLocator(Locator): ...@@ -357,7 +357,7 @@ class CourseLocator(Locator):
the name although that's mutable. We should also clearly define the purpose and restrictions of this the name although that's mutable. We should also clearly define the purpose and restrictions of this
(e.g., I'm assuming periods are fine). (e.g., I'm assuming periods are fine).
""" """
return self.course_id return self.package_id
def _set_value(self, parse, key, setter): def _set_value(self, parse, key, setter):
""" """
...@@ -379,12 +379,12 @@ class BlockUsageLocator(CourseLocator): ...@@ -379,12 +379,12 @@ class BlockUsageLocator(CourseLocator):
the defined element in the course. Courses can be a version of an offering, the the defined element in the course. Courses can be a version of an offering, the
current draft head, or the current production version. current draft head, or the current production version.
Locators can contain both a version and a course_id w/ branch. The split mongo functions Locators can contain both a version and a package_id w/ branch. The split mongo functions
may raise errors if these conflict w/ the current db state (i.e., the course's branch != may raise errors if these conflict w/ the current db state (i.e., the course's branch !=
the version_guid) the version_guid)
Locations can express as urls as well as dictionaries. They consist of Locations can express as urls as well as dictionaries. They consist of
course_identifier: course_guid | version_guid package_identifier: course_guid | version_guid
block : guid block : guid
branch : string branch : string
""" """
...@@ -392,34 +392,34 @@ class BlockUsageLocator(CourseLocator): ...@@ -392,34 +392,34 @@ class BlockUsageLocator(CourseLocator):
# Default value # Default value
block_id = None block_id = None
def __init__(self, url=None, version_guid=None, course_id=None, def __init__(self, url=None, version_guid=None, package_id=None,
branch=None, block_id=None): branch=None, block_id=None):
""" """
Construct a BlockUsageLocator Construct a BlockUsageLocator
Caller may provide url, version_guid, or course_id, and optionally provide branch. Caller may provide url, version_guid, or package_id, and optionally provide branch.
The block_id may be specified, either explictly or as part of The block_id may be specified, either explictly or as part of
the url or course_id. If omitted, the locator is created but it the url or package_id. If omitted, the locator is created but it
has not yet been initialized. has not yet been initialized.
Resulting BlockUsageLocator will have a block_id property. Resulting BlockUsageLocator will have a block_id property.
It will have either a version_guid property or a course_id (with optional branch) property, or both. It will have either a version_guid property or a package_id (with optional branch) property, or both.
version_guid must be an instance of bson.objectid.ObjectId or None version_guid must be an instance of bson.objectid.ObjectId or None
url, course_id, branch, and block_id must be strings or None url, package_id, branch, and block_id must be strings or None
""" """
self._validate_args(url, version_guid, course_id) self._validate_args(url, version_guid, package_id)
if url: if url:
self.init_block_ref_from_str(url) self.init_block_ref_from_str(url)
if course_id: if package_id:
self.init_block_ref_from_course_id(course_id) self.init_block_ref_from_package_id(package_id)
if block_id: if block_id:
self.init_block_ref(block_id) self.init_block_ref(block_id)
super(BlockUsageLocator, self).__init__( super(BlockUsageLocator, self).__init__(
url=url, url=url,
version_guid=version_guid, version_guid=version_guid,
course_id=course_id, package_id=package_id,
branch=branch branch=branch
) )
...@@ -432,7 +432,7 @@ class BlockUsageLocator(CourseLocator): ...@@ -432,7 +432,7 @@ class BlockUsageLocator(CourseLocator):
def version_agnostic(self): def version_agnostic(self):
""" """
Returns a copy of itself. Returns a copy of itself.
If both version_guid and course_id are known, use a blank course_id in the copy. If both version_guid and package_id are known, use a blank package_id in the copy.
We don't care if the locator's version is not the current head; so, avoid version conflict We don't care if the locator's version is not the current head; so, avoid version conflict
by reducing info. by reducing info.
...@@ -444,7 +444,7 @@ class BlockUsageLocator(CourseLocator): ...@@ -444,7 +444,7 @@ class BlockUsageLocator(CourseLocator):
branch=self.branch, branch=self.branch,
block_id=self.block_id) block_id=self.block_id)
else: else:
return BlockUsageLocator(course_id=self.course_id, return BlockUsageLocator(package_id=self.package_id,
branch=self.branch, branch=self.branch,
block_id=self.block_id) block_id=self.block_id)
...@@ -478,13 +478,13 @@ class BlockUsageLocator(CourseLocator): ...@@ -478,13 +478,13 @@ class BlockUsageLocator(CourseLocator):
raise ValueError('Could not parse "%s" as a url' % value) raise ValueError('Could not parse "%s" as a url' % value)
self._set_value(parse, 'block', self.set_block_id) self._set_value(parse, 'block', self.set_block_id)
def init_block_ref_from_course_id(self, course_id): def init_block_ref_from_package_id(self, package_id):
if isinstance(course_id, CourseLocator): if isinstance(package_id, CourseLocator):
course_id = course_id.course_id package_id = package_id.package_id
assert course_id, "%s does not have a valid course_id" assert package_id, "%s does not have a valid package_id"
parse = parse_course_id(course_id) parse = parse_package_id(package_id)
if parse is None: if parse is None:
raise ValueError('Could not parse "%s" as a course_id' % course_id) raise ValueError('Could not parse "%s" as a package_id' % package_id)
self._set_value(parse, 'block', self.set_block_id) self._set_value(parse, 'block', self.set_block_id)
def __unicode__(self): def __unicode__(self):
......
...@@ -11,7 +11,7 @@ ALLOWED_ID_CHARS = r'[a-zA-Z0-9_\-~.:]' ...@@ -11,7 +11,7 @@ ALLOWED_ID_CHARS = r'[a-zA-Z0-9_\-~.:]'
URL_RE_SOURCE = r""" URL_RE_SOURCE = r"""
(?P<tag>edx://)? (?P<tag>edx://)?
((?P<course_id>{ALLOWED_ID_CHARS}+)/?)? ((?P<package_id>{ALLOWED_ID_CHARS}+)/?)?
({BRANCH_PREFIX}(?P<branch>{ALLOWED_ID_CHARS}+)/?)? ({BRANCH_PREFIX}(?P<branch>{ALLOWED_ID_CHARS}+)/?)?
({VERSION_PREFIX}(?P<version_guid>[A-F0-9]+)/?)? ({VERSION_PREFIX}(?P<version_guid>[A-F0-9]+)/?)?
({BLOCK_PREFIX}(?P<block>{ALLOWED_ID_CHARS}+))? ({BLOCK_PREFIX}(?P<block>{ALLOWED_ID_CHARS}+))?
...@@ -26,7 +26,7 @@ URL_RE = re.compile('^' + URL_RE_SOURCE + '$', re.IGNORECASE | re.VERBOSE) ...@@ -26,7 +26,7 @@ URL_RE = re.compile('^' + URL_RE_SOURCE + '$', re.IGNORECASE | re.VERBOSE)
def parse_url(string, tag_optional=False): def parse_url(string, tag_optional=False):
""" """
A url usually begins with 'edx://' (case-insensitive match), A url usually begins with 'edx://' (case-insensitive match),
followed by either a version_guid or a course_id. If tag_optional, then followed by either a version_guid or a package_id. If tag_optional, then
the url does not have to start with the tag and edx will be assumed. the url does not have to start with the tag and edx will be assumed.
Examples: Examples:
...@@ -38,10 +38,10 @@ def parse_url(string, tag_optional=False): ...@@ -38,10 +38,10 @@ def parse_url(string, tag_optional=False):
This returns None if string cannot be parsed. This returns None if string cannot be parsed.
If it can be parsed as a version_guid with no preceding course_id, returns a dict If it can be parsed as a version_guid with no preceding package_id, returns a dict
with key 'version_guid' and the value, with key 'version_guid' and the value,
If it can be parsed as a course_id, returns a dict If it can be parsed as a package_id, returns a dict
with key 'id' and optional keys 'branch' and 'version_guid'. with key 'id' and optional keys 'branch' and 'version_guid'.
""" """
...@@ -69,15 +69,15 @@ def parse_block_ref(string): ...@@ -69,15 +69,15 @@ def parse_block_ref(string):
return None return None
def parse_course_id(string): def parse_package_id(string):
r""" r"""
A course_id has a main id component. A package_id has a main id component.
There may also be an optional branch (/branch/published or /branch/draft). There may also be an optional branch (/branch/published or /branch/draft).
There may also be an optional version (/version/519665f6223ebd6980884f2b). There may also be an optional version (/version/519665f6223ebd6980884f2b).
There may also be an optional block (/block/HW3 or /block/Quiz2). There may also be an optional block (/block/HW3 or /block/Quiz2).
Examples of valid course_ids: Examples of valid package_ids:
'mit.eecs.6002x' 'mit.eecs.6002x'
'mit.eecs.6002x/branch/published' 'mit.eecs.6002x/branch/published'
...@@ -88,7 +88,7 @@ def parse_course_id(string): ...@@ -88,7 +88,7 @@ def parse_course_id(string):
Syntax: Syntax:
course_id = main_id [/branch/ branch] [/version/ version ] [/block/ block] package_id = main_id [/branch/ branch] [/version/ version ] [/block/ block]
main_id = name [. name]* main_id = name [. name]*
...@@ -98,7 +98,7 @@ def parse_course_id(string): ...@@ -98,7 +98,7 @@ def parse_course_id(string):
name = ALLOWED_ID_CHARS name = ALLOWED_ID_CHARS
If string is a course_id, returns a dict with keys 'id', 'branch', and 'block'. If string is a package_id, returns a dict with keys 'id', 'branch', and 'block'.
Revision is optional: if missing returned_dict['branch'] is None. Revision is optional: if missing returned_dict['branch'] is None.
Block is optional: if missing returned_dict['block'] is None. Block is optional: if missing returned_dict['block'] is None.
Else returns None. Else returns None.
......
...@@ -23,41 +23,41 @@ class SplitMigrator(object): ...@@ -23,41 +23,41 @@ class SplitMigrator(object):
self.draft_modulestore = draft_modulestore self.draft_modulestore = draft_modulestore
self.loc_mapper = loc_mapper self.loc_mapper = loc_mapper
def migrate_mongo_course(self, course_location, user_id, new_course_id=None): def migrate_mongo_course(self, course_location, user_id, new_package_id=None):
""" """
Create a new course in split_mongo representing the published and draft versions of the course from the Create a new course in split_mongo representing the published and draft versions of the course from the
original mongo store. And return the new_course_id (which the caller can also get by calling original mongo store. And return the new_package_id (which the caller can also get by calling
self.loc_mapper.translate_location(old_course_location) self.loc_mapper.translate_location(old_course_location)
If the new course already exists, this raises DuplicateItemError If the new course already exists, this raises DuplicateItemError
:param course_location: a Location whose category is 'course' and points to the course :param course_location: a Location whose category is 'course' and points to the course
:param user_id: the user whose action is causing this migration :param user_id: the user whose action is causing this migration
:param new_course_id: (optional) the Locator.course_id for the new course. Defaults to :param new_package_id: (optional) the Locator.package_id for the new course. Defaults to
whatever translate_location_to_locator returns whatever translate_location_to_locator returns
""" """
new_course_id = self.loc_mapper.create_map_entry(course_location, course_id=new_course_id) new_package_id = self.loc_mapper.create_map_entry(course_location, package_id=new_package_id)
old_course_id = course_location.course_id old_course_id = course_location.course_id
# the only difference in data between the old and split_mongo xblocks are the locations; # the only difference in data between the old and split_mongo xblocks are the locations;
# so, any field which holds a location must change to a Locator; otherwise, the persistence # so, any field which holds a location must change to a Locator; otherwise, the persistence
# layer and kvs's know how to store it. # layer and kvs's know how to store it.
# locations are in location, children, conditionals, course.tab # locations are in location, children, conditionals, course.tab
# create the course: set fields to explicitly_set for each scope, id_root = new_course_id, master_branch = 'production' # create the course: set fields to explicitly_set for each scope, id_root = new_package_id, master_branch = 'production'
original_course = self.direct_modulestore.get_item(course_location) original_course = self.direct_modulestore.get_item(course_location)
new_course_root_locator = self.loc_mapper.translate_location(old_course_id, course_location) new_course_root_locator = self.loc_mapper.translate_location(old_course_id, course_location)
new_course = self.split_modulestore.create_course( new_course = self.split_modulestore.create_course(
course_location.org, original_course.display_name, course_location.org, original_course.display_name,
user_id, id_root=new_course_id, user_id, id_root=new_package_id,
fields=self._get_json_fields_translate_children(original_course, old_course_id, True), fields=self._get_json_fields_translate_children(original_course, old_course_id, True),
root_block_id=new_course_root_locator.block_id, root_block_id=new_course_root_locator.block_id,
master_branch=new_course_root_locator.branch master_branch=new_course_root_locator.branch
) )
self._copy_published_modules_to_course(new_course, course_location, old_course_id, user_id) self._copy_published_modules_to_course(new_course, course_location, old_course_id, user_id)
self._add_draft_modules_to_course(new_course_id, old_course_id, course_location, user_id) self._add_draft_modules_to_course(new_package_id, old_course_id, course_location, user_id)
return new_course_id return new_package_id
def _copy_published_modules_to_course(self, new_course, old_course_loc, old_course_id, user_id): def _copy_published_modules_to_course(self, new_course, old_course_loc, old_course_id, user_id):
""" """
...@@ -94,13 +94,13 @@ class SplitMigrator(object): ...@@ -94,13 +94,13 @@ class SplitMigrator(object):
# children which meant some pointers were to non-existent locations in 'direct' # children which meant some pointers were to non-existent locations in 'direct'
self.split_modulestore.internal_clean_children(course_version_locator) self.split_modulestore.internal_clean_children(course_version_locator)
def _add_draft_modules_to_course(self, new_course_id, old_course_id, old_course_loc, user_id): def _add_draft_modules_to_course(self, new_package_id, old_course_id, old_course_loc, user_id):
""" """
update each draft. Create any which don't exist in published and attach to their parents. update each draft. Create any which don't exist in published and attach to their parents.
""" """
# each true update below will trigger a new version of the structure. We may want to just have one new version # each true update below will trigger a new version of the structure. We may want to just have one new version
# but that's for a later date. # but that's for a later date.
new_draft_course_loc = CourseLocator(course_id=new_course_id, branch='draft') new_draft_course_loc = CourseLocator(package_id=new_package_id, branch='draft')
# to prevent race conditions of grandchilden being added before their parents and thus having no parent to # to prevent race conditions of grandchilden being added before their parents and thus having no parent to
# add to # add to
awaiting_adoption = {} awaiting_adoption = {}
...@@ -112,7 +112,7 @@ class SplitMigrator(object): ...@@ -112,7 +112,7 @@ class SplitMigrator(object):
new_locator = self.loc_mapper.translate_location( new_locator = self.loc_mapper.translate_location(
old_course_id, module.location, False, add_entry_if_missing=True old_course_id, module.location, False, add_entry_if_missing=True
) )
if self.split_modulestore.has_item(new_course_id, new_locator): if self.split_modulestore.has_item(new_package_id, new_locator):
# was in 'direct' so draft is a new version # was in 'direct' so draft is a new version
split_module = self.split_modulestore.get_item(new_locator) split_module = self.split_modulestore.get_item(new_locator)
# need to remove any no-longer-explicitly-set values and add/update any now set values. # need to remove any no-longer-explicitly-set values and add/update any now set values.
......
...@@ -27,9 +27,9 @@ class CachingDescriptorSystem(MakoDescriptorSystem): ...@@ -27,9 +27,9 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
modulestore: the module store that can be used to retrieve additional modulestore: the module store that can be used to retrieve additional
modules modules
course_entry: the originally fetched enveloped course_structure w/ branch and course_id info. course_entry: the originally fetched enveloped course_structure w/ branch and package_id info.
Callers to _load_item provide an override but that function ignores the provided structure and Callers to _load_item provide an override but that function ignores the provided structure and
only looks at the branch and course_id only looks at the branch and package_id
module_data: a dict mapping Location -> json that was cached from the module_data: a dict mapping Location -> json that was cached from the
underlying modulestore underlying modulestore
...@@ -78,14 +78,14 @@ class CachingDescriptorSystem(MakoDescriptorSystem): ...@@ -78,14 +78,14 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
# the thread is working with more than one named container pointing to the same specific structure is # the thread is working with more than one named container pointing to the same specific structure is
# low; thus, the course_entry is most likely correct. If the thread is looking at > 1 named container # low; thus, the course_entry is most likely correct. If the thread is looking at > 1 named container
# pointing to the same structure, the access is likely to be chunky enough that the last known container # pointing to the same structure, the access is likely to be chunky enough that the last known container
# is the intended one when not given a course_entry_override; thus, the caching of the last branch/course_id. # is the intended one when not given a course_entry_override; thus, the caching of the last branch/package_id.
def xblock_from_json(self, class_, block_id, json_data, course_entry_override=None): def xblock_from_json(self, class_, block_id, json_data, course_entry_override=None):
if course_entry_override is None: if course_entry_override is None:
course_entry_override = self.course_entry course_entry_override = self.course_entry
else: else:
# most recent retrieval is most likely the right one for next caller (see comment above fn) # most recent retrieval is most likely the right one for next caller (see comment above fn)
self.course_entry['branch'] = course_entry_override['branch'] self.course_entry['branch'] = course_entry_override['branch']
self.course_entry['course_id'] = course_entry_override['course_id'] self.course_entry['package_id'] = course_entry_override['package_id']
# most likely a lazy loader or the id directly # most likely a lazy loader or the id directly
definition = json_data.get('definition', {}) definition = json_data.get('definition', {})
definition_id = self.modulestore.definition_locator(definition) definition_id = self.modulestore.definition_locator(definition)
...@@ -97,7 +97,7 @@ class CachingDescriptorSystem(MakoDescriptorSystem): ...@@ -97,7 +97,7 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
block_locator = BlockUsageLocator( block_locator = BlockUsageLocator(
version_guid=course_entry_override['structure']['_id'], version_guid=course_entry_override['structure']['_id'],
block_id=block_id, block_id=block_id,
course_id=course_entry_override.get('course_id'), package_id=course_entry_override.get('package_id'),
branch=course_entry_override.get('branch') branch=course_entry_override.get('branch')
) )
......
...@@ -3,7 +3,7 @@ Provides full versioning CRUD and representation for collections of xblocks (e.g ...@@ -3,7 +3,7 @@ Provides full versioning CRUD and representation for collections of xblocks (e.g
Representation: Representation:
* course_index: a dictionary: * course_index: a dictionary:
** '_id': course_id (e.g., myu.mydept.mycourse.myrun), ** '_id': package_id (e.g., myu.mydept.mycourse.myrun),
** 'org': the org's id. Only used for searching not identity, ** 'org': the org's id. Only used for searching not identity,
** 'prettyid': a vague to-be-determined field probably more useful to storing searchable tags, ** 'prettyid': a vague to-be-determined field probably more useful to storing searchable tags,
** 'edited_by': user_id of user who created the original entry, ** 'edited_by': user_id of user who created the original entry,
...@@ -227,7 +227,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -227,7 +227,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
return the CourseDescriptor! It returns the actual db json from return the CourseDescriptor! It returns the actual db json from
structures. structures.
Semantics: if course_id and branch given, then it will get that branch. If Semantics: if package_id and branch given, then it will get that branch. If
also give a version_guid, it will see if the current head of that branch == that guid. If not also give a version_guid, it will see if the current head of that branch == that guid. If not
it raises VersionConflictError (the version now differs from what it was when you got your it raises VersionConflictError (the version now differs from what it was when you got your
reference) reference)
...@@ -239,9 +239,9 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -239,9 +239,9 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
if not course_locator.is_fully_specified(): if not course_locator.is_fully_specified():
raise InsufficientSpecificationError('Not fully specified: %s' % course_locator) raise InsufficientSpecificationError('Not fully specified: %s' % course_locator)
if course_locator.course_id is not None and course_locator.branch is not None: if course_locator.package_id is not None and course_locator.branch is not None:
# use the course_id # use the package_id
index = self.db_connection.get_course_index(course_locator.course_id) index = self.db_connection.get_course_index(course_locator.package_id)
if index is None: if index is None:
raise ItemNotFoundError(course_locator) raise ItemNotFoundError(course_locator)
if course_locator.branch not in index['versions']: if course_locator.branch not in index['versions']:
...@@ -258,11 +258,11 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -258,11 +258,11 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
version_guid = course_locator.as_object_id(version_guid) version_guid = course_locator.as_object_id(version_guid)
entry = self.db_connection.get_structure(version_guid) entry = self.db_connection.get_structure(version_guid)
# b/c more than one course can use same structure, the 'course_id' and 'branch' are not intrinsic to structure # b/c more than one course can use same structure, the 'package_id' and 'branch' are not intrinsic to structure
# and the one assoc'd w/ it by another fetch may not be the one relevant to this fetch; so, # and the one assoc'd w/ it by another fetch may not be the one relevant to this fetch; so,
# add it in the envelope for the structure. # add it in the envelope for the structure.
envelope = { envelope = {
'course_id': course_locator.course_id, 'package_id': course_locator.package_id,
'branch': course_locator.branch, 'branch': course_locator.branch,
'structure': entry, 'structure': entry,
} }
...@@ -300,7 +300,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -300,7 +300,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
result = [] result = []
for entry in course_entries: for entry in course_entries:
envelope = { envelope = {
'course_id': id_version_map[entry['_id']], 'package_id': id_version_map[entry['_id']],
'branch': branch, 'branch': branch,
'structure': entry, 'structure': entry,
} }
...@@ -327,7 +327,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -327,7 +327,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
''' '''
return self.get_course(location) return self.get_course(location)
def has_item(self, course_id, block_location): def has_item(self, package_id, block_location):
""" """
Returns True if location exists in its course. Returns false if Returns True if location exists in its course. Returns false if
the course or the block w/in the course do not exist for the given version. the course or the block w/in the course do not exist for the given version.
...@@ -433,13 +433,13 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -433,13 +433,13 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
return [BlockUsageLocator(url=locator.as_course_locator(), block_id=parent_id) return [BlockUsageLocator(url=locator.as_course_locator(), block_id=parent_id)
for parent_id in items] for parent_id in items]
def get_orphans(self, course_id, detached_categories, branch): def get_orphans(self, package_id, detached_categories, branch):
""" """
Return a dict of all of the orphans in the course. Return a dict of all of the orphans in the course.
:param course_id: :param package_id:
""" """
course = self._lookup_course(CourseLocator(course_id=course_id, branch=branch)) course = self._lookup_course(CourseLocator(package_id=package_id, branch=branch))
items = set(course['structure']['blocks'].keys()) items = set(course['structure']['blocks'].keys())
items.remove(course['structure']['root']) items.remove(course['structure']['root'])
for block_id, block_data in course['structure']['blocks'].iteritems(): for block_id, block_data in course['structure']['blocks'].iteritems():
...@@ -447,7 +447,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -447,7 +447,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
if block_data['category'] in detached_categories: if block_data['category'] in detached_categories:
items.discard(block_id) items.discard(block_id)
return [ return [
BlockUsageLocator(course_id=course_id, branch=branch, block_id=block_id) BlockUsageLocator(package_id=package_id, branch=branch, block_id=block_id)
for block_id in items for block_id in items
] ]
...@@ -456,7 +456,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -456,7 +456,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
The index records the initial creation of the indexed course and tracks the current version The index records the initial creation of the indexed course and tracks the current version
heads. This function is primarily for test verification but may serve some heads. This function is primarily for test verification but may serve some
more general purpose. more general purpose.
:param course_locator: must have a course_id set :param course_locator: must have a package_id set
:return {'org': , 'prettyid': , :return {'org': , 'prettyid': ,
versions: {'draft': the head draft version id, versions: {'draft': the head draft version id,
'published': the head published version id if any, 'published': the head published version id if any,
...@@ -465,9 +465,9 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -465,9 +465,9 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
'edited_on': when the course was originally created 'edited_on': when the course was originally created
} }
""" """
if course_locator.course_id is None: if course_locator.package_id is None:
return None return None
index = self.db_connection.get_course_index(course_locator.course_id) index = self.db_connection.get_course_index(course_locator.package_id)
return index return index
# TODO figure out a way to make this info accessible from the course descriptor # TODO figure out a way to make this info accessible from the course descriptor
...@@ -662,7 +662,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -662,7 +662,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
serial += 1 serial += 1
return category + str(serial) return category + str(serial)
def _generate_course_id(self, id_root): def _generate_package_id(self, id_root):
""" """
Generate a somewhat readable course id unique w/in this db using the id_root Generate a somewhat readable course id unique w/in this db using the id_root
:param course_blocks: the current list of blocks. :param course_blocks: the current list of blocks.
...@@ -699,7 +699,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -699,7 +699,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
merely the containing course. merely the containing course.
raises InsufficientSpecificationError if there is no course locator. raises InsufficientSpecificationError if there is no course locator.
raises VersionConflictError if course_id and version_guid given and the current version head != version_guid raises VersionConflictError if package_id and version_guid given and the current version head != version_guid
and force is not True. and force is not True.
:param force: fork the structure and don't update the course draftVersion if the above :param force: fork the structure and don't update the course draftVersion if the above
:param continue_revision: for multistep transactions, continue revising the given version rather than creating :param continue_revision: for multistep transactions, continue revising the given version rather than creating
...@@ -724,11 +724,11 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -724,11 +724,11 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
Rules for course locator: Rules for course locator:
* If the course locator specifies a course_id and either it doesn't * If the course locator specifies a package_id and either it doesn't
specify version_guid or the one it specifies == the current head of the branch, specify version_guid or the one it specifies == the current head of the branch,
it progresses the course to point it progresses the course to point
to the new head and sets the active version to point to the new head to the new head and sets the active version to point to the new head
* If the locator has a course_id but its version_guid != current head, it raises VersionConflictError. * If the locator has a package_id but its version_guid != current head, it raises VersionConflictError.
NOTE: using a version_guid will end up creating a new version of the course. Your new item won't be in NOTE: using a version_guid will end up creating a new version of the course. Your new item won't be in
the course id'd by version_guid but instead in one w/ a new version_guid. Ensure in this case that you get the course id'd by version_guid but instead in one w/ a new version_guid. Ensure in this case that you get
...@@ -805,7 +805,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -805,7 +805,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
course_parent = None course_parent = None
# reconstruct the new_item from the cache # reconstruct the new_item from the cache
return self.get_item(BlockUsageLocator(course_id=course_parent, return self.get_item(BlockUsageLocator(package_id=course_parent,
block_id=new_block_id, block_id=new_block_id,
version_guid=new_id)) version_guid=new_id))
...@@ -818,7 +818,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -818,7 +818,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
Create a new entry in the active courses index which points to an existing or new structure. Returns Create a new entry in the active courses index which points to an existing or new structure. Returns
the course root of the resulting entry (the location has the course id) the course root of the resulting entry (the location has the course id)
id_root: allows the caller to specify the course_id. It's a root in that, if it's already taken, id_root: allows the caller to specify the package_id. It's a root in that, if it's already taken,
this method will append things to the root to make it unique. (defaults to org) this method will append things to the root to make it unique. (defaults to org)
fields: if scope.settings fields provided, will set the fields of the root course object in the fields: if scope.settings fields provided, will set the fields of the root course object in the
...@@ -911,7 +911,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -911,7 +911,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
# create the index entry # create the index entry
if id_root is None: if id_root is None:
id_root = org id_root = org
new_id = self._generate_course_id(id_root) new_id = self._generate_package_id(id_root)
index_entry = { index_entry = {
'_id': new_id, '_id': new_id,
...@@ -921,7 +921,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -921,7 +921,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
'edited_on': datetime.datetime.now(UTC), 'edited_on': datetime.datetime.now(UTC),
'versions': versions_dict} 'versions': versions_dict}
self.db_connection.insert_course_index(index_entry) self.db_connection.insert_course_index(index_entry)
return self.get_course(CourseLocator(course_id=new_id, branch=master_branch)) return self.get_course(CourseLocator(package_id=new_id, branch=master_branch))
def update_item(self, descriptor, user_id, force=False): def update_item(self, descriptor, user_id, force=False):
""" """
...@@ -930,7 +930,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -930,7 +930,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
raises ItemNotFoundError if the location does not exist. raises ItemNotFoundError if the location does not exist.
Creates a new course version. If the descriptor's location has a course_id, it moves the course head Creates a new course version. If the descriptor's location has a package_id, it moves the course head
pointer. If the version_guid of the descriptor points to a non-head version and there's been an intervening pointer. If the version_guid of the descriptor points to a non-head version and there's been an intervening
change to this item, it raises a VersionConflictError unless force is True. In the force case, it forks change to this item, it raises a VersionConflictError unless force is True. In the force case, it forks
the course but leaves the head pointer where it is (this change will not be in the course head). the course but leaves the head pointer where it is (this change will not be in the course head).
...@@ -1019,7 +1019,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -1019,7 +1019,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
# fetch and return the new item--fetching is unnecessary but a good qc step # fetch and return the new item--fetching is unnecessary but a good qc step
return self.get_item( return self.get_item(
BlockUsageLocator( BlockUsageLocator(
course_id=xblock.location.course_id, package_id=xblock.location.package_id,
block_id=xblock.location.block_id, block_id=xblock.location.block_id,
branch=xblock.location.branch, branch=xblock.location.branch,
version_guid=new_id version_guid=new_id
...@@ -1143,7 +1143,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -1143,7 +1143,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
""" """
# get the destination's index, and source and destination structures. # get the destination's index, and source and destination structures.
source_structure = self._lookup_course(source_course)['structure'] source_structure = self._lookup_course(source_course)['structure']
index_entry = self.db_connection.get_course_index(destination_course.course_id) index_entry = self.db_connection.get_course_index(destination_course.package_id)
if index_entry is None: if index_entry is None:
# brand new course # brand new course
raise ItemNotFoundError(destination_course) raise ItemNotFoundError(destination_course)
...@@ -1207,7 +1207,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -1207,7 +1207,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
raises ItemNotFoundError if the location does not exist. raises ItemNotFoundError if the location does not exist.
raises ValueError if usage_locator points to the structure root raises ValueError if usage_locator points to the structure root
Creates a new course version. If the descriptor's location has a course_id, it moves the course head Creates a new course version. If the descriptor's location has a package_id, it moves the course head
pointer. If the version_guid of the descriptor points to a non-head version and there's been an intervening pointer. If the version_guid of the descriptor points to a non-head version and there's been an intervening
change to this item, it raises a VersionConflictError unless force is True. In the force case, it forks change to this item, it raises a VersionConflictError unless force is True. In the force case, it forks
the course but leaves the head pointer where it is (this change will not be in the course head). the course but leaves the head pointer where it is (this change will not be in the course head).
...@@ -1249,12 +1249,12 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -1249,12 +1249,12 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
# update the index entry if appropriate # update the index entry if appropriate
if index_entry is not None: if index_entry is not None:
self._update_head(index_entry, usage_locator.branch, new_id) self._update_head(index_entry, usage_locator.branch, new_id)
result.course_id = usage_locator.course_id result.package_id = usage_locator.package_id
result.branch = usage_locator.branch result.branch = usage_locator.branch
return result return result
def delete_course(self, course_id): def delete_course(self, package_id):
""" """
Remove the given course from the course index. Remove the given course from the course index.
...@@ -1262,11 +1262,11 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -1262,11 +1262,11 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
with a versions hash to restore the course; however, the edited_on and with a versions hash to restore the course; however, the edited_on and
edited_by won't reflect the originals, of course. edited_by won't reflect the originals, of course.
:param course_id: uses course_id rather than locator to emphasize its global effect :param package_id: uses package_id rather than locator to emphasize its global effect
""" """
index = self.db_connection.get_course_index(course_id) index = self.db_connection.get_course_index(package_id)
if index is None: if index is None:
raise ItemNotFoundError(course_id) raise ItemNotFoundError(package_id)
# this is the only real delete in the system. should it do something else? # this is the only real delete in the system. should it do something else?
self.db_connection.delete_course_index(index['_id']) self.db_connection.delete_course_index(index['_id'])
...@@ -1405,7 +1405,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -1405,7 +1405,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
:param continue_version: if True, assumes this operation requires a head version and will not create a new :param continue_version: if True, assumes this operation requires a head version and will not create a new
version but instead continue an existing transaction on this version. This flag cannot be True if force is True. version but instead continue an existing transaction on this version. This flag cannot be True if force is True.
""" """
if locator.course_id is None or locator.branch is None: if locator.package_id is None or locator.branch is None:
if continue_version: if continue_version:
raise InsufficientSpecificationError( raise InsufficientSpecificationError(
"To continue a version, the locator must point to one ({}).".format(locator) "To continue a version, the locator must point to one ({}).".format(locator)
...@@ -1413,7 +1413,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase): ...@@ -1413,7 +1413,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
else: else:
return None return None
else: else:
index_entry = self.db_connection.get_course_index(locator.course_id) index_entry = self.db_connection.get_course_index(locator.package_id)
is_head = ( is_head = (
locator.version_guid is None or locator.version_guid is None or
index_entry['versions'][locator.branch] == locator.version_guid index_entry['versions'][locator.branch] == locator.version_guid
......
...@@ -75,9 +75,9 @@ class TestLocationMapper(unittest.TestCase): ...@@ -75,9 +75,9 @@ class TestLocationMapper(unittest.TestCase):
self.assertEqual(entry['prod_branch'], 'live') self.assertEqual(entry['prod_branch'], 'live')
self.assertEqual(entry['block_map'], block_map) self.assertEqual(entry['block_map'], block_map)
def translate_n_check(self, location, old_style_course_id, new_style_course_id, block_id, branch, add_entry=False): def translate_n_check(self, location, old_style_course_id, new_style_package_id, block_id, branch, add_entry=False):
""" """
Request translation, check course_id, block_id, and branch Request translation, check package_id, block_id, and branch
""" """
prob_locator = loc_mapper().translate_location( prob_locator = loc_mapper().translate_location(
old_style_course_id, old_style_course_id,
...@@ -85,7 +85,7 @@ class TestLocationMapper(unittest.TestCase): ...@@ -85,7 +85,7 @@ class TestLocationMapper(unittest.TestCase):
published= (branch=='published'), published= (branch=='published'),
add_entry_if_missing=add_entry add_entry_if_missing=add_entry
) )
self.assertEqual(prob_locator.course_id, new_style_course_id) self.assertEqual(prob_locator.package_id, new_style_package_id)
self.assertEqual(prob_locator.block_id, block_id) self.assertEqual(prob_locator.block_id, block_id)
self.assertEqual(prob_locator.branch, branch) self.assertEqual(prob_locator.branch, branch)
...@@ -104,7 +104,7 @@ class TestLocationMapper(unittest.TestCase): ...@@ -104,7 +104,7 @@ class TestLocationMapper(unittest.TestCase):
add_entry_if_missing=False add_entry_if_missing=False
) )
new_style_course_id = '{}.geek_dept.{}.baz_run'.format(org, course) new_style_package_id = '{}.geek_dept.{}.baz_run'.format(org, course)
block_map = { block_map = {
'abc123': {'problem': 'problem2'}, 'abc123': {'problem': 'problem2'},
'def456': {'problem': 'problem4'}, 'def456': {'problem': 'problem4'},
...@@ -112,15 +112,15 @@ class TestLocationMapper(unittest.TestCase): ...@@ -112,15 +112,15 @@ class TestLocationMapper(unittest.TestCase):
} }
loc_mapper().create_map_entry( loc_mapper().create_map_entry(
Location('i4x', org, course, 'course', 'baz_run'), Location('i4x', org, course, 'course', 'baz_run'),
new_style_course_id, new_style_package_id,
block_map=block_map block_map=block_map
) )
test_problem_locn = Location('i4x', org, course, 'problem', 'abc123') test_problem_locn = Location('i4x', org, course, 'problem', 'abc123')
# only one course matches # only one course matches
self.translate_n_check(test_problem_locn, old_style_course_id, new_style_course_id, 'problem2', 'published') self.translate_n_check(test_problem_locn, old_style_course_id, new_style_package_id, 'problem2', 'published')
# look for w/ only the Location (works b/c there's only one possible course match). Will force # look for w/ only the Location (works b/c there's only one possible course match). Will force
# cache as default translation for this problemid # cache as default translation for this problemid
self.translate_n_check(test_problem_locn, None, new_style_course_id, 'problem2', 'published') self.translate_n_check(test_problem_locn, None, new_style_package_id, 'problem2', 'published')
# look for non-existent problem # look for non-existent problem
with self.assertRaises(ItemNotFoundError): with self.assertRaises(ItemNotFoundError):
loc_mapper().translate_location( loc_mapper().translate_location(
...@@ -143,7 +143,7 @@ class TestLocationMapper(unittest.TestCase): ...@@ -143,7 +143,7 @@ class TestLocationMapper(unittest.TestCase):
block_map=distractor_block_map block_map=distractor_block_map
) )
# test that old translation still works # test that old translation still works
self.translate_n_check(test_problem_locn, old_style_course_id, new_style_course_id, 'problem2', 'published') self.translate_n_check(test_problem_locn, old_style_course_id, new_style_package_id, 'problem2', 'published')
# and new returns new id # and new returns new id
self.translate_n_check(test_problem_locn, test_delta_old_id, test_delta_new_id, 'problem3', 'published') self.translate_n_check(test_problem_locn, test_delta_old_id, test_delta_new_id, 'problem3', 'published')
# look for default translation of uncached Location (not unique; so, just verify it returns something) # look for default translation of uncached Location (not unique; so, just verify it returns something)
...@@ -177,24 +177,24 @@ class TestLocationMapper(unittest.TestCase): ...@@ -177,24 +177,24 @@ class TestLocationMapper(unittest.TestCase):
old_style_course_id = '{}/{}/{}'.format(org, course, 'baz_run') old_style_course_id = '{}/{}/{}'.format(org, course, 'baz_run')
problem_name = 'abc123abc123abc123abc123abc123f9' problem_name = 'abc123abc123abc123abc123abc123f9'
location = Location('i4x', org, course, 'problem', problem_name) location = Location('i4x', org, course, 'problem', problem_name)
new_style_course_id = '{}.{}.{}'.format(org, course, 'baz_run') new_style_package_id = '{}.{}.{}'.format(org, course, 'baz_run')
self.translate_n_check(location, old_style_course_id, new_style_course_id, 'problemabc', 'published', True) self.translate_n_check(location, old_style_course_id, new_style_package_id, 'problemabc', 'published', True)
# look for w/ only the Location (works b/c there's only one possible course match): causes cache # look for w/ only the Location (works b/c there's only one possible course match): causes cache
self.translate_n_check(location, None, new_style_course_id, 'problemabc', 'published', True) self.translate_n_check(location, None, new_style_package_id, 'problemabc', 'published', True)
# create an entry w/o a guid name # create an entry w/o a guid name
other_location = Location('i4x', org, course, 'chapter', 'intro') other_location = Location('i4x', org, course, 'chapter', 'intro')
self.translate_n_check(other_location, old_style_course_id, new_style_course_id, 'intro', 'published', True) self.translate_n_check(other_location, old_style_course_id, new_style_package_id, 'intro', 'published', True)
# add a distractor course # add a distractor course
delta_new_course_id = '{}.geek_dept.{}.{}'.format(org, course, 'delta_run') delta_new_package_id = '{}.geek_dept.{}.{}'.format(org, course, 'delta_run')
delta_course_locn = Location('i4x', org, course, 'course', 'delta_run') delta_course_locn = Location('i4x', org, course, 'course', 'delta_run')
loc_mapper().create_map_entry( loc_mapper().create_map_entry(
delta_course_locn, delta_course_locn,
delta_new_course_id, delta_new_package_id,
block_map={problem_name: {'problem': 'problem3'}} block_map={problem_name: {'problem': 'problem3'}}
) )
self.translate_n_check(location, old_style_course_id, new_style_course_id, 'problemabc', 'published', True) self.translate_n_check(location, old_style_course_id, new_style_package_id, 'problemabc', 'published', True)
# add a new one to both courses (ensure name doesn't have same beginning) # add a new one to both courses (ensure name doesn't have same beginning)
new_prob_name = uuid.uuid4().hex new_prob_name = uuid.uuid4().hex
...@@ -202,9 +202,9 @@ class TestLocationMapper(unittest.TestCase): ...@@ -202,9 +202,9 @@ class TestLocationMapper(unittest.TestCase):
new_prob_name = uuid.uuid4().hex new_prob_name = uuid.uuid4().hex
new_prob_locn = location.replace(name=new_prob_name) new_prob_locn = location.replace(name=new_prob_name)
new_usage_id = 'problem{}'.format(new_prob_name[:3]) new_usage_id = 'problem{}'.format(new_prob_name[:3])
self.translate_n_check(new_prob_locn, old_style_course_id, new_style_course_id, new_usage_id, 'published', True) self.translate_n_check(new_prob_locn, old_style_course_id, new_style_package_id, new_usage_id, 'published', True)
self.translate_n_check( self.translate_n_check(
new_prob_locn, delta_course_locn.course_id, delta_new_course_id, new_usage_id, 'published', True new_prob_locn, delta_course_locn.course_id, delta_new_package_id, new_usage_id, 'published', True
) )
# look for w/ only the Location: causes caching and not unique; so, can't check which course # look for w/ only the Location: causes caching and not unique; so, can't check which course
prob_locator = loc_mapper().translate_location( prob_locator = loc_mapper().translate_location(
...@@ -217,7 +217,7 @@ class TestLocationMapper(unittest.TestCase): ...@@ -217,7 +217,7 @@ class TestLocationMapper(unittest.TestCase):
# add a default course pointing to the delta_run # add a default course pointing to the delta_run
loc_mapper().create_map_entry( loc_mapper().create_map_entry(
Location('i4x', org, course, 'problem', '789abc123efg456'), Location('i4x', org, course, 'problem', '789abc123efg456'),
delta_new_course_id, delta_new_package_id,
block_map={problem_name: {'problem': 'problem3'}} block_map={problem_name: {'problem': 'problem3'}}
) )
# now the ambiguous query should return delta # now the ambiguous query should return delta
...@@ -226,11 +226,11 @@ class TestLocationMapper(unittest.TestCase): ...@@ -226,11 +226,11 @@ class TestLocationMapper(unittest.TestCase):
again_prob_name = uuid.uuid4().hex again_prob_name = uuid.uuid4().hex
again_prob_locn = location.replace(name=again_prob_name) again_prob_locn = location.replace(name=again_prob_name)
again_usage_id = 'problem{}'.format(again_prob_name[:3]) again_usage_id = 'problem{}'.format(again_prob_name[:3])
self.translate_n_check(again_prob_locn, old_style_course_id, new_style_course_id, again_usage_id, 'published', True) self.translate_n_check(again_prob_locn, old_style_course_id, new_style_package_id, again_usage_id, 'published', True)
self.translate_n_check( self.translate_n_check(
again_prob_locn, delta_course_locn.course_id, delta_new_course_id, again_usage_id, 'published', True again_prob_locn, delta_course_locn.course_id, delta_new_package_id, again_usage_id, 'published', True
) )
self.translate_n_check(again_prob_locn, None, delta_new_course_id, again_usage_id, 'published', True) self.translate_n_check(again_prob_locn, None, delta_new_package_id, again_usage_id, 'published', True)
def test_translate_locator(self): def test_translate_locator(self):
""" """
...@@ -239,9 +239,9 @@ class TestLocationMapper(unittest.TestCase): ...@@ -239,9 +239,9 @@ class TestLocationMapper(unittest.TestCase):
# lookup for non-existent course # lookup for non-existent course
org = 'foo_org' org = 'foo_org'
course = 'bar_course' course = 'bar_course'
new_style_course_id = '{}.geek_dept.{}.baz_run'.format(org, course) new_style_package_id = '{}.geek_dept.{}.baz_run'.format(org, course)
prob_locator = BlockUsageLocator( prob_locator = BlockUsageLocator(
course_id=new_style_course_id, package_id=new_style_package_id,
block_id='problem2', block_id='problem2',
branch='published' branch='published'
) )
...@@ -250,7 +250,7 @@ class TestLocationMapper(unittest.TestCase): ...@@ -250,7 +250,7 @@ class TestLocationMapper(unittest.TestCase):
loc_mapper().create_map_entry( loc_mapper().create_map_entry(
Location('i4x', org, course, 'course', 'baz_run'), Location('i4x', org, course, 'course', 'baz_run'),
new_style_course_id, new_style_package_id,
block_map={ block_map={
'abc123': {'problem': 'problem2'}, 'abc123': {'problem': 'problem2'},
'48f23a10395384929234': {'chapter': 'chapter48f'}, '48f23a10395384929234': {'chapter': 'chapter48f'},
...@@ -266,20 +266,20 @@ class TestLocationMapper(unittest.TestCase): ...@@ -266,20 +266,20 @@ class TestLocationMapper(unittest.TestCase):
self.assertEqual(prob_location, Location('i4x', org, course, 'course', 'baz_run', None)) self.assertEqual(prob_location, Location('i4x', org, course, 'course', 'baz_run', None))
# explicit branch # explicit branch
prob_locator = BlockUsageLocator( prob_locator = BlockUsageLocator(
course_id=prob_locator.course_id, branch='draft', block_id=prob_locator.block_id package_id=prob_locator.package_id, branch='draft', block_id=prob_locator.block_id
) )
prob_location = loc_mapper().translate_locator_to_location(prob_locator) prob_location = loc_mapper().translate_locator_to_location(prob_locator)
# Even though the problem was set as draft, we always return revision=None to work # Even though the problem was set as draft, we always return revision=None to work
# with old mongo/draft modulestores. # with old mongo/draft modulestores.
self.assertEqual(prob_location, Location('i4x', org, course, 'problem', 'abc123', None)) self.assertEqual(prob_location, Location('i4x', org, course, 'problem', 'abc123', None))
prob_locator = BlockUsageLocator( prob_locator = BlockUsageLocator(
course_id=new_style_course_id, block_id='problem2', branch='production' package_id=new_style_package_id, block_id='problem2', branch='production'
) )
prob_location = loc_mapper().translate_locator_to_location(prob_locator) prob_location = loc_mapper().translate_locator_to_location(prob_locator)
self.assertEqual(prob_location, Location('i4x', org, course, 'problem', 'abc123', None)) self.assertEqual(prob_location, Location('i4x', org, course, 'problem', 'abc123', None))
# same for chapter except chapter cannot be draft in old system # same for chapter except chapter cannot be draft in old system
chap_locator = BlockUsageLocator( chap_locator = BlockUsageLocator(
course_id=new_style_course_id, package_id=new_style_package_id,
block_id='chapter48f', block_id='chapter48f',
branch='production' branch='production'
) )
...@@ -290,14 +290,14 @@ class TestLocationMapper(unittest.TestCase): ...@@ -290,14 +290,14 @@ class TestLocationMapper(unittest.TestCase):
chap_location = loc_mapper().translate_locator_to_location(chap_locator) chap_location = loc_mapper().translate_locator_to_location(chap_locator)
self.assertEqual(chap_location, Location('i4x', org, course, 'chapter', '48f23a10395384929234')) self.assertEqual(chap_location, Location('i4x', org, course, 'chapter', '48f23a10395384929234'))
chap_locator = BlockUsageLocator( chap_locator = BlockUsageLocator(
course_id=new_style_course_id, block_id='chapter48f', branch='production' package_id=new_style_package_id, block_id='chapter48f', branch='production'
) )
chap_location = loc_mapper().translate_locator_to_location(chap_locator) chap_location = loc_mapper().translate_locator_to_location(chap_locator)
self.assertEqual(chap_location, Location('i4x', org, course, 'chapter', '48f23a10395384929234')) self.assertEqual(chap_location, Location('i4x', org, course, 'chapter', '48f23a10395384929234'))
# look for non-existent problem # look for non-existent problem
prob_locator2 = BlockUsageLocator( prob_locator2 = BlockUsageLocator(
course_id=new_style_course_id, package_id=new_style_package_id,
branch='draft', branch='draft',
block_id='problem3' block_id='problem3'
) )
...@@ -305,10 +305,10 @@ class TestLocationMapper(unittest.TestCase): ...@@ -305,10 +305,10 @@ class TestLocationMapper(unittest.TestCase):
self.assertIsNone(prob_location, 'Found non-existent problem') self.assertIsNone(prob_location, 'Found non-existent problem')
# add a distractor course # add a distractor course
new_style_course_id = '{}.geek_dept.{}.{}'.format(org, course, 'delta_run') new_style_package_id = '{}.geek_dept.{}.{}'.format(org, course, 'delta_run')
loc_mapper().create_map_entry( loc_mapper().create_map_entry(
Location('i4x', org, course, 'course', 'delta_run'), Location('i4x', org, course, 'course', 'delta_run'),
new_style_course_id, new_style_package_id,
block_map={'abc123': {'problem': 'problem3'}} block_map={'abc123': {'problem': 'problem3'}}
) )
prob_location = loc_mapper().translate_locator_to_location(prob_locator) prob_location = loc_mapper().translate_locator_to_location(prob_locator)
...@@ -317,12 +317,12 @@ class TestLocationMapper(unittest.TestCase): ...@@ -317,12 +317,12 @@ class TestLocationMapper(unittest.TestCase):
# add a default course pointing to the delta_run # add a default course pointing to the delta_run
loc_mapper().create_map_entry( loc_mapper().create_map_entry(
Location('i4x', org, course, 'problem', '789abc123efg456'), Location('i4x', org, course, 'problem', '789abc123efg456'),
new_style_course_id, new_style_package_id,
block_map={'abc123': {'problem': 'problem3'}} block_map={'abc123': {'problem': 'problem3'}}
) )
# now query delta (2 entries point to it) # now query delta (2 entries point to it)
prob_locator = BlockUsageLocator( prob_locator = BlockUsageLocator(
course_id=new_style_course_id, package_id=new_style_package_id,
branch='production', branch='production',
block_id='problem3' block_id='problem3'
) )
......
...@@ -24,14 +24,14 @@ class LocatorTest(TestCase): ...@@ -24,14 +24,14 @@ class LocatorTest(TestCase):
OverSpecificationError, OverSpecificationError,
CourseLocator, CourseLocator,
url='edx://mit.eecs.6002x', url='edx://mit.eecs.6002x',
course_id='harvard.history', package_id='harvard.history',
branch='published', branch='published',
version_guid=ObjectId()) version_guid=ObjectId())
self.assertRaises( self.assertRaises(
OverSpecificationError, OverSpecificationError,
CourseLocator, CourseLocator,
url='edx://mit.eecs.6002x', url='edx://mit.eecs.6002x',
course_id='harvard.history', package_id='harvard.history',
version_guid=ObjectId()) version_guid=ObjectId())
self.assertRaises( self.assertRaises(
OverSpecificationError, OverSpecificationError,
...@@ -41,7 +41,7 @@ class LocatorTest(TestCase): ...@@ -41,7 +41,7 @@ class LocatorTest(TestCase):
self.assertRaises( self.assertRaises(
OverSpecificationError, OverSpecificationError,
CourseLocator, CourseLocator,
course_id='mit.eecs.6002x/' + BRANCH_PREFIX + 'published', package_id='mit.eecs.6002x/' + BRANCH_PREFIX + 'published',
branch='draft') branch='draft')
def test_course_constructor_underspecified(self): def test_course_constructor_underspecified(self):
...@@ -71,9 +71,9 @@ class LocatorTest(TestCase): ...@@ -71,9 +71,9 @@ class LocatorTest(TestCase):
self.assertEqual(str(testobj_2), VERSION_PREFIX + test_id_2_loc) self.assertEqual(str(testobj_2), VERSION_PREFIX + test_id_2_loc)
self.assertEqual(testobj_2.url(), 'edx://' + VERSION_PREFIX + test_id_2_loc) self.assertEqual(testobj_2.url(), 'edx://' + VERSION_PREFIX + test_id_2_loc)
def test_course_constructor_bad_course_id(self): def test_course_constructor_bad_package_id(self):
""" """
Test all sorts of badly-formed course_ids (and urls with those course_ids) Test all sorts of badly-formed package_ids (and urls with those package_ids)
""" """
for bad_id in (' mit.eecs', for bad_id in (' mit.eecs',
'mit.eecs ', 'mit.eecs ',
...@@ -91,7 +91,7 @@ class LocatorTest(TestCase): ...@@ -91,7 +91,7 @@ class LocatorTest(TestCase):
'mit.eecs/' + BRANCH_PREFIX + 'this ', 'mit.eecs/' + BRANCH_PREFIX + 'this ',
'mit.eecs/' + BRANCH_PREFIX + 'th%is ', 'mit.eecs/' + BRANCH_PREFIX + 'th%is ',
): ):
self.assertRaises(ValueError, CourseLocator, course_id=bad_id) self.assertRaises(ValueError, CourseLocator, package_id=bad_id)
self.assertRaises(ValueError, CourseLocator, url='edx://' + bad_id) self.assertRaises(ValueError, CourseLocator, url='edx://' + bad_id)
def test_course_constructor_bad_url(self): def test_course_constructor_bad_url(self):
...@@ -103,16 +103,16 @@ class LocatorTest(TestCase): ...@@ -103,16 +103,16 @@ class LocatorTest(TestCase):
def test_course_constructor_redundant_001(self): def test_course_constructor_redundant_001(self):
testurn = 'mit.eecs.6002x' testurn = 'mit.eecs.6002x'
testobj = CourseLocator(course_id=testurn, url='edx://' + testurn) testobj = CourseLocator(package_id=testurn, url='edx://' + testurn)
self.check_course_locn_fields(testobj, 'course_id', course_id=testurn) self.check_course_locn_fields(testobj, 'package_id', package_id=testurn)
def test_course_constructor_redundant_002(self): def test_course_constructor_redundant_002(self):
testurn = 'mit.eecs.6002x/' + BRANCH_PREFIX + 'published' testurn = 'mit.eecs.6002x/' + BRANCH_PREFIX + 'published'
expected_urn = 'mit.eecs.6002x' expected_urn = 'mit.eecs.6002x'
expected_rev = 'published' expected_rev = 'published'
testobj = CourseLocator(course_id=testurn, url='edx://' + testurn) testobj = CourseLocator(package_id=testurn, url='edx://' + testurn)
self.check_course_locn_fields(testobj, 'course_id', self.check_course_locn_fields(testobj, 'package_id',
course_id=expected_urn, package_id=expected_urn,
branch=expected_rev) branch=expected_rev)
def test_course_constructor_url(self): def test_course_constructor_url(self):
...@@ -126,71 +126,71 @@ class LocatorTest(TestCase): ...@@ -126,71 +126,71 @@ class LocatorTest(TestCase):
version_guid=ObjectId(test_id_loc) version_guid=ObjectId(test_id_loc)
) )
def test_course_constructor_url_course_id_and_version_guid(self): def test_course_constructor_url_package_id_and_version_guid(self):
test_id_loc = '519665f6223ebd6980884f2b' test_id_loc = '519665f6223ebd6980884f2b'
testobj = CourseLocator(url='edx://mit.eecs-honors.6002x/' + VERSION_PREFIX + test_id_loc) testobj = CourseLocator(url='edx://mit.eecs-honors.6002x/' + VERSION_PREFIX + test_id_loc)
self.check_course_locn_fields(testobj, 'error parsing url with both course ID and version GUID', self.check_course_locn_fields(testobj, 'error parsing url with both course ID and version GUID',
course_id='mit.eecs-honors.6002x', package_id='mit.eecs-honors.6002x',
version_guid=ObjectId(test_id_loc)) version_guid=ObjectId(test_id_loc))
def test_course_constructor_url_course_id_branch_and_version_guid(self): def test_course_constructor_url_package_id_branch_and_version_guid(self):
test_id_loc = '519665f6223ebd6980884f2b' test_id_loc = '519665f6223ebd6980884f2b'
testobj = CourseLocator(url='edx://mit.eecs.~6002x/' + BRANCH_PREFIX + 'draft-1/' + VERSION_PREFIX + test_id_loc) testobj = CourseLocator(url='edx://mit.eecs.~6002x/' + BRANCH_PREFIX + 'draft-1/' + VERSION_PREFIX + test_id_loc)
self.check_course_locn_fields(testobj, 'error parsing url with both course ID branch, and version GUID', self.check_course_locn_fields(testobj, 'error parsing url with both course ID branch, and version GUID',
course_id='mit.eecs.~6002x', package_id='mit.eecs.~6002x',
branch='draft-1', branch='draft-1',
version_guid=ObjectId(test_id_loc)) version_guid=ObjectId(test_id_loc))
def test_course_constructor_course_id_no_branch(self): def test_course_constructor_package_id_no_branch(self):
testurn = 'mit.eecs.6002x' testurn = 'mit.eecs.6002x'
testobj = CourseLocator(course_id=testurn) testobj = CourseLocator(package_id=testurn)
self.check_course_locn_fields(testobj, 'course_id', course_id=testurn) self.check_course_locn_fields(testobj, 'package_id', package_id=testurn)
self.assertEqual(testobj.course_id, testurn) self.assertEqual(testobj.package_id, testurn)
self.assertEqual(str(testobj), testurn) self.assertEqual(str(testobj), testurn)
self.assertEqual(testobj.url(), 'edx://' + testurn) self.assertEqual(testobj.url(), 'edx://' + testurn)
def test_course_constructor_course_id_with_branch(self): def test_course_constructor_package_id_with_branch(self):
testurn = 'mit.eecs.6002x/' + BRANCH_PREFIX + 'published' testurn = 'mit.eecs.6002x/' + BRANCH_PREFIX + 'published'
expected_id = 'mit.eecs.6002x' expected_id = 'mit.eecs.6002x'
expected_branch = 'published' expected_branch = 'published'
testobj = CourseLocator(course_id=testurn) testobj = CourseLocator(package_id=testurn)
self.check_course_locn_fields(testobj, 'course_id with branch', self.check_course_locn_fields(testobj, 'package_id with branch',
course_id=expected_id, package_id=expected_id,
branch=expected_branch, branch=expected_branch,
) )
self.assertEqual(testobj.course_id, expected_id) self.assertEqual(testobj.package_id, expected_id)
self.assertEqual(testobj.branch, expected_branch) self.assertEqual(testobj.branch, expected_branch)
self.assertEqual(str(testobj), testurn) self.assertEqual(str(testobj), testurn)
self.assertEqual(testobj.url(), 'edx://' + testurn) self.assertEqual(testobj.url(), 'edx://' + testurn)
def test_course_constructor_course_id_separate_branch(self): def test_course_constructor_package_id_separate_branch(self):
test_id = 'mit.eecs.6002x' test_id = 'mit.eecs.6002x'
test_branch = 'published' test_branch = 'published'
expected_urn = 'mit.eecs.6002x/' + BRANCH_PREFIX + 'published' expected_urn = 'mit.eecs.6002x/' + BRANCH_PREFIX + 'published'
testobj = CourseLocator(course_id=test_id, branch=test_branch) testobj = CourseLocator(package_id=test_id, branch=test_branch)
self.check_course_locn_fields(testobj, 'course_id with separate branch', self.check_course_locn_fields(testobj, 'package_id with separate branch',
course_id=test_id, package_id=test_id,
branch=test_branch, branch=test_branch,
) )
self.assertEqual(testobj.course_id, test_id) self.assertEqual(testobj.package_id, test_id)
self.assertEqual(testobj.branch, test_branch) self.assertEqual(testobj.branch, test_branch)
self.assertEqual(str(testobj), expected_urn) self.assertEqual(str(testobj), expected_urn)
self.assertEqual(testobj.url(), 'edx://' + expected_urn) self.assertEqual(testobj.url(), 'edx://' + expected_urn)
def test_course_constructor_course_id_repeated_branch(self): def test_course_constructor_package_id_repeated_branch(self):
""" """
The same branch appears in the course_id and the branch field. The same branch appears in the package_id and the branch field.
""" """
test_id = 'mit.eecs.6002x/' + BRANCH_PREFIX + 'published' test_id = 'mit.eecs.6002x/' + BRANCH_PREFIX + 'published'
test_branch = 'published' test_branch = 'published'
expected_id = 'mit.eecs.6002x' expected_id = 'mit.eecs.6002x'
expected_urn = test_id expected_urn = test_id
testobj = CourseLocator(course_id=test_id, branch=test_branch) testobj = CourseLocator(package_id=test_id, branch=test_branch)
self.check_course_locn_fields(testobj, 'course_id with repeated branch', self.check_course_locn_fields(testobj, 'package_id with repeated branch',
course_id=expected_id, package_id=expected_id,
branch=test_branch, branch=test_branch,
) )
self.assertEqual(testobj.course_id, expected_id) self.assertEqual(testobj.package_id, expected_id)
self.assertEqual(testobj.branch, test_branch) self.assertEqual(testobj.branch, test_branch)
self.assertEqual(str(testobj), expected_urn) self.assertEqual(str(testobj), expected_urn)
self.assertEqual(testobj.url(), 'edx://' + expected_urn) self.assertEqual(testobj.url(), 'edx://' + expected_urn)
...@@ -200,9 +200,9 @@ class LocatorTest(TestCase): ...@@ -200,9 +200,9 @@ class LocatorTest(TestCase):
expected_id = 'mit.eecs.6002x' expected_id = 'mit.eecs.6002x'
expected_branch = 'published' expected_branch = 'published'
expected_block_ref = 'HW3' expected_block_ref = 'HW3'
testobj = BlockUsageLocator(course_id=testurn) testobj = BlockUsageLocator(package_id=testurn)
self.check_block_locn_fields(testobj, 'test_block constructor', self.check_block_locn_fields(testobj, 'test_block constructor',
course_id=expected_id, package_id=expected_id,
branch=expected_branch, branch=expected_branch,
block=expected_block_ref) block=expected_block_ref)
self.assertEqual(str(testobj), testurn) self.assertEqual(str(testobj), testurn)
...@@ -210,7 +210,7 @@ class LocatorTest(TestCase): ...@@ -210,7 +210,7 @@ class LocatorTest(TestCase):
agnostic = testobj.version_agnostic() agnostic = testobj.version_agnostic()
self.assertIsNone(agnostic.version_guid) self.assertIsNone(agnostic.version_guid)
self.check_block_locn_fields(agnostic, 'test_block constructor', self.check_block_locn_fields(agnostic, 'test_block constructor',
course_id=expected_id, package_id=expected_id,
branch=expected_branch, branch=expected_branch,
block=expected_block_ref) block=expected_block_ref)
...@@ -221,7 +221,7 @@ class LocatorTest(TestCase): ...@@ -221,7 +221,7 @@ class LocatorTest(TestCase):
) )
self.check_block_locn_fields( self.check_block_locn_fields(
testobj, 'error parsing URL with version and block', testobj, 'error parsing URL with version and block',
course_id='mit.eecs.6002x', package_id='mit.eecs.6002x',
block='lab2', block='lab2',
version_guid=ObjectId(test_id_loc) version_guid=ObjectId(test_id_loc)
) )
...@@ -229,10 +229,10 @@ class LocatorTest(TestCase): ...@@ -229,10 +229,10 @@ class LocatorTest(TestCase):
self.check_block_locn_fields( self.check_block_locn_fields(
agnostic, 'error parsing URL with version and block', agnostic, 'error parsing URL with version and block',
block='lab2', block='lab2',
course_id=None, package_id=None,
version_guid=ObjectId(test_id_loc) version_guid=ObjectId(test_id_loc)
) )
self.assertIsNone(agnostic.course_id) self.assertIsNone(agnostic.package_id)
def test_block_constructor_url_kitchen_sink(self): def test_block_constructor_url_kitchen_sink(self):
test_id_loc = '519665f6223ebd6980884f2b' test_id_loc = '519665f6223ebd6980884f2b'
...@@ -243,7 +243,7 @@ class LocatorTest(TestCase): ...@@ -243,7 +243,7 @@ class LocatorTest(TestCase):
) )
self.check_block_locn_fields( self.check_block_locn_fields(
testobj, 'error parsing URL with branch, version, and block', testobj, 'error parsing URL with branch, version, and block',
course_id='mit.eecs.6002x', package_id='mit.eecs.6002x',
branch='draft', branch='draft',
block='lab2', block='lab2',
version_guid=ObjectId(test_id_loc) version_guid=ObjectId(test_id_loc)
...@@ -253,15 +253,15 @@ class LocatorTest(TestCase): ...@@ -253,15 +253,15 @@ class LocatorTest(TestCase):
""" """
It seems we used to use colons in names; so, ensure they're acceptable. It seems we used to use colons in names; so, ensure they're acceptable.
""" """
course_id = 'mit.eecs-1' package_id = 'mit.eecs-1'
branch = 'foo' branch = 'foo'
block_id = 'problem:with-colon~2' block_id = 'problem:with-colon~2'
testobj = BlockUsageLocator(course_id=course_id, branch=branch, block_id=block_id) testobj = BlockUsageLocator(package_id=package_id, branch=branch, block_id=block_id)
self.check_block_locn_fields(testobj, 'Cannot handle colon', course_id=course_id, branch=branch, block=block_id) self.check_block_locn_fields(testobj, 'Cannot handle colon', package_id=package_id, branch=branch, block=block_id)
def test_repr(self): def test_repr(self):
testurn = 'mit.eecs.6002x/' + BRANCH_PREFIX + 'published/' + BLOCK_PREFIX + 'HW3' testurn = 'mit.eecs.6002x/' + BRANCH_PREFIX + 'published/' + BLOCK_PREFIX + 'HW3'
testobj = BlockUsageLocator(course_id=testurn) testobj = BlockUsageLocator(package_id=testurn)
self.assertEqual('BlockUsageLocator("mit.eecs.6002x/branch/published/block/HW3")', repr(testobj)) self.assertEqual('BlockUsageLocator("mit.eecs.6002x/branch/published/block/HW3")', repr(testobj))
def test_old_location_helpers(self): def test_old_location_helpers(self):
...@@ -275,7 +275,7 @@ class LocatorTest(TestCase): ...@@ -275,7 +275,7 @@ class LocatorTest(TestCase):
self.assertEqual(location, Locator.to_locator_or_location(list(location_tuple))) self.assertEqual(location, Locator.to_locator_or_location(list(location_tuple)))
self.assertEqual(location, Locator.to_locator_or_location(location.dict())) self.assertEqual(location, Locator.to_locator_or_location(location.dict()))
locator = BlockUsageLocator(course_id='foo.bar', branch='alpha', block_id='deep') locator = BlockUsageLocator(package_id='foo.bar', branch='alpha', block_id='deep')
self.assertEqual(locator, Locator.to_locator_or_location(locator)) self.assertEqual(locator, Locator.to_locator_or_location(locator))
self.assertEqual(locator.as_course_locator(), Locator.to_locator_or_location(locator.as_course_locator())) self.assertEqual(locator.as_course_locator(), Locator.to_locator_or_location(locator.as_course_locator()))
self.assertEqual(location, Locator.to_locator_or_location(location.url())) self.assertEqual(location, Locator.to_locator_or_location(location.url()))
...@@ -299,7 +299,7 @@ class LocatorTest(TestCase): ...@@ -299,7 +299,7 @@ class LocatorTest(TestCase):
""" """
Test the url_reverse method Test the url_reverse method
""" """
locator = CourseLocator(course_id="a.fancy_course-id", branch="branch_1.2-3") locator = CourseLocator(package_id="a.fancy_course-id", branch="branch_1.2-3")
self.assertEqual( self.assertEqual(
'/expression/{}/format'.format(unicode(locator)), '/expression/{}/format'.format(unicode(locator)),
locator.url_reverse('expression', 'format') locator.url_reverse('expression', 'format')
...@@ -332,19 +332,19 @@ class LocatorTest(TestCase): ...@@ -332,19 +332,19 @@ class LocatorTest(TestCase):
# Utilities # Utilities
def check_course_locn_fields(self, testobj, msg, version_guid=None, def check_course_locn_fields(self, testobj, msg, version_guid=None,
course_id=None, branch=None): package_id=None, branch=None):
""" """
Checks the version, course_id, and branch in testobj Checks the version, package_id, and branch in testobj
""" """
self.assertEqual(testobj.version_guid, version_guid, msg) self.assertEqual(testobj.version_guid, version_guid, msg)
self.assertEqual(testobj.course_id, course_id, msg) self.assertEqual(testobj.package_id, package_id, msg)
self.assertEqual(testobj.branch, branch, msg) self.assertEqual(testobj.branch, branch, msg)
def check_block_locn_fields(self, testobj, msg, version_guid=None, def check_block_locn_fields(self, testobj, msg, version_guid=None,
course_id=None, branch=None, block=None): package_id=None, branch=None, block=None):
""" """
Does adds a block id check over and above the check_course_locn_fields tests Does adds a block id check over and above the check_course_locn_fields tests
""" """
self.check_course_locn_fields(testobj, msg, version_guid, course_id, self.check_course_locn_fields(testobj, msg, version_guid, package_id,
branch) branch)
self.assertEqual(testobj.block_id, block) self.assertEqual(testobj.block_id, block)
...@@ -30,7 +30,7 @@ class TestOrphan(unittest.TestCase): ...@@ -30,7 +30,7 @@ class TestOrphan(unittest.TestCase):
'xblock_mixins': (InheritanceMixin,) 'xblock_mixins': (InheritanceMixin,)
} }
split_course_id = 'test_org.test_course.runid' split_package_id = 'test_org.test_course.runid'
def setUp(self): def setUp(self):
self.db_config['collection'] = 'modulestore{0}'.format(uuid.uuid4().hex[:5]) self.db_config['collection'] = 'modulestore{0}'.format(uuid.uuid4().hex[:5])
...@@ -85,13 +85,13 @@ class TestOrphan(unittest.TestCase): ...@@ -85,13 +85,13 @@ class TestOrphan(unittest.TestCase):
self.old_mongo.update_children(parent_location, parent.children) self.old_mongo.update_children(parent_location, parent.children)
# create pointer for split # create pointer for split
course_or_parent_locator = BlockUsageLocator( course_or_parent_locator = BlockUsageLocator(
course_id=self.split_course_id, package_id=self.split_package_id,
branch='draft', branch='draft',
block_id=parent_name block_id=parent_name
) )
else: else:
course_or_parent_locator = CourseLocator( course_or_parent_locator = CourseLocator(
course_id='test_org.test_course.runid', package_id='test_org.test_course.runid',
branch='draft', branch='draft',
) )
self.split_mongo.create_item(course_or_parent_locator, category, self.userid, block_id=name, fields=fields) self.split_mongo.create_item(course_or_parent_locator, category, self.userid, block_id=name, fields=fields)
...@@ -114,7 +114,7 @@ class TestOrphan(unittest.TestCase): ...@@ -114,7 +114,7 @@ class TestOrphan(unittest.TestCase):
fields.update(data) fields.update(data)
# split requires the course to be created separately from creating items # split requires the course to be created separately from creating items
self.split_mongo.create_course( self.split_mongo.create_course(
'test_org', 'my course', self.userid, self.split_course_id, fields=fields, root_block_id='runid' 'test_org', 'my course', self.userid, self.split_package_id, fields=fields, root_block_id='runid'
) )
self.course_location = Location('i4x', 'test_org', 'test_course', 'course', 'runid') self.course_location = Location('i4x', 'test_org', 'test_course', 'course', 'runid')
self.old_mongo.create_and_save_xmodule(self.course_location, data, metadata) self.old_mongo.create_and_save_xmodule(self.course_location, data, metadata)
...@@ -148,11 +148,11 @@ class TestOrphan(unittest.TestCase): ...@@ -148,11 +148,11 @@ class TestOrphan(unittest.TestCase):
""" """
Test that old mongo finds the orphans Test that old mongo finds the orphans
""" """
orphans = self.split_mongo.get_orphans(self.split_course_id, ['static_tab', 'about', 'course_info'], 'draft') orphans = self.split_mongo.get_orphans(self.split_package_id, ['static_tab', 'about', 'course_info'], 'draft')
self.assertEqual(len(orphans), 3, "Wrong # {}".format(orphans)) self.assertEqual(len(orphans), 3, "Wrong # {}".format(orphans))
location = BlockUsageLocator(course_id=self.split_course_id, branch='draft', block_id='OrphanChapter') location = BlockUsageLocator(package_id=self.split_package_id, branch='draft', block_id='OrphanChapter')
self.assertIn(location, orphans) self.assertIn(location, orphans)
location = BlockUsageLocator(course_id=self.split_course_id, branch='draft', block_id='OrphanVert') location = BlockUsageLocator(package_id=self.split_package_id, branch='draft', block_id='OrphanVert')
self.assertIn(location, orphans) self.assertIn(location, orphans)
location = BlockUsageLocator(course_id=self.split_course_id, branch='draft', block_id='OrphanHtml') location = BlockUsageLocator(package_id=self.split_package_id, branch='draft', block_id='OrphanHtml')
self.assertIn(location, orphans) self.assertIn(location, orphans)
...@@ -120,7 +120,7 @@ class SplitModuleCourseTests(SplitModuleTest): ...@@ -120,7 +120,7 @@ class SplitModuleCourseTests(SplitModuleTest):
self.assertEqual(len(courses), 3, "Wrong number of courses") self.assertEqual(len(courses), 3, "Wrong number of courses")
# check metadata -- NOTE no promised order # check metadata -- NOTE no promised order
course = self.findByIdInResult(courses, "head12345") course = self.findByIdInResult(courses, "head12345")
self.assertEqual(course.location.course_id, "GreekHero") self.assertEqual(course.location.package_id, "GreekHero")
self.assertEqual( self.assertEqual(
str(course.location.version_guid), self.GUID_D0, str(course.location.version_guid), self.GUID_D0,
"course version mismatch" "course version mismatch"
...@@ -151,7 +151,7 @@ class SplitModuleCourseTests(SplitModuleTest): ...@@ -151,7 +151,7 @@ class SplitModuleCourseTests(SplitModuleTest):
self.assertEqual(len(courses_published), 1, len(courses_published)) self.assertEqual(len(courses_published), 1, len(courses_published))
course = self.findByIdInResult(courses_published, "head23456") course = self.findByIdInResult(courses_published, "head23456")
self.assertIsNotNone(course, "published courses") self.assertIsNotNone(course, "published courses")
self.assertEqual(course.location.course_id, "wonderful") self.assertEqual(course.location.package_id, "wonderful")
self.assertEqual(str(course.location.version_guid), self.GUID_P, self.assertEqual(str(course.location.version_guid), self.GUID_P,
course.location.version_guid) course.location.version_guid)
self.assertEqual(course.category, 'course', 'wrong category') self.assertEqual(course.category, 'course', 'wrong category')
...@@ -190,7 +190,7 @@ class SplitModuleCourseTests(SplitModuleTest): ...@@ -190,7 +190,7 @@ class SplitModuleCourseTests(SplitModuleTest):
''' '''
locator = CourseLocator(version_guid=self.GUID_D1) locator = CourseLocator(version_guid=self.GUID_D1)
course = modulestore().get_course(locator) course = modulestore().get_course(locator)
self.assertIsNone(course.location.course_id) self.assertIsNone(course.location.package_id)
self.assertEqual(str(course.location.version_guid), self.GUID_D1) self.assertEqual(str(course.location.version_guid), self.GUID_D1)
self.assertEqual(course.category, 'course') self.assertEqual(course.category, 'course')
self.assertEqual(len(course.tabs), 6) self.assertEqual(len(course.tabs), 6)
...@@ -203,9 +203,9 @@ class SplitModuleCourseTests(SplitModuleTest): ...@@ -203,9 +203,9 @@ class SplitModuleCourseTests(SplitModuleTest):
self.assertEqual(course.edited_by, "testassist@edx.org") self.assertEqual(course.edited_by, "testassist@edx.org")
self.assertDictEqual(course.grade_cutoffs, {"Pass": 0.55}) self.assertDictEqual(course.grade_cutoffs, {"Pass": 0.55})
locator = CourseLocator(course_id='GreekHero', branch='draft') locator = CourseLocator(package_id='GreekHero', branch='draft')
course = modulestore().get_course(locator) course = modulestore().get_course(locator)
self.assertEqual(course.location.course_id, "GreekHero") self.assertEqual(course.location.package_id, "GreekHero")
self.assertEqual(str(course.location.version_guid), self.GUID_D0) self.assertEqual(str(course.location.version_guid), self.GUID_D0)
self.assertEqual(course.category, 'course') self.assertEqual(course.category, 'course')
self.assertEqual(len(course.tabs), 6) self.assertEqual(len(course.tabs), 6)
...@@ -216,24 +216,24 @@ class SplitModuleCourseTests(SplitModuleTest): ...@@ -216,24 +216,24 @@ class SplitModuleCourseTests(SplitModuleTest):
self.assertEqual(course.edited_by, "testassist@edx.org") self.assertEqual(course.edited_by, "testassist@edx.org")
self.assertDictEqual(course.grade_cutoffs, {"Pass": 0.45}) self.assertDictEqual(course.grade_cutoffs, {"Pass": 0.45})
locator = CourseLocator(course_id='wonderful', branch='published') locator = CourseLocator(package_id='wonderful', branch='published')
course = modulestore().get_course(locator) course = modulestore().get_course(locator)
self.assertEqual(course.location.course_id, "wonderful") self.assertEqual(course.location.package_id, "wonderful")
self.assertEqual(str(course.location.version_guid), self.GUID_P) self.assertEqual(str(course.location.version_guid), self.GUID_P)
locator = CourseLocator(course_id='wonderful', branch='draft') locator = CourseLocator(package_id='wonderful', branch='draft')
course = modulestore().get_course(locator) course = modulestore().get_course(locator)
self.assertEqual(str(course.location.version_guid), self.GUID_D2) self.assertEqual(str(course.location.version_guid), self.GUID_D2)
def test_get_course_negative(self): def test_get_course_negative(self):
# Now negative testing # Now negative testing
self.assertRaises(InsufficientSpecificationError, self.assertRaises(InsufficientSpecificationError,
modulestore().get_course, CourseLocator(course_id='edu.meh.blah')) modulestore().get_course, CourseLocator(package_id='edu.meh.blah'))
self.assertRaises(ItemNotFoundError, self.assertRaises(ItemNotFoundError,
modulestore().get_course, CourseLocator(course_id='nosuchthing', branch='draft')) modulestore().get_course, CourseLocator(package_id='nosuchthing', branch='draft'))
self.assertRaises(ItemNotFoundError, self.assertRaises(ItemNotFoundError,
modulestore().get_course, modulestore().get_course,
CourseLocator(course_id='GreekHero', branch='published')) CourseLocator(package_id='GreekHero', branch='published'))
def test_cache(self): def test_cache(self):
""" """
...@@ -252,7 +252,7 @@ class SplitModuleCourseTests(SplitModuleTest): ...@@ -252,7 +252,7 @@ class SplitModuleCourseTests(SplitModuleTest):
locator = CourseLocator(version_guid=self.GUID_D3) locator = CourseLocator(version_guid=self.GUID_D3)
result = modulestore().get_course_successors(locator) result = modulestore().get_course_successors(locator)
self.assertIsInstance(result, VersionTree) self.assertIsInstance(result, VersionTree)
self.assertIsNone(result.locator.course_id) self.assertIsNone(result.locator.package_id)
self.assertEqual(str(result.locator.version_guid), self.GUID_D3) self.assertEqual(str(result.locator.version_guid), self.GUID_D3)
self.assertEqual(len(result.children), 1) self.assertEqual(len(result.children), 1)
self.assertEqual(str(result.children[0].locator.version_guid), self.GUID_D1) self.assertEqual(str(result.children[0].locator.version_guid), self.GUID_D1)
...@@ -275,71 +275,71 @@ class SplitModuleItemTests(SplitModuleTest): ...@@ -275,71 +275,71 @@ class SplitModuleItemTests(SplitModuleTest):
''' '''
has_item(BlockUsageLocator) has_item(BlockUsageLocator)
''' '''
course_id = 'GreekHero' package_id = 'GreekHero'
# positive tests of various forms # positive tests of various forms
locator = BlockUsageLocator(version_guid=self.GUID_D1, block_id='head12345') locator = BlockUsageLocator(version_guid=self.GUID_D1, block_id='head12345')
self.assertTrue(modulestore().has_item(course_id, locator), self.assertTrue(modulestore().has_item(package_id, locator),
"couldn't find in %s" % self.GUID_D1) "couldn't find in %s" % self.GUID_D1)
locator = BlockUsageLocator(course_id='GreekHero', block_id='head12345', branch='draft') locator = BlockUsageLocator(package_id='GreekHero', block_id='head12345', branch='draft')
self.assertTrue( self.assertTrue(
modulestore().has_item(locator.course_id, locator), modulestore().has_item(locator.package_id, locator),
"couldn't find in 12345" "couldn't find in 12345"
) )
self.assertTrue( self.assertTrue(
modulestore().has_item(locator.course_id, BlockUsageLocator( modulestore().has_item(locator.package_id, BlockUsageLocator(
course_id=locator.course_id, package_id=locator.package_id,
branch='draft', branch='draft',
block_id=locator.block_id block_id=locator.block_id
)), )),
"couldn't find in draft 12345" "couldn't find in draft 12345"
) )
self.assertFalse( self.assertFalse(
modulestore().has_item(locator.course_id, BlockUsageLocator( modulestore().has_item(locator.package_id, BlockUsageLocator(
course_id=locator.course_id, package_id=locator.package_id,
branch='published', branch='published',
block_id=locator.block_id)), block_id=locator.block_id)),
"found in published 12345" "found in published 12345"
) )
locator.branch = 'draft' locator.branch = 'draft'
self.assertTrue( self.assertTrue(
modulestore().has_item(locator.course_id, locator), modulestore().has_item(locator.package_id, locator),
"not found in draft 12345" "not found in draft 12345"
) )
# not a course obj # not a course obj
locator = BlockUsageLocator(course_id='GreekHero', block_id='chapter1', branch='draft') locator = BlockUsageLocator(package_id='GreekHero', block_id='chapter1', branch='draft')
self.assertTrue( self.assertTrue(
modulestore().has_item(locator.course_id, locator), modulestore().has_item(locator.package_id, locator),
"couldn't find chapter1" "couldn't find chapter1"
) )
# in published course # in published course
locator = BlockUsageLocator(course_id="wonderful", block_id="head23456", branch='draft') locator = BlockUsageLocator(package_id="wonderful", block_id="head23456", branch='draft')
self.assertTrue( self.assertTrue(
modulestore().has_item( modulestore().has_item(
locator.course_id, locator.package_id,
BlockUsageLocator(course_id=locator.course_id, block_id=locator.block_id, branch='published') BlockUsageLocator(package_id=locator.package_id, block_id=locator.block_id, branch='published')
), "couldn't find in 23456" ), "couldn't find in 23456"
) )
locator.branch = 'published' locator.branch = 'published'
self.assertTrue(modulestore().has_item(course_id, locator), "couldn't find in 23456") self.assertTrue(modulestore().has_item(package_id, locator), "couldn't find in 23456")
def test_negative_has_item(self): def test_negative_has_item(self):
# negative tests--not found # negative tests--not found
# no such course or block # no such course or block
course_id = 'GreekHero' package_id = 'GreekHero'
locator = BlockUsageLocator(course_id="doesnotexist", block_id="head23456", branch='draft') locator = BlockUsageLocator(package_id="doesnotexist", block_id="head23456", branch='draft')
self.assertFalse(modulestore().has_item(course_id, locator)) self.assertFalse(modulestore().has_item(package_id, locator))
locator = BlockUsageLocator(course_id="wonderful", block_id="doesnotexist", branch='draft') locator = BlockUsageLocator(package_id="wonderful", block_id="doesnotexist", branch='draft')
self.assertFalse(modulestore().has_item(course_id, locator)) self.assertFalse(modulestore().has_item(package_id, locator))
# negative tests--insufficient specification # negative tests--insufficient specification
self.assertRaises(InsufficientSpecificationError, BlockUsageLocator) self.assertRaises(InsufficientSpecificationError, BlockUsageLocator)
self.assertRaises(InsufficientSpecificationError, self.assertRaises(InsufficientSpecificationError,
modulestore().has_item, None, BlockUsageLocator(version_guid=self.GUID_D1)) modulestore().has_item, None, BlockUsageLocator(version_guid=self.GUID_D1))
self.assertRaises(InsufficientSpecificationError, self.assertRaises(InsufficientSpecificationError,
modulestore().has_item, None, BlockUsageLocator(course_id='GreekHero')) modulestore().has_item, None, BlockUsageLocator(package_id='GreekHero'))
def test_get_item(self): def test_get_item(self):
''' '''
...@@ -349,11 +349,11 @@ class SplitModuleItemTests(SplitModuleTest): ...@@ -349,11 +349,11 @@ class SplitModuleItemTests(SplitModuleTest):
locator = BlockUsageLocator(version_guid=self.GUID_D1, block_id='head12345') locator = BlockUsageLocator(version_guid=self.GUID_D1, block_id='head12345')
block = modulestore().get_item(locator) block = modulestore().get_item(locator)
self.assertIsInstance(block, CourseDescriptor) self.assertIsInstance(block, CourseDescriptor)
# get_instance just redirects to get_item, ignores course_id # get_instance just redirects to get_item, ignores package_id
self.assertIsInstance(modulestore().get_instance("course_id", locator), CourseDescriptor) self.assertIsInstance(modulestore().get_instance("package_id", locator), CourseDescriptor)
def verify_greek_hero(block): def verify_greek_hero(block):
self.assertEqual(block.location.course_id, "GreekHero") self.assertEqual(block.location.package_id, "GreekHero")
self.assertEqual(len(block.tabs), 6, "wrong number of tabs") self.assertEqual(len(block.tabs), 6, "wrong number of tabs")
self.assertEqual(block.display_name, "The Ancient Greek Hero") self.assertEqual(block.display_name, "The Ancient Greek Hero")
self.assertEqual(block.advertised_start, "Fall 2013") self.assertEqual(block.advertised_start, "Fall 2013")
...@@ -365,15 +365,15 @@ class SplitModuleItemTests(SplitModuleTest): ...@@ -365,15 +365,15 @@ class SplitModuleItemTests(SplitModuleTest):
block.grade_cutoffs, {"Pass": 0.45}, block.grade_cutoffs, {"Pass": 0.45},
) )
locator = BlockUsageLocator(course_id='GreekHero', block_id='head12345', branch='draft') locator = BlockUsageLocator(package_id='GreekHero', block_id='head12345', branch='draft')
verify_greek_hero(modulestore().get_item(locator)) verify_greek_hero(modulestore().get_item(locator))
# get_instance just redirects to get_item, ignores course_id # get_instance just redirects to get_item, ignores package_id
verify_greek_hero(modulestore().get_instance("course_id", locator)) verify_greek_hero(modulestore().get_instance("package_id", locator))
# try to look up other branches # try to look up other branches
self.assertRaises(ItemNotFoundError, self.assertRaises(ItemNotFoundError,
modulestore().get_item, modulestore().get_item,
BlockUsageLocator(course_id=locator.as_course_locator(), BlockUsageLocator(package_id=locator.as_course_locator(),
block_id=locator.block_id, block_id=locator.block_id,
branch='published')) branch='published'))
locator.branch = 'draft' locator.branch = 'draft'
...@@ -384,16 +384,16 @@ class SplitModuleItemTests(SplitModuleTest): ...@@ -384,16 +384,16 @@ class SplitModuleItemTests(SplitModuleTest):
def test_get_non_root(self): def test_get_non_root(self):
# not a course obj # not a course obj
locator = BlockUsageLocator(course_id='GreekHero', block_id='chapter1', branch='draft') locator = BlockUsageLocator(package_id='GreekHero', block_id='chapter1', branch='draft')
block = modulestore().get_item(locator) block = modulestore().get_item(locator)
self.assertEqual(block.location.course_id, "GreekHero") self.assertEqual(block.location.package_id, "GreekHero")
self.assertEqual(block.category, 'chapter') self.assertEqual(block.category, 'chapter')
self.assertEqual(str(block.definition_locator.definition_id), "cd00000000000000dddd0020") self.assertEqual(str(block.definition_locator.definition_id), "cd00000000000000dddd0020")
self.assertEqual(block.display_name, "Hercules") self.assertEqual(block.display_name, "Hercules")
self.assertEqual(block.edited_by, "testassist@edx.org") self.assertEqual(block.edited_by, "testassist@edx.org")
# in published course # in published course
locator = BlockUsageLocator(course_id="wonderful", block_id="head23456", branch='published') locator = BlockUsageLocator(package_id="wonderful", block_id="head23456", branch='published')
self.assertIsInstance( self.assertIsInstance(
modulestore().get_item(locator), modulestore().get_item(locator),
CourseDescriptor CourseDescriptor
...@@ -401,10 +401,10 @@ class SplitModuleItemTests(SplitModuleTest): ...@@ -401,10 +401,10 @@ class SplitModuleItemTests(SplitModuleTest):
# negative tests--not found # negative tests--not found
# no such course or block # no such course or block
locator = BlockUsageLocator(course_id="doesnotexist", block_id="head23456", branch='draft') locator = BlockUsageLocator(package_id="doesnotexist", block_id="head23456", branch='draft')
with self.assertRaises(ItemNotFoundError): with self.assertRaises(ItemNotFoundError):
modulestore().get_item(locator) modulestore().get_item(locator)
locator = BlockUsageLocator(course_id="wonderful", block_id="doesnotexist", branch='draft') locator = BlockUsageLocator(package_id="wonderful", block_id="doesnotexist", branch='draft')
with self.assertRaises(ItemNotFoundError): with self.assertRaises(ItemNotFoundError):
modulestore().get_item(locator) modulestore().get_item(locator)
...@@ -412,7 +412,7 @@ class SplitModuleItemTests(SplitModuleTest): ...@@ -412,7 +412,7 @@ class SplitModuleItemTests(SplitModuleTest):
with self.assertRaises(InsufficientSpecificationError): with self.assertRaises(InsufficientSpecificationError):
modulestore().get_item(BlockUsageLocator(version_guid=self.GUID_D1)) modulestore().get_item(BlockUsageLocator(version_guid=self.GUID_D1))
with self.assertRaises(InsufficientSpecificationError): with self.assertRaises(InsufficientSpecificationError):
modulestore().get_item(BlockUsageLocator(course_id='GreekHero', branch='draft')) modulestore().get_item(BlockUsageLocator(package_id='GreekHero', branch='draft'))
# pylint: disable=W0212 # pylint: disable=W0212
def test_matching(self): def test_matching(self):
...@@ -473,11 +473,11 @@ class SplitModuleItemTests(SplitModuleTest): ...@@ -473,11 +473,11 @@ class SplitModuleItemTests(SplitModuleTest):
''' '''
get_parent_locations(locator, [block_id], [branch]): [BlockUsageLocator] get_parent_locations(locator, [block_id], [branch]): [BlockUsageLocator]
''' '''
locator = BlockUsageLocator(course_id="GreekHero", branch='draft', block_id='chapter1') locator = BlockUsageLocator(package_id="GreekHero", branch='draft', block_id='chapter1')
parents = modulestore().get_parent_locations(locator) parents = modulestore().get_parent_locations(locator)
self.assertEqual(len(parents), 1) self.assertEqual(len(parents), 1)
self.assertEqual(parents[0].block_id, 'head12345') self.assertEqual(parents[0].block_id, 'head12345')
self.assertEqual(parents[0].course_id, "GreekHero") self.assertEqual(parents[0].package_id, "GreekHero")
locator.block_id = 'chapter2' locator.block_id = 'chapter2'
parents = modulestore().get_parent_locations(locator) parents = modulestore().get_parent_locations(locator)
self.assertEqual(len(parents), 1) self.assertEqual(len(parents), 1)
...@@ -490,7 +490,7 @@ class SplitModuleItemTests(SplitModuleTest): ...@@ -490,7 +490,7 @@ class SplitModuleItemTests(SplitModuleTest):
""" """
Test the existing get_children method on xdescriptors Test the existing get_children method on xdescriptors
""" """
locator = BlockUsageLocator(course_id="GreekHero", block_id="head12345", branch='draft') locator = BlockUsageLocator(package_id="GreekHero", block_id="head12345", branch='draft')
block = modulestore().get_item(locator) block = modulestore().get_item(locator)
children = block.get_children() children = block.get_children()
expected_ids = [ expected_ids = [
...@@ -532,7 +532,7 @@ class TestItemCrud(SplitModuleTest): ...@@ -532,7 +532,7 @@ class TestItemCrud(SplitModuleTest):
create_item(course_or_parent_locator, category, user, definition_locator=None, fields): new_desciptor create_item(course_or_parent_locator, category, user, definition_locator=None, fields): new_desciptor
""" """
# grab link to course to ensure new versioning works # grab link to course to ensure new versioning works
locator = CourseLocator(course_id="GreekHero", branch='draft') locator = CourseLocator(package_id="GreekHero", branch='draft')
premod_course = modulestore().get_course(locator) premod_course = modulestore().get_course(locator)
premod_time = datetime.datetime.now(UTC) - datetime.timedelta(seconds=1) premod_time = datetime.datetime.now(UTC) - datetime.timedelta(seconds=1)
# add minimal one w/o a parent # add minimal one w/o a parent
...@@ -542,7 +542,7 @@ class TestItemCrud(SplitModuleTest): ...@@ -542,7 +542,7 @@ class TestItemCrud(SplitModuleTest):
fields={'display_name': 'new sequential'} fields={'display_name': 'new sequential'}
) )
# check that course version changed and course's previous is the other one # check that course version changed and course's previous is the other one
self.assertEqual(new_module.location.course_id, "GreekHero") self.assertEqual(new_module.location.package_id, "GreekHero")
self.assertNotEqual(new_module.location.version_guid, premod_course.location.version_guid) self.assertNotEqual(new_module.location.version_guid, premod_course.location.version_guid)
self.assertIsNone(locator.version_guid, "Version inadvertently filled in") self.assertIsNone(locator.version_guid, "Version inadvertently filled in")
current_course = modulestore().get_course(locator) current_course = modulestore().get_course(locator)
...@@ -569,7 +569,7 @@ class TestItemCrud(SplitModuleTest): ...@@ -569,7 +569,7 @@ class TestItemCrud(SplitModuleTest):
""" """
Test create_item w/ specifying the parent of the new item Test create_item w/ specifying the parent of the new item
""" """
locator = BlockUsageLocator(course_id="wonderful", block_id="head23456", branch='draft') locator = BlockUsageLocator(package_id="wonderful", block_id="head23456", branch='draft')
premod_course = modulestore().get_course(locator) premod_course = modulestore().get_course(locator)
category = 'chapter' category = 'chapter'
new_module = modulestore().create_item( new_module = modulestore().create_item(
...@@ -589,7 +589,7 @@ class TestItemCrud(SplitModuleTest): ...@@ -589,7 +589,7 @@ class TestItemCrud(SplitModuleTest):
a definition id and new def data that it branches the definition in the db. a definition id and new def data that it branches the definition in the db.
Actually, this tries to test all create_item features not tested above. Actually, this tries to test all create_item features not tested above.
""" """
locator = BlockUsageLocator(course_id="contender", block_id="head345679", branch='draft') locator = BlockUsageLocator(package_id="contender", block_id="head345679", branch='draft')
category = 'problem' category = 'problem'
premod_time = datetime.datetime.now(UTC) - datetime.timedelta(seconds=1) premod_time = datetime.datetime.now(UTC) - datetime.timedelta(seconds=1)
new_payload = "<problem>empty</problem>" new_payload = "<problem>empty</problem>"
...@@ -633,7 +633,7 @@ class TestItemCrud(SplitModuleTest): ...@@ -633,7 +633,7 @@ class TestItemCrud(SplitModuleTest):
course_block_update_version = new_course.update_version course_block_update_version = new_course.update_version
self.assertIsNotNone(new_course_locator.version_guid, "Want to test a definite version") self.assertIsNotNone(new_course_locator.version_guid, "Want to test a definite version")
versionless_course_locator = CourseLocator( versionless_course_locator = CourseLocator(
course_id=new_course_locator.course_id, branch=new_course_locator.branch package_id=new_course_locator.package_id, branch=new_course_locator.branch
) )
# positive simple case: no force, add chapter # positive simple case: no force, add chapter
...@@ -687,7 +687,7 @@ class TestItemCrud(SplitModuleTest): ...@@ -687,7 +687,7 @@ class TestItemCrud(SplitModuleTest):
# add new child to old parent in continued (leave off version_guid) # add new child to old parent in continued (leave off version_guid)
course_module_locator = BlockUsageLocator( course_module_locator = BlockUsageLocator(
course_id=new_course.location.course_id, package_id=new_course.location.package_id,
block_id=new_course.location.block_id, block_id=new_course.location.block_id,
branch=new_course.location.branch branch=new_course.location.branch
) )
...@@ -709,7 +709,7 @@ class TestItemCrud(SplitModuleTest): ...@@ -709,7 +709,7 @@ class TestItemCrud(SplitModuleTest):
""" """
test updating an items metadata ensuring the definition doesn't version but the course does if it should test updating an items metadata ensuring the definition doesn't version but the course does if it should
""" """
locator = BlockUsageLocator(course_id="GreekHero", block_id="problem3_2", branch='draft') locator = BlockUsageLocator(package_id="GreekHero", block_id="problem3_2", branch='draft')
problem = modulestore().get_item(locator) problem = modulestore().get_item(locator)
pre_def_id = problem.definition_locator.definition_id pre_def_id = problem.definition_locator.definition_id
pre_version_guid = problem.location.version_guid pre_version_guid = problem.location.version_guid
...@@ -747,7 +747,7 @@ class TestItemCrud(SplitModuleTest): ...@@ -747,7 +747,7 @@ class TestItemCrud(SplitModuleTest):
""" """
test updating an item's children ensuring the definition doesn't version but the course does if it should test updating an item's children ensuring the definition doesn't version but the course does if it should
""" """
locator = BlockUsageLocator(course_id="GreekHero", block_id="chapter3", branch='draft') locator = BlockUsageLocator(package_id="GreekHero", block_id="chapter3", branch='draft')
block = modulestore().get_item(locator) block = modulestore().get_item(locator)
pre_def_id = block.definition_locator.definition_id pre_def_id = block.definition_locator.definition_id
pre_version_guid = block.location.version_guid pre_version_guid = block.location.version_guid
...@@ -773,7 +773,7 @@ class TestItemCrud(SplitModuleTest): ...@@ -773,7 +773,7 @@ class TestItemCrud(SplitModuleTest):
""" """
test updating an item's definition: ensure it gets versioned as well as the course getting versioned test updating an item's definition: ensure it gets versioned as well as the course getting versioned
""" """
locator = BlockUsageLocator(course_id="GreekHero", block_id="head12345", branch='draft') locator = BlockUsageLocator(package_id="GreekHero", block_id="head12345", branch='draft')
block = modulestore().get_item(locator) block = modulestore().get_item(locator)
pre_def_id = block.definition_locator.definition_id pre_def_id = block.definition_locator.definition_id
pre_version_guid = block.location.version_guid pre_version_guid = block.location.version_guid
...@@ -791,7 +791,7 @@ class TestItemCrud(SplitModuleTest): ...@@ -791,7 +791,7 @@ class TestItemCrud(SplitModuleTest):
Test updating metadata, children, and definition in a single call ensuring all the versioning occurs Test updating metadata, children, and definition in a single call ensuring all the versioning occurs
""" """
# first add 2 children to the course for the update to manipulate # first add 2 children to the course for the update to manipulate
locator = BlockUsageLocator(course_id="contender", block_id="head345679", branch='draft') locator = BlockUsageLocator(package_id="contender", block_id="head345679", branch='draft')
category = 'problem' category = 'problem'
new_payload = "<problem>empty</problem>" new_payload = "<problem>empty</problem>"
modulestore().create_item( modulestore().create_item(
...@@ -832,7 +832,7 @@ class TestItemCrud(SplitModuleTest): ...@@ -832,7 +832,7 @@ class TestItemCrud(SplitModuleTest):
course.location, course.location,
'deleting_user') 'deleting_user')
reusable_location = BlockUsageLocator( reusable_location = BlockUsageLocator(
course_id=course.location.course_id, package_id=course.location.package_id,
block_id=course.location.block_id, block_id=course.location.block_id,
branch='draft') branch='draft')
...@@ -840,16 +840,16 @@ class TestItemCrud(SplitModuleTest): ...@@ -840,16 +840,16 @@ class TestItemCrud(SplitModuleTest):
problems = modulestore().get_items(reusable_location, {'category': 'problem'}) problems = modulestore().get_items(reusable_location, {'category': 'problem'})
locn_to_del = problems[0].location locn_to_del = problems[0].location
new_course_loc = modulestore().delete_item(locn_to_del, 'deleting_user', delete_children=False) new_course_loc = modulestore().delete_item(locn_to_del, 'deleting_user', delete_children=False)
deleted = BlockUsageLocator(course_id=reusable_location.course_id, deleted = BlockUsageLocator(package_id=reusable_location.package_id,
branch=reusable_location.branch, branch=reusable_location.branch,
block_id=locn_to_del.block_id) block_id=locn_to_del.block_id)
self.assertFalse(modulestore().has_item(reusable_location.course_id, deleted)) self.assertFalse(modulestore().has_item(reusable_location.package_id, deleted))
self.assertRaises(VersionConflictError, modulestore().has_item, reusable_location.course_id, locn_to_del) self.assertRaises(VersionConflictError, modulestore().has_item, reusable_location.package_id, locn_to_del)
locator = BlockUsageLocator( locator = BlockUsageLocator(
version_guid=locn_to_del.version_guid, version_guid=locn_to_del.version_guid,
block_id=locn_to_del.block_id block_id=locn_to_del.block_id
) )
self.assertTrue(modulestore().has_item(reusable_location.course_id, locator)) self.assertTrue(modulestore().has_item(reusable_location.package_id, locator))
self.assertNotEqual(new_course_loc.version_guid, course.location.version_guid) self.assertNotEqual(new_course_loc.version_guid, course.location.version_guid)
# delete a subtree # delete a subtree
...@@ -860,15 +860,15 @@ class TestItemCrud(SplitModuleTest): ...@@ -860,15 +860,15 @@ class TestItemCrud(SplitModuleTest):
def check_subtree(node): def check_subtree(node):
if node: if node:
node_loc = node.location node_loc = node.location
self.assertFalse(modulestore().has_item(reusable_location.course_id, self.assertFalse(modulestore().has_item(reusable_location.package_id,
BlockUsageLocator( BlockUsageLocator(
course_id=node_loc.course_id, package_id=node_loc.package_id,
branch=node_loc.branch, branch=node_loc.branch,
block_id=node.location.block_id))) block_id=node.location.block_id)))
locator = BlockUsageLocator( locator = BlockUsageLocator(
version_guid=node.location.version_guid, version_guid=node.location.version_guid,
block_id=node.location.block_id) block_id=node.location.block_id)
self.assertTrue(modulestore().has_item(reusable_location.course_id, locator)) self.assertTrue(modulestore().has_item(reusable_location.package_id, locator))
if node.has_children: if node.has_children:
for sub in node.get_children(): for sub in node.get_children():
check_subtree(sub) check_subtree(sub)
...@@ -877,7 +877,7 @@ class TestItemCrud(SplitModuleTest): ...@@ -877,7 +877,7 @@ class TestItemCrud(SplitModuleTest):
def create_course_for_deletion(self): def create_course_for_deletion(self):
course = modulestore().create_course('nihilx', 'deletion', 'deleting_user') course = modulestore().create_course('nihilx', 'deletion', 'deleting_user')
root = BlockUsageLocator( root = BlockUsageLocator(
course_id=course.location.course_id, package_id=course.location.package_id,
block_id=course.location.block_id, block_id=course.location.block_id,
branch='draft') branch='draft')
for _ in range(4): for _ in range(4):
...@@ -934,13 +934,13 @@ class TestCourseCreation(SplitModuleTest): ...@@ -934,13 +934,13 @@ class TestCourseCreation(SplitModuleTest):
Test making a course which points to an existing draft and published but not making any changes to either. Test making a course which points to an existing draft and published but not making any changes to either.
""" """
pre_time = datetime.datetime.now(UTC) pre_time = datetime.datetime.now(UTC)
original_locator = CourseLocator(course_id="wonderful", branch='draft') original_locator = CourseLocator(package_id="wonderful", branch='draft')
original_index = modulestore().get_course_index_info(original_locator) original_index = modulestore().get_course_index_info(original_locator)
new_draft = modulestore().create_course( new_draft = modulestore().create_course(
'leech', 'best_course', 'leech_master', id_root='best', 'leech', 'best_course', 'leech_master', id_root='best',
versions_dict=original_index['versions']) versions_dict=original_index['versions'])
new_draft_locator = new_draft.location new_draft_locator = new_draft.location
self.assertRegexpMatches(new_draft_locator.course_id, r'best.*') self.assertRegexpMatches(new_draft_locator.package_id, r'best.*')
# the edited_by and other meta fields on the new course will be the original author not this one # the edited_by and other meta fields on the new course will be the original author not this one
self.assertEqual(new_draft.edited_by, 'test@edx.org') self.assertEqual(new_draft.edited_by, 'test@edx.org')
self.assertLess(new_draft.edited_on, pre_time) self.assertLess(new_draft.edited_on, pre_time)
...@@ -951,7 +951,7 @@ class TestCourseCreation(SplitModuleTest): ...@@ -951,7 +951,7 @@ class TestCourseCreation(SplitModuleTest):
self.assertLessEqual(new_index["edited_on"], datetime.datetime.now(UTC)) self.assertLessEqual(new_index["edited_on"], datetime.datetime.now(UTC))
self.assertEqual(new_index['edited_by'], 'leech_master') self.assertEqual(new_index['edited_by'], 'leech_master')
new_published_locator = CourseLocator(course_id=new_draft_locator.course_id, branch='published') new_published_locator = CourseLocator(package_id=new_draft_locator.package_id, branch='published')
new_published = modulestore().get_course(new_published_locator) new_published = modulestore().get_course(new_published_locator)
self.assertEqual(new_published.edited_by, 'test@edx.org') self.assertEqual(new_published.edited_by, 'test@edx.org')
self.assertLess(new_published.edited_on, pre_time) self.assertLess(new_published.edited_on, pre_time)
...@@ -979,7 +979,7 @@ class TestCourseCreation(SplitModuleTest): ...@@ -979,7 +979,7 @@ class TestCourseCreation(SplitModuleTest):
original_course = modulestore().get_course(original_locator) original_course = modulestore().get_course(original_locator)
self.assertEqual(original_course.location.version_guid, original_index['versions']['draft']) self.assertEqual(original_course.location.version_guid, original_index['versions']['draft'])
self.assertFalse( self.assertFalse(
modulestore().has_item(new_draft_locator.course_id, BlockUsageLocator( modulestore().has_item(new_draft_locator.package_id, BlockUsageLocator(
original_locator, original_locator,
block_id=new_item.location.block_id block_id=new_item.location.block_id
)) ))
...@@ -990,7 +990,7 @@ class TestCourseCreation(SplitModuleTest): ...@@ -990,7 +990,7 @@ class TestCourseCreation(SplitModuleTest):
Create a new course which overrides metadata and course_data Create a new course which overrides metadata and course_data
""" """
pre_time = datetime.datetime.now(UTC) pre_time = datetime.datetime.now(UTC)
original_locator = CourseLocator(course_id="contender", branch='draft') original_locator = CourseLocator(package_id="contender", branch='draft')
original = modulestore().get_course(original_locator) original = modulestore().get_course(original_locator)
original_index = modulestore().get_course_index_info(original_locator) original_index = modulestore().get_course_index_info(original_locator)
fields = {} fields = {}
...@@ -1007,7 +1007,7 @@ class TestCourseCreation(SplitModuleTest): ...@@ -1007,7 +1007,7 @@ class TestCourseCreation(SplitModuleTest):
fields=fields fields=fields
) )
new_draft_locator = new_draft.location new_draft_locator = new_draft.location
self.assertRegexpMatches(new_draft_locator.course_id, r'counter.*') self.assertRegexpMatches(new_draft_locator.package_id, r'counter.*')
# the edited_by and other meta fields on the new course will be the original author not this one # the edited_by and other meta fields on the new course will be the original author not this one
self.assertEqual(new_draft.edited_by, 'leech_master') self.assertEqual(new_draft.edited_by, 'leech_master')
self.assertGreaterEqual(new_draft.edited_on, pre_time) self.assertGreaterEqual(new_draft.edited_on, pre_time)
...@@ -1027,7 +1027,7 @@ class TestCourseCreation(SplitModuleTest): ...@@ -1027,7 +1027,7 @@ class TestCourseCreation(SplitModuleTest):
""" """
Test changing the org, pretty id, etc of a course. Test that it doesn't allow changing the id, etc. Test changing the org, pretty id, etc of a course. Test that it doesn't allow changing the id, etc.
""" """
locator = CourseLocator(course_id="GreekHero", branch='draft') locator = CourseLocator(package_id="GreekHero", branch='draft')
course_info = modulestore().get_course_index_info(locator) course_info = modulestore().get_course_index_info(locator)
course_info['org'] = 'funkyU' course_info['org'] = 'funkyU'
modulestore().update_course_index(course_info) modulestore().update_course_index(course_info)
...@@ -1051,7 +1051,7 @@ class TestCourseCreation(SplitModuleTest): ...@@ -1051,7 +1051,7 @@ class TestCourseCreation(SplitModuleTest):
# an allowed but not recommended way to publish a course # an allowed but not recommended way to publish a course
versions['published'] = self.GUID_D1 versions['published'] = self.GUID_D1
modulestore().update_course_index(course_info) modulestore().update_course_index(course_info)
course = modulestore().get_course(CourseLocator(course_id=locator.course_id, branch="published")) course = modulestore().get_course(CourseLocator(package_id=locator.package_id, branch="published"))
self.assertEqual(str(course.location.version_guid), self.GUID_D1) self.assertEqual(str(course.location.version_guid), self.GUID_D1)
def test_create_with_root(self): def test_create_with_root(self):
...@@ -1086,11 +1086,11 @@ class TestInheritance(SplitModuleTest): ...@@ -1086,11 +1086,11 @@ class TestInheritance(SplitModuleTest):
""" """
# Note, not testing value where defined (course) b/c there's no # Note, not testing value where defined (course) b/c there's no
# defined accessor for it on CourseDescriptor. # defined accessor for it on CourseDescriptor.
locator = BlockUsageLocator(course_id="GreekHero", block_id="problem3_2", branch='draft') locator = BlockUsageLocator(package_id="GreekHero", block_id="problem3_2", branch='draft')
node = modulestore().get_item(locator) node = modulestore().get_item(locator)
# inherited # inherited
self.assertEqual(node.graceperiod, datetime.timedelta(hours=2)) self.assertEqual(node.graceperiod, datetime.timedelta(hours=2))
locator = BlockUsageLocator(course_id="GreekHero", block_id="problem1", branch='draft') locator = BlockUsageLocator(package_id="GreekHero", block_id="problem1", branch='draft')
node = modulestore().get_item(locator) node = modulestore().get_item(locator)
# overridden # overridden
self.assertEqual(node.graceperiod, datetime.timedelta(hours=4)) self.assertEqual(node.graceperiod, datetime.timedelta(hours=4))
...@@ -1111,8 +1111,8 @@ class TestPublish(SplitModuleTest): ...@@ -1111,8 +1111,8 @@ class TestPublish(SplitModuleTest):
""" """
Test the standard patterns: publish to new branch, revise and publish Test the standard patterns: publish to new branch, revise and publish
""" """
source_course = CourseLocator(course_id="GreekHero", branch='draft') source_course = CourseLocator(package_id="GreekHero", branch='draft')
dest_course = CourseLocator(course_id="GreekHero", branch="published") dest_course = CourseLocator(package_id="GreekHero", branch="published")
modulestore().xblock_publish(self.user, source_course, dest_course, ["head12345"], ["chapter2", "chapter3"]) modulestore().xblock_publish(self.user, source_course, dest_course, ["head12345"], ["chapter2", "chapter3"])
expected = ["head12345", "chapter1"] expected = ["head12345", "chapter1"]
self._check_course( self._check_course(
...@@ -1153,13 +1153,13 @@ class TestPublish(SplitModuleTest): ...@@ -1153,13 +1153,13 @@ class TestPublish(SplitModuleTest):
""" """
Test the exceptions which preclude successful publication Test the exceptions which preclude successful publication
""" """
source_course = CourseLocator(course_id="GreekHero", branch='draft') source_course = CourseLocator(package_id="GreekHero", branch='draft')
# destination does not exist # destination does not exist
destination_course = CourseLocator(course_id="Unknown", branch="published") destination_course = CourseLocator(package_id="Unknown", branch="published")
with self.assertRaises(ItemNotFoundError): with self.assertRaises(ItemNotFoundError):
modulestore().xblock_publish(self.user, source_course, destination_course, ["chapter3"], None) modulestore().xblock_publish(self.user, source_course, destination_course, ["chapter3"], None)
# publishing into a new branch w/o publishing the root # publishing into a new branch w/o publishing the root
destination_course = CourseLocator(course_id="GreekHero", branch="published") destination_course = CourseLocator(package_id="GreekHero", branch="published")
with self.assertRaises(ItemNotFoundError): with self.assertRaises(ItemNotFoundError):
modulestore().xblock_publish(self.user, source_course, destination_course, ["chapter3"], None) modulestore().xblock_publish(self.user, source_course, destination_course, ["chapter3"], None)
# publishing a subdag w/o the parent already in course # publishing a subdag w/o the parent already in course
...@@ -1171,8 +1171,8 @@ class TestPublish(SplitModuleTest): ...@@ -1171,8 +1171,8 @@ class TestPublish(SplitModuleTest):
""" """
Test publishing moves and deletes. Test publishing moves and deletes.
""" """
source_course = CourseLocator(course_id="GreekHero", branch='draft') source_course = CourseLocator(package_id="GreekHero", branch='draft')
dest_course = CourseLocator(course_id="GreekHero", branch="published") dest_course = CourseLocator(package_id="GreekHero", branch="published")
modulestore().xblock_publish(self.user, source_course, dest_course, ["head12345"], ["chapter2"]) modulestore().xblock_publish(self.user, source_course, dest_course, ["head12345"], ["chapter2"])
expected = ["head12345", "chapter1", "chapter3", "problem1", "problem3_2"] expected = ["head12345", "chapter1", "chapter3", "problem1", "problem3_2"]
self._check_course(source_course, dest_course, expected, ["chapter2"]) self._check_course(source_course, dest_course, expected, ["chapter2"])
...@@ -1210,7 +1210,7 @@ class TestPublish(SplitModuleTest): ...@@ -1210,7 +1210,7 @@ class TestPublish(SplitModuleTest):
""" """
Generate a BlockUsageLocator for the combo of the course location and block id Generate a BlockUsageLocator for the combo of the course location and block id
""" """
return BlockUsageLocator(course_id=course_loc.course_id, branch=course_loc.branch, block_id=block_id) return BlockUsageLocator(package_id=course_loc.package_id, branch=course_loc.branch, block_id=block_id)
def _compare_children(self, source_children, dest_children, unexpected): def _compare_children(self, source_children, dest_children, unexpected):
""" """
......
...@@ -10,7 +10,7 @@ from django.contrib.auth.models import User, Group ...@@ -10,7 +10,7 @@ from django.contrib.auth.models import User, Group
from xmodule.modulestore import Location from xmodule.modulestore import Location
from xmodule.modulestore.exceptions import InvalidLocationError, ItemNotFoundError from xmodule.modulestore.exceptions import InvalidLocationError, ItemNotFoundError
from xmodule.modulestore.django import loc_mapper from xmodule.modulestore.django import loc_mapper
from xmodule.modulestore.locator import CourseLocator from xmodule.modulestore.locator import CourseLocator, Locator
class CourseContextRequired(Exception): class CourseContextRequired(Exception):
...@@ -144,29 +144,29 @@ class CourseRole(GroupBasedRole): ...@@ -144,29 +144,29 @@ class CourseRole(GroupBasedRole):
""" """
# TODO: figure out how to make the group name generation lazy so it doesn't force the # TODO: figure out how to make the group name generation lazy so it doesn't force the
# loc mapping? # loc mapping?
if not hasattr(location, 'course_id'): location = Locator.to_locator_or_location(location)
location = Location(location)
# direct copy from auth.authz.get_all_course_role_groupnames will refactor to one impl asap # direct copy from auth.authz.get_all_course_role_groupnames will refactor to one impl asap
groupnames = [] groupnames = []
try:
groupnames.append('{0}_{1}'.format(role, location.course_id))
except InvalidLocationError: # will occur on old locations where location is not of category course
if course_context is None:
raise CourseContextRequired()
else:
groupnames.append('{0}_{1}'.format(role, course_context))
# pylint: disable=no-member # pylint: disable=no-member
if isinstance(location, Location): if isinstance(location, Location):
try: try:
groupnames.append('{0}_{1}'.format(role, location.course_id))
except InvalidLocationError: # will occur on old locations where location is not of category course
if course_context is None:
raise CourseContextRequired()
else:
groupnames.append('{0}_{1}'.format(role, course_context))
try:
locator = loc_mapper().translate_location(location.course_id, location, False, False) locator = loc_mapper().translate_location(location.course_id, location, False, False)
groupnames.append('{0}_{1}'.format(role, locator.course_id)) groupnames.append('{0}_{1}'.format(role, locator.package_id))
except (InvalidLocationError, ItemNotFoundError): except (InvalidLocationError, ItemNotFoundError):
# if it's never been mapped, the auth won't be via the Locator syntax # if it's never been mapped, the auth won't be via the Locator syntax
pass pass
# least preferred legacy role_course format # least preferred legacy role_course format
groupnames.append('{0}_{1}'.format(role, location.course)) groupnames.append('{0}_{1}'.format(role, location.course))
elif isinstance(location, CourseLocator): elif isinstance(location, CourseLocator):
groupnames.append('{0}_{1}'.format(role, location.package_id))
# handle old Location syntax # handle old Location syntax
old_location = loc_mapper().translate_locator_to_location(location, get_course=True) old_location = loc_mapper().translate_locator_to_location(location, get_course=True)
if old_location: if old_location:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment