Allow Blender to mark shots as used/not used in edit.
NOTE: requires schema change, so be careful.
This commit is contained in:
@@ -30,6 +30,10 @@ node_type_shot = {
|
||||
'type': 'string',
|
||||
'maxlength': 256,
|
||||
},
|
||||
'used_in_edit': {
|
||||
'type': 'boolean',
|
||||
'default': True,
|
||||
},
|
||||
},
|
||||
'form_schema': {},
|
||||
'parent': ['scene']
|
||||
|
@@ -19,7 +19,7 @@ from pillar import attrs_extra
|
||||
from attract.node_types import node_type_shot, node_type_task
|
||||
|
||||
# From patch operation name to fields that operation may edit.
|
||||
VALID_PATCH_OPERATIONS = {
|
||||
VALID_PATCH_FIELDS = {
|
||||
u'from-blender': {
|
||||
u'name',
|
||||
u'picture',
|
||||
@@ -34,6 +34,11 @@ VALID_PATCH_OPERATIONS = {
|
||||
u'description',
|
||||
},
|
||||
}
|
||||
|
||||
VALID_PATCH_OPERATIONS = {
|
||||
u'from-blender', u'from-web', u'unlink', u'relink',
|
||||
}
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -220,6 +225,7 @@ def node_setattr(node, key, value):
|
||||
@register_patch_handler(node_type_shot['name'])
|
||||
def patch_shot(node_id, 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.
|
||||
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)
|
||||
raise wz_exceptions.NotFound('Node %s not found' % node_id)
|
||||
|
||||
# Set the fields
|
||||
log.info('Patching node %s: %s', node_id, patch)
|
||||
for key, value in patch['$set'].items():
|
||||
node_setattr(node, key, value)
|
||||
op = patch['op']
|
||||
if op in VALID_PATCH_FIELDS:
|
||||
# Set the fields
|
||||
for key, value in patch['$set'].items():
|
||||
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)
|
||||
r, _, _, status = put_internal('nodes', node, _id=node_id)
|
||||
return pillar.api.utils.jsonify(r, status=status)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def assert_is_valid_patch(patch):
|
||||
"""Raises an exception when the patch isn't valid."""
|
||||
|
||||
@@ -248,12 +265,15 @@ def assert_is_valid_patch(patch):
|
||||
except KeyError:
|
||||
raise wz_exceptions.BadRequest("PATCH should have a key 'op' indicating the operation.")
|
||||
|
||||
try:
|
||||
allowed_fields = VALID_PATCH_OPERATIONS[op]
|
||||
except KeyError:
|
||||
valid_ops = u', '.join(VALID_PATCH_OPERATIONS.keys())
|
||||
if op not in VALID_PATCH_OPERATIONS:
|
||||
valid_ops = u', '.join(sorted(VALID_PATCH_OPERATIONS))
|
||||
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:
|
||||
fields = set(patch['$set'].keys())
|
||||
except KeyError:
|
||||
|
@@ -339,6 +339,38 @@ class PatchShotTest(AbstractShotTest):
|
||||
}
|
||||
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):
|
||||
"""
|
||||
|
Reference in New Issue
Block a user