Initial commit: MCP Hub Community Edition v3.0.0
Community edition generated from private repo via sync pipeline. Includes 9 plugins (WordPress, WooCommerce, WP Advanced, Gitea, n8n, Supabase, OpenPanel, Appwrite, Directus) with ~587 tools. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
685
plugins/appwrite/handlers/storage.py
Normal file
685
plugins/appwrite/handlers/storage.py
Normal file
@@ -0,0 +1,685 @@
|
||||
"""
|
||||
Storage Handler - manages Appwrite storage buckets and files
|
||||
|
||||
Phase I.3: 14 tools
|
||||
- Buckets: 5 (list, get, create, update, delete)
|
||||
- Files: 9 (list, get, create, update, delete, download, preview, view, get_url)
|
||||
"""
|
||||
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
from plugins.appwrite.client import AppwriteClient
|
||||
|
||||
def get_tool_specifications() -> list[dict[str, Any]]:
|
||||
"""Return tool specifications for ToolGenerator (14 tools)"""
|
||||
return [
|
||||
# =====================
|
||||
# BUCKETS (5)
|
||||
# =====================
|
||||
{
|
||||
"name": "list_buckets",
|
||||
"method_name": "list_buckets",
|
||||
"description": "List all storage buckets.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"queries": {
|
||||
"anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}],
|
||||
"description": "Query strings for filtering",
|
||||
},
|
||||
"search": {
|
||||
"anyOf": [{"type": "string"}, {"type": "null"}],
|
||||
"description": "Search term to filter buckets",
|
||||
},
|
||||
},
|
||||
"required": [],
|
||||
},
|
||||
"scope": "read",
|
||||
},
|
||||
{
|
||||
"name": "get_bucket",
|
||||
"method_name": "get_bucket",
|
||||
"description": "Get bucket details by ID.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {"bucket_id": {"type": "string", "description": "Bucket ID"}},
|
||||
"required": ["bucket_id"],
|
||||
},
|
||||
"scope": "read",
|
||||
},
|
||||
{
|
||||
"name": "create_bucket",
|
||||
"method_name": "create_bucket",
|
||||
"description": "Create a new storage bucket.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bucket_id": {
|
||||
"type": "string",
|
||||
"description": "Unique bucket ID. Use 'unique()' for auto-generation",
|
||||
},
|
||||
"name": {"type": "string", "description": "Bucket name"},
|
||||
"permissions": {
|
||||
"anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}],
|
||||
"description": "Bucket permissions",
|
||||
},
|
||||
"file_security": {
|
||||
"type": "boolean",
|
||||
"description": "Enable file-level security",
|
||||
"default": True,
|
||||
},
|
||||
"enabled": {"type": "boolean", "description": "Enable bucket", "default": True},
|
||||
"maximum_file_size": {
|
||||
"anyOf": [{"type": "integer"}, {"type": "null"}],
|
||||
"description": "Maximum file size in bytes",
|
||||
},
|
||||
"allowed_file_extensions": {
|
||||
"anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}],
|
||||
"description": "Allowed file extensions (e.g., ['jpg', 'png', 'pdf'])",
|
||||
},
|
||||
"compression": {
|
||||
"type": "string",
|
||||
"enum": ["none", "gzip", "zstd"],
|
||||
"description": "Compression algorithm",
|
||||
"default": "none",
|
||||
},
|
||||
"encryption": {
|
||||
"type": "boolean",
|
||||
"description": "Enable encryption",
|
||||
"default": True,
|
||||
},
|
||||
"antivirus": {
|
||||
"type": "boolean",
|
||||
"description": "Enable antivirus scanning",
|
||||
"default": True,
|
||||
},
|
||||
},
|
||||
"required": ["bucket_id", "name"],
|
||||
},
|
||||
"scope": "write",
|
||||
},
|
||||
{
|
||||
"name": "update_bucket",
|
||||
"method_name": "update_bucket",
|
||||
"description": "Update bucket settings.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bucket_id": {"type": "string", "description": "Bucket ID"},
|
||||
"name": {"type": "string", "description": "Bucket name"},
|
||||
"permissions": {
|
||||
"anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}],
|
||||
"description": "New permissions",
|
||||
},
|
||||
"enabled": {
|
||||
"anyOf": [{"type": "boolean"}, {"type": "null"}],
|
||||
"description": "Enable/disable bucket",
|
||||
},
|
||||
"maximum_file_size": {
|
||||
"anyOf": [{"type": "integer"}, {"type": "null"}],
|
||||
"description": "Maximum file size in bytes",
|
||||
},
|
||||
"allowed_file_extensions": {
|
||||
"anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}],
|
||||
"description": "Allowed extensions",
|
||||
},
|
||||
},
|
||||
"required": ["bucket_id", "name"],
|
||||
},
|
||||
"scope": "write",
|
||||
},
|
||||
{
|
||||
"name": "delete_bucket",
|
||||
"method_name": "delete_bucket",
|
||||
"description": "Delete a storage bucket. All files in the bucket will be deleted.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bucket_id": {"type": "string", "description": "Bucket ID to delete"}
|
||||
},
|
||||
"required": ["bucket_id"],
|
||||
},
|
||||
"scope": "admin",
|
||||
},
|
||||
# =====================
|
||||
# FILES (9)
|
||||
# =====================
|
||||
{
|
||||
"name": "list_files",
|
||||
"method_name": "list_files",
|
||||
"description": "List files in a bucket.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bucket_id": {"type": "string", "description": "Bucket ID"},
|
||||
"queries": {
|
||||
"anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}],
|
||||
"description": "Query strings for filtering",
|
||||
},
|
||||
"search": {
|
||||
"anyOf": [{"type": "string"}, {"type": "null"}],
|
||||
"description": "Search term to filter files by name",
|
||||
},
|
||||
},
|
||||
"required": ["bucket_id"],
|
||||
},
|
||||
"scope": "read",
|
||||
},
|
||||
{
|
||||
"name": "get_file",
|
||||
"method_name": "get_file",
|
||||
"description": "Get file metadata (not content).",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bucket_id": {"type": "string", "description": "Bucket ID"},
|
||||
"file_id": {"type": "string", "description": "File ID"},
|
||||
},
|
||||
"required": ["bucket_id", "file_id"],
|
||||
},
|
||||
"scope": "read",
|
||||
},
|
||||
{
|
||||
"name": "delete_file",
|
||||
"method_name": "delete_file",
|
||||
"description": "Delete a file from storage.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bucket_id": {"type": "string", "description": "Bucket ID"},
|
||||
"file_id": {"type": "string", "description": "File ID to delete"},
|
||||
},
|
||||
"required": ["bucket_id", "file_id"],
|
||||
},
|
||||
"scope": "write",
|
||||
},
|
||||
{
|
||||
"name": "download_file",
|
||||
"method_name": "download_file",
|
||||
"description": "Download file content. Returns base64 encoded data.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bucket_id": {"type": "string", "description": "Bucket ID"},
|
||||
"file_id": {"type": "string", "description": "File ID"},
|
||||
},
|
||||
"required": ["bucket_id", "file_id"],
|
||||
},
|
||||
"scope": "read",
|
||||
},
|
||||
{
|
||||
"name": "get_file_preview",
|
||||
"method_name": "get_file_preview",
|
||||
"description": "Get image preview with transformations (resize, crop, etc.). Only works for image files.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bucket_id": {"type": "string", "description": "Bucket ID"},
|
||||
"file_id": {"type": "string", "description": "File ID"},
|
||||
"width": {
|
||||
"anyOf": [
|
||||
{"type": "integer", "minimum": 0, "maximum": 4000},
|
||||
{"type": "null"},
|
||||
],
|
||||
"description": "Width in pixels (0-4000)",
|
||||
},
|
||||
"height": {
|
||||
"anyOf": [
|
||||
{"type": "integer", "minimum": 0, "maximum": 4000},
|
||||
{"type": "null"},
|
||||
],
|
||||
"description": "Height in pixels (0-4000)",
|
||||
},
|
||||
"gravity": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"center",
|
||||
"top",
|
||||
"top-left",
|
||||
"top-right",
|
||||
"left",
|
||||
"right",
|
||||
"bottom",
|
||||
"bottom-left",
|
||||
"bottom-right",
|
||||
],
|
||||
},
|
||||
{"type": "null"},
|
||||
],
|
||||
"description": "Crop gravity",
|
||||
},
|
||||
"quality": {
|
||||
"anyOf": [
|
||||
{"type": "integer", "minimum": 0, "maximum": 100},
|
||||
{"type": "null"},
|
||||
],
|
||||
"description": "Image quality (0-100)",
|
||||
},
|
||||
"border_width": {
|
||||
"anyOf": [{"type": "integer"}, {"type": "null"}],
|
||||
"description": "Border width in pixels",
|
||||
},
|
||||
"border_color": {
|
||||
"anyOf": [{"type": "string"}, {"type": "null"}],
|
||||
"description": "Border color (hex without #)",
|
||||
},
|
||||
"border_radius": {
|
||||
"anyOf": [{"type": "integer"}, {"type": "null"}],
|
||||
"description": "Border radius for rounded corners",
|
||||
},
|
||||
"rotation": {
|
||||
"anyOf": [
|
||||
{"type": "integer", "minimum": 0, "maximum": 360},
|
||||
{"type": "null"},
|
||||
],
|
||||
"description": "Rotation angle (0-360)",
|
||||
},
|
||||
"background": {
|
||||
"anyOf": [{"type": "string"}, {"type": "null"}],
|
||||
"description": "Background color (hex without #)",
|
||||
},
|
||||
"output": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["jpeg", "jpg", "png", "gif", "webp", "avif"],
|
||||
},
|
||||
{"type": "null"},
|
||||
],
|
||||
"description": "Output format",
|
||||
},
|
||||
},
|
||||
"required": ["bucket_id", "file_id"],
|
||||
},
|
||||
"scope": "read",
|
||||
},
|
||||
{
|
||||
"name": "get_file_view",
|
||||
"method_name": "get_file_view",
|
||||
"description": "Get file content for viewing in browser. Returns base64 encoded data.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bucket_id": {"type": "string", "description": "Bucket ID"},
|
||||
"file_id": {"type": "string", "description": "File ID"},
|
||||
},
|
||||
"required": ["bucket_id", "file_id"],
|
||||
},
|
||||
"scope": "read",
|
||||
},
|
||||
{
|
||||
"name": "get_file_url",
|
||||
"method_name": "get_file_url",
|
||||
"description": "Get the public URL for a file (if bucket is public).",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bucket_id": {"type": "string", "description": "Bucket ID"},
|
||||
"file_id": {"type": "string", "description": "File ID"},
|
||||
"url_type": {
|
||||
"type": "string",
|
||||
"enum": ["view", "download", "preview"],
|
||||
"description": "Type of URL to generate",
|
||||
"default": "view",
|
||||
},
|
||||
},
|
||||
"required": ["bucket_id", "file_id"],
|
||||
},
|
||||
"scope": "read",
|
||||
},
|
||||
{
|
||||
"name": "bulk_delete_files",
|
||||
"method_name": "bulk_delete_files",
|
||||
"description": "Delete multiple files from a bucket.",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"bucket_id": {"type": "string", "description": "Bucket ID"},
|
||||
"file_ids": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Array of file IDs to delete",
|
||||
},
|
||||
},
|
||||
"required": ["bucket_id", "file_ids"],
|
||||
},
|
||||
"scope": "write",
|
||||
},
|
||||
{
|
||||
"name": "get_bucket_stats",
|
||||
"method_name": "get_bucket_stats",
|
||||
"description": "Get storage statistics for a bucket (file count and total size).",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {"bucket_id": {"type": "string", "description": "Bucket ID"}},
|
||||
"required": ["bucket_id"],
|
||||
},
|
||||
"scope": "read",
|
||||
},
|
||||
]
|
||||
|
||||
# =====================
|
||||
# HANDLER FUNCTIONS
|
||||
# =====================
|
||||
|
||||
async def list_buckets(
|
||||
client: AppwriteClient, queries: list[str] | None = None, search: str | None = None
|
||||
) -> str:
|
||||
"""List all buckets."""
|
||||
try:
|
||||
result = await client.list_buckets(queries=queries, search=search)
|
||||
buckets = result.get("buckets", [])
|
||||
|
||||
response = {"success": True, "total": result.get("total", len(buckets)), "buckets": buckets}
|
||||
return json.dumps(response, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def get_bucket(client: AppwriteClient, bucket_id: str) -> str:
|
||||
"""Get bucket by ID."""
|
||||
try:
|
||||
result = await client.get_bucket(bucket_id)
|
||||
return json.dumps({"success": True, "bucket": result}, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def create_bucket(
|
||||
client: AppwriteClient,
|
||||
bucket_id: str,
|
||||
name: str,
|
||||
permissions: list[str] | None = None,
|
||||
file_security: bool = True,
|
||||
enabled: bool = True,
|
||||
maximum_file_size: int | None = None,
|
||||
allowed_file_extensions: list[str] | None = None,
|
||||
compression: str = "none",
|
||||
encryption: bool = True,
|
||||
antivirus: bool = True,
|
||||
) -> str:
|
||||
"""Create a new bucket."""
|
||||
try:
|
||||
result = await client.create_bucket(
|
||||
bucket_id=bucket_id,
|
||||
name=name,
|
||||
permissions=permissions,
|
||||
file_security=file_security,
|
||||
enabled=enabled,
|
||||
maximum_file_size=maximum_file_size,
|
||||
allowed_file_extensions=allowed_file_extensions,
|
||||
compression=compression,
|
||||
encryption=encryption,
|
||||
antivirus=antivirus,
|
||||
)
|
||||
return json.dumps(
|
||||
{"success": True, "message": f"Bucket '{name}' created successfully", "bucket": result},
|
||||
indent=2,
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def update_bucket(
|
||||
client: AppwriteClient,
|
||||
bucket_id: str,
|
||||
name: str,
|
||||
permissions: list[str] | None = None,
|
||||
enabled: bool | None = None,
|
||||
maximum_file_size: int | None = None,
|
||||
allowed_file_extensions: list[str] | None = None,
|
||||
) -> str:
|
||||
"""Update bucket."""
|
||||
try:
|
||||
result = await client.update_bucket(
|
||||
bucket_id=bucket_id,
|
||||
name=name,
|
||||
permissions=permissions,
|
||||
enabled=enabled,
|
||||
maximum_file_size=maximum_file_size,
|
||||
allowed_file_extensions=allowed_file_extensions,
|
||||
)
|
||||
return json.dumps(
|
||||
{"success": True, "message": "Bucket updated successfully", "bucket": result},
|
||||
indent=2,
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def delete_bucket(client: AppwriteClient, bucket_id: str) -> str:
|
||||
"""Delete bucket."""
|
||||
try:
|
||||
await client.delete_bucket(bucket_id)
|
||||
return json.dumps(
|
||||
{"success": True, "message": f"Bucket '{bucket_id}' deleted successfully"}, indent=2
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def list_files(
|
||||
client: AppwriteClient,
|
||||
bucket_id: str,
|
||||
queries: list[str] | None = None,
|
||||
search: str | None = None,
|
||||
) -> str:
|
||||
"""List files in bucket."""
|
||||
try:
|
||||
result = await client.list_files(bucket_id=bucket_id, queries=queries, search=search)
|
||||
files = result.get("files", [])
|
||||
|
||||
response = {
|
||||
"success": True,
|
||||
"bucket_id": bucket_id,
|
||||
"total": result.get("total", len(files)),
|
||||
"files": files,
|
||||
}
|
||||
return json.dumps(response, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def get_file(client: AppwriteClient, bucket_id: str, file_id: str) -> str:
|
||||
"""Get file metadata."""
|
||||
try:
|
||||
result = await client.get_file(bucket_id, file_id)
|
||||
return json.dumps({"success": True, "file": result}, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def delete_file(client: AppwriteClient, bucket_id: str, file_id: str) -> str:
|
||||
"""Delete file."""
|
||||
try:
|
||||
await client.delete_file(bucket_id, file_id)
|
||||
return json.dumps(
|
||||
{"success": True, "message": f"File '{file_id}' deleted successfully"}, indent=2
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def download_file(client: AppwriteClient, bucket_id: str, file_id: str) -> str:
|
||||
"""Download file content."""
|
||||
try:
|
||||
result = await client.get_file_download(bucket_id, file_id)
|
||||
return json.dumps(
|
||||
{
|
||||
"success": True,
|
||||
"file_id": file_id,
|
||||
"content_type": result.get("content_type"),
|
||||
"size": result.get("size"),
|
||||
"data_base64": result.get("data"),
|
||||
},
|
||||
indent=2,
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def get_file_preview(
|
||||
client: AppwriteClient,
|
||||
bucket_id: str,
|
||||
file_id: str,
|
||||
width: int | None = None,
|
||||
height: int | None = None,
|
||||
gravity: str | None = None,
|
||||
quality: int | None = None,
|
||||
border_width: int | None = None,
|
||||
border_color: str | None = None,
|
||||
border_radius: int | None = None,
|
||||
rotation: int | None = None,
|
||||
background: str | None = None,
|
||||
output: str | None = None,
|
||||
) -> str:
|
||||
"""Get file preview with transformations."""
|
||||
try:
|
||||
result = await client.get_file_preview(
|
||||
bucket_id=bucket_id,
|
||||
file_id=file_id,
|
||||
width=width,
|
||||
height=height,
|
||||
gravity=gravity,
|
||||
quality=quality,
|
||||
border_width=border_width,
|
||||
border_color=border_color,
|
||||
border_radius=border_radius,
|
||||
rotation=rotation,
|
||||
background=background,
|
||||
output=output,
|
||||
)
|
||||
return json.dumps(
|
||||
{
|
||||
"success": True,
|
||||
"file_id": file_id,
|
||||
"transformations": {
|
||||
"width": width,
|
||||
"height": height,
|
||||
"quality": quality,
|
||||
"output": output,
|
||||
},
|
||||
"content_type": result.get("content_type"),
|
||||
"size": result.get("size"),
|
||||
"data_base64": result.get("data"),
|
||||
},
|
||||
indent=2,
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def get_file_view(client: AppwriteClient, bucket_id: str, file_id: str) -> str:
|
||||
"""Get file for viewing."""
|
||||
try:
|
||||
result = await client.get_file_view(bucket_id, file_id)
|
||||
return json.dumps(
|
||||
{
|
||||
"success": True,
|
||||
"file_id": file_id,
|
||||
"content_type": result.get("content_type"),
|
||||
"size": result.get("size"),
|
||||
"data_base64": result.get("data"),
|
||||
},
|
||||
indent=2,
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def get_file_url(
|
||||
client: AppwriteClient, bucket_id: str, file_id: str, url_type: str = "view"
|
||||
) -> str:
|
||||
"""Get file URL."""
|
||||
try:
|
||||
base_url = client.base_url
|
||||
if url_type == "download":
|
||||
url = f"{base_url}/storage/buckets/{bucket_id}/files/{file_id}/download"
|
||||
elif url_type == "preview":
|
||||
url = f"{base_url}/storage/buckets/{bucket_id}/files/{file_id}/preview"
|
||||
else:
|
||||
url = f"{base_url}/storage/buckets/{bucket_id}/files/{file_id}/view"
|
||||
|
||||
return json.dumps(
|
||||
{
|
||||
"success": True,
|
||||
"file_id": file_id,
|
||||
"url_type": url_type,
|
||||
"url": url,
|
||||
"note": "URL requires authentication unless bucket is public",
|
||||
},
|
||||
indent=2,
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def bulk_delete_files(client: AppwriteClient, bucket_id: str, file_ids: list[str]) -> str:
|
||||
"""Delete multiple files."""
|
||||
try:
|
||||
results = []
|
||||
errors = []
|
||||
|
||||
for file_id in file_ids:
|
||||
try:
|
||||
await client.delete_file(bucket_id, file_id)
|
||||
results.append({"id": file_id, "success": True})
|
||||
except Exception as e:
|
||||
errors.append({"file_id": file_id, "error": str(e)})
|
||||
|
||||
response = {
|
||||
"success": len(errors) == 0,
|
||||
"deleted": len(results),
|
||||
"failed": len(errors),
|
||||
"results": results,
|
||||
}
|
||||
if errors:
|
||||
response["errors"] = errors
|
||||
|
||||
return json.dumps(response, indent=2, ensure_ascii=False)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
|
||||
async def get_bucket_stats(client: AppwriteClient, bucket_id: str) -> str:
|
||||
"""Get bucket statistics."""
|
||||
try:
|
||||
# Get files without query params to avoid syntax errors
|
||||
# Appwrite returns first 25 files by default
|
||||
result = await client.list_files(bucket_id=bucket_id)
|
||||
files = result.get("files", [])
|
||||
total = result.get("total", len(files))
|
||||
|
||||
total_size = sum(f.get("sizeOriginal", 0) for f in files)
|
||||
|
||||
return json.dumps(
|
||||
{
|
||||
"success": True,
|
||||
"bucket_id": bucket_id,
|
||||
"stats": {
|
||||
"file_count": total,
|
||||
"total_size_bytes": total_size,
|
||||
"total_size_mb": round(total_size / (1024 * 1024), 2),
|
||||
"sample_count": len(files),
|
||||
},
|
||||
"note": (
|
||||
f"Size calculated from {len(files)} sampled files"
|
||||
if total > len(files)
|
||||
else None
|
||||
),
|
||||
},
|
||||
indent=2,
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return json.dumps({"success": False, "error": str(e)}, indent=2)
|
||||
Reference in New Issue
Block a user