New publishing controls on unit page (continued)

STUD-1707
This commit is contained in:
cahrens
2014-07-02 13:06:34 -04:00
parent bbcc0030ea
commit d6475f4558
11 changed files with 268 additions and 44 deletions

View File

@@ -1,6 +1,8 @@
from __future__ import absolute_import
"""
Helper methods for Studio views.
"""
import logging
from __future__ import absolute_import
from django.conf import settings
from django.http import HttpResponse
@@ -13,11 +15,6 @@ from contentstore.utils import reverse_course_url, reverse_usage_url
__all__ = ['edge', 'event', 'landing']
EDITING_TEMPLATES = [
"basic-modal", "modal-button", "edit-xblock-modal", "editor-mode-button", "upload-dialog", "image-modal",
"add-xblock-component", "add-xblock-component-button", "add-xblock-component-menu",
"add-xblock-component-menu-problem", "xblock-string-field-editor",
]
# points to the temporary course landing page with log in and sign up
def landing(request, org, course, coursename):

View File

@@ -23,6 +23,8 @@ from contentstore.tests.utils import CourseTestCase
from student.tests.factories import UserFactory
from xmodule.capa_module import CapaDescriptor
from xmodule.modulestore import PublishState
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.django import modulestore
from xmodule.x_module import STUDIO_VIEW, STUDENT_VIEW
from xblock.exceptions import NoSuchHandlerError
from opaque_keys.edx.keys import UsageKey, CourseKey
@@ -567,7 +569,7 @@ class TestEditItem(ItemTest):
self.assertEqual(updated_draft.due, datetime(2077, 10, 10, 4, 0, tzinfo=UTC))
self.assertIsNone(published.due)
# Fetch the published version again to make sure the due date is still unset.
published = modulestore().get_item(published.location, revision=REVISION_OPTION_PUBLISHED_ONLY)
published = modulestore().get_item(published.location, revision=ModuleStoreEnum.RevisionOption.published_only)
self.assertIsNone(published.due)
def test_make_public_with_update(self):
@@ -620,7 +622,7 @@ class TestEditItem(ItemTest):
draft = self.get_item_from_modulestore(self.problem_usage_key, verify_is_draft=True)
self.assertNotEqual(draft.data, published.data)
# Fetch the published version again to make sure the data is correct.
published = modulestore().get_item(published.location, revision=REVISION_OPTION_PUBLISHED_ONLY)
published = modulestore().get_item(published.location, revision=ModuleStoreEnum.RevisionOption.published_only)
self.assertNotEqual(draft.data, published.data)
def test_publish_states_of_nested_xblocks(self):

View File

