Commit e8bcc172 by Don Mitchell

Merge branch 'feature/cale/cms-master' into feature/dhm/drag

parents 3a2c5752 e884f17d
...@@ -350,6 +350,21 @@ class ContentStoreTest(TestCase): ...@@ -350,6 +350,21 @@ class ContentStoreTest(TestCase):
def test_edit_unit_full(self): def test_edit_unit_full(self):
self.check_edit_unit('full') self.check_edit_unit('full')
def test_about_overrides(self):
'''
This test case verifies that a course can use specialized override for about data, e.g. /about/Fall_2012/effort.html
while there is a base definition in /about/effort.html
'''
import_from_xml(modulestore(), 'common/test/data/', ['full'])
ms = modulestore('direct')
effort = ms.get_item(Location(['i4x','edX','full','about','effort', None]))
self.assertEqual(effort.definition['data'],'6 hours')
# this one should be in a non-override folder
effort = ms.get_item(Location(['i4x','edX','full','about','end_date', None]))
self.assertEqual(effort.definition['data'],'TBD')
def test_clone_course(self): def test_clone_course(self):
import_from_xml(modulestore(), 'common/test/data/', ['full']) import_from_xml(modulestore(), 'common/test/data/', ['full'])
......
...@@ -228,7 +228,11 @@ class CourseDescriptor(SequenceDescriptor): ...@@ -228,7 +228,11 @@ class CourseDescriptor(SequenceDescriptor):
if policy_dir: if policy_dir:
paths = [policy_dir + '/grading_policy.json'] + paths paths = [policy_dir + '/grading_policy.json'] + paths
policy = json.loads(cls.read_grading_policy(paths, system)) try:
policy = json.loads(cls.read_grading_policy(paths, system))
except ValueError:
system.error_tracker("Unable to decode grading policy as json")
policy = None
# cdodge: import the grading policy information that is on disk and put into the # cdodge: import the grading policy information that is on disk and put into the
# descriptor 'definition' bucket as a dictionary so that it is persisted in the DB # descriptor 'definition' bucket as a dictionary so that it is persisted in the DB
......
...@@ -13,6 +13,7 @@ from importlib import import_module ...@@ -13,6 +13,7 @@ from importlib import import_module
from lxml import etree from lxml import etree
from path import path from path import path
from xmodule.error_module import ErrorDescriptor
from xmodule.errortracker import make_error_tracker, exc_info_to_str from xmodule.errortracker import make_error_tracker, exc_info_to_str
from xmodule.course_module import CourseDescriptor from xmodule.course_module import CourseDescriptor
from xmodule.mako_module import MakoDescriptorSystem from xmodule.mako_module import MakoDescriptorSystem
...@@ -167,8 +168,6 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem): ...@@ -167,8 +168,6 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem):
# Didn't load properly. Fall back on loading as an error # Didn't load properly. Fall back on loading as an error
# descriptor. This should never error due to formatting. # descriptor. This should never error due to formatting.
# Put import here to avoid circular import errors
from xmodule.error_module import ErrorDescriptor
msg = "Error loading from xml. " + str(err)[:200] msg = "Error loading from xml. " + str(err)[:200]
log.warning(msg) log.warning(msg)
...@@ -311,7 +310,7 @@ class XMLModuleStore(ModuleStoreBase): ...@@ -311,7 +310,7 @@ class XMLModuleStore(ModuleStoreBase):
log.exception(msg) log.exception(msg)
errorlog.tracker(msg) errorlog.tracker(msg)
if course_descriptor is not None: if course_descriptor is not None and not isinstance(course_descriptor, ErrorDescriptor):
self.courses[course_dir] = course_descriptor self.courses[course_dir] = course_descriptor
self._location_errors[course_descriptor.location] = errorlog self._location_errors[course_descriptor.location] = errorlog
self.parent_trackers[course_descriptor.id].make_known(course_descriptor.location) self.parent_trackers[course_descriptor.id].make_known(course_descriptor.location)
...@@ -423,6 +422,10 @@ class XMLModuleStore(ModuleStoreBase): ...@@ -423,6 +422,10 @@ class XMLModuleStore(ModuleStoreBase):
course_descriptor = system.process_xml(etree.tostring(course_data, encoding='unicode')) course_descriptor = system.process_xml(etree.tostring(course_data, encoding='unicode'))
# If we fail to load the course, then skip the rest of the loading steps
if isinstance(course_descriptor, ErrorDescriptor):
return course_descriptor
# NOTE: The descriptors end up loading somewhat bottom up, which # NOTE: The descriptors end up loading somewhat bottom up, which
# breaks metadata inheritance via get_children(). Instead # breaks metadata inheritance via get_children(). Instead
# (actually, in addition to, for now), we do a final inheritance pass # (actually, in addition to, for now), we do a final inheritance pass
...@@ -444,33 +447,39 @@ class XMLModuleStore(ModuleStoreBase): ...@@ -444,33 +447,39 @@ class XMLModuleStore(ModuleStoreBase):
log.debug('========> Done with course import from {0}'.format(course_dir)) log.debug('========> Done with course import from {0}'.format(course_dir))
return course_descriptor return course_descriptor
def load_extra_content(self, system, course_descriptor, category, base_dir, course_dir, url_name): def load_extra_content(self, system, course_descriptor, category, base_dir, course_dir, url_name):
if url_name:
path = base_dir / url_name
if not os.path.exists(path): self._load_extra_content(system, course_descriptor, category, base_dir, course_dir)
path = base_dir
# then look in a override folder based on the course run
if os.path.isdir(base_dir / url_name):
self._load_extra_content(system, course_descriptor, category, base_dir / url_name, course_dir)
def _load_extra_content(self, system, course_descriptor, category, path, course_dir):
for filepath in glob.glob(path/ '*'): for filepath in glob.glob(path/ '*'):
with open(filepath) as f: if not os.path.isdir(filepath):
try: with open(filepath) as f:
html = f.read().decode('utf-8') try:
# tabs are referenced in policy.json through a 'slug' which is just the filename without the .html suffix html = f.read().decode('utf-8')
slug = os.path.splitext(os.path.basename(filepath))[0] # tabs are referenced in policy.json through a 'slug' which is just the filename without the .html suffix
loc = Location('i4x', course_descriptor.location.org, course_descriptor.location.course, category, slug) slug = os.path.splitext(os.path.basename(filepath))[0]
module = HtmlDescriptor(system, definition={'data' : html}, **{'location' : loc}) loc = Location('i4x', course_descriptor.location.org, course_descriptor.location.course, category, slug)
# VS[compat]: module = HtmlDescriptor(system, definition={'data' : html}, **{'location' : loc})
# Hack because we need to pull in the 'display_name' for static tabs (because we need to edit them) # VS[compat]:
# from the course policy # Hack because we need to pull in the 'display_name' for static tabs (because we need to edit them)
if category == "static_tab": # from the course policy
for tab in course_descriptor.tabs or []: if category == "static_tab":
if tab.get('url_slug') == slug: for tab in course_descriptor.tabs or []:
module.metadata['display_name'] = tab['name'] if tab.get('url_slug') == slug:
module.metadata['data_dir'] = course_dir module.metadata['display_name'] = tab['name']
self.modules[course_descriptor.id][module.location] = module module.metadata['data_dir'] = course_dir
except Exception, e: self.modules[course_descriptor.id][module.location] = module
logging.exception("Failed to load {0}. Skipping... Exception: {1}".format(filepath, str(e))) except Exception, e:
system.error_tracker("ERROR: " + str(e)) logging.exception("Failed to load {0}. Skipping... Exception: {1}".format(filepath, str(e)))
system.error_tracker("ERROR: " + str(e))
def get_instance(self, course_id, location, depth=0): def get_instance(self, course_id, location, depth=0):
""" """
......
12 hours
\ No newline at end of file
TBD
\ No newline at end of file
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
set -e set -e
set -x set -x
git remote prune origin
# Reset the submodule, in case it changed # Reset the submodule, in case it changed
git submodule foreach 'git reset --hard HEAD' git submodule foreach 'git reset --hard HEAD'
......
...@@ -15,6 +15,8 @@ function github_mark_failed_on_exit { ...@@ -15,6 +15,8 @@ function github_mark_failed_on_exit {
trap '[ $? == "0" ] || github_status state:failure "failed"' EXIT trap '[ $? == "0" ] || github_status state:failure "failed"' EXIT
} }
git remote prune origin
github_mark_failed_on_exit github_mark_failed_on_exit
github_status state:pending "is running" github_status state:pending "is running"
......
...@@ -83,7 +83,8 @@ XQUEUE_INTERFACE = AUTH_TOKENS['XQUEUE_INTERFACE'] ...@@ -83,7 +83,8 @@ XQUEUE_INTERFACE = AUTH_TOKENS['XQUEUE_INTERFACE']
MODULESTORE = AUTH_TOKENS.get('MODULESTORE', MODULESTORE) MODULESTORE = AUTH_TOKENS.get('MODULESTORE', MODULESTORE)
CONTENTSTORE = AUTH_TOKENS.get('CONTENTSTORE', CONTENTSTORE) CONTENTSTORE = AUTH_TOKENS.get('CONTENTSTORE', CONTENTSTORE)
STAFF_GRADING_INTERFACE = AUTH_TOKENS.get('STAFF_GRADING_INTERFACE') STAFF_GRADING_INTERFACE = AUTH_TOKENS.get('STAFF_GRADING_INTERFACE', STAFF_GRADING_INTERFACE)
PEER_GRADING_INTERFACE = AUTH_TOKENS.get('PEER_GRADING_INTERFACE', PEER_GRADING_INTERFACE)
PEARSON_TEST_USER = "pearsontest" PEARSON_TEST_USER = "pearsontest"
PEARSON_TEST_PASSWORD = AUTH_TOKENS.get("PEARSON_TEST_PASSWORD") PEARSON_TEST_PASSWORD = AUTH_TOKENS.get("PEARSON_TEST_PASSWORD")
...@@ -328,12 +328,28 @@ WIKI_LINK_DEFAULT_LEVEL = 2 ...@@ -328,12 +328,28 @@ WIKI_LINK_DEFAULT_LEVEL = 2
################################# Staff grading config ##################### ################################# Staff grading config #####################
STAFF_GRADING_INTERFACE = None #By setting up the default settings with an incorrect user name and password,
# will get an error when attempting to connect
STAFF_GRADING_INTERFACE = {
'url': 'http://sandbox-grader-001.m.edx.org/staff_grading',
'username': 'incorrect_user',
'password': 'incorrect_pass',
}
# Used for testing, debugging # Used for testing, debugging
MOCK_STAFF_GRADING = False MOCK_STAFF_GRADING = False
################################# Peer grading config ##################### ################################# Peer grading config #####################
PEER_GRADING_INTERFACE = None
#By setting up the default settings with an incorrect user name and password,
# will get an error when attempting to connect
PEER_GRADING_INTERFACE = {
'url': 'http://sandbox-grader-001.m.edx.org/peer_grading',
'username': 'incorrect_user',
'password': 'incorrect_pass',
}
# Used for testing, debugging
MOCK_PEER_GRADING = False MOCK_PEER_GRADING = False
################################# Jasmine ################################### ################################# Jasmine ###################################
......
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