Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AY-7217_Add support to sync task assignees and statuses for all entities #113

Merged
merged 22 commits into from
Dec 6, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 37 additions & 3 deletions server/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from typing import Any, Type
from typing import Any, Type, Optional
from nxtools import logging
from fastapi import Path

from ayon_server.addons import BaseServerAddon
from ayon_server.lib.postgres import Postgres
from .settings import ShotgridSettings
from nxtools import logging

from .settings import ShotgridSettings

SG_ID_ATTRIB = "shotgridId"
SG_TYPE_ATTRIB = "shotgridType"
Expand All @@ -16,6 +17,15 @@ class ShotgridAddon(BaseServerAddon):

frontend_scopes: dict[str, Any] = {"settings": {}}

def initialize(self) -> None:

# returning user for SG id value
self.add_endpoint(
"/get_ayon_name_by_sg_id/{sg_user_id}",
self.get_ayon_name_by_sg_id,
method="GET",
)

async def setup(self):
need_restart = await self.create_shotgrid_attributes()
if need_restart:
Expand Down Expand Up @@ -110,3 +120,27 @@ async def create_shotgrid_attributes(self) -> bool:
else:
logging.debug("Shotgrid Attributes already exist.")
return False

async def get_ayon_name_by_sg_id(
self,
sg_user_id: str = Path(
...,
description="Id of Shotgrid user ",
example="123",
)
) -> Optional[str]:
"""Queries user for specific 'sg_user_id' field in 'data'.
Field added during user synchronization to be explicit, not depending that
SG login will be same as AYON (which is not as @ is not allowed in AYON)
"""
query = f"""
SELECT
*
FROM public.users
WHERE data ? 'sg_user_id' AND data->>'sg_user_id' = '{sg_user_id}';
"""

res = await Postgres.fetch(query)
if res:
return res[0]["name"]
6 changes: 3 additions & 3 deletions services/leecher/leecher/listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,10 @@ def __init__(self):
}
self.custom_sg_attribs = set(self.custom_attribs_map.values())

# TODO: implement a way to handle status_list and tags
self.custom_attribs_map.update({
# "status": "status_list",
"tags": "tags"
"status": "status_list",
"tags": "tags",
"assignees": "task_assignees"
})

self.sg_enabled_entities = self.settings["compatibility_settings"]["shotgrid_enabled_entities"] # noqa: E501
Expand Down
6 changes: 6 additions & 0 deletions services/processor/processor/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ def __init__(self):
for attr in self.settings["compatibility_settings"]["custom_attribs_map"]
if attr["sg"]
}
self.custom_attribs_map.update({
"status": "status_list",
"tags": "tags",
"assignees": "task_assignees"
})

