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',
|
'type': 'string',
|
||||||
'maxlength': 256,
|
'maxlength': 256,
|
||||||
},
|
},
|
||||||
|
'used_in_edit': {
|
||||||
|
'type': 'boolean',
|
||||||
|
'default': True,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'form_schema': {},
|
'form_schema': {},
|
||||||
'parent': ['scene']
|
'parent': ['scene']
|
||||||
|
@@ -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)
|
||||||
|
|
||||||
# Set the fields
|
op = patch['op']
|
||||||
log.info('Patching node %s: %s', node_id, patch)
|
if op in VALID_PATCH_FIELDS:
|
||||||
for key, value in patch['$set'].items():
|
# Set the fields
|
||||||
node_setattr(node, key, value)
|
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)
|
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:
|
||||||
|
@@ -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):
|
||||||
"""
|
"""
|
||||||
|
Reference in New Issue
Block a user