mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-25 21:32:15 +01:00
329 lines
10 KiB
Python
329 lines
10 KiB
Python
import os
|
|
import json
|
|
import threading
|
|
import time
|
|
from Qt import QtCore, QtGui, QtWidgets
|
|
|
|
from pype.vendor import ftrack_api
|
|
from pypeapp import style
|
|
from pype.ftrack import FtrackServer, credentials, login_dialog as login_dialog
|
|
|
|
from pype import api as pype
|
|
|
|
|
|
log = pype.Logger().get_logger("FtrackModule", "ftrack")
|
|
|
|
|
|
class FtrackModule:
|
|
def __init__(self, main_parent=None, parent=None):
|
|
|
|
self.parent = parent
|
|
self.widget_login = login_dialog.Login_Dialog_ui(self)
|
|
self.action_server = FtrackServer('action')
|
|
self.thread_action_server = None
|
|
self.thread_timer = None
|
|
|
|
self.bool_logged = False
|
|
self.bool_action_server = False
|
|
self.bool_timer_event = False
|
|
|
|
def show_login_widget(self):
|
|
self.widget_login.show()
|
|
|
|
def validate(self):
|
|
validation = False
|
|
cred = credentials._get_credentials()
|
|
try:
|
|
if 'username' in cred and 'apiKey' in cred:
|
|
validation = credentials._check_credentials(
|
|
cred['username'],
|
|
cred['apiKey']
|
|
)
|
|
if validation is False:
|
|
self.show_login_widget()
|
|
else:
|
|
self.show_login_widget()
|
|
|
|
except Exception as e:
|
|
log.error("We are unable to connect to Ftrack: {0}".format(e))
|
|
|
|
validation = credentials._check_credentials()
|
|
if validation is True:
|
|
log.info("Connected to Ftrack successfully")
|
|
self.loginChange()
|
|
else:
|
|
log.warning("Please sign in to Ftrack")
|
|
self.bool_logged = False
|
|
self.set_menu_visibility()
|
|
|
|
return validation
|
|
|
|
# Necessary - login_dialog works with this method after logging in
|
|
def loginChange(self):
|
|
self.bool_logged = True
|
|
self.set_menu_visibility()
|
|
self.start_action_server()
|
|
|
|
def logout(self):
|
|
credentials._clear_credentials()
|
|
self.stop_action_server()
|
|
|
|
log.info("Logged out of Ftrack")
|
|
self.bool_logged = False
|
|
self.set_menu_visibility()
|
|
|
|
# Actions part
|
|
def start_action_server(self):
|
|
if self.thread_action_server is None:
|
|
self.thread_action_server = threading.Thread(
|
|
target=self.set_action_server
|
|
)
|
|
self.thread_action_server.daemon = True
|
|
self.thread_action_server.start()
|
|
|
|
log.info("Ftrack action server launched")
|
|
self.bool_action_server = True
|
|
self.set_menu_visibility()
|
|
|
|
def set_action_server(self):
|
|
try:
|
|
self.action_server.run_server()
|
|
except Exception:
|
|
msg = 'Ftrack Action server crashed! Please try to start again.'
|
|
log.error(msg)
|
|
# TODO show message to user
|
|
self.bool_action_server = False
|
|
self.set_menu_visibility()
|
|
|
|
def reset_action_server(self):
|
|
self.stop_action_server()
|
|
self.start_action_server()
|
|
|
|
def stop_action_server(self):
|
|
try:
|
|
self.action_server.stop_session()
|
|
if self.thread_action_server is not None:
|
|
self.thread_action_server.join()
|
|
self.thread_action_server = None
|
|
|
|
log.info("Ftrack action server stopped")
|
|
self.bool_action_server = False
|
|
self.set_menu_visibility()
|
|
except Exception as e:
|
|
log.error("During Killing action server: {0}".format(e))
|
|
|
|
# Definition of Tray menu
|
|
def tray_menu(self, parent_menu):
|
|
# Menu for Tray App
|
|
self.menu = QtWidgets.QMenu('Ftrack', parent_menu)
|
|
self.menu.setProperty('submenu', 'on')
|
|
|
|
# Actions - server
|
|
self.smActionS = self.menu.addMenu("Action server")
|
|
|
|
self.aRunActionS = QtWidgets.QAction(
|
|
"Run action server", self.smActionS
|
|
)
|
|
self.aResetActionS = QtWidgets.QAction(
|
|
"Reset action server", self.smActionS
|
|
)
|
|
self.aStopActionS = QtWidgets.QAction(
|
|
"Stop action server", self.smActionS
|
|
)
|
|
|
|
self.aRunActionS.triggered.connect(self.start_action_server)
|
|
self.aResetActionS.triggered.connect(self.reset_action_server)
|
|
self.aStopActionS.triggered.connect(self.stop_action_server)
|
|
|
|
self.smActionS.addAction(self.aRunActionS)
|
|
self.smActionS.addAction(self.aResetActionS)
|
|
self.smActionS.addAction(self.aStopActionS)
|
|
|
|
# Actions - basic
|
|
self.aLogin = QtWidgets.QAction("Login", self.menu)
|
|
self.aLogin.triggered.connect(self.validate)
|
|
self.aLogout = QtWidgets.QAction("Logout", self.menu)
|
|
self.aLogout.triggered.connect(self.logout)
|
|
|
|
self.menu.addAction(self.aLogin)
|
|
self.menu.addAction(self.aLogout)
|
|
|
|
self.bool_logged = False
|
|
self.set_menu_visibility()
|
|
|
|
parent_menu.addMenu(self.menu)
|
|
|
|
def tray_start(self):
|
|
self.validate()
|
|
|
|
# Definition of visibility of each menu actions
|
|
def set_menu_visibility(self):
|
|
|
|
self.smActionS.menuAction().setVisible(self.bool_logged)
|
|
self.aLogin.setVisible(not self.bool_logged)
|
|
self.aLogout.setVisible(self.bool_logged)
|
|
|
|
if self.bool_logged is False:
|
|
if self.bool_timer_event is True:
|
|
self.stop_timer_thread()
|
|
return
|
|
|
|
self.aRunActionS.setVisible(not self.bool_action_server)
|
|
self.aResetActionS.setVisible(self.bool_action_server)
|
|
self.aStopActionS.setVisible(self.bool_action_server)
|
|
|
|
if self.bool_timer_event is False:
|
|
self.start_timer_thread()
|
|
|
|
def start_timer_thread(self):
|
|
try:
|
|
if self.thread_timer is None:
|
|
self.thread_timer = FtrackEventsThread(self)
|
|
self.bool_timer_event = True
|
|
self.thread_timer.signal_timer_started.connect(
|
|
self.timer_started
|
|
)
|
|
self.thread_timer.signal_timer_stopped.connect(
|
|
self.timer_stopped
|
|
)
|
|
self.thread_timer.start()
|
|
except Exception:
|
|
pass
|
|
|
|
def stop_timer_thread(self):
|
|
try:
|
|
if self.thread_timer is not None:
|
|
self.thread_timer.terminate()
|
|
self.thread_timer.wait()
|
|
self.thread_timer = None
|
|
|
|
except Exception as e:
|
|
log.error("During Killing Timer event server: {0}".format(e))
|
|
|
|
def process_modules(self, modules):
|
|
if 'TimersManager' in modules:
|
|
self.timer_manager = modules['TimersManager']
|
|
self.timer_manager.add_module(self)
|
|
|
|
def start_timer_manager(self, data):
|
|
if self.thread_timer is not None:
|
|
self.thread_timer.ftrack_start_timer(data)
|
|
|
|
def stop_timer_manager(self):
|
|
if self.thread_timer is not None:
|
|
self.thread_timer.ftrack_stop_timer()
|
|
|
|
def timer_started(self, data):
|
|
if hasattr(self, 'timer_manager'):
|
|
self.timer_manager.start_timers(data)
|
|
|
|
def timer_stopped(self):
|
|
if hasattr(self, 'timer_manager'):
|
|
self.timer_manager.stop_timers()
|
|
|
|
|
|
class FtrackEventsThread(QtCore.QThread):
|
|
# Senders
|
|
signal_timer_started = QtCore.Signal(object)
|
|
signal_timer_stopped = QtCore.Signal()
|
|
|
|
def __init__(self, parent):
|
|
super(FtrackEventsThread, self).__init__()
|
|
cred = credentials._get_credentials()
|
|
self.username = cred['username']
|
|
self.user = None
|
|
self.last_task = None
|
|
|
|
def run(self):
|
|
self.timer_session = ftrack_api.Session(auto_connect_event_hub=True)
|
|
self.timer_session.event_hub.subscribe(
|
|
'topic=ftrack.update and source.user.username={}'.format(
|
|
self.username
|
|
),
|
|
self.event_handler)
|
|
|
|
user_query = 'User where username is "{}"'.format(self.username)
|
|
self.user = self.timer_session.query(user_query).one()
|
|
|
|
timer_query = 'Timer where user.username is "{}"'.format(self.username)
|
|
timer = self.timer_session.query(timer_query).first()
|
|
if timer is not None:
|
|
self.last_task = timer['context']
|
|
self.signal_timer_started.emit(
|
|
self.get_data_from_task(self.last_task)
|
|
)
|
|
|
|
self.timer_session.event_hub.wait()
|
|
|
|
def get_data_from_task(self, task_entity):
|
|
data = {}
|
|
data['task_name'] = task_entity['name']
|
|
data['task_type'] = task_entity['type']['name']
|
|
data['project_name'] = task_entity['project']['full_name']
|
|
data['hierarchy'] = self.get_parents(task_entity['parent'])
|
|
|
|
return data
|
|
|
|
def get_parents(self, entity):
|
|
output = []
|
|
if entity.entity_type.lower() == 'project':
|
|
return output
|
|
output.extend(self.get_parents(entity['parent']))
|
|
output.append(entity['name'])
|
|
|
|
return output
|
|
|
|
def event_handler(self, event):
|
|
try:
|
|
if event['data']['entities'][0]['objectTypeId'] != 'timer':
|
|
return
|
|
except Exception:
|
|
return
|
|
|
|
new = event['data']['entities'][0]['changes']['start']['new']
|
|
old = event['data']['entities'][0]['changes']['start']['old']
|
|
|
|
if old is None and new is None:
|
|
return
|
|
|
|
timer_query = 'Timer where user.username is "{}"'.format(self.username)
|
|
timer = self.timer_session.query(timer_query).first()
|
|
if timer is not None:
|
|
self.last_task = timer['context']
|
|
|
|
if old is None:
|
|
self.signal_timer_started.emit(
|
|
self.get_data_from_task(self.last_task)
|
|
)
|
|
elif new is None:
|
|
self.signal_timer_stopped.emit()
|
|
|
|
def ftrack_stop_timer(self):
|
|
try:
|
|
self.user.stop_timer()
|
|
self.timer_session.commit()
|
|
self.signal_timer_stopped.emit()
|
|
except Exception as e:
|
|
log.debug("Timer stop had issues: {}".format(e))
|
|
|
|
def ftrack_start_timer(self, input_data):
|
|
if self.user is None:
|
|
return
|
|
if (
|
|
input_data['task_name'] == self.last_task['name'] and
|
|
input_data['hierarchy'][-1] == self.last_task['parent']['name']
|
|
):
|
|
return
|
|
task_query = (
|
|
'Task where name is "{task_name}"'
|
|
' and parent.name is "{entity_name}"'
|
|
' and project.full_name is "{project_name}"'
|
|
).format(**input_data)
|
|
|
|
task = self.timer_session.query(task_query).one()
|
|
self.last_task = task
|
|
self.user.start_timer(task)
|
|
self.timer_session.commit()
|
|
self.signal_timer_started.emit(
|
|
self.get_data_from_task(self.last_task)
|
|
)
|