Allow Blender to mark shots as used/not used in edit.

NOTE: requires schema change, so be careful.
This commit is contained in:
2016-11-03 18:08:51 +01:00
parent dad5e4ceac
commit c40fdb378c
3 changed files with 65 additions and 9 deletions

View File

@@ -30,6 +30,10 @@ node_type_shot = {
'type': 'string', 'type': 'string',
'maxlength': 256, 'maxlength': 256,
}, },
'used_in_edit': {
'type': 'boolean',
'default': True,
},
}, },
'form_schema': {}, 'form_schema': {},
'parent': ['scene'] 'parent': ['scene']

View File

@@ -19,7 +19,7 @@ from pillar import attrs_extra
from attract.node_types import node_type_shot, node_type_task from attract.node_types import node_type_shot, node_type_task
# From patch operation name to fields that operation may edit. # From patch operation name to fields that operation may edit.
VALID_PATCH_OPERATIONS = { VALID_PATCH_FIELDS = {
u'from-blender': { u'from-blender': {
u'name', u'name',
u'picture', u'picture',
@@ -34,6 +34,11 @@ VALID_PATCH_OPERATIONS = {
u'description', u'description',
}, },
} }
VALID_PATCH_OPERATIONS = {
u'from-blender', u'from-web', u'unlink', u'relink',
}
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@@ -220,6 +225,7 @@ def node_setattr(node, key, value):
@register_patch_handler(node_type_shot['name']) @register_patch_handler(node_type_shot['name'])
def patch_shot(node_id, patch): def patch_shot(node_id, patch):
assert_is_valid_patch(patch) assert_is_valid_patch(patch)
log.info('Patching node %s: %s', node_id, patch)
# Find the full node, so we can PUT it through Eve for validation. # Find the full node, so we can PUT it through Eve for validation.
nodes_coll = flask.current_app.data.driver.db['nodes'] nodes_coll = flask.current_app.data.driver.db['nodes']
@@ -230,16 +236,27 @@ def patch_shot(node_id, patch):
log.warning('How can node %s not be found?', node_id) log.warning('How can node %s not be found?', node_id)
raise wz_exceptions.NotFound('Node %s not found' % node_id) raise wz_exceptions.NotFound('Node %s not found' % node_id)
op = patch['op']
if op in VALID_PATCH_FIELDS:
# Set the fields # Set the fields
log.info('Patching node %s: %s', node_id, patch)
for key, value in patch['$set'].items(): for key, value in patch['$set'].items():
node_setattr(node, key, value) node_setattr(node, key, value)
else:
# Remaining operations are for marking as 'in use' or 'not in use'.
used_in_edit = {
u'unlink': False,
u'relink': True,
}[op]
node['properties']['used_in_edit'] = used_in_edit
node = pillar.api.utils.remove_private_keys(node) node = pillar.api.utils.remove_private_keys(node)
r, _, _, status = put_internal('nodes', node, _id=node_id) r, _, _, status = put_internal('nodes', node, _id=node_id)
return pillar.api.utils.jsonify(r, status=status) return pillar.api.utils.jsonify(r, status=status)
def assert_is_valid_patch(patch): def assert_is_valid_patch(patch):
"""Raises an exception when the patch isn't valid.""" """Raises an exception when the patch isn't valid."""
@@ -248,12 +265,15 @@ def assert_is_valid_patch(patch):
except KeyError: except KeyError:
raise wz_exceptions.BadRequest("PATCH should have a key 'op' indicating the operation.") raise wz_exceptions.BadRequest("PATCH should have a key 'op' indicating the operation.")
try: if op not in VALID_PATCH_OPERATIONS:
allowed_fields = VALID_PATCH_OPERATIONS[op] valid_ops = u', '.join(sorted(VALID_PATCH_OPERATIONS))
except KeyError:
valid_ops = u', '.join(VALID_PATCH_OPERATIONS.keys())
raise wz_exceptions.BadRequest(u'Operation should be one of %s' % valid_ops) raise wz_exceptions.BadRequest(u'Operation should be one of %s' % valid_ops)
if op not in VALID_PATCH_FIELDS:
# Valid operation, and we don't have to check the fields.
return
allowed_fields = VALID_PATCH_FIELDS[op]
try: try:
fields = set(patch['$set'].keys()) fields = set(patch['$set'].keys())
except KeyError: except KeyError:

View File

@@ -339,6 +339,38 @@ class PatchShotTest(AbstractShotTest):
} }
self.patch(url, json=patch, auth_token='other', expected_status=403) self.patch(url, json=patch, auth_token='other', expected_status=403)
@responses.activate
def test_patch_unlink(self):
shot = self.create_shot()
self.create_valid_auth_token(ctd.EXAMPLE_PROJECT_OWNER_ID, 'token')
url = '/api/nodes/%s' % shot._id
dbnode = self.get(url, auth_token='token').json()
self.assertNotIn('used_in_edit', dbnode['properties'])
patch = {'op': 'unlink'}
self.patch(url, json=patch, auth_token='token')
dbnode = self.get(url, auth_token='token').json()
self.assertFalse(dbnode['properties']['used_in_edit'])
@responses.activate
def test_patch_relink(self):
shot = self.create_shot()
self.create_valid_auth_token(ctd.EXAMPLE_PROJECT_OWNER_ID, 'token')
url = '/api/nodes/%s' % shot._id
dbnode = self.get(url, auth_token='token').json()
self.assertNotIn('used_in_edit', dbnode['properties'])
patch = {'op': 'relink'}
self.patch(url, json=patch, auth_token='token')
dbnode = self.get(url, auth_token='token').json()
self.assertTrue(dbnode['properties']['used_in_edit'])
class RequiredAfterCreationTest(AbstractShotTest): class RequiredAfterCreationTest(AbstractShotTest):
""" """