Commit 93656e39 by Nimisha Asthagiri

Merge pull request #10390 from edx/mobile/make-course-usage-key

Add make_course_usage_key method to modulestore
parents 0fece869 6fb8335b
...@@ -907,6 +907,14 @@ class ModuleStoreRead(ModuleStoreAssetBase): ...@@ -907,6 +907,14 @@ class ModuleStoreRead(ModuleStoreAssetBase):
pass pass
@abstractmethod @abstractmethod
def make_course_usage_key(self, course_key):
"""
Return a valid :class:`~opaque_keys.edx.keys.UsageKey` for this modulestore
that matches the supplied course_key.
"""
pass
@abstractmethod
def get_courses(self, **kwargs): def get_courses(self, **kwargs):
''' '''
Returns a list containing the top level XModuleDescriptors of the courses Returns a list containing the top level XModuleDescriptors of the courses
......
...@@ -313,6 +313,15 @@ class MixedModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase): ...@@ -313,6 +313,15 @@ class MixedModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase):
# Otherwise, return the key created by the default store # Otherwise, return the key created by the default store
return self.default_modulestore.make_course_key(org, course, run) return self.default_modulestore.make_course_key(org, course, run)
def make_course_usage_key(self, course_key):
"""
Return a valid :class:`~opaque_keys.edx.keys.UsageKey` for the modulestore
that matches the supplied course_key.
"""
assert isinstance(course_key, CourseKey)
store = self._get_modulestore_for_courselike(course_key)
return store.make_course_usage_key(course_key)
@strip_key @strip_key
def get_course(self, course_key, depth=0, **kwargs): def get_course(self, course_key, depth=0, **kwargs):
""" """
......
...@@ -1033,6 +1033,13 @@ class MongoModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase, Mongo ...@@ -1033,6 +1033,13 @@ class MongoModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase, Mongo
""" """
return CourseLocator(org, course, run, deprecated=True) return CourseLocator(org, course, run, deprecated=True)
def make_course_usage_key(self, course_key):
"""
Return a valid :class:`~opaque_keys.edx.keys.UsageKey` for this modulestore
that matches the supplied course_key.
"""
return BlockUsageLocator(course_key, 'course', course_key.run)
def get_course(self, course_key, depth=0, **kwargs): def get_course(self, course_key, depth=0, **kwargs):
""" """
Get the course with the given courseid (org/course/run) Get the course with the given courseid (org/course/run)
......
...@@ -70,6 +70,7 @@ from xmodule.errortracker import null_error_tracker ...@@ -70,6 +70,7 @@ from xmodule.errortracker import null_error_tracker
from opaque_keys.edx.locator import ( from opaque_keys.edx.locator import (
BlockUsageLocator, DefinitionLocator, CourseLocator, LibraryLocator, VersionTree, LocalId, BlockUsageLocator, DefinitionLocator, CourseLocator, LibraryLocator, VersionTree, LocalId,
) )
from ccx_keys.locator import CCXLocator, CCXBlockUsageLocator
from xmodule.modulestore.exceptions import InsufficientSpecificationError, VersionConflictError, DuplicateItemError, \ from xmodule.modulestore.exceptions import InsufficientSpecificationError, VersionConflictError, DuplicateItemError, \
DuplicateCourseError DuplicateCourseError
from xmodule.modulestore import ( from xmodule.modulestore import (
...@@ -949,6 +950,14 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase): ...@@ -949,6 +950,14 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
""" """
return CourseLocator(org, course, run) return CourseLocator(org, course, run)
def make_course_usage_key(self, course_key):
"""
Return a valid :class:`~opaque_keys.edx.keys.UsageKey` for this modulestore
that matches the supplied course_key.
"""
locator_cls = CCXBlockUsageLocator if isinstance(course_key, CCXLocator) else BlockUsageLocator
return locator_cls(course_key, 'course', 'course')
def _get_structure(self, structure_id, depth, head_validation=True, **kwargs): def _get_structure(self, structure_id, depth, head_validation=True, **kwargs):
""" """
Gets Course or Library by locator Gets Course or Library by locator
......
...@@ -758,6 +758,13 @@ class TestMongoModuleStore(TestMongoModuleStoreBase): ...@@ -758,6 +758,13 @@ class TestMongoModuleStore(TestMongoModuleStoreBase):
# Clean up the data so we don't break other tests which apparently expect a particular state # Clean up the data so we don't break other tests which apparently expect a particular state
self.draft_store.delete_course(course.id, self.dummy_user) self.draft_store.delete_course(course.id, self.dummy_user)
def test_make_course_usage_key(self):
"""Test that we get back the appropriate usage key for the root of a course key."""
course_key = CourseLocator(org="edX", course="101", run="2015")
root_block_key = self.draft_store.make_course_usage_key(course_key)
self.assertEqual(root_block_key.block_type, "course")
self.assertEqual(root_block_key.name, "2015")
class TestMongoModuleStoreWithNoAssetCollection(TestMongoModuleStore): class TestMongoModuleStoreWithNoAssetCollection(TestMongoModuleStore):
''' '''
......
...@@ -10,6 +10,7 @@ import re ...@@ -10,6 +10,7 @@ import re
import unittest import unittest
import uuid import uuid
import ddt
from contracts import contract from contracts import contract
from nose.plugins.attrib import attr from nose.plugins.attrib import attr
from django.core.cache import get_cache, InvalidCacheBackendError from django.core.cache import get_cache, InvalidCacheBackendError
...@@ -23,7 +24,8 @@ from xmodule.modulestore.exceptions import ( ...@@ -23,7 +24,8 @@ from xmodule.modulestore.exceptions import (
DuplicateItemError, DuplicateCourseError, DuplicateItemError, DuplicateCourseError,
InsufficientSpecificationError InsufficientSpecificationError
) )
from opaque_keys.edx.locator import CourseLocator, BlockUsageLocator, VersionTree, LocalId from opaque_keys.edx.locator import CourseKey, CourseLocator, BlockUsageLocator, VersionTree, LocalId
from ccx_keys.locator import CCXBlockUsageLocator
from xmodule.modulestore.inheritance import InheritanceMixin from xmodule.modulestore.inheritance import InheritanceMixin
from xmodule.x_module import XModuleMixin from xmodule.x_module import XModuleMixin
from xmodule.fields import Date, Timedelta from xmodule.fields import Date, Timedelta
...@@ -596,6 +598,7 @@ class TestHasChildrenAtDepth(SplitModuleTest): ...@@ -596,6 +598,7 @@ class TestHasChildrenAtDepth(SplitModuleTest):
self.assertFalse(ch3.has_children_at_depth(1)) self.assertFalse(ch3.has_children_at_depth(1))
@ddt.ddt
class SplitModuleCourseTests(SplitModuleTest): class SplitModuleCourseTests(SplitModuleTest):
''' '''
Course CRUD operation tests Course CRUD operation tests
...@@ -908,6 +911,22 @@ class SplitModuleCourseTests(SplitModuleTest): ...@@ -908,6 +911,22 @@ class SplitModuleCourseTests(SplitModuleTest):
version_history = modulestore().get_block_generations(second_problem.location) version_history = modulestore().get_block_generations(second_problem.location)
self.assertNotEqual(version_history.locator.version_guid, first_problem.location.version_guid) self.assertNotEqual(version_history.locator.version_guid, first_problem.location.version_guid)
@ddt.data(
("course-v1:edx+test_course+test_run", BlockUsageLocator),
("ccx-v1:edX+test_course+test_run+ccx@1", CCXBlockUsageLocator),
)
@ddt.unpack
def test_make_course_usage_key(self, course_id, root_block_cls):
"""Test that we get back the appropriate usage key for the root of a course key.
In particular, we want to make sure that it properly handles CCX courses.
"""
course_key = CourseKey.from_string(course_id)
root_block_key = modulestore().make_course_usage_key(course_key)
self.assertIsInstance(root_block_key, root_block_cls)
self.assertEqual(root_block_key.block_type, "course")
self.assertEqual(root_block_key.name, "course")
class TestCourseStructureCache(SplitModuleTest): class TestCourseStructureCache(SplitModuleTest):
"""Tests for the CourseStructureCache""" """Tests for the CourseStructureCache"""
......
...@@ -27,7 +27,7 @@ from xmodule.modulestore.xml_exporter import DEFAULT_CONTENT_FIELDS ...@@ -27,7 +27,7 @@ from xmodule.modulestore.xml_exporter import DEFAULT_CONTENT_FIELDS
from xmodule.modulestore import ModuleStoreEnum, ModuleStoreReadBase, LIBRARY_ROOT, COURSE_ROOT from xmodule.modulestore import ModuleStoreEnum, ModuleStoreReadBase, LIBRARY_ROOT, COURSE_ROOT
from xmodule.tabs import CourseTabList from xmodule.tabs import CourseTabList
from opaque_keys.edx.locations import SlashSeparatedCourseKey, Location from opaque_keys.edx.locations import SlashSeparatedCourseKey, Location
from opaque_keys.edx.locator import CourseLocator, LibraryLocator from opaque_keys.edx.locator import CourseLocator, LibraryLocator, BlockUsageLocator
from xblock.field_data import DictFieldData from xblock.field_data import DictFieldData
from xblock.runtime import DictKeyValueStore from xblock.runtime import DictKeyValueStore
...@@ -821,6 +821,13 @@ class XMLModuleStore(ModuleStoreReadBase): ...@@ -821,6 +821,13 @@ class XMLModuleStore(ModuleStoreReadBase):
""" """
return CourseLocator(org, course, run, deprecated=True) return CourseLocator(org, course, run, deprecated=True)
def make_course_usage_key(self, course_key):
"""
Return a valid :class:`~opaque_keys.edx.keys.UsageKey` for this modulestore
that matches the supplied course_key.
"""
return BlockUsageLocator(course_key, 'course', course_key.run)
def get_courses(self, **kwargs): def get_courses(self, **kwargs):
""" """
Returns a list of course descriptors. If there were errors on loading, Returns a list of course descriptors. If there were errors on loading,
......
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