Blender Kitsu: Set Custom Thumbnail during Playblast #77
@ -2,11 +2,16 @@ from . import client as raw
|
|||||||
from . import cache
|
from . import cache
|
||||||
from . import helpers
|
from . import helpers
|
||||||
|
|
||||||
|
try:
|
||||||
|
from . import events
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
from . import asset
|
from . import asset
|
||||||
from . import casting
|
from . import casting
|
||||||
from . import context
|
from . import context
|
||||||
from . import entity
|
|
||||||
from . import edit
|
from . import edit
|
||||||
|
from . import entity
|
||||||
from . import files
|
from . import files
|
||||||
from . import project
|
from . import project
|
||||||
from . import person
|
from . import person
|
||||||
@ -16,7 +21,11 @@ from . import task
|
|||||||
from . import user
|
from . import user
|
||||||
from . import playlist
|
from . import playlist
|
||||||
|
|
||||||
from .exception import AuthFailedException, ParameterException
|
from .exception import (
|
||||||
|
AuthFailedException,
|
||||||
|
ParameterException,
|
||||||
|
NotAuthenticatedException,
|
||||||
|
)
|
||||||
from .__version__ import __version__
|
from .__version__ import __version__
|
||||||
|
|
||||||
|
|
||||||
@ -28,13 +37,30 @@ def set_host(url, client=raw.default_client):
|
|||||||
raw.set_host(url, client=client)
|
raw.set_host(url, client=client)
|
||||||
|
|
||||||
|
|
||||||
def log_in(email, password, client=raw.default_client):
|
def log_in(
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
totp=None,
|
||||||
|
email_otp=None,
|
||||||
|
fido_authentication_response=None,
|
||||||
|
recovery_code=None,
|
||||||
|
client=raw.default_client,
|
||||||
|
):
|
||||||
tokens = {}
|
tokens = {}
|
||||||
try:
|
try:
|
||||||
tokens = raw.post(
|
tokens = raw.post(
|
||||||
"auth/login", {"email": email, "password": password}, client=client
|
"auth/login",
|
||||||
|
{
|
||||||
|
"email": email,
|
||||||
|
"password": password,
|
||||||
|
"totp": totp,
|
||||||
|
"email_otp": email_otp,
|
||||||
|
"fido_authentication_response": fido_authentication_response,
|
||||||
|
"recovery_code": recovery_code,
|
||||||
|
},
|
||||||
|
client=client,
|
||||||
)
|
)
|
||||||
except ParameterException:
|
except (NotAuthenticatedException, ParameterException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if not tokens or (
|
if not tokens or (
|
||||||
@ -46,6 +72,10 @@ def log_in(email, password, client=raw.default_client):
|
|||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
|
|
||||||
|
def send_email_otp(email, client=raw.default_client):
|
||||||
|
return raw.get("auth/email-otp", params={"email": email}, client=client)
|
||||||
|
|
||||||
|
|
||||||
def log_out(client=raw.default_client):
|
def log_out(client=raw.default_client):
|
||||||
tokens = {}
|
tokens = {}
|
||||||
try:
|
try:
|
||||||
@ -56,6 +86,24 @@ def log_out(client=raw.default_client):
|
|||||||
return tokens
|
return tokens
|
||||||
|
|
||||||
|
|
||||||
|
def refresh_token(client=raw.default_client):
|
||||||
|
headers = {"User-Agent": "CGWire Gazu %s" % __version__}
|
||||||
|
if "refresh_token" in client.tokens:
|
||||||
|
headers["Authorization"] = "Bearer %s" % client.tokens["refresh_token"]
|
||||||
|
|
||||||
|
response = client.session.get(
|
||||||
|
raw.get_full_url("auth/refresh-token", client=client),
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
raw.check_status(response, "auth/refresh-token")
|
||||||
|
|
||||||
|
tokens = response.json()
|
||||||
|
|
||||||
|
client.tokens["access_token"] = tokens["access_token"]
|
||||||
|
|
||||||
|
return tokens
|
||||||
|
|
||||||
|
|
||||||
def get_event_host(client=raw.default_client):
|
def get_event_host(client=raw.default_client):
|
||||||
return raw.get_event_host(client=client)
|
return raw.get_event_host(client=client)
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
__version__ = "0.8.30"
|
__version__ = "0.9.3"
|
||||||
|
@ -124,7 +124,7 @@ def get_asset_by_name(project, name, asset_type=None, client=default):
|
|||||||
def get_asset(asset_id, client=default):
|
def get_asset(asset_id, client=default):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
asset_id (str): Id of claimed asset.
|
asset_id (str): ID of claimed asset.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Asset matching given ID.
|
dict: Asset matching given ID.
|
||||||
@ -270,6 +270,7 @@ def all_asset_types_for_project(project, client=default):
|
|||||||
Returns:
|
Returns:
|
||||||
list: Asset types from assets listed in given project.
|
list: Asset types from assets listed in given project.
|
||||||
"""
|
"""
|
||||||
|
project = normalize_model_parameter(project)
|
||||||
path = "projects/%s/asset-types" % project["id"]
|
path = "projects/%s/asset-types" % project["id"]
|
||||||
return sort_by_name(raw.fetch_all(path, client=client))
|
return sort_by_name(raw.fetch_all(path, client=client))
|
||||||
|
|
||||||
@ -291,7 +292,7 @@ def all_asset_types_for_shot(shot, client=default):
|
|||||||
def get_asset_type(asset_type_id, client=default):
|
def get_asset_type(asset_type_id, client=default):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
asset_type_id (str/): Id of claimed asset type.
|
asset_type_id (str/): ID of claimed asset type.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Asset Type matching given ID.
|
dict: Asset Type matching given ID.
|
||||||
@ -358,7 +359,7 @@ def remove_asset_type(asset_type, client=default):
|
|||||||
def get_asset_instance(asset_instance_id, client=default):
|
def get_asset_instance(asset_instance_id, client=default):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
asset_instance_id (str): Id of claimed asset instance.
|
asset_instance_id (str): ID of claimed asset instance.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Asset Instance matching given ID.
|
dict: Asset Instance matching given ID.
|
||||||
|
@ -181,7 +181,6 @@ def cache(function, maxsize=300, expire=120):
|
|||||||
|
|
||||||
@wraps(function)
|
@wraps(function)
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
|
|
||||||
if is_cache_enabled(state):
|
if is_cache_enabled(state):
|
||||||
key = get_cache_key(args, kwargs)
|
key = get_cache_key(args, kwargs)
|
||||||
|
|
||||||
|
@ -3,14 +3,10 @@ import functools
|
|||||||
import json
|
import json
|
||||||
import shutil
|
import shutil
|
||||||
import urllib
|
import urllib
|
||||||
|
import os
|
||||||
|
|
||||||
from .encoder import CustomJSONEncoder
|
from .encoder import CustomJSONEncoder
|
||||||
|
|
||||||
if sys.version_info[0] == 3:
|
|
||||||
from json import JSONDecodeError
|
|
||||||
else:
|
|
||||||
JSONDecodeError = ValueError
|
|
||||||
|
|
||||||
from .__version__ import __version__
|
from .__version__ import __version__
|
||||||
|
|
||||||
from .exception import (
|
from .exception import (
|
||||||
@ -24,6 +20,13 @@ from .exception import (
|
|||||||
UploadFailedException,
|
UploadFailedException,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if sys.version_info[0] == 3:
|
||||||
|
from json import JSONDecodeError
|
||||||
|
else:
|
||||||
|
JSONDecodeError = ValueError
|
||||||
|
|
||||||
|
DEBUG = os.getenv("GAZU_DEBUG", "false").lower() == "true"
|
||||||
|
|
||||||
|
|
||||||
class KitsuClient(object):
|
class KitsuClient(object):
|
||||||
def __init__(self, host, ssl_verify=True, cert=None):
|
def __init__(self, host, ssl_verify=True, cert=None):
|
||||||
@ -47,10 +50,7 @@ try:
|
|||||||
requests.models.complexjson.dumps = functools.partial(
|
requests.models.complexjson.dumps = functools.partial(
|
||||||
json.dumps, cls=CustomJSONEncoder
|
json.dumps, cls=CustomJSONEncoder
|
||||||
)
|
)
|
||||||
# Set host to "" otherwise requests.Session() takes a long time during Blender startup
|
host = "http://gazu.change.serverhost/api"
|
||||||
# Whyever that is.
|
|
||||||
# host = "http://gazu.change.serverhost/api"
|
|
||||||
host = ""
|
|
||||||
default_client = create_client(host)
|
default_client = create_client(host)
|
||||||
except Exception:
|
except Exception:
|
||||||
print("Warning, running in setup mode!")
|
print("Warning, running in setup mode!")
|
||||||
@ -77,9 +77,9 @@ def host_is_valid(client=default_client):
|
|||||||
if not host_is_up(client):
|
if not host_is_up(client):
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
post("auth/login", {"email": "", "password": ""})
|
post("auth/login", {"email": ""})
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
return type(exc) == ParameterException
|
return isinstance(exc, (NotAuthenticatedException, ParameterException))
|
||||||
|
|
||||||
|
|
||||||
def get_host(client=default_client):
|
def get_host(client=default_client):
|
||||||
@ -196,6 +196,8 @@ def get(path, json_response=True, params=None, client=default_client):
|
|||||||
Returns:
|
Returns:
|
||||||
The request result.
|
The request result.
|
||||||
"""
|
"""
|
||||||
|
if DEBUG:
|
||||||
|
print("GET", get_full_url(path, client))
|
||||||
path = build_path_with_params(path, params)
|
path = build_path_with_params(path, params)
|
||||||
response = client.session.get(
|
response = client.session.get(
|
||||||
get_full_url(path, client=client),
|
get_full_url(path, client=client),
|
||||||
@ -216,6 +218,10 @@ def post(path, data, client=default_client):
|
|||||||
Returns:
|
Returns:
|
||||||
The request result.
|
The request result.
|
||||||
"""
|
"""
|
||||||
|
if DEBUG:
|
||||||
|
print("POST", get_full_url(path, client))
|
||||||
|
if not "password" in data:
|
||||||
|
print("Body:", data)
|
||||||
response = client.session.post(
|
response = client.session.post(
|
||||||
get_full_url(path, client),
|
get_full_url(path, client),
|
||||||
json=data,
|
json=data,
|
||||||
@ -237,6 +243,9 @@ def put(path, data, client=default_client):
|
|||||||
Returns:
|
Returns:
|
||||||
The request result.
|
The request result.
|
||||||
"""
|
"""
|
||||||
|
if DEBUG:
|
||||||
|
print("PUT", get_full_url(path, client))
|
||||||
|
print("Body:", data)
|
||||||
response = client.session.put(
|
response = client.session.put(
|
||||||
get_full_url(path, client),
|
get_full_url(path, client),
|
||||||
json=data,
|
json=data,
|
||||||
@ -253,6 +262,8 @@ def delete(path, params=None, client=default_client):
|
|||||||
Returns:
|
Returns:
|
||||||
The request result.
|
The request result.
|
||||||
"""
|
"""
|
||||||
|
if DEBUG:
|
||||||
|
print("DELETE", get_full_url(path, client))
|
||||||
path = build_path_with_params(path, params)
|
path = build_path_with_params(path, params)
|
||||||
|
|
||||||
response = client.session.delete(
|
response = client.session.delete(
|
||||||
|
@ -1,59 +1,147 @@
|
|||||||
from blender_kitsu import gazu
|
|
||||||
from . import client as raw
|
from . import client as raw
|
||||||
from .sorting import sort_by_name
|
|
||||||
|
|
||||||
from .cache import cache
|
from .cache import cache
|
||||||
from .helpers import normalize_model_parameter
|
from .helpers import normalize_model_parameter
|
||||||
|
|
||||||
default = raw.default_client
|
default = raw.default_client
|
||||||
|
|
||||||
@cache
|
|
||||||
def get_all_edits(relations=False, client=default):
|
|
||||||
"""
|
|
||||||
Retrieve all edit entries.
|
|
||||||
"""
|
|
||||||
params = {}
|
|
||||||
if relations:
|
|
||||||
params = {"relations": "true"}
|
|
||||||
path = "edits/all"
|
|
||||||
edits = raw.fetch_all(path, params, client=client)
|
|
||||||
return sort_by_name(edits)
|
|
||||||
|
|
||||||
@cache
|
@cache
|
||||||
def get_edit(edit_id, relations=False, client=default):
|
def get_edit(edit_id, client=default):
|
||||||
"""
|
|
||||||
Retrieve all edit entries.
|
|
||||||
"""
|
|
||||||
edit_entry = normalize_model_parameter(edit_id)
|
|
||||||
params = {}
|
|
||||||
if relations:
|
|
||||||
params = {"relations": "true"}
|
|
||||||
path = f"edits/{edit_entry['id']}"
|
|
||||||
edit_entry = raw.fetch_all(path, params, client=client)
|
|
||||||
return edit_entry
|
|
||||||
|
|
||||||
@cache
|
|
||||||
def get_all_edits_with_tasks(relations=False, client=default):
|
|
||||||
"""
|
|
||||||
Retrieve all edit entries.
|
|
||||||
"""
|
|
||||||
params = {}
|
|
||||||
if relations:
|
|
||||||
params = {"relations": "true"}
|
|
||||||
path = "edits/with-tasks"
|
|
||||||
edits_with_tasks = raw.fetch_all(path, params, client=client)
|
|
||||||
return sort_by_name(edits_with_tasks)
|
|
||||||
|
|
||||||
@cache
|
|
||||||
def get_all_previews_for_edit(edit, client=default):
|
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
|
edit_id (str): ID of claimed edit.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Edit corresponding to given edit ID.
|
||||||
|
"""
|
||||||
|
return raw.fetch_one("edits", edit_id, client=client)
|
||||||
|
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def get_edit_by_name(project, edit_name, client=default):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
project (str / dict): The project dict or the project ID.
|
||||||
|
edit_name (str): Name of claimed edit.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Edit corresponding to given name and sequence.
|
||||||
|
"""
|
||||||
|
project = normalize_model_parameter(project)
|
||||||
|
return raw.fetch_first(
|
||||||
|
"edits/all",
|
||||||
|
{"project_id": project["id"], "name": edit_name},
|
||||||
|
client=client,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def get_edit_url(edit, client=default):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
edit (str / dict): The edit dict or the edit ID.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
url (str): Web url associated to the given edit
|
||||||
|
"""
|
||||||
|
edit = normalize_model_parameter(edit)
|
||||||
|
edit = get_edit(edit["id"])
|
||||||
|
path = "{host}/productions/{project_id}/"
|
||||||
|
if edit["episode_id"] is None:
|
||||||
|
path += "edits/{edit_id}/"
|
||||||
|
else:
|
||||||
|
path += "episodes/{episode_id}/edits/{edit_id}/"
|
||||||
|
return path.format(
|
||||||
|
host=raw.get_api_url_from_host(client=client),
|
||||||
|
project_id=edit["project_id"],
|
||||||
|
edit_id=edit["id"],
|
||||||
|
episode_id=edit["episode_id"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def new_edit(
|
||||||
|
project,
|
||||||
|
name,
|
||||||
|
description=None,
|
||||||
|
data={},
|
||||||
|
episode=None,
|
||||||
|
client=default,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Create an edit for given project (and episode if given).
|
||||||
|
Allow to set metadata too.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project (str / dict): The project dict or the project ID.
|
||||||
|
name (str): The name of the edit to create.
|
||||||
|
description (str): The description of the edit to create.
|
||||||
|
data (dict): Free field to set metadata of any kind.
|
||||||
episode (str / dict): The episode dict or the episode ID.
|
episode (str / dict): The episode dict or the episode ID.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
list: Shots which are children of given episode.
|
Created edit.
|
||||||
|
"""
|
||||||
|
project = normalize_model_parameter(project)
|
||||||
|
if episode is not None:
|
||||||
|
episode = normalize_model_parameter(episode)
|
||||||
|
|
||||||
|
data = {"name": name, "data": data, "parent_id": episode["id"]}
|
||||||
|
|
||||||
|
if description is not None:
|
||||||
|
data["description"] = description
|
||||||
|
|
||||||
|
edit = get_edit_by_name(project, name, client=client)
|
||||||
|
if edit is None:
|
||||||
|
path = "data/projects/%s/edits" % project["id"]
|
||||||
|
return raw.post(path, data, client=client)
|
||||||
|
else:
|
||||||
|
return edit
|
||||||
|
|
||||||
|
|
||||||
|
def remove_edit(edit, force=False, client=default):
|
||||||
|
"""
|
||||||
|
Remove given edit from database.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
edit (dict / str): Edit to remove.
|
||||||
"""
|
"""
|
||||||
edit = normalize_model_parameter(edit)
|
edit = normalize_model_parameter(edit)
|
||||||
edit_previews = (raw.fetch_all(f"edits/{edit['id']}/preview-files", client=client))
|
path = "data/edits/%s" % edit["id"]
|
||||||
for key in [key for key in enumerate(edit_previews.keys())]:
|
params = {}
|
||||||
return edit_previews[key[1]]
|
if force:
|
||||||
|
params = {"force": "true"}
|
||||||
|
return raw.delete(path, params, client=client)
|
||||||
|
|
||||||
|
|
||||||
|
def update_edit(edit, client=default):
|
||||||
|
"""
|
||||||
|
Save given edit data into the API. Metadata are fully replaced by the ones
|
||||||
|
set on given edit.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
edit (dict): The edit dict to update.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Updated edit.
|
||||||
|
"""
|
||||||
|
return raw.put("data/entities/%s" % edit["id"], edit, client=client)
|
||||||
|
|
||||||
|
|
||||||
|
def update_edit_data(edit, data={}, client=default):
|
||||||
|
"""
|
||||||
|
Update the metadata for the provided edit. Keys that are not provided are
|
||||||
|
not changed.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
edit (dict / ID): The edit dict or ID to save in database.
|
||||||
|
data (dict): Free field to set metadata of any kind.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Updated edit.
|
||||||
|
"""
|
||||||
|
edit = normalize_model_parameter(edit)
|
||||||
|
current_edit = get_edit(edit["id"], client=client)
|
||||||
|
updated_edit = {"id": current_edit["id"], "data": current_edit["data"]}
|
||||||
|
updated_edit["data"].update(data)
|
||||||
|
return update_edit(updated_edit, client=client)
|
||||||
|
@ -29,36 +29,39 @@ def all_entity_types(client=default):
|
|||||||
def get_entity(entity_id, client=default):
|
def get_entity(entity_id, client=default):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
id (str, client=default): ID of claimed entity.
|
entity_id (str): ID of claimed entity.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Retrieve entity matching given ID (It can be an entity of any
|
dict: Retrieve entity matching given ID (it can be an entity of any
|
||||||
kind: asset, shot, sequence or episode).
|
kind: asset, shot, sequence or episode).
|
||||||
"""
|
"""
|
||||||
return raw.fetch_one("entities", entity_id, client=client)
|
return raw.fetch_one("entities", entity_id, client=client)
|
||||||
|
|
||||||
|
|
||||||
@cache
|
@cache
|
||||||
def get_entity_by_name(entity_name, client=default):
|
def get_entity_by_name(entity_name, project=None, client=default):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
name (str, client=default): The name of the claimed entity.
|
name (str): The name of the claimed entity.
|
||||||
|
project (str, dict): Project ID or dict.
|
||||||
Returns:
|
Returns:
|
||||||
Retrieve entity matching given name.
|
Retrieve entity matching given name (and project if given).
|
||||||
"""
|
"""
|
||||||
return raw.fetch_first("entities", {"name": entity_name}, client=client)
|
params = {"name": entity_name}
|
||||||
|
if project is not None:
|
||||||
|
project = normalize_model_parameter(project)
|
||||||
|
params["project_id"] = project["id"]
|
||||||
|
return raw.fetch_first("entities", params, client=client)
|
||||||
|
|
||||||
|
|
||||||
@cache
|
@cache
|
||||||
def get_entity_type(entity_type_id, client=default):
|
def get_entity_type(entity_type_id, client=default):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
id (str, client=default): ID of claimed entity type.
|
entity_type_id (str): ID of claimed entity type.
|
||||||
, client=client
|
Returns:
|
||||||
Returns:
|
Retrieve entity type matching given ID (It can be an entity type of any
|
||||||
Retrieve entity type matching given ID (It can be an entity type of any
|
kind).
|
||||||
kind).
|
|
||||||
"""
|
"""
|
||||||
return raw.fetch_one("entity-types", entity_type_id, client=client)
|
return raw.fetch_one("entity-types", entity_type_id, client=client)
|
||||||
|
|
||||||
@ -77,6 +80,41 @@ def get_entity_type_by_name(entity_type_name, client=default):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def guess_from_path(project_id, path, sep="/"):
|
||||||
|
"""
|
||||||
|
Get list of possible project file tree templates matching a file path
|
||||||
|
and data ids corresponding to template tokens.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project_id (str): Project id of given file
|
||||||
|
file_path (str): Path to a file
|
||||||
|
sep (str): File path separator, defaults to "/"
|
||||||
|
Returns:
|
||||||
|
list: dictionnaries with the corresponding entities and template name.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
[
|
||||||
|
{
|
||||||
|
'Asset': '<asset_id>',
|
||||||
|
'Project': '<project_id>',
|
||||||
|
'Template': 'asset'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'Project': '<project_id>',
|
||||||
|
'Template': 'instance'
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
return raw.post(
|
||||||
|
"/data/entities/guess_from_path",
|
||||||
|
{"project_id": project_id, "file_path": path, "sep": sep},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def new_entity_type(name, client=default):
|
def new_entity_type(name, client=default):
|
||||||
"""
|
"""
|
||||||
Creates an entity type with the given name.
|
Creates an entity type with the given name.
|
||||||
@ -104,16 +142,3 @@ def remove_entity(entity, force=False, client=default):
|
|||||||
if force:
|
if force:
|
||||||
params = {"force": "true"}
|
params = {"force": "true"}
|
||||||
return raw.delete(path, params, client=client)
|
return raw.delete(path, params, client=client)
|
||||||
|
|
||||||
def update_entity(entity, client=default):
|
|
||||||
"""
|
|
||||||
Save given shot data into the API. Metadata are fully replaced by the ones
|
|
||||||
set on given shot.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
Entity (dict): The shot dict to update.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict: Updated entity.
|
|
||||||
"""
|
|
||||||
return raw.put(f"data/entities/{entity['id']}", entity, client=client)
|
|
71
scripts-blender/addons/blender_kitsu/gazu/events.py
Normal file
71
scripts-blender/addons/blender_kitsu/gazu/events.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
if sys.version_info[0] == 2:
|
||||||
|
raise ImportError(
|
||||||
|
"The events part of Gazu is not available for Python 2.7"
|
||||||
|
)
|
||||||
|
from .exception import AuthFailedException
|
||||||
|
from .client import default_client, get_event_host
|
||||||
|
from gazu.client import make_auth_header
|
||||||
|
import socketio
|
||||||
|
|
||||||
|
|
||||||
|
class EventsNamespace(socketio.ClientNamespace):
|
||||||
|
def on_connect(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_disconnect(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on_error(self, data):
|
||||||
|
return connect_error(data)
|
||||||
|
|
||||||
|
|
||||||
|
def init(
|
||||||
|
client=default_client,
|
||||||
|
ssl_verify=False,
|
||||||
|
reconnection=True,
|
||||||
|
logger=False,
|
||||||
|
**kwargs
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Init configuration for SocketIO client.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Event client that will be able to set listeners.
|
||||||
|
"""
|
||||||
|
params = {"ssl_verify": ssl_verify}
|
||||||
|
params.update(kwargs)
|
||||||
|
event_client = socketio.Client(
|
||||||
|
logger=logger, reconnection=reconnection, **params
|
||||||
|
)
|
||||||
|
event_client.on("connect_error", connect_error)
|
||||||
|
event_client.register_namespace(EventsNamespace("/events"))
|
||||||
|
event_client.connect(get_event_host(client), make_auth_header())
|
||||||
|
return event_client
|
||||||
|
|
||||||
|
|
||||||
|
def connect_error(data):
|
||||||
|
print("The connection failed!")
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def add_listener(event_client, event_name, event_handler):
|
||||||
|
"""
|
||||||
|
Set a listener that reacts to a given event.
|
||||||
|
"""
|
||||||
|
event_client.on(event_name, event_handler, "/events")
|
||||||
|
return event_client
|
||||||
|
|
||||||
|
|
||||||
|
def run_client(event_client):
|
||||||
|
"""
|
||||||
|
Run event client (it blocks current thread). It listens to all events
|
||||||
|
configured.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
print("Listening to Kitsu events...")
|
||||||
|
event_client.wait()
|
||||||
|
except TypeError:
|
||||||
|
raise AuthFailedException
|
||||||
|
return event_client
|
@ -79,7 +79,7 @@ class TooBigFileException(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class TaskStatusNotFound(Exception):
|
class TaskStatusNotFoundException(Exception):
|
||||||
"""
|
"""
|
||||||
Error raised when a task status is not found.
|
Error raised when a task status is not found.
|
||||||
"""
|
"""
|
||||||
@ -91,3 +91,9 @@ class DownloadFileException(Exception):
|
|||||||
"""
|
"""
|
||||||
Error raised when a file can't be downloaded.
|
Error raised when a file can't be downloaded.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class TaskMustBeADictException(Exception):
|
||||||
|
"""
|
||||||
|
Error raised when a task should be a dict.
|
||||||
|
"""
|
||||||
|
@ -1083,7 +1083,7 @@ def download_preview_file(preview_file, file_path, client=default):
|
|||||||
file_path (str): Location on hard drive where to save the file.
|
file_path (str): Location on hard drive where to save the file.
|
||||||
"""
|
"""
|
||||||
return raw.download(
|
return raw.download(
|
||||||
get_preview_file_url(preview_file),
|
get_preview_file_url(preview_file, client=client),
|
||||||
file_path,
|
file_path,
|
||||||
client=client,
|
client=client,
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
import datetime
|
import datetime
|
||||||
import shutil
|
import shutil
|
||||||
@ -7,7 +7,7 @@ import requests
|
|||||||
import tempfile
|
import tempfile
|
||||||
import mimetypes
|
import mimetypes
|
||||||
|
|
||||||
from .exception import DownloadFileException
|
from gazu.exception import DownloadFileException
|
||||||
|
|
||||||
if sys.version_info[0] == 3:
|
if sys.version_info[0] == 3:
|
||||||
import urllib.parse as urlparse
|
import urllib.parse as urlparse
|
||||||
|
@ -38,15 +38,61 @@ def all_persons(client=default):
|
|||||||
|
|
||||||
|
|
||||||
@cache
|
@cache
|
||||||
def get_person(id, client=default):
|
def get_time_spents_range(person_id, start_date, end_date, client=default):
|
||||||
|
"""
|
||||||
|
Gets the time spents of the current user for the given date range.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
person_id (str): An uuid identifying a person.
|
||||||
|
start_date (str): The first day of the date range as a date string with
|
||||||
|
the following format: YYYY-MM-DD
|
||||||
|
end_date (str): The last day of the date range as a date string with
|
||||||
|
the following format: YYYY-MM-DD
|
||||||
|
Returns:
|
||||||
|
list: All of the person's time spents
|
||||||
|
"""
|
||||||
|
date_range = {
|
||||||
|
"start_date": start_date,
|
||||||
|
"end_date": end_date,
|
||||||
|
}
|
||||||
|
return raw.get(
|
||||||
|
"/data/persons/{}/time-spents".format(person_id),
|
||||||
|
params=date_range,
|
||||||
|
client=client,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_month_time_spents(id, date, client=default):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
id (str): An uuid identifying a person.
|
id (str): An uuid identifying a person.
|
||||||
|
date (datetime.date): The date of the month to query.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: All of the person's time spents for the given month.
|
||||||
|
"""
|
||||||
|
date = date.strftime("%Y/%m")
|
||||||
|
return raw.get(
|
||||||
|
"data/persons/{}/time-spents/month/all/{}".format(id, date),
|
||||||
|
client=client,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def get_person(id, relations=False, client=default):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
id (str): An uuid identifying a person.
|
||||||
|
relations (bool): Whether to get the relations for the given person.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Person corresponding to given id.
|
dict: Person corresponding to given id.
|
||||||
"""
|
"""
|
||||||
return raw.fetch_one("persons", id, client=client)
|
params = {"id": id}
|
||||||
|
if relations:
|
||||||
|
params["relations"] = "true"
|
||||||
|
|
||||||
|
return raw.fetch_first("persons", params=params, client=client)
|
||||||
|
|
||||||
|
|
||||||
@cache
|
@cache
|
||||||
@ -152,7 +198,7 @@ def new_person(
|
|||||||
Returns:
|
Returns:
|
||||||
dict: Created person.
|
dict: Created person.
|
||||||
"""
|
"""
|
||||||
person = get_person_by_email(email)
|
person = get_person_by_email(email, client=client)
|
||||||
if person is None:
|
if person is None:
|
||||||
person = raw.post(
|
person = raw.post(
|
||||||
"data/persons/new",
|
"data/persons/new",
|
||||||
|
@ -256,6 +256,7 @@ def add_metadata_descriptor(
|
|||||||
project,
|
project,
|
||||||
name,
|
name,
|
||||||
entity_type,
|
entity_type,
|
||||||
|
data_type="string",
|
||||||
choices=[],
|
choices=[],
|
||||||
for_client=False,
|
for_client=False,
|
||||||
departments=[],
|
departments=[],
|
||||||
@ -278,6 +279,7 @@ def add_metadata_descriptor(
|
|||||||
project = normalize_model_parameter(project)
|
project = normalize_model_parameter(project)
|
||||||
data = {
|
data = {
|
||||||
"name": name,
|
"name": name,
|
||||||
|
"data_type": data_type,
|
||||||
"choices": choices,
|
"choices": choices,
|
||||||
"for_client": for_client,
|
"for_client": for_client,
|
||||||
"entity_type": entity_type,
|
"entity_type": entity_type,
|
||||||
@ -292,7 +294,27 @@ def add_metadata_descriptor(
|
|||||||
|
|
||||||
def get_metadata_descriptor(project, metadata_descriptor_id, client=default):
|
def get_metadata_descriptor(project, metadata_descriptor_id, client=default):
|
||||||
"""
|
"""
|
||||||
Get a metadata descriptor matchind it's ID.
|
Retrieve a the metadata descriptor matching given ID.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project (dict / ID): The project dict or id.
|
||||||
|
metadata_descriptor_id (dict / ID): The metadata descriptor dict or id.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: The metadata descriptor matching the ID.
|
||||||
|
"""
|
||||||
|
project = normalize_model_parameter(project)
|
||||||
|
metadata_descriptor = normalize_model_parameter(metadata_descriptor_id)
|
||||||
|
return raw.fetch_one(
|
||||||
|
"projects/%s/metadata-descriptors" % project["id"],
|
||||||
|
metadata_descriptor["id"],
|
||||||
|
client=client,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_metadata_descriptor_by_field_name(project, field_name, client=default):
|
||||||
|
"""
|
||||||
|
Get a metadata descriptor matchind given project and name.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
project (dict / ID): The project dict or id.
|
project (dict / ID): The project dict or id.
|
||||||
@ -302,10 +324,12 @@ def get_metadata_descriptor(project, metadata_descriptor_id, client=default):
|
|||||||
dict: The metadata descriptor matchind the ID.
|
dict: The metadata descriptor matchind the ID.
|
||||||
"""
|
"""
|
||||||
project = normalize_model_parameter(project)
|
project = normalize_model_parameter(project)
|
||||||
metadata_descriptor = normalize_model_parameter(metadata_descriptor_id)
|
return raw.fetch_first(
|
||||||
return raw.fetch_one(
|
"metadata-descriptors",
|
||||||
"projects/%s/metadata-descriptors" % project["id"],
|
params={
|
||||||
metadata_descriptor["id"],
|
"project_id": project["id"],
|
||||||
|
"field_name": field_name,
|
||||||
|
},
|
||||||
client=client,
|
client=client,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -375,3 +399,46 @@ def remove_metadata_descriptor(
|
|||||||
params,
|
params,
|
||||||
client=client,
|
client=client,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_team(project, client=default):
|
||||||
|
"""
|
||||||
|
Get team for project.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project (dict / ID): The project dict or id.
|
||||||
|
"""
|
||||||
|
project = normalize_model_parameter(project)
|
||||||
|
return raw.fetch_all("projects/%s/team" % project["id"], client=client)
|
||||||
|
|
||||||
|
|
||||||
|
def add_person_to_team(project, person, client=default):
|
||||||
|
"""
|
||||||
|
Add a person to the team project.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project (dict / ID): The project dict or id.
|
||||||
|
person (dict / ID): The person dict or id.
|
||||||
|
"""
|
||||||
|
project = normalize_model_parameter(project)
|
||||||
|
person = normalize_model_parameter(person)
|
||||||
|
data = {"person_id": person["id"]}
|
||||||
|
return raw.post(
|
||||||
|
"data/projects/%s/team" % project["id"], data, client=client
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_person_from_team(project, person, client=default):
|
||||||
|
"""
|
||||||
|
Remove a person from the team project.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project (dict / ID): The project dict or id.
|
||||||
|
person (dict / ID): The person dict or id.
|
||||||
|
"""
|
||||||
|
project = normalize_model_parameter(project)
|
||||||
|
person = normalize_model_parameter(person)
|
||||||
|
return raw.delete(
|
||||||
|
"data/projects/%s/team/%s" % (project["id"], person["id"]),
|
||||||
|
client=client,
|
||||||
|
)
|
||||||
|
@ -14,9 +14,9 @@ def new_scene(project, sequence, name, client=default):
|
|||||||
"""
|
"""
|
||||||
project = normalize_model_parameter(project)
|
project = normalize_model_parameter(project)
|
||||||
sequence = normalize_model_parameter(sequence)
|
sequence = normalize_model_parameter(sequence)
|
||||||
shot = {"name": name, "sequence_id": sequence["id"]}
|
scene = {"name": name, "sequence_id": sequence["id"]}
|
||||||
return raw.post(
|
return raw.post(
|
||||||
"data/projects/%s/scenes" % project["id"], shot, client=client
|
"data/projects/%s/scenes" % project["id"], scene, client=client
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ def all_episodes_for_project(project, client=default):
|
|||||||
def get_episode(episode_id, client=default):
|
def get_episode(episode_id, client=default):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
episode_id (str): Id of claimed episode.
|
episode_id (str): ID of claimed episode.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Episode corresponding to given episode ID.
|
dict: Episode corresponding to given episode ID.
|
||||||
@ -205,7 +205,7 @@ def get_sequence_from_shot(shot, client=default):
|
|||||||
def get_shot(shot_id, client=default):
|
def get_shot(shot_id, client=default):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
shot_id (str): Id of claimed shot.
|
shot_id (str): ID of claimed shot.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Shot corresponding to given shot ID.
|
dict: Shot corresponding to given shot ID.
|
||||||
|
@ -1,4 +1,15 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
from .helpers import normalize_model_parameter
|
||||||
|
|
||||||
from . import client as raw
|
from . import client as raw
|
||||||
|
from . import asset as asset_module
|
||||||
|
from . import casting as casting_module
|
||||||
|
from . import person as person_module
|
||||||
|
from . import project as project_module
|
||||||
|
from . import files as files_module
|
||||||
|
from . import shot as shot_module
|
||||||
|
from . import task as task_module
|
||||||
|
|
||||||
from .helpers import normalize_model_parameter, validate_date_format
|
from .helpers import normalize_model_parameter, validate_date_format
|
||||||
|
|
||||||
@ -6,7 +17,12 @@ default = raw.default_client
|
|||||||
|
|
||||||
|
|
||||||
def get_last_events(
|
def get_last_events(
|
||||||
page_size=20000, project=None, after=None, before=None, client=default
|
page_size=20000,
|
||||||
|
project=None,
|
||||||
|
after=None,
|
||||||
|
before=None,
|
||||||
|
only_files=False,
|
||||||
|
client=default,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Get last events that occured on the machine.
|
Get last events that occured on the machine.
|
||||||
@ -16,13 +32,13 @@ def get_last_events(
|
|||||||
project (dict/id): Get only events related to this project.
|
project (dict/id): Get only events related to this project.
|
||||||
after (dict/id): Get only events occuring after given date.
|
after (dict/id): Get only events occuring after given date.
|
||||||
before (dict/id): Get only events occuring before given date.
|
before (dict/id): Get only events occuring before given date.
|
||||||
|
only_files (bool): Get only events related to files.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Last events matching criterions.
|
dict: Last events matching criterions.
|
||||||
"""
|
"""
|
||||||
path = "/data/events/last"
|
path = "/data/events/last"
|
||||||
params = {"page_size": page_size}
|
params = {"page_size": page_size, "only_files": only_files}
|
||||||
if project is not None:
|
if project is not None:
|
||||||
project = normalize_model_parameter(project)
|
project = normalize_model_parameter(project)
|
||||||
params["project_id"] = project["id"]
|
params["project_id"] = project["id"]
|
||||||
@ -167,6 +183,447 @@ def get_id_map_by_id(source_list, target_list, field="name"):
|
|||||||
|
|
||||||
|
|
||||||
def is_changed(source_model, target_model):
|
def is_changed(source_model, target_model):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
source_model (dict): Model from the source API.
|
||||||
|
target_model (dict): Matching model from the target API.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if the source model is older than the target model (based on
|
||||||
|
`updated_at` field)
|
||||||
|
"""
|
||||||
source_date = source_model["updated_at"]
|
source_date = source_model["updated_at"]
|
||||||
target_date = target_model["updated_at"]
|
target_date = target_model["updated_at"]
|
||||||
return source_date > target_date
|
return source_date > target_date
|
||||||
|
|
||||||
|
|
||||||
|
def get_sync_department_id_map(source_client, target_client):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
source_client (KitsuClient): client to get data from source API
|
||||||
|
target_client (KitsuClient): client to push data to target API
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: A dict matching source departments ids with target department ids
|
||||||
|
"""
|
||||||
|
departments_source = person_module.all_departments(client=source_client)
|
||||||
|
departments_target = person_module.all_departments(client=target_client)
|
||||||
|
return get_id_map_by_id(departments_source, departments_target)
|
||||||
|
|
||||||
|
|
||||||
|
def get_sync_asset_type_id_map(source_client, target_client):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
source_client (KitsuClient): client to get data from source API
|
||||||
|
target_client (KitsuClient): client to push data to target API
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: A dict matching source asset type ids with target asset type ids
|
||||||
|
"""
|
||||||
|
asset_types_source = asset_module.all_asset_types(client=source_client)
|
||||||
|
asset_types_target = asset_module.all_asset_types(client=target_client)
|
||||||
|
return get_id_map_by_id(asset_types_source, asset_types_target)
|
||||||
|
|
||||||
|
|
||||||
|
def get_sync_project_id_map(source_client, target_client):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
source_client (KitsuClient): client to get data from source API
|
||||||
|
target_client (KitsuClient): client to push data to target API
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: A dict matching source project ids with target project ids
|
||||||
|
"""
|
||||||
|
projects_source = project_module.all_projects(client=source_client)
|
||||||
|
projects_target = project_module.all_projects(client=target_client)
|
||||||
|
return get_id_map_by_id(projects_source, projects_target)
|
||||||
|
|
||||||
|
|
||||||
|
def get_sync_task_type_id_map(source_client, target_client):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
source_client (KitsuClient): client to get data from source API
|
||||||
|
target_client (KitsuClient): client to push data to target API
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: A dict matching source task type ids with target task type ids
|
||||||
|
"""
|
||||||
|
task_types_source = task_module.all_task_types(client=source_client)
|
||||||
|
task_types_target = task_module.all_task_types(client=target_client)
|
||||||
|
return get_id_map_by_id(task_types_source, task_types_target)
|
||||||
|
|
||||||
|
|
||||||
|
def get_sync_task_status_id_map(source_client, target_client):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
source_client (KitsuClient): client to get data from source API
|
||||||
|
target_client (KitsuClient): client to push data to target API
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: A dict matching source task status ids with target task status
|
||||||
|
ids
|
||||||
|
"""
|
||||||
|
task_statuses_source = task_module.all_task_statuses(client=source_client)
|
||||||
|
task_statuses_target = task_module.all_task_statuses(client=target_client)
|
||||||
|
return get_id_map_by_id(task_statuses_source, task_statuses_target)
|
||||||
|
|
||||||
|
|
||||||
|
def get_sync_person_id_map(source_client, target_client):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
source_client (KitsuClient): client to get data from source API
|
||||||
|
target_client (KitsuClient): client to push data to target API
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: A dict matching source person ids with target person ids
|
||||||
|
"""
|
||||||
|
persons_source = person_module.all_persons(client=source_client)
|
||||||
|
persons_target = person_module.all_persons(client=target_client)
|
||||||
|
return get_id_map_by_id(persons_source, persons_target, field="email")
|
||||||
|
|
||||||
|
|
||||||
|
def push_assets(project_source, project_target, client_source, client_target):
|
||||||
|
"""
|
||||||
|
Copy assets from source to target and preserve audit fields (`id`,
|
||||||
|
`created_at`, and `updated_at`)
|
||||||
|
Args:
|
||||||
|
project_source (dict): The project to get assets from
|
||||||
|
project_target (dict): The project to push assets to
|
||||||
|
source_client (KitsuClient): client to get data from source API
|
||||||
|
target_client (KitsuClient): client to push data to target API
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: Pushed assets
|
||||||
|
"""
|
||||||
|
asset_types_map = get_sync_asset_type_id_map(client_source, client_target)
|
||||||
|
task_types_map = get_sync_task_type_id_map(client_source, client_target)
|
||||||
|
assets = asset_module.all_assets_for_project(
|
||||||
|
project_source, client=client_source
|
||||||
|
)
|
||||||
|
for asset in assets:
|
||||||
|
asset["entity_type_id"] = asset_types_map[asset["entity_type_id"]]
|
||||||
|
if asset["ready_for"] is not None:
|
||||||
|
asset["ready_for"] = task_types_map[asset["ready_for"]]
|
||||||
|
asset["project_id"] = project_target["id"]
|
||||||
|
return import_entities(assets, client=client_target)
|
||||||
|
|
||||||
|
|
||||||
|
def push_episodes(
|
||||||
|
project_source, project_target, client_source, client_target
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Copy episodes from source to target and preserve audit fields (`id`,
|
||||||
|
`created_at`, and `updated_at`)
|
||||||
|
Args:
|
||||||
|
project_source (dict): The project to get episodes from
|
||||||
|
project_target (dict): The project to push episodes to
|
||||||
|
source_client (KitsuClient): client to get data from source API
|
||||||
|
target_client (KitsuClient): client to push data to target API
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: Pushed episodes
|
||||||
|
"""
|
||||||
|
episodes = shot_module.all_episodes_for_project(
|
||||||
|
project_source, client=client_source
|
||||||
|
)
|
||||||
|
for episode in episodes:
|
||||||
|
episode["project_id"] = project_target["id"]
|
||||||
|
return import_entities(episodes, client=client_target)
|
||||||
|
|
||||||
|
|
||||||
|
def push_sequences(
|
||||||
|
project_source, project_target, client_source, client_target
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Copy sequences from source to target and preserve audit fields (`id`,
|
||||||
|
`created_at`, and `updated_at`)
|
||||||
|
Args:
|
||||||
|
project_source (dict): The project to get sequences from
|
||||||
|
project_target (dict): The project to push sequences to
|
||||||
|
source_client (KitsuClient): client to get data from source API
|
||||||
|
target_client (KitsuClient): client to push data to target API
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: Pushed sequences
|
||||||
|
"""
|
||||||
|
sequences = shot_module.all_sequences_for_project(
|
||||||
|
project_source, client=client_source
|
||||||
|
)
|
||||||
|
for sequence in sequences:
|
||||||
|
sequence["project_id"] = project_target["id"]
|
||||||
|
return import_entities(sequences, client=client_target)
|
||||||
|
|
||||||
|
|
||||||
|
def push_shots(project_source, project_target, client_source, client_target):
|
||||||
|
"""
|
||||||
|
Copy shots from source to target and preserve audit fields (`id`,
|
||||||
|
`created_at`, and `updated_at`)
|
||||||
|
Args:
|
||||||
|
project_source (dict): The project to get shots from
|
||||||
|
project_target (dict): The project to push shots to
|
||||||
|
source_client (KitsuClient): client to get data from source API
|
||||||
|
target_client (KitsuClient): client to push data to target API
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: Pushed shots
|
||||||
|
"""
|
||||||
|
shots = shot_module.all_shots_for_project(
|
||||||
|
project_source, client=client_source
|
||||||
|
)
|
||||||
|
for shot in shots:
|
||||||
|
shot["project_id"] = project_target["id"]
|
||||||
|
return import_entities(shots, client=client_target)
|
||||||
|
|
||||||
|
|
||||||
|
def push_entity_links(
|
||||||
|
project_source, project_target, client_source, client_target
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Copy assets from source to target and preserve audit fields (`id`,
|
||||||
|
`created_at`, and `updated_at`)
|
||||||
|
Args:
|
||||||
|
project_source (dict): The project to get assets from
|
||||||
|
project_target (dict): The project to push assets to
|
||||||
|
source_client (KitsuClient): client to get data from source API
|
||||||
|
target_client (KitsuClient): client to push data to target API
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: Pushed entity links
|
||||||
|
"""
|
||||||
|
links = casting_module.all_entity_links_for_project(
|
||||||
|
project_source, client=client_source
|
||||||
|
)
|
||||||
|
return import_entity_links(links, client=client_target)
|
||||||
|
|
||||||
|
|
||||||
|
def push_project_entities(
|
||||||
|
project_source, project_target, client_source, client_target
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Copy assets, episodes, sequences, shots and entity links from source to
|
||||||
|
target and preserve audit fields (`id`, `created_at`, and `updated_at`)
|
||||||
|
Args:
|
||||||
|
project_source (dict): The project to get assets from
|
||||||
|
project_target (dict): The project to push assets to
|
||||||
|
source_client (KitsuClient): client to get data from source API
|
||||||
|
target_client (KitsuClient): client to push data to target API
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Pushed data
|
||||||
|
"""
|
||||||
|
assets = push_assets(project_source, project_target)
|
||||||
|
episodes = []
|
||||||
|
if project_source["production_type"] == "tvshow":
|
||||||
|
episodes = push_episodes(project_source, project_target)
|
||||||
|
sequences = push_sequences(project_source, project_target)
|
||||||
|
shots = push_shots(project_source, project_target)
|
||||||
|
entity_links = push_entity_links(project_source, project_target)
|
||||||
|
return {
|
||||||
|
"assets": assets,
|
||||||
|
"episodes": episodes,
|
||||||
|
"sequences": sequences,
|
||||||
|
"shots": shots,
|
||||||
|
"entity_links": entity_links,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def push_tasks(
|
||||||
|
project_source,
|
||||||
|
project_target,
|
||||||
|
default_status,
|
||||||
|
client_source,
|
||||||
|
client_target,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Copy tasks from source to target and preserve audit fields (`id`,
|
||||||
|
`created_at`, and `updated_at`)
|
||||||
|
Attachments and previews are created too.
|
||||||
|
Args:
|
||||||
|
project_source (dict): The project to get assets from
|
||||||
|
project_target (dict): The project to push assets to
|
||||||
|
source_client (KitsuClient): client to get data from source API
|
||||||
|
target_client (KitsuClient): client to push data to target API
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: Pushed entity links
|
||||||
|
"""
|
||||||
|
|
||||||
|
default_status_id = normalize_model_parameter(default_status)["id"]
|
||||||
|
task_type_map = get_sync_task_type_id_map(client_source, client_target)
|
||||||
|
task_status_map = get_sync_task_status_id_map(client_source, client_target)
|
||||||
|
person_map = get_sync_person_id_map(client_source, client_target)
|
||||||
|
|
||||||
|
tasks = task_module.all_tasks_for_project(
|
||||||
|
project_source, client=client_source
|
||||||
|
)
|
||||||
|
for task in tasks:
|
||||||
|
task["task_type_id"] = task_type_map[task["task_type_id"]]
|
||||||
|
task["task_status_id"] = default_status_id
|
||||||
|
task["assigner_id"] = person_map[task["assigner_id"]]
|
||||||
|
task["project_id"] = project_target["id"]
|
||||||
|
|
||||||
|
task["assignees"] = [
|
||||||
|
person_map[person_id] for person_id in task["assignees"]
|
||||||
|
]
|
||||||
|
return import_tasks(tasks, client=client_target)
|
||||||
|
|
||||||
|
|
||||||
|
def push_tasks_comments(project_source, client_source, client_target):
|
||||||
|
"""
|
||||||
|
Create a new comment into target api for each comment in source project
|
||||||
|
but preserve only `created_at` field.
|
||||||
|
Attachments and previews are created too.
|
||||||
|
Args:
|
||||||
|
project_source (dict): The project to get assets from
|
||||||
|
project_target (dict): The project to push assets to
|
||||||
|
source_client (KitsuClient): client to get data from source API
|
||||||
|
target_client (KitsuClient): client to push data to target API
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: Created comments
|
||||||
|
"""
|
||||||
|
|
||||||
|
task_status_map = get_sync_task_status_id_map(client_source, client_target)
|
||||||
|
person_map = get_sync_person_id_map(client_source, client_target)
|
||||||
|
tasks = task_module.all_tasks_for_project(
|
||||||
|
project_source, client=client_source
|
||||||
|
)
|
||||||
|
for task in tasks:
|
||||||
|
push_task_comments(
|
||||||
|
task_status_map, person_map, task, client_source, client_target
|
||||||
|
)
|
||||||
|
return tasks
|
||||||
|
|
||||||
|
|
||||||
|
def push_task_comments(
|
||||||
|
task_status_map, person_map, task, client_source, client_target
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Create a new comment into target api for each comment in source task
|
||||||
|
but preserve only `created_at` field.
|
||||||
|
Attachments and previews are created too.
|
||||||
|
Args:
|
||||||
|
project_source (dict): The project to get assets from
|
||||||
|
project_target (dict): The project to push assets to
|
||||||
|
source_client (KitsuClient): client to get data from source API
|
||||||
|
target_client (KitsuClient): client to push data to target API
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: Created comments
|
||||||
|
"""
|
||||||
|
comments = task_module.all_comments_for_task(task, client=client_source)
|
||||||
|
comments.reverse()
|
||||||
|
comments_target = []
|
||||||
|
for comment in comments:
|
||||||
|
comment_target = push_task_comment(
|
||||||
|
task_status_map,
|
||||||
|
person_map,
|
||||||
|
task,
|
||||||
|
comment,
|
||||||
|
client_source,
|
||||||
|
client_target,
|
||||||
|
)
|
||||||
|
comments_target.append(comment_target)
|
||||||
|
return comments_target
|
||||||
|
|
||||||
|
|
||||||
|
def push_task_comment(
|
||||||
|
task_status_map, person_map, task, comment, client_source, client_target
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Create a new comment into target api for each comment in source task
|
||||||
|
but preserve only `created_at` field.
|
||||||
|
Attachments and previews are created too.
|
||||||
|
Args:
|
||||||
|
project_source (dict): The project to get assets from
|
||||||
|
project_target (dict): The project to push assets to
|
||||||
|
source_client (KitsuClient): client to get data from source API
|
||||||
|
target_client (KitsuClient): client to push data to target API
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: Created comments
|
||||||
|
"""
|
||||||
|
attachments = []
|
||||||
|
for attachment_id in comment["attachment_files"]:
|
||||||
|
if type(attachment_id) == dict:
|
||||||
|
attachment_id = attachment_id["id"]
|
||||||
|
attachment_file = gazu.files.get_attachment_file(
|
||||||
|
attachment_id, client=client_source
|
||||||
|
)
|
||||||
|
file_path = "/tmp/zou/sync/" + attachment_file["name"]
|
||||||
|
files_module.download_attachment_file(
|
||||||
|
attachment_file, file_path, client=client_source
|
||||||
|
)
|
||||||
|
attachments.append(file_path)
|
||||||
|
|
||||||
|
previews = []
|
||||||
|
for preview_file in comment["previews"]:
|
||||||
|
if type(preview_file) is str:
|
||||||
|
preview_file_id = preview_file
|
||||||
|
else:
|
||||||
|
preview_file_id = preview_file["id"]
|
||||||
|
preview_file = files_module.get_preview_file(
|
||||||
|
preview_file_id, client=client_source
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
preview_file["original_name"] is not None
|
||||||
|
and preview_file["extension"] is not None
|
||||||
|
):
|
||||||
|
file_path = (
|
||||||
|
"/tmp/zou/sync/"
|
||||||
|
+ preview_file["original_name"]
|
||||||
|
+ "."
|
||||||
|
+ preview_file["extension"]
|
||||||
|
)
|
||||||
|
files_module.download_preview_file(
|
||||||
|
preview_file, file_path, client=client_source
|
||||||
|
)
|
||||||
|
previews.append(
|
||||||
|
{
|
||||||
|
"file_path": file_path,
|
||||||
|
"annotations": preview_file["annotations"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
task_status = {"id": task_status_map[comment["task_status_id"]]}
|
||||||
|
author_id = person_map[comment["person_id"]]
|
||||||
|
person = {"id": author_id}
|
||||||
|
|
||||||
|
comment_target = task_module.add_comment(
|
||||||
|
task,
|
||||||
|
task_status,
|
||||||
|
attachments=attachments,
|
||||||
|
comment=comment["text"],
|
||||||
|
created_at=comment["created_at"],
|
||||||
|
person=person,
|
||||||
|
checklist=comment["checklist"] or [],
|
||||||
|
client=client_target,
|
||||||
|
)
|
||||||
|
|
||||||
|
for preview in previews:
|
||||||
|
new_preview_file = task_module.add_preview(
|
||||||
|
task, comment_target, preview["file_path"], client=client_target
|
||||||
|
)
|
||||||
|
files_module.update_preview(
|
||||||
|
new_preview_file,
|
||||||
|
{"annotations": preview["annotations"]},
|
||||||
|
client=client_target,
|
||||||
|
)
|
||||||
|
os.remove(preview["file_path"])
|
||||||
|
|
||||||
|
for attachment_path in attachments:
|
||||||
|
os.remove(attachment_path)
|
||||||
|
|
||||||
|
return comment
|
||||||
|
|
||||||
|
|
||||||
|
def convert_id_list(ids, model_map):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
ids (list): Ids to convert.
|
||||||
|
model_map (dict): Map matching ids to another value.c
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: Ids converted through given model map.
|
||||||
|
"""
|
||||||
|
return [model_map[id] for id in ids]
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
import string
|
import string
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from .exception import TaskStatusNotFound
|
from gazu.exception import (
|
||||||
|
TaskStatusNotFoundException,
|
||||||
|
TaskMustBeADictException,
|
||||||
|
)
|
||||||
|
|
||||||
from . import client as raw
|
from . import client as raw
|
||||||
from .sorting import sort_by_name
|
from .sorting import sort_by_name
|
||||||
@ -147,20 +150,6 @@ def all_tasks_for_episode(episode, relations=False, client=default):
|
|||||||
return sort_by_name(tasks)
|
return sort_by_name(tasks)
|
||||||
|
|
||||||
|
|
||||||
@cache
|
|
||||||
def all_tasks_for_edit(edit, relations=False, client=default):
|
|
||||||
"""
|
|
||||||
Retrieve all tasks directly linked to given edit.
|
|
||||||
"""
|
|
||||||
edit = normalize_model_parameter(edit)
|
|
||||||
params = {}
|
|
||||||
if relations:
|
|
||||||
params = {"relations": "true"}
|
|
||||||
path = "edits/%s/tasks" % edit["id"]
|
|
||||||
tasks = raw.fetch_all(path, params, client=client)
|
|
||||||
return sort_by_name(tasks)
|
|
||||||
|
|
||||||
|
|
||||||
@cache
|
@cache
|
||||||
def all_shot_tasks_for_sequence(sequence, relations=False, client=default):
|
def all_shot_tasks_for_sequence(sequence, relations=False, client=default):
|
||||||
"""
|
"""
|
||||||
@ -394,7 +383,7 @@ def get_task_by_name(entity, task_type, name="main", client=default):
|
|||||||
def get_task_type(task_type_id, client=default):
|
def get_task_type(task_type_id, client=default):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
task_type_id (str): Id of claimed task type.
|
task_type_id (str): ID of claimed task type.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Task type matching given ID.
|
dict: Task type matching given ID.
|
||||||
@ -437,11 +426,22 @@ def get_task_by_path(project, file_path, entity_type="shot", client=default):
|
|||||||
return raw.post("data/tasks/from-path/", data, client=client)
|
return raw.post("data/tasks/from-path/", data, client=client)
|
||||||
|
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def get_default_task_status(client=default):
|
||||||
|
"""
|
||||||
|
Returns:
|
||||||
|
dict: The unique task status flagged with `is_default`.
|
||||||
|
"""
|
||||||
|
return raw.fetch_first(
|
||||||
|
"task-status", params={"is_default": True}, client=client
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@cache
|
@cache
|
||||||
def get_task_status(task_status_id, client=default):
|
def get_task_status(task_status_id, client=default):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
task_status_id (str): Id of claimed task status.
|
task_status_id (str): ID of claimed task status.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Task status matching given ID.
|
dict: Task status matching given ID.
|
||||||
@ -521,7 +521,7 @@ def remove_task_status(task_status, client=default):
|
|||||||
def get_task(task_id, client=default):
|
def get_task(task_id, client=default):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
task_id (str): Id of claimed task.
|
task_id (str): ID of claimed task.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Task matching given ID.
|
dict: Task matching given ID.
|
||||||
@ -603,7 +603,7 @@ def start_task(task, started_task_status=None, client=default):
|
|||||||
"wip", client=client
|
"wip", client=client
|
||||||
)
|
)
|
||||||
if started_task_status is None:
|
if started_task_status is None:
|
||||||
raise TaskStatusNotFound(
|
raise TaskStatusNotFoundException(
|
||||||
(
|
(
|
||||||
"started_task_status is None : 'wip' task status is "
|
"started_task_status is None : 'wip' task status is "
|
||||||
"non-existent. You have to create it or to set an other "
|
"non-existent. You have to create it or to set an other "
|
||||||
@ -647,9 +647,9 @@ def task_to_review(
|
|||||||
|
|
||||||
|
|
||||||
@cache
|
@cache
|
||||||
def get_time_spent(task, date, client=default):
|
def get_time_spent(task, date=None, client=default):
|
||||||
"""
|
"""
|
||||||
Get the time spent by CG artists on a task at a given date. A field contains
|
Get the time spent by CG artists on a task at a given date if given. A field contains
|
||||||
the total time spent. Durations are given in seconds. Date format is
|
the total time spent. Durations are given in seconds. Date format is
|
||||||
YYYY-MM-DD.
|
YYYY-MM-DD.
|
||||||
|
|
||||||
@ -661,7 +661,9 @@ def get_time_spent(task, date, client=default):
|
|||||||
dict: A dict with person ID as key and time spent object as value.
|
dict: A dict with person ID as key and time spent object as value.
|
||||||
"""
|
"""
|
||||||
task = normalize_model_parameter(task)
|
task = normalize_model_parameter(task)
|
||||||
path = "actions/tasks/%s/time-spents/%s" % (task["id"], date)
|
path = "actions/tasks/%s/time-spents" % (task["id"])
|
||||||
|
if date is not None:
|
||||||
|
path += "/%s" % (date)
|
||||||
return raw.get(path, client=client)
|
return raw.get(path, client=client)
|
||||||
|
|
||||||
|
|
||||||
@ -734,7 +736,9 @@ def add_comment(
|
|||||||
task_status (str / dict): The task status dict or ID.
|
task_status (str / dict): The task status dict or ID.
|
||||||
comment (str): Comment text
|
comment (str): Comment text
|
||||||
person (str / dict): Comment author
|
person (str / dict): Comment author
|
||||||
date (str): Comment date
|
checklist (list): Comment checklist
|
||||||
|
attachments (list[file_path]): Attachments file paths
|
||||||
|
created_at (str): Comment date
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Created comment.
|
dict: Created comment.
|
||||||
@ -878,7 +882,9 @@ def add_preview(
|
|||||||
task (str / dict): The task dict or the task ID.
|
task (str / dict): The task dict or the task ID.
|
||||||
comment (str / dict): The comment or the comment ID.
|
comment (str / dict): The comment or the comment ID.
|
||||||
preview_file_path (str): Path of the file to upload as preview.
|
preview_file_path (str): Path of the file to upload as preview.
|
||||||
|
preview_file_path (str): Path of the file to upload as preview.
|
||||||
|
preview_file_url (str): Url to download the preview file if no path is
|
||||||
|
given.
|
||||||
Returns:
|
Returns:
|
||||||
dict: Created preview file model.
|
dict: Created preview file model.
|
||||||
"""
|
"""
|
||||||
@ -896,19 +902,74 @@ def add_preview(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def set_main_preview(preview_file, client=default):
|
def publish_preview(
|
||||||
|
task,
|
||||||
|
task_status,
|
||||||
|
comment="",
|
||||||
|
person=None,
|
||||||
|
checklist=[],
|
||||||
|
attachments=[],
|
||||||
|
created_at=None,
|
||||||
|
client=default,
|
||||||
|
preview_file_path=None,
|
||||||
|
preview_file_url=None,
|
||||||
|
normalize_movie=True,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Publish a comment and include given preview for given task and set given
|
||||||
|
task status.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
task (str / dict): The task dict or the task ID.
|
||||||
|
task_status (str / dict): The task status dict or ID.
|
||||||
|
comment (str): Comment text
|
||||||
|
person (str / dict): Comment author
|
||||||
|
checklist (list): Comment checklist
|
||||||
|
attachments (list[file_path]): Attachments file paths
|
||||||
|
created_at (str): Comment date
|
||||||
|
preview_file_path (str): Path of the file to upload as preview.
|
||||||
|
preview_file_url (str): Url to download the preview file if no path is
|
||||||
|
given.
|
||||||
|
normalize_movie (bool): Set to false to not do operations on it on the
|
||||||
|
server side.
|
||||||
|
Returns:
|
||||||
|
dict: Created preview file model.
|
||||||
|
"""
|
||||||
|
new_comment = add_comment(
|
||||||
|
task,
|
||||||
|
task_status,
|
||||||
|
comment=comment,
|
||||||
|
person=person,
|
||||||
|
checklist=checklist,
|
||||||
|
attachments=[],
|
||||||
|
created_at=created_at,
|
||||||
|
client=client,
|
||||||
|
)
|
||||||
|
add_preview(
|
||||||
|
task,
|
||||||
|
new_comment,
|
||||||
|
preview_file_path=preview_file_path,
|
||||||
|
preview_file_url=preview_file_url,
|
||||||
|
normalize_movie=normalize_movie,
|
||||||
|
)
|
||||||
|
return new_comment
|
||||||
|
|
||||||
|
|
||||||
|
def set_main_preview(preview_file, frame_number, client=default):
|
||||||
"""
|
"""
|
||||||
Set given preview as thumbnail of given entity.
|
Set given preview as thumbnail of given entity.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
preview_file (str / dict): The preview file dict or ID.
|
preview_file (str / dict): The preview file dict or ID.
|
||||||
|
frame_number (int): Frame of preview video to set as main preview
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Created preview file model.
|
dict: Created preview file model.
|
||||||
"""
|
"""
|
||||||
|
data = {"frame_number": frame_number} if frame_number > 1 else {}
|
||||||
preview_file = normalize_model_parameter(preview_file)
|
preview_file = normalize_model_parameter(preview_file)
|
||||||
path = "actions/preview-files/%s/set-main-preview" % preview_file["id"]
|
path = "actions/preview-files/%s/set-main-preview" % preview_file["id"]
|
||||||
return raw.put(path, {}, client=client)
|
return raw.put(path, data, client=client)
|
||||||
|
|
||||||
|
|
||||||
@cache
|
@cache
|
||||||
@ -954,17 +1015,19 @@ def assign_task(task, person, client=default):
|
|||||||
return raw.put(path, {"task_ids": task["id"]}, client=client)
|
return raw.put(path, {"task_ids": task["id"]}, client=client)
|
||||||
|
|
||||||
|
|
||||||
def new_task_type(name, client=default):
|
def new_task_type(name, color="#000000", client=default):
|
||||||
"""
|
"""
|
||||||
Create a new task type with the given name.
|
Create a new task type with the given name.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name (str): The name of the task type
|
name (str): The name of the task type
|
||||||
|
color (str): The color of the task type as an hexadecimal string
|
||||||
|
with # as first character. ex : #00FF00
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: The created task type
|
dict: The created task type
|
||||||
"""
|
"""
|
||||||
data = {"name": name}
|
data = {"name": name, "color": color}
|
||||||
return raw.post("data/task-types", data, client=client)
|
return raw.post("data/task-types", data, client=client)
|
||||||
|
|
||||||
|
|
||||||
@ -975,7 +1038,7 @@ def new_task_status(name, short_name, color, client=default):
|
|||||||
Args:
|
Args:
|
||||||
name (str): The name of the task status
|
name (str): The name of the task status
|
||||||
short_name (str): The short name of the task status
|
short_name (str): The short name of the task status
|
||||||
color (str): The color of the task status has an hexadecimal string
|
color (str): The color of the task status as an hexadecimal string
|
||||||
with # as first character. ex : #00FF00
|
with # as first character. ex : #00FF00
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@ -1032,12 +1095,13 @@ def update_task_data(task, data={}, client=default):
|
|||||||
def get_task_url(task, client=default):
|
def get_task_url(task, client=default):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
task (str / dict): The task dict or the task ID.
|
task (dict): The task dict.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
url (str): Web url associated to the given task
|
url (str): Web url associated to the given task
|
||||||
"""
|
"""
|
||||||
task = normalize_model_parameter(task)
|
if not isinstance(task, dict):
|
||||||
|
raise TaskMustBeADictException
|
||||||
path = "{host}/productions/{project_id}/shots/tasks/{task_id}/"
|
path = "{host}/productions/{project_id}/shots/tasks/{task_id}/"
|
||||||
return path.format(
|
return path.format(
|
||||||
host=raw.get_api_url_from_host(client=client),
|
host=raw.get_api_url_from_host(client=client),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import datetime
|
import datetime
|
||||||
from .exception import NotAuthenticatedException
|
from gazu.exception import NotAuthenticatedException
|
||||||
|
|
||||||
from . import client as raw
|
from . import client as raw
|
||||||
from .sorting import sort_by_name
|
from .sorting import sort_by_name
|
||||||
@ -247,6 +247,26 @@ def all_done_tasks(client=default):
|
|||||||
return raw.fetch_all("user/done-tasks", client=client)
|
return raw.fetch_all("user/done-tasks", client=client)
|
||||||
|
|
||||||
|
|
||||||
|
@cache
|
||||||
|
def get_timespents_range(start_date, end_date, client=default):
|
||||||
|
"""
|
||||||
|
Gets the timespents of the current user for the given date range.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
start_date (str): The first day of the date range as a date string with
|
||||||
|
the following format: YYYY-MM-DD
|
||||||
|
end_date (str): The last day of the date range as a date string with
|
||||||
|
the following format: YYYY-MM-DD
|
||||||
|
Returns:
|
||||||
|
list: All of the person's time spents
|
||||||
|
"""
|
||||||
|
date_range = {
|
||||||
|
"start_date": start_date,
|
||||||
|
"end_date": end_date,
|
||||||
|
}
|
||||||
|
return raw.get("/data/user/time-spents", params=date_range, client=client)
|
||||||
|
|
||||||
|
|
||||||
def log_desktop_session_log_in(client=default):
|
def log_desktop_session_log_in(client=default):
|
||||||
"""
|
"""
|
||||||
Add a log entry to mention that the user logged in his computer.
|
Add a log entry to mention that the user logged in his computer.
|
||||||
|
Loading…
Reference in New Issue
Block a user