mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 12:54:40 +01:00
204 lines
5.5 KiB
Python
204 lines
5.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Tools used in **Igniter** GUI."""
|
|
import os
|
|
from typing import Union
|
|
from urllib.parse import urlparse, parse_qs, ParseResult
|
|
from pathlib import Path
|
|
import platform
|
|
|
|
import certifi
|
|
from pymongo import MongoClient
|
|
from pymongo.errors import (
|
|
ServerSelectionTimeoutError,
|
|
InvalidURI,
|
|
ConfigurationError,
|
|
OperationFailure
|
|
)
|
|
|
|
|
|
def add_certificate_path_to_mongo_url(mongo_url):
|
|
"""Check if should add ca certificate to mongo url.
|
|
|
|
Since 30.9.2021 cloud mongo requires newer certificates that are not
|
|
available on most of workstation. This adds path to certifi certificate
|
|
which is valid for it. To add the certificate path url must have scheme
|
|
'mongodb+srv' or has 'ssl=true' or 'tls=true' in url query.
|
|
"""
|
|
parsed = urlparse(mongo_url)
|
|
query = parse_qs(parsed.query)
|
|
lowered_query_keys = set(key.lower() for key in query.keys())
|
|
add_certificate = False
|
|
# Check if url 'ssl' or 'tls' are set to 'true'
|
|
for key in ("ssl", "tls"):
|
|
if key in query and "true" in query["ssl"]:
|
|
add_certificate = True
|
|
break
|
|
|
|
# Check if url contains 'mongodb+srv'
|
|
if not add_certificate and parsed.scheme == "mongodb+srv":
|
|
add_certificate = True
|
|
|
|
# Check if url does already contain certificate path
|
|
if add_certificate and "tlscafile" in lowered_query_keys:
|
|
add_certificate = False
|
|
|
|
# Add certificate path to mongo url
|
|
if add_certificate:
|
|
path = parsed.path
|
|
if not path:
|
|
path = "/admin"
|
|
query = parsed.query
|
|
tls_query = "tlscafile={}".format(certifi.where())
|
|
if not query:
|
|
query = tls_query
|
|
else:
|
|
query = "&".join((query, tls_query))
|
|
new_url = ParseResult(
|
|
parsed.scheme, parsed.netloc, path,
|
|
parsed.params, query, parsed.fragment
|
|
)
|
|
mongo_url = new_url.geturl()
|
|
|
|
return mongo_url
|
|
|
|
|
|
def validate_mongo_connection(cnx: str) -> (bool, str):
|
|
"""Check if provided mongodb URL is valid.
|
|
|
|
Args:
|
|
cnx (str): URL to validate.
|
|
|
|
Returns:
|
|
(bool, str): True if ok, False if not and reason in str.
|
|
|
|
"""
|
|
parsed = urlparse(cnx)
|
|
if parsed.scheme not in ["mongodb", "mongodb+srv"]:
|
|
return False, "Not mongodb schema"
|
|
|
|
kwargs = {
|
|
"serverSelectionTimeoutMS": 2000
|
|
}
|
|
try:
|
|
client = MongoClient(cnx, **kwargs)
|
|
client.server_info()
|
|
with client.start_session():
|
|
pass
|
|
client.close()
|
|
except ServerSelectionTimeoutError as e:
|
|
return False, f"Cannot connect to server {cnx} - {e}"
|
|
except ValueError:
|
|
return False, f"Invalid port specified {parsed.port}"
|
|
except (ConfigurationError, OperationFailure, InvalidURI) as exc:
|
|
return False, str(exc)
|
|
else:
|
|
return True, "Connection is successful"
|
|
|
|
|
|
def validate_mongo_string(mongo: str) -> (bool, str):
|
|
"""Validate string if it is mongo url acceptable by **Igniter**..
|
|
|
|
Args:
|
|
mongo (str): String to validate.
|
|
|
|
Returns:
|
|
(bool, str):
|
|
True if valid, False if not and in second part of tuple
|
|
the reason why it failed.
|
|
|
|
"""
|
|
if not mongo:
|
|
return True, "empty string"
|
|
return validate_mongo_connection(mongo)
|
|
|
|
|
|
def validate_path_string(path: str) -> (bool, str):
|
|
"""Validate string if it is path to OpenPype repository.
|
|
|
|
Args:
|
|
path (str): Path to validate.
|
|
|
|
|
|
Returns:
|
|
(bool, str):
|
|
True if valid, False if not and in second part of tuple
|
|
the reason why it failed.
|
|
|
|
"""
|
|
if not path:
|
|
return False, "empty string"
|
|
|
|
if not Path(path).exists():
|
|
return False, "path doesn't exists"
|
|
|
|
if not Path(path).is_dir():
|
|
return False, "path is not directory"
|
|
|
|
return True, "valid path"
|
|
|
|
|
|
def get_openpype_global_settings(url: str) -> dict:
|
|
"""Load global settings from Mongo database.
|
|
|
|
We are loading data from database `openpype` and collection `settings`.
|
|
There we expect document type `global_settings`.
|
|
|
|
Args:
|
|
url (str): MongoDB url.
|
|
|
|
Returns:
|
|
dict: With settings data. Empty dictionary is returned if not found.
|
|
"""
|
|
try:
|
|
# Create mongo connection
|
|
client = MongoClient(url)
|
|
# Access settings collection
|
|
col = client["openpype"]["settings"]
|
|
# Query global settings
|
|
global_settings = col.find_one({"type": "global_settings"}) or {}
|
|
# Close Mongo connection
|
|
client.close()
|
|
|
|
except Exception:
|
|
# TODO log traceback or message
|
|
return {}
|
|
|
|
return global_settings.get("data") or {}
|
|
|
|
|
|
def get_openpype_path_from_db(url: str) -> Union[str, None]:
|
|
"""Get OpenPype path from global settings.
|
|
|
|
Args:
|
|
url (str): mongodb url.
|
|
|
|
Returns:
|
|
path to OpenPype or None if not found
|
|
"""
|
|
global_settings = get_openpype_global_settings(url)
|
|
paths = (
|
|
global_settings
|
|
.get("openpype_path", {})
|
|
.get(platform.system().lower())
|
|
) or []
|
|
# For cases when `openpype_path` is a single path
|
|
if paths and isinstance(paths, str):
|
|
paths = [paths]
|
|
|
|
# Loop over paths and return only existing
|
|
for path in paths:
|
|
if os.path.exists(path):
|
|
return path
|
|
return None
|
|
|
|
|
|
def load_stylesheet() -> str:
|
|
"""Load css style sheet.
|
|
|
|
Returns:
|
|
str: content of the stylesheet
|
|
|
|
"""
|
|
stylesheet_path = Path(__file__).parent.resolve() / "stylesheet.css"
|
|
|
|
return stylesheet_path.read_text()
|