self.custom_attribs_types = {
attr["sg"]: (attr["type"], attr["scope"])
for attr in self.settings["compatibility_settings"]["custom_attribs_map"]
Expand Down
12 changes: 10 additions & 2 deletions services/shotgrid_common/ayon_shotgrid_hub/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ class AyonShotgridHub:
log = get_logger(__file__)
custom_attribs_map = {
"status": "status_list",
"tags": "tags"
"tags": "tags",
"assignees": "task_assignees"
}

def __init__(self,
Expand Down Expand Up @@ -419,6 +420,7 @@ def react_to_ayon_event(self, ayon_event):
ayon_event,
self._sg,
self._ay_project,
self.custom_attribs_map,
)
case "entity.task.attrib_changed" | "entity.folder.attrib_changed":
attrib_key = next(iter(ayon_event["payload"]["newValue"]))
Expand All @@ -434,7 +436,13 @@ def react_to_ayon_event(self, ayon_event):
self._ay_project,
self.custom_attribs_map,
)
case "entity.task.status_changed" | "entity.folder.status_changed" | "entity.task.tags_changed" | "entity.folder.tags_changed":
case (
"entity.task.status_changed"
| "entity.folder.status_changed"
| "entity.task.tags_changed"
| "entity.folder.tags_changed"
| "entity.task.assignees_changed"
):
# TODO: for some reason the payload here is not a dict but we know
# we always want to update the entity
update_sg_entity_from_ayon_event(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,9 @@ def match_ayon_hierarchy_in_shotgrid(
)

# entity was not synced before and need to be created
if not sg_entity_id or not sg_ay_dict:
# We only create new entities for Folders/Tasks entities
# For Version entities we only try update the status if it already exists
if sg_entity_type != "Version" and (not sg_entity_id or not sg_ay_dict):
sg_parent_entity = sg_session.find_one(
sg_ay_parent_entity["attribs"][SHOTGRID_TYPE_ATTRIB],
filters=[[
Expand All @@ -216,6 +218,10 @@ def match_ayon_hierarchy_in_shotgrid(
sg_ay_dicts[sg_entity_id] = sg_ay_dict
sg_ay_dicts_parents[sg_parent_entity["id"]].add(sg_entity_id)

if not sg_ay_dict:
log.warning(f"AYON entity {ay_entity} not found in SG, ignoring it")
continue

# add Shotgrid ID and type to AYON entity
ay_entity.attribs.set(
SHOTGRID_ID_ATTRIB,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,10 @@ def match_shotgrid_hierarchy_in_ayon(
sg_project_sync_status = "Failed"
else:
update_ay_entity_custom_attributes(
ay_entity, sg_ay_dict, custom_attribs_map
ay_entity,
sg_ay_dict,
custom_attribs_map,
ay_project=entity_hub.project_entity
)

# skip if no ay_entity is found
Expand Down
18 changes: 16 additions & 2 deletions services/shotgrid_common/ayon_shotgrid_hub/update_from_ayon.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,18 @@ def update_sg_entity_from_ayon_event(
new_attribs["tags"].append(
{"name": tag_name, "id": tag_id, "type": "Tag"}
)

elif ayon_event["topic"].endswith("assignees_changed"):
sg_assignees = []
for user_name in new_attribs:
ayon_user = ayon_api.get_user(user_name)
if not ayon_user or not ayon_user["data"].get("sg_user_id"):
log.warning(f"User {user_name} is not synched to SG yet.")
continue
sg_assignees.append(
{"type": "HumanUser",
"id": ayon_user["data"]["sg_user_id"]}
)
new_attribs = {"assignees": sg_assignees}
else:
log.warning(
"Unknown event type, skipping update of custom attribs.")
Expand Down Expand Up @@ -407,7 +418,7 @@ def _create_sg_entity(
sg_field_name: ay_entity.name,
CUST_FIELD_CODE_ID: ay_entity.id,
}
else:
elif ay_entity.entity_type == "folder":
data = {
"project": sg_project,
sg_field_name: ay_entity.name,
Expand All @@ -422,6 +433,9 @@ def _create_sg_entity(
log.warning(f"Cannot convert '{sg_parent_id} to parent "
"it correctly.")

if not data:
return

# Fill up data with any extra attributes from AYON we want to sync to SG
data.update(get_sg_custom_attributes_data(
sg_session,
Expand Down
22 changes: 19 additions & 3 deletions services/shotgrid_common/ayon_shotgrid_hub/update_from_shotgrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,21 +394,28 @@ def update_ayon_entity_from_sg_event(

# Ensure AYON Entity has the correct ShotGrid ID
ayon_entity_sg_id = str(
ay_entity.attribs.get_attribute(SHOTGRID_ID_ATTRIB).value)
ay_entity.attribs.get(SHOTGRID_ID_ATTRIB, "")
)
sg_entity_sg_id = str(
sg_ay_dict["attribs"].get(SHOTGRID_ID_ATTRIB, "")
)
log.debug(f"Updating AYON Entity: {ay_entity.name}")

if ayon_entity_sg_id != sg_entity_sg_id:
# We need to check for existence in `ayon_entity_sg_id` as it could be
# that it's a new entity and it doesn't have a ShotGrid ID yet.
if ayon_entity_sg_id and ayon_entity_sg_id != sg_entity_sg_id:
log.error("Mismatching ShotGrid IDs, aborting...")
raise ValueError("Mismatching ShotGrid IDs, aborting...")

ay_entity.name = sg_ay_dict["name"]
ay_entity.label = sg_ay_dict["label"]

# TODO: Only update the updated fields in the event
update_ay_entity_custom_attributes(
ay_entity, sg_ay_dict, custom_attribs_map
ay_entity,
sg_ay_dict,
custom_attribs_map,
ay_project=ayon_entity_hub.project_entity
)

ayon_entity_hub.commit_changes()
Expand All @@ -422,6 +429,15 @@ def update_ayon_entity_from_sg_event(
}
)

ay_entity.attribs.set(
SHOTGRID_ID_ATTRIB,
sg_ay_dict["attribs"].get(SHOTGRID_ID_ATTRIB, "")
)
ay_entity.attribs.set(
SHOTGRID_TYPE_ATTRIB,
sg_ay_dict["attribs"].get(SHOTGRID_TYPE_ATTRIB, "")
)

return ay_entity


Expand Down
2 changes: 1 addition & 1 deletion services/shotgrid_common/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
"content",
"entity",
"step",
"task_assignees",
CUST_FIELD_CODE_ID,
CUST_FIELD_CODE_SYNC,
]
Expand Down Expand Up @@ -161,4 +162,3 @@
class FOLDER_REPARENTING_TYPE:
ROOT_RELOCATE = "root_relocate"
TYPE_GROUPING = "type_grouping"

Loading
Loading