diff --git a/pype/ftrack/actions/action_application_loader.py b/pype/ftrack/actions/action_application_loader.py index 50714e4535..67a158db14 100644 --- a/pype/ftrack/actions/action_application_loader.py +++ b/pype/ftrack/actions/action_application_loader.py @@ -35,10 +35,12 @@ def registerApp(app, session): label = apptoml.get('ftrack_label', app.get('label', name)) icon = apptoml.get('ftrack_icon', None) description = apptoml.get('description', None) + preactions = apptoml.get('preactions', []) # register action AppAction( - session, label, name, executable, variant, icon, description + session, label, name, executable, variant, + icon, description, preactions ).register() diff --git a/pype/ftrack/actions/action_start_timer.py b/pype/ftrack/actions/action_start_timer.py new file mode 100644 index 0000000000..d1f4aa3d09 --- /dev/null +++ b/pype/ftrack/actions/action_start_timer.py @@ -0,0 +1,79 @@ +import ftrack_api +from pype.ftrack import BaseAction + + +class StartTimer(BaseAction): + '''Starts timer.''' + + identifier = 'start.timer' + label = 'Start timer' + description = 'Starts timer' + + def discover(self, session, entities, event): + return False + + def _handle_result(*arg): + return + + def launch(self, session, entities, event): + entity = entities[0] + if entity.entity_type.lower() != 'task': + return + self.start_ftrack_timer(entity) + try: + self.start_clockify_timer(entity) + except Exception: + self.log.warning( + 'Failed starting Clockify timer for task: ' + entity['name'] + ) + return + + def start_ftrack_timer(self, task): + user_query = 'User where username is "{}"'.format(self.session.api_user) + user = self.session.query(user_query).one() + self.log.info('Starting Ftrack timer for task: ' + task['name']) + user.start_timer(task, force=True) + self.session.commit() + + def start_clockify_timer(self, task): + # Validate Clockify settings if Clockify is required + clockify_timer = os.environ.get('CLOCKIFY_WORKSPACE', None) + if clockify_timer is None: + return + + from pype.clockify import ClockifyAPI + clockapi = ClockifyAPI() + if clockapi.verify_api() is False: + return + task_type = task['type']['name'] + project_name = task['project']['full_name'] + + def get_parents(entity): + output = [] + if entity.entity_type.lower() == 'project': + return output + output.extend(get_parents(entity['parent'])) + output.append(entity['name']) + + return output + + desc_items = get_parents(task['parent']) + desc_items.append(task['name']) + description = '/'.join(desc_items) + + project_id = clockapi.get_project_id(project_name) + tag_ids = [] + tag_ids.append(clockapi.get_tag_id(task_type)) + clockapi.start_time_entry( + description, project_id, tag_ids=tag_ids + ) + self.log.info('Starting Clockify timer for task: ' + task['name']) + + +def register(session, **kw): + '''Register plugin. Called when used as an plugin.''' + + if not isinstance(session, ftrack_api.session.Session): + return + + StartTimer(session).register() diff --git a/pype/ftrack/lib/ftrack_action_handler.py b/pype/ftrack/lib/ftrack_action_handler.py index c6d6181c1f..7a25155718 100644 --- a/pype/ftrack/lib/ftrack_action_handler.py +++ b/pype/ftrack/lib/ftrack_action_handler.py @@ -66,6 +66,10 @@ class BaseAction(BaseHandler): self.session, event ) + preactions_launched = self._handle_preactions(self.session, event) + if preactions_launched is False: + return + interface = self._interface( self.session, *args ) diff --git a/pype/ftrack/lib/ftrack_app_handler.py b/pype/ftrack/lib/ftrack_app_handler.py index e4075e9a19..3c2bc418a8 100644 --- a/pype/ftrack/lib/ftrack_app_handler.py +++ b/pype/ftrack/lib/ftrack_app_handler.py @@ -23,10 +23,11 @@ class AppAction(BaseHandler): ''' type = 'Application' + preactions = ['start.timer'] def __init__( self, session, label, name, executable, - variant=None, icon=None, description=None + variant=None, icon=None, description=None, preactions=[] ): super().__init__(session) '''Expects a ftrack_api.Session instance''' @@ -44,6 +45,7 @@ class AppAction(BaseHandler): self.variant = variant self.icon = icon self.description = description + self.preactions.extend(preactions) def register(self): '''Registers the action, subscribing the discover and launch topics.''' @@ -117,6 +119,12 @@ class AppAction(BaseHandler): self.session, event ) + preactions_launched = self._handle_preactions( + self.session, event + ) + if preactions_launched is False: + return + response = self.launch( self.session, *args ) @@ -148,25 +156,6 @@ class AppAction(BaseHandler): entity = entities[0] project_name = entity['project']['full_name'] - # Validate Clockify settings if Clockify is required - clockify_timer = os.environ.get('CLOCKIFY_WORKSPACE', None) - if clockify_timer is not None: - from pype.clockify import ClockifyAPI - clockapi = ClockifyAPI() - if clockapi.verify_api() is False: - title = 'Launch message' - header = '# You Can\'t launch **any Application**' - message = ( - '
You don\'t have set Clockify API' - ' key in Clockify settings
' - ) - items = [ - {'type': 'label', 'value': header}, - {'type': 'label', 'value': message} - ] - self.show_interface(event, items, title) - return False - database = pypelib.get_avalon_database() # Get current environments @@ -335,39 +324,6 @@ class AppAction(BaseHandler): } pass - # RUN TIMER IN FTRACK - username = event['source']['user']['username'] - user_query = 'User where username is "{}"'.format(username) - user = session.query(user_query).one() - task = session.query('Task where id is {}'.format(entity['id'])).one() - self.log.info('Starting timer for task: ' + task['name']) - user.start_timer(task, force=True) - - # RUN TIMER IN Clockify - if clockify_timer is not None: - task_type = task['type']['name'] - project_name = task['project']['full_name'] - - def get_parents(entity): - output = [] - if entity.entity_type.lower() == 'project': - return output - output.extend(get_parents(entity['parent'])) - output.append(entity['name']) - - return output - - desc_items = get_parents(task['parent']) - desc_items.append(task['name']) - description = '/'.join(desc_items) - - project_id = clockapi.get_project_id(project_name) - tag_ids = [] - tag_ids.append(clockapi.get_tag_id(task_type)) - clockapi.start_time_entry( - description, project_id, tag_ids=tag_ids - ) - # Change status of task to In progress config = get_config_data() diff --git a/pype/ftrack/lib/ftrack_base_handler.py b/pype/ftrack/lib/ftrack_base_handler.py index 7a04ba329c..aaaf6a12aa 100644 --- a/pype/ftrack/lib/ftrack_base_handler.py +++ b/pype/ftrack/lib/ftrack_base_handler.py @@ -25,6 +25,7 @@ class BaseHandler(object): priority = 100 # Type is just for logging purpose (e.g.: Action, Event, Application,...) type = 'No-type' + preactions = [] def __init__(self, session): '''Expects a ftrack_api.Session instance''' @@ -46,18 +47,7 @@ class BaseHandler(object): else: label = '{} {}'.format(self.label, self.variant) try: - if hasattr(self, "role_list") and len(self.role_list) > 0: - username = self.session.api_user - user = self.session.query( - 'User where username is "{}"'.format(username) - ).one() - available = False - for role in user['user_security_roles']: - if role['security_role']['name'] in self.role_list: - available = True - break - if available is False: - raise MissingPermision + self._preregister() start_time = time.perf_counter() func(*args, **kwargs) @@ -119,6 +109,35 @@ class BaseHandler(object): def reset_session(self): self.session.reset() + if hasattr(self, "role_list") and len(self.role_list) > 0: + username = self.session.api_user + user = self.session.query( + 'User where username is "{}"'.format(username) + ).one() + available = False + for role in user['user_security_roles']: + if role['security_role']['name'] in self.role_list: + available = True + break + if available is False: + raise MissingPermision + + # Custom validations + result = self.preregister() + if result is True: + return + msg = "Pre-register conditions were not met" + if isinstance(result, str): + msg = result + raise Exception(msg) + + def preregister(self): + ''' + Preregister conditions. + Registration continues if returns True. + ''' + return True + def register(self): ''' Registers the action, subscribing the discover and launch topics. @@ -227,6 +246,10 @@ class BaseHandler(object): self.session, event ) + preactions_launched = self._handle_preactions(self.session, event) + if preactions_launched is False: + return + interface = self._interface( self.session, *args ) @@ -263,6 +286,47 @@ class BaseHandler(object): ''' raise NotImplementedError() + def _handle_preactions(self, session, event): + # If preactions are not set + if len(self.preactions) == 0: + return True + # If no selection + selection = event.get('data', {}).get('selection', None) + if (selection is None): + return False + # If preactions were already started + if event['data'].get('preactions_launched', None) is True: + return True + + # Launch preactions + for preaction in self.preactions: + event = ftrack_api.event.base.Event( + topic='ftrack.action.launch', + data=dict( + actionIdentifier=preaction, + selection=selection + ), + source=dict( + user=dict(username=session.api_user) + ) + ) + session.event_hub.publish(event, on_error='ignore') + # Relaunch this action + event = ftrack_api.event.base.Event( + topic='ftrack.action.launch', + data=dict( + actionIdentifier=self.identifier, + selection=selection, + preactions_launched=True + ), + source=dict( + user=dict(username=session.api_user) + ) + ) + session.event_hub.publish(event, on_error='ignore') + + return False + def _interface(self, *args): interface = self.interface(*args) if interface: