actions are discovered by settings

This commit is contained in:
iLLiCiTiT 2020-12-21 19:09:44 +01:00
parent 4ca70aa937
commit c3c415e405
14 changed files with 190 additions and 109 deletions

View file

@ -9,7 +9,6 @@ class CleanHierarchicalAttrsAction(BaseAction):
label = "Pype Admin"
variant = "- Clean hierarchical custom attributes"
description = "Unset empty hierarchical attribute values."
role_list = ["Pypeclub", "Administrator", "Project Manager"]
icon = statics_icon("ftrack", "action_icons", "PypeAdmin.svg")
all_project_entities_query = (
@ -20,12 +19,17 @@ class CleanHierarchicalAttrsAction(BaseAction):
"select value, entity_id from CustomAttributeValue "
"where entity_id in ({}) and configuration_id is \"{}\""
)
settings_key = "clean_hierarchical_attr"
def discover(self, session, entities, event):
"""Show only on project entity."""
if len(entities) == 1 and entities[0].entity_type.lower() == "project":
return True
return False
if (
len(entities) != 1
or entities[0].entity_type.lower() != "project"
):
return False
return self.valid_roles(session, entities, event)
def launch(self, session, entities, event):
project = entities[0]

View file

@ -131,9 +131,8 @@ class CustomAttributes(BaseAction):
variant = '- 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 = statics_icon("ftrack", "action_icons", "PypeAdmin.svg")
settings_key = "create_update_attributes"
required_keys = ("key", "label", "type")
@ -150,7 +149,7 @@ class CustomAttributes(BaseAction):
Validation
- action is only for Administrators
'''
return True
return self.valid_roles(session, entities, event)
def launch(self, session, entities, event):
# JOB SETTINGS

View file

@ -18,8 +18,8 @@ class DeleteAssetSubset(BaseAction):
#: Action description.
description = "Removes from Avalon with all childs and asset from Ftrack"
icon = statics_icon("ftrack", "action_icons", "DeleteAsset.svg")
#: roles that are allowed to register this action
role_list = ["Pypeclub", "Administrator", "Project Manager"]
settings_key = "delete_asset_subset"
#: Db connection
dbcon = AvalonMongoDB()
@ -32,17 +32,21 @@ class DeleteAssetSubset(BaseAction):
""" Validation """
task_ids = []
for ent_info in event["data"]["selection"]:
entType = ent_info.get("entityType", "")
if entType == "task":
if ent_info.get("entityType") == "task":
task_ids.append(ent_info["entityId"])
is_valid = False
for entity in entities:
ftrack_id = entity["id"]
if ftrack_id not in task_ids:
continue
if entity.entity_type.lower() != "task":
return True
return False
if (
entity["id"] in task_ids
and entity.entity_type.lower() != "task"
):
is_valid = True
break
if is_valid:
is_valid = self.valid_roles(session, entities, event)
return is_valid
def _launch(self, event):
try:

View file

@ -21,7 +21,6 @@ class DeleteOldVersions(BaseAction):
"Delete files from older publishes so project can be"
" archived with only lates versions."
)
role_list = ["Pypeclub", "Project Manager", "Administrator"]
icon = statics_icon("ftrack", "action_icons", "PypeAdmin.svg")
dbcon = AvalonMongoDB()
@ -31,13 +30,16 @@ class DeleteOldVersions(BaseAction):
sequence_splitter = "__sequence_splitter__"
def discover(self, session, entities, event):
''' Validation '''
selection = event["data"].get("selection") or []
for entity in selection:
entity_type = (entity.get("entityType") or "").lower()
if entity_type == "assetversion":
return True
return False
""" Validation. """
is_valid = False
for entity in entities:
if entity.entity_type.lower() == "assetversion":
is_valid = True
break
if is_valid:
is_valid = self.valid_roles(session, entities, event)
return is_valid
def interface(self, session, entities, event):
# TODO Add roots existence validation

View file

@ -23,6 +23,7 @@ class Delivery(BaseAction):
description = "Deliver data to client"
role_list = ["Pypeclub", "Administrator", "Project manager"]
icon = statics_icon("ftrack", "action_icons", "Delivery.svg")
settings_key = "delivery_action"
def __init__(self, *args, **kwargs):
self.db_con = AvalonMongoDB()
@ -30,11 +31,15 @@ class Delivery(BaseAction):
super(Delivery, self).__init__(*args, **kwargs)
def discover(self, session, entities, event):
is_valid = False
for entity in entities:
if entity.entity_type.lower() == "assetversion":
return True
is_valid = True
break
return False
if is_valid:
is_valid = self.valid_roles(session, entities, event)
return is_valid
def interface(self, session, entities, event):
if event["data"].get("values", {}):

View file

@ -13,13 +13,12 @@ class JobKiller(BaseAction):
#: Action description.
description = 'Killing selected running jobs'
#: roles that are allowed to register this action
role_list = ['Pypeclub', 'Administrator']
icon = statics_icon("ftrack", "action_icons", "PypeAdmin.svg")
settings_key = "job_killer"
def discover(self, session, entities, event):
''' Validation '''
return True
return self.valid_roles(session, entities, event)
def interface(self, session, entities, event):
if not event['data'].get('values', {}):

View file

@ -16,22 +16,23 @@ class PrepareProject(BaseAction):
#: Action description.
description = 'Set basic attributes on the project'
#: roles that are allowed to register this action
role_list = ["Pypeclub", "Administrator", "Project manager"]
icon = statics_icon("ftrack", "action_icons", "PrepareProject.svg")
settings_key = "prepare_project"
# Key to store info about trigerring create folder structure
create_project_structure_key = "create_folder_structure"
item_splitter = {'type': 'label', 'value': '---'}
def discover(self, session, entities, event):
''' Validation '''
if len(entities) != 1:
if (
len(entities) != 1
or entities[0].entity_type.lower() != "project"
):
return False
if entities[0].entity_type.lower() != "project":
return False
return True
return self.valid_roles(session, entities, event)
def interface(self, session, entities, event):
if event['data'].get('values', {}):

View file

@ -15,7 +15,6 @@ class SeedDebugProject(BaseAction):
#: priority
priority = 100
#: roles that are allowed to register this action
role_list = ["Pypeclub"]
icon = statics_icon("ftrack", "action_icons", "SeedProject.svg")
# Asset names which will be created in `Assets` entity
@ -58,9 +57,12 @@ class SeedDebugProject(BaseAction):
existing_projects = None
new_project_item = "< New Project >"
current_project_item = "< Current Project >"
settings_key = "seed_project"
def discover(self, session, entities, event):
''' Validation '''
if not self.valid_roles(session, entities, event):
return False
return True
def interface(self, session, entities, event):

View file

@ -21,8 +21,8 @@ class StoreThumbnailsToAvalon(BaseAction):
# Action description
description = 'Test action'
# roles that are allowed to register this action
role_list = ["Pypeclub", "Administrator", "Project Manager"]
icon = statics_icon("ftrack", "action_icons", "PypeAdmin.svg")
settings_key = "store_thubmnail_to_avalon"
thumbnail_key = "AVALON_THUMBNAIL_ROOT"
@ -31,10 +31,15 @@ class StoreThumbnailsToAvalon(BaseAction):
super(StoreThumbnailsToAvalon, self).__init__(*args, **kwargs)
def discover(self, session, entities, event):
is_valid = False
for entity in entities:
if entity.entity_type.lower() == "assetversion":
return True
return False
is_valid = True
break
if is_valid:
is_valid = self.valid_roles(session, entities, event)
return is_valid
def launch(self, session, entities, event):
user = session.query(

View file

@ -41,20 +41,26 @@ class SyncToAvalonLocal(BaseAction):
#: priority
priority = 200
#: roles that are allowed to register this action
role_list = ["Pypeclub"]
icon = statics_icon("ftrack", "action_icons", "PypeAdmin.svg")
settings_key = "sync_to_avalon_local"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.entities_factory = SyncEntitiesFactory(self.log, self.session)
def discover(self, session, entities, event):
''' Validation '''
""" Validate selection. """
is_valid = False
for ent in event["data"]["selection"]:
# Ignore entities that are not tasks or projects
if ent["entityType"].lower() in ["show", "task"]:
return True
return False
is_valid = True
break
if is_valid:
is_valid = self.valid_roles(session, entities, event)
return is_valid
def launch(self, session, in_entities, event):
time_start = time.time()

View file

@ -15,11 +15,9 @@ class ThumbToChildren(BaseAction):
icon = statics_icon("ftrack", "action_icons", "Thumbnail.svg")
def discover(self, session, entities, event):
''' Validation '''
if (len(entities) != 1 or entities[0].entity_type in ['Project']):
"""Show only on project."""
if (len(entities) != 1 or entities[0].entity_type in ["Project"]):
return False
return True
def launch(self, session, entities, event):

View file

@ -61,8 +61,8 @@ class TaskStatusToParent(BaseEvent):
session, event, project_id
)
# Load settings
project_settings = self.get_settings_for_project(
session, event, project_entity=project_entity
project_settings = self.get_project_settings_from_event(
event, project_entity
)
# Prepare loaded settings and check if can be processed

View file

@ -29,6 +29,8 @@ class BaseAction(BaseHandler):
icon = None
type = 'Action'
settings_frack_subkey = "user_handlers"
def __init__(self, session):
'''Expects a ftrack_api.Session instance'''
if self.label is None:
@ -88,63 +90,6 @@ class BaseAction(BaseHandler):
}]
}
@classmethod
def get_user_entity_from_event(cls, session, event):
"""Query user entity from event."""
not_set = object()
# Check if user is already stored in event data
user_entity = event["data"].get("user_entity", not_set)
if user_entity is not_set:
# Query user entity from event
user_info = event.get("source", {}).get("user", {})
user_id = user_info.get("id")
username = user_info.get("username")
if user_id:
user_entity = session.query(
"User where id is {}".format(user_id)
).first()
if not user_entity and username:
user_entity = session.query(
"User where username is {}".format(username)
).first()
event["data"]["user_entity"] = user_entity
return user_entity
@classmethod
def get_user_roles_from_event(cls, session, event):
"""Query user entity from event."""
not_set = object()
user_roles = event["data"].get("user_roles", not_set)
if user_roles is not_set:
user_roles = []
user_entity = cls.get_user_entity_from_event(session, event)
for role in user_entity["user_security_roles"]:
user_roles.append(role["security_role"]["name"].lower())
event["data"]["user_roles"] = user_roles
return user_roles
def get_project_entity_from_event(self, session, event, entities):
"""Load or query and fill project entity from/to event data.
Project data are stored by ftrack id because in most cases it is
easier to access project id than project name.
Args:
session (ftrack_api.Session): Current session.
event (ftrack_api.Event): Processed event by session.
entities (list): Ftrack entities of selection.
"""
# Try to get project entity from event
project_entity = event["data"].get("project_entity")
if not project_entity:
project_entity = self.get_project_from_entity(entities[0])
event["data"]["project_entity"] = project_entity
return project_entity
def discover(self, session, entities, event):
'''Return true if we can handle the selected entities.
@ -253,6 +198,112 @@ class BaseAction(BaseHandler):
return result
@staticmethod
def roles_check(settings_roles, user_roles, default=True):
"""Compare roles from setting and user's roles.
Args:
settings_roles(list): List of role names from settings.
user_roles(list): User's lowered role names.
default(bool): If `settings_roles` is empty list.
Returns:
bool: `True` if user has at least one role from settings or
default if `settings_roles` is empty.
"""
if not settings_roles:
return default
for role_name in settings_roles:
if role_name.lower() in user_roles:
return True
return False
@classmethod
def get_user_entity_from_event(cls, session, event):
"""Query user entity from event."""
not_set = object()
# Check if user is already stored in event data
user_entity = event["data"].get("user_entity", not_set)
if user_entity is not_set:
# Query user entity from event
user_info = event.get("source", {}).get("user", {})
user_id = user_info.get("id")
username = user_info.get("username")
if user_id:
user_entity = session.query(
"User where id is {}".format(user_id)
).first()
if not user_entity and username:
user_entity = session.query(
"User where username is {}".format(username)
).first()
event["data"]["user_entity"] = user_entity
return user_entity
@classmethod
def get_user_roles_from_event(cls, session, event):
"""Query user entity from event."""
not_set = object()
user_roles = event["data"].get("user_roles", not_set)
if user_roles is not_set:
user_roles = []
user_entity = cls.get_user_entity_from_event(session, event)
for role in user_entity["user_security_roles"]:
user_roles.append(role["security_role"]["name"].lower())
event["data"]["user_roles"] = user_roles
return user_roles
def get_project_entity_from_event(self, session, event, entities):
"""Load or query and fill project entity from/to event data.
Project data are stored by ftrack id because in most cases it is
easier to access project id than project name.
Args:
session (ftrack_api.Session): Current session.
event (ftrack_api.Event): Processed event by session.
entities (list): Ftrack entities of selection.
"""
# Try to get project entity from event
project_entity = event["data"].get("project_entity")
if not project_entity:
project_entity = self.get_project_from_entity(
entities[0], session
)
event["data"]["project_entity"] = project_entity
return project_entity
def get_ftrack_settings(self, session, event, entities):
project_entity = self.get_project_entity_from_event(
session, event, entities
)
project_settings = self.get_project_settings_from_event(
event, project_entity
)
return project_settings["ftrack"]
def valid_roles(self, session, entities, event):
"""Validate user roles by settings.
Method requires to have set `settings_key` attribute.
"""
ftrack_settings = self.get_ftrack_settings(session, event, entities)
settings = (
ftrack_settings[self.settings_frack_subkey][self.settings_key]
)
if not settings.get("enabled", True):
return False
user_role_list = self.get_user_roles_from_event(session, event)
if not self.roles_check(settings.get("role_list"), user_role_list):
return False
return True
class ServerAction(BaseAction):
"""Action class meant to be used on event server.
@ -261,6 +312,8 @@ class ServerAction(BaseAction):
For the same reason register is modified to not filter topics by username.
"""
settings_frack_subkey = "events"
def register(self):
"""Register subcription to Ftrack event hub."""
self.session.event_hub.subscribe(

View file

@ -528,7 +528,7 @@ class BaseHandler(object):
"Publishing event: {}"
).format(str(event.__dict__)))
def get_project_from_entity(self, entity):
def get_project_from_entity(self, entity, session=None):
low_entity_type = entity.entity_type.lower()
if low_entity_type == "project":
return entity
@ -549,7 +549,10 @@ class BaseHandler(object):
return parent["project"]
project_data = entity["link"][0]
return self.session.query(
if session is None:
session = self.session
return session.query(
"Project where id is {}".format(project_data["id"])
).one()