Commit b7368ef6 by Don Mitchell

Change course_id to package_id

on new Locators to make it clear that they have a different syntax
than Location.course_id altho they represent the same info.
parent 6c4aae73
......@@ -37,23 +37,21 @@ def get_all_course_role_groupnames(location, role, use_filter=True):
'''
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 = []
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):
# least preferred role_course format
groupnames.append('{0}_{1}'.format(role, location.course))
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
try:
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):
pass
# least preferred role_course format for legacy reasons
groupnames.append('{0}_{1}'.format(role, location.course))
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)
if old_location:
# the slashified version of the course_id (myu/mycourse/myrun)
......
......@@ -136,13 +136,13 @@ class TemplateTests(unittest.TestCase):
persistent_factories.ItemFactory.create(display_name='chapter 1',
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)
# verify it can be retireved by id
self.assertIsInstance(modulestore('split').get_course(id_locator), CourseDescriptor)
# and by guid
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
self.assertRaises(ItemNotFoundError, modulestore('split').get_course, id_locator)
# but can by guid
......
......@@ -90,7 +90,7 @@ class TestCourseAccess(ModuleStoreTestCase):
# first check the groupname for the course creator.
self.assertTrue(
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(),
"Didn't add creator as instructor."
)
......@@ -124,4 +124,4 @@ class TestCourseAccess(ModuleStoreTestCase):
for role in [INSTRUCTOR_ROLE_NAME, STAFF_ROLE_NAME]:
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_location), "{} no copy access".format(user))
\ No newline at end of file
self.assertTrue(has_access(user, copy_course_location), "{} no copy access".format(user))
......@@ -34,7 +34,7 @@ __all__ = ['assets_handler']
@login_required
@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.
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=
DELETE
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):
raise PermissionDenied()
......
......@@ -26,7 +26,7 @@ __all__ = ['checklists_handler']
@require_http_methods(("GET", "POST", "PUT"))
@login_required
@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.
......@@ -36,7 +36,7 @@ def checklists_handler(request, tag=None, course_id=None, branch=None, version_g
POST or PUT
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):
raise PermissionDenied()
......
......@@ -53,7 +53,7 @@ ADVANCED_COMPONENT_POLICY_KEY = 'advanced_modules'
@require_http_methods(["GET"])
@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.
......@@ -62,7 +62,7 @@ def subsection_handler(request, tag=None, course_id=None, branch=None, version_g
json: not currently supported
"""
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:
old_location, course, item, lms_link = _get_item_in_course(request, locator)
except ItemNotFoundError:
......@@ -142,7 +142,7 @@ def _load_mixed_class(category):
@require_http_methods(["GET"])
@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.
......@@ -151,7 +151,7 @@ def unit_handler(request, tag=None, course_id=None, branch=None, version_guid=No
json: not currently supported
"""
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:
old_location, course, item, lms_link = _get_item_in_course(request, locator)
except ItemNotFoundError:
......
......@@ -60,12 +60,12 @@ __all__ = ['course_info_handler', 'course_handler', 'course_info_update_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
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):
raise PermissionDenied()
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
# pylint: disable=unused-argument
@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.
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=
index entry.
PUT
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
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=
return create_new_course(request)
elif not has_access(
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()
elif request.method == 'PUT':
......@@ -114,10 +114,10 @@ def course_handler(request, tag=None, course_id=None, branch=None, version_guid=
else:
return HttpResponseBadRequest()
elif request.method == 'GET': # assume html
if course_id is None:
if package_id is None:
return course_listing(request)
else:
return course_index(request, course_id, branch, version_guid, block)
return course_index(request, package_id, branch, version_guid, block)
else:
return HttpResponseNotFound()
......@@ -157,9 +157,7 @@ def course_listing(request):
course.display_name,
# note, couldn't get django reverse to work; so, wrote workaround
course_loc.url_reverse('course/', ''),
get_lms_link_for_item(
course.location
),
get_lms_link_for_item(course.location),
course.display_org_with_default,
course.display_number_with_default,
course.location.name
......@@ -175,14 +173,14 @@ def course_listing(request):
@login_required
@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.
org, course, name: Attributes of the Location for the item to edit
"""
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)
sections = course.get_children()
......@@ -315,13 +313,13 @@ def create_new_course(request):
@login_required
@ensure_csrf_cookie
@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
html: return html for editing the course info handouts and updates.
"""
__, 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'):
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_
@ensure_csrf_cookie
@require_http_methods(("GET", "POST", "PUT", "DELETE"))
@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):
"""
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
"""
if 'application/json' not in request.META.get('HTTP_ACCEPT', 'application/json'):
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)
if provided_id == '':
provided_id = None
......@@ -400,7 +398,7 @@ def course_info_update_handler(request, tag=None, course_id=None, branch=None, v
@ensure_csrf_cookie
@require_http_methods(("GET", "PUT", "POST"))
@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
GET
......@@ -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
"""
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':
upload_asset_url = locator.url_reverse('assets/')
......@@ -444,7 +442,7 @@ def settings_handler(request, tag=None, course_id=None, branch=None, version_gui
@ensure_csrf_cookie
@require_http_methods(("GET", "POST", "PUT", "DELETE"))
@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
GET
......@@ -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)
"""
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':
......@@ -550,7 +548,7 @@ def _config_course_advanced_components(request, course_module):
@ensure_csrf_cookie
@require_http_methods(("GET", "POST", "PUT"))
@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
GET
......@@ -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
"""
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':
......@@ -652,7 +650,7 @@ def assign_textbook_id(textbook, used_ids=()):
@require_http_methods(("GET", "POST", "PUT"))
@login_required
@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.
......@@ -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
"""
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)
......@@ -729,7 +727,7 @@ def textbooks_list_handler(request, tag=None, course_id=None, branch=None, versi
@login_required
@ensure_csrf_cookie
@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.
Used by the Backbone application.
......@@ -742,7 +740,7 @@ def textbooks_detail_handler(request, tid, tag=None, course_id=None, branch=None
json: remove textbook
"""
__, 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)
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
@login_required
@ensure_csrf_cookie
@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.
......@@ -60,7 +60,7 @@ def import_handler(request, tag=None, course_id=None, branch=None, version_guid=
POST or PUT
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):
raise PermissionDenied()
......@@ -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
session_status = request.session.setdefault("import_status", {})
key = location.course_id + filename
key = location.package_id + filename
session_status[key] = 1
request.session.modified = True
......@@ -261,7 +261,7 @@ def import_handler(request, tag=None, course_id=None, branch=None, version_guid=
@require_GET
@ensure_csrf_cookie
@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:
......@@ -271,13 +271,13 @@ def import_status_handler(request, tag=None, course_id=None, branch=None, versio
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):
raise PermissionDenied()
try:
session_status = request.session["import_status"]
status = session_status[location.course_id + filename]
status = session_status[location.package_id + filename]
except KeyError:
status = 0
......@@ -287,7 +287,7 @@ def import_status_handler(request, tag=None, course_id=None, branch=None, versio
@ensure_csrf_cookie
@login_required
@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.
......@@ -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
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):
raise PermissionDenied()
......
......@@ -47,7 +47,7 @@ CREATE_IF_NOT_FOUND = ['course_info']
@require_http_methods(("DELETE", "GET", "PUT", "POST"))
@login_required
@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.
......@@ -78,8 +78,8 @@ def xblock_handler(request, tag=None, course_id=None, branch=None, version_guid=
:boilerplate: template name for populating fields, optional
The locator (and old-style id) for the created xblock (minus children) is returned.
"""
if course_id is not None:
locator = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block)
if package_id is not None:
locator = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
if not has_access(request.user, locator):
raise PermissionDenied()
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=
delete_all_versions = str_to_bool(request.REQUEST.get('all_versions', 'False'))
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(
request,
locator,
......@@ -133,7 +133,7 @@ def xblock_handler(request, tag=None, course_id=None, branch=None, version_guid=
return _create_item(request)
else:
return HttpResponseBadRequest(
"Only instance creation is supported without a course_id.",
"Only instance creation is supported without a package_id.",
content_type="text/plain"
)
......@@ -319,7 +319,7 @@ def _delete_item_at_location(item_location, delete_children=False, delete_all_ve
# pylint: disable=W0613
@login_required
@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.
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=
from the root via children
: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
old_location = loc_mapper().translate_locator_to_location(location)
if request.method == 'GET':
......
......@@ -48,7 +48,7 @@ def initialize_course_tabs(course):
@login_required
@ensure_csrf_cookie
@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.
......@@ -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.
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):
raise PermissionDenied()
......
......@@ -40,7 +40,7 @@ def request_course_creator(request):
@login_required
@ensure_csrf_cookie
@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.
......@@ -52,7 +52,7 @@ def course_team_handler(request, tag=None, course_id=None, branch=None, version_
DELETE:
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):
raise PermissionDenied()
......
......@@ -17,7 +17,6 @@ from xblock.fields import Scope, List, String, Dict, Boolean
from .fields import Date
from xmodule.modulestore.locator import CourseLocator
from django.utils.timezone import UTC
from xmodule.util import date_utils
log = logging.getLogger(__name__)
......@@ -400,7 +399,7 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
if isinstance(self.location, Location):
self.wiki_slug = self.location.course
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:
# For existing courses with show_timezone set to False (and no due_date_display_format specified),
......
......@@ -51,21 +51,21 @@ class LocMapperStore(object):
self.cache = cache
# 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):
"""
Add a new entry to map this course_location to the new style CourseLocator.course_id. If course_id is not
provided, it creates the default map of using org.course.name from the location (just like course_id) if
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 if
the location.category = 'course'; otherwise, it uses org.course.
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
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
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.
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):
: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
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.
:param course_id: the CourseLocator style course_id
a "default" map for the org/course pair to a new package_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
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
......@@ -86,11 +86,11 @@ class LocMapperStore(object):
: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.
"""
if course_id is None:
if package_id is None:
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:
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
location_id = self._construct_location_son(
course_location.org, course_location.course,
......@@ -99,12 +99,12 @@ class LocMapperStore(object):
self.location_map.insert({
'_id': location_id,
'course_id': course_id,
'course_id': package_id,
'draft_branch': draft_branch,
'prod_branch': prod_branch,
'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):
"""
......@@ -174,9 +174,9 @@ class LocMapperStore(object):
raise InvalidLocationError()
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(
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:
result = published_usage
else:
......@@ -199,13 +199,13 @@ class LocMapperStore(object):
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.
:param locator: a BlockUsageLocator
"""
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:
cached_value = self._get_location_from_cache(locator)
if cached_value:
......@@ -213,7 +213,7 @@ class LocMapperStore(object):
# This does not require that the course exist in any modulestore
# 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
if maps.count() == 0:
return None
......@@ -365,12 +365,12 @@ class LocMapperStore(object):
"""
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.
"""
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):
"""
......@@ -380,7 +380,7 @@ class LocMapperStore(object):
"""
setmany = {}
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(draft_usage)] = location
setmany['{}+{}'.format(old_course_id, location.url())] = (published_usage, draft_usage)
......
......@@ -12,7 +12,7 @@ from bson.errors import InvalidId
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
import re
from xmodule.modulestore import Location
......@@ -149,15 +149,15 @@ class CourseLocator(Locator):
"""
Examples of valid CourseLocator specifications:
CourseLocator(version_guid=ObjectId('519665f6223ebd6980884f2b'))
CourseLocator(course_id='mit.eecs.6002x')
CourseLocator(course_id='mit.eecs.6002x/branch/published')
CourseLocator(course_id='mit.eecs.6002x', branch='published')
CourseLocator(package_id='mit.eecs.6002x')
CourseLocator(package_id='mit.eecs.6002x/branch/published')
CourseLocator(package_id='mit.eecs.6002x', branch='published')
CourseLocator(url='edx://version/519665f6223ebd6980884f2b')
CourseLocator(url='edx://mit.eecs.6002x')
CourseLocator(url='edx://mit.eecs.6002x/branch/published')
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',
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
......@@ -166,47 +166,47 @@ class CourseLocator(Locator):
# Default values
version_guid = None
course_id = None
package_id = 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
Caller may provide url (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
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
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:
self.init_from_url(url)
if version_guid:
self.init_from_version_guid(version_guid)
if course_id or branch:
self.init_from_course_id(course_id, branch)
if self.version_guid is None and self.course_id is None:
raise ValueError("Either version_guid or course_id should be set: {}".format(url))
if package_id or branch:
self.init_from_package_id(package_id, branch)
if self.version_guid is None and self.package_id is None:
raise ValueError("Either version_guid or package_id should be set: {}".format(url))
def __unicode__(self):
"""
Return a string representing this location.
"""
if self.course_id:
result = self.course_id
if self.package_id:
result = self.package_id
if self.branch:
result += '/' + BRANCH_PREFIX + self.branch
return result
elif self.version_guid:
return VERSION_PREFIX + str(self.version_guid)
else:
# raise InsufficientSpecificationError("missing course_id or version_guid")
return '<InsufficientSpecificationError: missing course_id or version_guid>'
# raise InsufficientSpecificationError("missing package_id or version_guid")
return '<InsufficientSpecificationError: missing package_id or version_guid>'
def url(self):
"""
......@@ -214,29 +214,29 @@ class CourseLocator(Locator):
"""
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
arg and doesn't use keyword
"""
if not any((url, version_guid, course_id)):
raise InsufficientSpecificationError("Must provide one of url, version_guid, course_id")
if not any((url, version_guid, package_id)):
raise InsufficientSpecificationError("Must provide one of url, version_guid, package_id")
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.
This should always return True, since this should be validated in the constructor.
"""
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.
If course_id has already been initialized to a different value, raise an exception.
Initialize package_id to new value.
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):
"""
......@@ -259,7 +259,7 @@ class CourseLocator(Locator):
The copy does not include subclass information, such as
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,
branch=self.branch)
......@@ -285,7 +285,7 @@ class CourseLocator(Locator):
def init_from_url(self, url):
"""
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):
parse = url.__dict__
......@@ -298,7 +298,7 @@ class CourseLocator(Locator):
self._set_value(
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)
def init_from_version_guid(self, version_guid):
......@@ -313,29 +313,29 @@ class CourseLocator(Locator):
raise TypeError('%s is not an instance of ObjectId' % 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'.
It may be provided explicitly (explicit_branch) or embedded into course_id.
If branch is part of course_id (".../branch/published"), parse it out separately.
It may be provided explicitly (explicit_branch) or embedded into package_id.
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 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 isinstance(course_id, CourseLocator):
course_id = course_id.course_id
if not course_id:
raise ValueError("%s does not have a valid course_id" % course_id)
if package_id:
if isinstance(package_id, CourseLocator):
package_id = package_id.package_id
if not package_id:
raise ValueError("%s does not have a valid package_id" % package_id)
parse = parse_course_id(course_id)
if not parse or parse['course_id'] is None:
raise ValueError('Could not parse "%s" as a course_id' % course_id)
self.set_course_id(parse['course_id'])
parse = parse_package_id(package_id)
if not parse or parse['package_id'] is None:
raise ValueError('Could not parse "%s" as a package_id' % package_id)
self.set_package_id(parse['package_id'])
rev = parse['branch']
if rev:
self.set_branch(rev)
......@@ -357,7 +357,7 @@ class CourseLocator(Locator):
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).
"""
return self.course_id
return self.package_id
def _set_value(self, parse, key, setter):
"""
......@@ -379,12 +379,12 @@ class BlockUsageLocator(CourseLocator):
the defined element in the course. Courses can be a version of an offering, the
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 !=
the version_guid)
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
branch : string
"""
......@@ -392,34 +392,34 @@ class BlockUsageLocator(CourseLocator):
# Default value
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):
"""
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 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.
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
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:
self.init_block_ref_from_str(url)
if course_id:
self.init_block_ref_from_course_id(course_id)
if package_id:
self.init_block_ref_from_package_id(package_id)
if block_id:
self.init_block_ref(block_id)
super(BlockUsageLocator, self).__init__(
url=url,
version_guid=version_guid,
course_id=course_id,
package_id=package_id,
branch=branch
)
......@@ -432,7 +432,7 @@ class BlockUsageLocator(CourseLocator):
def version_agnostic(self):
"""
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
by reducing info.
......@@ -444,7 +444,7 @@ class BlockUsageLocator(CourseLocator):
branch=self.branch,
block_id=self.block_id)
else:
return BlockUsageLocator(course_id=self.course_id,
return BlockUsageLocator(package_id=self.package_id,
branch=self.branch,
block_id=self.block_id)
......@@ -478,13 +478,13 @@ class BlockUsageLocator(CourseLocator):
raise ValueError('Could not parse "%s" as a url' % value)
self._set_value(parse, 'block', self.set_block_id)
def init_block_ref_from_course_id(self, course_id):
if isinstance(course_id, CourseLocator):
course_id = course_id.course_id
assert course_id, "%s does not have a valid course_id"
parse = parse_course_id(course_id)
def init_block_ref_from_package_id(self, package_id):
if isinstance(package_id, CourseLocator):
package_id = package_id.package_id
assert package_id, "%s does not have a valid package_id"
parse = parse_package_id(package_id)
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)
def __unicode__(self):
......
......@@ -11,7 +11,7 @@ ALLOWED_ID_CHARS = r'[a-zA-Z0-9_\-~.:]'
URL_RE_SOURCE = r"""
(?P<tag>edx://)?
((?P<course_id>{ALLOWED_ID_CHARS}+)/?)?
((?P<package_id>{ALLOWED_ID_CHARS}+)/?)?
({BRANCH_PREFIX}(?P<branch>{ALLOWED_ID_CHARS}+)/?)?
({VERSION_PREFIX}(?P<version_guid>[A-F0-9]+)/?)?
({BLOCK_PREFIX}(?P<block>{ALLOWED_ID_CHARS}+))?
......@@ -26,7 +26,7 @@ URL_RE = re.compile('^' + URL_RE_SOURCE + '$', re.IGNORECASE | re.VERBOSE)
def parse_url(string, tag_optional=False):
"""
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.
Examples:
......@@ -38,10 +38,10 @@ def parse_url(string, tag_optional=False):
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,
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'.
"""
......@@ -69,15 +69,15 @@ def parse_block_ref(string):
return None
def parse_course_id(string):
def parse_package_id(string):
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 version (/version/519665f6223ebd6980884f2b).
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/branch/published'
......@@ -88,7 +88,7 @@ def parse_course_id(string):
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]*
......@@ -98,7 +98,7 @@ def parse_course_id(string):
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.
Block is optional: if missing returned_dict['block'] is None.
Else returns None.
......
......@@ -23,41 +23,41 @@ class SplitMigrator(object):
self.draft_modulestore = draft_modulestore
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
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)
If the new course already exists, this raises DuplicateItemError
: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 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
"""
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
# 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
# layer and kvs's know how to store it.
# 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)
new_course_root_locator = self.loc_mapper.translate_location(old_course_id, course_location)
new_course = self.split_modulestore.create_course(
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),
root_block_id=new_course_root_locator.block_id,
master_branch=new_course_root_locator.branch
)
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):
"""
......@@ -94,13 +94,13 @@ class SplitMigrator(object):
# children which meant some pointers were to non-existent locations in 'direct'
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.
"""
# 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.
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
# add to
awaiting_adoption = {}
......@@ -112,7 +112,7 @@ class SplitMigrator(object):
new_locator = self.loc_mapper.translate_location(
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
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.
......
......@@ -27,9 +27,9 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
modulestore: the module store that can be used to retrieve additional
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
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
underlying modulestore
......@@ -78,14 +78,14 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
# 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
# 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):
if course_entry_override is None:
course_entry_override = self.course_entry
else:
# 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['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
definition = json_data.get('definition', {})
definition_id = self.modulestore.definition_locator(definition)
......@@ -97,7 +97,7 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
block_locator = BlockUsageLocator(
version_guid=course_entry_override['structure']['_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')
)
......
......@@ -3,7 +3,7 @@ Provides full versioning CRUD and representation for collections of xblocks (e.g
Representation:
* 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,
** '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,
......@@ -227,7 +227,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
return the CourseDescriptor! It returns the actual db json from
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
it raises VersionConflictError (the version now differs from what it was when you got your
reference)
......@@ -239,9 +239,9 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
if not course_locator.is_fully_specified():
raise InsufficientSpecificationError('Not fully specified: %s' % course_locator)
if course_locator.course_id is not None and course_locator.branch is not None:
# use the course_id
index = self.db_connection.get_course_index(course_locator.course_id)
if course_locator.package_id is not None and course_locator.branch is not None:
# use the package_id
index = self.db_connection.get_course_index(course_locator.package_id)
if index is None:
raise ItemNotFoundError(course_locator)
if course_locator.branch not in index['versions']:
......@@ -258,11 +258,11 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
version_guid = course_locator.as_object_id(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,
# add it in the envelope for the structure.
envelope = {
'course_id': course_locator.course_id,
'package_id': course_locator.package_id,
'branch': course_locator.branch,
'structure': entry,
}
......@@ -300,7 +300,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
result = []
for entry in course_entries:
envelope = {
'course_id': id_version_map[entry['_id']],
'package_id': id_version_map[entry['_id']],
'branch': branch,
'structure': entry,
}
......@@ -327,7 +327,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
'''
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
the course or the block w/in the course do not exist for the given version.
......@@ -433,13 +433,13 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
return [BlockUsageLocator(url=locator.as_course_locator(), block_id=parent_id)
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.
: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.remove(course['structure']['root'])
for block_id, block_data in course['structure']['blocks'].iteritems():
......@@ -447,7 +447,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
if block_data['category'] in detached_categories:
items.discard(block_id)
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
]
......@@ -456,7 +456,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
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
more general purpose.
:param course_locator: must have a course_id set
:param course_locator: must have a package_id set
:return {'org': , 'prettyid': ,
versions: {'draft': the head draft version id,
'published': the head published version id if any,
......@@ -465,9 +465,9 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
'edited_on': when the course was originally created
}
"""
if course_locator.course_id is None:
if course_locator.package_id is 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
# TODO figure out a way to make this info accessible from the course descriptor
......@@ -662,7 +662,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
serial += 1
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
:param course_blocks: the current list of blocks.
......@@ -699,7 +699,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
merely the containing course.
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.
: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
......@@ -724,11 +724,11 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
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,
it progresses the course to point
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
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):
course_parent = None
# 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,
version_guid=new_id))
......@@ -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
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)
fields: if scope.settings fields provided, will set the fields of the root course object in the
......@@ -911,7 +911,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
# create the index entry
if id_root is None:
id_root = org
new_id = self._generate_course_id(id_root)
new_id = self._generate_package_id(id_root)
index_entry = {
'_id': new_id,
......@@ -921,7 +921,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
'edited_on': datetime.datetime.now(UTC),
'versions': versions_dict}
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):
"""
......@@ -930,7 +930,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
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
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).
......@@ -1019,7 +1019,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
# fetch and return the new item--fetching is unnecessary but a good qc step
return self.get_item(
BlockUsageLocator(
course_id=xblock.location.course_id,
package_id=xblock.location.package_id,
block_id=xblock.location.block_id,
branch=xblock.location.branch,
version_guid=new_id
......@@ -1143,7 +1143,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
"""
# get the destination's index, and source and destination structures.
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:
# brand new course
raise ItemNotFoundError(destination_course)
......@@ -1207,7 +1207,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
raises ItemNotFoundError if the location does not exist.
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
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).
......@@ -1249,12 +1249,12 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
# update the index entry if appropriate
if index_entry is not None:
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
return result
def delete_course(self, course_id):
def delete_course(self, package_id):
"""
Remove the given course from the course index.
......@@ -1262,11 +1262,11 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
with a versions hash to restore the course; however, the edited_on and
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:
raise ItemNotFoundError(course_id)
raise ItemNotFoundError(package_id)
# this is the only real delete in the system. should it do something else?
self.db_connection.delete_course_index(index['_id'])
......@@ -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
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:
raise InsufficientSpecificationError(
"To continue a version, the locator must point to one ({}).".format(locator)
......@@ -1413,7 +1413,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
else:
return None
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 = (
locator.version_guid is None or
index_entry['versions'][locator.branch] == locator.version_guid
......
......@@ -75,9 +75,9 @@ class TestLocationMapper(unittest.TestCase):
self.assertEqual(entry['prod_branch'], 'live')
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(
old_style_course_id,
......@@ -85,7 +85,7 @@ class TestLocationMapper(unittest.TestCase):
published= (branch=='published'),
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.branch, branch)
......@@ -104,7 +104,7 @@ class TestLocationMapper(unittest.TestCase):
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 = {
'abc123': {'problem': 'problem2'},
'def456': {'problem': 'problem4'},
......@@ -112,15 +112,15 @@ class TestLocationMapper(unittest.TestCase):
}
loc_mapper().create_map_entry(
Location('i4x', org, course, 'course', 'baz_run'),
new_style_course_id,
new_style_package_id,
block_map=block_map
)
test_problem_locn = Location('i4x', org, course, 'problem', 'abc123')
# 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
# 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
with self.assertRaises(ItemNotFoundError):
loc_mapper().translate_location(
......@@ -143,7 +143,7 @@ class TestLocationMapper(unittest.TestCase):
block_map=distractor_block_map
)
# 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
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)
......@@ -177,24 +177,24 @@ class TestLocationMapper(unittest.TestCase):
old_style_course_id = '{}/{}/{}'.format(org, course, 'baz_run')
problem_name = 'abc123abc123abc123abc123abc123f9'
location = Location('i4x', org, course, 'problem', problem_name)
new_style_course_id = '{}.{}.{}'.format(org, course, 'baz_run')
self.translate_n_check(location, old_style_course_id, new_style_course_id, 'problemabc', 'published', True)
new_style_package_id = '{}.{}.{}'.format(org, course, 'baz_run')
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
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
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
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')
loc_mapper().create_map_entry(
delta_course_locn,
delta_new_course_id,
delta_new_package_id,
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)
new_prob_name = uuid.uuid4().hex
......@@ -202,9 +202,9 @@ class TestLocationMapper(unittest.TestCase):
new_prob_name = uuid.uuid4().hex
new_prob_locn = location.replace(name=new_prob_name)
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(
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
prob_locator = loc_mapper().translate_location(
......@@ -217,7 +217,7 @@ class TestLocationMapper(unittest.TestCase):
# add a default course pointing to the delta_run
loc_mapper().create_map_entry(
Location('i4x', org, course, 'problem', '789abc123efg456'),
delta_new_course_id,
delta_new_package_id,
block_map={problem_name: {'problem': 'problem3'}}
)
# now the ambiguous query should return delta
......@@ -226,11 +226,11 @@ class TestLocationMapper(unittest.TestCase):
again_prob_name = uuid.uuid4().hex
again_prob_locn = location.replace(name=again_prob_name)
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(
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):
"""
......@@ -239,9 +239,9 @@ class TestLocationMapper(unittest.TestCase):
# lookup for non-existent course
org = 'foo_org'
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(
course_id=new_style_course_id,
package_id=new_style_package_id,
block_id='problem2',
branch='published'
)
......@@ -250,7 +250,7 @@ class TestLocationMapper(unittest.TestCase):
loc_mapper().create_map_entry(
Location('i4x', org, course, 'course', 'baz_run'),
new_style_course_id,
new_style_package_id,
block_map={
'abc123': {'problem': 'problem2'},
'48f23a10395384929234': {'chapter': 'chapter48f'},
......@@ -266,20 +266,20 @@ class TestLocationMapper(unittest.TestCase):
self.assertEqual(prob_location, Location('i4x', org, course, 'course', 'baz_run', None))
# explicit branch
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)
# Even though the problem was set as draft, we always return revision=None to work
# with old mongo/draft modulestores.
self.assertEqual(prob_location, Location('i4x', org, course, 'problem', 'abc123', None))
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)
self.assertEqual(prob_location, Location('i4x', org, course, 'problem', 'abc123', None))
# same for chapter except chapter cannot be draft in old system
chap_locator = BlockUsageLocator(
course_id=new_style_course_id,
package_id=new_style_package_id,
block_id='chapter48f',
branch='production'
)
......@@ -290,14 +290,14 @@ class TestLocationMapper(unittest.TestCase):
chap_location = loc_mapper().translate_locator_to_location(chap_locator)
self.assertEqual(chap_location, Location('i4x', org, course, 'chapter', '48f23a10395384929234'))
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)
self.assertEqual(chap_location, Location('i4x', org, course, 'chapter', '48f23a10395384929234'))
# look for non-existent problem
prob_locator2 = BlockUsageLocator(
course_id=new_style_course_id,
package_id=new_style_package_id,
branch='draft',
block_id='problem3'
)
......@@ -305,10 +305,10 @@ class TestLocationMapper(unittest.TestCase):
self.assertIsNone(prob_location, 'Found non-existent problem')
# 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(
Location('i4x', org, course, 'course', 'delta_run'),
new_style_course_id,
new_style_package_id,
block_map={'abc123': {'problem': 'problem3'}}
)
prob_location = loc_mapper().translate_locator_to_location(prob_locator)
......@@ -317,12 +317,12 @@ class TestLocationMapper(unittest.TestCase):
# add a default course pointing to the delta_run
loc_mapper().create_map_entry(
Location('i4x', org, course, 'problem', '789abc123efg456'),
new_style_course_id,
new_style_package_id,
block_map={'abc123': {'problem': 'problem3'}}
)
# now query delta (2 entries point to it)
prob_locator = BlockUsageLocator(
course_id=new_style_course_id,
package_id=new_style_package_id,
branch='production',
block_id='problem3'
)
......
......@@ -24,14 +24,14 @@ class LocatorTest(TestCase):
OverSpecificationError,
CourseLocator,
url='edx://mit.eecs.6002x',
course_id='harvard.history',
package_id='harvard.history',
branch='published',
version_guid=ObjectId())
self.assertRaises(
OverSpecificationError,
CourseLocator,
url='edx://mit.eecs.6002x',
course_id='harvard.history',
package_id='harvard.history',
version_guid=ObjectId())
self.assertRaises(
OverSpecificationError,
......@@ -41,7 +41,7 @@ class LocatorTest(TestCase):
self.assertRaises(
OverSpecificationError,
CourseLocator,
course_id='mit.eecs.6002x/' + BRANCH_PREFIX + 'published',
package_id='mit.eecs.6002x/' + BRANCH_PREFIX + 'published',
branch='draft')
def test_course_constructor_underspecified(self):
......@@ -71,9 +71,9 @@ class LocatorTest(TestCase):
self.assertEqual(str(testobj_2), 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',
'mit.eecs ',
......@@ -91,7 +91,7 @@ class LocatorTest(TestCase):
'mit.eecs/' + BRANCH_PREFIX + 'this ',
'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)
def test_course_constructor_bad_url(self):
......@@ -103,16 +103,16 @@ class LocatorTest(TestCase):
def test_course_constructor_redundant_001(self):
testurn = 'mit.eecs.6002x'
testobj = CourseLocator(course_id=testurn, url='edx://' + testurn)
self.check_course_locn_fields(testobj, 'course_id', course_id=testurn)
testobj = CourseLocator(package_id=testurn, url='edx://' + testurn)
self.check_course_locn_fields(testobj, 'package_id', package_id=testurn)
def test_course_constructor_redundant_002(self):
testurn = 'mit.eecs.6002x/' + BRANCH_PREFIX + 'published'
expected_urn = 'mit.eecs.6002x'
expected_rev = 'published'
testobj = CourseLocator(course_id=testurn, url='edx://' + testurn)
self.check_course_locn_fields(testobj, 'course_id',
course_id=expected_urn,
testobj = CourseLocator(package_id=testurn, url='edx://' + testurn)
self.check_course_locn_fields(testobj, 'package_id',
package_id=expected_urn,
branch=expected_rev)
def test_course_constructor_url(self):
......@@ -126,71 +126,71 @@ class LocatorTest(TestCase):
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'
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',
course_id='mit.eecs-honors.6002x',
package_id='mit.eecs-honors.6002x',
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'
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',
course_id='mit.eecs.~6002x',
package_id='mit.eecs.~6002x',
branch='draft-1',
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'
testobj = CourseLocator(course_id=testurn)
self.check_course_locn_fields(testobj, 'course_id', course_id=testurn)
self.assertEqual(testobj.course_id, testurn)
testobj = CourseLocator(package_id=testurn)
self.check_course_locn_fields(testobj, 'package_id', package_id=testurn)
self.assertEqual(testobj.package_id, testurn)
self.assertEqual(str(testobj), 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'
expected_id = 'mit.eecs.6002x'
expected_branch = 'published'
testobj = CourseLocator(course_id=testurn)
self.check_course_locn_fields(testobj, 'course_id with branch',
course_id=expected_id,
testobj = CourseLocator(package_id=testurn)
self.check_course_locn_fields(testobj, 'package_id with branch',
package_id=expected_id,
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(str(testobj), 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_branch = 'published'
expected_urn = 'mit.eecs.6002x/' + BRANCH_PREFIX + 'published'
testobj = CourseLocator(course_id=test_id, branch=test_branch)
self.check_course_locn_fields(testobj, 'course_id with separate branch',
course_id=test_id,
testobj = CourseLocator(package_id=test_id, branch=test_branch)
self.check_course_locn_fields(testobj, 'package_id with separate branch',
package_id=test_id,
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(str(testobj), 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_branch = 'published'
expected_id = 'mit.eecs.6002x'
expected_urn = test_id
testobj = CourseLocator(course_id=test_id, branch=test_branch)
self.check_course_locn_fields(testobj, 'course_id with repeated branch',
course_id=expected_id,
testobj = CourseLocator(package_id=test_id, branch=test_branch)
self.check_course_locn_fields(testobj, 'package_id with repeated branch',
package_id=expected_id,
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(str(testobj), expected_urn)
self.assertEqual(testobj.url(), 'edx://' + expected_urn)
......@@ -200,9 +200,9 @@ class LocatorTest(TestCase):
expected_id = 'mit.eecs.6002x'
expected_branch = 'published'
expected_block_ref = 'HW3'
testobj = BlockUsageLocator(course_id=testurn)
testobj = BlockUsageLocator(package_id=testurn)
self.check_block_locn_fields(testobj, 'test_block constructor',
course_id=expected_id,
package_id=expected_id,
branch=expected_branch,
block=expected_block_ref)
self.assertEqual(str(testobj), testurn)
......@@ -210,7 +210,7 @@ class LocatorTest(TestCase):
agnostic = testobj.version_agnostic()
self.assertIsNone(agnostic.version_guid)
self.check_block_locn_fields(agnostic, 'test_block constructor',
course_id=expected_id,
package_id=expected_id,
branch=expected_branch,
block=expected_block_ref)
......@@ -221,7 +221,7 @@ class LocatorTest(TestCase):
)
self.check_block_locn_fields(
testobj, 'error parsing URL with version and block',
course_id='mit.eecs.6002x',
package_id='mit.eecs.6002x',
block='lab2',
version_guid=ObjectId(test_id_loc)
)
......@@ -229,10 +229,10 @@ class LocatorTest(TestCase):
self.check_block_locn_fields(
agnostic, 'error parsing URL with version and block',
block='lab2',
course_id=None,
package_id=None,
version_guid=ObjectId(test_id_loc)
)
self.assertIsNone(agnostic.course_id)
self.assertIsNone(agnostic.package_id)
def test_block_constructor_url_kitchen_sink(self):
test_id_loc = '519665f6223ebd6980884f2b'
......@@ -243,7 +243,7 @@ class LocatorTest(TestCase):
)
self.check_block_locn_fields(
testobj, 'error parsing URL with branch, version, and block',
course_id='mit.eecs.6002x',
package_id='mit.eecs.6002x',
branch='draft',
block='lab2',
version_guid=ObjectId(test_id_loc)
......@@ -253,15 +253,15 @@ class LocatorTest(TestCase):
"""
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'
block_id = 'problem:with-colon~2'
testobj = BlockUsageLocator(course_id=course_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)
testobj = BlockUsageLocator(package_id=package_id, branch=branch, block_id=block_id)
self.check_block_locn_fields(testobj, 'Cannot handle colon', package_id=package_id, branch=branch, block=block_id)
def test_repr(self):
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))
def test_old_location_helpers(self):
......@@ -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(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.as_course_locator(), Locator.to_locator_or_location(locator.as_course_locator()))
self.assertEqual(location, Locator.to_locator_or_location(location.url()))
......@@ -299,7 +299,7 @@ class LocatorTest(TestCase):
"""
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(
'/expression/{}/format'.format(unicode(locator)),
locator.url_reverse('expression', 'format')
......@@ -332,19 +332,19 @@ class LocatorTest(TestCase):
# Utilities
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.course_id, course_id, msg)
self.assertEqual(testobj.package_id, package_id, msg)
self.assertEqual(testobj.branch, branch, msg)
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
"""
self.check_course_locn_fields(testobj, msg, version_guid, course_id,
self.check_course_locn_fields(testobj, msg, version_guid, package_id,
branch)
self.assertEqual(testobj.block_id, block)
......@@ -30,7 +30,7 @@ class TestOrphan(unittest.TestCase):
'xblock_mixins': (InheritanceMixin,)
}
split_course_id = 'test_org.test_course.runid'
split_package_id = 'test_org.test_course.runid'
def setUp(self):
self.db_config['collection'] = 'modulestore{0}'.format(uuid.uuid4().hex[:5])
......@@ -85,13 +85,13 @@ class TestOrphan(unittest.TestCase):
self.old_mongo.update_children(parent_location, parent.children)
# create pointer for split
course_or_parent_locator = BlockUsageLocator(
course_id=self.split_course_id,
package_id=self.split_package_id,
branch='draft',
block_id=parent_name
)
else:
course_or_parent_locator = CourseLocator(
course_id='test_org.test_course.runid',
package_id='test_org.test_course.runid',
branch='draft',
)
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):
fields.update(data)
# split requires the course to be created separately from creating items
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.old_mongo.create_and_save_xmodule(self.course_location, data, metadata)
......@@ -148,11 +148,11 @@ class TestOrphan(unittest.TestCase):
"""
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))
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)
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)
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)
......@@ -120,7 +120,7 @@ class SplitModuleCourseTests(SplitModuleTest):
self.assertEqual(len(courses), 3, "Wrong number of courses")
# check metadata -- NOTE no promised order
course = self.findByIdInResult(courses, "head12345")
self.assertEqual(course.location.course_id, "GreekHero")
self.assertEqual(course.location.package_id, "GreekHero")
self.assertEqual(
str(course.location.version_guid), self.GUID_D0,
"course version mismatch"
......@@ -151,7 +151,7 @@ class SplitModuleCourseTests(SplitModuleTest):
self.assertEqual(len(courses_published), 1, len(courses_published))
course = self.findByIdInResult(courses_published, "head23456")
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,
course.location.version_guid)
self.assertEqual(course.category, 'course', 'wrong category')
......@@ -190,7 +190,7 @@ class SplitModuleCourseTests(SplitModuleTest):
'''
locator = CourseLocator(version_guid=self.GUID_D1)
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(course.category, 'course')
self.assertEqual(len(course.tabs), 6)
......@@ -203,9 +203,9 @@ class SplitModuleCourseTests(SplitModuleTest):
self.assertEqual(course.edited_by, "testassist@edx.org")
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)
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(course.category, 'course')
self.assertEqual(len(course.tabs), 6)
......@@ -216,24 +216,24 @@ class SplitModuleCourseTests(SplitModuleTest):
self.assertEqual(course.edited_by, "testassist@edx.org")
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)
self.assertEqual(course.location.course_id, "wonderful")
self.assertEqual(course.location.package_id, "wonderful")
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)
self.assertEqual(str(course.location.version_guid), self.GUID_D2)
def test_get_course_negative(self):
# Now negative testing
self.assertRaises(InsufficientSpecificationError,
modulestore().get_course, CourseLocator(course_id='edu.meh.blah'))
modulestore().get_course, CourseLocator(package_id='edu.meh.blah'))
self.assertRaises(ItemNotFoundError,
modulestore().get_course, CourseLocator(course_id='nosuchthing', branch='draft'))
modulestore().get_course, CourseLocator(package_id='nosuchthing', branch='draft'))
self.assertRaises(ItemNotFoundError,
modulestore().get_course,
CourseLocator(course_id='GreekHero', branch='published'))
CourseLocator(package_id='GreekHero', branch='published'))
def test_cache(self):
"""
......@@ -252,7 +252,7 @@ class SplitModuleCourseTests(SplitModuleTest):
locator = CourseLocator(version_guid=self.GUID_D3)
result = modulestore().get_course_successors(locator)
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(len(result.children), 1)
self.assertEqual(str(result.children[0].locator.version_guid), self.GUID_D1)
......@@ -275,71 +275,71 @@ class SplitModuleItemTests(SplitModuleTest):
'''
has_item(BlockUsageLocator)
'''
course_id = 'GreekHero'
package_id = 'GreekHero'
# positive tests of various forms
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)
locator = BlockUsageLocator(course_id='GreekHero', block_id='head12345', branch='draft')
locator = BlockUsageLocator(package_id='GreekHero', block_id='head12345', branch='draft')
self.assertTrue(
modulestore().has_item(locator.course_id, locator),
modulestore().has_item(locator.package_id, locator),
"couldn't find in 12345"
)
self.assertTrue(
modulestore().has_item(locator.course_id, BlockUsageLocator(
course_id=locator.course_id,
modulestore().has_item(locator.package_id, BlockUsageLocator(
package_id=locator.package_id,
branch='draft',
block_id=locator.block_id
)),
"couldn't find in draft 12345"
)
self.assertFalse(
modulestore().has_item(locator.course_id, BlockUsageLocator(
course_id=locator.course_id,
modulestore().has_item(locator.package_id, BlockUsageLocator(
package_id=locator.package_id,
branch='published',
block_id=locator.block_id)),
"found in published 12345"
)
locator.branch = 'draft'
self.assertTrue(
modulestore().has_item(locator.course_id, locator),
modulestore().has_item(locator.package_id, locator),
"not found in draft 12345"
)
# 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(
modulestore().has_item(locator.course_id, locator),
modulestore().has_item(locator.package_id, locator),
"couldn't find chapter1"
)
# 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(
modulestore().has_item(
locator.course_id,
BlockUsageLocator(course_id=locator.course_id, block_id=locator.block_id, branch='published')
locator.package_id,
BlockUsageLocator(package_id=locator.package_id, block_id=locator.block_id, branch='published')
), "couldn't find in 23456"
)
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):
# negative tests--not found
# no such course or block
course_id = 'GreekHero'
locator = BlockUsageLocator(course_id="doesnotexist", block_id="head23456", branch='draft')
self.assertFalse(modulestore().has_item(course_id, locator))
locator = BlockUsageLocator(course_id="wonderful", block_id="doesnotexist", branch='draft')
self.assertFalse(modulestore().has_item(course_id, locator))
package_id = 'GreekHero'
locator = BlockUsageLocator(package_id="doesnotexist", block_id="head23456", branch='draft')
self.assertFalse(modulestore().has_item(package_id, locator))
locator = BlockUsageLocator(package_id="wonderful", block_id="doesnotexist", branch='draft')
self.assertFalse(modulestore().has_item(package_id, locator))
# negative tests--insufficient specification
self.assertRaises(InsufficientSpecificationError, BlockUsageLocator)
self.assertRaises(InsufficientSpecificationError,
modulestore().has_item, None, BlockUsageLocator(version_guid=self.GUID_D1))
self.assertRaises(InsufficientSpecificationError,
modulestore().has_item, None, BlockUsageLocator(course_id='GreekHero'))
modulestore().has_item, None, BlockUsageLocator(package_id='GreekHero'))
def test_get_item(self):
'''
......@@ -349,11 +349,11 @@ class SplitModuleItemTests(SplitModuleTest):
locator = BlockUsageLocator(version_guid=self.GUID_D1, block_id='head12345')
block = modulestore().get_item(locator)
self.assertIsInstance(block, CourseDescriptor)
# get_instance just redirects to get_item, ignores course_id
self.assertIsInstance(modulestore().get_instance("course_id", locator), CourseDescriptor)
# get_instance just redirects to get_item, ignores package_id
self.assertIsInstance(modulestore().get_instance("package_id", locator), CourseDescriptor)
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(block.display_name, "The Ancient Greek Hero")
self.assertEqual(block.advertised_start, "Fall 2013")
......@@ -365,15 +365,15 @@ class SplitModuleItemTests(SplitModuleTest):
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))
# get_instance just redirects to get_item, ignores course_id
verify_greek_hero(modulestore().get_instance("course_id", locator))
# get_instance just redirects to get_item, ignores package_id
verify_greek_hero(modulestore().get_instance("package_id", locator))
# try to look up other branches
self.assertRaises(ItemNotFoundError,
modulestore().get_item,
BlockUsageLocator(course_id=locator.as_course_locator(),
BlockUsageLocator(package_id=locator.as_course_locator(),
block_id=locator.block_id,
branch='published'))
locator.branch = 'draft'
......@@ -384,16 +384,16 @@ class SplitModuleItemTests(SplitModuleTest):
def test_get_non_root(self):
# 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)
self.assertEqual(block.location.course_id, "GreekHero")
self.assertEqual(block.location.package_id, "GreekHero")
self.assertEqual(block.category, 'chapter')
self.assertEqual(str(block.definition_locator.definition_id), "cd00000000000000dddd0020")
self.assertEqual(block.display_name, "Hercules")
self.assertEqual(block.edited_by, "testassist@edx.org")
# 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(
modulestore().get_item(locator),
CourseDescriptor
......@@ -401,10 +401,10 @@ class SplitModuleItemTests(SplitModuleTest):
# negative tests--not found
# 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):
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):
modulestore().get_item(locator)
......@@ -412,7 +412,7 @@ class SplitModuleItemTests(SplitModuleTest):
with self.assertRaises(InsufficientSpecificationError):
modulestore().get_item(BlockUsageLocator(version_guid=self.GUID_D1))
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
def test_matching(self):
......@@ -473,11 +473,11 @@ class SplitModuleItemTests(SplitModuleTest):
'''
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)
self.assertEqual(len(parents), 1)
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'
parents = modulestore().get_parent_locations(locator)
self.assertEqual(len(parents), 1)
......@@ -490,7 +490,7 @@ class SplitModuleItemTests(SplitModuleTest):
"""
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)
children = block.get_children()
expected_ids = [
......@@ -532,7 +532,7 @@ class TestItemCrud(SplitModuleTest):
create_item(course_or_parent_locator, category, user, definition_locator=None, fields): new_desciptor
"""
# 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_time = datetime.datetime.now(UTC) - datetime.timedelta(seconds=1)
# add minimal one w/o a parent
......@@ -542,7 +542,7 @@ class TestItemCrud(SplitModuleTest):
fields={'display_name': 'new sequential'}
)
# 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.assertIsNone(locator.version_guid, "Version inadvertently filled in")
current_course = modulestore().get_course(locator)
......@@ -569,7 +569,7 @@ class TestItemCrud(SplitModuleTest):
"""
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)
category = 'chapter'
new_module = modulestore().create_item(
......@@ -589,7 +589,7 @@ class TestItemCrud(SplitModuleTest):
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.
"""
locator = BlockUsageLocator(course_id="contender", block_id="head345679", branch='draft')
locator = BlockUsageLocator(package_id="contender", block_id="head345679", branch='draft')
category = 'problem'
premod_time = datetime.datetime.now(UTC) - datetime.timedelta(seconds=1)
new_payload = "<problem>empty</problem>"
......@@ -633,7 +633,7 @@ class TestItemCrud(SplitModuleTest):
course_block_update_version = new_course.update_version
self.assertIsNotNone(new_course_locator.version_guid, "Want to test a definite version")
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
......@@ -687,7 +687,7 @@ class TestItemCrud(SplitModuleTest):
# add new child to old parent in continued (leave off version_guid)
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,
branch=new_course.location.branch
)
......@@ -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
"""
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)
pre_def_id = problem.definition_locator.definition_id
pre_version_guid = problem.location.version_guid
......@@ -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
"""
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)
pre_def_id = block.definition_locator.definition_id
pre_version_guid = block.location.version_guid
......@@ -773,7 +773,7 @@ class TestItemCrud(SplitModuleTest):
"""
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)
pre_def_id = block.definition_locator.definition_id
pre_version_guid = block.location.version_guid
......@@ -791,7 +791,7 @@ class TestItemCrud(SplitModuleTest):
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
locator = BlockUsageLocator(course_id="contender", block_id="head345679", branch='draft')
locator = BlockUsageLocator(package_id="contender", block_id="head345679", branch='draft')
category = 'problem'
new_payload = "<problem>empty</problem>"
modulestore().create_item(
......@@ -832,7 +832,7 @@ class TestItemCrud(SplitModuleTest):
course.location,
'deleting_user')
reusable_location = BlockUsageLocator(
course_id=course.location.course_id,
package_id=course.location.package_id,
block_id=course.location.block_id,
branch='draft')
......@@ -840,16 +840,16 @@ class TestItemCrud(SplitModuleTest):
problems = modulestore().get_items(reusable_location, {'category': 'problem'})
locn_to_del = problems[0].location
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,
block_id=locn_to_del.block_id)
self.assertFalse(modulestore().has_item(reusable_location.course_id, deleted))
self.assertRaises(VersionConflictError, modulestore().has_item, reusable_location.course_id, locn_to_del)
self.assertFalse(modulestore().has_item(reusable_location.package_id, deleted))
self.assertRaises(VersionConflictError, modulestore().has_item, reusable_location.package_id, locn_to_del)
locator = BlockUsageLocator(
version_guid=locn_to_del.version_guid,
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)
# delete a subtree
......@@ -860,15 +860,15 @@ class TestItemCrud(SplitModuleTest):
def check_subtree(node):
if node:
node_loc = node.location
self.assertFalse(modulestore().has_item(reusable_location.course_id,
self.assertFalse(modulestore().has_item(reusable_location.package_id,
BlockUsageLocator(
course_id=node_loc.course_id,
package_id=node_loc.package_id,
branch=node_loc.branch,
block_id=node.location.block_id)))
locator = BlockUsageLocator(
version_guid=node.location.version_guid,
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:
for sub in node.get_children():
check_subtree(sub)
......@@ -877,7 +877,7 @@ class TestItemCrud(SplitModuleTest):
def create_course_for_deletion(self):
course = modulestore().create_course('nihilx', 'deletion', 'deleting_user')
root = BlockUsageLocator(
course_id=course.location.course_id,
package_id=course.location.package_id,
block_id=course.location.block_id,
branch='draft')
for _ in range(4):
......@@ -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.
"""
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)
new_draft = modulestore().create_course(
'leech', 'best_course', 'leech_master', id_root='best',
versions_dict=original_index['versions'])
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
self.assertEqual(new_draft.edited_by, 'test@edx.org')
self.assertLess(new_draft.edited_on, pre_time)
......@@ -951,7 +951,7 @@ class TestCourseCreation(SplitModuleTest):
self.assertLessEqual(new_index["edited_on"], datetime.datetime.now(UTC))
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)
self.assertEqual(new_published.edited_by, 'test@edx.org')
self.assertLess(new_published.edited_on, pre_time)
......@@ -979,7 +979,7 @@ class TestCourseCreation(SplitModuleTest):
original_course = modulestore().get_course(original_locator)
self.assertEqual(original_course.location.version_guid, original_index['versions']['draft'])
self.assertFalse(
modulestore().has_item(new_draft_locator.course_id, BlockUsageLocator(
modulestore().has_item(new_draft_locator.package_id, BlockUsageLocator(
original_locator,
block_id=new_item.location.block_id
))
......@@ -990,7 +990,7 @@ class TestCourseCreation(SplitModuleTest):
Create a new course which overrides metadata and course_data
"""
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_index = modulestore().get_course_index_info(original_locator)
fields = {}
......@@ -1007,7 +1007,7 @@ class TestCourseCreation(SplitModuleTest):
fields=fields
)
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
self.assertEqual(new_draft.edited_by, 'leech_master')
self.assertGreaterEqual(new_draft.edited_on, pre_time)
......@@ -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.
"""
locator = CourseLocator(course_id="GreekHero", branch='draft')
locator = CourseLocator(package_id="GreekHero", branch='draft')
course_info = modulestore().get_course_index_info(locator)
course_info['org'] = 'funkyU'
modulestore().update_course_index(course_info)
......@@ -1051,7 +1051,7 @@ class TestCourseCreation(SplitModuleTest):
# an allowed but not recommended way to publish a course
versions['published'] = self.GUID_D1
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)
def test_create_with_root(self):
......@@ -1086,11 +1086,11 @@ class TestInheritance(SplitModuleTest):
"""
# Note, not testing value where defined (course) b/c there's no
# 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)
# inherited
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)
# overridden
self.assertEqual(node.graceperiod, datetime.timedelta(hours=4))
......@@ -1111,8 +1111,8 @@ class TestPublish(SplitModuleTest):
"""
Test the standard patterns: publish to new branch, revise and publish
"""
source_course = CourseLocator(course_id="GreekHero", branch='draft')
dest_course = CourseLocator(course_id="GreekHero", branch="published")
source_course = CourseLocator(package_id="GreekHero", branch='draft')
dest_course = CourseLocator(package_id="GreekHero", branch="published")
modulestore().xblock_publish(self.user, source_course, dest_course, ["head12345"], ["chapter2", "chapter3"])
expected = ["head12345", "chapter1"]
self._check_course(
......@@ -1153,13 +1153,13 @@ class TestPublish(SplitModuleTest):
"""
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_course = CourseLocator(course_id="Unknown", branch="published")
destination_course = CourseLocator(package_id="Unknown", branch="published")
with self.assertRaises(ItemNotFoundError):
modulestore().xblock_publish(self.user, source_course, destination_course, ["chapter3"], None)
# 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):
modulestore().xblock_publish(self.user, source_course, destination_course, ["chapter3"], None)
# publishing a subdag w/o the parent already in course
......@@ -1171,8 +1171,8 @@ class TestPublish(SplitModuleTest):
"""
Test publishing moves and deletes.
"""
source_course = CourseLocator(course_id="GreekHero", branch='draft')
dest_course = CourseLocator(course_id="GreekHero", branch="published")
source_course = CourseLocator(package_id="GreekHero", branch='draft')
dest_course = CourseLocator(package_id="GreekHero", branch="published")
modulestore().xblock_publish(self.user, source_course, dest_course, ["head12345"], ["chapter2"])
expected = ["head12345", "chapter1", "chapter3", "problem1", "problem3_2"]
self._check_course(source_course, dest_course, expected, ["chapter2"])
......@@ -1210,7 +1210,7 @@ class TestPublish(SplitModuleTest):
"""
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):
"""
......
......@@ -10,7 +10,7 @@ from django.contrib.auth.models import User, Group
from xmodule.modulestore import Location
from xmodule.modulestore.exceptions import InvalidLocationError, ItemNotFoundError
from xmodule.modulestore.django import loc_mapper
from xmodule.modulestore.locator import CourseLocator
from xmodule.modulestore.locator import CourseLocator, Locator
class CourseContextRequired(Exception):
......@@ -144,29 +144,29 @@ class CourseRole(GroupBasedRole):
"""
# TODO: figure out how to make the group name generation lazy so it doesn't force the
# loc mapping?
if not hasattr(location, 'course_id'):
location = Location(location)
location = Locator.to_locator_or_location(location)
# direct copy from auth.authz.get_all_course_role_groupnames will refactor to one impl asap
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
if isinstance(location, Location):
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)
groupnames.append('{0}_{1}'.format(role, locator.course_id))
groupnames.append('{0}_{1}'.format(role, locator.package_id))
except (InvalidLocationError, ItemNotFoundError):
# if it's never been mapped, the auth won't be via the Locator syntax
pass
# least preferred legacy role_course format
groupnames.append('{0}_{1}'.format(role, location.course))
elif isinstance(location, CourseLocator):
groupnames.append('{0}_{1}'.format(role, location.package_id))
# handle old Location syntax
old_location = loc_mapper().translate_locator_to_location(location, get_course=True)
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