Commit 91f102c7 by Nimisha Asthagiri

Merge pull request #4232 from edx/nimisha/modulestore-enum-constants

ModulestoreEnum class.
parents d6049239 8dca8053
......@@ -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)
......
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()
......
......@@ -247,7 +247,7 @@ XBLOCK_MIXINS = (LmsBlockMixin, InheritanceMixin, XModuleMixin)
XBLOCK_SELECT_FUNCTION = prefer_xmodules
############################ Modulestore Configuration ################################
MODULESTORE_BRANCH = 'draft'
MODULESTORE_BRANCH = 'draft-preferred'
############################ DJANGO_BUILTINS ################################
# Change DEBUG/TEMPLATE_DEBUG in your environment settings files, not here
......
......@@ -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'
# 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
# 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
REVISION_OPTION_DRAFT_PREFERRED = 'rev-opt-draft-preferred'
class ModuleStoreEnum(object):
"""
A class to encapsulate common constants that are used with the various modulestores.
"""
# only DRAFT versions are queried and no PUBLISHED versions
REVISION_OPTION_DRAFT_ONLY = 'rev-opt-draft-only'
class Type(object):
"""
The various types of modulestores provided
"""
split = 'split'
mongo = 'mongo'
xml = 'xml'
# # only PUBLISHED versions are queried and no DRAFT versions
REVISION_OPTION_PUBLISHED_ONLY = 'rev-opt-published-only'
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'
# all revisions are queried
REVISION_OPTION_ALL = 'rev-opt-all'
# only DRAFT versions are queried and no PUBLISHED versions
draft_only = 'rev-opt-draft-only'
# # only PUBLISHED versions are queried and no DRAFT versions
published_only = 'rev-opt-published-only'
# 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'
# all revisions are queried
all = 'rev-opt-all'
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'
# 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')
......@@ -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
......@@ -492,7 +492,7 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
def get_orphans(self, course_key):
"""
Return a dict of all of the orphans in the course.
Return an array of all of the orphans in the course.
"""
detached_categories = [name for name, __ in XBlock.load_tagged_classes("detached")]
course = self._lookup_course(course_key)
......@@ -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.BranchName.published)
self.delete_item(published_location, user_id)
def update_course_index(self, updated_index_entry):
......@@ -1456,16 +1456,12 @@ class SplitMongoModuleStore(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 SPLIT_MONGO_MODULESTORE_TYPE
return ModuleStoreEnum.Type.split
def internal_clean_children(self, course_locator):
"""
......@@ -1797,7 +1793,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.
"""
......
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')
......
......@@ -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'
}
......@@ -475,7 +475,7 @@ XBLOCK_SELECT_FUNCTION = prefer_xmodules
############# ModuleStore Configuration ##########
MODULESTORE_BRANCH = 'published'
MODULESTORE_BRANCH = 'published-only'
CONTENTSTORE = None
DOC_STORE_CONFIG = {
'host': 'localhost',
......
......@@ -109,7 +109,7 @@ STATICFILES_DIRS += [
if os.path.isdir(COMMON_TEST_DATA_ROOT / course_dir)
]
MODULESTORE_BRANCH = 'draft'
MODULESTORE_BRANCH = 'draft-preferred'
update_module_store_settings(
MODULESTORE,
module_store_options={
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment