gateway/modules/workflows/methods/methodSharepoint/helpers/siteDiscovery.py
2025-12-17 10:45:09 +01:00

173 lines
6.3 KiB
Python

# Copyright (c) 2025 Patrick Motsch
# All rights reserved.
"""
Site Discovery helper for SharePoint operations.
Handles SharePoint site discovery, filtering, and resolution.
"""
import logging
import urllib.parse
from typing import Dict, Any, List, Optional
logger = logging.getLogger(__name__)
class SiteDiscoveryHelper:
"""Helper for SharePoint site discovery and resolution"""
def __init__(self, methodInstance):
"""
Initialize site discovery helper.
Args:
methodInstance: Instance of MethodSharepoint (for access to services)
"""
self.method = methodInstance
self.services = methodInstance.services
async def discoverSharePointSites(self, limit: Optional[int] = None) -> List[Dict[str, Any]]:
"""
Discover SharePoint sites accessible to the user via Microsoft Graph API.
Args:
limit: Optional limit on number of sites to return
Returns:
List of site information dictionaries
"""
try:
# Query Microsoft Graph to get sites the user has access to
endpoint = "sites?search=*"
if limit:
endpoint += f"&$top={limit}"
result = await self.method.apiClient.makeGraphApiCall(endpoint)
if "error" in result:
logger.error(f"Error discovering SharePoint sites: {result['error']}")
return []
sites = result.get("value", [])
if limit:
sites = sites[:limit]
logger.info(f"Discovered {len(sites)} SharePoint sites" + (f" (limited to {limit})" if limit else ""))
# Process and return site information
processedSites = []
for site in sites:
siteInfo = {
"id": site.get("id"),
"displayName": site.get("displayName"),
"name": site.get("name"),
"webUrl": site.get("webUrl"),
"description": site.get("description"),
"createdDateTime": site.get("createdDateTime"),
"lastModifiedDateTime": site.get("lastModifiedDateTime")
}
processedSites.append(siteInfo)
logger.debug(f"Site: {siteInfo['displayName']} - {siteInfo['webUrl']}")
return processedSites
except Exception as e:
logger.error(f"Error discovering SharePoint sites: {str(e)}")
return []
def extractHostnameFromWebUrl(self, webUrl: str) -> Optional[str]:
"""Extract hostname from SharePoint webUrl (e.g., https://pcuster.sharepoint.com)"""
try:
if not webUrl:
return None
parsed = urllib.parse.urlparse(webUrl)
return parsed.hostname
except Exception as e:
logger.error(f"Error extracting hostname from webUrl '{webUrl}': {str(e)}")
return None
def extractSiteFromStandardPath(self, pathQuery: str) -> Optional[Dict[str, str]]:
"""
Extract site name from Microsoft-standard server-relative path.
Delegates to SharePoint service.
"""
return self.services.sharepoint.extractSiteFromStandardPath(pathQuery)
async def getSiteByStandardPath(self, sitePath: str) -> Optional[Dict[str, Any]]:
"""
Get SharePoint site directly by Microsoft-standard path.
Delegates to SharePoint service.
"""
return await self.services.sharepoint.getSiteByStandardPath(sitePath)
def filterSitesByHint(self, sites: List[Dict[str, Any]], siteHint: str) -> List[Dict[str, Any]]:
"""
Filter discovered sites by a human-entered site hint.
Delegates to SharePoint service.
"""
return self.services.sharepoint.filterSitesByHint(sites, siteHint)
async def getSiteId(self, hostname: str, sitePath: str) -> str:
"""
Get SharePoint site ID from hostname and site path.
Args:
hostname: SharePoint hostname
sitePath: Site path
Returns:
Site ID string
"""
try:
endpoint = f"sites/{hostname}:/{sitePath}"
result = await self.method.apiClient.makeGraphApiCall(endpoint)
if "error" in result:
logger.error(f"Error getting site ID: {result['error']}")
return ""
return result.get("id", "")
except Exception as e:
logger.error(f"Error getting site ID: {str(e)}")
return ""
async def resolveSitesFromPathQuery(self, pathQuery: str) -> tuple[List[Dict[str, Any]], Optional[str]]:
"""
Resolve sites from pathQuery using SharePoint service helper methods.
Args:
pathQuery: Path query string
Returns:
Tuple of (sites list, error message)
"""
try:
# Validate pathQuery format
isValid, errorMsg = self.services.sharepoint.validatePathQuery(pathQuery)
if not isValid:
return [], errorMsg
# Resolve sites using service helper
sites = await self.services.sharepoint.resolveSitesFromPathQuery(pathQuery)
if not sites:
return [], "No SharePoint sites found or accessible"
return sites, None
except Exception as e:
logger.error(f"Error resolving sites from pathQuery '{pathQuery}': {str(e)}")
return [], f"Error resolving sites from pathQuery: {str(e)}"
def parseSiteUrl(self, siteUrl: str) -> Dict[str, str]:
"""Parse SharePoint site URL to extract hostname and site path"""
try:
parsed = urllib.parse.urlparse(siteUrl)
hostname = parsed.hostname
path = parsed.path.strip('/')
return {
"hostname": hostname,
"sitePath": path
}
except Exception as e:
logger.error(f"Error parsing site URL {siteUrl}: {str(e)}")
return {"hostname": "", "sitePath": ""}