gateway/modules/workflows/methods/methodClickup/actions/upload_attachment.py

88 lines
3.8 KiB
Python

# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
import base64
import json
import logging
from typing import Any, Dict
from modules.datamodels.datamodelChat import ActionDocument, ActionResult
from ..helpers.pathparse import parse_task_id
logger = logging.getLogger(__name__)
async def upload_attachment(self, parameters: Dict[str, Any]) -> ActionResult:
connection_reference = parameters.get("connectionReference")
task_id = (parameters.get("taskId") or "").strip()
path_hint = (parameters.get("path") or "").strip()
if not connection_reference:
return ActionResult.isFailure(error="connectionReference is required")
if not task_id and path_hint:
task_id = parse_task_id(path_hint) or ""
if not task_id:
return ActionResult.isFailure(error="taskId is required")
conn = self.connection.get_clickup_connection(connection_reference)
if not conn:
return ActionResult.isFailure(error="No valid ClickUp connection")
content_param = parameters.get("content")
if not content_param:
return ActionResult.isFailure(error="content is required (connect a file node upstream)")
content = content_param[0] if isinstance(content_param, (list, tuple)) and content_param else content_param
file_name = parameters.get("fileName")
file_bytes = None
if isinstance(content, dict):
file_name = file_name or content.get("documentName") or content.get("fileName") or "attachment"
raw_data = content.get("documentData")
if (content.get("validationMetadata") or {}).get("fileId") and not raw_data:
fid = content["validationMetadata"]["fileId"]
try:
raw = self.services.chat.getFileData(fid)
file_bytes = raw if isinstance(raw, bytes) else str(raw).encode("utf-8")
except Exception as e:
return ActionResult.isFailure(error=f"Could not load file {fid}: {e}")
elif raw_data is not None:
if isinstance(raw_data, bytes):
file_bytes = raw_data
elif isinstance(raw_data, str):
try:
file_bytes = base64.b64decode(raw_data)
except Exception:
file_bytes = raw_data.encode("utf-8")
else:
return ActionResult.isFailure(error="Unsupported documentData type")
else:
return ActionResult.isFailure(error="Could not read file bytes from content")
elif hasattr(content, "documentData"):
file_name = file_name or getattr(content, "documentName", None) or getattr(content, "fileName", None) or "attachment"
raw_data = content.documentData
if isinstance(raw_data, bytes):
file_bytes = raw_data
elif isinstance(raw_data, str):
try:
file_bytes = base64.b64decode(raw_data)
except Exception:
file_bytes = raw_data.encode("utf-8")
else:
return ActionResult.isFailure(error="Unsupported documentData on ActionDocument")
else:
return ActionResult.isFailure(error="Unsupported content format")
if not file_bytes:
return ActionResult.isFailure(error="Empty file content")
data = await self.services.clickup.uploadTaskAttachment(task_id, file_bytes, file_name or "file")
if isinstance(data, dict) and data.get("error"):
return ActionResult.isFailure(error=str(data.get("error")) + (data.get("body") or ""))
doc = ActionDocument(
documentName="clickup_upload_attachment.json",
documentData=json.dumps(data, ensure_ascii=False, indent=2),
mimeType="application/json",
validationMetadata={"actionType": "clickup.uploadAttachment", "taskId": task_id},
)
return ActionResult.isSuccess(documents=[doc])