159 lines
6.6 KiB
Python
159 lines
6.6 KiB
Python
# 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)
|
||
|