Basic tools to list items in a folder, search for files / folders, and download a file content.
106 lines
3.1 KiB
Python
106 lines
3.1 KiB
Python
import json
|
|
from typing import Any, Optional
|
|
|
|
import httpx
|
|
|
|
from arcade_dropbox.constants import (
|
|
API_BASE_URL,
|
|
API_VERSION,
|
|
ENDPOINT_URL_MAP,
|
|
Endpoint,
|
|
EndpointType,
|
|
)
|
|
from arcade_dropbox.exceptions import DropboxApiError
|
|
|
|
|
|
def build_dropbox_url(endpoint_type: EndpointType, endpoint_path: str) -> str:
|
|
base_url = API_BASE_URL.format(endpoint_type=endpoint_type.value)
|
|
return f"{base_url}/{API_VERSION}/{endpoint_path.strip('/')}"
|
|
|
|
|
|
def build_dropbox_headers(token: Optional[str]) -> dict[str, str]:
|
|
return {"Authorization": f"Bearer {token}"} if token else {}
|
|
|
|
|
|
def build_dropbox_json(**kwargs: Any) -> dict:
|
|
return {key: value for key, value in kwargs.items() if value is not None}
|
|
|
|
|
|
async def send_dropbox_request(
|
|
authorization_token: Optional[str],
|
|
endpoint: Endpoint,
|
|
**kwargs: Any,
|
|
) -> Any:
|
|
endpoint_type, endpoint_path = ENDPOINT_URL_MAP[endpoint]
|
|
url = build_dropbox_url(endpoint_type, endpoint_path)
|
|
headers = build_dropbox_headers(authorization_token)
|
|
json_data = build_dropbox_json(**kwargs)
|
|
|
|
if json_data.get("cursor"):
|
|
url += "/continue"
|
|
# If cursor is provided, every other argument must be ignored to avoid API error
|
|
json_data = {"cursor": json_data["cursor"]}
|
|
|
|
if endpoint_type == EndpointType.CONTENT:
|
|
headers["Dropbox-API-Arg"] = json.dumps(json_data)
|
|
json_data = {}
|
|
|
|
async with httpx.AsyncClient() as client:
|
|
request_args: dict[str, Any] = {"url": url, "headers": headers}
|
|
|
|
if json_data:
|
|
request_args["json"] = json_data
|
|
|
|
response = await client.post(**request_args)
|
|
|
|
try:
|
|
data = response.json()
|
|
except Exception:
|
|
data = {}
|
|
|
|
if response.status_code != 200:
|
|
raise DropboxApiError(
|
|
status_code=response.status_code,
|
|
error_summary=data.get("error_summary", response.text),
|
|
user_message=data.get("user_message"),
|
|
)
|
|
|
|
if endpoint_type == EndpointType.CONTENT:
|
|
data = json.loads(response.headers["Dropbox-API-Result"])
|
|
data = clean_dropbox_entry(data, default_type="file")
|
|
data["content"] = response.text
|
|
return data
|
|
|
|
return response.json()
|
|
|
|
|
|
def clean_dropbox_entry(entry: dict, default_type: Optional[str] = None) -> dict:
|
|
return {
|
|
"type": entry.get(".tag", default_type),
|
|
"id": entry.get("id"),
|
|
"name": entry.get("name"),
|
|
"path": entry.get("path_display"),
|
|
"size_in_bytes": entry.get("size"),
|
|
"modified_datetime": entry.get("server_modified"),
|
|
}
|
|
|
|
|
|
def clean_dropbox_entries(entries: list[dict]) -> list[dict]:
|
|
return [clean_dropbox_entry(entry) for entry in entries]
|
|
|
|
|
|
def parse_dropbox_path(path: Optional[str]) -> Optional[str]:
|
|
if not isinstance(path, str):
|
|
return ""
|
|
|
|
if not path:
|
|
return ""
|
|
|
|
if path in ["/", "\\"]:
|
|
return ""
|
|
|
|
# Normalize windows-style paths to unix-style paths
|
|
path = path.replace("\\", "/")
|
|
|
|
# Dropbox expects the path to always start with a slash
|
|
return "/" + path.strip("/")
|