Additional logic to handle more course_image URL edge cases

This changes logic to allow more missed use cases of course_image to
work properly.  The cases are:

. XML courses with the course_image attribute set
. Mongo courses that are imported without a contentstore
. Mongo courses that have course_image set but don't have a content store

It also exports default images_static_course.jpg to
images/static_course.jpg to handle a use case where a course author
uploaded an image to the default location in studio without using the
studio interface for adding course images, they then export the course, and then
import it without a contentstore
This commit is contained in:
Carson Gee
2014-04-16 18:05:33 -04:00
parent bf56d30355
commit c4ea338035
7 changed files with 105 additions and 7 deletions

View File

@@ -1,11 +1,14 @@
from pprint import pprint
# pylint: disable=E0611
from nose.tools import assert_equals, assert_raises, \
assert_not_equals, assert_false
assert_not_equals, assert_false, assert_true
from itertools import ifilter
# pylint: enable=E0611
from path import path
import pymongo
import logging
import shutil
from tempfile import mkdtemp
from uuid import uuid4
from xblock.fields import Scope
@@ -16,6 +19,7 @@ from xmodule.tests import DATA_DIR
from xmodule.modulestore import Location, MONGO_MODULESTORE_TYPE
from xmodule.modulestore.mongo import MongoModuleStore, MongoKeyValueStore
from xmodule.modulestore.draft import DraftModuleStore
from xmodule.modulestore.xml_exporter import export_to_xml
from xmodule.modulestore.xml_importer import import_from_xml, perform_xlint
from xmodule.contentstore.mongo import MongoContentStore
@@ -310,6 +314,50 @@ class TestMongoModuleStore(object):
assert_equals(len(course_locations), 1)
assert_in(Location('i4x', 'edX', 'simple', 'course', '2012_Fall'), course_locations)
def test_export_course_image(self):
"""
Test to make sure that we have a course image in the contentstore,
then export it to ensure it gets copied to both file locations.
"""
location = Location('c4x', 'edX', 'simple', 'asset', 'images_course_image.jpg')
course_location = Location('i4x', 'edX', 'simple', 'course', '2012_Fall')
# This will raise if the course image is missing
self.content_store.find(location)
root_dir = path(mkdtemp())
export_to_xml(self.store, self.content_store, course_location, root_dir, 'test_export')
assert_true(path(root_dir / 'test_export/static/images/course_image.jpg').isfile())
assert_true(path(root_dir / 'test_export/static/images_course_image.jpg').isfile())
shutil.rmtree(root_dir)
def test_export_course_image_nondefault(self):
"""
Make sure that if a non-default image path is specified that we
don't export it to the static default location
"""
course = self.get_course_by_id('edX/toy/2012_Fall')
assert_true(course.course_image, 'just_a_test.jpg')
root_dir = path(mkdtemp())
export_to_xml(self.store, self.content_store, course.location, root_dir, 'test_export')
assert_true(path(root_dir / 'test_export/static/just_a_test.jpg').isfile())
assert_false(path(root_dir / 'test_export/static/images/course_image.jpg').isfile())
shutil.rmtree(root_dir)
def test_course_without_image(self):
"""
Make sure we elegantly passover our code when there isn't a static
image
"""
course = self.get_course_by_id('edX/simple_with_draft/2012_Fall')
root_dir = path(mkdtemp())
export_to_xml(self.store, self.content_store, course.location, root_dir, 'test_export')
assert_false(path(root_dir / 'test_export/static/images/course_image.jpg').isfile())
assert_false(path(root_dir / 'test_export/static/images_course_image.jpg').isfile())
shutil.rmtree(root_dir)
class TestMongoKeyValueStore(object):
"""

View File

@@ -5,6 +5,8 @@ Methods for exporting course data to XML
import logging
import lxml.etree
from xblock.fields import Scope
from xmodule.contentstore.content import StaticContent
from xmodule.exceptions import NotFoundError
from xmodule.modulestore import Location
from xmodule.modulestore.inheritance import own_metadata
from fs.osfs import OSFS
@@ -79,6 +81,26 @@ def export_to_xml(modulestore, contentstore, course_location, root_dir, course_d
root_dir + '/' + course_dir + '/policies/assets.json',
)
# If we are using the default course image, export it to the
# legacy location to support backwards compatibility.
if course.course_image == course.fields['course_image'].default:
try:
course_image = contentstore.find(
StaticContent.compute_location(
course.location.org,
course.location.course,
course.course_image
),
)
except NotFoundError:
pass
else:
output_dir = root_dir + '/' + course_dir + '/static/images/'
if not os.path.isdir(output_dir):
os.makedirs(output_dir)
with OSFS(output_dir).open('course_image.jpg', 'wb') as course_image_file:
course_image_file.write(course_image.data)
# export the static tabs
export_extra_content(export_fs, modulestore, course_id, course_location, 'static_tab', 'tabs', '.html')

Binary file not shown.

After

Width:  |  Height:  |  Size: 547 B

View File

@@ -1,4 +1,4 @@
<course>
<course course_image="just_a_test.jpg">
<textbook title="Textbook" book_url="https://s3.amazonaws.com/edx-textbooks/guttag_computation_v3/"/>
<chapter url_name="Overview">
<videosequence url_name="Toy_Videos">

Binary file not shown.

After

Width:  |  Height:  |  Size: 547 B