@@ -44,8 +44,7 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin
);
};
respondWithJson = function(json) {
var requestIndex = requests.length - 1;
respondWithJson = function(json, requestIndex) {
create_sinon.respondWithJson(
requests,
json,
@@ -131,10 +130,29 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin
draftBit = "draft",
publishButtonCss = ".action-publish",
discardChangesButtonCss = ".action-discard",
request, lastRequest, promptSpies;
request, lastRequest, promptSpies, sendDiscardChangesToServer;
lastRequest = function() { return requests[requests.length - 1]; };
sendDiscardChangesToServer = function(test) {
// Helper function to do the discard operation, up until the server response.
renderContainerPage(mockContainerXBlockHtml, test);
fetch({"id": "locator-container", "published": true, "has_changes": true});
expect(containerPage.$(discardChangesButtonCss)).not.toHaveClass('is-disabled');
expect(containerPage.$(bitPublishingCss)).toHaveClass(draftBit);
// Click discard changes
containerPage.$(discardChangesButtonCss).click();
// Confirm the discard.
expect(promptSpies.constructor).toHaveBeenCalled();
promptSpies.constructor.mostRecentCall.args[0].actions.primary.click(promptSpies);
request = lastRequest();
expect(request.url).toEqual("/xblock/locator-container");
expect(request.method).toEqual("DELETE");
expect(request.requestBody).toEqual(null);
};
beforeEach(function() {
promptSpies = spyOnConstructor(Prompt, "Warning", ["show", "hide"]);
promptSpies.show.andReturn(this.promptSpies);
@@ -199,6 +217,8 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin
// Verify updates displayed
expect(containerPage.$(bitPublishingCss)).toHaveClass(publishedBit);
// Verify that the "published" value has been cleared out of the model.
expect(containerPage.model.get("publish")).toBeNull();
});
it('can does not fetch if publish fails', function () {
@@ -217,27 +237,26 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin
// Verify still in draft state.
expect(containerPage.$(bitPublishingCss)).toHaveClass(draftBit);
// Verify that the "published" value has been cleared out of the model.
expect(containerPage.model.get("publish")).toBeNull();
});
/* STUD-1860
it('can discard changes', function () {
renderContainerPage(mockContainerXBlockHtml, this);
fetch({"id": "locator-container", "published": true, "has_changes": true});
expect(containerPage.$(discardChangesButtonCss)).not.toHaveClass('is-disabled');
expect(containerPage.$(bitPublishingCss)).toHaveClass(draftBit);
// Click discard changes
containerPage.$(discardChangesButtonCss).click();
sendDiscardChangesToServer(this);
// Confirm the discard.
expect(promptSpies.constructor).toHaveBeenCalled();
promptSpies.constructor.mostRecentCall.args[0].actions.primary.click(promptSpies);
var numRequests = requests.length;
create_sinon.respondToDelete(requests);
// Response to fetch, specifying the very next request (as multiple requests will be sent to server)
respondWithJson({"id": "locator-container", "published": true, "has_changes": false}, numRequests);
expect(containerPage.$(discardChangesButtonCss)).toHaveClass('is-disabled');
expect(containerPage.$(bitPublishingCss)).toHaveClass(publishedBit);
});
*/
request = lastRequest();
expect(request.url).toEqual("/xblock/locator-container");
expect(request.method).toEqual("DELETE");
expect(request.requestBody).toEqual(null);
it('does not fetch if discard changes fails', function () {
sendDiscardChangesToServer(this);
// Respond with failure because code does window.location.reload (which will
// put tests into an infinite loop) on success.
var numRequests = requests.length;
// Respond with failure
create_sinon.respondWithError(requests);
@@ -249,8 +268,6 @@ define(["jquery", "underscore", "underscore.string", "js/spec_helpers/create_sin
it('does not discard changes on cancel', function () {
renderContainerPage(mockContainerXBlockHtml, this);
fetch({"id": "locator-container", "published": true, "has_changes": true});
expect(containerPage.$(discardChangesButtonCss)).not.toHaveClass('is-disabled');
expect(containerPage.$(bitPublishingCss)).toHaveClass(draftBit);
var numRequests = requests.length;
// Click discard changes

View File

@@ -28,7 +28,9 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/contai
if (this.isUnitPage) {
this.xblockPublisher = new ContainerSubviews.Publisher({
el: this.$('#publish-unit'),
model: this.model
model: this.model,
// When "Discard Changes" is clicked, the whole page must be re-rendered.
renderPage: this.render
});
this.xblockPublisher.render();

View File

@@ -92,6 +92,7 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/feedba
BaseView.prototype.initialize.call(this);
this.template = this.loadTemplate('publish-xblock');
this.model.on('sync', this.onSync, this);
this.renderPage = this.options.renderPage;
},
onSync: function(e) {
@@ -121,6 +122,8 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/feedba
this.runOperationShowingMessage(gettext('Publishing…'),
function () {
return xblockInfo.save({publish: 'make_public'});
}).always(function() {
xblockInfo.set("publish", null);
}).done(function () {
xblockInfo.fetch();
});
@@ -130,7 +133,7 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/feedba
if (e && e.preventDefault) {
e.preventDefault();
}
var xblockInfo = this.model, view;
var xblockInfo = this.model, view, renderPage = this.renderPage;
view = new PromptView.Warning({
title: gettext("Discard Changes"),
@@ -144,7 +147,19 @@ define(["jquery", "underscore", "gettext", "js/views/baseview", "js/views/feedba
type: 'DELETE',
url: xblockInfo.url()
}).success(function () {
return window.location.reload();
window.alert("Refresh the page to see that changes were discarded. " +
"Auto-refresh will be implemented in a later story.");
/* Fetch is never returning on sandbox-- try
doing a PUT instead of a DELETE with publish option
to work around, or contact dev ops.
STUD-1860
window.crazyAjaxHandler = xblockInfo.fetch({
complete: function(a, b, c) {
debugger;
}
});
renderPage();
*/
});
}
},

View File

@@ -11,7 +11,7 @@ else:
import json
from xmodule.modulestore import PublishState
from contentstore.views.helpers import xblock_studio_url, xblock_type_display_name, EDITING_TEMPLATES
from contentstore.views.helpers import xblock_studio_url, xblock_type_display_name
from django.utils.translation import ugettext as _
%>
<%block name="title">${xblock.display_name_with_default} ${xblock_type_display_name(xblock)}</%block>
@@ -20,16 +20,17 @@ from django.utils.translation import ugettext as _
<%namespace name='static' file='static_content.html'/>
<%namespace name="units" file="widgets/units.html" />
<%!
templates = ["basic-modal", "modal-button", "edit-xblock-modal",
"editor-mode-button", "upload-dialog", "image-modal",
"add-xblock-component", "add-xblock-component-button", "add-xblock-component-menu",
"add-xblock-component-menu-problem", "xblock-string-field-editor", "publish-xblock"]
%>
<%block name="header_extras">
% for template_name in EDITING_TEMPLATES:
% for template_name in templates:
<script type="text/template" id="${template_name}-tpl">
<%static:include path="js/${template_name}.underscore" />
</script>
<script type="text/template" id="publish-xblock-tpl">
<%static:include path="js/publish-xblock.underscore" />
</script>
% endfor
<link rel="stylesheet" type="text/css" href="${static.url('js/vendor/timepicker/jquery.timepicker.css')}" />
</%block>
@@ -40,7 +41,6 @@ from django.utils.translation import ugettext as _
"js/collections/component_template", "xmodule", "coffee/src/main", "xblock/cms.runtime.v1"],
function(doc, $, XBlockInfo, ContainerPage, ComponentTemplates, xmoduleLoader) {
var templates = new ComponentTemplates(${component_templates | n}, {parse: true});
// TODO: can go back to dumping on server side if easier.
var mainXBlockInfo = new XBlockInfo(${json.dumps(xblock_info) | n});
var isUnitPage = ${json.dumps(is_unit_page)}

View File

@@ -7,14 +7,14 @@
<% } %>
</h3>
<!--To be added in STUDIO-1708-->
<!--To be added in STUDIO-1826-->
<!--<div class="wrapper-last-draft bar-mod-content">-->
<!--<p class="copy meta">-->
<!--Draft saved on 6/15/2014 at 12:45pm by amako-->
<!--</p>-->
<!--</div>-->
<!--To be added in STUD-1712-->
<!--To be added in STUD-1829-->
<!--<div class="wrapper-release bar-mod-content">-->
<!--<h5 class="title">Will Release:</h5>-->
<!--<p class="copy">-->
@@ -23,7 +23,7 @@
<!--</p>-->
<!--</div>-->
<!--To be added in STUD-1713-->
<!--To be added in STUD-1830-->
<!--<div class="wrapper-visibility bar-mod-content">-->
<!--<h5 class="title">Will be Visible to:</h5>-->
<!--<p class="copy">Staff and Students</p>-->