Commit ad271073 by Andy Armstrong Committed by cahrens

Support making drafts of nested xblocks

parent a51c993f
......@@ -194,30 +194,30 @@ def course_image_url(course):
return path
class UnitState(object):
class PublishState(object):
draft = 'draft'
private = 'private'
public = 'public'
def compute_unit_state(unit):
def compute_publish_state(xblock):
"""
Returns whether this unit is 'draft', 'public', or 'private'.
Returns whether this xblock is 'draft', 'public', or 'private'.
'draft' content is in the process of being edited, but still has a previous
version visible in the LMS
'public' content is locked and visible in the LMS
'private' content is editabled and not visible in the LMS
'private' content is editable and not visible in the LMS
"""
if getattr(unit, 'is_draft', False):
if getattr(xblock, 'is_draft', False):
try:
modulestore('direct').get_item(unit.location)
return UnitState.draft
modulestore('direct').get_item(xblock.location)
return PublishState.draft
except ItemNotFoundError:
return UnitState.private
return PublishState.private
else:
return UnitState.public
return PublishState.public
def add_extra_panel_tab(tab_type, course):
......
......@@ -26,7 +26,7 @@ from xblock.runtime import Mixologist
from lms.lib.xblock.runtime import unquote_slashes
from contentstore.utils import get_lms_link_for_item, compute_unit_state, UnitState, get_modulestore
from contentstore.utils import get_lms_link_for_item, compute_publish_state, PublishState, get_modulestore
from contentstore.views.helpers import get_parent_xblock
from models.settings.course_grading import CourseGradingModel
......@@ -282,7 +282,7 @@ def unit_handler(request, tag=None, package_id=None, branch=None, version_guid=N
),
'section': containing_section,
'new_unit_category': 'vertical',
'unit_state': compute_unit_state(item),
'unit_state': compute_publish_state(item),
'published_date': (
get_default_time_display(item.published_date)
if item.published_date is not None else None
......
......@@ -97,5 +97,5 @@ def xblock_studio_url(xblock, course=None):
course_id = None
if course:
course_id = course.location.course_id
locator = loc_mapper().translate_location(course_id, xblock.location)
locator = loc_mapper().translate_location(course_id, xblock.location, published=False)
return locator.url_reverse(prefix)
......@@ -296,9 +296,9 @@ def _save_item(request, usage_loc, item_location, data=None, children=None, meta
if publish == 'make_private':
_xmodule_recurse(existing_item, lambda i: modulestore().unpublish(i.location))
elif publish == 'create_draft':
# This clones the existing item location to a draft location (the draft is
# This recursively clones the existing item location to a draft location (the draft is
# implicit, because modulestore is a Draft modulestore)
modulestore().convert_to_draft(item_location)
_xmodule_recurse(existing_item, lambda i: modulestore().convert_to_draft(i.location))
if data:
# TODO Allow any scope.content fields not just "data" (exactly like the get below this)
......
......@@ -15,6 +15,7 @@ from django.test.client import RequestFactory
from contentstore.views.component import component_handler
from contentstore.tests.utils import CourseTestCase
from contentstore.utils import compute_publish_state, PublishState
from student.tests.factories import UserFactory
from xmodule.capa_module import CapaDescriptor
from xmodule.modulestore.django import modulestore
......@@ -647,6 +648,7 @@ class TestEditItem(ItemTest):
self.assertEqual(resp.status_code, 200)
# Activate the editing view
view_url = '/xblock/{locator}/studio_view'.format(locator=self.problem_locator)
resp = self.client.get(view_url, HTTP_ACCEPT='application/json')
self.assertEqual(resp.status_code, 200)
......@@ -656,6 +658,50 @@ class TestEditItem(ItemTest):
self.assertNotEqual(draft.data, published.data)
def test_publish_states_of_nested_xblocks(self):
""" Test publishing of a unit page containing a nested xblock """
resp = self.create_xblock(parent_locator=self.seq_locator, display_name='Test Unit', category='vertical')
unit_locator = self.response_locator(resp)
resp = self.create_xblock(parent_locator=unit_locator, category='wrapper')
wrapper_locator = self.response_locator(resp)
resp = self.create_xblock(parent_locator=wrapper_locator, category='html')
html_locator = self.response_locator(resp)
# The unit and its children should be private initially
unit_update_url = '/xblock/' + unit_locator
unit = self.get_item_from_modulestore(unit_locator, True)
html = self.get_item_from_modulestore(html_locator, True)
self.assertEqual(compute_publish_state(unit), PublishState.private)
self.assertEqual(compute_publish_state(html), PublishState.private)
# Make the unit public and verify that the problem is also made public
resp = self.client.ajax_post(
unit_update_url,
data={'publish': 'make_public'}
)
self.assertEqual(resp.status_code, 200)
unit = self.get_item_from_modulestore(unit_locator, True)
html = self.get_item_from_modulestore(html_locator, True)
self.assertEqual(compute_publish_state(unit), PublishState.public)
self.assertEqual(compute_publish_state(html), PublishState.public)
# Make a draft for the unit and verify that the problem also has a draft
resp = self.client.ajax_post(
unit_update_url,
data={
'id': unit_locator,
'metadata': {},
'publish': 'create_draft'
}
)
self.assertEqual(resp.status_code, 200)
unit = self.get_item_from_modulestore(unit_locator, True)
html = self.get_item_from_modulestore(html_locator, True)
self.assertEqual(compute_publish_state(unit), PublishState.draft)
self.assertEqual(compute_publish_state(html), PublishState.draft)
@ddt.ddt
class TestComponentHandler(TestCase):
def setUp(self):
......
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