Merge pull request #350 from ynput/enhancement/applications-live-attributes-update

Applications: Live attributes update
This commit is contained in:
murphy 2024-04-04 09:45:45 +02:00 committed by GitHub
commit fa515ea252
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 121 additions and 40 deletions

View file

@ -3,6 +3,7 @@ import json
import copy
from ayon_server.addons import BaseServerAddon, AddonLibrary
from ayon_server.entities.core import attribute_library
from ayon_server.lib.postgres import Postgres
from .version import __version__
@ -118,9 +119,28 @@ class ApplicationsAddon(BaseServerAddon):
)
async def setup(self):
need_restart = await self.create_applications_attribute()
need_restart = await self.create_required_attributes()
if need_restart:
self.request_server_restart()
await self._update_enums()
def _get_applications_def(self):
return {
"name": "applications",
"type": "list_of_strings",
"title": "Applications",
"scope": ["project"],
"enum":[],
}
def _get_tools_def(self):
return {
"name": "tools",
"type": "list_of_strings",
"title": "Tools",
"scope": ["project", "folder", "task"],
"enum":[],
}
async def create_applications_attribute(self) -> bool:
"""Make sure there are required attributes which ftrack addon needs.
@ -129,6 +149,73 @@ class ApplicationsAddon(BaseServerAddon):
bool: 'True' if an attribute was created or updated.
"""
need_restart = await self.create_required_attributes()
await self._update_enums()
return need_restart
async def create_required_attributes(self) -> bool:
"""Make sure there are required 'applications' and 'tools' attributes.
This only checks for the existence of the attributes, it does not populate
them with any data. When an attribute is added, server needs to be restarted,
while adding enum data to the attribute does not require a restart.
Returns:
bool: 'True' if an attribute was created or updated.
"""
# keep track of the last attribute position (for adding new attributes)
apps_attribute_data = self._get_applications_def()
tools_attribute_data = self._get_tools_def()
apps_attrib_name = apps_attribute_data["name"]
tools_attrib_name = tools_attribute_data["name"]
async with Postgres.acquire() as conn, conn.transaction():
query = "SELECT BOOL_OR(name = 'applications') AS has_applications, BOOL_OR(name = 'tools') AS has_tools FROM attributes;"
result = (await conn.fetch(query))[0]
attributes_to_create = {}
if not result["has_applications"]:
attributes_to_create[apps_attrib_name] = {
"scope": apps_attribute_data["scope"],
"data": {
"title": apps_attribute_data["title"],
"type": apps_attribute_data["type"],
"enum": [],
}
}
if not result["has_tools"]:
attributes_to_create[tools_attrib_name] = {
"scope": tools_attribute_data["scope"],
"data": {
"title": tools_attribute_data["title"],
"type": tools_attribute_data["type"],
"enum": [],
},
}
needs_restart = False
# when any of the required attributes are not present, add them
# and return 'True' to indicate that server needs to be restarted
for name, payload in attributes_to_create.items():
insert_query = "INSERT INTO attributes (name, scope, data, position) VALUES ($1, $2, $3, (SELECT COALESCE(MAX(position), 0) + 1 FROM attributes)) ON CONFLICT DO NOTHING"
await conn.execute(
insert_query,
name,
payload["scope"],
payload["data"],
)
needs_restart = True
return needs_restart
async def _update_enums(self):
"""Updates applications and tools enums based on the addon settings.
This method is called when the addon is started (after we are sure that the
'applications' and 'tools' attributes exist) and when the addon settings are
updated (using on_settings_updated method).
"""
instance = AddonLibrary.getinstance()
app_defs = instance.data.get(self.name)
all_applications = []
@ -148,33 +235,32 @@ class ApplicationsAddon(BaseServerAddon):
merge_groups(all_applications, app_groups)
merge_groups(all_tools, studio_settings["tool_groups"])
query = "SELECT name, position, scope, data from public.attributes"
apps_attrib_name = "applications"
tools_attrib_name = "tools"
apps_enum = get_enum_items_from_groups(all_applications)
tools_enum = get_enum_items_from_groups(all_tools)
apps_attribute_data = {
"type": "list_of_strings",
"title": "Applications",
"enum": apps_enum
"enum": apps_enum,
}
tools_attribute_data = {
"type": "list_of_strings",
"title": "Tools",
"enum": tools_enum
"enum": tools_enum,
}
apps_scope = ["project"]
tools_scope = ["project", "folder", "task"]
apps_match_position = None
apps_matches = False
tools_match_position = None
tools_matches = False
position = 1
async for row in Postgres.iterate(query):
position += 1
async for row in Postgres.iterate(
"SELECT name, position, scope, data from public.attributes"
):
if row["name"] == apps_attrib_name:
# Check if scope is matching ftrack addon requirements
if (
@ -182,7 +268,6 @@ class ApplicationsAddon(BaseServerAddon):
and row["data"].get("enum") == apps_enum
):
apps_matches = True
apps_match_position = row["position"]
elif row["name"] == tools_attrib_name:
if (
@ -190,45 +275,41 @@ class ApplicationsAddon(BaseServerAddon):
and row["data"].get("enum") == tools_enum
):
tools_matches = True
tools_match_position = row["position"]
if apps_matches and tools_matches:
return False
return
postgre_query = "\n".join((
"INSERT INTO public.attributes",
" (name, position, scope, data)",
"VALUES",
" ($1, $2, $3, $4)",
"ON CONFLICT (name)",
"DO UPDATE SET",
" scope = $3,",
" data = $4",
))
if not apps_matches:
# Reuse position from found attribute
if apps_match_position is None:
apps_match_position = position
position += 1
await Postgres.execute(
postgre_query,
apps_attrib_name,
apps_match_position,
"""
UPDATE attributes SET
scope = $1,
data = $2
WHERE
name = $3
""",
apps_scope,
apps_attribute_data,
apps_attrib_name,
)
if not tools_matches:
if tools_match_position is None:
tools_match_position = position
position += 1
await Postgres.execute(
postgre_query,
tools_attrib_name,
tools_match_position,
"""
UPDATE attributes SET
scope = $1,
data = $2
WHERE
name = $3
""",
tools_scope,
tools_attribute_data,
tools_attrib_name,
)
return True
# Reset attributes cache on server
await attribute_library.load()
async def on_settings_changed(self, *args, **kwargs):
_ = args, kwargs
await self._update_enums()

View file

@ -1 +1 @@
__version__ = "0.1.8"
__version__ = "0.1.9"