Introducing Attract assets, with a pretty similar workflow to shots.
This commit is contained in:
@@ -2,6 +2,6 @@ from .act import node_type_act
|
||||
from .scene import node_type_scene
|
||||
from .shot import node_type_shot
|
||||
from .task import node_type_task
|
||||
from .asset import node_type_asset
|
||||
|
||||
NODE_TYPES = (node_type_act, node_type_scene, node_type_shot, node_type_task)
|
||||
|
||||
NODE_TYPES = (node_type_act, node_type_scene, node_type_shot, node_type_task, node_type_asset)
|
||||
|
26
attract/node_types/asset.py
Normal file
26
attract/node_types/asset.py
Normal file
@@ -0,0 +1,26 @@
|
||||
node_type_asset = {
|
||||
'name': 'attract_asset',
|
||||
'description': 'Attract Asset Node Type, for planning asset creation',
|
||||
'dyn_schema': {
|
||||
'status': {
|
||||
'type': 'string',
|
||||
'allowed': [
|
||||
'on_hold',
|
||||
'todo',
|
||||
'in_progress',
|
||||
'review',
|
||||
'final'
|
||||
],
|
||||
'default': 'todo',
|
||||
'required_after_creation': True,
|
||||
},
|
||||
'notes': {
|
||||
'type': 'string',
|
||||
'maxlength': 256,
|
||||
},
|
||||
},
|
||||
'form_schema': {},
|
||||
'parent': ['attract_scene', 'attract_shot']
|
||||
}
|
||||
|
||||
task_types = ['modeling', 'rigging', 'material']
|
@@ -20,7 +20,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_FIELDS = {
|
||||
VALID_SHOT_PATCH_FIELDS = {
|
||||
u'from-blender': {
|
||||
u'name',
|
||||
u'picture',
|
||||
@@ -37,7 +37,7 @@ VALID_PATCH_FIELDS = {
|
||||
},
|
||||
}
|
||||
|
||||
VALID_PATCH_OPERATIONS = {
|
||||
VALID_SHOT_PATCH_OPERATIONS = {
|
||||
u'from-blender', u'from-web', u'unlink', u'relink',
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ def patch_shot(node_id, patch):
|
||||
raise wz_exceptions.NotFound('Node %s not found' % node_id)
|
||||
|
||||
op = patch['op']
|
||||
if op in VALID_PATCH_FIELDS:
|
||||
if op in VALID_SHOT_PATCH_FIELDS:
|
||||
# Set the fields
|
||||
for key, value in patch['$set'].items():
|
||||
node_setattr(node, key, value)
|
||||
@@ -253,15 +253,15 @@ def assert_is_valid_patch(patch):
|
||||
except KeyError:
|
||||
raise wz_exceptions.BadRequest("PATCH should have a key 'op' indicating the operation.")
|
||||
|
||||
if op not in VALID_PATCH_OPERATIONS:
|
||||
valid_ops = u', '.join(sorted(VALID_PATCH_OPERATIONS))
|
||||
if op not in VALID_SHOT_PATCH_OPERATIONS:
|
||||
valid_ops = u', '.join(sorted(VALID_SHOT_PATCH_OPERATIONS))
|
||||
raise wz_exceptions.BadRequest(u'Operation should be one of %s' % valid_ops)
|
||||
|
||||
if op not in VALID_PATCH_FIELDS:
|
||||
if op not in VALID_SHOT_PATCH_FIELDS:
|
||||
# Valid operation, and we don't have to check the fields.
|
||||
return
|
||||
|
||||
allowed_fields = VALID_PATCH_FIELDS[op]
|
||||
allowed_fields = VALID_SHOT_PATCH_FIELDS[op]
|
||||
try:
|
||||
fields = set(patch['$set'].keys())
|
||||
except KeyError:
|
||||
|
@@ -1,9 +1,15 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
"""Hooks for shots & assets.
|
||||
|
||||
These two node types have very similar use, which is why they are covered by the same code.
|
||||
"""
|
||||
|
||||
import itertools
|
||||
import logging
|
||||
|
||||
from attract.node_types.shot import node_type_shot, human_readable_properties
|
||||
from attract.node_types.asset import node_type_asset
|
||||
from pillar.api.nodes import only_for_node_type_decorator
|
||||
import pillar.api.activities
|
||||
import pillar.api.utils.authentication
|
||||
@@ -12,9 +18,16 @@ import pillar.web.jinja
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
only_for_shot = only_for_node_type_decorator(node_type_shot['name'])
|
||||
for_shot_asset = only_for_node_type_decorator(node_type_shot['name'],
|
||||
node_type_asset['name'])
|
||||
|
||||
typenames = {
|
||||
node_type_shot['name']: 'shot',
|
||||
node_type_asset['name']: 'asset',
|
||||
}
|
||||
|
||||
|
||||
def register_shot_activity(shot, descr):
|
||||
def register_shot_asset_activity(shot, descr):
|
||||
user_id = pillar.api.utils.authentication.current_user_id()
|
||||
pillar.api.activities.register_activity(
|
||||
user_id,
|
||||
@@ -26,20 +39,22 @@ def register_shot_activity(shot, descr):
|
||||
)
|
||||
|
||||
|
||||
@only_for_shot
|
||||
def activity_after_replacing_shot(shot, original):
|
||||
@for_shot_asset
|
||||
def activity_after_replacing_shot_asset(shot_or_asset, original):
|
||||
"""
|
||||
Note: this is also used on PATCH, since our custom shot PATCH handler
|
||||
performs a PUT-internal to run the patched node through Eve for
|
||||
validation.
|
||||
"""
|
||||
|
||||
typename = typenames[shot_or_asset['node_type']]
|
||||
|
||||
# Compare to original, and either mention the things that changed,
|
||||
# or (if they are equal) don't log an activity at all.
|
||||
changes = list(itertools.islice(pillar.api.utils.doc_diff(shot, original), 2))
|
||||
changes = list(itertools.islice(pillar.api.utils.doc_diff(shot_or_asset, original), 2))
|
||||
if not changes:
|
||||
log.info('Not registering replacement of shot %s, as it is identical '
|
||||
'in non-private fields.', shot['_id'])
|
||||
log.info('Not registering replacement of %s %s, as it is identical '
|
||||
'in non-private fields.', typename, shot_or_asset['_id'])
|
||||
return
|
||||
|
||||
if len(changes) == 1:
|
||||
@@ -52,31 +67,33 @@ def activity_after_replacing_shot(shot, original):
|
||||
|
||||
# Some key- and value-specific overrides
|
||||
if val_shot is pillar.api.utils.DoesNotExist:
|
||||
descr = 'removed "%s" from shot "%s"' % (human_key, shot['name'])
|
||||
descr = 'removed "%s" from shot "%s"' % (human_key, shot_or_asset['name'])
|
||||
if key == 'picture':
|
||||
descr = 'changed the thumbnail of shot "%s"' % shot['name']
|
||||
descr = 'changed the thumbnail of %s "%s"' % (typename, shot_or_asset['name'])
|
||||
elif key == 'properties.status':
|
||||
val_shot = pillar.web.jinja.format_undertitle(val_shot)
|
||||
elif isinstance(val_shot, basestring) and len(val_shot) > 80:
|
||||
val_shot = val_shot[:80] + u'…'
|
||||
|
||||
if descr is None:
|
||||
descr = 'changed "%s" to "%s" in shot "%s"' %\
|
||||
(human_key, val_shot, shot['name'])
|
||||
descr = 'changed "%s" to "%s" in %s "%s"' % \
|
||||
(human_key, val_shot, typename, shot_or_asset['name'])
|
||||
else:
|
||||
descr = 'edited shot "%s"' % shot['name']
|
||||
descr = 'edited %s "%s"' % (typename, shot_or_asset['name'])
|
||||
|
||||
register_shot_activity(shot, descr)
|
||||
register_shot_asset_activity(shot_or_asset, descr)
|
||||
|
||||
|
||||
@only_for_shot
|
||||
def activity_after_creating_shot(shot):
|
||||
register_shot_activity(shot, 'created a new shot "%s"' % shot['name'])
|
||||
@for_shot_asset
|
||||
def activity_after_creating_shot_asset(shot_or_asset):
|
||||
typename = typenames[shot_or_asset['node_type']]
|
||||
register_shot_asset_activity(shot_or_asset, 'created a new %s "%s"' % (
|
||||
typename, shot_or_asset['name']))
|
||||
|
||||
|
||||
def activity_after_creating_shots(nodes):
|
||||
def activity_after_creating_shots_assets(nodes):
|
||||
for node in nodes:
|
||||
activity_after_creating_shot(node)
|
||||
activity_after_creating_shot_asset(node)
|
||||
|
||||
|
||||
@only_for_shot
|
||||
@@ -90,14 +107,16 @@ def nodes_set_default_used_in_edit(nodes):
|
||||
set_default_used_in_edit(node)
|
||||
|
||||
|
||||
@only_for_shot
|
||||
def activity_after_deleting_shot(shot):
|
||||
register_shot_activity(shot, 'deleted shot "%s"' % shot['name'])
|
||||
@for_shot_asset
|
||||
def activity_after_deleting_shot_asset(shot_or_asset):
|
||||
typename = typenames[shot_or_asset['node_type']]
|
||||
register_shot_asset_activity(shot_or_asset, 'deleted %s "%s"' % (
|
||||
typename, shot_or_asset['name']))
|
||||
|
||||
|
||||
def setup_app(app):
|
||||
app.on_replaced_nodes += activity_after_replacing_shot
|
||||
app.on_replaced_nodes += activity_after_replacing_shot_asset
|
||||
app.on_insert_nodes += nodes_set_default_used_in_edit
|
||||
app.on_inserted_nodes += activity_after_creating_shots
|
||||
app.on_deleted_item_nodes += activity_after_deleting_shot
|
||||
app.on_deleted_resource_nodes += activity_after_deleting_shot
|
||||
app.on_inserted_nodes += activity_after_creating_shots_assets
|
||||
app.on_deleted_item_nodes += activity_after_deleting_shot_asset
|
||||
app.on_deleted_resource_nodes += activity_after_deleting_shot_asset
|
||||
|
Reference in New Issue
Block a user