gateway/modules/methods/methodPowerpoint.py
2025-06-10 18:19:33 +02:00

376 lines
No EOL
15 KiB
Python

from typing import Dict, Any, Optional
import logging
import os
from pathlib import Path
from modules.methods.methodBase import MethodBase, AuthSource, MethodResult
from modules.models.userConnection import UserConnection
from modules.models.account import Account
from modules.protocols.msGraphProtocol import MSGraphProtocol
logger = logging.getLogger(__name__)
class MethodPowerpoint(MethodBase):
"""Powerpoint method implementation for PowerPoint operations"""
def __init__(self):
super().__init__()
self.name = "powerpoint"
self.description = "Handle PowerPoint operations like reading, writing, and converting presentations"
self.authSource = AuthSource.MICROSOFT # PowerPoint operations need Microsoft auth
@property
def actions(self) -> Dict[str, Dict[str, Any]]:
"""Available actions and their parameters"""
return {
"read": {
"description": "Read PowerPoint presentation content",
"retryMax": 2,
"timeout": 30,
"parameters": {
"path": {"type": "string", "required": True},
"format": {"type": "string", "required": False},
"includeNotes": {"type": "boolean", "required": False}
}
},
"write": {
"description": "Write content to PowerPoint presentation",
"retryMax": 2,
"timeout": 60,
"parameters": {
"path": {"type": "string", "required": True},
"content": {"type": "object", "required": True},
"template": {"type": "string", "required": False}
}
},
"convert": {
"description": "Convert PowerPoint presentation between formats",
"retryMax": 2,
"timeout": 60,
"parameters": {
"sourcePath": {"type": "string", "required": True},
"targetPath": {"type": "string", "required": True},
"sourceFormat": {"type": "string", "required": False},
"targetFormat": {"type": "string", "required": False}
}
},
"createPresentation": {
"description": "Create a new PowerPoint presentation",
"retryMax": 2,
"timeout": 60,
"parameters": {
"title": {"type": "string", "required": True},
"template": {"type": "string", "required": False}
}
},
"addSlide": {
"description": "Add a new slide to presentation",
"retryMax": 2,
"timeout": 60,
"parameters": {
"presentationId": {"type": "string", "required": True},
"layout": {"type": "string", "required": False},
"title": {"type": "string", "required": False}
}
},
"addContent": {
"description": "Add content to a slide",
"retryMax": 2,
"timeout": 60,
"parameters": {
"presentationId": {"type": "string", "required": True},
"slideId": {"type": "string", "required": True},
"contentType": {"type": "string", "required": True},
"content": {"type": "object", "required": True},
"position": {"type": "object", "required": False}
}
}
}
async def execute(self, action: str, parameters: Dict[str, Any], authData: Optional[Dict[str, Any]] = None) -> MethodResult:
"""Execute PowerPoint method"""
try:
# Validate parameters
if not await self.validateParameters(action, parameters):
return self._createResult(
success=False,
data={"error": f"Invalid parameters for {action}"}
)
# Get UserConnection from auth_data
if not authData or "userConnection" not in authData:
return self._createResult(
success=False,
data={"error": "UserConnection required for PowerPoint operations"}
)
userConnection: UserConnection = authData["userConnection"]
# Execute action
if action == "createPresentation":
return await self._createPresentation(parameters, userConnection)
elif action == "addSlide":
return await self._addSlide(parameters, userConnection)
elif action == "addContent":
return await self._addContent(parameters, userConnection)
else:
return self._createResult(
success=False,
data={"error": f"Unknown action: {action}"}
)
except Exception as e:
logger.error(f"Error executing PowerPoint {action}: {e}")
return self._createResult(
success=False,
data={"error": str(e)}
)
async def _read_presentation(self, parameters: Dict[str, Any], authData: Dict[str, Any]) -> MethodResult:
"""Read PowerPoint presentation content"""
try:
path = Path(parameters["path"])
if not path.exists():
return self._createResult(
success=False,
data={"error": f"File not found: {path}"}
)
# Determine format if not specified
format = parameters.get("format")
if not format:
format = path.suffix[1:] if path.suffix else "pptx"
# TODO: Implement PowerPoint reading using Microsoft Graph API
# This is a placeholder implementation
return self._createResult(
success=True,
data={
"path": str(path),
"format": format,
"slides": [
{
"number": 1,
"title": "Example Slide",
"content": "Example content",
"notes": "Example notes" if parameters.get("includeNotes", False) else None
}
]
}
)
except Exception as e:
logger.error(f"Error reading presentation: {e}")
return self._createResult(
success=False,
data={"error": f"Read failed: {str(e)}"}
)
async def _write_presentation(self, parameters: Dict[str, Any], authData: Dict[str, Any]) -> MethodResult:
"""Write content to PowerPoint presentation"""
try:
path = Path(parameters["path"])
# Create directory if it doesn't exist
path.parent.mkdir(parents=True, exist_ok=True)
# Determine format if not specified
format = parameters.get("format")
if not format:
format = path.suffix[1:] if path.suffix else "pptx"
# TODO: Implement PowerPoint writing using Microsoft Graph API
# This is a placeholder implementation
return self._createResult(
success=True,
data={
"path": str(path),
"format": format,
"slides": len(parameters["content"].get("slides", []))
}
)
except Exception as e:
logger.error(f"Error writing presentation: {e}")
return self._createResult(
success=False,
data={"error": f"Write failed: {str(e)}"}
)
async def _convert_presentation(self, parameters: Dict[str, Any], authData: Dict[str, Any]) -> MethodResult:
"""Convert PowerPoint presentation between formats"""
try:
source_path = Path(parameters["sourcePath"])
target_path = Path(parameters["targetPath"])
if not source_path.exists():
return self._createResult(
success=False,
data={"error": f"Source file not found: {source_path}"}
)
# Determine formats if not specified
source_format = parameters.get("sourceFormat")
if not source_format:
source_format = source_path.suffix[1:] if source_path.suffix else "pptx"
target_format = parameters.get("targetFormat")
if not target_format:
target_format = target_path.suffix[1:] if target_path.suffix else "pptx"
# TODO: Implement PowerPoint conversion using Microsoft Graph API
# This is a placeholder implementation
return self._createResult(
success=True,
data={
"sourcePath": str(source_path),
"targetPath": str(target_path),
"sourceFormat": source_format,
"targetFormat": target_format
}
)
except Exception as e:
logger.error(f"Error converting presentation: {e}")
return self._createResult(
success=False,
data={"error": f"Conversion failed: {str(e)}"}
)
async def _createPresentation(self, parameters: Dict[str, Any], userConnection: UserConnection) -> MethodResult:
"""Create a new PowerPoint presentation"""
try:
title = parameters["title"]
template = parameters.get("template")
# Create PowerPoint account
account = Account(
credentials=(userConnection.authToken, userConnection.refreshToken),
protocol=MSGraphProtocol()
)
# Get drive
drive = account.drive()
# Create presentation
if template:
# Copy template
templateFile = drive.get_item_by_path(template)
newFile = templateFile.copy(f"{title}.pptx")
else:
# Create blank presentation
newFile = drive.create_file(
name=f"{title}.pptx",
content_type="application/vnd.openxmlformats-officedocument.presentationml.presentation"
)
return self._createResult(
success=True,
data={
"id": newFile.object_id,
"name": newFile.name,
"webUrl": newFile.web_url
}
)
except Exception as e:
logger.error(f"Error creating PowerPoint presentation: {e}")
return self._createResult(
success=False,
data={"error": f"Create failed: {str(e)}"}
)
async def _addSlide(self, parameters: Dict[str, Any], userConnection: UserConnection) -> MethodResult:
"""Add a new slide to presentation"""
try:
presentationId = parameters["presentationId"]
layout = parameters.get("layout", "title")
title = parameters.get("title")
# Create PowerPoint account
account = Account(
credentials=(userConnection.authToken, userConnection.refreshToken),
protocol=MSGraphProtocol()
)
# Get drive
drive = account.drive()
# Get presentation
presentation = drive.get_item_by_id(presentationId)
# Add slide
slide = presentation.add_slide(layout=layout)
if title:
slide.title = title
return self._createResult(
success=True,
data={
"slideId": slide.object_id,
"layout": layout,
"title": title
}
)
except Exception as e:
logger.error(f"Error adding PowerPoint slide: {e}")
return self._createResult(
success=False,
data={"error": f"Add slide failed: {str(e)}"}
)
async def _addContent(self, parameters: Dict[str, Any], userConnection: UserConnection) -> MethodResult:
"""Add content to a slide"""
try:
presentationId = parameters["presentationId"]
slideId = parameters["slideId"]
contentType = parameters["contentType"]
content = parameters["content"]
position = parameters.get("position", {"x": 0, "y": 0})
# Create PowerPoint account
account = Account(
credentials=(userConnection.authToken, userConnection.refreshToken),
protocol=MSGraphProtocol()
)
# Get drive
drive = account.drive()
# Get presentation and slide
presentation = drive.get_item_by_id(presentationId)
slide = presentation.get_slide(slideId)
# Add content based on type
if contentType == "text":
shape = slide.add_text_box(
text=content,
left=position["x"],
top=position["y"]
)
elif contentType == "image":
shape = slide.add_picture(
image_path=content,
left=position["x"],
top=position["y"]
)
elif contentType == "table":
shape = slide.add_table(
rows=content["rows"],
cols=content["cols"],
left=position["x"],
top=position["y"]
)
else:
raise ValueError(f"Unsupported content type: {contentType}")
return self._createResult(
success=True,
data={
"shapeId": shape.object_id,
"contentType": contentType,
"position": position
}
)
except Exception as e:
logger.error(f"Error adding PowerPoint content: {e}")
return self._createResult(
success=False,
data={"error": f"Add content failed: {str(e)}"}
)