mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Merged in feature/pype-223_more_ftrack_cleanup (pull request #87)
Feature/PYPE-223 more ftrack cleanup Approved-by: Milan Kolar <milan@orbi.tools>
This commit is contained in:
commit
e04f2033dd
28 changed files with 500 additions and 179 deletions
|
|
@ -1 +1,2 @@
|
|||
from .lib import *
|
||||
from .ftrack_server import *
|
||||
|
|
|
|||
|
|
@ -87,8 +87,7 @@ def register(session, **kw):
|
|||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
action_handler = AssetDelete(session)
|
||||
action_handler.register()
|
||||
AssetDelete(session).register()
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
|
|
|
|||
|
|
@ -111,6 +111,13 @@ class CustomAttributes(BaseAction):
|
|||
label = 'Create/Update Avalon Attributes'
|
||||
#: Action description.
|
||||
description = 'Creates Avalon/Mongo ID for double check'
|
||||
#: roles that are allowed to register this action
|
||||
role_list = ['Pypeclub', 'Administrator']
|
||||
icon = (
|
||||
'https://cdn4.iconfinder.com/data/icons/'
|
||||
'ios-web-user-interface-multi-circle-flat-vol-4/512/'
|
||||
'Bullet_list_menu_lines_points_items_options-512.png'
|
||||
)
|
||||
|
||||
def __init__(self, session):
|
||||
super().__init__(session)
|
||||
|
|
@ -576,23 +583,7 @@ def register(session, **kw):
|
|||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
roleList = ['Pypeclub', 'Administrator']
|
||||
|
||||
username = session.api_user
|
||||
user = session.query('User where username is "{}"'.format(username)).one()
|
||||
available = False
|
||||
for role in user['user_security_roles']:
|
||||
if role['security_role']['name'] in roleList:
|
||||
available = True
|
||||
break
|
||||
if available is True:
|
||||
CustomAttributes(session).register()
|
||||
else:
|
||||
logging.info(
|
||||
"!!! You're missing required permissions for action {}".format(
|
||||
CustomAttributes.__name__
|
||||
)
|
||||
)
|
||||
CustomAttributes(session).register()
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
|
|
|
|||
|
|
@ -13,10 +13,16 @@ class DeleteAsset(BaseAction):
|
|||
#: Action identifier.
|
||||
identifier = 'delete.asset'
|
||||
#: Action label.
|
||||
label = 'Delete asset/subsets'
|
||||
label = 'Delete Asset/Subsets'
|
||||
#: Action description.
|
||||
description = 'Removes from Avalon with all childs and asset from Ftrack'
|
||||
icon = "https://www.iconsdb.com/icons/preview/white/full-trash-xxl.png"
|
||||
icon = (
|
||||
'https://cdn4.iconfinder.com/data/icons/'
|
||||
'ios-web-user-interface-multi-circle-flat-vol-5/512/'
|
||||
'Delete_dustbin_empty_recycle_recycling_remove_trash-512.png'
|
||||
)
|
||||
#: roles that are allowed to register this action
|
||||
role_list = ['Pypeclub', 'Administrator']
|
||||
#: Db
|
||||
db = DbConnector()
|
||||
|
||||
|
|
@ -171,7 +177,7 @@ class DeleteAsset(BaseAction):
|
|||
)
|
||||
else:
|
||||
title = title.format(
|
||||
'{} subset'.format(len_subsets)
|
||||
'{} subsets'.format(len_subsets)
|
||||
)
|
||||
|
||||
self.values = values
|
||||
|
|
@ -310,23 +316,7 @@ def register(session, **kw):
|
|||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
roleList = ['Pypeclub', 'Administrator']
|
||||
|
||||
username = session.api_user
|
||||
user = session.query('User where username is "{}"'.format(username)).one()
|
||||
available = False
|
||||
for role in user['user_security_roles']:
|
||||
if role['security_role']['name'] in roleList:
|
||||
available = True
|
||||
break
|
||||
if available is True:
|
||||
DeleteAsset(session).register()
|
||||
else:
|
||||
logging.info(
|
||||
"!!! You're missing required permissions for action {}".format(
|
||||
DeleteAsset.__name__
|
||||
)
|
||||
)
|
||||
DeleteAsset(session).register()
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
|
|
|
|||
|
|
@ -15,6 +15,13 @@ class AssetsRemover(BaseAction):
|
|||
label = 'Delete Assets by Name'
|
||||
#: Action description.
|
||||
description = 'Removes assets from Ftrack and Avalon db with all childs'
|
||||
#: roles that are allowed to register this action
|
||||
role_list = ['Pypeclub', 'Administrator']
|
||||
icon = (
|
||||
'https://cdn4.iconfinder.com/data/icons/'
|
||||
'ios-web-user-interface-multi-circle-flat-vol-5/512/'
|
||||
'Clipboard_copy_delete_minus_paste_remove-512.png'
|
||||
)
|
||||
#: Db
|
||||
db = DbConnector()
|
||||
|
||||
|
|
@ -135,23 +142,7 @@ def register(session, **kw):
|
|||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
roleList = ['Pypeclub', 'Administrator']
|
||||
|
||||
username = session.api_user
|
||||
user = session.query('User where username is "{}"'.format(username)).one()
|
||||
available = False
|
||||
for role in user['user_security_roles']:
|
||||
if role['security_role']['name'] in roleList:
|
||||
available = True
|
||||
break
|
||||
if available is True:
|
||||
AssetsRemover(session).register()
|
||||
else:
|
||||
logging.info(
|
||||
"!!! You're missing required permissions for action {}".format(
|
||||
AssetsRemover.__name__
|
||||
)
|
||||
)
|
||||
AssetsRemover(session).register()
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
|
|
|
|||
|
|
@ -51,8 +51,7 @@ def register(session, **kw):
|
|||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
action_handler = VersionsCleanup(session)
|
||||
action_handler.register()
|
||||
VersionsCleanup(session).register()
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
|
|
|
|||
|
|
@ -17,7 +17,12 @@ class JobKiller(BaseAction):
|
|||
label = 'Job Killer'
|
||||
#: Action description.
|
||||
description = 'Killing all running jobs younger than day'
|
||||
|
||||
#: roles that are allowed to register this action
|
||||
role_list = ['Pypeclub', 'Administrator']
|
||||
icon = (
|
||||
'https://cdn2.iconfinder.com/data/icons/new-year-resolutions/64/'
|
||||
'resolutions-23-512.png'
|
||||
)
|
||||
def prediscover(self, event):
|
||||
''' Validation '''
|
||||
|
||||
|
|
@ -103,23 +108,8 @@ def register(session, **kw):
|
|||
# return without doing anything.
|
||||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
roleList = ['Pypeclub', 'Administrator']
|
||||
|
||||
username = session.api_user
|
||||
user = session.query('User where username is "{}"'.format(username)).one()
|
||||
available = False
|
||||
for role in user['user_security_roles']:
|
||||
if role['security_role']['name'] in roleList:
|
||||
available = True
|
||||
break
|
||||
if available is True:
|
||||
JobKiller(session).register()
|
||||
else:
|
||||
logging.info(
|
||||
"!!! You're missing required permissions for action {}".format(
|
||||
JobKiller.__name__
|
||||
)
|
||||
)
|
||||
JobKiller(session).register()
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
|
|
|
|||
|
|
@ -80,8 +80,7 @@ def register(session, **kw):
|
|||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
action_handler = SetVersion(session)
|
||||
action_handler.register()
|
||||
SetVersion(session).register()
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ class SyncToAvalon(BaseAction):
|
|||
'https://cdn1.iconfinder.com/data/icons/hawcons/32/'
|
||||
'699650-icon-92-inbox-download-512.png'
|
||||
)
|
||||
#: roles that are allowed to register this action
|
||||
role_list = ['Pypeclub']
|
||||
#: Action priority
|
||||
priority = 200
|
||||
|
||||
|
|
@ -223,23 +225,8 @@ def register(session, **kw):
|
|||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
roleList = ['Pypeclub']
|
||||
SyncToAvalon(session).register()
|
||||
|
||||
username = session.api_user
|
||||
user = session.query('User where username is "{}"'.format(username)).one()
|
||||
available = False
|
||||
for role in user['user_security_roles']:
|
||||
if role['security_role']['name'] in roleList:
|
||||
available = True
|
||||
break
|
||||
if available is True:
|
||||
SyncToAvalon(session).register()
|
||||
else:
|
||||
logging.info(
|
||||
"!!! You're missing required permissions for action {}".format(
|
||||
SyncToAvalon.__name__
|
||||
)
|
||||
)
|
||||
|
||||
def main(arguments=None):
|
||||
'''Set up logging and register action.'''
|
||||
|
|
|
|||
|
|
@ -25,8 +25,13 @@ class TestAction(BaseAction):
|
|||
description = 'Test action'
|
||||
#: priority
|
||||
priority = 10000
|
||||
|
||||
def prediscover(self, session, entities, event):
|
||||
#: roles that are allowed to register this action
|
||||
role_list = ['Pypecub']
|
||||
icon = (
|
||||
'https://cdn4.iconfinder.com/data/icons/hospital-19/512/'
|
||||
'8_hospital-512.png'
|
||||
)
|
||||
def prediscover(self, event):
|
||||
''' Validation '''
|
||||
|
||||
return True
|
||||
|
|
@ -43,23 +48,7 @@ def register(session, **kw):
|
|||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
roleList = ['Pypeclub']
|
||||
|
||||
username = session.api_user
|
||||
user = session.query('User where username is "{}"'.format(username)).one()
|
||||
available = False
|
||||
for role in user['user_security_roles']:
|
||||
if role['security_role']['name'] in roleList:
|
||||
available = True
|
||||
break
|
||||
if available is True:
|
||||
TestAction(session).register()
|
||||
else:
|
||||
logging.info(
|
||||
"!!! You're missing required permissions for action {}".format(
|
||||
TestAction.__name__
|
||||
)
|
||||
)
|
||||
TestAction(session).register()
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
|
|
|
|||
|
|
@ -69,8 +69,7 @@ def register(session, **kw):
|
|||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
action_handler = ThumbToChildren(session)
|
||||
action_handler.register()
|
||||
ThumbToChildren(session).register()
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
|
|
|
|||
|
|
@ -91,8 +91,7 @@ def register(session, **kw):
|
|||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
action_handler = ThumbToParent(session)
|
||||
action_handler.register()
|
||||
ThumbToParent(session).register()
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
|
|
|
|||
70
pype/ftrack/actions/event_collect_entities.py
Normal file
70
pype/ftrack/actions/event_collect_entities.py
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
import ftrack_api
|
||||
from pype.ftrack import BaseEvent
|
||||
|
||||
|
||||
class CollectEntities(BaseEvent):
|
||||
|
||||
priority = 1
|
||||
|
||||
def _launch(self, event):
|
||||
entities, entity_types = self.translate_event(event)
|
||||
entities_count = len(entities)
|
||||
event['data']['entities'] = entities
|
||||
event['data']['entity_types'] = entity_types
|
||||
event['data']['entities_count'] = entities_count
|
||||
|
||||
return True
|
||||
|
||||
def translate_event(self, event):
|
||||
selection = event['data'].get('selection', [])
|
||||
|
||||
entities = list()
|
||||
entity_types = set()
|
||||
for entity in selection:
|
||||
ent = self.session.get(
|
||||
self.get_entity_type(entity),
|
||||
entity.get('entityId')
|
||||
)
|
||||
entities.append(ent)
|
||||
entity_types.add(ent.entity_type)
|
||||
|
||||
return [entities, entity_types]
|
||||
|
||||
def get_entity_type(self, entity):
|
||||
'''Return translated entity type tht can be used with API.'''
|
||||
# Get entity type and make sure it is lower cased. Most places except
|
||||
# the component tab in the Sidebar will use lower case notation.
|
||||
entity_type = entity.get('entityType').replace('_', '').lower()
|
||||
|
||||
for schema in self.session.schemas:
|
||||
alias_for = schema.get('alias_for')
|
||||
|
||||
if (
|
||||
alias_for and isinstance(alias_for, str) and
|
||||
alias_for.lower() == entity_type
|
||||
):
|
||||
return schema['id']
|
||||
|
||||
for schema in self.session.schemas:
|
||||
if schema['id'].lower() == entity_type:
|
||||
return schema['id']
|
||||
|
||||
raise ValueError(
|
||||
'Unable to translate entity type: {0}.'.format(entity_type)
|
||||
)
|
||||
|
||||
def register(self):
|
||||
self.session.event_hub.subscribe(
|
||||
'topic=ftrack.action.discover'
|
||||
' and source.user.username={0}'.format(self.session.api_user),
|
||||
self._launch,
|
||||
priority=self.priority
|
||||
)
|
||||
|
||||
|
||||
def register(session, **kw):
|
||||
'''Register plugin. Called when used as an plugin.'''
|
||||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
CollectEntities(session).register()
|
||||
|
|
@ -1,54 +1,65 @@
|
|||
import os
|
||||
import toml
|
||||
|
||||
import json
|
||||
import ftrack_api
|
||||
import appdirs
|
||||
|
||||
|
||||
config_path = os.path.normpath(appdirs.user_data_dir('pype-app', 'pype'))
|
||||
config_name = 'ftrack_cred.toml'
|
||||
fpath = os.path.join(config_path, config_name)
|
||||
folder = os.path.dirname(fpath)
|
||||
|
||||
if not os.path.isdir(folder):
|
||||
os.makedirs(folder)
|
||||
|
||||
|
||||
def _get_credentials():
|
||||
|
||||
folder = os.path.dirname(fpath)
|
||||
action_file_name = 'ftrack_cred.json'
|
||||
event_file_name = 'ftrack_event_cred.json'
|
||||
action_fpath = os.path.join(config_path, action_file_name)
|
||||
event_fpath = os.path.join(config_path, event_file_name)
|
||||
folders = set([os.path.dirname(action_fpath), os.path.dirname(event_fpath)])
|
||||
|
||||
for folder in folders:
|
||||
if not os.path.isdir(folder):
|
||||
os.makedirs(folder)
|
||||
|
||||
|
||||
def _get_credentials(event=False):
|
||||
if event:
|
||||
fpath = event_fpath
|
||||
else:
|
||||
fpath = action_fpath
|
||||
|
||||
credentials = {}
|
||||
try:
|
||||
file = open(fpath, 'r')
|
||||
credentials = json.load(file)
|
||||
except Exception:
|
||||
filecreate = open(fpath, 'w')
|
||||
filecreate.close()
|
||||
file = open(fpath, 'r')
|
||||
file = open(fpath, 'w')
|
||||
|
||||
credentials = toml.load(file)
|
||||
file.close()
|
||||
|
||||
return credentials
|
||||
|
||||
|
||||
def _save_credentials(username, apiKey):
|
||||
file = open(fpath, 'w')
|
||||
|
||||
def _save_credentials(username, apiKey, event=False, auto_connect=None):
|
||||
data = {
|
||||
'username': username,
|
||||
'apiKey': apiKey
|
||||
}
|
||||
|
||||
credentials = toml.dumps(data)
|
||||
file.write(credentials)
|
||||
if event:
|
||||
fpath = event_fpath
|
||||
if auto_connect is None:
|
||||
cred = _get_credentials(True)
|
||||
auto_connect = cred.get('auto_connect', False)
|
||||
data['auto_connect'] = auto_connect
|
||||
else:
|
||||
fpath = action_fpath
|
||||
|
||||
file = open(fpath, 'w')
|
||||
file.write(json.dumps(data))
|
||||
file.close()
|
||||
|
||||
|
||||
def _clear_credentials():
|
||||
file = open(fpath, 'w').close()
|
||||
def _clear_credentials(event=False):
|
||||
if event:
|
||||
fpath = event_fpath
|
||||
else:
|
||||
fpath = action_fpath
|
||||
open(fpath, 'w').close()
|
||||
_set_env(None, None)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -240,8 +240,7 @@ def register(session, **kw):
|
|||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
action_handler = Sync_To_Avalon(session)
|
||||
action_handler.register()
|
||||
Sync_To_Avalon(session).register()
|
||||
|
||||
|
||||
def main(arguments=None):
|
||||
|
|
|
|||
|
|
@ -83,5 +83,4 @@ def register(session, **kw):
|
|||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
event = NextTaskUpdate(session)
|
||||
event.register()
|
||||
NextTaskUpdate(session).register()
|
||||
|
|
|
|||
|
|
@ -165,5 +165,4 @@ def register(session, **kw):
|
|||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
event = Sync_to_Avalon(session)
|
||||
event.register()
|
||||
Sync_to_Avalon(session).register()
|
||||
|
|
|
|||
|
|
@ -27,5 +27,4 @@ def register(session, **kw):
|
|||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
event = Test_Event(session)
|
||||
event.register()
|
||||
Test_Event(session).register()
|
||||
|
|
|
|||
|
|
@ -45,5 +45,4 @@ def register(session, **kw):
|
|||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
event = ThumbnailEvents(session)
|
||||
event.register()
|
||||
ThumbnailEvents(session).register()
|
||||
|
|
|
|||
|
|
@ -75,5 +75,4 @@ def register(session, **kw):
|
|||
if not isinstance(session, ftrack_api.session.Session):
|
||||
return
|
||||
|
||||
event = VersionToTaskStatus(session)
|
||||
event.register()
|
||||
VersionToTaskStatus(session).register()
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from app.vendor.Qt import QtCore, QtGui, QtWidgets
|
|||
from pype.ftrack import credentials, login_dialog as login_dialog
|
||||
|
||||
from pype.vendor.pynput import mouse, keyboard
|
||||
from FtrackServer import FtrackServer
|
||||
from . import FtrackServer
|
||||
|
||||
from pype import api as pype
|
||||
|
||||
|
|
|
|||
8
pype/ftrack/ftrack_server/__init__.py
Normal file
8
pype/ftrack/ftrack_server/__init__.py
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
from .ftrack_server import FtrackServer
|
||||
from . import event_server, event_server_cli
|
||||
|
||||
__all__ = [
|
||||
'event_server',
|
||||
'event_server_cli',
|
||||
'FtrackServer'
|
||||
]
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import sys
|
||||
from pype.ftrack import credentials, login_dialog as login_dialog
|
||||
from FtrackServer import FtrackServer
|
||||
from pype.ftrack.ftrack_server import FtrackServer
|
||||
from app.vendor.Qt import QtWidgets
|
||||
from pype import api
|
||||
|
||||
|
|
@ -9,10 +9,12 @@ log = api.Logger.getLogger(__name__, "ftrack-event-server")
|
|||
|
||||
class EventServer:
|
||||
def __init__(self):
|
||||
self.login_widget = login_dialog.Login_Dialog_ui(self)
|
||||
self.login_widget = login_dialog.Login_Dialog_ui(
|
||||
parent=self, is_event=True
|
||||
)
|
||||
self.event_server = FtrackServer('event')
|
||||
|
||||
cred = credentials._get_credentials()
|
||||
cred = credentials._get_credentials(True)
|
||||
|
||||
if 'username' in cred and 'apiKey' in cred:
|
||||
self.login_widget.user_input.setText(cred['username'])
|
||||
|
|
@ -24,6 +26,7 @@ class EventServer:
|
|||
|
||||
def loginChange(self):
|
||||
log.info("Logged successfully")
|
||||
|
||||
self.login_widget.close()
|
||||
self.event_server.run_server()
|
||||
|
||||
114
pype/ftrack/ftrack_server/event_server_cli.py
Normal file
114
pype/ftrack/ftrack_server/event_server_cli.py
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
import sys
|
||||
from pype.ftrack import credentials
|
||||
from pype.ftrack.ftrack_server import FtrackServer
|
||||
from app import api
|
||||
|
||||
log = api.Logger.getLogger(__name__, "ftrack-event-server-cli")
|
||||
|
||||
possible_yes = ['y', 'yes']
|
||||
possible_no = ['n', 'no']
|
||||
possible_third = ['a', 'auto']
|
||||
possible_exit = ['exit']
|
||||
|
||||
|
||||
def ask_yes_no(third=False):
|
||||
msg = "Y/N:"
|
||||
if third:
|
||||
msg = "Y/N/AUTO:"
|
||||
log.info(msg)
|
||||
response = input().lower()
|
||||
if response in possible_exit:
|
||||
sys.exit()
|
||||
elif response in possible_yes:
|
||||
return True
|
||||
elif response in possible_no:
|
||||
return False
|
||||
else:
|
||||
all_entries = possible_no
|
||||
all_entries.extend(possible_yes)
|
||||
if third is True:
|
||||
if response in possible_third:
|
||||
return 'auto'
|
||||
else:
|
||||
all_entries.extend(possible_third)
|
||||
all_entries.extend(possible_exit)
|
||||
all_entries = ', '.join(all_entries)
|
||||
log.info(
|
||||
'Invalid input. Possible entries: [{}]. Try it again:'.foramt(
|
||||
all_entries
|
||||
)
|
||||
)
|
||||
return ask_yes_no()
|
||||
|
||||
|
||||
def cli_login():
|
||||
enter_cred = True
|
||||
cred_data = credentials._get_credentials(True)
|
||||
|
||||
user = cred_data.get('username', None)
|
||||
key = cred_data.get('apiKey', None)
|
||||
auto = cred_data.get('auto_connect', False)
|
||||
if user is None or key is None:
|
||||
log.info(
|
||||
'Credentials are not set. Do you want to enter them now? (Y/N)'
|
||||
)
|
||||
if ask_yes_no() is False:
|
||||
log.info("Exiting...")
|
||||
return
|
||||
elif credentials._check_credentials(user, key):
|
||||
if auto is False:
|
||||
log.info((
|
||||
'Do you want to log with username {}'
|
||||
' enter "auto" if want to autoconnect next time (Y/N/AUTO)'
|
||||
).format(
|
||||
user
|
||||
))
|
||||
result = ask_yes_no(True)
|
||||
if result is True:
|
||||
enter_cred = False
|
||||
elif result == 'auto':
|
||||
credentials._save_credentials(user, key, True, True)
|
||||
enter_cred = False
|
||||
else:
|
||||
enter_cred = False
|
||||
else:
|
||||
log.info(
|
||||
'Stored credentials are not valid.'
|
||||
' Do you want enter them now?(Y/N)'
|
||||
)
|
||||
if ask_yes_no() is False:
|
||||
log.info("Exiting...")
|
||||
return
|
||||
|
||||
while enter_cred:
|
||||
log.info('Please enter Ftrack API User:')
|
||||
user = input()
|
||||
log.info('And now enter Ftrack API Key:')
|
||||
key = input()
|
||||
if credentials._check_credentials(user, key):
|
||||
log.info(
|
||||
'Credentials are valid.'
|
||||
' Do you want to auto-connect next time?(Y/N)'
|
||||
)
|
||||
credentials._save_credentials(user, key, True, ask_yes_no())
|
||||
enter_cred = False
|
||||
break
|
||||
else:
|
||||
log.info(
|
||||
'Entered credentials are not valid.'
|
||||
' Do you want to try it again?(Y/N)'
|
||||
)
|
||||
if ask_yes_no() is False:
|
||||
log.info('Exiting...')
|
||||
return
|
||||
|
||||
server = FtrackServer('event')
|
||||
server.run_server()
|
||||
|
||||
|
||||
def main():
|
||||
cli_login()
|
||||
|
||||
|
||||
if (__name__ == ('__main__')):
|
||||
main()
|
||||
157
pype/ftrack/ftrack_server/ftrack_server.py
Normal file
157
pype/ftrack/ftrack_server/ftrack_server.py
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
import os
|
||||
import sys
|
||||
import types
|
||||
import importlib
|
||||
import ftrack_api
|
||||
import time
|
||||
import logging
|
||||
from app.api import Logger
|
||||
|
||||
log = Logger.getLogger(__name__)
|
||||
|
||||
"""
|
||||
# Required - Needed for connection to Ftrack
|
||||
FTRACK_SERVER # Ftrack server e.g. "https://myFtrack.ftrackapp.com"
|
||||
FTRACK_API_KEY # Ftrack user's API key "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
FTRACK_API_USER # Ftrack username e.g. "user.name"
|
||||
|
||||
# Required - Paths to folder with actions
|
||||
FTRACK_ACTIONS_PATH # Paths to folders where are located actions
|
||||
- EXAMPLE: "M:/FtrackApi/../actions/"
|
||||
FTRACK_EVENTS_PATH # Paths to folders where are located actions
|
||||
- EXAMPLE: "M:/FtrackApi/../events/"
|
||||
|
||||
# Required - Needed for import included modules
|
||||
PYTHONPATH # Path to ftrack_api and paths to all modules used in actions
|
||||
- path to ftrack_action_handler, etc.
|
||||
"""
|
||||
|
||||
|
||||
class FtrackServer():
|
||||
def __init__(self, type='action'):
|
||||
"""
|
||||
- 'type' is by default set to 'action' - Runs Action server
|
||||
- enter 'event' for Event server
|
||||
|
||||
EXAMPLE FOR EVENT SERVER:
|
||||
...
|
||||
server = FtrackServer('event')
|
||||
server.run_server()
|
||||
..
|
||||
"""
|
||||
# set Ftrack logging to Warning only - OPTIONAL
|
||||
ftrack_log = logging.getLogger("ftrack_api")
|
||||
ftrack_log.setLevel(logging.WARNING)
|
||||
|
||||
self.type = type
|
||||
self.actionsAvailable = True
|
||||
self.eventsAvailable = True
|
||||
# Separate all paths
|
||||
if "FTRACK_ACTIONS_PATH" in os.environ:
|
||||
all_action_paths = os.environ["FTRACK_ACTIONS_PATH"]
|
||||
self.actionsPaths = all_action_paths.split(os.pathsep)
|
||||
else:
|
||||
self.actionsAvailable = False
|
||||
|
||||
if "FTRACK_EVENTS_PATH" in os.environ:
|
||||
all_event_paths = os.environ["FTRACK_EVENTS_PATH"]
|
||||
self.eventsPaths = all_event_paths.split(os.pathsep)
|
||||
else:
|
||||
self.eventsAvailable = False
|
||||
|
||||
def stop_session(self):
|
||||
if self.session.event_hub.connected is True:
|
||||
self.session.event_hub.disconnect()
|
||||
self.session.close()
|
||||
self.session = None
|
||||
|
||||
def set_files(self, paths):
|
||||
# Iterate all paths
|
||||
functions = []
|
||||
for path in paths:
|
||||
# add path to PYTHON PATH
|
||||
if path not in sys.path:
|
||||
sys.path.append(path)
|
||||
|
||||
# Get all modules with functions
|
||||
for file in os.listdir(path):
|
||||
# Get only .py files with action functions
|
||||
try:
|
||||
if '.pyc' in file or '.py' not in file:
|
||||
continue
|
||||
|
||||
ignore = 'ignore_me'
|
||||
mod = importlib.import_module(os.path.splitext(file)[0])
|
||||
importlib.reload(mod)
|
||||
mod_functions = dict(
|
||||
[
|
||||
(name, function)
|
||||
for name, function in mod.__dict__.items()
|
||||
if isinstance(function, types.FunctionType) or
|
||||
name == ignore
|
||||
]
|
||||
)
|
||||
# Don't care about ignore_me files
|
||||
if (
|
||||
ignore in mod_functions and
|
||||
mod_functions[ignore] is True
|
||||
):
|
||||
continue
|
||||
# separate files by register function
|
||||
if 'register' not in mod_functions:
|
||||
msg = (
|
||||
'"{0}" - Missing register method'
|
||||
).format(file, self.type)
|
||||
log.warning(msg)
|
||||
continue
|
||||
|
||||
functions.append({
|
||||
'name': file,
|
||||
'register': mod_functions['register']
|
||||
})
|
||||
except Exception as e:
|
||||
msg = 'Loading of file "{}" failed ({})'.format(
|
||||
file, str(e)
|
||||
)
|
||||
log.warning(msg)
|
||||
|
||||
if len(functions) < 1:
|
||||
raise Exception
|
||||
|
||||
for function in functions:
|
||||
try:
|
||||
function['register'](self.session)
|
||||
except Exception as e:
|
||||
msg = '"{}" - register was not successful ({})'.format(
|
||||
function['name'], str(e)
|
||||
)
|
||||
log.warning(msg)
|
||||
time.sleep(0.05)
|
||||
|
||||
def run_server(self):
|
||||
self.session = ftrack_api.Session(auto_connect_event_hub=True,)
|
||||
|
||||
if self.type.lower() == 'event':
|
||||
if self.eventsAvailable is False:
|
||||
msg = (
|
||||
'FTRACK_EVENTS_PATH is not set'
|
||||
', event server won\'t launch'
|
||||
)
|
||||
log.error(msg)
|
||||
return
|
||||
self.set_files(self.eventsPaths)
|
||||
else:
|
||||
if self.actionsAvailable is False:
|
||||
msg = (
|
||||
'FTRACK_ACTIONS_PATH is not set'
|
||||
', action server won\'t launch'
|
||||
)
|
||||
log.error(msg)
|
||||
return
|
||||
self.set_files(self.actionsPaths)
|
||||
|
||||
log.info(60*"*")
|
||||
log.info('Registration of actions/events has finished!')
|
||||
|
||||
# keep event_hub on session running
|
||||
self.session.event_hub.wait()
|
||||
|
|
@ -143,10 +143,6 @@ class AppAction(BaseHandler):
|
|||
|
||||
'''
|
||||
|
||||
self.log.info((
|
||||
"Action - {0} ({1}) - just started"
|
||||
).format(self.label, self.identifier))
|
||||
|
||||
entity = entities[0]
|
||||
project_name = entity['project']['full_name']
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@ import time
|
|||
from pype import api as pype
|
||||
|
||||
|
||||
class MissingPermision(Exception):
|
||||
def __init__(self):
|
||||
super().__init__('Missing permission')
|
||||
|
||||
|
||||
class BaseHandler(object):
|
||||
'''Custom Action base class
|
||||
|
||||
|
|
@ -25,10 +30,11 @@ class BaseHandler(object):
|
|||
self.log = pype.Logger.getLogger(self.__class__.__name__)
|
||||
|
||||
# Using decorator
|
||||
self.register = self.register_log(self.register)
|
||||
self.register = self.register_decorator(self.register)
|
||||
self.launch = self.launch_log(self.launch)
|
||||
|
||||
# Decorator
|
||||
def register_log(self, func):
|
||||
def register_decorator(self, func):
|
||||
@functools.wraps(func)
|
||||
def wrapper_register(*args, **kwargs):
|
||||
label = self.__class__.__name__
|
||||
|
|
@ -37,8 +43,20 @@ class BaseHandler(object):
|
|||
label = self.label
|
||||
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
|
||||
|
||||
start_time = time.perf_counter()
|
||||
func(*args, **kwargs)
|
||||
end_time = time.perf_counter()
|
||||
|
|
@ -46,6 +64,10 @@ class BaseHandler(object):
|
|||
self.log.info((
|
||||
'{} "{}" - Registered successfully ({:.4f}sec)'
|
||||
).format(self.type, label, run_time))
|
||||
except MissingPermision:
|
||||
self.log.info((
|
||||
'!{} "{}" - You\'re missing required permissions'
|
||||
).format(self.type, label))
|
||||
except NotImplementedError:
|
||||
self.log.error((
|
||||
'{} "{}" - Register method is not implemented'
|
||||
|
|
@ -58,6 +80,29 @@ class BaseHandler(object):
|
|||
)
|
||||
return wrapper_register
|
||||
|
||||
# Decorator
|
||||
def launch_log(self, func):
|
||||
@functools.wraps(func)
|
||||
def wrapper_launch(*args, **kwargs):
|
||||
label = self.__class__.__name__
|
||||
if hasattr(self, 'label'):
|
||||
if self.variant is None:
|
||||
label = self.label
|
||||
else:
|
||||
label = '{} {}'.format(self.label, self.variant)
|
||||
|
||||
try:
|
||||
result = func(*args, **kwargs)
|
||||
self.log.info((
|
||||
'{} "{}" Launched'
|
||||
).format(self.type, label))
|
||||
return result
|
||||
except Exception as e:
|
||||
self.log.error('{} "{}": Launch failed ({})'.format(
|
||||
self.type, label, str(e))
|
||||
)
|
||||
return wrapper_launch
|
||||
|
||||
@property
|
||||
def session(self):
|
||||
'''Return current session.'''
|
||||
|
|
@ -126,19 +171,7 @@ class BaseHandler(object):
|
|||
|
||||
'''Return *event* translated structure to be used with the API.'''
|
||||
|
||||
_selection = event['data'].get('selection', [])
|
||||
|
||||
_entities = list()
|
||||
for entity in _selection:
|
||||
_entities.append(
|
||||
(
|
||||
session.get(
|
||||
self._get_entity_type(entity),
|
||||
entity.get('entityId')
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
_entities = event['data']['entities']
|
||||
return [
|
||||
_entities,
|
||||
event
|
||||
|
|
|
|||
|
|
@ -16,11 +16,12 @@ class Login_Dialog_ui(QtWidgets.QWidget):
|
|||
buttons = []
|
||||
labels = []
|
||||
|
||||
def __init__(self, parent=None):
|
||||
def __init__(self, parent=None, is_event=False):
|
||||
|
||||
super(Login_Dialog_ui, self).__init__()
|
||||
|
||||
self.parent = parent
|
||||
self.is_event = is_event
|
||||
|
||||
if hasattr(parent, 'icon'):
|
||||
self.setWindowIcon(self.parent.icon)
|
||||
|
|
@ -205,7 +206,7 @@ class Login_Dialog_ui(QtWidgets.QWidget):
|
|||
verification = credentials._check_credentials(username, apiKey)
|
||||
|
||||
if verification:
|
||||
credentials._save_credentials(username, apiKey)
|
||||
credentials._save_credentials(username, apiKey, self.is_event)
|
||||
credentials._set_env(username, apiKey)
|
||||
if self.parent is not None:
|
||||
self.parent.loginChange()
|
||||
|
|
@ -305,7 +306,7 @@ class Login_Dialog_ui(QtWidgets.QWidget):
|
|||
verification = credentials._check_credentials(username, apiKey)
|
||||
|
||||
if verification is True:
|
||||
credentials._save_credentials(username, apiKey)
|
||||
credentials._save_credentials(username, apiKey, self.is_event)
|
||||
credentials._set_env(username, apiKey)
|
||||
if self.parent is not None:
|
||||
self.parent.loginChange()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue