mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-06 05:01:14 -07:00
Update cloudinary-1.26.0
This commit is contained in:
parent
ebffd124f6
commit
4b28040d59
17 changed files with 1169 additions and 307 deletions
|
@ -1,5 +1,6 @@
|
|||
# Copyright Cloudinary
|
||||
|
||||
import datetime
|
||||
import email.utils
|
||||
import json
|
||||
import socket
|
||||
|
@ -10,6 +11,11 @@ from urllib3.exceptions import HTTPError
|
|||
|
||||
import cloudinary
|
||||
from cloudinary import utils
|
||||
from cloudinary.api_client.call_api import (
|
||||
call_api,
|
||||
call_metadata_api,
|
||||
call_json_api
|
||||
)
|
||||
from cloudinary.exceptions import (
|
||||
BadRequest,
|
||||
AuthorizationRequired,
|
||||
|
@ -20,37 +26,32 @@ from cloudinary.exceptions import (
|
|||
GeneralError
|
||||
)
|
||||
|
||||
logger = cloudinary.logger
|
||||
|
||||
EXCEPTION_CODES = {
|
||||
400: BadRequest,
|
||||
401: AuthorizationRequired,
|
||||
403: NotAllowed,
|
||||
404: NotFound,
|
||||
409: AlreadyExists,
|
||||
420: RateLimited,
|
||||
500: GeneralError
|
||||
}
|
||||
|
||||
|
||||
class Response(dict):
|
||||
def __init__(self, result, response, **kwargs):
|
||||
super(Response, self).__init__(**kwargs)
|
||||
self.update(result)
|
||||
self.rate_limit_allowed = int(response.headers["x-featureratelimit-limit"])
|
||||
self.rate_limit_reset_at = email.utils.parsedate(response.headers["x-featureratelimit-reset"])
|
||||
self.rate_limit_remaining = int(response.headers["x-featureratelimit-remaining"])
|
||||
|
||||
|
||||
_http = utils.get_http_connector(cloudinary.config(), cloudinary.CERT_KWARGS)
|
||||
|
||||
|
||||
def ping(**options):
|
||||
return call_api("get", ["ping"], {}, **options)
|
||||
|
||||
|
||||
def usage(**options):
|
||||
return call_api("get", ["usage"], {}, **options)
|
||||
"""Get account usage details.
|
||||
|
||||
Get a report on the status of your Cloudinary account usage details, including storage, credits, bandwidth,
|
||||
requests, number of resources, and add-on usage. Note that numbers are updated periodically.
|
||||
|
||||
See: `Get account usage details
|
||||
<https://cloudinary.com/documentation/admin_api#get_account_usage_details>`_
|
||||
|
||||
:param options: Additional options
|
||||
:type options: dict, optional
|
||||
:return: Detailed usage information
|
||||
:rtype: Response
|
||||
"""
|
||||
date = options.pop("date", None)
|
||||
uri = ["usage"]
|
||||
if date:
|
||||
if isinstance(date, datetime.date):
|
||||
date = utils.encode_date_to_usage_api_format(date)
|
||||
uri.append(date)
|
||||
return call_api("get", uri, {}, **options)
|
||||
|
||||
|
||||
def resource_types(**options):
|
||||
|
@ -64,7 +65,7 @@ def resources(**options):
|
|||
if upload_type:
|
||||
uri.append(upload_type)
|
||||
params = only(options, "next_cursor", "max_results", "prefix", "tags",
|
||||
"context", "moderations", "direction", "start_at")
|
||||
"context", "moderations", "direction", "start_at", "metadata")
|
||||
return call_api("get", uri, params, **options)
|
||||
|
||||
|
||||
|
@ -72,7 +73,7 @@ def resources_by_tag(tag, **options):
|
|||
resource_type = options.pop("resource_type", "image")
|
||||
uri = ["resources", resource_type, "tags", tag]
|
||||
params = only(options, "next_cursor", "max_results", "tags",
|
||||
"context", "moderations", "direction")
|
||||
"context", "moderations", "direction", "metadata")
|
||||
return call_api("get", uri, params, **options)
|
||||
|
||||
|
||||
|
@ -80,7 +81,7 @@ def resources_by_moderation(kind, status, **options):
|
|||
resource_type = options.pop("resource_type", "image")
|
||||
uri = ["resources", resource_type, "moderations", kind, status]
|
||||
params = only(options, "next_cursor", "max_results", "tags",
|
||||
"context", "moderations", "direction")
|
||||
"context", "moderations", "direction", "metadata")
|
||||
return call_api("get", uri, params, **options)
|
||||
|
||||
|
||||
|
@ -92,12 +93,39 @@ def resources_by_ids(public_ids, **options):
|
|||
return call_api("get", uri, params, **options)
|
||||
|
||||
|
||||
def resources_by_context(key, value=None, **options):
|
||||
"""Retrieves resources (assets) with a specified context key.
|
||||
This method does not return deleted assets even if they have been backed up.
|
||||
|
||||
See: `Get resources by context API reference
|
||||
<https://cloudinary.com/documentation/admin_api#get_resources_by_context>`_
|
||||
|
||||
:param key: Only assets with this context key are returned
|
||||
:type key: str
|
||||
:param value: Only assets with this value for the context key are returned
|
||||
:type value: str, optional
|
||||
:param options: Additional options
|
||||
:type options: dict, optional
|
||||
:return: Resources (assets) with a specified context key
|
||||
:rtype: Response
|
||||
"""
|
||||
resource_type = options.pop("resource_type", "image")
|
||||
uri = ["resources", resource_type, "context"]
|
||||
params = only(options, "next_cursor", "max_results", "tags",
|
||||
"context", "moderations", "direction", "metadata")
|
||||
params["key"] = key
|
||||
if value is not None:
|
||||
params["value"] = value
|
||||
return call_api("get", uri, params, **options)
|
||||
|
||||
|
||||
def resource(public_id, **options):
|
||||
resource_type = options.pop("resource_type", "image")
|
||||
upload_type = options.pop("type", "upload")
|
||||
uri = ["resources", resource_type, upload_type, public_id]
|
||||
params = only(options, "exif", "faces", "colors", "image_metadata", "cinemagraph_analysis",
|
||||
"pages", "phash", "coordinates", "max_results", "quality_analysis", "derived_next_cursor")
|
||||
"pages", "phash", "coordinates", "max_results", "quality_analysis", "derived_next_cursor",
|
||||
"accessibility_analysis", "versions")
|
||||
return call_api("get", uri, params, **options)
|
||||
|
||||
|
||||
|
@ -327,8 +355,8 @@ def restore(public_ids, **options):
|
|||
resource_type = options.pop("resource_type", "image")
|
||||
upload_type = options.pop("type", "upload")
|
||||
uri = ["resources", resource_type, upload_type, "restore"]
|
||||
params = dict(public_ids=public_ids)
|
||||
return call_api("post", uri, params, **options)
|
||||
params = dict(public_ids=public_ids, **only(options, "versions"))
|
||||
return call_json_api("post", uri, params, **options)
|
||||
|
||||
|
||||
def upload_mappings(**options):
|
||||
|
@ -390,90 +418,6 @@ def update_streaming_profile(name, **options):
|
|||
return call_api('PUT', uri, params, **options)
|
||||
|
||||
|
||||
def call_json_api(method, uri, jsonBody, **options):
|
||||
logger.debug(jsonBody)
|
||||
data = json.dumps(jsonBody).encode('utf-8')
|
||||
return _call_api(method, uri, body=data,
|
||||
headers={'Content-Type': 'application/json'}, **options)
|
||||
|
||||
|
||||
def call_api(method, uri, params, **options):
|
||||
return _call_api(method, uri, params=params, **options)
|
||||
|
||||
|
||||
def call_metadata_api(method, uri, params, **options):
|
||||
"""Private function that assists with performing an API call to the
|
||||
metadata_fields part of the Admin API
|
||||
|
||||
:param method: The HTTP method. Valid methods: get, post, put, delete
|
||||
:param uri: REST endpoint of the API (without 'metadata_fields')
|
||||
:param params: Query/body parameters passed to the method
|
||||
:param options: Additional options
|
||||
|
||||
:rtype: Response
|
||||
"""
|
||||
uri = ["metadata_fields"] + (uri or [])
|
||||
return call_json_api(method, uri, params, **options)
|
||||
|
||||
|
||||
def _call_api(method, uri, params=None, body=None, headers=None, **options):
|
||||
prefix = options.pop("upload_prefix",
|
||||
cloudinary.config().upload_prefix) or "https://api.cloudinary.com"
|
||||
cloud_name = options.pop("cloud_name", cloudinary.config().cloud_name)
|
||||
if not cloud_name:
|
||||
raise Exception("Must supply cloud_name")
|
||||
api_key = options.pop("api_key", cloudinary.config().api_key)
|
||||
if not api_key:
|
||||
raise Exception("Must supply api_key")
|
||||
api_secret = options.pop("api_secret", cloudinary.config().api_secret)
|
||||
if not cloud_name:
|
||||
raise Exception("Must supply api_secret")
|
||||
api_url = "/".join([prefix, "v1_1", cloud_name] + uri)
|
||||
|
||||
processed_params = None
|
||||
if isinstance(params, dict):
|
||||
processed_params = {}
|
||||
for key, value in params.items():
|
||||
if isinstance(value, list) or isinstance(value, tuple):
|
||||
value_list = {"{}[{}]".format(key, i): i_value for i, i_value in enumerate(value)}
|
||||
processed_params.update(value_list)
|
||||
elif value:
|
||||
processed_params[key] = value
|
||||
|
||||
# Add authentication
|
||||
req_headers = urllib3.make_headers(
|
||||
basic_auth="{0}:{1}".format(api_key, api_secret),
|
||||
user_agent=cloudinary.get_user_agent()
|
||||
)
|
||||
if headers is not None:
|
||||
req_headers.update(headers)
|
||||
kw = {}
|
||||
if 'timeout' in options:
|
||||
kw['timeout'] = options['timeout']
|
||||
if body is not None:
|
||||
kw['body'] = body
|
||||
try:
|
||||
response = _http.request(method.upper(), api_url, processed_params, req_headers, **kw)
|
||||
body = response.data
|
||||
except HTTPError as e:
|
||||
raise GeneralError("Unexpected error {0}", e.message)
|
||||
except socket.error as e:
|
||||
raise GeneralError("Socket Error: %s" % (str(e)))
|
||||
|
||||
try:
|
||||
result = json.loads(body.decode('utf-8'))
|
||||
except Exception as e:
|
||||
# Error is parsing json
|
||||
raise GeneralError("Error parsing server response (%d) - %s. Got - %s" % (response.status, body, e))
|
||||
|
||||
if "error" in result:
|
||||
exception_class = EXCEPTION_CODES.get(response.status) or Exception
|
||||
exception_class = exception_class
|
||||
raise exception_class("Error {0} - {1}".format(response.status, result["error"]["message"]))
|
||||
|
||||
return Response(result, response)
|
||||
|
||||
|
||||
def only(source, *keys):
|
||||
return {key: source[key] for key in keys if key in source}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue