From f368385920a3c41a1342011b6f828830e5b968a3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Dec 2020 17:35:10 +0100 Subject: [PATCH 1/9] removed roles from registerings --- .../modules/ftrack/lib/ftrack_base_handler.py | 30 +++++-------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/pype/modules/ftrack/lib/ftrack_base_handler.py b/pype/modules/ftrack/lib/ftrack_base_handler.py index 022c4f0829..8fbb54440a 100644 --- a/pype/modules/ftrack/lib/ftrack_base_handler.py +++ b/pype/modules/ftrack/lib/ftrack_base_handler.py @@ -37,7 +37,6 @@ class BaseHandler(object): type = 'No-type' ignore_me = False preactions = [] - role_list = [] @staticmethod def join_query_keys(keys): @@ -142,28 +141,7 @@ class BaseHandler(object): def reset_session(self): self.session.reset() - def _register_role_check(self): - if not self.role_list or not isinstance(self.role_list, (list, tuple)): - return - - user_entity = self.session.query( - "User where username is \"{}\"".format(self.session.api_user) - ).one() - available = False - lowercase_rolelist = [ - role_name.lower() - for role_name in self.role_list - ] - for role in user_entity["user_security_roles"]: - if role["security_role"]["name"].lower() in lowercase_rolelist: - available = True - break - if available is False: - raise MissingPermision - def _preregister(self): - self._register_role_check() - # Custom validations result = self.preregister() if result is None: @@ -621,11 +599,19 @@ class BaseHandler(object): project_entity (ftrack_api.Entity): Project entity. Must be entered if project_id is not. """ + if not project_entity: project_entity = self.get_project_entity_from_event( session, event, project_id ) + if not project_entity: + raise AssertionError(( + "Invalid arguments entered. Project entity or project id" + "must be entered." + )) + + project_id = project_entity["id"] project_name = project_entity["full_name"] project_settings_by_id = event["data"].get("project_settings") From 1bf55c56868249d5c43edacab2fec7f222396e59 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Dec 2020 17:37:17 +0100 Subject: [PATCH 2/9] removed server action role check --- .../ftrack/lib/ftrack_action_handler.py | 72 ++----------------- 1 file changed, 7 insertions(+), 65 deletions(-) diff --git a/pype/modules/ftrack/lib/ftrack_action_handler.py b/pype/modules/ftrack/lib/ftrack_action_handler.py index e04ed6b404..6d45748b23 100644 --- a/pype/modules/ftrack/lib/ftrack_action_handler.py +++ b/pype/modules/ftrack/lib/ftrack_action_handler.py @@ -67,6 +67,9 @@ class BaseAction(BaseHandler): def _discover(self, event): entities = self._translate_event(event) + if not entities: + return + accepts = self.discover(self.session, entities, event) if not accepts: return @@ -146,21 +149,18 @@ class BaseAction(BaseHandler): def _launch(self, event): entities = self._translate_event(event) + if not entities: + return preactions_launched = self._handle_preactions(self.session, event) if preactions_launched is False: return - interface = self._interface( - self.session, entities, event - ) - + interface = self._interface(self.session, entities, event) if interface: return interface - response = self.launch( - self.session, entities, event - ) + response = self.launch(self.session, entities, event) return self._handle_result(response) @@ -204,64 +204,6 @@ class ServerAction(BaseAction): For the same reason register is modified to not filter topics by username. """ - def __init__(self, *args, **kwargs): - if not self.role_list: - self.role_list = set() - else: - self.role_list = set( - role_name.lower() - for role_name in self.role_list - ) - super(ServerAction, self).__init__(*args, **kwargs) - - def _register_role_check(self): - # Skip register role check. - return - - def _discover(self, event): - """Check user discover availability.""" - if not self._check_user_discover(event): - return - return super(ServerAction, self)._discover(event) - - def _check_user_discover(self, event): - """Should be action discovered by user trying to show actions.""" - if not self.role_list: - return True - - user_entity = self._get_user_entity(event) - if not user_entity: - return False - - for role in user_entity["user_security_roles"]: - lowered_role = role["security_role"]["name"].lower() - if lowered_role in self.role_list: - return True - return False - - def _get_user_entity(self, 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 = self.session.query( - "User where id is {}".format(user_id) - ).first() - if not user_entity and username: - user_entity = self.session.query( - "User where username is {}".format(username) - ).first() - event["data"]["user_entity"] = user_entity - - return user_entity - def register(self): """Register subcription to Ftrack event hub.""" self.session.event_hub.subscribe( From 5517fe09cc92ee4417baba44579bacdfe432728a Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Dec 2020 17:39:27 +0100 Subject: [PATCH 3/9] implemented helper functions to get user roles from event --- .../ftrack/lib/ftrack_action_handler.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/pype/modules/ftrack/lib/ftrack_action_handler.py b/pype/modules/ftrack/lib/ftrack_action_handler.py index 6d45748b23..1dcc5ca647 100644 --- a/pype/modules/ftrack/lib/ftrack_action_handler.py +++ b/pype/modules/ftrack/lib/ftrack_action_handler.py @@ -88,6 +88,44 @@ 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 discover(self, session, entities, event): '''Return true if we can handle the selected entities. From 8ed00fbdef6fe9af869708a1c67f2e9c321183c1 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Dec 2020 17:47:16 +0100 Subject: [PATCH 4/9] get_project_entity_from_event moved to event handler --- .../modules/ftrack/lib/ftrack_base_handler.py | 29 ------------------ .../ftrack/lib/ftrack_event_handler.py | 30 +++++++++++++++++++ 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/pype/modules/ftrack/lib/ftrack_base_handler.py b/pype/modules/ftrack/lib/ftrack_base_handler.py index 8fbb54440a..517bcfd3c8 100644 --- a/pype/modules/ftrack/lib/ftrack_base_handler.py +++ b/pype/modules/ftrack/lib/ftrack_base_handler.py @@ -553,35 +553,6 @@ class BaseHandler(object): "Project where id is {}".format(project_data["id"]) ).one() - def get_project_entity_from_event(self, session, event, project_id): - """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. - project_id (str): Ftrack project id. - """ - if not project_id: - raise ValueError( - "Entered `project_id` is not valid. {} ({})".format( - str(project_id), str(type(project_id)) - ) - ) - # Try to get project entity from event - project_entities = event["data"].get("project_entities") - if not project_entities: - project_entities = {} - event["data"]["project_entities"] = project_entities - - project_entity = project_entities.get(project_id) - if not project_entity: - # Get project entity from task and store to event - project_entity = session.get("Project", project_id) - event["data"]["project_entities"][project_id] = project_entity - return project_entity def get_settings_for_project( self, session, event, project_id=None, project_entity=None diff --git a/pype/modules/ftrack/lib/ftrack_event_handler.py b/pype/modules/ftrack/lib/ftrack_event_handler.py index 53b78ccc17..73cebc4d34 100644 --- a/pype/modules/ftrack/lib/ftrack_event_handler.py +++ b/pype/modules/ftrack/lib/ftrack_event_handler.py @@ -46,3 +46,33 @@ class BaseEvent(BaseHandler): session, ignore=['socialfeed', 'socialnotification'] ) + + def get_project_entity_from_event(self, session, event, project_id): + """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. + project_id (str): Ftrack project id. + """ + if not project_id: + raise ValueError( + "Entered `project_id` is not valid. {} ({})".format( + str(project_id), str(type(project_id)) + ) + ) + # Try to get project entity from event + project_entities = event["data"].get("project_entities") + if not project_entities: + project_entities = {} + event["data"]["project_entities"] = project_entities + + project_entity = project_entities.get(project_id) + if not project_entity: + # Get project entity from task and store to event + project_entity = session.get("Project", project_id) + event["data"]["project_entities"][project_id] = project_entity + return project_entity From ff80d5df6de3544bba83f050b4a16efc841f5562 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Dec 2020 17:47:38 +0100 Subject: [PATCH 5/9] `get_settings_for_project` expect only project_entity --- pype/modules/ftrack/lib/ftrack_base_handler.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/pype/modules/ftrack/lib/ftrack_base_handler.py b/pype/modules/ftrack/lib/ftrack_base_handler.py index 517bcfd3c8..ebcc3b3809 100644 --- a/pype/modules/ftrack/lib/ftrack_base_handler.py +++ b/pype/modules/ftrack/lib/ftrack_base_handler.py @@ -563,19 +563,9 @@ class BaseHandler(object): easier to access project id than project name. Args: - session (ftrack_api.Session): Current session. event (ftrack_api.Event): Processed event by session. - project_id (str): Ftrack project id. Must be entered if - project_entity is not. - project_entity (ftrack_api.Entity): Project entity. Must be entered - if project_id is not. + project_entity (ftrack_api.Entity): Project entity. """ - - if not project_entity: - project_entity = self.get_project_entity_from_event( - session, event, project_id - ) - if not project_entity: raise AssertionError(( "Invalid arguments entered. Project entity or project id" From 3eb4674ac977355d2161738a58476061b59c108b Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Dec 2020 17:48:21 +0100 Subject: [PATCH 6/9] renamed `get_settings_for_project` to `get_project_settings_from_event` --- pype/modules/ftrack/events/event_task_to_version_status.py | 4 ++-- pype/modules/ftrack/events/event_thumbnail_updates.py | 4 ++-- pype/modules/ftrack/events/event_version_to_task_statuses.py | 4 ++-- pype/modules/ftrack/lib/ftrack_base_handler.py | 5 +---- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/pype/modules/ftrack/events/event_task_to_version_status.py b/pype/modules/ftrack/events/event_task_to_version_status.py index 8d226424c3..fa2cb043bd 100644 --- a/pype/modules/ftrack/events/event_task_to_version_status.py +++ b/pype/modules/ftrack/events/event_task_to_version_status.py @@ -102,8 +102,8 @@ class TaskToVersionStatus(BaseEvent): project_entity = self.get_project_entity_from_event( session, event, project_id ) - project_settings = self.get_settings_for_project( - session, event, project_entity=project_entity + project_settings = self.get_project_settings_from_event( + event, project_entity ) project_name = project_entity["full_name"] diff --git a/pype/modules/ftrack/events/event_thumbnail_updates.py b/pype/modules/ftrack/events/event_thumbnail_updates.py index 09d992b8c4..cda43b05a9 100644 --- a/pype/modules/ftrack/events/event_thumbnail_updates.py +++ b/pype/modules/ftrack/events/event_thumbnail_updates.py @@ -22,8 +22,8 @@ class ThumbnailEvents(BaseEvent): project_entity = self.get_project_entity_from_event( session, event, project_id ) - project_settings = self.get_settings_for_project( - session, event, project_entity=project_entity + project_settings = self.get_project_settings_from_event( + event, project_entity ) project_name = project_entity["full_name"] diff --git a/pype/modules/ftrack/events/event_version_to_task_statuses.py b/pype/modules/ftrack/events/event_version_to_task_statuses.py index 03f873f2cd..6debd4aac4 100644 --- a/pype/modules/ftrack/events/event_version_to_task_statuses.py +++ b/pype/modules/ftrack/events/event_version_to_task_statuses.py @@ -51,8 +51,8 @@ class VersionToTaskStatus(BaseEvent): project_entity = self.get_project_entity_from_event( session, event, project_id ) - project_settings = self.get_settings_for_project( - session, event, project_entity=project_entity + project_settings = self.get_project_settings_from_event( + event, project_entity ) project_name = project_entity["full_name"] diff --git a/pype/modules/ftrack/lib/ftrack_base_handler.py b/pype/modules/ftrack/lib/ftrack_base_handler.py index ebcc3b3809..00a3cd8cdc 100644 --- a/pype/modules/ftrack/lib/ftrack_base_handler.py +++ b/pype/modules/ftrack/lib/ftrack_base_handler.py @@ -553,10 +553,7 @@ class BaseHandler(object): "Project where id is {}".format(project_data["id"]) ).one() - - def get_settings_for_project( - self, session, event, project_id=None, project_entity=None - ): + def get_project_settings_from_event(self, event, project_entity): """Load or fill pype's project settings from event data. Project data are stored by ftrack id because in most cases it is From 4ca70aa937e14a20ef08f775c33bda9ae83c07eb Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Dec 2020 17:49:24 +0100 Subject: [PATCH 7/9] implemented `get_project_entity_from_event` for action handler --- .../ftrack/lib/ftrack_action_handler.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pype/modules/ftrack/lib/ftrack_action_handler.py b/pype/modules/ftrack/lib/ftrack_action_handler.py index 1dcc5ca647..aa6cb7c1b0 100644 --- a/pype/modules/ftrack/lib/ftrack_action_handler.py +++ b/pype/modules/ftrack/lib/ftrack_action_handler.py @@ -126,6 +126,25 @@ class BaseAction(BaseHandler): 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. From c3c415e4059f1cd39f1a99cf855cecb73ce08c83 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 21 Dec 2020 19:09:44 +0100 Subject: [PATCH 8/9] actions are discovered by settings --- .../action_clean_hierarchical_attributes.py | 12 +- .../actions/action_create_cust_attrs.py | 5 +- .../ftrack/actions/action_delete_asset.py | 24 +-- .../actions/action_delete_old_versions.py | 18 +- .../modules/ftrack/actions/action_delivery.py | 9 +- .../ftrack/actions/action_job_killer.py | 5 +- .../ftrack/actions/action_prepare_project.py | 13 +- pype/modules/ftrack/actions/action_seed.py | 4 +- .../action_store_thumbnails_to_avalon.py | 11 +- .../ftrack/actions/action_sync_to_avalon.py | 14 +- .../actions/action_thumbnail_to_childern.py | 6 +- .../events/event_task_to_parent_status.py | 4 +- .../ftrack/lib/ftrack_action_handler.py | 167 ++++++++++++------ .../modules/ftrack/lib/ftrack_base_handler.py | 7 +- 14 files changed, 190 insertions(+), 109 deletions(-) diff --git a/pype/modules/ftrack/actions/action_clean_hierarchical_attributes.py b/pype/modules/ftrack/actions/action_clean_hierarchical_attributes.py index dc3a638192..f9824ec8ea 100644 --- a/pype/modules/ftrack/actions/action_clean_hierarchical_attributes.py +++ b/pype/modules/ftrack/actions/action_clean_hierarchical_attributes.py @@ -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] diff --git a/pype/modules/ftrack/actions/action_create_cust_attrs.py b/pype/modules/ftrack/actions/action_create_cust_attrs.py index 9d6c16b556..a6601775f1 100644 --- a/pype/modules/ftrack/actions/action_create_cust_attrs.py +++ b/pype/modules/ftrack/actions/action_create_cust_attrs.py @@ -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 diff --git a/pype/modules/ftrack/actions/action_delete_asset.py b/pype/modules/ftrack/actions/action_delete_asset.py index 4720273c81..3bdbbe2470 100644 --- a/pype/modules/ftrack/actions/action_delete_asset.py +++ b/pype/modules/ftrack/actions/action_delete_asset.py @@ -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: diff --git a/pype/modules/ftrack/actions/action_delete_old_versions.py b/pype/modules/ftrack/actions/action_delete_old_versions.py index 31d15da9e5..e1c1e173a3 100644 --- a/pype/modules/ftrack/actions/action_delete_old_versions.py +++ b/pype/modules/ftrack/actions/action_delete_old_versions.py @@ -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 diff --git a/pype/modules/ftrack/actions/action_delivery.py b/pype/modules/ftrack/actions/action_delivery.py index 853fe64ec7..e9e939bb47 100644 --- a/pype/modules/ftrack/actions/action_delivery.py +++ b/pype/modules/ftrack/actions/action_delivery.py @@ -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", {}): diff --git a/pype/modules/ftrack/actions/action_job_killer.py b/pype/modules/ftrack/actions/action_job_killer.py index cb193b88ce..1ddd1383a7 100644 --- a/pype/modules/ftrack/actions/action_job_killer.py +++ b/pype/modules/ftrack/actions/action_job_killer.py @@ -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', {}): diff --git a/pype/modules/ftrack/actions/action_prepare_project.py b/pype/modules/ftrack/actions/action_prepare_project.py index 98493f65c7..3a955067d8 100644 --- a/pype/modules/ftrack/actions/action_prepare_project.py +++ b/pype/modules/ftrack/actions/action_prepare_project.py @@ -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', {}): diff --git a/pype/modules/ftrack/actions/action_seed.py b/pype/modules/ftrack/actions/action_seed.py index 2610a25024..549afc660c 100644 --- a/pype/modules/ftrack/actions/action_seed.py +++ b/pype/modules/ftrack/actions/action_seed.py @@ -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): diff --git a/pype/modules/ftrack/actions/action_store_thumbnails_to_avalon.py b/pype/modules/ftrack/actions/action_store_thumbnails_to_avalon.py index 6df8271381..84f857e37a 100644 --- a/pype/modules/ftrack/actions/action_store_thumbnails_to_avalon.py +++ b/pype/modules/ftrack/actions/action_store_thumbnails_to_avalon.py @@ -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( diff --git a/pype/modules/ftrack/actions/action_sync_to_avalon.py b/pype/modules/ftrack/actions/action_sync_to_avalon.py index 6077511092..b86b469d1c 100644 --- a/pype/modules/ftrack/actions/action_sync_to_avalon.py +++ b/pype/modules/ftrack/actions/action_sync_to_avalon.py @@ -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() diff --git a/pype/modules/ftrack/actions/action_thumbnail_to_childern.py b/pype/modules/ftrack/actions/action_thumbnail_to_childern.py index 604688d221..b90dfa027c 100644 --- a/pype/modules/ftrack/actions/action_thumbnail_to_childern.py +++ b/pype/modules/ftrack/actions/action_thumbnail_to_childern.py @@ -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): diff --git a/pype/modules/ftrack/events/event_task_to_parent_status.py b/pype/modules/ftrack/events/event_task_to_parent_status.py index 2bb7be1a26..30c995495e 100644 --- a/pype/modules/ftrack/events/event_task_to_parent_status.py +++ b/pype/modules/ftrack/events/event_task_to_parent_status.py @@ -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 diff --git a/pype/modules/ftrack/lib/ftrack_action_handler.py b/pype/modules/ftrack/lib/ftrack_action_handler.py index aa6cb7c1b0..11952cf3c0 100644 --- a/pype/modules/ftrack/lib/ftrack_action_handler.py +++ b/pype/modules/ftrack/lib/ftrack_action_handler.py @@ -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( diff --git a/pype/modules/ftrack/lib/ftrack_base_handler.py b/pype/modules/ftrack/lib/ftrack_base_handler.py index 00a3cd8cdc..2a8f400101 100644 --- a/pype/modules/ftrack/lib/ftrack_base_handler.py +++ b/pype/modules/ftrack/lib/ftrack_base_handler.py @@ -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() From 8bacfc83ab861d42323df1771a595ddb1da24f13 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Mon, 21 Dec 2020 22:39:06 +0100 Subject: [PATCH 9/9] tweak to defaults --- pype/settings/defaults/project_settings/ftrack.json | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pype/settings/defaults/project_settings/ftrack.json b/pype/settings/defaults/project_settings/ftrack.json index 2bf11de468..a16295f84c 100644 --- a/pype/settings/defaults/project_settings/ftrack.json +++ b/pype/settings/defaults/project_settings/ftrack.json @@ -94,13 +94,11 @@ "ignored_statuses": [ "In Progress", "Omitted", - "On hold" + "On hold", + "Approved" ], "status_change": { - "In Progress": [], - "Ready": [ - "Not Ready" - ] + "In Progress": [] } }, "create_update_attributes": { @@ -167,7 +165,8 @@ "sync_to_avalon_local": { "enabled": true, "role_list": [ - "Pypeclub" + "Pypeclub", + "Administrator" ] }, "seed_project": {