158 lines
7.3 KiB
Python
158 lines
7.3 KiB
Python
# Copyright (c) 2025 Patrick Motsch
|
|
# All rights reserved.
|
|
|
|
import logging
|
|
import json
|
|
import base64
|
|
from typing import Dict, Any
|
|
from modules.datamodels.datamodelChat import ActionResult, ActionDocument
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
async def uploadFile(self, parameters: Dict[str, Any]) -> ActionResult:
|
|
try:
|
|
connectionReference = parameters.get("connectionReference")
|
|
if not connectionReference:
|
|
return ActionResult.isFailure(error="connectionReference parameter is required")
|
|
|
|
contentParam = parameters.get("content")
|
|
if not contentParam:
|
|
return ActionResult.isFailure(error="content parameter is required")
|
|
|
|
# Resolve siteId and folderPath: pathQuery (path) or explicit siteId+folderPath
|
|
pathQuery = (parameters.get("pathQuery") or parameters.get("path") or "").strip()
|
|
siteIdParam = parameters.get("siteId")
|
|
folderPath = parameters.get("folderPath")
|
|
siteId = None
|
|
|
|
if pathQuery and pathQuery != "*":
|
|
# Option 1: pathQuery (e.g. /sites/host,siteId,webId/15. Persoenliche Ordner/Ida Dittrich/)
|
|
sites, errorMsg = await self.siteDiscovery.resolveSitesFromPathQuery(pathQuery)
|
|
if errorMsg:
|
|
return ActionResult.isFailure(error=errorMsg)
|
|
if not sites:
|
|
return ActionResult.isFailure(error="Could not resolve site from path")
|
|
parsedPath = self.services.sharepoint.extractSiteFromStandardPath(pathQuery)
|
|
if not parsedPath:
|
|
return ActionResult.isFailure(error="path must be a standard SharePoint path (e.g. /sites/SiteName/Shared Documents/Folder)")
|
|
innerPath = (parsedPath.get("innerPath") or "").strip().rstrip("/")
|
|
siteId = sites[0].get("id")
|
|
folderPath = innerPath
|
|
elif siteIdParam and folderPath:
|
|
# Option 2: explicit siteId + folderPath
|
|
if isinstance(siteIdParam, str):
|
|
from modules.datamodels.datamodelDocref import DocumentReferenceList
|
|
try:
|
|
docList = DocumentReferenceList.from_string_list([siteIdParam])
|
|
chatDocuments = self.services.chat.getChatDocumentsFromDocumentList(docList)
|
|
if chatDocuments and len(chatDocuments) > 0:
|
|
siteInfoJson = json.loads(chatDocuments[0].documentData)
|
|
siteId = siteInfoJson.get("id")
|
|
except Exception:
|
|
pass
|
|
if not siteId:
|
|
siteId = siteIdParam
|
|
else:
|
|
siteId = siteIdParam
|
|
else:
|
|
return ActionResult.isFailure(error="Either path (e.g. /sites/.../Folder) or both siteId and folderPath are required")
|
|
|
|
if not siteId:
|
|
return ActionResult.isFailure(error="Could not resolve siteId")
|
|
|
|
# fileName: from param or from content document
|
|
fileName = parameters.get("fileName")
|
|
if not fileName and contentParam:
|
|
content = contentParam[0] if isinstance(contentParam, (list, tuple)) and contentParam else contentParam
|
|
if isinstance(content, dict):
|
|
fileName = content.get("documentName") or content.get("fileName")
|
|
elif hasattr(content, "documentName"):
|
|
fileName = getattr(content, "documentName", None) or getattr(content, "fileName", None)
|
|
if not fileName:
|
|
fileName = "file"
|
|
|
|
# Get file content: support inline ActionDocument (from automation2 e.g. sharepoint.downloadFile)
|
|
# or docItem references (chat workflow)
|
|
content = contentParam[0] if isinstance(contentParam, (list, tuple)) and contentParam else contentParam
|
|
fileContentBase64 = None
|
|
if isinstance(content, dict) and content.get("documentData"):
|
|
fileContentBase64 = content.get("documentData")
|
|
elif hasattr(content, "documentData") and content.documentData:
|
|
fileContentBase64 = content.documentData
|
|
elif isinstance(content, dict) and (content.get("validationMetadata") or {}).get("fileId"):
|
|
file_id = content["validationMetadata"]["fileId"]
|
|
try:
|
|
raw = self.services.chat.getFileData(file_id)
|
|
fileContentBase64 = base64.b64encode(raw if isinstance(raw, bytes) else str(raw).encode("utf-8")).decode("utf-8")
|
|
except Exception as e:
|
|
return ActionResult.isFailure(error=f"Could not load file content from fileId {file_id}: {e}")
|
|
if not fileContentBase64:
|
|
from modules.datamodels.datamodelDocref import DocumentReferenceList
|
|
docList = DocumentReferenceList.from_string_list([content] if isinstance(content, str) else content)
|
|
chatDocuments = self.services.chat.getChatDocumentsFromDocumentList(docList)
|
|
if not chatDocuments or len(chatDocuments) == 0:
|
|
return ActionResult.isFailure(error="Could not get file content from document reference")
|
|
fileContentBase64 = chatDocuments[0].documentData
|
|
|
|
# Decode base64
|
|
try:
|
|
fileContent = base64.b64decode(fileContentBase64)
|
|
except Exception as e:
|
|
return ActionResult.isFailure(error=f"Could not decode base64 file content: {str(e)}")
|
|
|
|
# Get Microsoft connection
|
|
connection = self.connection.getMicrosoftConnection(connectionReference)
|
|
if not connection:
|
|
return ActionResult.isFailure(error="No valid Microsoft connection found for the provided connection reference")
|
|
|
|
# Upload file
|
|
uploadResult = await self.services.sharepoint.uploadFile(
|
|
siteId=siteId,
|
|
folderPath=folderPath,
|
|
fileName=fileName,
|
|
content=fileContent
|
|
)
|
|
|
|
if "error" in uploadResult:
|
|
return ActionResult.isFailure(error=f"Upload failed: {uploadResult['error']}")
|
|
|
|
logger.info(f"Uploaded file to SharePoint: {folderPath}/{fileName} ({len(fileContent)} bytes)")
|
|
|
|
# Generate filename
|
|
workflowContext = self.services.chat.getWorkflowContext() if hasattr(self.services, 'chat') else None
|
|
filename = self._generateMeaningfulFileName(
|
|
"file_upload_result",
|
|
"json",
|
|
workflowContext,
|
|
"uploadFile"
|
|
)
|
|
|
|
result = {
|
|
"success": True,
|
|
"siteId": siteId,
|
|
"filePath": f"{folderPath}/{fileName}",
|
|
"fileSize": len(fileContent),
|
|
"uploadResult": uploadResult
|
|
}
|
|
|
|
validationMetadata = self._createValidationMetadata(
|
|
"uploadFile",
|
|
siteId=siteId,
|
|
filePath=f"{folderPath}/{fileName}",
|
|
fileSize=len(fileContent)
|
|
)
|
|
|
|
document = ActionDocument(
|
|
documentName=filename,
|
|
documentData=json.dumps(result, indent=2),
|
|
mimeType="application/json",
|
|
validationMetadata=validationMetadata
|
|
)
|
|
|
|
return ActionResult.isSuccess(documents=[document])
|
|
|
|
except Exception as e:
|
|
errorMsg = f"Error uploading file to SharePoint: {str(e)}"
|
|
logger.error(errorMsg)
|
|
return ActionResult.isFailure(error=errorMsg)
|
|
|