Snippets

ftrack Action - Create notes on multiple entities

Updated by Mattias Lagergren

File README.rst Modified

  • Ignore whitespace
  • Hide word diff
 Available on
 ============
 
-* Projects
-* Tasks (including encapsulating folders)
-* Versions
+* Project
+* Object (Folder, Shot, Task, etc.)
+* Version
 
 Running the action
 ==================
 
+Install the ftrack-action-handler:
+
+.. code::
+
+    pip install git+https://bitbucket.org/ftrack/ftrack-action-handler.git
+
+.. tip::
+
+    You can use `virtualenv <https://virtualenv.pypa.io/en/stable/>`_ or similar
+    solutions to avoid installing packages into your system's Python environment.
+
 Start the listener from the terminal using the following command:
 
 .. code::
 If you wish to see debugging information, set the verbosity level by appending
 ``-v debug`` to the command.
 
-For more information, see the 
-`documentation on using actions <http://ftrack.rtd.ftrack.com/en/latest/using/actions.html>`_.
+Reade more
+==========
+
+For more information in our documentation:
+
+* `Using actions <http://ftrack.rtd.ftrack.com/en/latest/using/actions.html>`_.
+* `Action handler <http://ftrack-action-handler.rtd.ftrack.com/en/latest/index.html>`_.

File note_on_multiple_entities_action.py Modified

  • Ignore whitespace
  • Hide word diff
 # :coding: utf-8
 # :copyright: Copyright (c) 2015 ftrack
-import sys
-import argparse
+
 import logging
 import threading
+import sys
+import argparse
+import json
+
+import ftrack_api
 
-import ftrack
+from ftrack_action_handler.action import BaseAction
 
 
 def async(fn):
     return wrapper
 
 
-class NoteOnMultipleEntitiesAction(ftrack.Action):
+class NoteOnMultipleEntitiesAction(BaseAction):
     '''Action to write note on multiple entities.'''
 
     #: Action identifier.
     label = 'Write notes'
 
     @async
-    def createNotes(self, selection, text, category):
-        entityCount = len(selection)
-        logging.info('Creating notes on {0} entities'.format(entityCount))
+    def create_notes(self, entities, text, category_id, source):
+        '''Create notes on *entities*.'''
 
-        job = ftrack.createJob(
-            'Creating notes ({0} of {1})'.format(1, entityCount), 'running'
+        # Create new session as sessions are not garantueed to be thread-safe.
+        session = ftrack_api.Session(
+            auto_connect_event_hub=False, plugin_paths=[]
         )
+
+        category = session.get('NoteCategory', category_id)
+        user = session.query(
+            'User where username is "{0}"'.format(source['user']['username'])
+        ).one()
+
+        logging.info('Creating notes on {0} entities'.format(len(entities)))
+
+        job = session.create('Job', {
+            'user': user,
+            'status': 'running',
+            'data': json.dumps({
+                'description': 'Creating notes on {0} entities'.format(
+                    len(entities)
+                )
+            })
+        })
+
         try:
-            for index, item in enumerate(selection, start=1):
-                entityType = item['entityType']
-                entityId = item['entityId']
-                entity = None
-
-                if index != 1:
-                    job.setDescription('Creating notes ({0} of {1})'.format(index, entityCount))
-
-                if entityType == 'show':
-                    entity = ftrack.Project(entityId)
-                elif entityType == 'task':
-                    entity = ftrack.Task(entityId)
-                elif entityType == 'assetversion':
-                    entity = ftrack.AssetVersion(entityId)
-
-                if not entity:
-                    logging.warning(
-                        u'Entity ({0}, {1}) not a valid type, skipping..'
-                        .format(entityId, entityType)
-                    )
+            session.commit()
+        except:
+            session.rollback()
+            raise
 
-                entity.createNote(text, category)
+        try:
+            for entity_type, entity_id in entities:
+                entity = session.get(entity_type, entity_id)
+                if category:
+                    entity.create_note(
+                        text, user, category=category
+                    )
+                else:
+                    entity.create_note(text, user)
         except Exception:
-            job.setStatus('failed')
+            session.rollback()
+
+            job['status'] = 'failed'
 
-        logging.info('Note creation completed.')
-        job.setStatus('done')
+            try:
+                session.commit()
+            except:
+                session.rollback()
+            raise
 
-    def launch(self, event):
+        job['status'] = 'done'
+
+        try:
+            session.commit()
+        except:
+            session.rollback()
+            raise
+
+    def discover(self, session, entities, event):
+        '''Return true if the action is discoverable.
+
+        Action is discoverable if all entities have a notes relationship and
+        at least one entity is selected.
+
+        '''
+        return (
+            entities and
+            all([
+                entity_type in session.types and
+                'notes' in session.types[entity_type].attributes.keys()
+                for entity_type, entity_id in entities
+            ])
+        )
+
+    def launch(self, session, entities, event):
         '''Callback method for action.'''
+        self.logger.info(
+            u'Launching action with selection {0}'.format(entities)
+        )
+
         data = event['data']
         logging.info(u'Launching action with data: {0}'.format(data))
 
-        selection = data.get('selection', [])
-        if not selection:
-            return {'success': False}
-
         if 'values' in data:
             text = data['values'].get('note_text')
-            category = data['values'].get('note_category', 'auto')
-            self.createNotes(selection, text, category)
-
-            return {
-                'success': True,
-                'message': 'Started creating notes'
-            }
+            category_id = data['values'].get('note_category')
+            self.create_notes(entities, text, category_id, event['source'])
 
-        options = [
-            {'label': category.getName(), 'value': category.getId()}
-            for category in ftrack.getNoteCategories()
-        ]
-        options.insert(0, {'label': 'Default', 'value': 'auto'})
+        return {
+            'success': True,
+            'message': 'Started creating notes'
+        }
 
+    def interface(self, session, entities, event):
+        '''Return interface.'''
+        values = event['data'].get('values', {})
 
-        return {
-            'items': [
+        if not values:
+            options = [
+                {'label': category['name'], 'value': category['id']}
+                for category in session.query(
+                    'select name, id from NoteCategory'
+                )
+            ]
+            options.insert(0, {'label': 'Default', 'value': 'auto'})
+            return [
                 {
-                    'value': '## Writing note on **{0}** items. ##'.format(len(selection)),
+                    'value': '## Writing note on **{0}** items. ##'.format(
+                        len(entities)
+                    ),
                     'type': 'label'
                 }, {
                     'label': 'Content',
                     'data': options
                 }
             ]
-        }
 
 
-def register(registry, **kw):
-    '''Register action. Called when used as an event plugin.'''
-    logger = logging.getLogger(
-        'note-on-multiple-entities'
-    )
-
-    # Validate that registry is an instance of ftrack.Registry. If not,
-    # assume that register is being called from a new or incompatible API and
+def register(session, **kw):
+    '''Register plugin. Called when used as an plugin.'''
+    # Validate that session is an instance of ftrack_api.Session. If not,
+    # assume that register is being called from an old or incompatible API and
     # return without doing anything.
-    if not isinstance(registry, ftrack.Registry):
-        logger.debug(
-            'Not subscribing plugin as passed argument {0!r} is not an '
-            'ftrack.Registry instance.'.format(registry)
-        )
+    if not isinstance(session, ftrack_api.session.Session):
         return
 
-    action = NoteOnMultipleEntitiesAction()
-    action.register()
+    action_handler = NoteOnMultipleEntitiesAction(session)
+    action_handler.register()
 
 
 def main(arguments=None):
     )
     namespace = parser.parse_args(arguments)
 
-    # Set up basic logging
+    # Set up basic logging.
     logging.basicConfig(level=loggingLevels[namespace.verbosity])
 
-    # Subscribe to action.
-    ftrack.setup()
-    action = NoteOnMultipleEntitiesAction()
-    action.register()
+    session = ftrack_api.Session()
+    register(session)
 
-    # Wait for events
-    ftrack.EVENT_HUB.wait()
+    # Wait for events.
+    logging.info(
+        'Registered actions and listening for events. Use Ctrl-C to abort.'
+    )
+    session.event_hub.wait()
 
 
 if __name__ == '__main__':
Updated by Lucas Correia

File note_on_multiple_entities_action.py Modified

  • Ignore whitespace
  • Hide word diff
         )
         return
 
