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): ...@@ -37,23 +37,21 @@ def get_all_course_role_groupnames(location, role, use_filter=True):
''' '''
location = Locator.to_locator_or_location(location) location = Locator.to_locator_or_location(location)
# hack: check for existence of a group name in the legacy LMS format <role>_<course>
# if it exists, then use that one, otherwise use a <role>_<course_id> which contains
# more information
groupnames = [] groupnames = []
try:
groupnames.append('{0}_{1}'.format(role, location.course_id))
except InvalidLocationError: # will occur on old locations where location is not of category course
pass
if isinstance(location, Location): if isinstance(location, Location):
# least preferred role_course format try:
groupnames.append('{0}_{1}'.format(role, location.course)) groupnames.append('{0}_{1}'.format(role, location.course_id))
except InvalidLocationError: # will occur on old locations where location is not of category course
pass
try: try:
locator = loc_mapper().translate_location(location.course_id, location, False, False) locator = loc_mapper().translate_location(location.course_id, location, False, False)
groupnames.append('{0}_{1}'.format(role, locator.course_id)) groupnames.append('{0}_{1}'.format(role, locator.package_id))
except (InvalidLocationError, ItemNotFoundError): except (InvalidLocationError, ItemNotFoundError):
pass pass
# least preferred role_course format for legacy reasons
groupnames.append('{0}_{1}'.format(role, location.course))
elif isinstance(location, CourseLocator): elif isinstance(location, CourseLocator):
groupnames.append('{0}_{1}'.format(role, location.package_id))
old_location = loc_mapper().translate_locator_to_location(location, get_course=True) old_location = loc_mapper().translate_locator_to_location(location, get_course=True)
if old_location: if old_location:
# the slashified version of the course_id (myu/mycourse/myrun) # the slashified version of the course_id (myu/mycourse/myrun)
......
...@@ -136,13 +136,13 @@ class TemplateTests(unittest.TestCase): ...@@ -136,13 +136,13 @@ class TemplateTests(unittest.TestCase):
persistent_factories.ItemFactory.create(display_name='chapter 1', persistent_factories.ItemFactory.create(display_name='chapter 1',
parent_location=test_course.location) parent_location=test_course.location)
id_locator = CourseLocator(course_id=test_course.location.course_id, branch='draft') id_locator = CourseLocator(package_id=test_course.location.package_id, branch='draft')
guid_locator = CourseLocator(version_guid=test_course.location.version_guid) guid_locator = CourseLocator(version_guid=test_course.location.version_guid)
# verify it can be retireved by id # verify it can be retireved by id
self.assertIsInstance(modulestore('split').get_course(id_locator), CourseDescriptor) self.assertIsInstance(modulestore('split').get_course(id_locator), CourseDescriptor)
# and by guid # and by guid
self.assertIsInstance(modulestore('split').get_course(guid_locator), CourseDescriptor) self.assertIsInstance(modulestore('split').get_course(guid_locator), CourseDescriptor)
modulestore('split').delete_course(id_locator.course_id) modulestore('split').delete_course(id_locator.package_id)
# test can no longer retrieve by id # test can no longer retrieve by id
self.assertRaises(ItemNotFoundError, modulestore('split').get_course, id_locator) self.assertRaises(ItemNotFoundError, modulestore('split').get_course, id_locator)
# but can by guid # but can by guid
......
...@@ -90,7 +90,7 @@ class TestCourseAccess(ModuleStoreTestCase): ...@@ -90,7 +90,7 @@ class TestCourseAccess(ModuleStoreTestCase):
# first check the groupname for the course creator. # first check the groupname for the course creator.
self.assertTrue( self.assertTrue(
self.user.groups.filter( self.user.groups.filter(
name="{}_{}".format(INSTRUCTOR_ROLE_NAME, self.course_locator.course_id) name="{}_{}".format(INSTRUCTOR_ROLE_NAME, self.course_locator.package_id)
).exists(), ).exists(),
"Didn't add creator as instructor." "Didn't add creator as instructor."
) )
...@@ -124,4 +124,4 @@ class TestCourseAccess(ModuleStoreTestCase): ...@@ -124,4 +124,4 @@ class TestCourseAccess(ModuleStoreTestCase):
for role in [INSTRUCTOR_ROLE_NAME, STAFF_ROLE_NAME]: for role in [INSTRUCTOR_ROLE_NAME, STAFF_ROLE_NAME]:
for user in user_by_role[role]: for user in user_by_role[role]:
self.assertTrue(has_access(user, copy_course_locator), "{} no copy access".format(user)) self.assertTrue(has_access(user, copy_course_locator), "{} no copy access".format(user))
self.assertTrue(has_access(user, copy_course_location), "{} no copy access".format(user)) self.assertTrue(has_access(user, copy_course_location), "{} no copy access".format(user))
\ No newline at end of file
...@@ -34,7 +34,7 @@ __all__ = ['assets_handler'] ...@@ -34,7 +34,7 @@ __all__ = ['assets_handler']
@login_required @login_required
@ensure_csrf_cookie @ensure_csrf_cookie
def assets_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None, asset_id=None): def assets_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None, asset_id=None):
""" """
The restful handler for assets. The restful handler for assets.
It allows retrieval of all the assets (as an HTML page), as well as uploading new assets, It allows retrieval of all the assets (as an HTML page), as well as uploading new assets,
...@@ -51,7 +51,7 @@ def assets_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -51,7 +51,7 @@ def assets_handler(request, tag=None, course_id=None, branch=None, version_guid=
DELETE DELETE
json: delete an asset json: delete an asset
""" """
location = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) location = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
if not has_access(request.user, location): if not has_access(request.user, location):
raise PermissionDenied() raise PermissionDenied()
......
...@@ -26,7 +26,7 @@ __all__ = ['checklists_handler'] ...@@ -26,7 +26,7 @@ __all__ = ['checklists_handler']
@require_http_methods(("GET", "POST", "PUT")) @require_http_methods(("GET", "POST", "PUT"))
@login_required @login_required
@ensure_csrf_cookie @ensure_csrf_cookie
def checklists_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None, checklist_index=None): def checklists_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None, checklist_index=None):
""" """
The restful handler for checklists. The restful handler for checklists.
...@@ -36,7 +36,7 @@ def checklists_handler(request, tag=None, course_id=None, branch=None, version_g ...@@ -36,7 +36,7 @@ def checklists_handler(request, tag=None, course_id=None, branch=None, version_g
POST or PUT POST or PUT
json: updates the checked state for items within a particular checklist. checklist_index is required. json: updates the checked state for items within a particular checklist. checklist_index is required.
""" """
location = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) location = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
if not has_access(request.user, location): if not has_access(request.user, location):
raise PermissionDenied() raise PermissionDenied()
......
...@@ -53,7 +53,7 @@ ADVANCED_COMPONENT_POLICY_KEY = 'advanced_modules' ...@@ -53,7 +53,7 @@ ADVANCED_COMPONENT_POLICY_KEY = 'advanced_modules'
@require_http_methods(["GET"]) @require_http_methods(["GET"])
@login_required @login_required
def subsection_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): def subsection_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
""" """
The restful handler for subsection-specific requests. The restful handler for subsection-specific requests.
...@@ -62,7 +62,7 @@ def subsection_handler(request, tag=None, course_id=None, branch=None, version_g ...@@ -62,7 +62,7 @@ def subsection_handler(request, tag=None, course_id=None, branch=None, version_g
json: not currently supported json: not currently supported
""" """
if 'text/html' in request.META.get('HTTP_ACCEPT', 'text/html'): if 'text/html' in request.META.get('HTTP_ACCEPT', 'text/html'):
locator = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) locator = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
try: try:
old_location, course, item, lms_link = _get_item_in_course(request, locator) old_location, course, item, lms_link = _get_item_in_course(request, locator)
except ItemNotFoundError: except ItemNotFoundError:
...@@ -142,7 +142,7 @@ def _load_mixed_class(category): ...@@ -142,7 +142,7 @@ def _load_mixed_class(category):
@require_http_methods(["GET"]) @require_http_methods(["GET"])
@login_required @login_required
def unit_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): def unit_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
""" """
The restful handler for unit-specific requests. The restful handler for unit-specific requests.
...@@ -151,7 +151,7 @@ def unit_handler(request, tag=None, course_id=None, branch=None, version_guid=No ...@@ -151,7 +151,7 @@ def unit_handler(request, tag=None, course_id=None, branch=None, version_guid=No
json: not currently supported json: not currently supported
""" """
if 'text/html' in request.META.get('HTTP_ACCEPT', 'text/html'): if 'text/html' in request.META.get('HTTP_ACCEPT', 'text/html'):
locator = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) locator = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
try: try:
old_location, course, item, lms_link = _get_item_in_course(request, locator) old_location, course, item, lms_link = _get_item_in_course(request, locator)
except ItemNotFoundError: except ItemNotFoundError:
......
...@@ -50,7 +50,7 @@ CONTENT_RE = re.compile(r"(?P<start>\d{1,11})-(?P<stop>\d{1,11})/(?P<end>\d{1,11 ...@@ -50,7 +50,7 @@ CONTENT_RE = re.compile(r"(?P<start>\d{1,11})-(?P<stop>\d{1,11})/(?P<end>\d{1,11
@login_required @login_required
@ensure_csrf_cookie @ensure_csrf_cookie
@require_http_methods(("GET", "POST", "PUT")) @require_http_methods(("GET", "POST", "PUT"))
def import_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): def import_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
""" """
The restful handler for importing a course. The restful handler for importing a course.
...@@ -60,7 +60,7 @@ def import_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -60,7 +60,7 @@ def import_handler(request, tag=None, course_id=None, branch=None, version_guid=
POST or PUT POST or PUT
json: import a course via the .tar.gz file specified in request.FILES json: import a course via the .tar.gz file specified in request.FILES
""" """
location = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) location = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
if not has_access(request.user, location): if not has_access(request.user, location):
raise PermissionDenied() raise PermissionDenied()
...@@ -148,7 +148,7 @@ def import_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -148,7 +148,7 @@ def import_handler(request, tag=None, course_id=None, branch=None, version_guid=
# Use sessions to keep info about import progress # Use sessions to keep info about import progress
session_status = request.session.setdefault("import_status", {}) session_status = request.session.setdefault("import_status", {})
key = location.course_id + filename key = location.package_id + filename
session_status[key] = 1 session_status[key] = 1
request.session.modified = True request.session.modified = True
...@@ -261,7 +261,7 @@ def import_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -261,7 +261,7 @@ def import_handler(request, tag=None, course_id=None, branch=None, version_guid=
@require_GET @require_GET
@ensure_csrf_cookie @ensure_csrf_cookie
@login_required @login_required
def import_status_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None, filename=None): def import_status_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None, filename=None):
""" """
Returns an integer corresponding to the status of a file import. These are: Returns an integer corresponding to the status of a file import. These are:
...@@ -271,13 +271,13 @@ def import_status_handler(request, tag=None, course_id=None, branch=None, versio ...@@ -271,13 +271,13 @@ def import_status_handler(request, tag=None, course_id=None, branch=None, versio
3 : Importing to mongo 3 : Importing to mongo
""" """
location = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) location = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
if not has_access(request.user, location): if not has_access(request.user, location):
raise PermissionDenied() raise PermissionDenied()
try: try:
session_status = request.session["import_status"] session_status = request.session["import_status"]
status = session_status[location.course_id + filename] status = session_status[location.package_id + filename]
except KeyError: except KeyError:
status = 0 status = 0
...@@ -287,7 +287,7 @@ def import_status_handler(request, tag=None, course_id=None, branch=None, versio ...@@ -287,7 +287,7 @@ def import_status_handler(request, tag=None, course_id=None, branch=None, versio
@ensure_csrf_cookie @ensure_csrf_cookie
@login_required @login_required
@require_http_methods(("GET",)) @require_http_methods(("GET",))
def export_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): def export_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
""" """
The restful handler for exporting a course. The restful handler for exporting a course.
...@@ -302,7 +302,7 @@ def export_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -302,7 +302,7 @@ def export_handler(request, tag=None, course_id=None, branch=None, version_guid=
If the tar.gz file has been requested but the export operation fails, an HTML page will be returned If the tar.gz file has been requested but the export operation fails, an HTML page will be returned
which describes the error. which describes the error.
""" """
location = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) location = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
if not has_access(request.user, location): if not has_access(request.user, location):
raise PermissionDenied() raise PermissionDenied()
......
...@@ -47,7 +47,7 @@ CREATE_IF_NOT_FOUND = ['course_info'] ...@@ -47,7 +47,7 @@ CREATE_IF_NOT_FOUND = ['course_info']
@require_http_methods(("DELETE", "GET", "PUT", "POST")) @require_http_methods(("DELETE", "GET", "PUT", "POST"))
@login_required @login_required
@expect_json @expect_json
def xblock_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): def xblock_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
""" """
The restful handler for xblock requests. The restful handler for xblock requests.
...@@ -78,8 +78,8 @@ def xblock_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -78,8 +78,8 @@ def xblock_handler(request, tag=None, course_id=None, branch=None, version_guid=
:boilerplate: template name for populating fields, optional :boilerplate: template name for populating fields, optional
The locator (and old-style id) for the created xblock (minus children) is returned. The locator (and old-style id) for the created xblock (minus children) is returned.
""" """
if course_id is not None: if package_id is not None:
locator = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) locator = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
if not has_access(request.user, locator): if not has_access(request.user, locator):
raise PermissionDenied() raise PermissionDenied()
old_location = loc_mapper().translate_locator_to_location(locator) old_location = loc_mapper().translate_locator_to_location(locator)
...@@ -117,7 +117,7 @@ def xblock_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -117,7 +117,7 @@ def xblock_handler(request, tag=None, course_id=None, branch=None, version_guid=
delete_all_versions = str_to_bool(request.REQUEST.get('all_versions', 'False')) delete_all_versions = str_to_bool(request.REQUEST.get('all_versions', 'False'))
return _delete_item_at_location(old_location, delete_children, delete_all_versions) return _delete_item_at_location(old_location, delete_children, delete_all_versions)
else: # Since we have a course_id, we are updating an existing xblock. else: # Since we have a package_id, we are updating an existing xblock.
return _save_item( return _save_item(
request, request,
locator, locator,
...@@ -133,7 +133,7 @@ def xblock_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -133,7 +133,7 @@ def xblock_handler(request, tag=None, course_id=None, branch=None, version_guid=
return _create_item(request) return _create_item(request)
else: else:
return HttpResponseBadRequest( return HttpResponseBadRequest(
"Only instance creation is supported without a course_id.", "Only instance creation is supported without a package_id.",
content_type="text/plain" content_type="text/plain"
) )
...@@ -319,7 +319,7 @@ def _delete_item_at_location(item_location, delete_children=False, delete_all_ve ...@@ -319,7 +319,7 @@ def _delete_item_at_location(item_location, delete_children=False, delete_all_ve
# pylint: disable=W0613 # pylint: disable=W0613
@login_required @login_required
@require_http_methods(("GET", "DELETE")) @require_http_methods(("GET", "DELETE"))
def orphan_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): def orphan_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
""" """
View for handling orphan related requests. GET gets all of the current orphans. View for handling orphan related requests. GET gets all of the current orphans.
DELETE removes all orphans (requires is_staff access) DELETE removes all orphans (requires is_staff access)
...@@ -328,9 +328,9 @@ def orphan_handler(request, tag=None, course_id=None, branch=None, version_guid= ...@@ -328,9 +328,9 @@ def orphan_handler(request, tag=None, course_id=None, branch=None, version_guid=
from the root via children from the root via children
:param request: :param request:
:param course_id: Locator syntax course_id :param package_id: Locator syntax package_id
""" """
location = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) location = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
# DHM: when split becomes back-end, move or conditionalize this conversion # DHM: when split becomes back-end, move or conditionalize this conversion
old_location = loc_mapper().translate_locator_to_location(location) old_location = loc_mapper().translate_locator_to_location(location)
if request.method == 'GET': if request.method == 'GET':
......
...@@ -48,7 +48,7 @@ def initialize_course_tabs(course): ...@@ -48,7 +48,7 @@ def initialize_course_tabs(course):
@login_required @login_required
@ensure_csrf_cookie @ensure_csrf_cookie
@require_http_methods(("GET", "POST", "PUT")) @require_http_methods(("GET", "POST", "PUT"))
def tabs_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None): def tabs_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
""" """
The restful handler for static tabs. The restful handler for static tabs.
...@@ -62,7 +62,7 @@ def tabs_handler(request, tag=None, course_id=None, branch=None, version_guid=No ...@@ -62,7 +62,7 @@ def tabs_handler(request, tag=None, course_id=None, branch=None, version_guid=No
Creating a tab, deleting a tab, or changing its contents is not supported through this method. Creating a tab, deleting a tab, or changing its contents is not supported through this method.
Instead use the general xblock URL (see item.xblock_handler). Instead use the general xblock URL (see item.xblock_handler).
""" """
locator = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) locator = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
if not has_access(request.user, locator): if not has_access(request.user, locator):
raise PermissionDenied() raise PermissionDenied()
......
...@@ -40,7 +40,7 @@ def request_course_creator(request): ...@@ -40,7 +40,7 @@ def request_course_creator(request):
@login_required @login_required
@ensure_csrf_cookie @ensure_csrf_cookie
@require_http_methods(("GET", "POST", "PUT", "DELETE")) @require_http_methods(("GET", "POST", "PUT", "DELETE"))
def course_team_handler(request, tag=None, course_id=None, branch=None, version_guid=None, block=None, email=None): def course_team_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None, email=None):
""" """
The restful handler for course team users. The restful handler for course team users.
...@@ -52,7 +52,7 @@ def course_team_handler(request, tag=None, course_id=None, branch=None, version_ ...@@ -52,7 +52,7 @@ def course_team_handler(request, tag=None, course_id=None, branch=None, version_
DELETE: DELETE:
json: remove a particular course team member from the course team (email is required). json: remove a particular course team member from the course team (email is required).
""" """
location = BlockUsageLocator(course_id=course_id, branch=branch, version_guid=version_guid, block_id=block) location = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
if not has_access(request.user, location): if not has_access(request.user, location):
raise PermissionDenied() raise PermissionDenied()
......
...@@ -17,7 +17,6 @@ from xblock.fields import Scope, List, String, Dict, Boolean ...@@ -17,7 +17,6 @@ from xblock.fields import Scope, List, String, Dict, Boolean
from .fields import Date from .fields import Date
from xmodule.modulestore.locator import CourseLocator from xmodule.modulestore.locator import CourseLocator
from django.utils.timezone import UTC from django.utils.timezone import UTC
from xmodule.util import date_utils
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -400,7 +399,7 @@ class CourseDescriptor(CourseFields, SequenceDescriptor): ...@@ -400,7 +399,7 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
if isinstance(self.location, Location): if isinstance(self.location, Location):
self.wiki_slug = self.location.course self.wiki_slug = self.location.course
elif isinstance(self.location, CourseLocator): elif isinstance(self.location, CourseLocator):
self.wiki_slug = self.location.course_id or self.display_name self.wiki_slug = self.location.package_id or self.display_name
if self.due_date_display_format is None and self.show_timezone is False: if self.due_date_display_format is None and self.show_timezone is False:
# For existing courses with show_timezone set to False (and no due_date_display_format specified), # For existing courses with show_timezone set to False (and no due_date_display_format specified),
......
...@@ -51,21 +51,21 @@ class LocMapperStore(object): ...@@ -51,21 +51,21 @@ class LocMapperStore(object):
self.cache = cache self.cache = cache
# location_map functions # location_map functions
def create_map_entry(self, course_location, course_id=None, draft_branch='draft', prod_branch='published', def create_map_entry(self, course_location, package_id=None, draft_branch='draft', prod_branch='published',
block_map=None): block_map=None):
""" """
Add a new entry to map this course_location to the new style CourseLocator.course_id. If course_id is not Add a new entry to map this course_location to the new style CourseLocator.package_id. If package_id is not
provided, it creates the default map of using org.course.name from the location (just like course_id) if provided, it creates the default map of using org.course.name from the location if
the location.category = 'course'; otherwise, it uses org.course. the location.category = 'course'; otherwise, it uses org.course.
You can create more than one mapping to the You can create more than one mapping to the
same course_id target. In that case, the reverse translate will be arbitrary (no guarantee of which wins). same package_id target. In that case, the reverse translate will be arbitrary (no guarantee of which wins).
The use The use
case for more than one mapping is to map both org/course/run and org/course to the same new course_id thus case for more than one mapping is to map both org/course/run and org/course to the same new package_id thus
making a default for org/course. When querying for just org/course, the translator will prefer any entry making a default for org/course. When querying for just org/course, the translator will prefer any entry
which does not have a name in the _id; otherwise, it will return an arbitrary match. which does not have a name in the _id; otherwise, it will return an arbitrary match.
Note: the opposite is not true. That is, it never makes sense to use 2 different CourseLocator.course_id Note: the opposite is not true. That is, it never makes sense to use 2 different CourseLocator.package_id
keys to index the same old Locator org/course/.. pattern. There's no checking to ensure you don't do this. keys to index the same old Locator org/course/.. pattern. There's no checking to ensure you don't do this.
NOTE: if there's already an entry w the given course_location, this may either overwrite that entry or NOTE: if there's already an entry w the given course_location, this may either overwrite that entry or
...@@ -74,8 +74,8 @@ class LocMapperStore(object): ...@@ -74,8 +74,8 @@ class LocMapperStore(object):
:param course_location: a Location preferably whose category is 'course'. Unlike the other :param course_location: a Location preferably whose category is 'course'. Unlike the other
map methods, this one doesn't take the old-style course_id. It should be called with map methods, this one doesn't take the old-style course_id. It should be called with
a course location not a block location; however, if called w/ a non-course Location, it creates a course location not a block location; however, if called w/ a non-course Location, it creates
a "default" map for the org/course pair to a new course_id. a "default" map for the org/course pair to a new package_id.
:param course_id: the CourseLocator style course_id :param package_id: the CourseLocator style package_id
:param draft_branch: the branch name to assign for drafts. This is hardcoded because old mongo had :param draft_branch: the branch name to assign for drafts. This is hardcoded because old mongo had
a fixed notion that there was 2 and only 2 versions for modules: draft and production. The old mongo a fixed notion that there was 2 and only 2 versions for modules: draft and production. The old mongo
did not, however, require that a draft version exist. The new one, however, does require a draft to did not, however, require that a draft version exist. The new one, however, does require a draft to
...@@ -86,11 +86,11 @@ class LocMapperStore(object): ...@@ -86,11 +86,11 @@ class LocMapperStore(object):
:param block_map: an optional map to specify preferred names for blocks where the keys are the :param block_map: an optional map to specify preferred names for blocks where the keys are the
Location block names and the values are the BlockUsageLocator.block_id. Location block names and the values are the BlockUsageLocator.block_id.
""" """
if course_id is None: if package_id is None:
if course_location.category == 'course': if course_location.category == 'course':
course_id = "{0.org}.{0.course}.{0.name}".format(course_location) package_id = "{0.org}.{0.course}.{0.name}".format(course_location)
else: else:
course_id = "{0.org}.{0.course}".format(course_location) package_id = "{0.org}.{0.course}".format(course_location)
# very like _interpret_location_id but w/o the _id # very like _interpret_location_id but w/o the _id
location_id = self._construct_location_son( location_id = self._construct_location_son(
course_location.org, course_location.course, course_location.org, course_location.course,
...@@ -99,12 +99,12 @@ class LocMapperStore(object): ...@@ -99,12 +99,12 @@ class LocMapperStore(object):
self.location_map.insert({ self.location_map.insert({
'_id': location_id, '_id': location_id,
'course_id': course_id, 'course_id': package_id,
'draft_branch': draft_branch, 'draft_branch': draft_branch,
'prod_branch': prod_branch, 'prod_branch': prod_branch,
'block_map': block_map or {}, 'block_map': block_map or {},
}) })
return course_id return package_id
def translate_location(self, old_style_course_id, location, published=True, add_entry_if_missing=True): def translate_location(self, old_style_course_id, location, published=True, add_entry_if_missing=True):
""" """
...@@ -174,9 +174,9 @@ class LocMapperStore(object): ...@@ -174,9 +174,9 @@ class LocMapperStore(object):
raise InvalidLocationError() raise InvalidLocationError()
published_usage = BlockUsageLocator( published_usage = BlockUsageLocator(
course_id=entry['course_id'], branch=entry['prod_branch'], block_id=block_id) package_id=entry['course_id'], branch=entry['prod_branch'], block_id=block_id)
draft_usage = BlockUsageLocator( draft_usage = BlockUsageLocator(
course_id=entry['course_id'], branch=entry['draft_branch'], block_id=block_id) package_id=entry['course_id'], branch=entry['draft_branch'], block_id=block_id)
if published: if published:
result = published_usage result = published_usage
else: else:
...@@ -199,13 +199,13 @@ class LocMapperStore(object): ...@@ -199,13 +199,13 @@ class LocMapperStore(object):
If there are no matches, it returns None. If there are no matches, it returns None.
If there's more than one location to locator mapping to the same course_id, it looks for the first If there's more than one location to locator mapping to the same package_id, it looks for the first
one with a mapping for the block block_id and picks that arbitrary course location. one with a mapping for the block block_id and picks that arbitrary course location.
:param locator: a BlockUsageLocator :param locator: a BlockUsageLocator
""" """
if get_course: if get_course:
cached_value = self._get_course_location_from_cache(locator.course_id) cached_value = self._get_course_location_from_cache(locator.package_id)
else: else:
cached_value = self._get_location_from_cache(locator) cached_value = self._get_location_from_cache(locator)
if cached_value: if cached_value:
...@@ -213,7 +213,7 @@ class LocMapperStore(object): ...@@ -213,7 +213,7 @@ class LocMapperStore(object):
# This does not require that the course exist in any modulestore # This does not require that the course exist in any modulestore
# only that it has a mapping entry. # only that it has a mapping entry.
maps = self.location_map.find({'course_id': locator.course_id}) maps = self.location_map.find({'course_id': locator.package_id})
# look for one which maps to this block block_id # look for one which maps to this block block_id
if maps.count() == 0: if maps.count() == 0:
return None return None
...@@ -365,12 +365,12 @@ class LocMapperStore(object): ...@@ -365,12 +365,12 @@ class LocMapperStore(object):
""" """
return self.cache.get(unicode(locator)) return self.cache.get(unicode(locator))
def _get_course_location_from_cache(self, locator_course_id): def _get_course_location_from_cache(self, locator_package_id):
""" """
See if the course_id is in the cache. If so, return the mapped location to the See if the package_id is in the cache. If so, return the mapped location to the
course root. course root.
""" """
return self.cache.get('courseId+{}'.format(locator_course_id)) return self.cache.get('courseId+{}'.format(locator_package_id))
def _cache_location_map_entry(self, old_course_id, location, published_usage, draft_usage): def _cache_location_map_entry(self, old_course_id, location, published_usage, draft_usage):
""" """
...@@ -380,7 +380,7 @@ class LocMapperStore(object): ...@@ -380,7 +380,7 @@ class LocMapperStore(object):
""" """
setmany = {} setmany = {}
if location.category == 'course': if location.category == 'course':
setmany['courseId+{}'.format(published_usage.course_id)] = location setmany['courseId+{}'.format(published_usage.package_id)] = location
setmany[unicode(published_usage)] = location setmany[unicode(published_usage)] = location
setmany[unicode(draft_usage)] = location setmany[unicode(draft_usage)] = location
setmany['{}+{}'.format(old_course_id, location.url())] = (published_usage, draft_usage) setmany['{}+{}'.format(old_course_id, location.url())] = (published_usage, draft_usage)
......
...@@ -11,7 +11,7 @@ ALLOWED_ID_CHARS = r'[a-zA-Z0-9_\-~.:]' ...@@ -11,7 +11,7 @@ ALLOWED_ID_CHARS = r'[a-zA-Z0-9_\-~.:]'
URL_RE_SOURCE = r""" URL_RE_SOURCE = r"""
(?P<tag>edx://)? (?P<tag>edx://)?
((?P<course_id>{ALLOWED_ID_CHARS}+)/?)? ((?P<package_id>{ALLOWED_ID_CHARS}+)/?)?
({BRANCH_PREFIX}(?P<branch>{ALLOWED_ID_CHARS}+)/?)? ({BRANCH_PREFIX}(?P<branch>{ALLOWED_ID_CHARS}+)/?)?
({VERSION_PREFIX}(?P<version_guid>[A-F0-9]+)/?)? ({VERSION_PREFIX}(?P<version_guid>[A-F0-9]+)/?)?
({BLOCK_PREFIX}(?P<block>{ALLOWED_ID_CHARS}+))? ({BLOCK_PREFIX}(?P<block>{ALLOWED_ID_CHARS}+))?
...@@ -26,7 +26,7 @@ URL_RE = re.compile('^' + URL_RE_SOURCE + '$', re.IGNORECASE | re.VERBOSE) ...@@ -26,7 +26,7 @@ URL_RE = re.compile('^' + URL_RE_SOURCE + '$', re.IGNORECASE | re.VERBOSE)
def parse_url(string, tag_optional=False): def parse_url(string, tag_optional=False):
""" """
A url usually begins with 'edx://' (case-insensitive match), A url usually begins with 'edx://' (case-insensitive match),
followed by either a version_guid or a course_id. If tag_optional, then followed by either a version_guid or a package_id. If tag_optional, then
the url does not have to start with the tag and edx will be assumed. the url does not have to start with the tag and edx will be assumed.
Examples: Examples:
...@@ -38,10 +38,10 @@ def parse_url(string, tag_optional=False): ...@@ -38,10 +38,10 @@ def parse_url(string, tag_optional=False):
This returns None if string cannot be parsed. This returns None if string cannot be parsed.
If it can be parsed as a version_guid with no preceding course_id, returns a dict If it can be parsed as a version_guid with no preceding package_id, returns a dict
with key 'version_guid' and the value, with key 'version_guid' and the value,
If it can be parsed as a course_id, returns a dict If it can be parsed as a package_id, returns a dict
with key 'id' and optional keys 'branch' and 'version_guid'. with key 'id' and optional keys 'branch' and 'version_guid'.
""" """
...@@ -69,15 +69,15 @@ def parse_block_ref(string): ...@@ -69,15 +69,15 @@ def parse_block_ref(string):
return None return None
def parse_course_id(string): def parse_package_id(string):
r""" r"""
A course_id has a main id component. A package_id has a main id component.
There may also be an optional branch (/branch/published or /branch/draft). There may also be an optional branch (/branch/published or /branch/draft).
There may also be an optional version (/version/519665f6223ebd6980884f2b). There may also be an optional version (/version/519665f6223ebd6980884f2b).
There may also be an optional block (/block/HW3 or /block/Quiz2). There may also be an optional block (/block/HW3 or /block/Quiz2).
Examples of valid course_ids: Examples of valid package_ids:
'mit.eecs.6002x' 'mit.eecs.6002x'
'mit.eecs.6002x/branch/published' 'mit.eecs.6002x/branch/published'
...@@ -88,7 +88,7 @@ def parse_course_id(string): ...@@ -88,7 +88,7 @@ def parse_course_id(string):
Syntax: Syntax:
course_id = main_id [/branch/ branch] [/version/ version ] [/block/ block] package_id = main_id [/branch/ branch] [/version/ version ] [/block/ block]
main_id = name [. name]* main_id = name [. name]*
...@@ -98,7 +98,7 @@ def parse_course_id(string): ...@@ -98,7 +98,7 @@ def parse_course_id(string):
name = ALLOWED_ID_CHARS name = ALLOWED_ID_CHARS
If string is a course_id, returns a dict with keys 'id', 'branch', and 'block'. If string is a package_id, returns a dict with keys 'id', 'branch', and 'block'.
Revision is optional: if missing returned_dict['branch'] is None. Revision is optional: if missing returned_dict['branch'] is None.
Block is optional: if missing returned_dict['block'] is None. Block is optional: if missing returned_dict['block'] is None.
Else returns None. Else returns None.
......
...@@ -23,41 +23,41 @@ class SplitMigrator(object): ...@@ -23,41 +23,41 @@ class SplitMigrator(object):
self.draft_modulestore = draft_modulestore self.draft_modulestore = draft_modulestore
self.loc_mapper = loc_mapper self.loc_mapper = loc_mapper
def migrate_mongo_course(self, course_location, user_id, new_course_id=None): def migrate_mongo_course(self, course_location, user_id, new_package_id=None):
""" """
Create a new course in split_mongo representing the published and draft versions of the course from the Create a new course in split_mongo representing the published and draft versions of the course from the
original mongo store. And return the new_course_id (which the caller can also get by calling original mongo store. And return the new_package_id (which the caller can also get by calling
self.loc_mapper.translate_location(old_course_location) self.loc_mapper.translate_location(old_course_location)
If the new course already exists, this raises DuplicateItemError If the new course already exists, this raises DuplicateItemError
:param course_location: a Location whose category is 'course' and points to the course :param course_location: a Location whose category is 'course' and points to the course
:param user_id: the user whose action is causing this migration :param user_id: the user whose action is causing this migration
:param new_course_id: (optional) the Locator.course_id for the new course. Defaults to :param new_package_id: (optional) the Locator.package_id for the new course. Defaults to
whatever translate_location_to_locator returns whatever translate_location_to_locator returns
""" """
new_course_id = self.loc_mapper.create_map_entry(course_location, course_id=new_course_id) new_package_id = self.loc_mapper.create_map_entry(course_location, package_id=new_package_id)
old_course_id = course_location.course_id old_course_id = course_location.course_id
# the only difference in data between the old and split_mongo xblocks are the locations; # the only difference in data between the old and split_mongo xblocks are the locations;
# so, any field which holds a location must change to a Locator; otherwise, the persistence # so, any field which holds a location must change to a Locator; otherwise, the persistence
# layer and kvs's know how to store it. # layer and kvs's know how to store it.
# locations are in location, children, conditionals, course.tab # locations are in location, children, conditionals, course.tab
# create the course: set fields to explicitly_set for each scope, id_root = new_course_id, master_branch = 'production' # create the course: set fields to explicitly_set for each scope, id_root = new_package_id, master_branch = 'production'
original_course = self.direct_modulestore.get_item(course_location) original_course = self.direct_modulestore.get_item(course_location)
new_course_root_locator = self.loc_mapper.translate_location(old_course_id, course_location) new_course_root_locator = self.loc_mapper.translate_location(old_course_id, course_location)
new_course = self.split_modulestore.create_course( new_course = self.split_modulestore.create_course(
course_location.org, original_course.display_name, course_location.org, original_course.display_name,
user_id, id_root=new_course_id, user_id, id_root=new_package_id,
fields=self._get_json_fields_translate_children(original_course, old_course_id, True), fields=self._get_json_fields_translate_children(original_course, old_course_id, True),
root_block_id=new_course_root_locator.block_id, root_block_id=new_course_root_locator.block_id,
master_branch=new_course_root_locator.branch master_branch=new_course_root_locator.branch
) )
self._copy_published_modules_to_course(new_course, course_location, old_course_id, user_id) self._copy_published_modules_to_course(new_course, course_location, old_course_id, user_id)
self._add_draft_modules_to_course(new_course_id, old_course_id, course_location, user_id) self._add_draft_modules_to_course(new_package_id, old_course_id, course_location, user_id)
return new_course_id return new_package_id
def _copy_published_modules_to_course(self, new_course, old_course_loc, old_course_id, user_id): def _copy_published_modules_to_course(self, new_course, old_course_loc, old_course_id, user_id):
""" """
...@@ -94,13 +94,13 @@ class SplitMigrator(object): ...@@ -94,13 +94,13 @@ class SplitMigrator(object):
# children which meant some pointers were to non-existent locations in 'direct' # children which meant some pointers were to non-existent locations in 'direct'
self.split_modulestore.internal_clean_children(course_version_locator) self.split_modulestore.internal_clean_children(course_version_locator)
def _add_draft_modules_to_course(self, new_course_id, old_course_id, old_course_loc, user_id): def _add_draft_modules_to_course(self, new_package_id, old_course_id, old_course_loc, user_id):
""" """
update each draft. Create any which don't exist in published and attach to their parents. update each draft. Create any which don't exist in published and attach to their parents.
""" """
# each true update below will trigger a new version of the structure. We may want to just have one new version # each true update below will trigger a new version of the structure. We may want to just have one new version
# but that's for a later date. # but that's for a later date.
new_draft_course_loc = CourseLocator(course_id=new_course_id, branch='draft') new_draft_course_loc = CourseLocator(package_id=new_package_id, branch='draft')
# to prevent race conditions of grandchilden being added before their parents and thus having no parent to # to prevent race conditions of grandchilden being added before their parents and thus having no parent to
# add to # add to
awaiting_adoption = {} awaiting_adoption = {}
...@@ -112,7 +112,7 @@ class SplitMigrator(object): ...@@ -112,7 +112,7 @@ class SplitMigrator(object):
new_locator = self.loc_mapper.translate_location( new_locator = self.loc_mapper.translate_location(
old_course_id, module.location, False, add_entry_if_missing=True old_course_id, module.location, False, add_entry_if_missing=True
) )
if self.split_modulestore.has_item(new_course_id, new_locator): if self.split_modulestore.has_item(new_package_id, new_locator):
# was in 'direct' so draft is a new version # was in 'direct' so draft is a new version
split_module = self.split_modulestore.get_item(new_locator) split_module = self.split_modulestore.get_item(new_locator)
# need to remove any no-longer-explicitly-set values and add/update any now set values. # need to remove any no-longer-explicitly-set values and add/update any now set values.
......
...@@ -27,9 +27,9 @@ class CachingDescriptorSystem(MakoDescriptorSystem): ...@@ -27,9 +27,9 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
modulestore: the module store that can be used to retrieve additional modulestore: the module store that can be used to retrieve additional
modules modules
course_entry: the originally fetched enveloped course_structure w/ branch and course_id info. course_entry: the originally fetched enveloped course_structure w/ branch and package_id info.
Callers to _load_item provide an override but that function ignores the provided structure and Callers to _load_item provide an override but that function ignores the provided structure and
only looks at the branch and course_id only looks at the branch and package_id
module_data: a dict mapping Location -> json that was cached from the module_data: a dict mapping Location -> json that was cached from the
underlying modulestore underlying modulestore
...@@ -78,14 +78,14 @@ class CachingDescriptorSystem(MakoDescriptorSystem): ...@@ -78,14 +78,14 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
# the thread is working with more than one named container pointing to the same specific structure is # the thread is working with more than one named container pointing to the same specific structure is
# low; thus, the course_entry is most likely correct. If the thread is looking at > 1 named container # low; thus, the course_entry is most likely correct. If the thread is looking at > 1 named container
# pointing to the same structure, the access is likely to be chunky enough that the last known container # pointing to the same structure, the access is likely to be chunky enough that the last known container
# is the intended one when not given a course_entry_override; thus, the caching of the last branch/course_id. # is the intended one when not given a course_entry_override; thus, the caching of the last branch/package_id.
def xblock_from_json(self, class_, block_id, json_data, course_entry_override=None): def xblock_from_json(self, class_, block_id, json_data, course_entry_override=None):
if course_entry_override is None: if course_entry_override is None:
course_entry_override = self.course_entry course_entry_override = self.course_entry
else: else:
# most recent retrieval is most likely the right one for next caller (see comment above fn) # most recent retrieval is most likely the right one for next caller (see comment above fn)
self.course_entry['branch'] = course_entry_override['branch'] self.course_entry['branch'] = course_entry_override['branch']
self.course_entry['course_id'] = course_entry_override['course_id'] self.course_entry['package_id'] = course_entry_override['package_id']
# most likely a lazy loader or the id directly # most likely a lazy loader or the id directly
definition = json_data.get('definition', {}) definition = json_data.get('definition', {})
definition_id = self.modulestore.definition_locator(definition) definition_id = self.modulestore.definition_locator(definition)
...@@ -97,7 +97,7 @@ class CachingDescriptorSystem(MakoDescriptorSystem): ...@@ -97,7 +97,7 @@ class CachingDescriptorSystem(MakoDescriptorSystem):
block_locator = BlockUsageLocator( block_locator = BlockUsageLocator(
version_guid=course_entry_override['structure']['_id'], version_guid=course_entry_override['structure']['_id'],
block_id=block_id, block_id=block_id,
course_id=course_entry_override.get('course_id'), package_id=course_entry_override.get('package_id'),
branch=course_entry_override.get('branch') branch=course_entry_override.get('branch')
) )
......
...@@ -30,7 +30,7 @@ class TestOrphan(unittest.TestCase): ...@@ -30,7 +30,7 @@ class TestOrphan(unittest.TestCase):
'xblock_mixins': (InheritanceMixin,) 'xblock_mixins': (InheritanceMixin,)
} }
split_course_id = 'test_org.test_course.runid' split_package_id = 'test_org.test_course.runid'
def setUp(self): def setUp(self):
self.db_config['collection'] = 'modulestore{0}'.format(uuid.uuid4().hex[:5]) self.db_config['collection'] = 'modulestore{0}'.format(uuid.uuid4().hex[:5])
...@@ -85,13 +85,13 @@ class TestOrphan(unittest.TestCase): ...@@ -85,13 +85,13 @@ class TestOrphan(unittest.TestCase):
self.old_mongo.update_children(parent_location, parent.children) self.old_mongo.update_children(parent_location, parent.children)
# create pointer for split # create pointer for split
course_or_parent_locator = BlockUsageLocator( course_or_parent_locator = BlockUsageLocator(
course_id=self.split_course_id, package_id=self.split_package_id,
branch='draft', branch='draft',
block_id=parent_name block_id=parent_name
) )
else: else:
course_or_parent_locator = CourseLocator( course_or_parent_locator = CourseLocator(
course_id='test_org.test_course.runid', package_id='test_org.test_course.runid',
branch='draft', branch='draft',
) )
self.split_mongo.create_item(course_or_parent_locator, category, self.userid, block_id=name, fields=fields) self.split_mongo.create_item(course_or_parent_locator, category, self.userid, block_id=name, fields=fields)
...@@ -114,7 +114,7 @@ class TestOrphan(unittest.TestCase): ...@@ -114,7 +114,7 @@ class TestOrphan(unittest.TestCase):
fields.update(data) fields.update(data)
# split requires the course to be created separately from creating items # split requires the course to be created separately from creating items
self.split_mongo.create_course( self.split_mongo.create_course(
'test_org', 'my course', self.userid, self.split_course_id, fields=fields, root_block_id='runid' 'test_org', 'my course', self.userid, self.split_package_id, fields=fields, root_block_id='runid'
) )
self.course_location = Location('i4x', 'test_org', 'test_course', 'course', 'runid') self.course_location = Location('i4x', 'test_org', 'test_course', 'course', 'runid')
self.old_mongo.create_and_save_xmodule(self.course_location, data, metadata) self.old_mongo.create_and_save_xmodule(self.course_location, data, metadata)
...@@ -148,11 +148,11 @@ class TestOrphan(unittest.TestCase): ...@@ -148,11 +148,11 @@ class TestOrphan(unittest.TestCase):
""" """
Test that old mongo finds the orphans Test that old mongo finds the orphans
""" """
orphans = self.split_mongo.get_orphans(self.split_course_id, ['static_tab', 'about', 'course_info'], 'draft') orphans = self.split_mongo.get_orphans(self.split_package_id, ['static_tab', 'about', 'course_info'], 'draft')
self.assertEqual(len(orphans), 3, "Wrong # {}".format(orphans)) self.assertEqual(len(orphans), 3, "Wrong # {}".format(orphans))
location = BlockUsageLocator(course_id=self.split_course_id, branch='draft', block_id='OrphanChapter') location = BlockUsageLocator(package_id=self.split_package_id, branch='draft', block_id='OrphanChapter')
self.assertIn(location, orphans) self.assertIn(location, orphans)
location = BlockUsageLocator(course_id=self.split_course_id, branch='draft', block_id='OrphanVert') location = BlockUsageLocator(package_id=self.split_package_id, branch='draft', block_id='OrphanVert')
self.assertIn(location, orphans) self.assertIn(location, orphans)
location = BlockUsageLocator(course_id=self.split_course_id, branch='draft', block_id='OrphanHtml') location = BlockUsageLocator(package_id=self.split_package_id, branch='draft', block_id='OrphanHtml')
self.assertIn(location, orphans) self.assertIn(location, orphans)
...@@ -10,7 +10,7 @@ from django.contrib.auth.models import User, Group ...@@ -10,7 +10,7 @@ from django.contrib.auth.models import User, Group
from xmodule.modulestore import Location from xmodule.modulestore import Location
from xmodule.modulestore.exceptions import InvalidLocationError, ItemNotFoundError from xmodule.modulestore.exceptions import InvalidLocationError, ItemNotFoundError
from xmodule.modulestore.django import loc_mapper from xmodule.modulestore.django import loc_mapper
from xmodule.modulestore.locator import CourseLocator from xmodule.modulestore.locator import CourseLocator, Locator
class CourseContextRequired(Exception): class CourseContextRequired(Exception):
...@@ -144,29 +144,29 @@ class CourseRole(GroupBasedRole): ...@@ -144,29 +144,29 @@ class CourseRole(GroupBasedRole):
""" """
# TODO: figure out how to make the group name generation lazy so it doesn't force the # TODO: figure out how to make the group name generation lazy so it doesn't force the
# loc mapping? # loc mapping?
if not hasattr(location, 'course_id'): location = Locator.to_locator_or_location(location)
location = Location(location)
# direct copy from auth.authz.get_all_course_role_groupnames will refactor to one impl asap # direct copy from auth.authz.get_all_course_role_groupnames will refactor to one impl asap
groupnames = [] groupnames = []
try:
groupnames.append('{0}_{1}'.format(role, location.course_id))
except InvalidLocationError: # will occur on old locations where location is not of category course
if course_context is None:
raise CourseContextRequired()
else:
groupnames.append('{0}_{1}'.format(role, course_context))
# pylint: disable=no-member # pylint: disable=no-member
if isinstance(location, Location): if isinstance(location, Location):
try: try:
groupnames.append('{0}_{1}'.format(role, location.course_id))
except InvalidLocationError: # will occur on old locations where location is not of category course
if course_context is None:
raise CourseContextRequired()
else:
groupnames.append('{0}_{1}'.format(role, course_context))
try:
locator = loc_mapper().translate_location(location.course_id, location, False, False) locator = loc_mapper().translate_location(location.course_id, location, False, False)
groupnames.append('{0}_{1}'.format(role, locator.course_id)) groupnames.append('{0}_{1}'.format(role, locator.package_id))
except (InvalidLocationError, ItemNotFoundError): except (InvalidLocationError, ItemNotFoundError):
# if it's never been mapped, the auth won't be via the Locator syntax # if it's never been mapped, the auth won't be via the Locator syntax
pass pass
# least preferred legacy role_course format # least preferred legacy role_course format
groupnames.append('{0}_{1}'.format(role, location.course)) groupnames.append('{0}_{1}'.format(role, location.course))
elif isinstance(location, CourseLocator): elif isinstance(location, CourseLocator):
groupnames.append('{0}_{1}'.format(role, location.package_id))
# handle old Location syntax # handle old Location syntax
old_location = loc_mapper().translate_locator_to_location(location, get_course=True) old_location = loc_mapper().translate_locator_to_location(location, get_course=True)
if old_location: if old_location:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment