Files
motia-iii/src/steps/crm/document/generate_document_preview_step.py
bsiggel 0c97d97726 feat(webhooks): Add webhook handlers for Beteiligte and Document entities
- Implemented create, update, and delete webhook handlers for Beteiligte.
- Implemented create, update, and delete webhook handlers for Document entities.
- Added logging and error handling for each webhook handler.
- Created a universal step for generating document previews.
- Ensured payload validation and entity ID extraction for batch processing.
2026-03-26 10:07:42 +00:00

131 lines
4.7 KiB
Python

"""
Generate Document Preview Step
Universal step for generating document previews.
Can be triggered by any document sync flow.
Flow:
1. Load document from EspoCRM
2. Download file attachment
3. Generate preview (PDF, DOCX, Images → WebP)
4. Upload preview to EspoCRM
5. Update document metadata
Event: document.generate_preview
Input: entity_id, entity_type (default: 'CDokumente')
"""
from typing import Dict, Any
from motia import FlowContext, queue
import tempfile
import os
config = {
"name": "Generate Document Preview",
"description": "Generates preview image for documents",
"flows": ["document-preview"],
"triggers": [queue("document.generate_preview")],
"enqueues": [],
}
async def handler(event_data: Dict[str, Any], ctx: FlowContext[Any]) -> None:
"""
Generate preview for a document.
Args:
event_data: {
'entity_id': str, # Required: Document ID
'entity_type': str, # Optional: 'CDokumente' (default) or 'Document'
}
"""
from services.document_sync_utils import DocumentSync
entity_id = event_data.get('entity_id')
entity_type = event_data.get('entity_type', 'CDokumente')
if not entity_id:
ctx.logger.error("❌ Missing entity_id in event data")
return
ctx.logger.info("=" * 80)
ctx.logger.info(f"🖼️ GENERATE DOCUMENT PREVIEW")
ctx.logger.info("=" * 80)
ctx.logger.info(f"Entity Type: {entity_type}")
ctx.logger.info(f"Document ID: {entity_id}")
ctx.logger.info("=" * 80)
# Initialize sync utils
sync_utils = DocumentSync(ctx)
try:
# Step 1: Get download info from EspoCRM
ctx.logger.info("📥 Step 1: Getting download info from EspoCRM...")
download_info = await sync_utils.get_document_download_info(entity_id, entity_type)
if not download_info:
ctx.logger.warn("⚠️ No download info available - skipping preview generation")
return
attachment_id = download_info['attachment_id']
filename = download_info['filename']
mime_type = download_info['mime_type']
ctx.logger.info(f" Filename: {filename}")
ctx.logger.info(f" MIME Type: {mime_type}")
ctx.logger.info(f" Attachment ID: {attachment_id}")
# Step 2: Download file from EspoCRM
ctx.logger.info("📥 Step 2: Downloading file from EspoCRM...")
file_content = await sync_utils.espocrm.download_attachment(attachment_id)
ctx.logger.info(f" Downloaded: {len(file_content)} bytes")
# Step 3: Save to temporary file for preview generation
ctx.logger.info("💾 Step 3: Saving to temporary file...")
with tempfile.NamedTemporaryFile(mode='wb', delete=False, suffix=os.path.splitext(filename)[1]) as tmp_file:
tmp_file.write(file_content)
tmp_path = tmp_file.name
try:
# Step 4: Generate preview (600x800 WebP)
ctx.logger.info(f"🖼️ Step 4: Generating preview (600x800 WebP)...")
preview_data = await sync_utils.generate_thumbnail(
tmp_path,
mime_type,
max_width=600,
max_height=800
)
if preview_data:
ctx.logger.info(f"✅ Preview generated: {len(preview_data)} bytes WebP")
# Step 5: Upload preview to EspoCRM
ctx.logger.info(f"📤 Step 5: Uploading preview to EspoCRM...")
await sync_utils._upload_preview_to_espocrm(entity_id, preview_data, entity_type)
ctx.logger.info(f"✅ Preview uploaded successfully")
ctx.logger.info("=" * 80)
ctx.logger.info("✅ PREVIEW GENERATION COMPLETE")
ctx.logger.info("=" * 80)
else:
ctx.logger.warn("⚠️ Preview generation returned no data")
ctx.logger.info("=" * 80)
ctx.logger.info("⚠️ PREVIEW GENERATION FAILED")
ctx.logger.info("=" * 80)
finally:
# Cleanup temporary file
if os.path.exists(tmp_path):
os.remove(tmp_path)
ctx.logger.debug(f"🗑️ Removed temporary file: {tmp_path}")
except Exception as e:
ctx.logger.error(f"❌ Preview generation failed: {e}")
ctx.logger.info("=" * 80)
ctx.logger.info("❌ PREVIEW GENERATION ERROR")
ctx.logger.info("=" * 80)
import traceback
ctx.logger.debug(traceback.format_exc())
# Don't raise - preview generation is optional