173 lines
6.3 KiB
Python
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": ""}
|
|
|