Merge pull request #1091 from edx/assets/persist_lock
Export asset attrs to a policy file
This commit is contained in:
@@ -170,6 +170,16 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
|
||||
resp = self.client.get(reverse('edit_unit', kwargs={'location': descriptor.location.url()}))
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
def lockAnAsset(self, content_store, course_location):
|
||||
"""
|
||||
Lock an arbitrary asset in the course
|
||||
:param course_location:
|
||||
"""
|
||||
course_assets = content_store.get_all_content_for_course(course_location)
|
||||
self.assertGreater(len(course_assets), 0, "No assets to lock")
|
||||
content_store.set_attr(course_assets[0]['_id'], 'locked', True)
|
||||
return course_assets[0]['_id']
|
||||
|
||||
def test_edit_unit_toy(self):
|
||||
self.check_edit_unit('toy')
|
||||
|
||||
@@ -952,6 +962,11 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
|
||||
|
||||
self.assertIn(private_location_no_draft.url(), sequential.children)
|
||||
|
||||
locked_asset = self.lockAnAsset(content_store, location)
|
||||
locked_asset_attrs = content_store.get_attrs(locked_asset)
|
||||
# the later import will reupload
|
||||
del locked_asset_attrs['uploadDate']
|
||||
|
||||
print 'Exporting to tempdir = {0}'.format(root_dir)
|
||||
|
||||
# export out to a tempdir
|
||||
@@ -1034,6 +1049,10 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
|
||||
|
||||
self.assertGreater(len(course.textbooks), 0)
|
||||
|
||||
new_attrs = content_store.get_attrs(locked_asset)
|
||||
for key, value in locked_asset_attrs.iteritems():
|
||||
self.assertEqual(value, new_attrs[key])
|
||||
|
||||
shutil.rmtree(root_dir)
|
||||
|
||||
def test_export_course_with_metadata_only_video(self):
|
||||
|
||||
@@ -12,6 +12,7 @@ from .content import StaticContent, ContentStore, StaticContentStream
|
||||
from xmodule.exceptions import NotFoundError
|
||||
from fs.osfs import OSFS
|
||||
import os
|
||||
import json
|
||||
|
||||
|
||||
class MongoContentStore(ContentStore):
|
||||
@@ -103,12 +104,28 @@ class MongoContentStore(ContentStore):
|
||||
with disk_fs.open(content.name, 'wb') as asset_file:
|
||||
asset_file.write(content.data)
|
||||
|
||||
def export_all_for_course(self, course_location, output_directory):
|
||||
def export_all_for_course(self, course_location, output_directory, assets_policy_file):
|
||||
"""
|
||||
Export all of this course's assets to the output_directory. Export all of the assets'
|
||||
attributes to the policy file.
|
||||
|
||||
:param course_location: the Location of type 'course'
|
||||
:param output_directory: the directory under which to put all the asset files
|
||||
:param assets_policy_file: the filename for the policy file which should be in the same
|
||||
directory as the other policy files.
|
||||
"""
|
||||
policy = {}
|
||||
assets = self.get_all_content_for_course(course_location)
|
||||
|
||||
for asset in assets:
|
||||
asset_location = Location(asset['_id'])
|
||||
self.export(asset_location, output_directory)
|
||||
for attr, value in asset.iteritems():
|
||||
if attr not in ['_id', 'md5', 'uploadDate', 'length', 'chunkSize']:
|
||||
policy.setdefault(asset_location.url(), {})[attr] = value
|
||||
|
||||
with open(assets_policy_file, 'w') as f:
|
||||
json.dump(policy, f)
|
||||
|
||||
def get_all_content_thumbnails_for_course(self, location):
|
||||
return self._get_all_content_for_course(location, get_thumbnails=True)
|
||||
|
||||
@@ -55,8 +55,13 @@ def export_to_xml(modulestore, contentstore, course_location, root_dir, course_d
|
||||
with export_fs.open('course.xml', 'w') as course_xml:
|
||||
course_xml.write(xml)
|
||||
|
||||
policies_dir = export_fs.makeopendir('policies')
|
||||
# export the static assets
|
||||
contentstore.export_all_for_course(course_location, root_dir + '/' + course_dir + '/static/')
|
||||
contentstore.export_all_for_course(
|
||||
course_location,
|
||||
root_dir + '/' + course_dir + '/static/',
|
||||
root_dir + '/' + course_dir + '/policies/assets.json',
|
||||
)
|
||||
|
||||
# export the static tabs
|
||||
export_extra_content(export_fs, modulestore, course_location, 'static_tab', 'tabs', '.html')
|
||||
@@ -71,7 +76,6 @@ def export_to_xml(modulestore, contentstore, course_location, root_dir, course_d
|
||||
export_extra_content(export_fs, modulestore, course_location, 'about', 'about', '.html')
|
||||
|
||||
# export the grading policy
|
||||
policies_dir = export_fs.makeopendir('policies')
|
||||
course_run_policy_dir = policies_dir.makeopendir(course.location.name)
|
||||
with course_run_policy_dir.open('grading_policy.json', 'w') as grading_policy:
|
||||
grading_policy.write(dumps(course.grading_policy, cls=EdxJSONEncoder))
|
||||
|
||||
@@ -2,6 +2,7 @@ import logging
|
||||
import os
|
||||
import mimetypes
|
||||
from path import path
|
||||
import json
|
||||
|
||||
from xblock.fields import Scope
|
||||
|
||||
@@ -22,6 +23,13 @@ def import_static_content(modules, course_loc, course_data_path, static_content_
|
||||
|
||||
# now import all static assets
|
||||
static_dir = course_data_path / subpath
|
||||
try:
|
||||
with open(course_data_path / 'policies/assets.json') as f:
|
||||
policy = json.load(f)
|
||||
except (IOError, ValueError) as err:
|
||||
# xml backed courses won't have this file, only exported courses; so, its absence is not
|
||||
# really an exception.
|
||||
policy = {}
|
||||
|
||||
verbose = True
|
||||
|
||||
@@ -46,10 +54,16 @@ def import_static_content(modules, course_loc, course_data_path, static_content_
|
||||
if fullname_with_subpath.startswith('/'):
|
||||
fullname_with_subpath = fullname_with_subpath[1:]
|
||||
content_loc = StaticContent.compute_location(target_location_namespace.org, target_location_namespace.course, fullname_with_subpath)
|
||||
mime_type = mimetypes.guess_type(filename)[0]
|
||||
|
||||
|
||||
content = StaticContent(content_loc, filename, mime_type, data, import_path=fullname_with_subpath)
|
||||
policy_ele = policy.get(content_loc.url(), {})
|
||||
displayname = policy_ele.get('displayname', filename)
|
||||
locked = policy_ele.get('locked', False)
|
||||
mime_type = policy_ele.get('contentType', mimetypes.guess_type(filename)[0])
|
||||
content = StaticContent(
|
||||
content_loc, displayname, mime_type, data,
|
||||
import_path=fullname_with_subpath, locked=locked
|
||||
)
|
||||
|
||||
# first let's save a thumbnail so we can get back a thumbnail location
|
||||
(thumbnail_content, thumbnail_location) = static_content_store.generate_thumbnail(content)
|
||||
|
||||
Reference in New Issue
Block a user