Commit 9a79aef7 by Will Daly

Merge pull request #122 from edx/will/tim-71

Warn authors about changing a released problem.
parents 495c8f3d ef5b7b1f
......@@ -13,6 +13,7 @@ describe("OpenAssessment.StudioUI", function() {
this.loadError = false;
this.updateError = false;
this.xml = '<openassessment></openassessment>';
this.isReleased = false;
this.errorPromise = $.Deferred(function(defer) {
defer.rejectWith(this, ['Test error']);
......@@ -41,6 +42,13 @@ describe("OpenAssessment.StudioUI", function() {
return this.errorPromise;
}
};
this.checkReleased = function() {
var server = this;
return $.Deferred(function(defer) {
defer.resolveWith(this, [server.isReleased]);
}).promise();
};
};
var server = null;
......@@ -87,6 +95,22 @@ describe("OpenAssessment.StudioUI", function() {
expect(server.xml).toEqual('<openassessment>test!</openassessment>');
});
it("confirms changes for a released problem", function() {
// Simulate an XBlock that has been released
server.isReleased = true;
// Stub the confirmation step (avoid showing the dialog)
spyOn(ui, 'confirmPostReleaseUpdate').andCallFake(
function(onConfirm) { onConfirm(); }
);
// Save the updated XML
ui.save();
// Verify that the user was asked to confirm the changes
expect(ui.confirmPostReleaseUpdate).toHaveBeenCalled();
});
it("cancels editing", function() {
ui.cancel();
expect(runtime.notify).toHaveBeenCalledWith('cancel', {});
......
......@@ -130,6 +130,20 @@ describe("OpenAssessment.Server", function() {
});
});
it("Checks whether the XBlock has been released", function() {
stubAjax(true, { success: true, is_released: true });
var receivedIsReleased = null;
server.checkReleased().done(function(isReleased) {
receivedIsReleased = isReleased;
});
expect(receivedIsReleased).toBe(true);
expect($.ajax).toHaveBeenCalledWith({
url: '/check_released', type: "POST", data: "\"\""
});
});
it("informs the caller of an Ajax error when rendering as HTML", function() {
stubAjax(false, null);
......@@ -235,7 +249,7 @@ describe("OpenAssessment.Server", function() {
stubAjax(true, {success:false, msg:'Test error!'});
var receivedMsg = null;
var options = {clarity: "Very clear", precision: "Somewhat precise"}
var options = {clarity: "Very clear", precision: "Somewhat precise"};
server.peerAssess("abc1234", options, "Excellent job!").fail(function(msg) {
receivedMsg = msg;
});
......@@ -247,11 +261,34 @@ describe("OpenAssessment.Server", function() {
stubAjax(false, null);
var receivedMsg = null;
var options = {clarity: "Very clear", precision: "Somewhat precise"}
var options = {clarity: "Very clear", precision: "Somewhat precise"};
server.peerAssess("abc1234", options, "Excellent job!").fail(function(msg) {
receivedMsg = msg;
});
expect(receivedMsg).toEqual("Could not contact server.");
});
it("informs the caller of an AJAX error when checking whether the XBlock has been released", function() {
stubAjax(false, null);
var receivedMsg = null;
server.checkReleased().fail(function(errMsg) {
receivedMsg = errMsg;
});
expect(receivedMsg).toEqual("Could not contact server.");
});
it("informs the caller of a server error when checking whether the XBlock has been released", function() {
stubAjax(true, { success: false, msg: "Test error" });
var receivedMsg = null;
server.checkReleased().fail(function(errMsg) {
receivedMsg = errMsg;
});
expect(receivedMsg).toEqual("Test error");
});
});
......@@ -60,9 +60,44 @@ OpenAssessment.StudioUI.prototype = {
},
/**
Save the updated XML definition to the server.
Save the problem's XML definition to the server.
If the problem has been released, make the user confirm the save.
**/
save: function() {
var ui = this;
// Check whether the problem has been released; if not,
// warn the user and allow them to cancel.
this.server.checkReleased().done(
function(isReleased) {
if (isReleased) { ui.confirmPostReleaseUpdate($.proxy(ui.updateXml, ui)); }
else { ui.updateXml(); }
}
).fail(function(errMsg) {
// TODO: error message in the UI
console.log(errMsg);
}
);
},
/**
Make the user confirm that he/she wants to update a problem
that has already been released.
Args:
onConfirm (function): A function that accepts no arguments,
executed if the user confirms the update.
**/
confirmPostReleaseUpdate: function(onConfirm) {
var msg = "This problem has already been released. Any changes will apply only to future assessments.";
// TODO: classier confirm dialog
if (confirm(msg)) { onConfirm(); }
},
/**
Save the updated XML definition to the server.
**/
updateXml: function() {
// Notify the client-side runtime that we are starting
// to save so it can show the "Saving..." notification
this.runtime.notify('save', {state: 'start'});
......
......@@ -266,11 +266,41 @@ OpenAssessment.Server.prototype = {
$.ajax({
type: "POST", url: url, data: payload
}).done(function(data) {
if (data.success) { defer.resolve() }
if (data.success) { defer.resolve(); }
else { defer.rejectWith(this, [data.msg]); }
}).fail(function(data) {
defer.rejectWith(this, ['Could not contact server.']);
});
}).promise();
},
/**
Check whether the XBlock has been released.
Returns:
A JQuery promise, which resolves with a boolean indicating
whether the XBlock has been released. On failure, the promise
provides an error message.
Example:
server.checkReleased().done(
function(isReleased) {}
).fail(
function(errMsg) {}
)
**/
checkReleased: function() {
var url = this.url('check_released');
var payload = "\"\"";
return $.Deferred(function(defer) {
$.ajax({
type: "POST", url: url, data: payload
}).done(function(data) {
if (data.success) { defer.resolveWith(this, [data.is_released]); }
else { defer.rejectWith(this, [data.msg]); }
}).fail(function(data) {
defer.rejectWith(this, ["Could not contact server."]);
});
}).promise();
}
};
......@@ -93,3 +93,24 @@ class StudioMixin(object):
return {'success': False, 'msg': msg, 'xml': u''}
else:
return {'success': True, 'msg': '', 'xml': xml}
@XBlock.json_handler
def check_released(self, data, suffix=''):
"""
Check whether the problem has been released.
Args:
data (dict): Not used
Kwargs:
suffix (str): Not used
Returns:
dict with keys 'success' (bool), 'message' (unicode), and 'is_released' (bool)
"""
# There aren't currently any server-side error conditions we report to the client,
# but we send success/msg values anyway for consistency with other handlers.
return {
'success': True, 'msg': u'',
'is_released': self.is_released()
}
\ No newline at end of file
......@@ -125,3 +125,20 @@ class StudioViewTest(XBlockHandlerTestCase):
self.assertEqual(xblock.prompt, old_prompt)
self.assertItemsEqual(xblock.rubric_assessments, old_assessments)
self.assertItemsEqual(xblock.rubric_criteria, old_criteria)
@scenario('data/basic_scenario.xml')
def test_check_released(self, xblock):
# By default, the problem should be released
resp = self.request(xblock, 'check_released', json.dumps(""), response_format='json')
self.assertTrue(resp['success'])
self.assertTrue(resp['is_released'])
self.assertIn('msg', resp)
# Set the problem to unpublished with a start date in the future
xblock.published_date = None
xblock.start = dt.datetime(3000, 1, 1).replace(tzinfo=pytz.utc).isoformat()
resp = self.request(xblock, 'check_released', json.dumps(""), response_format='json')
self.assertTrue(resp['success'])
self.assertFalse(resp['is_released'])
self.assertIn('msg', resp)
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