ModulestoreEnum class.
This commit is contained in:
@@ -3,7 +3,7 @@ Script for finding all courses whose org/name pairs == other courses when ignori
|
||||
"""
|
||||
from django.core.management.base import BaseCommand
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.modulestore import MONGO_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
|
||||
|
||||
#
|
||||
@@ -16,7 +16,7 @@ class Command(BaseCommand):
|
||||
help = 'List all courses ids in the Mongo Modulestore which may collide when ignoring case'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
mstore = modulestore()._get_modulestore_by_type(MONGO_MODULESTORE_TYPE) # pylint: disable=protected-access
|
||||
mstore = modulestore()._get_modulestore_by_type(ModuleStoreEnum.Type.mongo) # pylint: disable=protected-access
|
||||
if hasattr(mstore, 'collection'):
|
||||
map_fn = '''
|
||||
function () {
|
||||
|
||||
@@ -6,7 +6,7 @@ import unittest
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.management import CommandError, call_command
|
||||
from contentstore.management.commands.migrate_to_split import Command
|
||||
from xmodule.modulestore import SPLIT_MONGO_MODULESTORE_TYPE, REVISION_OPTION_PUBLISHED_ONLY
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from xmodule.modulestore.django import modulestore, clear_existing_modulestores
|
||||
@@ -56,7 +56,7 @@ class TestMigrateToSplit(ModuleStoreTestCase):
|
||||
password = 'foo'
|
||||
self.user = User.objects.create_user(uname, email, password)
|
||||
self.course = CourseFactory()
|
||||
self.addCleanup(ModuleStoreTestCase.drop_mongo_collections, SPLIT_MONGO_MODULESTORE_TYPE)
|
||||
self.addCleanup(ModuleStoreTestCase.drop_mongo_collections, ModuleStoreEnum.Type.split)
|
||||
self.addCleanup(clear_existing_modulestores)
|
||||
|
||||
def test_user_email(self):
|
||||
@@ -84,6 +84,6 @@ class TestMigrateToSplit(ModuleStoreTestCase):
|
||||
str(self.user.id),
|
||||
"org.dept+name.run",
|
||||
)
|
||||
locator = CourseLocator(org="org.dept", offering="name.run", branch=REVISION_OPTION_PUBLISHED_ONLY)
|
||||
locator = CourseLocator(org="org.dept", offering="name.run", branch=ModuleStoreEnum.RevisionOption.published_only)
|
||||
course_from_split = modulestore('split').get_course(locator)
|
||||
self.assertIsNotNone(course_from_split)
|
||||
|
||||
@@ -27,10 +27,8 @@ from xmodule.contentstore.content import StaticContent
|
||||
from xmodule.contentstore.django import contentstore, _CONTENTSTORE
|
||||
from xmodule.contentstore.utils import restore_asset_from_trashcan, empty_asset_trashcan
|
||||
from xmodule.exceptions import NotFoundError, InvalidVersionError
|
||||
from xmodule.modulestore import (
|
||||
mongo, MONGO_MODULESTORE_TYPE, PublishState,
|
||||
REVISION_OPTION_PUBLISHED_ONLY, REVISION_OPTION_DRAFT_ONLY, KEY_REVISION_PUBLISHED, BRANCH_PUBLISHED_ONLY
|
||||
)
|
||||
from xmodule.modulestore import mongo, PublishState, ModuleStoreEnum
|
||||
from xmodule.modulestore.mongo.base import MongoRevisionKey
|
||||
from xmodule.modulestore.mixed import store_branch_setting
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError
|
||||
@@ -204,13 +202,13 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
|
||||
store.convert_to_draft(html_module_from_draft_store.location, self.user.id)
|
||||
|
||||
# Query get_items() and find the html item. This should just return back a single item (not 2).
|
||||
direct_store_items = store.get_items(course_key, revision=REVISION_OPTION_PUBLISHED_ONLY)
|
||||
direct_store_items = store.get_items(course_key, revision=ModuleStoreEnum.RevisionOption.published_only)
|
||||
html_items_from_direct_store = [item for item in direct_store_items if (item.location == html_usage_key)]
|
||||
self.assertEqual(len(html_items_from_direct_store), 1)
|
||||
self.assertFalse(getattr(html_items_from_direct_store[0], 'is_draft', False))
|
||||
|
||||
# Fetch from the draft store.
|
||||
draft_store_items = store.get_items(course_key, revision=REVISION_OPTION_DRAFT_ONLY)
|
||||
draft_store_items = store.get_items(course_key, revision=ModuleStoreEnum.RevisionOption.draft_only)
|
||||
html_items_from_draft_store = [item for item in draft_store_items if (item.location == html_usage_key)]
|
||||
self.assertEqual(len(html_items_from_draft_store), 1)
|
||||
self.assertTrue(getattr(html_items_from_draft_store[0], 'is_draft', False))
|
||||
@@ -663,9 +661,9 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
|
||||
clone_course(module_store, content_store, source_course_id, dest_course_id, self.user.id)
|
||||
|
||||
# first assert that all draft content got cloned as well
|
||||
draft_items = module_store.get_items(source_course_id, revision=REVISION_OPTION_DRAFT_ONLY)
|
||||
draft_items = module_store.get_items(source_course_id, revision=ModuleStoreEnum.RevisionOption.draft_only)
|
||||
self.assertGreater(len(draft_items), 0)
|
||||
draft_clone_items = module_store.get_items(dest_course_id, revision=REVISION_OPTION_DRAFT_ONLY)
|
||||
draft_clone_items = module_store.get_items(dest_course_id, revision=ModuleStoreEnum.RevisionOption.draft_only)
|
||||
self.assertGreater(len(draft_clone_items), 0)
|
||||
self.assertEqual(len(draft_items), len(draft_clone_items))
|
||||
|
||||
@@ -868,7 +866,7 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
|
||||
|
||||
# add the new private and new public to list of children
|
||||
sequential = module_store.get_item(course_id.make_usage_key('sequential', 'vertical_sequential'))
|
||||
private_location_no_draft = private_vertical.location.replace(revision=KEY_REVISION_PUBLISHED)
|
||||
private_location_no_draft = private_vertical.location.replace(revision=MongoRevisionKey.published)
|
||||
sequential.children.append(private_location_no_draft)
|
||||
sequential.children.append(public_vertical_location)
|
||||
module_store.update_item(sequential, self.user.id)
|
||||
@@ -939,7 +937,11 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
|
||||
target_course_id=course_id,
|
||||
)
|
||||
|
||||
items = module_store.get_items(course_id, category='vertical', revision=REVISION_OPTION_PUBLISHED_ONLY)
|
||||
items = module_store.get_items(
|
||||
course_id,
|
||||
category='vertical',
|
||||
revision=ModuleStoreEnum.RevisionOption.published_only
|
||||
)
|
||||
self._check_verticals(items)
|
||||
|
||||
def verify_item_publish_state(item, publish_state):
|
||||
@@ -1124,7 +1126,7 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
|
||||
self.assertContains(resp, '/c4x/edX/toy/asset/handouts_sample_handout.txt')
|
||||
|
||||
def test_prefetch_children(self):
|
||||
mongo_store = modulestore()._get_modulestore_by_type(MONGO_MODULESTORE_TYPE)
|
||||
mongo_store = modulestore()._get_modulestore_by_type(ModuleStoreEnum.Type.mongo)
|
||||
import_from_xml(modulestore(), self.user.id, 'common/test/data/', ['toy'])
|
||||
course_id = SlashSeparatedCourseKey('edX', 'toy', '2012_Fall')
|
||||
|
||||
@@ -1132,7 +1134,7 @@ class ContentStoreToyCourseTest(ContentStoreTestCase):
|
||||
mongo_store.collection.find = wrapper.find
|
||||
|
||||
# set the branch to 'publish' in order to prevent extra lookups of draft versions
|
||||
with store_branch_setting(mongo_store, BRANCH_PUBLISHED_ONLY):
|
||||
with store_branch_setting(mongo_store, ModuleStoreEnum.Branch.published_only):
|
||||
course = mongo_store.get_course(course_id, depth=2)
|
||||
|
||||
# make sure we haven't done too many round trips to DB
|
||||
|
||||
@@ -17,7 +17,7 @@ from student.tests.factories import UserFactory
|
||||
from student.roles import CourseInstructorRole, CourseStaffRole, GlobalStaff, OrgStaffRole, OrgInstructorRole
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory, check_mongo_calls
|
||||
from xmodule.modulestore import MONGO_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from opaque_keys.edx.locations import SlashSeparatedCourseKey
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.error_module import ErrorDescriptor
|
||||
@@ -199,7 +199,7 @@ class TestCourseListing(ModuleStoreTestCase):
|
||||
self.assertGreaterEqual(iteration_over_courses_time_2.elapsed, iteration_over_groups_time_2.elapsed)
|
||||
|
||||
# Now count the db queries
|
||||
store = modulestore()._get_modulestore_by_type(MONGO_MODULESTORE_TYPE)
|
||||
store = modulestore()._get_modulestore_by_type(ModuleStoreEnum.Type.mongo)
|
||||
with check_mongo_calls(store.collection, USER_COURSES_COUNT):
|
||||
courses_list = _accessible_courses_list_from_groups(self.request)
|
||||
|
||||
@@ -262,7 +262,7 @@ class TestCourseListing(ModuleStoreTestCase):
|
||||
Create good courses, courses that won't load, and deleted courses which still have
|
||||
roles. Test course listing.
|
||||
"""
|
||||
store = modulestore()._get_modulestore_by_type(MONGO_MODULESTORE_TYPE)
|
||||
store = modulestore()._get_modulestore_by_type(ModuleStoreEnum.Type.mongo)
|
||||
|
||||
course_location = SlashSeparatedCourseKey('testOrg', 'testCourse', 'RunBabyRun')
|
||||
self._create_course_with_access_groups(course_location, self.user)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import unittest
|
||||
|
||||
from xmodule import templates
|
||||
from xmodule.modulestore import SPLIT_MONGO_MODULESTORE_TYPE, BRANCH_NAME_DRAFT
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.tests import persistent_factories
|
||||
from xmodule.course_module import CourseDescriptor
|
||||
from xmodule.modulestore.django import modulestore, clear_existing_modulestores, _MIXED_MODULESTORE, \
|
||||
@@ -21,9 +21,9 @@ class TemplateTests(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
clear_existing_modulestores() # redundant w/ cleanup but someone was getting errors
|
||||
self.addCleanup(ModuleStoreTestCase.drop_mongo_collections, SPLIT_MONGO_MODULESTORE_TYPE)
|
||||
self.addCleanup(ModuleStoreTestCase.drop_mongo_collections, ModuleStoreEnum.Type.split)
|
||||
self.addCleanup(clear_existing_modulestores)
|
||||
self.split_store = modulestore()._get_modulestore_by_type(SPLIT_MONGO_MODULESTORE_TYPE)
|
||||
self.split_store = modulestore()._get_modulestore_by_type(ModuleStoreEnum.Type.split)
|
||||
|
||||
def test_get_templates(self):
|
||||
found = templates.all_templates()
|
||||
@@ -156,7 +156,7 @@ class TemplateTests(unittest.TestCase):
|
||||
persistent_factories.ItemFactory.create(display_name='chapter 1',
|
||||
parent_location=test_course.location)
|
||||
|
||||
id_locator = test_course.id.for_branch(BRANCH_NAME_DRAFT)
|
||||
id_locator = test_course.id.for_branch(ModuleStoreEnum.BranchName.draft)
|
||||
guid_locator = test_course.location.course_agnostic()
|
||||
# verify it can be retrieved by id
|
||||
self.assertIsInstance(self.split_store.get_course(id_locator), CourseDescriptor)
|
||||
@@ -241,7 +241,7 @@ class SplitAndLocMapperTests(unittest.TestCase):
|
||||
mapper = loc_mapper()
|
||||
|
||||
# instantiate mixed modulestore and thus split
|
||||
split_store = modulestore()._get_modulestore_by_type(SPLIT_MONGO_MODULESTORE_TYPE)
|
||||
split_store = modulestore()._get_modulestore_by_type(ModuleStoreEnum.Type.split)
|
||||
|
||||
# split must inject the same location mapper object since the mapper existed before it did
|
||||
self.assertEqual(split_store.loc_mapper, mapper)
|
||||
@@ -254,7 +254,7 @@ class SplitAndLocMapperTests(unittest.TestCase):
|
||||
self.assertIsNone(_loc_singleton)
|
||||
|
||||
# instantiate split before location mapper
|
||||
split_store = modulestore()._get_modulestore_by_type(SPLIT_MONGO_MODULESTORE_TYPE)
|
||||
split_store = modulestore()._get_modulestore_by_type(ModuleStoreEnum.Type.split)
|
||||
|
||||
# split must have instantiated loc_mapper
|
||||
mapper = loc_mapper()
|
||||
|
||||
@@ -21,7 +21,7 @@ from xblock.fragment import Fragment
|
||||
|
||||
import xmodule
|
||||
from xmodule.tabs import StaticTab, CourseTabList
|
||||
from xmodule.modulestore import PublishState, REVISION_OPTION_ALL
|
||||
from xmodule.modulestore import PublishState, ModuleStoreEnum
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.modulestore.draft import DIRECT_ONLY_CATEGORIES
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError, InvalidLocationError, DuplicateItemError
|
||||
@@ -527,7 +527,7 @@ def orphan_handler(request, course_key_string):
|
||||
# get_orphans returns the deprecated string format w/o revision
|
||||
usage_key = course_usage_key.make_usage_key_from_deprecated_string(itemloc)
|
||||
# need to delete all versions
|
||||
store.delete_item(usage_key, request.user.id, revision=REVISION_OPTION_ALL)
|
||||
store.delete_item(usage_key, request.user.id, revision=ModuleStoreEnum.RevisionOption.all)
|
||||
return JsonResponse({'deleted': items})
|
||||
else:
|
||||
raise PermissionDenied()
|
||||
|
||||
@@ -6,7 +6,7 @@ from staticfiles import finders
|
||||
from django.conf import settings
|
||||
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.modulestore import XML_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.contentstore.content import StaticContent
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -119,7 +119,9 @@ def replace_static_urls(text, data_directory, course_id=None, static_asset_path=
|
||||
if settings.DEBUG and finders.find(rest, True):
|
||||
return original
|
||||
# if we're running with a MongoBacked store course_namespace is not None, then use studio style urls
|
||||
elif (not static_asset_path) and course_id and modulestore().get_modulestore_type(course_id) != XML_MODULESTORE_TYPE:
|
||||
elif (not static_asset_path) \
|
||||
and course_id \
|
||||
and modulestore().get_modulestore_type(course_id) != ModuleStoreEnum.Type.xml:
|
||||
# first look in the static file pipeline and see if we are trying to reference
|
||||
# a piece of static content which is in the edx-platform repo (e.g. JS associated with an xmodule)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ from opaque_keys import InvalidKeyError
|
||||
import logging
|
||||
from django.db.models.query_utils import Q
|
||||
from django.db.utils import IntegrityError
|
||||
from xmodule.modulestore import XML_MODULESTORE_TYPE, MONGO_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.mixed import MixedModuleStore
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -27,8 +27,8 @@ class Migration(DataMigration):
|
||||
# Note: Remember to use orm['appname.ModelName'] rather than "from appname.models..."
|
||||
loc_map_collection = loc_mapper().location_map
|
||||
mixed_ms = modulestore()
|
||||
xml_ms = mixed_ms._get_modulestore_by_type(XML_MODULESTORE_TYPE)
|
||||
mongo_ms = mixed_ms._get_modulestore_by_type(MONGO_MODULESTORE_TYPE)
|
||||
xml_ms = mixed_ms._get_modulestore_by_type(ModuleStoreEnum.Type.xml)
|
||||
mongo_ms = mixed_ms._get_modulestore_by_type(ModuleStoreEnum.Type.mongo)
|
||||
|
||||
query = Q(name__startswith='staff') | Q(name__startswith='instructor') | Q(name__startswith='beta_testers')
|
||||
for group in orm['auth.Group'].objects.filter(query).exclude(name__contains="/").all():
|
||||
|
||||
@@ -6,7 +6,7 @@ from mock import patch, Mock
|
||||
|
||||
from student.tests.factories import UserFactory
|
||||
from student.roles import GlobalStaff
|
||||
from xmodule.modulestore import MONGO_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from opaque_keys.edx.locations import SlashSeparatedCourseKey
|
||||
@@ -90,7 +90,7 @@ class TestCourseListing(ModuleStoreTestCase):
|
||||
Create good courses, courses that won't load, and deleted courses which still have
|
||||
roles. Test course listing.
|
||||
"""
|
||||
mongo_store = modulestore()._get_modulestore_by_type(MONGO_MODULESTORE_TYPE)
|
||||
mongo_store = modulestore()._get_modulestore_by_type(ModuleStoreEnum.Type.mongo)
|
||||
|
||||
good_location = SlashSeparatedCourseKey('testOrg', 'testCourse', 'RunBabyRun')
|
||||
self._create_course_with_access_groups(good_location)
|
||||
|
||||
@@ -53,7 +53,7 @@ from dark_lang.models import DarkLangConfig
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from opaque_keys.edx.locations import SlashSeparatedCourseKey
|
||||
from xmodule.modulestore import XML_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -462,7 +462,7 @@ def dashboard(request):
|
||||
show_email_settings_for = frozenset(
|
||||
course.id for course, _enrollment in course_enrollment_pairs if (
|
||||
settings.FEATURES['ENABLE_INSTRUCTOR_EMAIL'] and
|
||||
modulestore().get_modulestore_type(course.id) != XML_MODULESTORE_TYPE and
|
||||
modulestore().get_modulestore_type(course.id) != ModuleStoreEnum.Type.xml and
|
||||
CourseAuthorization.instructor_email_enabled(course.id)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -19,7 +19,7 @@ from json import dumps
|
||||
from pymongo import MongoClient
|
||||
import xmodule.modulestore.django
|
||||
from xmodule.contentstore.django import _CONTENTSTORE
|
||||
from xmodule.modulestore import MONGO_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
|
||||
# There is an import issue when using django-staticfiles with lettuce
|
||||
# Lettuce assumes that we are using django.contrib.staticfiles,
|
||||
@@ -190,7 +190,7 @@ def reset_databases(scenario):
|
||||
mongo.drop_database(settings.CONTENTSTORE['DOC_STORE_CONFIG']['db'])
|
||||
_CONTENTSTORE.clear()
|
||||
|
||||
modulestore = xmodule.modulestore.django.modulestore()._get_modulestore_by_type(MONGO_MODULESTORE_TYPE)
|
||||
modulestore = xmodule.modulestore.django.modulestore()._get_modulestore_by_type(ModuleStoreEnum.Type.mongo)
|
||||
modulestore.collection.drop()
|
||||
xmodule.modulestore.django.clear_existing_modulestores()
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ from lettuce import world
|
||||
from django.contrib.auth.models import User, Group
|
||||
from student.models import CourseEnrollment
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.modulestore import MONGO_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.contentstore.django import contentstore
|
||||
|
||||
|
||||
@@ -72,6 +72,6 @@ def clear_courses():
|
||||
# (though it shouldn't), do this manually
|
||||
# from the bash shell to drop it:
|
||||
# $ mongo test_xmodule --eval "db.dropDatabase()"
|
||||
store = modulestore()._get_modulestore_by_type(MONGO_MODULESTORE_TYPE)
|
||||
store = modulestore()._get_modulestore_by_type(ModuleStoreEnum.Type.mongo)
|
||||
store.collection.drop()
|
||||
contentstore().fs_files.drop()
|
||||
|
||||
@@ -16,7 +16,7 @@ from xblock.fragment import Fragment
|
||||
from xmodule.seq_module import SequenceModule
|
||||
from xmodule.vertical_module import VerticalModule
|
||||
from xmodule.x_module import shim_xmodule_js, XModuleDescriptor, XModule, PREVIEW_VIEWS, STUDIO_VIEW
|
||||
from xmodule.modulestore import MONGO_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.django import modulestore
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -169,7 +169,7 @@ def add_staff_markup(user, has_instructor_access, block, view, frag, context):
|
||||
# TODO: make this more general, eg use an XModule attribute instead
|
||||
if isinstance(block, VerticalModule) and (not context or not context.get('child_of_vertical', False)):
|
||||
# check that the course is a mongo backed Studio course before doing work
|
||||
is_mongo_course = modulestore().get_modulestore_type(block.location.course_key) == MONGO_MODULESTORE_TYPE
|
||||
is_mongo_course = modulestore().get_modulestore_type(block.location.course_key) == ModuleStoreEnum.Type.mongo
|
||||
is_studio_course = block.course_edit_method == "Studio"
|
||||
|
||||
if is_studio_course and is_mongo_course:
|
||||
|
||||
@@ -25,44 +25,51 @@ from xblock.core import XBlock
|
||||
|
||||
log = logging.getLogger('edx.modulestore')
|
||||
|
||||
# Modulestore Types
|
||||
|
||||
SPLIT_MONGO_MODULESTORE_TYPE = 'split'
|
||||
MONGO_MODULESTORE_TYPE = 'mongo'
|
||||
XML_MODULESTORE_TYPE = 'xml'
|
||||
class ModuleStoreEnum(object):
|
||||
"""
|
||||
A class to encapsulate common constants that are used with the various modulestores.
|
||||
"""
|
||||
|
||||
class Type(object):
|
||||
"""
|
||||
The various types of modulestores provided
|
||||
"""
|
||||
split = 'split'
|
||||
mongo = 'mongo'
|
||||
xml = 'xml'
|
||||
|
||||
# Key Revision constants to use for Location and Usage Keys
|
||||
# Note: These values are persisted in the database, so should not be changed without migrations
|
||||
KEY_REVISION_DRAFT = 'draft'
|
||||
KEY_REVISION_PUBLISHED = None
|
||||
class RevisionOption(object):
|
||||
"""
|
||||
Revision constants to use for Module Store operations
|
||||
Note: These values are passed into store APIs and only used at run time
|
||||
"""
|
||||
# both DRAFT and PUBLISHED versions are queried, with preference to DRAFT versions
|
||||
draft_preferred = 'rev-opt-draft-preferred'
|
||||
|
||||
# only DRAFT versions are queried and no PUBLISHED versions
|
||||
draft_only = 'rev-opt-draft-only'
|
||||
|
||||
# Revision constants to use for Module Store operations
|
||||
# Note: These values are passed into store APIs and only used at run time
|
||||
# # only PUBLISHED versions are queried and no DRAFT versions
|
||||
published_only = 'rev-opt-published-only'
|
||||
|
||||
# both DRAFT and PUBLISHED versions are queried, with preference to DRAFT versions
|
||||
REVISION_OPTION_DRAFT_PREFERRED = 'rev-opt-draft-preferred'
|
||||
# all revisions are queried
|
||||
all = 'rev-opt-all'
|
||||
|
||||
# only DRAFT versions are queried and no PUBLISHED versions
|
||||
REVISION_OPTION_DRAFT_ONLY = 'rev-opt-draft-only'
|
||||
class Branch(object):
|
||||
"""
|
||||
Branch constants to use for stores, such as Mongo, that have only 2 branches: DRAFT and PUBLISHED
|
||||
Note: These values are taken from server configuration settings, so should not be changed without alerting DevOps
|
||||
"""
|
||||
draft_preferred = 'draft-preferred'
|
||||
published_only = 'published-only'
|
||||
|
||||
# # only PUBLISHED versions are queried and no DRAFT versions
|
||||
REVISION_OPTION_PUBLISHED_ONLY = 'rev-opt-published-only'
|
||||
|
||||
# all revisions are queried
|
||||
REVISION_OPTION_ALL = 'rev-opt-all'
|
||||
|
||||
|
||||
# Branch constants to use for stores, such as Mongo, that have only 2 branches: DRAFT and PUBLISHED
|
||||
# Note: These values are taken from server configuration settings, so should not be changed without alerting DevOps
|
||||
BRANCH_DRAFT_PREFERRED = 'draft'
|
||||
BRANCH_PUBLISHED_ONLY = 'published'
|
||||
|
||||
|
||||
# Branch constants to use for stores, such as Split, that have named branches
|
||||
BRANCH_NAME_DRAFT = 'draft'
|
||||
BRANCH_NAME_PUBLISHED = 'published'
|
||||
class BranchName(object):
|
||||
"""
|
||||
Branch constants to use for stores, such as Split, that have named branches
|
||||
"""
|
||||
draft = 'draft-branch'
|
||||
published = 'published-branch'
|
||||
|
||||
|
||||
class PublishState(object):
|
||||
|
||||
@@ -7,7 +7,7 @@ import pymongo
|
||||
import bson.son
|
||||
import urllib
|
||||
|
||||
from xmodule.modulestore import BRANCH_NAME_PUBLISHED, BRANCH_NAME_DRAFT
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.exceptions import InvalidLocationError, ItemNotFoundError
|
||||
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
|
||||
from opaque_keys.edx.locations import SlashSeparatedCourseKey
|
||||
@@ -55,7 +55,9 @@ class LocMapperStore(object):
|
||||
|
||||
# location_map functions
|
||||
def create_map_entry(self, course_key, org=None, offering=None,
|
||||
draft_branch=BRANCH_NAME_DRAFT, prod_branch=BRANCH_NAME_PUBLISHED, block_map=None):
|
||||
draft_branch=ModuleStoreEnum.BranchName.draft,
|
||||
prod_branch=ModuleStoreEnum.BranchName.published,
|
||||
block_map=None):
|
||||
"""
|
||||
Add a new entry to map this SlashSeparatedCourseKey to the new style CourseLocator.org & offering. If
|
||||
org and offering are not provided, it defaults them based on course_key.
|
||||
@@ -245,7 +247,7 @@ class LocMapperStore(object):
|
||||
for old_name, cat_to_usage in entry['block_map'].iteritems():
|
||||
for category, block_id in cat_to_usage.iteritems():
|
||||
# cache all entries and then figure out if we have the one we want
|
||||
# Always return revision=KEY_REVISION_PUBLISHED because the
|
||||
# Always return revision=MongoRevisionKey.published because the
|
||||
# old draft module store wraps locations as draft before
|
||||
# trying to access things.
|
||||
location = old_course_id.make_usage_key(
|
||||
|
||||
@@ -110,11 +110,7 @@ class MixedModuleStore(ModuleStoreWriteBase):
|
||||
def _get_modulestore_by_type(self, modulestore_type):
|
||||
"""
|
||||
This method should only really be used by tests and migration scripts when necessary.
|
||||
Returns the module store as requested by type. The type can be:
|
||||
|
||||
SPLIT_MONGO_MODULESTORE_TYPE
|
||||
MONGO_MODULESTORE_TYPE
|
||||
XML_MODULESTORE_TYPE
|
||||
Returns the module store as requested by type. The type can be a value from ModuleStoreEnum.Type.
|
||||
"""
|
||||
for store in self.modulestores:
|
||||
if store.get_modulestore_type() == modulestore_type:
|
||||
|
||||
@@ -33,11 +33,7 @@ from xblock.runtime import KvsFieldData
|
||||
from xblock.exceptions import InvalidScopeError
|
||||
from xblock.fields import Scope, ScopeIds, Reference, ReferenceList, ReferenceValueDict
|
||||
|
||||
from xmodule.modulestore import (
|
||||
ModuleStoreWriteBase, MONGO_MODULESTORE_TYPE,
|
||||
REVISION_OPTION_PUBLISHED_ONLY, REVISION_OPTION_DRAFT_PREFERRED,
|
||||
KEY_REVISION_DRAFT, KEY_REVISION_PUBLISHED
|
||||
)
|
||||
from xmodule.modulestore import ModuleStoreWriteBase, ModuleStoreEnum
|
||||
from opaque_keys.edx.locations import Location
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError, InvalidLocationError, ReferentialIntegrityError
|
||||
from xmodule.modulestore.inheritance import own_metadata, InheritanceMixin, inherit_metadata, InheritanceKeyValueStore
|
||||
@@ -58,6 +54,15 @@ SORT_REVISION_FAVOR_DRAFT = ('_id.revision', pymongo.DESCENDING)
|
||||
SORT_REVISION_FAVOR_PUBLISHED = ('_id.revision', pymongo.ASCENDING)
|
||||
|
||||
|
||||
class MongoRevisionKey(object):
|
||||
"""
|
||||
Key Revision constants to use for Location and Usage Keys in the Mongo modulestore
|
||||
Note: These values are persisted in the database, so should not be changed without migrations
|
||||
"""
|
||||
draft = 'draft'
|
||||
published = None
|
||||
|
||||
|
||||
class InvalidWriteError(Exception):
|
||||
"""
|
||||
Raised to indicate that writing to a particular key
|
||||
@@ -303,14 +308,14 @@ def as_draft(location):
|
||||
"""
|
||||
if location.category in DIRECT_ONLY_CATEGORIES:
|
||||
return location
|
||||
return location.replace(revision=KEY_REVISION_DRAFT)
|
||||
return location.replace(revision=MongoRevisionKey.draft)
|
||||
|
||||
|
||||
def as_published(location):
|
||||
"""
|
||||
Returns the Location that is the published version for `location`
|
||||
"""
|
||||
return location.replace(revision=KEY_REVISION_PUBLISHED)
|
||||
return location.replace(revision=MongoRevisionKey.published)
|
||||
|
||||
|
||||
class MongoModuleStore(ModuleStoreWriteBase):
|
||||
@@ -744,7 +749,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
|
||||
for key in ('tag', 'org', 'course', 'category', 'name', 'revision')
|
||||
])
|
||||
|
||||
def get_items(self, course_id, settings=None, content=None, key_revision=KEY_REVISION_PUBLISHED, **kwargs):
|
||||
def get_items(self, course_id, settings=None, content=None, key_revision=MongoRevisionKey.published, **kwargs):
|
||||
"""
|
||||
Returns:
|
||||
list of XModuleDescriptor instances for the matching items within the course with
|
||||
@@ -763,10 +768,10 @@ class MongoModuleStore(ModuleStoreWriteBase):
|
||||
content (dict): fields to look for which have content scope. Follows same syntax and
|
||||
rules as kwargs below.
|
||||
key_revision (str): the revision of the items you're looking for.
|
||||
KEY_REVISION_DRAFT - only returns drafts
|
||||
KEY_REVISION_PUBLISHED (equates to None) - only returns published
|
||||
MongoRevisionKey.draft - only returns drafts
|
||||
MongoRevisionKey.published (equates to None) - only returns published
|
||||
If you want one of each matching xblock but preferring draft to published, call this same method
|
||||
on the draft modulestore with REVISION_OPTION_DRAFT_PREFERRED.
|
||||
on the draft modulestore with ModuleStoreEnum.RevisionOption.draft_preferred.
|
||||
kwargs (key=value): what to look for within the course.
|
||||
Common qualifiers are ``category`` or any field name. if the target field is a list,
|
||||
then it searches for the given value in the list not list equivalence.
|
||||
@@ -1003,7 +1008,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
|
||||
value[key] = subvalue.to_deprecated_string()
|
||||
return jsonfields
|
||||
|
||||
def get_parent_location(self, location, revision=REVISION_OPTION_PUBLISHED_ONLY, **kwargs):
|
||||
def get_parent_location(self, location, revision=ModuleStoreEnum.RevisionOption.published_only, **kwargs):
|
||||
'''
|
||||
Find the location that is the parent of this location in this course.
|
||||
|
||||
@@ -1011,21 +1016,24 @@ class MongoModuleStore(ModuleStoreWriteBase):
|
||||
|
||||
Args:
|
||||
revision:
|
||||
REVISION_OPTION_PUBLISHED_ONLY - return only the PUBLISHED parent if it exists, else returns None
|
||||
REVISION_OPTION_DRAFT_PREFERRED - return either the DRAFT or PUBLISHED parent,
|
||||
preferring DRAFT, if parent(s) exists,
|
||||
else returns None
|
||||
ModuleStoreEnum.RevisionOption.published_only
|
||||
- return only the PUBLISHED parent if it exists, else returns None
|
||||
ModuleStoreEnum.RevisionOption.draft_preferred
|
||||
- return either the DRAFT or PUBLISHED parent,
|
||||
preferring DRAFT, if parent(s) exists,
|
||||
else returns None
|
||||
'''
|
||||
assert location.revision is None
|
||||
assert revision == REVISION_OPTION_PUBLISHED_ONLY or revision == REVISION_OPTION_DRAFT_PREFERRED
|
||||
assert revision == ModuleStoreEnum.RevisionOption.published_only \
|
||||
or revision == ModuleStoreEnum.RevisionOption.draft_preferred
|
||||
|
||||
# create a query with tag, org, course, and the children field set to the given location
|
||||
query = self._course_key_to_son(location.course_key)
|
||||
query['definition.children'] = location.to_deprecated_string()
|
||||
|
||||
# if only looking for the PUBLISHED parent, set the revision in the query to None
|
||||
if revision == REVISION_OPTION_PUBLISHED_ONLY:
|
||||
query['_id.revision'] = KEY_REVISION_PUBLISHED
|
||||
if revision == ModuleStoreEnum.RevisionOption.published_only:
|
||||
query['_id.revision'] = MongoRevisionKey.published
|
||||
|
||||
# query the collection, sorting by DRAFT first
|
||||
parents = self.collection.find(query, {'_id': True}, sort=[SORT_REVISION_FAVOR_DRAFT])
|
||||
@@ -1034,7 +1042,7 @@ class MongoModuleStore(ModuleStoreWriteBase):
|
||||
# no parents were found
|
||||
return None
|
||||
|
||||
if revision == REVISION_OPTION_PUBLISHED_ONLY:
|
||||
if revision == ModuleStoreEnum.RevisionOption.published_only:
|
||||
if parents.count() > 1:
|
||||
# should never have multiple PUBLISHED parents
|
||||
raise ReferentialIntegrityError(
|
||||
@@ -1055,16 +1063,11 @@ class MongoModuleStore(ModuleStoreWriteBase):
|
||||
|
||||
def get_modulestore_type(self, course_key=None):
|
||||
"""
|
||||
Returns an enumeration-like type reflecting the type of this modulestore
|
||||
The return can be one of:
|
||||
"xml" (for XML based courses),
|
||||
"mongo" for old-style MongoDB backed courses,
|
||||
"split" for new-style split MongoDB backed courses.
|
||||
|
||||
Returns an enumeration-like type reflecting the type of this modulestore per ModuleStoreEnum.Type
|
||||
Args:
|
||||
course_key: just for signature compatibility
|
||||
"""
|
||||
return MONGO_MODULESTORE_TYPE
|
||||
return ModuleStoreEnum.Type.mongo
|
||||
|
||||
def get_orphans(self, course_key):
|
||||
"""
|
||||
@@ -1114,6 +1117,6 @@ class MongoModuleStore(ModuleStoreWriteBase):
|
||||
Check that the db is reachable.
|
||||
"""
|
||||
if self.database.connection.alive():
|
||||
return {MONGO_MODULESTORE_TYPE: True}
|
||||
return {ModuleStoreEnum.Type.mongo: True}
|
||||
else:
|
||||
raise HeartbeatFailure("Can't connect to {}".format(self.database.name), 'mongo')
|
||||
|
||||
@@ -9,15 +9,11 @@ and otherwise returns i4x://org/course/cat/name).
|
||||
import pymongo
|
||||
|
||||
from xmodule.exceptions import InvalidVersionError
|
||||
from xmodule.modulestore import (
|
||||
PublishState,
|
||||
REVISION_OPTION_DRAFT_PREFERRED, REVISION_OPTION_DRAFT_ONLY, REVISION_OPTION_PUBLISHED_ONLY, REVISION_OPTION_ALL,
|
||||
KEY_REVISION_PUBLISHED, KEY_REVISION_DRAFT, BRANCH_PUBLISHED_ONLY, BRANCH_DRAFT_PREFERRED
|
||||
)
|
||||
from xmodule.modulestore import PublishState, ModuleStoreEnum
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError, DuplicateItemError, InvalidBranchSetting
|
||||
from xmodule.modulestore.mongo.base import (
|
||||
MongoModuleStore, as_draft, as_published,
|
||||
DIRECT_ONLY_CATEGORIES, SORT_REVISION_FAVOR_DRAFT,
|
||||
MongoModuleStore, MongoRevisionKey, as_draft, as_published,
|
||||
DIRECT_ONLY_CATEGORIES, SORT_REVISION_FAVOR_DRAFT
|
||||
)
|
||||
from opaque_keys.edx.locations import Location
|
||||
|
||||
@@ -29,8 +25,8 @@ def wrap_draft(item):
|
||||
Sets `item.is_draft` to `True` if the item is DRAFT, and `False` otherwise.
|
||||
Sets the item's location to the non-draft location in either case.
|
||||
"""
|
||||
setattr(item, 'is_draft', item.location.revision == KEY_REVISION_DRAFT)
|
||||
item.location = item.location.replace(revision=KEY_REVISION_PUBLISHED)
|
||||
setattr(item, 'is_draft', item.location.revision == MongoRevisionKey.draft)
|
||||
item.location = item.location.replace(revision=MongoRevisionKey.published)
|
||||
return item
|
||||
|
||||
|
||||
@@ -51,7 +47,7 @@ class DraftModuleStore(MongoModuleStore):
|
||||
branch_setting_func: a function that returns the branch setting to use for this store's operations
|
||||
"""
|
||||
super(DraftModuleStore, self).__init__(*args, **kwargs)
|
||||
self.branch_setting_func = kwargs.pop('branch_setting_func', lambda: BRANCH_PUBLISHED_ONLY)
|
||||
self.branch_setting_func = kwargs.pop('branch_setting_func', lambda: ModuleStoreEnum.Branch.published_only)
|
||||
|
||||
def get_item(self, usage_key, depth=0, revision=None):
|
||||
"""
|
||||
@@ -66,11 +62,11 @@ class DraftModuleStore(MongoModuleStore):
|
||||
get_children() to cache. None indicates to cache all descendants.
|
||||
|
||||
revision:
|
||||
REVISION_OPTION_PUBLISHED_ONLY - returns only the published item.
|
||||
REVISION_OPTION_DRAFT_ONLY - returns only the draft item.
|
||||
ModuleStoreEnum.RevisionOption.published_only - returns only the published item.
|
||||
ModuleStoreEnum.RevisionOption.draft_only - returns only the draft item.
|
||||
None - uses the branch setting as follows:
|
||||
if branch setting is BRANCH_PUBLISHED_ONLY, returns only the published item.
|
||||
if branch setting is BRANCH_DRAFT_PREFERRED, returns either draft or published item,
|
||||
if branch setting is ModuleStoreEnum.Branch.published_only, returns only the published item.
|
||||
if branch setting is ModuleStoreEnum.Branch.draft_preferred, returns either draft or published item,
|
||||
preferring draft.
|
||||
|
||||
Note: If the item is in DIRECT_ONLY_CATEGORIES, then returns only the PUBLISHED
|
||||
@@ -89,8 +85,8 @@ class DraftModuleStore(MongoModuleStore):
|
||||
def get_draft():
|
||||
return wrap_draft(super(DraftModuleStore, self).get_item(as_draft(usage_key), depth=depth))
|
||||
|
||||
# return the published version if REVISION_OPTION_PUBLISHED_ONLY is requested
|
||||
if revision == REVISION_OPTION_PUBLISHED_ONLY:
|
||||
# return the published version if ModuleStoreEnum.RevisionOption.published_only is requested
|
||||
if revision == ModuleStoreEnum.RevisionOption.published_only:
|
||||
return get_published()
|
||||
|
||||
# if the item is direct-only, there can only be a published version
|
||||
@@ -98,10 +94,10 @@ class DraftModuleStore(MongoModuleStore):
|
||||
return get_published()
|
||||
|
||||
# return the draft version (without any fallback to PUBLISHED) if DRAFT-ONLY is requested
|
||||
elif revision == REVISION_OPTION_DRAFT_ONLY:
|
||||
elif revision == ModuleStoreEnum.RevisionOption.draft_only:
|
||||
return get_draft()
|
||||
|
||||
elif self.branch_setting_func() == BRANCH_PUBLISHED_ONLY:
|
||||
elif self.branch_setting_func() == ModuleStoreEnum.Branch.published_only:
|
||||
return get_published()
|
||||
|
||||
else:
|
||||
@@ -120,11 +116,11 @@ class DraftModuleStore(MongoModuleStore):
|
||||
|
||||
Args:
|
||||
revision:
|
||||
REVISION_OPTION_PUBLISHED_ONLY - checks for the published item only
|
||||
REVISION_OPTION_DRAFT_ONLY - checks for the draft item only
|
||||
ModuleStoreEnum.RevisionOption.published_only - checks for the published item only
|
||||
ModuleStoreEnum.RevisionOption.draft_only - checks for the draft item only
|
||||
None - uses the branch setting, as follows:
|
||||
if branch setting is BRANCH_PUBLISHED_ONLY, checks for the published item only
|
||||
if branch setting is BRANCH_DRAFT_PREFERRED, checks whether draft or published item exists
|
||||
if branch setting is ModuleStoreEnum.Branch.published_only, checks for the published item only
|
||||
if branch setting is ModuleStoreEnum.Branch.draft_preferred, checks whether draft or published item exists
|
||||
"""
|
||||
def has_published():
|
||||
return super(DraftModuleStore, self).has_item(usage_key)
|
||||
@@ -132,9 +128,10 @@ class DraftModuleStore(MongoModuleStore):
|
||||
def has_draft():
|
||||
return super(DraftModuleStore, self).has_item(as_draft(usage_key))
|
||||
|
||||
if revision == REVISION_OPTION_DRAFT_ONLY:
|
||||
if revision == ModuleStoreEnum.RevisionOption.draft_only:
|
||||
return has_draft()
|
||||
elif revision == REVISION_OPTION_PUBLISHED_ONLY or self.branch_setting_func() == BRANCH_PUBLISHED_ONLY:
|
||||
elif revision == ModuleStoreEnum.RevisionOption.published_only \
|
||||
or self.branch_setting_func() == ModuleStoreEnum.Branch.published_only:
|
||||
return has_published()
|
||||
else:
|
||||
key = usage_key.to_deprecated_son(prefix='_id.')
|
||||
@@ -150,9 +147,9 @@ class DraftModuleStore(MongoModuleStore):
|
||||
Args:
|
||||
location (UsageKey): assumes the location's revision is None; so, uses revision keyword solely
|
||||
key_revision:
|
||||
KEY_REVISION_DRAFT - return only the draft parent
|
||||
KEY_REVISION_PUBLISHED - return only the published parent
|
||||
REVISION_OPTION_ALL - return both draft and published parents
|
||||
MongoRevisionKey.draft - return only the draft parent
|
||||
MongoRevisionKey.published - return only the published parent
|
||||
ModuleStoreEnum.RevisionOption.all - return both draft and published parents
|
||||
"""
|
||||
_verify_revision_is_published(location)
|
||||
|
||||
@@ -168,8 +165,8 @@ class DraftModuleStore(MongoModuleStore):
|
||||
Location._from_deprecated_son(parent['_id'], location.course_key.run)
|
||||
for parent in parents
|
||||
if (
|
||||
# return all versions of the parent if revision is REVISION_OPTION_ALL
|
||||
key_revision == REVISION_OPTION_ALL or
|
||||
# return all versions of the parent if revision is ModuleStoreEnum.RevisionOption.all
|
||||
key_revision == ModuleStoreEnum.RevisionOption.all or
|
||||
# return this parent if it's direct-only, regardless of which revision is requested
|
||||
parent['_id']['category'] in DIRECT_ONLY_CATEGORIES or
|
||||
# return this parent only if its revision matches the requested one
|
||||
@@ -186,9 +183,11 @@ class DraftModuleStore(MongoModuleStore):
|
||||
Args:
|
||||
revision:
|
||||
None - uses the branch setting for the revision
|
||||
REVISION_OPTION_PUBLISHED_ONLY - return only the PUBLISHED parent if it exists, else returns None
|
||||
REVISION_OPTION_DRAFT_PREFERRED - return either the DRAFT or PUBLISHED parent, preferring DRAFT, if parent(s) exists,
|
||||
else returns None
|
||||
ModuleStoreEnum.RevisionOption.published_only
|
||||
- return only the PUBLISHED parent if it exists, else returns None
|
||||
ModuleStoreEnum.RevisionOption.draft_preferred
|
||||
- return either the DRAFT or PUBLISHED parent, preferring DRAFT, if parent(s) exists,
|
||||
else returns None
|
||||
|
||||
If the draft has a different parent than the published, it returns only
|
||||
the draft's parent. Because parents don't record their children's revisions, this
|
||||
@@ -197,9 +196,9 @@ class DraftModuleStore(MongoModuleStore):
|
||||
Only xml_exporter currently uses this argument. Others should avoid it.
|
||||
'''
|
||||
if revision is None:
|
||||
revision = REVISION_OPTION_PUBLISHED_ONLY \
|
||||
if self.branch_setting_func() == BRANCH_PUBLISHED_ONLY \
|
||||
else REVISION_OPTION_DRAFT_PREFERRED
|
||||
revision = ModuleStoreEnum.RevisionOption.published_only \
|
||||
if self.branch_setting_func() == ModuleStoreEnum.Branch.published_only \
|
||||
else ModuleStoreEnum.RevisionOption.draft_preferred
|
||||
return super(DraftModuleStore, self).get_parent_location(location, revision, **kwargs)
|
||||
|
||||
def create_xmodule(self, location, definition_data=None, metadata=None, runtime=None, fields={}):
|
||||
@@ -213,7 +212,7 @@ class DraftModuleStore(MongoModuleStore):
|
||||
:param runtime: if you already have an xmodule from the course, the xmodule.runtime value
|
||||
:param fields: a dictionary of field names and values for the new xmodule
|
||||
"""
|
||||
self._verify_branch_setting(BRANCH_DRAFT_PREFERRED)
|
||||
self._verify_branch_setting(ModuleStoreEnum.Branch.draft_preferred)
|
||||
|
||||
if location.category not in DIRECT_ONLY_CATEGORIES:
|
||||
location = as_draft(location)
|
||||
@@ -236,12 +235,12 @@ class DraftModuleStore(MongoModuleStore):
|
||||
settings: not used
|
||||
content: not used
|
||||
revision:
|
||||
REVISION_OPTION_PUBLISHED_ONLY - returns only Published items
|
||||
REVISION_OPTION_DRAFT_ONLY - returns only Draft items
|
||||
ModuleStoreEnum.RevisionOption.published_only - returns only Published items
|
||||
ModuleStoreEnum.RevisionOption.draft_only - returns only Draft items
|
||||
None - uses the branch setting, as follows:
|
||||
if the branch setting is BRANCH_PUBLISHED_ONLY,
|
||||
if the branch setting is ModuleStoreEnum.Branch.published_only,
|
||||
returns only Published items
|
||||
if the branch setting is BRANCH_DRAFT_PREFERRED,
|
||||
if the branch setting is ModuleStoreEnum.Branch.draft_preferred,
|
||||
returns either Draft or Published, preferring Draft items.
|
||||
kwargs (key=value): what to look for within the course.
|
||||
Common qualifiers are ``category`` or any field name. if the target field is a list,
|
||||
@@ -253,20 +252,21 @@ class DraftModuleStore(MongoModuleStore):
|
||||
return super(DraftModuleStore, self).get_items(course_key, key_revision=key_revision, **kwargs)
|
||||
|
||||
def draft_items():
|
||||
return [wrap_draft(item) for item in base_get_items(KEY_REVISION_DRAFT)]
|
||||
return [wrap_draft(item) for item in base_get_items(MongoRevisionKey.draft)]
|
||||
|
||||
def published_items(draft_items):
|
||||
# filters out items that are not already in draft_items
|
||||
draft_items_locations = {item.location for item in draft_items}
|
||||
return [
|
||||
item for item in
|
||||
base_get_items(KEY_REVISION_PUBLISHED)
|
||||
base_get_items(MongoRevisionKey.published)
|
||||
if item.location not in draft_items_locations
|
||||
]
|
||||
|
||||
if revision == REVISION_OPTION_DRAFT_ONLY:
|
||||
if revision == ModuleStoreEnum.RevisionOption.draft_only:
|
||||
return draft_items()
|
||||
elif revision == REVISION_OPTION_PUBLISHED_ONLY or self.branch_setting_func() == BRANCH_PUBLISHED_ONLY:
|
||||
elif revision == ModuleStoreEnum.RevisionOption.published_only \
|
||||
or self.branch_setting_func() == ModuleStoreEnum.Branch.published_only:
|
||||
return published_items([])
|
||||
else:
|
||||
draft_items = draft_items()
|
||||
@@ -293,7 +293,7 @@ class DraftModuleStore(MongoModuleStore):
|
||||
Internal method with additional internal parameters to convert a subtree to draft.
|
||||
|
||||
Args:
|
||||
location: the location of the source (its revision must be KEY_REVISION_PUBLISHED)
|
||||
location: the location of the source (its revision must be MongoRevisionKey.published)
|
||||
user_id: the ID of the user doing the operation
|
||||
delete_published (Boolean): intended for use by unpublish
|
||||
ignore_if_draft(Boolean): for internal use only as part of depth first change
|
||||
@@ -304,7 +304,7 @@ class DraftModuleStore(MongoModuleStore):
|
||||
DuplicateItemError: if the source or any of its descendants already has a draft copy
|
||||
"""
|
||||
# verify input conditions
|
||||
self._verify_branch_setting(BRANCH_DRAFT_PREFERRED)
|
||||
self._verify_branch_setting(ModuleStoreEnum.Branch.draft_preferred)
|
||||
_verify_revision_is_published(location)
|
||||
|
||||
# ensure we are not creating a DRAFT of an item that is direct-only
|
||||
@@ -322,7 +322,7 @@ class DraftModuleStore(MongoModuleStore):
|
||||
next_tier.append(child_loc.to_deprecated_son())
|
||||
|
||||
# insert a new DRAFT version of the item
|
||||
item['_id']['revision'] = KEY_REVISION_DRAFT
|
||||
item['_id']['revision'] = MongoRevisionKey.draft
|
||||
# ensure keys are in fixed and right order before inserting
|
||||
item['_id'] = self._id_dict_to_son(item['_id'])
|
||||
try:
|
||||
@@ -334,7 +334,7 @@ class DraftModuleStore(MongoModuleStore):
|
||||
|
||||
# delete the old PUBLISHED version if requested
|
||||
if delete_published:
|
||||
item['_id']['revision'] = KEY_REVISION_PUBLISHED
|
||||
item['_id']['revision'] = MongoRevisionKey.published
|
||||
to_be_deleted.append(item['_id'])
|
||||
|
||||
return next_tier
|
||||
@@ -352,7 +352,7 @@ class DraftModuleStore(MongoModuleStore):
|
||||
In addition to the superclass's behavior, this method converts the unit to draft if it's not
|
||||
direct-only and not already draft.
|
||||
"""
|
||||
self._verify_branch_setting(BRANCH_DRAFT_PREFERRED)
|
||||
self._verify_branch_setting(ModuleStoreEnum.Branch.draft_preferred)
|
||||
|
||||
# if the xblock is direct-only, update the PUBLISHED version
|
||||
if xblock.location.category in DIRECT_ONLY_CATEGORIES:
|
||||
@@ -380,7 +380,7 @@ class DraftModuleStore(MongoModuleStore):
|
||||
The method determines which revisions to delete. It disconnects and deletes the subtree.
|
||||
In general, it assumes deletes only occur on drafts except for direct_only. The only exceptions
|
||||
are internal calls like deleting orphans (during publishing as well as from delete_orphan view).
|
||||
To indicate that all versions should be deleted, pass the keyword revision=REVISION_OPTION_ALL.
|
||||
To indicate that all versions should be deleted, pass the keyword revision=ModuleStoreEnum.RevisionOption.all.
|
||||
|
||||
* Deleting a DIRECT_ONLY_CATEGORIES block, deletes both draft and published children and removes from parent.
|
||||
* Deleting a specific version of block whose parent is of DIRECT_ONLY_CATEGORIES, only removes it from parent if
|
||||
@@ -392,32 +392,34 @@ class DraftModuleStore(MongoModuleStore):
|
||||
user_id: id of the user deleting the item
|
||||
revision:
|
||||
None - deletes the item and its subtree, and updates the parents per description above
|
||||
REVISION_OPTION_PUBLISHED_ONLY - removes only Published versions
|
||||
REVISION_OPTION_ALL - removes both Draft and Published parents
|
||||
ModuleStoreEnum.RevisionOption.published_only - removes only Published versions
|
||||
ModuleStoreEnum.RevisionOption.all - removes both Draft and Published parents
|
||||
currently only provided by contentstore.views.item.orphan_handler
|
||||
"""
|
||||
self._verify_branch_setting(BRANCH_DRAFT_PREFERRED)
|
||||
self._verify_branch_setting(ModuleStoreEnum.Branch.draft_preferred)
|
||||
_verify_revision_is_published(location)
|
||||
|
||||
is_item_direct_only = location.category in DIRECT_ONLY_CATEGORIES
|
||||
if is_item_direct_only or revision == REVISION_OPTION_PUBLISHED_ONLY:
|
||||
parent_revision = KEY_REVISION_PUBLISHED
|
||||
elif revision == REVISION_OPTION_ALL:
|
||||
parent_revision = REVISION_OPTION_ALL
|
||||
if is_item_direct_only or revision == ModuleStoreEnum.RevisionOption.published_only:
|
||||
parent_revision = MongoRevisionKey.published
|
||||
elif revision == ModuleStoreEnum.RevisionOption.all:
|
||||
parent_revision = ModuleStoreEnum.RevisionOption.all
|
||||
else:
|
||||
parent_revision = KEY_REVISION_DRAFT
|
||||
parent_revision = MongoRevisionKey.draft
|
||||
|
||||
# remove subtree from its parent
|
||||
parent_locations = self._get_raw_parent_locations(location, key_revision=parent_revision)
|
||||
# there could be 2 parents if
|
||||
# Case 1: the draft item moved from one parent to another
|
||||
# Case 2: revision==REVISION_OPTION_ALL and the single parent has 2 versions: draft and published
|
||||
# Case 2: revision==ModuleStoreEnum.RevisionOption.all and the single parent has 2 versions: draft and published
|
||||
for parent_location in parent_locations:
|
||||
# don't remove from direct_only parent if other versions of this still exists
|
||||
if not is_item_direct_only and parent_location.category in DIRECT_ONLY_CATEGORIES:
|
||||
# see if other version of root exists
|
||||
alt_location = location.replace(
|
||||
revision=KEY_REVISION_PUBLISHED if location.revision == KEY_REVISION_DRAFT else KEY_REVISION_DRAFT
|
||||
revision=MongoRevisionKey.published
|
||||
if location.revision == MongoRevisionKey.draft
|
||||
else MongoRevisionKey.draft
|
||||
)
|
||||
if super(DraftModuleStore, self).has_item(alt_location):
|
||||
continue
|
||||
@@ -427,9 +429,9 @@ class DraftModuleStore(MongoModuleStore):
|
||||
parent_block.location = parent_location # ensure the location is with the correct revision
|
||||
self.update_item(parent_block, user_id)
|
||||
|
||||
if is_item_direct_only or revision == REVISION_OPTION_ALL:
|
||||
if is_item_direct_only or revision == ModuleStoreEnum.RevisionOption.all:
|
||||
as_functions = [as_draft, as_published]
|
||||
elif revision == REVISION_OPTION_PUBLISHED_ONLY:
|
||||
elif revision == ModuleStoreEnum.RevisionOption.published_only:
|
||||
as_functions = [as_published]
|
||||
else:
|
||||
as_functions = [as_draft]
|
||||
@@ -574,7 +576,7 @@ class DraftModuleStore(MongoModuleStore):
|
||||
to_be_deleted.append(as_draft(item_location).to_deprecated_son())
|
||||
|
||||
# verify input conditions
|
||||
self._verify_branch_setting(BRANCH_DRAFT_PREFERRED)
|
||||
self._verify_branch_setting(ModuleStoreEnum.Branch.draft_preferred)
|
||||
_verify_revision_is_published(location)
|
||||
|
||||
_internal_depth_first(location)
|
||||
@@ -589,7 +591,7 @@ class DraftModuleStore(MongoModuleStore):
|
||||
NOTE: unlike publish, this gives an error if called above the draftable level as it's intended
|
||||
to remove things from the published version
|
||||
"""
|
||||
self._verify_branch_setting(BRANCH_DRAFT_PREFERRED)
|
||||
self._verify_branch_setting(ModuleStoreEnum.Branch.draft_preferred)
|
||||
return self._convert_to_draft(location, user_id, delete_published=True)
|
||||
|
||||
def _query_children_for_cache_children(self, course_key, items):
|
||||
@@ -600,7 +602,7 @@ class DraftModuleStore(MongoModuleStore):
|
||||
for non_draft in to_process_non_drafts:
|
||||
to_process_dict[Location._from_deprecated_son(non_draft["_id"], course_key.run)] = non_draft
|
||||
|
||||
if self.branch_setting_func() == BRANCH_DRAFT_PREFERRED:
|
||||
if self.branch_setting_func() == ModuleStoreEnum.Branch.draft_preferred:
|
||||
# now query all draft content in another round-trip
|
||||
query = []
|
||||
for item in items:
|
||||
@@ -664,6 +666,6 @@ class DraftModuleStore(MongoModuleStore):
|
||||
|
||||
def _verify_revision_is_published(location):
|
||||
"""
|
||||
Asserts that the revision set on the given location is KEY_REVISION_PUBLISHED
|
||||
Asserts that the revision set on the given location is MongoRevisionKey.published
|
||||
"""
|
||||
assert location.revision == KEY_REVISION_PUBLISHED
|
||||
assert location.revision == MongoRevisionKey.published
|
||||
|
||||
@@ -7,7 +7,7 @@ In general, it's strategy is to treat the other modulestores as read-only and to
|
||||
manipulate storage but use existing api's.
|
||||
'''
|
||||
from xblock.fields import Reference, ReferenceList, ReferenceValueDict
|
||||
from xmodule.modulestore import BRANCH_NAME_DRAFT, BRANCH_NAME_PUBLISHED, REVISION_OPTION_DRAFT_ONLY
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
|
||||
|
||||
class SplitMigrator(object):
|
||||
@@ -85,7 +85,7 @@ class SplitMigrator(object):
|
||||
# after done w/ published items, add version for DRAFT pointing to the published structure
|
||||
index_info = self.split_modulestore.get_course_index_info(course_version_locator)
|
||||
versions = index_info['versions']
|
||||
versions[BRANCH_NAME_DRAFT] = versions[BRANCH_NAME_PUBLISHED]
|
||||
versions[ModuleStoreEnum.BranchName.draft] = versions[ModuleStoreEnum.BranchName.published]
|
||||
self.split_modulestore.update_course_index(index_info)
|
||||
|
||||
# clean up orphans in published version: in old mongo, parents pointed to the union of their published and draft
|
||||
@@ -98,11 +98,11 @@ class SplitMigrator(object):
|
||||
"""
|
||||
# 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 = published_course_key.for_branch(BRANCH_NAME_DRAFT)
|
||||
new_draft_course_loc = published_course_key.for_branch(ModuleStoreEnum.BranchName.draft)
|
||||
# to prevent race conditions of grandchilden being added before their parents and thus having no parent to
|
||||
# add to
|
||||
awaiting_adoption = {}
|
||||
for module in self.draft_modulestore.get_items(course_key, revision=REVISION_OPTION_DRAFT_ONLY):
|
||||
for module in self.draft_modulestore.get_items(course_key, revision=ModuleStoreEnum.RevisionOption.draft_only):
|
||||
new_locator = self.loc_mapper.translate_location(
|
||||
module.location, False, add_entry_if_missing=True
|
||||
)
|
||||
|
||||
@@ -61,7 +61,7 @@ from opaque_keys.edx.locator import (
|
||||
from xmodule.modulestore.exceptions import InsufficientSpecificationError, VersionConflictError, DuplicateItemError, \
|
||||
DuplicateCourseError
|
||||
from xmodule.modulestore import (
|
||||
inheritance, ModuleStoreWriteBase, SPLIT_MONGO_MODULESTORE_TYPE, BRANCH_NAME_DRAFT, BRANCH_NAME_PUBLISHED
|
||||
inheritance, ModuleStoreWriteBase, ModuleStoreEnum
|
||||
)
|
||||
|
||||
from ..exceptions import ItemNotFoundError
|
||||
@@ -296,7 +296,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
|
||||
}
|
||||
return envelope
|
||||
|
||||
def get_courses(self, branch=BRANCH_NAME_DRAFT, qualifiers=None):
|
||||
def get_courses(self, branch=ModuleStoreEnum.BranchName.draft, qualifiers=None):
|
||||
'''
|
||||
Returns a list of course descriptors matching any given qualifiers.
|
||||
|
||||
@@ -304,9 +304,9 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
|
||||
legal query for mongo to use against the active_versions collection.
|
||||
|
||||
Note, this is to find the current head of the named branch type
|
||||
(e.g., BRANCH_NAME_DRAFT). To get specific versions via guid use get_course.
|
||||
(e.g., ModuleStoreEnum.BranchName.draft). To get specific versions via guid use get_course.
|
||||
|
||||
:param branch: the branch for which to return courses. Default value is BRANCH_NAME_DRAFT.
|
||||
:param branch: the branch for which to return courses. Default value is ModuleStoreEnum.BranchName.draft.
|
||||
:param qualifiers: an optional dict restricting which elements should match
|
||||
'''
|
||||
if qualifiers is None:
|
||||
@@ -385,9 +385,9 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
|
||||
:param usage_key: the block to check
|
||||
:return: True if the draft and published versions differ
|
||||
"""
|
||||
draft = self.get_item(usage_key.for_branch(BRANCH_NAME_DRAFT))
|
||||
draft = self.get_item(usage_key.for_branch(ModuleStoreEnum.BranchName.draft))
|
||||
try:
|
||||
published = self.get_item(usage_key.for_branch(BRANCH_NAME_PUBLISHED))
|
||||
published = self.get_item(usage_key.for_branch(ModuleStoreEnum.BranchName.published))
|
||||
except ItemNotFoundError:
|
||||
return True
|
||||
|
||||
@@ -872,7 +872,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
|
||||
|
||||
def create_course(
|
||||
self, org, offering, user_id, fields=None,
|
||||
master_branch=BRANCH_NAME_DRAFT, versions_dict=None, root_category='course',
|
||||
master_branch=ModuleStoreEnum.BranchName.draft, versions_dict=None, root_category='course',
|
||||
root_block_id='course', **kwargs
|
||||
):
|
||||
"""
|
||||
@@ -908,7 +908,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
|
||||
master_branch: the tag (key) for the version name in the dict which is the DRAFT version. Not the actual
|
||||
version guid, but what to call it.
|
||||
|
||||
versions_dict: the starting version ids where the keys are the tags such as DRAFT and REVISION_OPTION_PUBLISHED_ONLY
|
||||
versions_dict: the starting version ids where the keys are the tags such as DRAFT and PUBLISHED
|
||||
and the values are structure guids. If provided, the new course will reuse this version (unless you also
|
||||
provide any fields overrides, see above). if not provided, will create a mostly empty course
|
||||
structure with just a category course root xblock.
|
||||
@@ -1298,7 +1298,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
|
||||
self._update_head(index_entry, destination_course.branch, destination_structure['_id'])
|
||||
|
||||
def unpublish(self, location, user_id):
|
||||
published_location = location.replace(branch=REVISION_OPTION_PUBLISHED_ONLY)
|
||||
published_location = location.replace(branch=ModuleStoreEnum.RevisionOption.published_only)
|
||||
self.delete_item(published_location, user_id)
|
||||
|
||||
def update_course_index(self, updated_index_entry):
|
||||
@@ -1465,7 +1465,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
|
||||
Args:
|
||||
course_key: just for signature compatibility
|
||||
"""
|
||||
return SPLIT_MONGO_MODULESTORE_TYPE
|
||||
return ModuleStoreEnum.Type.split
|
||||
|
||||
def internal_clean_children(self, course_locator):
|
||||
"""
|
||||
@@ -1797,7 +1797,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
|
||||
"""
|
||||
Check that the db is reachable.
|
||||
"""
|
||||
return {SPLIT_MONGO_MODULESTORE_TYPE: self.db_connection.heartbeat()}
|
||||
return {ModuleStoreEnum.Type.split: self.db_connection.heartbeat()}
|
||||
|
||||
def compute_publish_state(self, xblock):
|
||||
"""
|
||||
|
||||
@@ -2,7 +2,7 @@ import re
|
||||
import logging
|
||||
|
||||
from xmodule.contentstore.content import StaticContent
|
||||
from xmodule.modulestore import REVISION_OPTION_PUBLISHED_ONLY, REVISION_OPTION_DRAFT_ONLY
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
|
||||
|
||||
def _prefix_only_url_replace_regex(prefix):
|
||||
@@ -136,12 +136,12 @@ def clone_course(modulestore, contentstore, source_course_id, dest_course_id, us
|
||||
raise Exception("Cannot find a course at {0}. Aborting".format(source_course_id))
|
||||
|
||||
# Get all modules under this namespace which is (tag, org, course) tuple
|
||||
modules = modulestore.get_items(source_course_id, revision=REVISION_OPTION_PUBLISHED_ONLY)
|
||||
modules = modulestore.get_items(source_course_id, revision=ModuleStoreEnum.RevisionOption.published_only)
|
||||
_clone_modules(modulestore, modules, source_course_id, dest_course_id, user_id)
|
||||
course_location = dest_course_id.make_usage_key('course', dest_course_id.run)
|
||||
modulestore.publish(course_location, user_id)
|
||||
|
||||
modules = modulestore.get_items(source_course_id, revision=REVISION_OPTION_DRAFT_ONLY)
|
||||
modules = modulestore.get_items(source_course_id, revision=ModuleStoreEnum.RevisionOption.draft_only)
|
||||
_clone_modules(modulestore, modules, source_course_id, dest_course_id, user_id)
|
||||
|
||||
# now iterate through all of the assets and clone them
|
||||
|
||||
@@ -6,7 +6,7 @@ from uuid import uuid4
|
||||
from django.test import TestCase
|
||||
from xmodule.modulestore.django import (
|
||||
modulestore, clear_existing_modulestores, loc_mapper)
|
||||
from xmodule.modulestore import MONGO_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.contentstore.django import contentstore
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ class ModuleStoreTestCase(TestCase):
|
||||
return updated_course
|
||||
|
||||
@staticmethod
|
||||
def drop_mongo_collections(modulestore_type=MONGO_MODULESTORE_TYPE):
|
||||
def drop_mongo_collections(modulestore_type=ModuleStoreEnum.Type.mongo):
|
||||
"""
|
||||
If using a Mongo-backed modulestore & contentstore, drop the collections.
|
||||
"""
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from xmodule.modulestore import SPLIT_MONGO_MODULESTORE_TYPE, BRANCH_NAME_DRAFT
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.course_module import CourseDescriptor
|
||||
from xmodule.x_module import XModuleDescriptor
|
||||
import factory
|
||||
@@ -15,7 +15,7 @@ class SplitFactory(factory.Factory):
|
||||
# Delayed import so that we only depend on django if the caller
|
||||
# hasn't provided their own modulestore
|
||||
from xmodule.modulestore.django import modulestore
|
||||
return modulestore()._get_modulestore_by_type(SPLIT_MONGO_MODULESTORE_TYPE)
|
||||
return modulestore()._get_modulestore_by_type(ModuleStoreEnum.Type.split)
|
||||
|
||||
|
||||
class PersistentCourseFactory(SplitFactory):
|
||||
@@ -25,7 +25,7 @@ class PersistentCourseFactory(SplitFactory):
|
||||
keywords: any xblock field plus (note, the below are filtered out; so, if they
|
||||
become legitimate xblock fields, they won't be settable via this factory)
|
||||
* org: defaults to textX
|
||||
* master_branch: (optional) defaults to BRANCH_NAME_DRAFT
|
||||
* master_branch: (optional) defaults to ModuleStoreEnum.BranchName.draft
|
||||
* user_id: (optional) defaults to 'test_user'
|
||||
* display_name (xblock field): will default to 'Robot Super Course' unless provided
|
||||
"""
|
||||
@@ -34,7 +34,7 @@ class PersistentCourseFactory(SplitFactory):
|
||||
# pylint: disable=W0613
|
||||
@classmethod
|
||||
def _create(cls, target_class, offering='999', org='testX', user_id='test_user',
|
||||
master_branch=BRANCH_NAME_DRAFT, **kwargs):
|
||||
master_branch=ModuleStoreEnum.BranchName.draft, **kwargs):
|
||||
|
||||
modulestore = kwargs.pop('modulestore')
|
||||
root_block_id = kwargs.pop('root_block_id', 'course')
|
||||
|
||||
@@ -5,7 +5,8 @@ import unittest
|
||||
import uuid
|
||||
from opaque_keys.edx.locations import Location
|
||||
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
|
||||
from xmodule.modulestore import BRANCH_NAME_PUBLISHED, BRANCH_NAME_DRAFT, KEY_REVISION_PUBLISHED
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.mongo.base import MongoRevisionKey
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError, InvalidLocationError
|
||||
from xmodule.modulestore.loc_mapper_store import LocMapperStore
|
||||
from mock import Mock
|
||||
@@ -63,8 +64,8 @@ class TestLocationMapper(LocMapperSetupSansDjango):
|
||||
self.assertIsNotNone(entry, "Didn't find entry")
|
||||
self.assertEqual(entry['org'], org)
|
||||
self.assertEqual(entry['offering'], '{}.{}'.format(course1, run))
|
||||
self.assertEqual(entry['draft_branch'], BRANCH_NAME_DRAFT)
|
||||
self.assertEqual(entry['prod_branch'], BRANCH_NAME_PUBLISHED)
|
||||
self.assertEqual(entry['draft_branch'], ModuleStoreEnum.BranchName.draft)
|
||||
self.assertEqual(entry['prod_branch'], ModuleStoreEnum.BranchName.published)
|
||||
self.assertEqual(entry['block_map'], {})
|
||||
|
||||
course2 = 'quux_course'
|
||||
@@ -124,7 +125,7 @@ class TestLocationMapper(LocMapperSetupSansDjango):
|
||||
"""
|
||||
prob_locator = loc_mapper().translate_location(
|
||||
location,
|
||||
published=(branch == BRANCH_NAME_PUBLISHED),
|
||||
published=(branch == ModuleStoreEnum.BranchName.published),
|
||||
add_entry_if_missing=add_entry
|
||||
)
|
||||
self.assertEqual(prob_locator.org, org)
|
||||
@@ -134,7 +135,7 @@ class TestLocationMapper(LocMapperSetupSansDjango):
|
||||
|
||||
course_locator = loc_mapper().translate_location_to_course_locator(
|
||||
location.course_key,
|
||||
published=(branch == BRANCH_NAME_PUBLISHED),
|
||||
published=(branch == ModuleStoreEnum.BranchName.published),
|
||||
)
|
||||
self.assertEqual(course_locator.org, org)
|
||||
self.assertEqual(course_locator.offering, offering)
|
||||
@@ -169,7 +170,8 @@ class TestLocationMapper(LocMapperSetupSansDjango):
|
||||
)
|
||||
test_problem_locn = Location(org, course, run, 'problem', 'abc123')
|
||||
|
||||
self.translate_n_check(test_problem_locn, new_style_org, new_style_offering, 'problem2', BRANCH_NAME_PUBLISHED)
|
||||
self.translate_n_check(test_problem_locn, new_style_org, new_style_offering, 'problem2',
|
||||
ModuleStoreEnum.BranchName.published)
|
||||
# look for non-existent problem
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
loc_mapper().translate_location(
|
||||
@@ -184,7 +186,7 @@ class TestLocationMapper(LocMapperSetupSansDjango):
|
||||
test_no_cat_locn = test_no_cat_locn.replace(name='def456')
|
||||
|
||||
self.translate_n_check(
|
||||
test_no_cat_locn, new_style_org, new_style_offering, 'problem4', BRANCH_NAME_PUBLISHED
|
||||
test_no_cat_locn, new_style_org, new_style_offering, 'problem4', ModuleStoreEnum.BranchName.published
|
||||
)
|
||||
|
||||
# add a distractor course (note that abc123 has a different translation in this one)
|
||||
@@ -203,12 +205,12 @@ class TestLocationMapper(LocMapperSetupSansDjango):
|
||||
)
|
||||
# test that old translation still works
|
||||
self.translate_n_check(
|
||||
test_problem_locn, new_style_org, new_style_offering, 'problem2', BRANCH_NAME_PUBLISHED
|
||||
test_problem_locn, new_style_org, new_style_offering, 'problem2', ModuleStoreEnum.BranchName.published
|
||||
)
|
||||
# and new returns new id
|
||||
self.translate_n_check(
|
||||
test_problem_locn.replace(run=run), test_delta_new_org, test_delta_new_offering,
|
||||
'problem3', BRANCH_NAME_PUBLISHED
|
||||
'problem3', ModuleStoreEnum.BranchName.published
|
||||
)
|
||||
|
||||
def test_translate_location_dwim(self):
|
||||
@@ -222,11 +224,11 @@ class TestLocationMapper(LocMapperSetupSansDjango):
|
||||
problem_name = 'abc123abc123abc123abc123abc123f9'
|
||||
location = Location(org, course, run, 'problem', problem_name)
|
||||
new_offering = '{}.{}'.format(course, run)
|
||||
self.translate_n_check(location, org, new_offering, 'problemabc', BRANCH_NAME_PUBLISHED, True)
|
||||
self.translate_n_check(location, org, new_offering, 'problemabc', ModuleStoreEnum.BranchName.published, True)
|
||||
|
||||
# create an entry w/o a guid name
|
||||
other_location = Location(org, course, run, 'chapter', 'intro')
|
||||
self.translate_n_check(other_location, org, new_offering, 'intro', BRANCH_NAME_PUBLISHED, True)
|
||||
self.translate_n_check(other_location, org, new_offering, 'intro', ModuleStoreEnum.BranchName.published, True)
|
||||
|
||||
# add a distractor course
|
||||
delta_new_org = '{}.geek_dept'.format(org)
|
||||
@@ -238,7 +240,7 @@ class TestLocationMapper(LocMapperSetupSansDjango):
|
||||
delta_new_org, delta_new_offering,
|
||||
block_map={problem_name: {'problem': 'problem3'}}
|
||||
)
|
||||
self.translate_n_check(location, org, new_offering, 'problemabc', BRANCH_NAME_PUBLISHED, True)
|
||||
self.translate_n_check(location, org, new_offering, 'problemabc', ModuleStoreEnum.BranchName.published, True)
|
||||
|
||||
# add a new one to both courses (ensure name doesn't have same beginning)
|
||||
new_prob_name = uuid.uuid4().hex
|
||||
@@ -246,10 +248,10 @@ class TestLocationMapper(LocMapperSetupSansDjango):
|
||||
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, org, new_offering, new_usage_id, BRANCH_NAME_PUBLISHED, True)
|
||||
self.translate_n_check(new_prob_locn, org, new_offering, new_usage_id, ModuleStoreEnum.BranchName.published, True)
|
||||
new_prob_locn = new_prob_locn.replace(run=run)
|
||||
self.translate_n_check(
|
||||
new_prob_locn, delta_new_org, delta_new_offering, new_usage_id, BRANCH_NAME_PUBLISHED, True
|
||||
new_prob_locn, delta_new_org, delta_new_offering, new_usage_id, ModuleStoreEnum.BranchName.published, True
|
||||
)
|
||||
|
||||
def test_translate_locator(self):
|
||||
@@ -264,7 +266,7 @@ class TestLocationMapper(LocMapperSetupSansDjango):
|
||||
new_style_offering = '{}.{}'.format(course, run)
|
||||
prob_course_key = CourseLocator(
|
||||
org=new_style_org, offering=new_style_offering,
|
||||
branch=BRANCH_NAME_PUBLISHED,
|
||||
branch=ModuleStoreEnum.BranchName.published,
|
||||
)
|
||||
prob_locator = BlockUsageLocator(
|
||||
prob_course_key,
|
||||
@@ -286,22 +288,22 @@ class TestLocationMapper(LocMapperSetupSansDjango):
|
||||
# only one course matches
|
||||
prob_location = loc_mapper().translate_locator_to_location(prob_locator)
|
||||
# default branch
|
||||
self.assertEqual(prob_location, Location(org, course, run, 'problem', 'abc123', KEY_REVISION_PUBLISHED))
|
||||
self.assertEqual(prob_location, Location(org, course, run, 'problem', 'abc123', MongoRevisionKey.published))
|
||||
# test get_course keyword
|
||||
prob_location = loc_mapper().translate_locator_to_location(prob_locator, get_course=True)
|
||||
self.assertEqual(prob_location, SlashSeparatedCourseKey(org, course, run))
|
||||
# explicit branch
|
||||
prob_locator = prob_locator.for_branch(BRANCH_NAME_DRAFT)
|
||||
prob_locator = prob_locator.for_branch(ModuleStoreEnum.BranchName.draft)
|
||||
prob_location = loc_mapper().translate_locator_to_location(prob_locator)
|
||||
# Even though the problem was set as draft, we always return revision= KEY_REVISION_PUBLISHED to work
|
||||
# Even though the problem was set as draft, we always return revision= MongoRevisionKey.published to work
|
||||
# with old mongo/draft modulestores.
|
||||
self.assertEqual(prob_location, Location(org, course, run, 'problem', 'abc123', KEY_REVISION_PUBLISHED))
|
||||
self.assertEqual(prob_location, Location(org, course, run, 'problem', 'abc123', MongoRevisionKey.published))
|
||||
prob_locator = BlockUsageLocator(
|
||||
prob_course_key.for_branch('production'),
|
||||
block_type='problem', block_id='problem2'
|
||||
)
|
||||
prob_location = loc_mapper().translate_locator_to_location(prob_locator)
|
||||
self.assertEqual(prob_location, Location(org, course, run, 'problem', 'abc123', KEY_REVISION_PUBLISHED))
|
||||
self.assertEqual(prob_location, Location(org, course, run, 'problem', 'abc123', MongoRevisionKey.published))
|
||||
# same for chapter except chapter cannot be draft in old system
|
||||
chap_locator = BlockUsageLocator(
|
||||
prob_course_key.for_branch('production'),
|
||||
@@ -310,7 +312,7 @@ class TestLocationMapper(LocMapperSetupSansDjango):
|
||||
chap_location = loc_mapper().translate_locator_to_location(chap_locator)
|
||||
self.assertEqual(chap_location, Location(org, course, run, 'chapter', '48f23a10395384929234'))
|
||||
# explicit branch
|
||||
chap_locator = chap_locator.for_branch(BRANCH_NAME_DRAFT)
|
||||
chap_locator = chap_locator.for_branch(ModuleStoreEnum.BranchName.draft)
|
||||
chap_location = loc_mapper().translate_locator_to_location(chap_locator)
|
||||
self.assertEqual(chap_location, Location(org, course, run, 'chapter', '48f23a10395384929234'))
|
||||
chap_locator = BlockUsageLocator(
|
||||
@@ -321,7 +323,7 @@ class TestLocationMapper(LocMapperSetupSansDjango):
|
||||
|
||||
# look for non-existent problem
|
||||
prob_locator2 = BlockUsageLocator(
|
||||
prob_course_key.for_branch(BRANCH_NAME_DRAFT),
|
||||
prob_course_key.for_branch(ModuleStoreEnum.BranchName.draft),
|
||||
block_type='problem', block_id='problem3'
|
||||
)
|
||||
prob_location = loc_mapper().translate_locator_to_location(prob_locator2)
|
||||
@@ -336,7 +338,7 @@ class TestLocationMapper(LocMapperSetupSansDjango):
|
||||
block_map={'abc123': {'problem': 'problem3'}}
|
||||
)
|
||||
prob_location = loc_mapper().translate_locator_to_location(prob_locator)
|
||||
self.assertEqual(prob_location, Location(org, course, run, 'problem', 'abc123', KEY_REVISION_PUBLISHED))
|
||||
self.assertEqual(prob_location, Location(org, course, run, 'problem', 'abc123', MongoRevisionKey.published))
|
||||
|
||||
def test_special_chars(self):
|
||||
"""
|
||||
|
||||
@@ -7,10 +7,7 @@ from collections import namedtuple
|
||||
|
||||
from xmodule.tests import DATA_DIR
|
||||
from opaque_keys.edx.locations import Location
|
||||
from xmodule.modulestore import (
|
||||
MONGO_MODULESTORE_TYPE, SPLIT_MONGO_MODULESTORE_TYPE, XML_MODULESTORE_TYPE,
|
||||
REVISION_OPTION_DRAFT_PREFERRED, REVISION_OPTION_PUBLISHED_ONLY, BRANCH_DRAFT_PREFERRED
|
||||
)
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError
|
||||
|
||||
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
|
||||
@@ -247,12 +244,12 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
|
||||
"""
|
||||
self.initdb(default_ms)
|
||||
self.assertEqual(self.store.get_modulestore_type(
|
||||
self._course_key_from_string(self.XML_COURSEID1)), XML_MODULESTORE_TYPE
|
||||
self._course_key_from_string(self.XML_COURSEID1)), ModuleStoreEnum.Type.xml
|
||||
)
|
||||
self.assertEqual(self.store.get_modulestore_type(
|
||||
self._course_key_from_string(self.XML_COURSEID2)), XML_MODULESTORE_TYPE
|
||||
self._course_key_from_string(self.XML_COURSEID2)), ModuleStoreEnum.Type.xml
|
||||
)
|
||||
mongo_ms_type = MONGO_MODULESTORE_TYPE if default_ms == 'draft' else SPLIT_MONGO_MODULESTORE_TYPE
|
||||
mongo_ms_type = ModuleStoreEnum.Type.mongo if default_ms == 'draft' else ModuleStoreEnum.Type.split
|
||||
self.assertEqual(self.store.get_modulestore_type(
|
||||
self._course_key_from_string(self.MONGO_COURSEID)), mongo_ms_type
|
||||
)
|
||||
@@ -352,7 +349,7 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
|
||||
Test that the xml modulestore only loaded the courses from the maps.
|
||||
"""
|
||||
self.initdb('draft')
|
||||
xml_store = self.store._get_modulestore_by_type(XML_MODULESTORE_TYPE)
|
||||
xml_store = self.store._get_modulestore_by_type(ModuleStoreEnum.Type.xml)
|
||||
courses = xml_store.get_courses()
|
||||
self.assertEqual(len(courses), 2)
|
||||
course_ids = [course.id for course in courses]
|
||||
@@ -366,7 +363,7 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
|
||||
Test that the xml modulestore doesn't allow write ops.
|
||||
"""
|
||||
self.initdb('draft')
|
||||
xml_store = self.store._get_modulestore_by_type(XML_MODULESTORE_TYPE)
|
||||
xml_store = self.store._get_modulestore_by_type(ModuleStoreEnum.Type.xml)
|
||||
# the important thing is not which exception it raises but that it raises an exception
|
||||
with self.assertRaises(AttributeError):
|
||||
xml_store.create_course("org", "course/run", 999)
|
||||
@@ -420,16 +417,16 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
|
||||
|
||||
self.verify_get_parent_locations_results([
|
||||
(child_to_move, new_parent, None),
|
||||
(child_to_move, new_parent, REVISION_OPTION_DRAFT_PREFERRED),
|
||||
(child_to_move, old_parent, REVISION_OPTION_PUBLISHED_ONLY),
|
||||
(child_to_move, new_parent, ModuleStoreEnum.RevisionOption.draft_preferred),
|
||||
(child_to_move, old_parent, ModuleStoreEnum.RevisionOption.published_only),
|
||||
])
|
||||
|
||||
# publish the course again
|
||||
self.store.publish(self.course.location, self.user_id)
|
||||
self.verify_get_parent_locations_results([
|
||||
(child_to_move, new_parent, None),
|
||||
(child_to_move, new_parent, REVISION_OPTION_DRAFT_PREFERRED),
|
||||
(child_to_move, new_parent, REVISION_OPTION_PUBLISHED_ONLY),
|
||||
(child_to_move, new_parent, ModuleStoreEnum.RevisionOption.draft_preferred),
|
||||
(child_to_move, new_parent, ModuleStoreEnum.RevisionOption.published_only),
|
||||
])
|
||||
|
||||
@ddt.data('draft')
|
||||
@@ -451,16 +448,16 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
|
||||
self.verify_get_parent_locations_results([
|
||||
(child_to_delete, old_parent, None),
|
||||
# Note: The following could be an unexpected result, but we want to avoid an extra database call
|
||||
(child_to_delete, old_parent, REVISION_OPTION_DRAFT_PREFERRED),
|
||||
(child_to_delete, old_parent, REVISION_OPTION_PUBLISHED_ONLY),
|
||||
(child_to_delete, old_parent, ModuleStoreEnum.RevisionOption.draft_preferred),
|
||||
(child_to_delete, old_parent, ModuleStoreEnum.RevisionOption.published_only),
|
||||
])
|
||||
|
||||
# publish the course again
|
||||
self.store.publish(self.course.location, self.user_id)
|
||||
self.verify_get_parent_locations_results([
|
||||
(child_to_delete, None, None),
|
||||
(child_to_delete, None, REVISION_OPTION_DRAFT_PREFERRED),
|
||||
(child_to_delete, None, REVISION_OPTION_PUBLISHED_ONLY),
|
||||
(child_to_delete, None, ModuleStoreEnum.RevisionOption.draft_preferred),
|
||||
(child_to_delete, None, ModuleStoreEnum.RevisionOption.published_only),
|
||||
])
|
||||
|
||||
@ddt.data('draft', 'split')
|
||||
@@ -529,6 +526,6 @@ def create_modulestore_instance(engine, doc_store_config, options, i18n_service=
|
||||
|
||||
return class_(
|
||||
doc_store_config=doc_store_config,
|
||||
branch_setting_func=lambda: BRANCH_DRAFT_PREFERRED,
|
||||
branch_setting_func=lambda: ModuleStoreEnum.Branch.draft_preferred,
|
||||
**options
|
||||
)
|
||||
|
||||
@@ -20,7 +20,7 @@ from xblock.plugin import Plugin
|
||||
|
||||
from xmodule.tests import DATA_DIR
|
||||
from opaque_keys.edx.locations import Location
|
||||
from xmodule.modulestore import MONGO_MODULESTORE_TYPE, BRANCH_DRAFT_PREFERRED
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.mongo import MongoModuleStore, MongoKeyValueStore
|
||||
from xmodule.modulestore.draft import DraftModuleStore
|
||||
from opaque_keys.edx.locations import SlashSeparatedCourseKey, AssetLocation
|
||||
@@ -103,7 +103,7 @@ class TestMongoModuleStore(unittest.TestCase):
|
||||
draft_store = DraftModuleStore(
|
||||
doc_store_config, FS_ROOT, RENDER_TEMPLATE,
|
||||
default_class=DEFAULT_CLASS,
|
||||
branch_setting_func=lambda: BRANCH_DRAFT_PREFERRED
|
||||
branch_setting_func=lambda: ModuleStoreEnum.Branch.draft_preferred
|
||||
)
|
||||
import_from_xml(
|
||||
draft_store,
|
||||
@@ -148,7 +148,7 @@ class TestMongoModuleStore(unittest.TestCase):
|
||||
{'host': HOST, 'db': DB, 'collection': COLLECTION},
|
||||
FS_ROOT, RENDER_TEMPLATE, default_class=DEFAULT_CLASS
|
||||
)
|
||||
assert_equals(store.get_modulestore_type(''), MONGO_MODULESTORE_TYPE)
|
||||
assert_equals(store.get_modulestore_type(''), ModuleStoreEnum.Type.mongo)
|
||||
|
||||
def test_get_courses(self):
|
||||
'''Make sure the course objects loaded properly'''
|
||||
|
||||
@@ -5,7 +5,7 @@ Tests for split_migrator
|
||||
import uuid
|
||||
import random
|
||||
import mock
|
||||
from xmodule.modulestore import KEY_REVISION_PUBLISHED
|
||||
from xmodule.modulestore.mongo.base import MongoRevisionKey
|
||||
from xmodule.modulestore.loc_mapper_store import LocMapperStore
|
||||
from xmodule.modulestore.split_migrator import SplitMigrator
|
||||
from xmodule.modulestore.tests import test_location_mapper
|
||||
@@ -178,7 +178,7 @@ class TestMigration(SplitWMongoCourseBoostrapper):
|
||||
self.assertEqual(
|
||||
presplit_dag_root.location,
|
||||
self.loc_mapper.translate_locator_to_location(split_dag_root.location).replace(
|
||||
revision=KEY_REVISION_PUBLISHED
|
||||
revision=MongoRevisionKey.published
|
||||
)
|
||||
)
|
||||
# compare all fields but children
|
||||
|
||||
@@ -11,7 +11,7 @@ import random
|
||||
|
||||
from xblock.fields import Scope
|
||||
from xmodule.course_module import CourseDescriptor
|
||||
from xmodule.modulestore import BRANCH_NAME_PUBLISHED, BRANCH_NAME_DRAFT
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.exceptions import (InsufficientSpecificationError, ItemNotFoundError, VersionConflictError,
|
||||
DuplicateItemError, DuplicateCourseError)
|
||||
from opaque_keys.edx.locator import CourseLocator, BlockUsageLocator, VersionTree, LocalId
|
||||
@@ -22,6 +22,10 @@ from xmodule.modulestore.split_mongo.split import SplitMongoModuleStore
|
||||
from xmodule.modulestore.tests.test_modulestore import check_has_course_method
|
||||
|
||||
|
||||
BRANCH_NAME_DRAFT = ModuleStoreEnum.BranchName.draft
|
||||
BRANCH_NAME_PUBLISHED = ModuleStoreEnum.BranchName.published
|
||||
|
||||
|
||||
class SplitModuleTest(unittest.TestCase):
|
||||
'''
|
||||
The base set of tests manually populates a db w/ courses which have
|
||||
|
||||
@@ -9,7 +9,7 @@ from opaque_keys.edx.locator import CourseLocator, BlockUsageLocator
|
||||
from xmodule.modulestore.split_mongo.split import SplitMongoModuleStore
|
||||
from xmodule.modulestore.mongo import MongoModuleStore, DraftMongoModuleStore
|
||||
from xmodule.modulestore.mongo.draft import DIRECT_ONLY_CATEGORIES
|
||||
from xmodule.modulestore import BRANCH_DRAFT_PREFERRED, BRANCH_NAME_DRAFT
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from mock import Mock
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ class SplitWMongoCourseBoostrapper(unittest.TestCase):
|
||||
'xblock_mixins': (InheritanceMixin,)
|
||||
}
|
||||
|
||||
split_course_key = CourseLocator('test_org', 'test_course.runid', branch=BRANCH_NAME_DRAFT)
|
||||
split_course_key = CourseLocator('test_org', 'test_course.runid', branch=ModuleStoreEnum.BranchName.draft)
|
||||
|
||||
def setUp(self):
|
||||
self.db_config['collection'] = 'modulestore{0}'.format(uuid.uuid4().hex[:5])
|
||||
@@ -56,7 +56,7 @@ class SplitWMongoCourseBoostrapper(unittest.TestCase):
|
||||
self.addCleanup(self.tear_down_split)
|
||||
self.old_mongo = MongoModuleStore(self.db_config, **self.modulestore_options)
|
||||
self.draft_mongo = DraftMongoModuleStore(
|
||||
self.db_config, branch_setting_func=lambda: BRANCH_DRAFT_PREFERRED, **self.modulestore_options
|
||||
self.db_config, branch_setting_func=lambda: ModuleStoreEnum.Branch.draft_preferred, **self.modulestore_options
|
||||
)
|
||||
self.addCleanup(self.tear_down_mongo)
|
||||
self.old_course_key = None
|
||||
|
||||
@@ -9,7 +9,7 @@ from mock import patch
|
||||
|
||||
from xmodule.modulestore.xml import XMLModuleStore
|
||||
from opaque_keys.edx.locations import Location
|
||||
from xmodule.modulestore import XML_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
|
||||
from .test_modulestore import check_path_to_location
|
||||
from xmodule.tests import DATA_DIR
|
||||
@@ -43,7 +43,7 @@ class TestXMLModuleStore(unittest.TestCase):
|
||||
|
||||
def test_xml_modulestore_type(self):
|
||||
store = XMLModuleStore(DATA_DIR, course_dirs=['toy', 'simple'])
|
||||
self.assertEqual(store.get_modulestore_type(), XML_MODULESTORE_TYPE)
|
||||
self.assertEqual(store.get_modulestore_type(), ModuleStoreEnum.Type.xml)
|
||||
|
||||
def test_unicode_chars_in_xml_content(self):
|
||||
# edX/full/6.002_Spring_2012 has non-ASCII chars, and during
|
||||
|
||||
@@ -19,7 +19,7 @@ from xmodule.errortracker import make_error_tracker, exc_info_to_str
|
||||
from xmodule.mako_module import MakoDescriptorSystem
|
||||
from xmodule.x_module import XMLParsingSystem, policy_key
|
||||
from xmodule.modulestore.xml_exporter import DEFAULT_CONTENT_FIELDS
|
||||
from xmodule.modulestore import REVISION_OPTION_PUBLISHED_ONLY
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.tabs import CourseTabList
|
||||
from opaque_keys.edx.keys import UsageKey
|
||||
from opaque_keys.edx.locations import SlashSeparatedCourseKey
|
||||
@@ -27,7 +27,7 @@ from opaque_keys.edx.locations import SlashSeparatedCourseKey
|
||||
from xblock.field_data import DictFieldData
|
||||
from xblock.runtime import DictKeyValueStore, IdGenerator
|
||||
|
||||
from . import ModuleStoreReadBase, Location, XML_MODULESTORE_TYPE
|
||||
from . import ModuleStoreReadBase, Location, ModuleStoreEnum
|
||||
|
||||
from .exceptions import ItemNotFoundError
|
||||
from .inheritance import compute_inherited_metadata, inheriting_field_data
|
||||
@@ -411,7 +411,7 @@ class XMLModuleStore(ModuleStoreReadBase):
|
||||
self.i18n_service = i18n_service
|
||||
|
||||
# The XML Module Store is a read-only store and only handles published content
|
||||
self.branch_setting_func = lambda: REVISION_OPTION_PUBLISHED_ONLY
|
||||
self.branch_setting_func = lambda: ModuleStoreEnum.RevisionOption.published_only
|
||||
|
||||
# If we are specifically asked for missing courses, that should
|
||||
# be an error. If we are asked for "all" courses, find the ones
|
||||
@@ -800,16 +800,11 @@ class XMLModuleStore(ModuleStoreReadBase):
|
||||
|
||||
def get_modulestore_type(self, course_key=None):
|
||||
"""
|
||||
Returns an enumeration-like type reflecting the type of this modulestore
|
||||
The return can be one of:
|
||||
"xml" (for XML based courses),
|
||||
"mongo" for old-style MongoDB backed courses,
|
||||
"split" for new-style split MongoDB backed courses.
|
||||
|
||||
Returns an enumeration-like type reflecting the type of this modulestore, per ModuleStoreEnum.Type
|
||||
Args:
|
||||
course_key: just for signature compatibility
|
||||
"""
|
||||
return XML_MODULESTORE_TYPE
|
||||
return ModuleStoreEnum.Type.xml
|
||||
|
||||
def get_courses_for_wiki(self, wiki_slug):
|
||||
"""
|
||||
@@ -827,5 +822,5 @@ class XMLModuleStore(ModuleStoreReadBase):
|
||||
|
||||
Returns the course count
|
||||
"""
|
||||
return {XML_MODULESTORE_TYPE: True}
|
||||
return {ModuleStoreEnum.Type.xml: True}
|
||||
|
||||
|
||||
@@ -7,9 +7,7 @@ import lxml.etree
|
||||
from xblock.fields import Scope
|
||||
from xmodule.contentstore.content import StaticContent
|
||||
from xmodule.exceptions import NotFoundError
|
||||
from xmodule.modulestore import (
|
||||
EdxJSONEncoder, BRANCH_PUBLISHED_ONLY, REVISION_OPTION_DRAFT_PREFERRED, REVISION_OPTION_DRAFT_ONLY
|
||||
)
|
||||
from xmodule.modulestore import EdxJSONEncoder, ModuleStoreEnum
|
||||
from xmodule.modulestore.inheritance import own_metadata
|
||||
from xmodule.modulestore.mixed import store_branch_setting
|
||||
from fs.osfs import OSFS
|
||||
@@ -47,7 +45,7 @@ def export_to_xml(modulestore, contentstore, course_key, root_dir, course_dir):
|
||||
root = lxml.etree.Element('unknown')
|
||||
|
||||
# export only the published content
|
||||
with store_branch_setting(course.runtime.modulestore, BRANCH_PUBLISHED_ONLY):
|
||||
with store_branch_setting(course.runtime.modulestore, ModuleStoreEnum.Branch.published_only):
|
||||
course.add_xml_to_node(root)
|
||||
|
||||
with export_fs.open('course.xml', 'w') as course_xml:
|
||||
@@ -107,11 +105,18 @@ def export_to_xml(modulestore, contentstore, course_key, root_dir, course_dir):
|
||||
# should we change the application, then this assumption will no longer be valid
|
||||
# NOTE: we need to explicitly implement the logic for setting the vertical's parent
|
||||
# and index here since the XML modulestore cannot load draft modules
|
||||
draft_verticals = modulestore.get_items(course_key, category='vertical', revision=REVISION_OPTION_DRAFT_ONLY)
|
||||
draft_verticals = modulestore.get_items(
|
||||
course_key,
|
||||
category='vertical',
|
||||
revision=ModuleStoreEnum.RevisionOption.draft_only
|
||||
)
|
||||
if len(draft_verticals) > 0:
|
||||
draft_course_dir = export_fs.makeopendir(DRAFT_DIR)
|
||||
for draft_vertical in draft_verticals:
|
||||
parent_loc = modulestore.get_parent_location(draft_vertical.location, revision=REVISION_OPTION_DRAFT_PREFERRED)
|
||||
parent_loc = modulestore.get_parent_location(
|
||||
draft_vertical.location,
|
||||
revision=ModuleStoreEnum.RevisionOption.draft_preferred
|
||||
)
|
||||
# Don't try to export orphaned items.
|
||||
if parent_loc is not None:
|
||||
logging.debug('parent_loc = {0}'.format(parent_loc))
|
||||
|
||||
@@ -17,7 +17,7 @@ from .store_utilities import rewrite_nonportable_content_links
|
||||
import xblock
|
||||
from xmodule.tabs import CourseTabList
|
||||
from xmodule.modulestore.exceptions import InvalidLocationError
|
||||
from xmodule.modulestore import KEY_REVISION_PUBLISHED, KEY_REVISION_DRAFT
|
||||
from xmodule.modulestore.mongo.base import MongoRevisionKey
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -505,14 +505,14 @@ def _import_course_draft(
|
||||
# Update the module's location to DRAFT revision
|
||||
# We need to call this method (instead of updating the location directly)
|
||||
# to ensure that pure XBlock field data is updated correctly.
|
||||
_update_module_location(module, module.location.replace(revision=KEY_REVISION_DRAFT))
|
||||
_update_module_location(module, module.location.replace(revision=MongoRevisionKey.draft))
|
||||
|
||||
# make sure our parent has us in its list of children
|
||||
# this is to make sure private only verticals show up
|
||||
# in the list of children since they would have been
|
||||
# filtered out from the non-draft store export
|
||||
if module.location.category == 'vertical':
|
||||
non_draft_location = module.location.replace(revision=KEY_REVISION_PUBLISHED)
|
||||
non_draft_location = module.location.replace(revision=MongoRevisionKey.published)
|
||||
sequential_url = module.xml_attributes['parent_sequential_url']
|
||||
index = int(module.xml_attributes['index_in_children_list'])
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ from django.core.exceptions import ValidationError
|
||||
from bulk_email.models import CourseEmailTemplate, COURSE_EMAIL_MESSAGE_BODY_TAG, CourseAuthorization
|
||||
|
||||
from opaque_keys import InvalidKeyError
|
||||
from xmodule.modulestore import XML_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from opaque_keys.edx.locations import SlashSeparatedCourseKey
|
||||
@@ -78,7 +78,7 @@ class CourseAuthorizationAdminForm(forms.ModelForm): # pylint: disable=R0924
|
||||
raise forms.ValidationError(msg)
|
||||
|
||||
# Now, try and discern if it is a Studio course - HTML editor doesn't work with XML courses
|
||||
is_studio_course = modulestore().get_modulestore_type(course_key) != XML_MODULESTORE_TYPE
|
||||
is_studio_course = modulestore().get_modulestore_type(course_key) != ModuleStoreEnum.Type.xml
|
||||
if not is_studio_course:
|
||||
msg = "Course Email feature is only available for courses authored in Studio. "
|
||||
msg += '"{0}" appears to be an XML backed course.'.format(course_key.to_deprecated_string())
|
||||
|
||||
@@ -11,7 +11,7 @@ from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE
|
||||
from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE
|
||||
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.modulestore import XML_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
|
||||
from mock import patch
|
||||
|
||||
@@ -132,7 +132,7 @@ class CourseAuthorizationXMLFormTest(ModuleStoreTestCase):
|
||||
def test_xml_course_authorization(self):
|
||||
course_id = SlashSeparatedCourseKey('edX', 'toy', '2012_Fall')
|
||||
# Assert this is an XML course
|
||||
self.assertEqual(modulestore().get_modulestore_type(course_id), XML_MODULESTORE_TYPE)
|
||||
self.assertEqual(modulestore().get_modulestore_type(course_id), ModuleStoreEnum.Type.xml)
|
||||
|
||||
form_data = {'course_id': course_id.to_deprecated_string(), 'email_enabled': True}
|
||||
form = CourseAuthorizationAdminForm(data=form_data)
|
||||
|
||||
@@ -8,13 +8,13 @@ from django.http import Http404
|
||||
from django.conf import settings
|
||||
|
||||
from edxmako.shortcuts import render_to_string
|
||||
from xmodule.modulestore import XML_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.contentstore.content import StaticContent
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError
|
||||
from static_replace import replace_static_urls
|
||||
from xmodule.modulestore import MONGO_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.x_module import STUDENT_VIEW
|
||||
|
||||
from courseware.access import has_access
|
||||
@@ -106,7 +106,7 @@ def get_opt_course_with_access(user, action, course_key):
|
||||
def course_image_url(course):
|
||||
"""Try to look up the image url for the course. If it's not found,
|
||||
log an error and return the dead link"""
|
||||
if course.static_asset_path or modulestore().get_modulestore_type(course.id) == XML_MODULESTORE_TYPE:
|
||||
if course.static_asset_path or modulestore().get_modulestore_type(course.id) == ModuleStoreEnum.Type.xml:
|
||||
# If we are a static course with the course_image attribute
|
||||
# set different than the default, return that path so that
|
||||
# courses can use custom course image paths, otherwise just
|
||||
@@ -369,7 +369,7 @@ def get_studio_url(course_key, page):
|
||||
assert(isinstance(course_key, CourseKey))
|
||||
course = get_course_by_id(course_key)
|
||||
is_studio_course = course.course_edit_method == "Studio"
|
||||
is_mongo_course = modulestore().get_modulestore_type(course_key) == MONGO_MODULESTORE_TYPE
|
||||
is_mongo_course = modulestore().get_modulestore_type(course_key) == ModuleStoreEnum.Type.mongo
|
||||
studio_link = None
|
||||
if is_studio_course and is_mongo_course:
|
||||
studio_link = get_cms_course_link(course, page)
|
||||
|
||||
@@ -7,7 +7,7 @@ import mock
|
||||
from django.test.utils import override_settings
|
||||
from student.tests.factories import UserFactory
|
||||
import xmodule.modulestore.django as store_django
|
||||
from xmodule.modulestore import BRANCH_DRAFT_PREFERRED
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from xmodule.tests.xml import factories as xml
|
||||
@@ -62,18 +62,18 @@ class ModuleStoreBranchSettingTest(ModuleStoreTestCase):
|
||||
mock.Mock(return_value='preview.localhost')
|
||||
)
|
||||
@override_settings(
|
||||
HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS={r'preview\.': BRANCH_DRAFT_PREFERRED},
|
||||
HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS={r'preview\.': ModuleStoreEnum.Branch.draft_preferred},
|
||||
MODULESTORE_BRANCH='fake_default_branch',
|
||||
)
|
||||
def test_default_modulestore_preview_mapping(self):
|
||||
self.assertEqual(store_django._get_modulestore_branch_setting(), BRANCH_DRAFT_PREFERRED)
|
||||
self.assertEqual(store_django._get_modulestore_branch_setting(), ModuleStoreEnum.Branch.draft_preferred)
|
||||
|
||||
@mock.patch(
|
||||
'xmodule.modulestore.django.get_current_request_hostname',
|
||||
mock.Mock(return_value='localhost')
|
||||
)
|
||||
@override_settings(
|
||||
HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS={r'preview\.': BRANCH_DRAFT_PREFERRED},
|
||||
HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS={r'preview\.': ModuleStoreEnum.Branch.draft_preferred},
|
||||
MODULESTORE_BRANCH='fake_default_branch',
|
||||
)
|
||||
def test_default_modulestore_branch_mapping(self):
|
||||
|
||||
@@ -10,7 +10,7 @@ from django.test.utils import override_settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.conf import settings
|
||||
|
||||
from xmodule.modulestore import KEY_REVISION_DRAFT
|
||||
from xmodule.modulestore.mongo.base import MongoRevisionKey
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
|
||||
from xmodule.x_module import STUDENT_VIEW
|
||||
@@ -160,7 +160,7 @@ class TestLTIModuleListing(ModuleStoreTestCase):
|
||||
parent_location=self.section2.location,
|
||||
display_name="lti draft",
|
||||
category="lti",
|
||||
location=self.course.id.make_usage_key('lti', 'lti_published').replace(revision=KEY_REVISION_DRAFT),
|
||||
location=self.course.id.make_usage_key('lti', 'lti_published').replace(revision=MongoRevisionKey.draft),
|
||||
)
|
||||
|
||||
def expected_handler_url(self, handler):
|
||||
|
||||
@@ -39,7 +39,7 @@ from external_auth.views import generate_password
|
||||
from student.models import CourseEnrollment, UserProfile, Registration
|
||||
import track.views
|
||||
from xmodule.contentstore.django import contentstore
|
||||
from xmodule.modulestore import XML_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.modulestore.store_utilities import delete_course
|
||||
from xmodule.modulestore.xml import XMLModuleStore
|
||||
@@ -573,7 +573,7 @@ class Courses(SysadminDashboardView):
|
||||
escape(str(err))
|
||||
)
|
||||
|
||||
is_xml_course = (modulestore().get_modulestore_type(course_key) == XML_MODULESTORE_TYPE)
|
||||
is_xml_course = (modulestore().get_modulestore_type(course_key) == ModuleStoreEnum.Type.xml)
|
||||
if course_found and is_xml_course:
|
||||
cdir = course.data_dir
|
||||
self.def_ms.courses.pop(cdir)
|
||||
|
||||
@@ -12,7 +12,7 @@ from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE
|
||||
from student.tests.factories import AdminFactory
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from xmodule.modulestore import XML_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
|
||||
from bulk_email.models import CourseAuthorization
|
||||
|
||||
@@ -103,7 +103,7 @@ class TestInstructorDashboardEmailView(ModuleStoreTestCase):
|
||||
# in `instructor/views/legacy.py` is doing the correct thing.
|
||||
|
||||
with patch('xmodule.modulestore.mongo.base.MongoModuleStore.get_modulestore_type') as mock_modulestore:
|
||||
mock_modulestore.return_value = XML_MODULESTORE_TYPE
|
||||
mock_modulestore.return_value = ModuleStoreEnum.Type.xml
|
||||
|
||||
# Assert that the URL for the email view is not in the response
|
||||
response = self.client.get(self.url)
|
||||
|
||||
@@ -15,7 +15,7 @@ from django.conf import settings
|
||||
from lms.lib.xblock.runtime import quote_slashes
|
||||
from xmodule_modifiers import wrap_xblock
|
||||
from xmodule.html_module import HtmlDescriptor
|
||||
from xmodule.modulestore import XML_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xblock.field_data import DictFieldData
|
||||
from xblock.fields import ScopeIds
|
||||
@@ -37,7 +37,7 @@ def instructor_dashboard_2(request, course_id):
|
||||
""" Display the instructor dashboard for a course. """
|
||||
course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
|
||||
course = get_course_by_id(course_key, depth=None)
|
||||
is_studio_course = (modulestore().get_modulestore_type(course_key) != XML_MODULESTORE_TYPE)
|
||||
is_studio_course = (modulestore().get_modulestore_type(course_key) != ModuleStoreEnum.Type.xml)
|
||||
|
||||
access = {
|
||||
'admin': request.user.is_staff,
|
||||
|
||||
@@ -28,7 +28,7 @@ from django.utils import timezone
|
||||
|
||||
from xmodule_modifiers import wrap_xblock
|
||||
import xmodule.graders as xmgraders
|
||||
from xmodule.modulestore import XML_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from opaque_keys.edx.locations import SlashSeparatedCourseKey
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError
|
||||
@@ -968,7 +968,7 @@ def instructor_dashboard(request, course_id):
|
||||
instructor_tasks = None
|
||||
|
||||
# determine if this is a studio-backed course so we can provide a link to edit this course in studio
|
||||
is_studio_course = modulestore().get_modulestore_type(course_key) != XML_MODULESTORE_TYPE
|
||||
is_studio_course = modulestore().get_modulestore_type(course_key) != ModuleStoreEnum.Type.xml
|
||||
studio_url = None
|
||||
if is_studio_course:
|
||||
studio_url = get_cms_course_link(course)
|
||||
|
||||
@@ -12,7 +12,7 @@ from django.utils.translation import ugettext as _
|
||||
|
||||
from courseware.models import StudentModule
|
||||
from xmodule.fields import Date
|
||||
from xmodule.modulestore import XML_MODULESTORE_TYPE
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.django import modulestore
|
||||
|
||||
from bulk_email.models import CourseAuthorization
|
||||
@@ -59,7 +59,7 @@ def bulk_email_is_enabled_for_course(course_id):
|
||||
"""
|
||||
|
||||
bulk_email_enabled_globally = (settings.FEATURES['ENABLE_INSTRUCTOR_EMAIL'] == True)
|
||||
is_studio_course = (modulestore().get_modulestore_type(course_id) != XML_MODULESTORE_TYPE)
|
||||
is_studio_course = (modulestore().get_modulestore_type(course_id) != ModuleStoreEnum.Type.xml)
|
||||
bulk_email_enabled_for_course = CourseAuthorization.instructor_email_enabled(course_id)
|
||||
|
||||
if bulk_email_enabled_globally and is_studio_course and bulk_email_enabled_for_course:
|
||||
|
||||
@@ -44,5 +44,5 @@ DEBUG_TOOLBAR_PANELS += (
|
||||
# what the 'default' modulestore to use while processing the request
|
||||
# for example 'preview.edx.org' should use the draft modulestore
|
||||
HOSTNAME_MODULESTORE_DEFAULT_MAPPINGS = {
|
||||
'preview\.': 'draft'
|
||||
'preview\.': 'draft-preferred'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user