gateway/modules/workflows/methods/methodSharepoint/actions/copyFile.py
2026-03-22 19:46:50 +01:00

159 lines
6.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
import logging
import json
from typing import Dict, Any
from modules.datamodels.datamodelChat import ActionResult, ActionDocument
logger = logging.getLogger(__name__)
async def copyFile(self, parameters: Dict[str, Any]) -> ActionResult:
try:
connectionReference = parameters.get("connectionReference")
if not connectionReference:
return ActionResult.isFailure(error="connectionReference parameter is required")
# Set SharePoint access token first required before siteDiscovery/sharepoint calls
connection = self.connection.getMicrosoftConnection(connectionReference)
if not connection:
return ActionResult.isFailure(error="No valid Microsoft connection found for the provided connection reference")
sourcePath = (parameters.get("sourcePath") or parameters.get("sourcePathQuery") or "").strip()
destPath = (parameters.get("destPath") or parameters.get("destPathQuery") or "").strip()
siteId = None
sourceFolder = None
sourceFile = None
destFolder = None
destFile = None
if sourcePath and destPath and sourcePath.startswith("/sites/") and destPath.startswith("/sites/"):
parsedSource = self.services.sharepoint.extractSiteFromStandardPath(sourcePath)
parsedDest = self.services.sharepoint.extractSiteFromStandardPath(destPath)
if parsedSource and parsedDest:
innerSrc = (parsedSource.get("innerPath") or "").strip().rstrip("/")
innerDest = (parsedDest.get("innerPath") or "").strip().rstrip("/")
if innerSrc:
if "/" in innerSrc:
sourceFolder = innerSrc.rsplit("/", 1)[0]
sourceFile = innerSrc.rsplit("/", 1)[-1]
else:
sourceFolder = ""
sourceFile = innerSrc
destFolder = innerDest
destFile = sourceFile
sites, _ = await self.siteDiscovery.resolveSitesFromPathQuery(sourcePath)
if sites:
siteId = sites[0].get("id")
if not siteId or not sourceFolder or not sourceFile or not destFolder:
siteIdParam = parameters.get("siteId")
sourceFolder = parameters.get("sourceFolder")
sourceFile = parameters.get("sourceFile")
destFolder = parameters.get("destFolder")
destFile = parameters.get("destFile")
if not siteIdParam:
return ActionResult.isFailure(error="Either sourcePath+destPath or siteId, sourceFolder, sourceFile, destFolder, destFile are required")
if not sourceFolder or not sourceFile or not destFolder or not destFile:
return ActionResult.isFailure(error="sourceFolder, sourceFile, destFolder, and destFile are required")
if not destFile:
destFile = sourceFile
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
if not siteId:
return ActionResult.isFailure(error="Could not resolve siteId")
# Copy file
await self.services.sharepoint.copyFileAsync(
siteId=siteId,
sourceFolder=sourceFolder,
sourceFile=sourceFile,
destFolder=destFolder,
destFile=destFile
)
logger.info(f"Copied file in SharePoint: {sourceFolder}/{sourceFile} -> {destFolder}/{destFile}")
# Generate filename
workflowContext = self.services.chat.getWorkflowContext() if hasattr(self.services, 'chat') else None
filename = self._generateMeaningfulFileName(
"file_copy_result",
"json",
workflowContext,
"copyFile"
)
result = {
"success": True,
"siteId": siteId,
"sourcePath": f"{sourceFolder}/{sourceFile}",
"destPath": f"{destFolder}/{destFile}"
}
validationMetadata = self._createValidationMetadata(
"copyFile",
siteId=siteId,
sourcePath=f"{sourceFolder}/{sourceFile}",
destPath=f"{destFolder}/{destFile}"
)
document = ActionDocument(
documentName=filename,
documentData=json.dumps(result, indent=2),
mimeType="application/json",
validationMetadata=validationMetadata
)
return ActionResult.isSuccess(documents=[document])
except Exception as e:
# Handle file not found gracefully
if "itemNotFound" in str(e) or "404" in str(e):
logger.warning(f"File not found for copy: {parameters.get('sourceFolder')}/{parameters.get('sourceFile')}")
# Return success with skipped status
workflowContext = self.services.chat.getWorkflowContext() if hasattr(self.services, 'chat') else None
filename = self._generateMeaningfulFileName(
"file_copy_result",
"json",
workflowContext,
"copyFile"
)
result = {
"success": True,
"skipped": True,
"reason": "File not found (may not exist yet)"
}
validationMetadata = self._createValidationMetadata(
"copyFile",
skipped=True
)
document = ActionDocument(
documentName=filename,
documentData=json.dumps(result, indent=2),
mimeType="application/json",
validationMetadata=validationMetadata
)
return ActionResult.isSuccess(documents=[document])
errorMsg = f"Error copying file in SharePoint: {str(e)}"
logger.error(errorMsg)
return ActionResult.isFailure(error=errorMsg)