mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-02 00:44:52 +01:00
SyncServer - change settings to new format
Sites are configured in System Schemas and defaults were modified All providers carry dict of modifiable properties for Local Settings
This commit is contained in:
parent
49e44f0d70
commit
1aafb697e4
11 changed files with 212 additions and 127 deletions
|
|
@ -27,37 +27,16 @@ class AbstractProvider:
|
|||
(boolean)
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
@abc.abstractmethod
|
||||
def set_editable_properties(self):
|
||||
def get_configurable_items(cls):
|
||||
"""
|
||||
Sets dictionary of editable properties with scopes.
|
||||
Returns filtered dict of editable properties
|
||||
|
||||
Example:
|
||||
{ 'credentials_url': {'scopes': [utils.EditableScopes.SYSTEM],
|
||||
'type': 'text'}}
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_editable_properties(self, scopes):
|
||||
"""
|
||||
Returns filtered list of editable properties
|
||||
|
||||
Args:
|
||||
scopes (list) of utils.EditableScopes (optional - filter on)
|
||||
|
||||
Returns:
|
||||
(dict)
|
||||
"""
|
||||
if not scopes:
|
||||
return self._editable_properties
|
||||
|
||||
editable = {}
|
||||
for scope in scopes:
|
||||
for key, properties in self._editable_properties.items():
|
||||
if scope in properties['scope']:
|
||||
editable[key] = properties
|
||||
|
||||
return editable
|
||||
|
||||
@abc.abstractmethod
|
||||
def upload_file(self, source_path, path,
|
||||
|
|
|
|||
|
|
@ -1,22 +1,32 @@
|
|||
from __future__ import print_function
|
||||
import os.path
|
||||
from googleapiclient.discovery import build
|
||||
import google.oauth2.service_account as service_account
|
||||
from googleapiclient import errors
|
||||
from .abstract_provider import AbstractProvider
|
||||
from googleapiclient.http import MediaFileUpload, MediaIoBaseDownload
|
||||
import time
|
||||
import sys
|
||||
from setuptools.extern import six
|
||||
|
||||
from openpype.api import Logger
|
||||
from openpype.api import get_system_settings
|
||||
from .abstract_provider import AbstractProvider
|
||||
from ..utils import time_function, ResumableError, EditableScopes
|
||||
import time
|
||||
|
||||
log = Logger().get_logger("SyncServer")
|
||||
|
||||
try:
|
||||
from googleapiclient.discovery import build
|
||||
import google.oauth2.service_account as service_account
|
||||
from googleapiclient import errors
|
||||
from googleapiclient.http import MediaFileUpload, MediaIoBaseDownload
|
||||
except (ImportError, SyntaxError):
|
||||
if six.PY3:
|
||||
six.reraise(*sys.exc_info())
|
||||
|
||||
# handle imports from Python 2 hosts - in those only basic methods are used
|
||||
log.warning("Import failed, imported from Python 2, operations will fail.")
|
||||
|
||||
SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly',
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive.readonly'] # for write|delete
|
||||
|
||||
log = Logger().get_logger("SyncServer")
|
||||
|
||||
|
||||
class GDriveHandler(AbstractProvider):
|
||||
"""
|
||||
|
|
@ -54,8 +64,7 @@ class GDriveHandler(AbstractProvider):
|
|||
self.active = False
|
||||
self.project_name = project_name
|
||||
self.site_name = site_name
|
||||
|
||||
self._editable_properties = {}
|
||||
self.service = None
|
||||
|
||||
self.presets = presets
|
||||
if not self.presets:
|
||||
|
|
@ -63,7 +72,7 @@ class GDriveHandler(AbstractProvider):
|
|||
format(site_name))
|
||||
return
|
||||
|
||||
if not os.path.exists(self.presets["credentials_url"]):
|
||||
if not os.path.exists(self.presets.get("credentials_url", "")):
|
||||
log.info("Sync Server: No credentials for Gdrive provider! ")
|
||||
return
|
||||
|
||||
|
|
@ -78,7 +87,6 @@ class GDriveHandler(AbstractProvider):
|
|||
|
||||
self._tree = tree
|
||||
self.active = True
|
||||
self.set_editable_properties()
|
||||
|
||||
def is_active(self):
|
||||
"""
|
||||
|
|
@ -86,18 +94,29 @@ class GDriveHandler(AbstractProvider):
|
|||
Returns:
|
||||
(boolean)
|
||||
"""
|
||||
return self.active
|
||||
return self.service is not None
|
||||
|
||||
def set_editable_properties(self):
|
||||
@classmethod
|
||||
def get_configurable_items(cls):
|
||||
"""
|
||||
Returns filtered dict of editable properties.
|
||||
|
||||
|
||||
Returns:
|
||||
(dict)
|
||||
"""
|
||||
editable = {
|
||||
# credentials could be override on Project or User level
|
||||
'credential_url': {'scope': [EditableScopes.PROJECT,
|
||||
EditableScopes.LOCAL],
|
||||
'label': "Credentials url",
|
||||
'type': 'text'},
|
||||
|
||||
'roots': {'scope': [EditableScopes.PROJECT],
|
||||
'type': 'dict'}
|
||||
# roots could be override only on Project leve, User cannot
|
||||
'root': {'scope': [EditableScopes.PROJECT],
|
||||
'label': "Roots",
|
||||
'type': 'dict'}
|
||||
}
|
||||
self._editable_properties = editable
|
||||
return editable
|
||||
|
||||
def get_roots_config(self, anatomy=None):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -65,6 +65,17 @@ class ProviderFactory:
|
|||
info = self._get_creator_info(provider)
|
||||
return info[1]
|
||||
|
||||
def get_provider_configurable_items(self, provider):
|
||||
"""
|
||||
Returns dict of modifiable properties for 'provider'.
|
||||
|
||||
Provider contains information which its properties and on what
|
||||
level could be override
|
||||
"""
|
||||
provider_info = self._get_creator_info(provider)
|
||||
|
||||
return provider_info[0].get_configurable_items()
|
||||
|
||||
def _get_creator_info(self, provider):
|
||||
"""
|
||||
Collect all necessary info for provider. Currently only creator
|
||||
|
|
|
|||
|
|
@ -25,18 +25,25 @@ class LocalDriveHandler(AbstractProvider):
|
|||
self._editable_properties = {}
|
||||
|
||||
self.active = self.is_active()
|
||||
self.set_editable_properties()
|
||||
|
||||
def is_active(self):
|
||||
return True
|
||||
|
||||
def set_editable_properties(self):
|
||||
@classmethod
|
||||
def get_configurable_items(cls):
|
||||
"""
|
||||
Returns filtered dict of editable properties
|
||||
|
||||
Returns:
|
||||
(dict)
|
||||
"""
|
||||
editable = {
|
||||
'roots': {'scope': [EditableScopes.PROJECT,
|
||||
EditableScopes.LOCAL],
|
||||
'type': 'dict'}
|
||||
'root': {'scope': [EditableScopes.PROJECT,
|
||||
EditableScopes.LOCAL],
|
||||
'label': "Roots",
|
||||
'type': 'dict'}
|
||||
}
|
||||
self._editable_properties = editable
|
||||
return editable
|
||||
|
||||
def upload_file(self, source_path, target_path,
|
||||
server, collection, file, representation, site,
|
||||
|
|
|
|||
|
|
@ -9,10 +9,12 @@ from .. import PypeModule, ITrayModule
|
|||
from openpype.api import (
|
||||
Anatomy,
|
||||
get_project_settings,
|
||||
get_system_settings,
|
||||
get_local_site_id)
|
||||
from openpype.lib import PypeLogger
|
||||
|
||||
from .providers.local_drive import LocalDriveHandler
|
||||
from .providers import lib
|
||||
|
||||
from .utils import time_function, SyncStatus
|
||||
|
||||
|
|
@ -390,31 +392,99 @@ class SyncServerModule(PypeModule, ITrayModule):
|
|||
|
||||
return remote_site
|
||||
|
||||
def get_configurable_items(self):
|
||||
pass
|
||||
|
||||
def get_configurable_items_for_site(self, project_name, site_name):
|
||||
def get_configurable_items(self, scope=None):
|
||||
"""
|
||||
Returns list of items that should be configurable by User
|
||||
Returns list of items that could be configurable for all projects.
|
||||
|
||||
Could be filtered by 'scope' argument (list)
|
||||
|
||||
Args:
|
||||
scope (list of utils.EditableScope) (optional)
|
||||
|
||||
Returns:
|
||||
(list of dict)
|
||||
[{key:"root", label:"root", value:"valueFromSettings"}]
|
||||
(dict of dict)
|
||||
{projectA: {
|
||||
siteA : {
|
||||
key:"root", label:"root", value:"valueFromSettings"
|
||||
}
|
||||
}
|
||||
"""
|
||||
# sites = set(self.get_active_sites(project_name),
|
||||
# self.get_remote_sites(project_name))
|
||||
# for site in sites:
|
||||
# if site_name
|
||||
|
||||
def _get_configurable_items_for_project(self, project_name):
|
||||
from .providers import lib
|
||||
sites = set(self.get_active_sites(project_name),
|
||||
self.get_remote_sites(project_name))
|
||||
editable = {}
|
||||
for site in sites:
|
||||
provider_name = self.get_provider_for_site(project_name, site)
|
||||
for project in self.connection.projects():
|
||||
project_name = project["name"]
|
||||
items = self.get_configurable_items_for_project(project_name,
|
||||
scope)
|
||||
editable.update(items)
|
||||
|
||||
return editable
|
||||
|
||||
def get_configurable_items_for_project(self, project_name, scope=None):
|
||||
"""
|
||||
Returns list of items that could be configurable for specific
|
||||
'project_name'
|
||||
|
||||
Args:
|
||||
project_name (str)
|
||||
scope (list of utils.EditableScope) (optional)
|
||||
|
||||
Returns:
|
||||
(dict of dict)
|
||||
{projectA: {
|
||||
siteA : {
|
||||
key:"root", label:"root", value:"valueFromSettings"
|
||||
}
|
||||
}
|
||||
"""
|
||||
sites = set(self.get_active_sites(project_name)) | \
|
||||
set(self.get_remote_sites(project_name))
|
||||
editable = {}
|
||||
for site_name in sites:
|
||||
items = self.get_configurable_items_for_site(project_name,
|
||||
site_name,
|
||||
scope)
|
||||
editable.update(items)
|
||||
|
||||
return editable
|
||||
|
||||
def get_configurable_items_for_site(self, project_name, site_name,
|
||||
scope=None):
|
||||
"""
|
||||
Returns list of items that could be configurable.
|
||||
|
||||
Args:
|
||||
project_name (str)
|
||||
site_name (str)
|
||||
scope (list of utils.EditableScope) (optional)
|
||||
|
||||
Returns:
|
||||
(dict of dict)
|
||||
{projectA: {
|
||||
siteA : {
|
||||
key:"root", label:"root", value:"valueFromSettings"
|
||||
}
|
||||
}
|
||||
"""
|
||||
provider_name = self.get_provider_for_site(site=site_name)
|
||||
items = lib.factory.get_provider_configurable_items(provider_name,
|
||||
scope)
|
||||
|
||||
if not scope:
|
||||
return {project_name: {site_name: items}}
|
||||
|
||||
editable = {}
|
||||
sync_s = self.get_sync_project_setting(project_name, True)
|
||||
for scope in set([scope]):
|
||||
for key, properties in items.items():
|
||||
if scope in properties['scope']:
|
||||
val = sync_s.get("sites", {}).get(site_name, {}).get(key)
|
||||
editable = {
|
||||
"key": key,
|
||||
"value": val,
|
||||
"label": properties.get("label"),
|
||||
"type": properties.get("type"),
|
||||
}
|
||||
|
||||
return {project_name: {site_name: editable}}
|
||||
|
||||
def reset_timer(self):
|
||||
"""
|
||||
|
|
@ -432,7 +502,7 @@ class SyncServerModule(PypeModule, ITrayModule):
|
|||
for project in self.connection.projects():
|
||||
project_name = project["name"]
|
||||
project_settings = self.get_sync_project_setting(project_name)
|
||||
if project_settings:
|
||||
if project_settings and project_settings.get("enabled"):
|
||||
enabled_projects.append(project_name)
|
||||
|
||||
return enabled_projects
|
||||
|
|
@ -584,55 +654,60 @@ class SyncServerModule(PypeModule, ITrayModule):
|
|||
|
||||
return self._sync_project_settings
|
||||
|
||||
def set_sync_project_settings(self):
|
||||
def set_sync_project_settings(self, exclude_locals=False):
|
||||
"""
|
||||
Set sync_project_settings for all projects (caching)
|
||||
|
||||
Args:
|
||||
exclude_locals (bool): ignore overrides from Local Settings
|
||||
For performance
|
||||
"""
|
||||
sync_project_settings = {}
|
||||
|
||||
# sites are now configured system wide
|
||||
sys_sett = get_system_settings()
|
||||
sync_sett = sys_sett["modules"].get("sync_server")
|
||||
system_sites = {}
|
||||
for site, detail in sync_sett.get("sites", {}).items():
|
||||
system_sites[site] = detail
|
||||
|
||||
for collection in self.connection.database.collection_names(False):
|
||||
sync_settings = self._parse_sync_settings_from_settings(
|
||||
get_project_settings(collection))
|
||||
if sync_settings:
|
||||
default_sites = self._get_default_site_configs()
|
||||
sync_settings['sites'].update(default_sites)
|
||||
sync_project_settings[collection] = sync_settings
|
||||
get_project_settings(collection,
|
||||
exclude_locals=exclude_locals))
|
||||
|
||||
default_sites = self._get_default_site_configs()
|
||||
sync_settings['sites'].update(default_sites)
|
||||
sync_settings['sites'].update(system_sites)
|
||||
sync_project_settings[collection] = sync_settings
|
||||
|
||||
if not sync_project_settings:
|
||||
log.info("No enabled and configured projects for sync.")
|
||||
|
||||
self._sync_project_settings = sync_project_settings
|
||||
|
||||
def get_sync_project_setting(self, project_name):
|
||||
def get_sync_project_setting(self, project_name, exclude_locals=False):
|
||||
""" Handles pulling sync_server's settings for enabled 'project_name'
|
||||
|
||||
Args:
|
||||
project_name (str): used in project settings
|
||||
exclude_locals (bool): ignore overrides from Local Settings
|
||||
Returns:
|
||||
(dict): settings dictionary for the enabled project,
|
||||
empty if no settings or sync is disabled
|
||||
"""
|
||||
# presets set already, do not call again and again
|
||||
# self.log.debug("project preset {}".format(self.presets))
|
||||
if self.sync_project_settings and \
|
||||
self.sync_project_settings.get(project_name):
|
||||
return self.sync_project_settings.get(project_name)
|
||||
if not self.sync_project_settings or \
|
||||
not self.sync_project_settings.get(project_name):
|
||||
self.set_sync_project_settings(project_name, exclude_locals)
|
||||
|
||||
settings = get_project_settings(project_name)
|
||||
return self._parse_sync_settings_from_settings(settings)
|
||||
return self.sync_project_settings.get(project_name)
|
||||
|
||||
def _parse_sync_settings_from_settings(self, settings):
|
||||
""" settings from api.get_project_settings, TOOD rename """
|
||||
sync_settings = settings.get("global").get("sync_server")
|
||||
if not sync_settings:
|
||||
log.info("No project setting not syncing.")
|
||||
return {}
|
||||
if sync_settings.get("enabled"):
|
||||
return sync_settings
|
||||
|
||||
return {}
|
||||
return sync_settings
|
||||
|
||||
def _get_default_site_configs(self):
|
||||
"""
|
||||
|
|
@ -643,16 +718,29 @@ class SyncServerModule(PypeModule, ITrayModule):
|
|||
get_local_site_id(): default_config}
|
||||
return all_sites
|
||||
|
||||
def get_provider_for_site(self, project_name, site):
|
||||
def get_provider_for_site(self, project_name=None, site=None):
|
||||
"""
|
||||
Return provider name for site.
|
||||
Return provider name for site (unique name across all projects.
|
||||
"""
|
||||
site_preset = self.get_sync_project_setting(project_name)["sites"].\
|
||||
get(site)
|
||||
if site_preset:
|
||||
return site_preset["provider"]
|
||||
sites = {self.DEFAULT_SITE: "local_drive",
|
||||
self.LOCAL_SITE: "local_drive",
|
||||
get_local_site_id(): "local_drive"}
|
||||
|
||||
return "NA"
|
||||
if site in sites.keys():
|
||||
return sites[site]
|
||||
|
||||
if project_name: # backward compatibility
|
||||
proj_settings = self.get_sync_project_setting(project_name)
|
||||
provider = proj_settings.get("sites", {}).get(site, {}).\
|
||||
get("provider")
|
||||
return provider
|
||||
|
||||
sys_sett = get_system_settings()
|
||||
sync_sett = sys_sett["modules"].get("sync_server")
|
||||
for site, detail in sync_sett.get("sites", {}).items():
|
||||
sites[site] = detail.get("provider")
|
||||
|
||||
return sites.get(site, 'N/A')
|
||||
|
||||
@time_function
|
||||
def get_sync_representations(self, collection, active_site, remote_site):
|
||||
|
|
@ -1130,7 +1218,7 @@ class SyncServerModule(PypeModule, ITrayModule):
|
|||
format(site_name))
|
||||
return
|
||||
|
||||
provider_name = self.get_provider_for_site(collection, site_name)
|
||||
provider_name = self.get_provider_for_site(site=site_name)
|
||||
|
||||
if provider_name == 'local_drive':
|
||||
query = {
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ def translate_provider_for_icon(sync_server, project, site):
|
|||
"""
|
||||
if site == sync_server.DEFAULT_SITE:
|
||||
return sync_server.DEFAULT_SITE
|
||||
return sync_server.get_provider_for_site(project, site)
|
||||
return sync_server.get_provider_for_site(site=site)
|
||||
|
||||
|
||||
def get_item_by_id(model, object_id):
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ class _SyncRepresentationWidget(QtWidgets.QWidget):
|
|||
|
||||
for site, progress in {active_site: local_progress,
|
||||
remote_site: remote_progress}.items():
|
||||
provider = self.sync_server.get_provider_for_site(project, site)
|
||||
provider = self.sync_server.get_provider_for_site(site=site)
|
||||
if provider == 'local_drive':
|
||||
if 'studio' in site:
|
||||
txt = " studio version"
|
||||
|
|
|
|||
|
|
@ -267,13 +267,6 @@
|
|||
"remote_site": "studio"
|
||||
},
|
||||
"sites": {
|
||||
"gdrive": {
|
||||
"provider": "gdrive",
|
||||
"credentials_url": "",
|
||||
"root": {
|
||||
"work": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"project_plugins": {
|
||||
|
|
|
|||
|
|
@ -135,7 +135,8 @@
|
|||
"workspace_name": ""
|
||||
},
|
||||
"sync_server": {
|
||||
"enabled": false
|
||||
"enabled": false,
|
||||
"sites": {}
|
||||
},
|
||||
"deadline": {
|
||||
"enabled": true,
|
||||
|
|
|
|||
|
|
@ -231,21 +231,17 @@ class ProvidersEnum(BaseEnumEntity):
|
|||
self.placeholder = None
|
||||
|
||||
def _get_enum_values(self):
|
||||
# from openpype.modules.sync_server.providers import lib as lib_providers
|
||||
#
|
||||
# providers = lib_providers.factory.providers
|
||||
#
|
||||
# valid_keys = set()
|
||||
# enum_items = []
|
||||
# for provider_code, provider_info in providers.items():
|
||||
# provider, _ = provider_info
|
||||
# enum_items.append({provider_code: provider.LABEL})
|
||||
# valid_keys.add(provider_code)
|
||||
from openpype.modules.sync_server.providers import lib as lib_providers
|
||||
|
||||
providers = lib_providers.factory.providers
|
||||
|
||||
valid_keys = set()
|
||||
enum_items = []
|
||||
if not valid_keys:
|
||||
enum_items.append({'': 'N/A'})
|
||||
valid_keys.add('')
|
||||
valid_keys.add('')
|
||||
enum_items = [{'': 'Choose Provider'}]
|
||||
for provider_code, provider_info in providers.items():
|
||||
provider, _ = provider_info
|
||||
enum_items.append({provider_code: provider.LABEL})
|
||||
valid_keys.add(provider_code)
|
||||
|
||||
return enum_items, valid_keys
|
||||
|
||||
|
|
@ -259,7 +255,3 @@ class ProvidersEnum(BaseEnumEntity):
|
|||
self._current_value = value_on_not_set
|
||||
|
||||
self.value_on_not_set = value_on_not_set
|
||||
|
||||
|
||||
# class ActiveSiteEnum
|
||||
# class RemoteSiteEnum
|
||||
|
|
@ -49,11 +49,6 @@
|
|||
{
|
||||
"type": "dict",
|
||||
"children": [
|
||||
{
|
||||
"type": "text",
|
||||
"key": "provider",
|
||||
"label": "Provider"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"key": "credentials_url",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue