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

Sync: Utils cleanup & Project Delete #61

Open
wants to merge 13 commits into
base: develop
Choose a base branch
from
30 changes: 5 additions & 25 deletions server/kitsu/push.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@
create_task,
delete_folder,
delete_task,
delete_project,
get_folder_by_kitsu_id,
get_task_by_kitsu_id,
get_user_by_kitsu_id,
update_project,

update_folder,
update_task,
)
Expand Down Expand Up @@ -230,16 +230,13 @@ async def sync_person(
existing_users: dict[str, Any],
entity_dict: "EntityDict",
):

first_name, entity_id= required_values(entity_dict, ["first_name", "id"])
last_name = entity_dict.get("last_name", '')
first_name, entity_id = required_values(entity_dict, ["first_name", "id"])
last_name = entity_dict.get("last_name", "")

# == check should Person entity be synced ==
# do not sync Kitsu API bots
if entity_dict.get("is_bot"):
logging.info(
f"skipping sync_person for Kitsu Bot: {first_name} {last_name}"
)
logging.info(f"skipping sync_person for Kitsu Bot: {first_name} {last_name}")
return

logging.info(f"sync_person: {first_name} {last_name}")
Expand Down Expand Up @@ -330,23 +327,6 @@ async def sync_project(
await update_project(project.name, **anatomy_data)


async def delete_project(
addon: "KitsuAddon",
user: "UserEntity",
project: "ProjectEntity",
entity_dict: "EntityDict",
):
logging.info("delete_project")
session = await Session.create(user)
headers = {"Authorization": f"Bearer {session.token}"}
# Check if group already exists
async with httpx.AsyncClient() as client:
await client.delete(
f"{entity_dict['ayon_server_url']}/api/projects/{project.name}",
headers=headers,
)


async def sync_folder(
addon: "KitsuAddon",
user: "UserEntity",
Expand Down Expand Up @@ -645,7 +625,7 @@ async def remove_entities(
continue

if entity_dict["type"] == "Project":
if settings.delete_ayon_projects.enabled:
if settings.sync_settings.delete_projects:
await update_project(
addon,
user,
Expand Down
199 changes: 97 additions & 102 deletions server/kitsu/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
UserEntity,
)
from ayon_server.events import dispatch_event
from ayon_server.exceptions import ForbiddenException
from ayon_server.lib.postgres import Postgres


Expand Down Expand Up @@ -86,7 +87,7 @@ async def get_task_by_kitsu_id(
"""Get an Ayon TaskEntity by its Kitsu ID"""

if existing_tasks and (kitsu_id in existing_tasks):
folder_id = existing_tasks[kitsu_id]
task_id = existing_tasks[kitsu_id]

else:
res = await Postgres.fetch(
Expand All @@ -98,9 +99,9 @@ async def get_task_by_kitsu_id(
)
if not res:
return None
folder_id = res[0]["id"]
task_id = res[0]["id"]

return await TaskEntity.load(project_name, folder_id)
return await TaskEntity.load(project_name, task_id)


async def create_folder(
Expand All @@ -119,16 +120,7 @@ async def create_folder(
project_name=project_name,
payload=payload,
)
await folder.save()
event = {
"topic": "entity.folder.created",
"description": f"Folder {folder.name} created",
"summary": {"entityId": folder.id, "parentId": folder.parent_id},
"project": project_name,
}

await dispatch_event(**event)
return folder
return await create_entity(project_name, folder)


async def update_folder(
Expand All @@ -138,32 +130,14 @@ async def update_folder(
**kwargs,
) -> bool:
folder = await FolderEntity.load(project_name, folder_id)
changed = False

payload: dict[str, Any] = {**kwargs, **create_name_and_label(name)}
kwargs: dict[str, Any] = {**kwargs, **create_name_and_label(name)}

for key in ["name", "label"]:
if key in payload and getattr(folder, key) != payload[key]:
setattr(folder, key, payload[key])
changed = True

for key, value in payload["attrib"].items():
if getattr(folder.attrib, key) != value:
setattr(folder.attrib, key, value)
if key not in folder.own_attrib:
folder.own_attrib.append(key)
changed = True
if changed:
await folder.save()
event = {
"topic": "entity.folder.updated",
"description": f"Folder {folder.name} updated",
"summary": {"entityId": folder.id, "parentId": folder.parent_id},
"project": project_name,
}
await dispatch_event(**event)

return changed
return await update_entity(
project_name,
folder,
kwargs,
attr_whitelist=["name", "label"],
)


async def delete_folder(
Expand All @@ -173,18 +147,7 @@ async def delete_folder(
**kwargs,
) -> None:
folder = await FolderEntity.load(project_name, folder_id)

# do we need this?
await folder.ensure_delete_access(user)

await folder.delete()
event = {
"topic": "entity.folder.deleted",
"description": f"Folder {folder.name} deleted",
"summary": {"entityId": folder.id, "parentId": folder.parent_id},
"project": project_name,
}
await dispatch_event(**event)
await delete_entity(project_name, folder, user)


async def create_task(
Expand All @@ -197,16 +160,7 @@ async def create_task(
project_name=project_name,
payload=payload,
)

await task.save()
event = {
"topic": "entity.task.created",
"description": f"Task {task.name} created",
"summary": {"entityId": task.id, "parentId": task.parent_id},
"project": project_name,
}
await dispatch_event(**event)
return task
return await create_entity(project_name, task)


async def update_task(
Expand All @@ -216,32 +170,14 @@ async def update_task(
**kwargs,
) -> bool:
task = await TaskEntity.load(project_name, task_id)
changed = False

payload = {**kwargs, **create_name_and_label(name)}
kwargs = {**kwargs, **create_name_and_label(name)}

# keys that can be updated
for key in ["name", "label", "status", "task_type", "assignees"]:
if key in payload and getattr(task, key) != payload[key]:
setattr(task, key, payload[key])
changed = True
if "attrib" in payload:
for key, value in payload["attrib"].items():
if getattr(task.attrib, key) != value:
setattr(task.attrib, key, value)
if key not in task.own_attrib:
task.own_attrib.append(key)
changed = True
if changed:
await task.save()
event = {
"topic": "entity.task.updated",
"description": f"Task {task.name} updated",
"summary": {"entityId": task.id, "parentId": task.parent_id},
"project": project_name,
}
await dispatch_event(**event)
return changed
return await update_entity(
project_name,
task,
kwargs,
attr_whitelist=["name", "label", "status", "task_type", "assignees"],
)


async def delete_task(
Expand All @@ -251,18 +187,7 @@ async def delete_task(
**kwargs,
) -> None:
task = await TaskEntity.load(project_name, task_id)

# do we need this?
await task.ensure_delete_access(user)

await task.delete()
event = {
"topic": "entity.task.deleted",
"description": f"Task {task.name} deleted",
"summary": {"entityId": task.id, "parentId": task.parent_id},
"project": project_name,
}
await dispatch_event(**event)
await delete_entity(project_name, task, user)


async def update_project(
Expand All @@ -281,25 +206,62 @@ async def update_project(
)


async def update_entity(project_name, entity, kwargs, attr_whitelist: list[str] | None = None):
"""updates the entity for given attribute whitelist, saves changes and dispatches an update event"""
async def delete_project(project_name: str, user: "UserEntity"):
project = await ProjectEntity.load(project_name)
if not user.is_manager:
raise ForbiddenException("You need to be a manager in order to delete projects")

return await delete_entity(project_name, project, user)


## ====================================================


async def create_entity(project_name: str, entity):
"""create a new entity and dispatch a create event, returns the entity"""
await entity.save()

summary = {
key: getattr(entity, key)
for key in {
"id",
"parent_id",
"name",
}
if hasattr(entity, key)
}

event = {
"topic": f"entity.{entity.entity_type}.created",
"description": f"{entity.entity_type} {entity.name} created",
"summary": summary,
"project": project_name,
}
await dispatch_event(**event)
return entity


async def update_entity(
project_name, entity, kwargs, attr_whitelist: list[str] | None = None
) -> bool:
"""updates the entity for given attribute whitelist, saves changes and dispatches an update event"""
changed = False
if attr_whitelist is None:
attr_whitelist = []

# keys that can be updated
for key in attr_whitelist:
if key in kwargs and getattr(entity, key) != kwargs[key]:
setattr(entity, key, kwargs[key])
logging.info(f"setattr {key}")
logging.debug(f"setattr {key} {getattr(entity, key)} => {kwargs[key]}")
changed = True
if "attrib" in kwargs:
for key, value in kwargs["attrib"].items():
if getattr(entity.attrib, key) != value:
setattr(entity.attrib, key, value)
if key not in entity.own_attrib:
entity.own_attrib.append(key)
logging.info(
logging.debug(
f"setattr attrib.{key} {getattr(entity.attrib, key)} => {value}"
)
changed = True
Expand All @@ -320,6 +282,39 @@ async def update_entity(project_name, entity, kwargs, attr_whitelist: list[str]
"summary": summary,
"project": project_name,
}
logging.info(f"dispatch_event: {event}")
logging.debug(f"dispatch_event: {event}")
await dispatch_event(**event)
return changed


async def delete_entity(
project_name: str,
entity,
user: "UserEntity",
) -> None:
"""delete the given entity after checking user permission, dispatches a delete event"""

# check user permission to delete this entity
if hasattr(entity, "ensure_delete_access") and callable(
entity.ensure_delete_access
):
await entity.ensure_delete_access(user)

await entity.delete()

summary = {}
if hasattr(entity, "id"):
summary["id"] = entity.id
if hasattr(entity, "parent_id"):
summary["parent_id"] = entity.parent_id
if hasattr(entity, "name"):
summary["name"] = entity.name

event = {
"topic": f"entity.{entity.entity_type}.deleted",
"description": f"{entity.entity_type} {entity.name} deleted",
"summary": summary,
"project": project_name,
}
logging.debug(f"dispatch_event: {event}")
await dispatch_event(**event)
Loading