Commit bf8183f6 by Ben McMorran

Merge pull request #4544 from edx/benmcmorran/fixes-from-bulk-publishing

Return edit info from update_item and refactor item.py to use usage_key_with_run
parents 8a5bb729 66301fcf
...@@ -62,6 +62,15 @@ def hash_resource(resource): ...@@ -62,6 +62,15 @@ def hash_resource(resource):
return md5.hexdigest() return md5.hexdigest()
def usage_key_with_run(usage_key_string):
"""
Converts usage_key_string to a UsageKey, adding a course run if necessary
"""
usage_key = UsageKey.from_string(usage_key_string)
usage_key = usage_key.replace(course_key=modulestore().fill_in_run(usage_key.course_key))
return usage_key
# pylint: disable=unused-argument # pylint: disable=unused-argument
@require_http_methods(("DELETE", "GET", "PUT", "POST")) @require_http_methods(("DELETE", "GET", "PUT", "POST"))
@login_required @login_required
...@@ -100,9 +109,7 @@ def xblock_handler(request, usage_key_string): ...@@ -100,9 +109,7 @@ def xblock_handler(request, usage_key_string):
The locator (unicode representation of a UsageKey) for the created xblock (minus children) is returned. The locator (unicode representation of a UsageKey) for the created xblock (minus children) is returned.
""" """
if usage_key_string: if usage_key_string:
usage_key = UsageKey.from_string(usage_key_string) usage_key = usage_key_with_run(usage_key_string)
# usage_key's course_key may have an empty run property
usage_key = usage_key.replace(course_key=modulestore().fill_in_run(usage_key.course_key))
if not has_course_access(request.user, usage_key.course_key): if not has_course_access(request.user, usage_key.course_key):
raise PermissionDenied() raise PermissionDenied()
...@@ -137,16 +144,8 @@ def xblock_handler(request, usage_key_string): ...@@ -137,16 +144,8 @@ def xblock_handler(request, usage_key_string):
) )
elif request.method in ('PUT', 'POST'): elif request.method in ('PUT', 'POST'):
if 'duplicate_source_locator' in request.json: if 'duplicate_source_locator' in request.json:
parent_usage_key = UsageKey.from_string(request.json['parent_locator']) parent_usage_key = usage_key_with_run(request.json['parent_locator'])
# usage_key's course_key may have an empty run property duplicate_source_usage_key = usage_key_with_run(request.json['duplicate_source_locator'])
parent_usage_key = parent_usage_key.replace(
course_key=modulestore().fill_in_run(parent_usage_key.course_key)
)
duplicate_source_usage_key = UsageKey.from_string(request.json['duplicate_source_locator'])
# usage_key's course_key may have an empty run property
duplicate_source_usage_key = duplicate_source_usage_key.replace(
course_key=modulestore().fill_in_run(duplicate_source_usage_key.course_key)
)
dest_usage_key = _duplicate_item( dest_usage_key = _duplicate_item(
parent_usage_key, parent_usage_key,
...@@ -177,9 +176,7 @@ def xblock_view_handler(request, usage_key_string, view_name): ...@@ -177,9 +176,7 @@ def xblock_view_handler(request, usage_key_string, view_name):
resources: A list of tuples where the first element is the resource hash, and resources: A list of tuples where the first element is the resource hash, and
the second is the resource description the second is the resource description
""" """
usage_key = UsageKey.from_string(usage_key_string) usage_key = usage_key_with_run(usage_key_string)
# usage_key's course_key may have an empty run property
usage_key = usage_key.replace(course_key=modulestore().fill_in_run(usage_key.course_key))
if not has_course_access(request.user, usage_key.course_key): if not has_course_access(request.user, usage_key.course_key):
raise PermissionDenied() raise PermissionDenied()
...@@ -319,8 +316,7 @@ def _save_item(user, usage_key, data=None, children=None, metadata=None, nullout ...@@ -319,8 +316,7 @@ def _save_item(user, usage_key, data=None, children=None, metadata=None, nullout
if children is not None: if children is not None:
children_usage_keys = [] children_usage_keys = []
for child in children: for child in children:
child_usage_key = UsageKey.from_string(child) child_usage_key = usage_key_with_run(child)
child_usage_key = child_usage_key.replace(course_key=modulestore().fill_in_run(child_usage_key.course_key))
children_usage_keys.append(child_usage_key) children_usage_keys.append(child_usage_key)
existing_item.children = children_usage_keys existing_item.children = children_usage_keys
...@@ -387,9 +383,7 @@ def _save_item(user, usage_key, data=None, children=None, metadata=None, nullout ...@@ -387,9 +383,7 @@ def _save_item(user, usage_key, data=None, children=None, metadata=None, nullout
@expect_json @expect_json
def _create_item(request): def _create_item(request):
"""View for create items.""" """View for create items."""
usage_key = UsageKey.from_string(request.json['parent_locator']) usage_key = usage_key_with_run(request.json['parent_locator'])
# usage_key's course_key may have an empty run property
usage_key = usage_key.replace(course_key=modulestore().fill_in_run(usage_key.course_key))
category = request.json['category'] category = request.json['category']
display_name = request.json.get('display_name') display_name = request.json.get('display_name')
......
...@@ -1013,7 +1013,7 @@ class MongoModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase): ...@@ -1013,7 +1013,7 @@ class MongoModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase):
location = course_key.make_usage_key(block_type, block_id) location = course_key.make_usage_key(block_type, block_id)
xblock = self.create_xmodule(location, **kwargs) xblock = self.create_xmodule(location, **kwargs)
self.update_item(xblock, user_id, allow_not_found=True) xblock = self.update_item(xblock, user_id, allow_not_found=True)
return xblock return xblock
...@@ -1127,6 +1127,19 @@ class MongoModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase): ...@@ -1127,6 +1127,19 @@ class MongoModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase):
} }
self._update_ancestors(xblock.scope_ids.usage_id, ancestor_payload) self._update_ancestors(xblock.scope_ids.usage_id, ancestor_payload)
# update the edit info of the instantiated xblock
xblock.edited_on = now
xblock.edited_by = user_id
xblock.subtree_edited_on = now
xblock.subtree_edited_by = user_id
if not hasattr(xblock, 'published_date'):
xblock.published_date = None
if not hasattr(xblock, 'published_by'):
xblock.published_by = None
if isPublish:
xblock.published_date = now
xblock.published_by = user_id
# recompute (and update) the metadata inheritance tree which is cached # recompute (and update) the metadata inheritance tree which is cached
self.refresh_cached_metadata_inheritance_tree(xblock.scope_ids.usage_id.course_key, xblock.runtime) self.refresh_cached_metadata_inheritance_tree(xblock.scope_ids.usage_id.course_key, xblock.runtime)
# fire signal that we've written to DB # fire signal that we've written to DB
......
...@@ -4,6 +4,8 @@ import ddt ...@@ -4,6 +4,8 @@ import ddt
from importlib import import_module from importlib import import_module
from collections import namedtuple from collections import namedtuple
import unittest import unittest
import datetime
from pytz import UTC
from xmodule.tests import DATA_DIR from xmodule.tests import DATA_DIR
from opaque_keys.edx.locations import Location from opaque_keys.edx.locations import Location
...@@ -666,6 +668,28 @@ class TestMixedModuleStore(unittest.TestCase): ...@@ -666,6 +668,28 @@ class TestMixedModuleStore(unittest.TestCase):
self.assertEqual(len(orphans), 0, "unexpected orphans: {}".format(orphans)) self.assertEqual(len(orphans), 0, "unexpected orphans: {}".format(orphans))
@ddt.data('draft', 'split') @ddt.data('draft', 'split')
def test_create_item_populates_edited_info(self, default_ms):
self.initdb(default_ms)
block = self.store.create_item(
self.user_id,
self.course.location.version_agnostic().course_key,
'problem'
)
self.assertEqual(self.user_id, block.edited_by)
self.assertGreater(datetime.datetime.now(UTC), block.edited_on)
@ddt.data('draft')
def test_create_item_populates_subtree_edited_info(self, default_ms):
self.initdb(default_ms)
block = self.store.create_item(
self.user_id,
self.course.location.version_agnostic().course_key,
'problem'
)
self.assertEqual(self.user_id, block.subtree_edited_by)
self.assertGreater(datetime.datetime.now(UTC), block.subtree_edited_on)
@ddt.data('draft', 'split')
def test_get_courses_for_wiki(self, default_ms): def test_get_courses_for_wiki(self, default_ms):
""" """
Test the get_courses_for_wiki method Test the get_courses_for_wiki method
......
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