Added etag checking when saving tasks & shots. Still a bit rough.

Needs nicer user interface stuff for explaining what's going on.
This commit is contained in:
2016-09-22 18:28:11 +02:00
parent d13abb5b34
commit 498e1d5ecc
7 changed files with 47 additions and 7 deletions

View File

@@ -92,6 +92,7 @@ class ShotManager(object):
api = pillar_api()
shot = pillarsdk.Node.find(shot_id, api=api)
shot._etag = fields.pop('_etag')
shot.name = fields.pop('name')
shot.description = fields.pop('description')
shot.properties.status = fields.pop('status')

View File

@@ -133,13 +133,16 @@ function attract_form_save(form_id, item_id, item_save_url, options={})
if (console) console.log('Done saving', saved_item);
$('#status-bar')
.text('Saved ' + options.type + '. ' + saved_item._updated);
$form.find("input[name='_etag']").val(saved_item._etag);
if (options.done) options.done($item, saved_item);
})
.fail(function(xhr_or_response_data) {
// jQuery sends the response data (if JSON), or an XHR object (if not JSON).
if (console) console.log('Failed saving', xhr_or_response_data);
$('#status-bar').text('Failed saving. ' + xhr_or_response_data.responseText);
$button.removeClass('btn-default').addClass('btn-danger');
$('#status-bar').text('Failed saving. ' + xhr_or_response_data.status);
if (options.fail) options.fail($item, xhr_or_response_data);
})
@@ -171,7 +174,12 @@ function task_save(task_id, task_url) {
;
},
fail: function($item, xhr_or_response_data) {
$('#task-details').html(xhr_or_response_data.responseText);
if (xhr_or_response_data.status == 412) {
// TODO: implement something nice here. Just make sure we don't throw
// away the user's edits. It's up to the user to handle this.
} else {
$('#task-details').html(xhr_or_response_data.responseText);
}
},
type: 'task'
});
@@ -189,7 +197,12 @@ function shot_save(shot_id, shot_url) {
;
},
fail: function($item, xhr_or_response_data) {
$('#task-details').html(xhr_or_response_data.responseText);
if (xhr_or_response_data.status == 412) {
// TODO: implement something nice here. Just make sure we don't throw
// away the user's edits. It's up to the user to handle this.
} else {
$('#task-details').html(xhr_or_response_data.responseText);
}
},
type: 'shot'
});

View File

@@ -66,6 +66,7 @@ class TaskManager(object):
api = pillar_api()
task = pillarsdk.Node.find(task_id, api=api)
task._etag = fields.pop('_etag')
task.name = fields.pop('name')
task.description = fields.pop('description')
task.properties.status = fields.pop('status')

View File

@@ -1,5 +1,6 @@
.attract-form
form#shot_form(onsubmit="return shot_save('{{shot._id}}', '{{ url_for('attract.shots.perproject.save', project_url=project['url'], shot_id=shot._id) }}')")
input(type='hidden',name='_etag',value='{{ shot._etag }}')
.input-transparent-group
input.input-transparent.item-name(
name="name",
@@ -30,4 +31,6 @@
.input-group-separator
.input-transparent-group
| {% if 'PUT' in shot.allowed_methods %}
button.btn.btn-default.btn-block(type=submit) Save Changes
| {% endif %}

View File

@@ -1,5 +1,6 @@
.attract-form
form#task_form(onsubmit="return task_save('{{task._id}}', '{{ url_for('attract.tasks.perproject.save', project_url=project['url'], task_id=task._id) }}')")
input(type='hidden',name='_etag',value='{{ task._etag }}')
.input-transparent-group
input.input-transparent.item-name(
name="name",
@@ -47,7 +48,9 @@
| {% endfor %}
.input-transparent-group
button.btn.btn-default.btn-block(type=submit) Save Changes
| {% if 'PUT' in task.allowed_methods %}
button.btn.btn-default.btn-block(type='submit') Save Changes
| {% endif %}
#task-view-feed

View File

@@ -4,6 +4,7 @@ import responses
from bson import ObjectId
import pillarsdk
import pillarsdk.exceptions as sdk_exceptions
import pillar.tests
import pillar.auth
import pillar.tests.common_test_data as ctd
@@ -94,10 +95,19 @@ class ShotManagerTest(AbstractAttractTest):
self.mock_blenderid_validate_happy()
self.assertRaises(sdk_exceptions.PreconditionFailed,
self.smngr.edit_shot,
shot_id=shot['_id'],
name=u'ผัดไทย',
description=u'Shoot the Pad Thai',
status='todo',
_etag='jemoeder')
self.smngr.edit_shot(shot_id=shot['_id'],
name=u'ผัดไทย',
description=u'Shoot the Pad Thai',
status='todo')
status='todo',
_etag=shot._etag)
# Test directly with MongoDB
with self.app.test_request_context():
@@ -107,4 +117,3 @@ class ShotManagerTest(AbstractAttractTest):
self.assertEqual(u'todo', found['properties']['status'])
self.assertEqual(u'Shoot the Pad Thai', found['description'])
self.assertNotIn(u'notes', found['properties'])

View File

@@ -4,6 +4,7 @@ import responses
from bson import ObjectId
import pillarsdk
import pillarsdk.exceptions as sdk_exceptions
import pillar.api.utils
import pillar.tests
import pillar.auth
@@ -59,11 +60,20 @@ class TaskWorkflowTest(AbstractAttractTest):
pillar.auth.login_user(ctd.EXAMPLE_PROJECT_OWNER_ID)
self.mock_blenderid_validate_happy()
self.assertRaises(sdk_exceptions.PreconditionFailed,
self.mngr.edit_task,
task._id,
task_type=u'je møder',
name=u'nööw name',
description=u'€ ≠ ¥',
status='todo',
_etag='jemoeder')
self.mngr.edit_task(task._id,
task_type=u'je møder',
name=u'nööw name',
description=u'€ ≠ ¥',
status='todo')
status='todo',
_etag=task._etag)
# Test directly with MongoDB
with self.app.test_request_context():