+    action = NoteOnMultipleEntitiesAction()
+    action.register()
+
 
 def main(arguments=None):
     '''Set up logging and register action.'''
Updated by Lucas Correia

File note_on_multiple_entities_action.py Modified

  • Ignore whitespace
  • Hide word diff
         }
 
 
+def register(registry, **kw):
+    '''Register action. Called when used as an event plugin.'''
+    logger = logging.getLogger(
+        'note-on-multiple-entities'
+    )
+
+    # Validate that registry is an instance of ftrack.Registry. If not,
+    # assume that register is being called from a new or incompatible API and
+    # return without doing anything.
+    if not isinstance(registry, ftrack.Registry):
+        logger.debug(
+            'Not subscribing plugin as passed argument {0!r} is not an '
+            'ftrack.Registry instance.'.format(registry)
+        )
+        return
+
+
 def main(arguments=None):
     '''Set up logging and register action.'''
     if arguments is None:
Updated by Lucas Correia

File note_on_multiple_entities_action.py Modified

  • Ignore whitespace
  • Hide word diff
                 if index != 1:
                     job.setDescription('Creating notes ({0} of {1})'.format(index, entityCount))
 
-                if entityType == ftrack.Project._type:
+                if entityType == 'show':
                     entity = ftrack.Project(entityId)
-                elif entityType == ftrack.Task._type:
+                elif entityType == 'task':
                     entity = ftrack.Task(entityId)
-                elif entityType == ftrack.AssetVersion._type:
+                elif entityType == 'assetversion':
                     entity = ftrack.AssetVersion(entityId)
 
                 if not entity:
Updated by Lucas Correia

File README.rst Modified

  • Ignore whitespace
  • Hide word diff
 Note on multiple entities action
 ********************************
 
+The action *Note on multiple entities* will go through your selection and create
+a note for each of the items.
+
+Using the action
+================
+
+Navigate to a project in the web interface and select a few items in the 
+spreadsheet and select `Actions` from the context menu. Click on `Write notes`
+and add your text and optionally select a note category.
+
+Notes created are copies, and any replies will only show up on one of the notes.
+
+Available on
+============
+
+* Projects
+* Tasks (including encapsulating folders)
+* Versions
+
 Running the action
 ==================
 
 
 For more information, see the 
 `documentation on using actions <http://ftrack.rtd.ftrack.com/en/latest/using/actions.html>`_.
-
-Using the action
-================
-
-Navigate to a project in the web interface and select a few items
-in the spreadsheet and select `Actions` from the context menu. Click 
-on `Write notes` and add your text and optionally select a note
-category.
-
-Notes created are copies, and any replies will only show up on one of the notes.
  1. 1
  2. 2
HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.