from typing import Dict, Any, Optional import logging from datetime import datetime, UTC from office365.runtime.auth.user_credential import UserCredential from office365.sharepoint.client_context import ClientContext from office365.sharepoint.files.file import File from office365.sharepoint.lists.list import List from office365.sharepoint.lists.list_creation_information import ListCreationInformation from modules.methods.methodBase import MethodBase, AuthSource, MethodResult from modules.models.userConnection import UserConnection logger = logging.getLogger(__name__) class MethodSharepoint(MethodBase): """SharePoint method implementation for document operations""" def __init__(self): super().__init__() self.name = "sharepoint" self.description = "Handle SharePoint document operations like search, read, and write" self.auth_source = AuthSource.MICROSOFT @property def actions(self) -> Dict[str, Dict[str, Any]]: """Available actions and their parameters""" return { "search": { "description": "Search SharePoint documents", "retryMax": 3, "timeout": 30, "parameters": { "query": {"type": "string", "required": True}, "siteUrl": {"type": "string", "required": True}, "listName": {"type": "string", "required": False}, "maxResults": {"type": "number", "required": False} } }, "read": { "description": "Read SharePoint document content", "retryMax": 2, "timeout": 30, "parameters": { "fileUrl": {"type": "string", "required": True}, "siteUrl": {"type": "string", "required": True} } }, "write": { "description": "Write content to SharePoint document", "retryMax": 2, "timeout": 30, "parameters": { "fileUrl": {"type": "string", "required": True}, "siteUrl": {"type": "string", "required": True}, "content": {"type": "string", "required": True}, "contentType": {"type": "string", "required": False} } } } async def execute(self, action: str, parameters: Dict[str, Any], auth_data: Optional[Dict[str, Any]] = None) -> MethodResult: """Execute SharePoint method""" try: # Validate parameters if not await self.validate_parameters(action, parameters): return self._create_result( success=False, data={"error": f"Invalid parameters for {action}"} ) # Get UserConnection from auth_data if not auth_data or "userConnection" not in auth_data: return self._create_result( success=False, data={"error": "UserConnection required for SharePoint operations"} ) user_connection: UserConnection = auth_data["userConnection"] # Execute action if action == "search": return await self._search_documents(parameters, user_connection) elif action == "read": return await self._read_document(parameters, user_connection) elif action == "write": return await self._write_document(parameters, user_connection) else: return self._create_result( success=False, data={"error": f"Unknown action: {action}"} ) except Exception as e: logger.error(f"Error executing SharePoint {action}: {e}") return self._create_result( success=False, data={"error": str(e)} ) async def _search_documents(self, parameters: Dict[str, Any], user_connection: UserConnection) -> MethodResult: """Search SharePoint documents""" try: site_url = parameters["siteUrl"] query = parameters["query"] list_name = parameters.get("listName") max_results = parameters.get("maxResults", 10) # Create SharePoint context ctx = ClientContext(site_url).with_credentials( UserCredential(user_connection.authToken, user_connection.refreshToken) ) # Search in specific list or entire site if list_name: target_list = ctx.web.lists.get_by_title(list_name) items = target_list.items.filter(f"Title eq '{query}'").top(max_results).get().execute_query() results = [{ "title": item.properties["Title"], "url": item.properties["FileRef"], "modified": item.properties["Modified"], "created": item.properties["Created"] } for item in items] else: # Search entire site search_results = ctx.search(query).execute_query() results = [{ "title": result.properties["Title"], "url": result.properties["Path"], "modified": result.properties["LastModifiedTime"], "created": result.properties["Created"] } for result in search_results[:max_results]] return self._create_result( success=True, data={ "query": query, "results": results } ) except Exception as e: logger.error(f"Error searching SharePoint documents: {e}") return self._create_result( success=False, data={"error": f"Search failed: {str(e)}"} ) async def _read_document(self, parameters: Dict[str, Any], user_connection: UserConnection) -> MethodResult: """Read SharePoint document content""" try: site_url = parameters["siteUrl"] file_url = parameters["fileUrl"] # Create SharePoint context ctx = ClientContext(site_url).with_credentials( UserCredential(user_connection.authToken, user_connection.refreshToken) ) # Get file file = ctx.web.get_file_by_server_relative_url(file_url) file_content = file.read().execute_query() return self._create_result( success=True, data={ "url": file_url, "content": file_content.content.decode('utf-8'), "modified": file.properties["TimeLastModified"], "size": file.properties["Length"] } ) except Exception as e: logger.error(f"Error reading SharePoint document: {e}") return self._create_result( success=False, data={"error": f"Read failed: {str(e)}"} ) async def _write_document(self, parameters: Dict[str, Any], user_connection: UserConnection) -> MethodResult: """Write content to SharePoint document""" try: site_url = parameters["siteUrl"] file_url = parameters["fileUrl"] content = parameters["content"] content_type = parameters.get("contentType", "text/plain") # Create SharePoint context ctx = ClientContext(site_url).with_credentials( UserCredential(user_connection.authToken, user_connection.refreshToken) ) # Get or create file try: file = ctx.web.get_file_by_server_relative_url(file_url) except: # Create new file folder_url = "/".join(file_url.split("/")[:-1]) file_name = file_url.split("/")[-1] folder = ctx.web.get_folder_by_server_relative_url(folder_url) file = folder.upload_file(file_name, content.encode('utf-8')).execute_query() # Update file content file.write(content.encode('utf-8')).execute_query() return self._create_result( success=True, data={ "url": file_url, "modified": datetime.now(UTC).isoformat(), "size": len(content.encode('utf-8')) } ) except Exception as e: logger.error(f"Error writing SharePoint document: {e}") return self._create_result( success=False, data={"error": f"Write failed: {str(e)}"} )