feat: Add Advoware Filesystem Change Webhook for exploratory logging
This commit is contained in:
1
src/steps/advoware_docs/__init__.py
Normal file
1
src/steps/advoware_docs/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# Advoware Document Sync Steps
|
||||
145
src/steps/advoware_docs/filesystem_webhook_step.py
Normal file
145
src/steps/advoware_docs/filesystem_webhook_step.py
Normal file
@@ -0,0 +1,145 @@
|
||||
"""
|
||||
Advoware Filesystem Change Webhook
|
||||
|
||||
Empfängt Events vom Windows-Watcher (explorative Phase).
|
||||
Aktuell nur Logging, keine Business-Logik.
|
||||
"""
|
||||
from typing import Dict, Any
|
||||
from motia import http, FlowContext, ApiRequest, ApiResponse
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
config = {
|
||||
"name": "Advoware Filesystem Change Webhook (Exploratory)",
|
||||
"description": "Empfängt Filesystem-Events vom Windows-Watcher. Aktuell nur Logging für explorative Analyse.",
|
||||
"flows": ["advoware-document-sync-exploratory"],
|
||||
"triggers": [http("POST", "/advoware/filesystem/akte-changed")],
|
||||
"enqueues": [] # Noch keine Events, nur Logging
|
||||
}
|
||||
|
||||
async def handler(request: ApiRequest, ctx: FlowContext) -> ApiResponse:
|
||||
"""
|
||||
Handler für Filesystem-Events (explorative Phase)
|
||||
|
||||
Payload:
|
||||
{
|
||||
"aktennummer": "201900145",
|
||||
"timestamp": "2026-03-20T10:15:30Z"
|
||||
}
|
||||
|
||||
Aktuelles Verhalten:
|
||||
- Validiere Auth-Token
|
||||
- Logge alle Details
|
||||
- Return 200 OK
|
||||
"""
|
||||
try:
|
||||
ctx.logger.info("=" * 80)
|
||||
ctx.logger.info("📥 ADVOWARE FILESYSTEM EVENT EMPFANGEN")
|
||||
ctx.logger.info("=" * 80)
|
||||
|
||||
# ========================================================
|
||||
# 1. AUTH-TOKEN VALIDIERUNG
|
||||
# ========================================================
|
||||
auth_header = request.headers.get('Authorization', '')
|
||||
expected_token = os.getenv('ADVOWARE_WATCHER_AUTH_TOKEN', 'CHANGE_ME')
|
||||
|
||||
ctx.logger.info(f"🔐 Auth-Header: {auth_header[:20]}..." if auth_header else "❌ Kein Auth-Header")
|
||||
|
||||
if not auth_header.startswith('Bearer ') or auth_header[7:] != expected_token:
|
||||
ctx.logger.error("❌ Invalid auth token")
|
||||
ctx.logger.error(f" Expected: Bearer {expected_token[:10]}...")
|
||||
ctx.logger.error(f" Received: {auth_header[:30]}...")
|
||||
return ApiResponse(status_code=401, body={"error": "Unauthorized"})
|
||||
|
||||
ctx.logger.info("✅ Auth-Token valid")
|
||||
|
||||
# ========================================================
|
||||
# 2. PAYLOAD LOGGING
|
||||
# ========================================================
|
||||
payload = request.body
|
||||
|
||||
ctx.logger.info(f"📦 Payload Type: {type(payload)}")
|
||||
ctx.logger.info(f"📦 Payload Keys: {list(payload.keys()) if isinstance(payload, dict) else 'N/A'}")
|
||||
ctx.logger.info(f"📦 Payload Content:")
|
||||
|
||||
# Detailliertes Logging aller Felder
|
||||
if isinstance(payload, dict):
|
||||
for key, value in payload.items():
|
||||
ctx.logger.info(f" {key}: {value} (type: {type(value).__name__})")
|
||||
else:
|
||||
ctx.logger.info(f" {payload}")
|
||||
|
||||
# Aktennummer extrahieren
|
||||
aktennummer = payload.get('aktennummer') if isinstance(payload, dict) else None
|
||||
timestamp = payload.get('timestamp') if isinstance(payload, dict) else None
|
||||
|
||||
if not aktennummer:
|
||||
ctx.logger.error("❌ Missing 'aktennummer' in payload")
|
||||
return ApiResponse(status_code=400, body={"error": "Missing aktennummer"})
|
||||
|
||||
ctx.logger.info(f"📂 Aktennummer: {aktennummer}")
|
||||
ctx.logger.info(f"⏰ Timestamp: {timestamp}")
|
||||
|
||||
# ========================================================
|
||||
# 3. REQUEST HEADERS LOGGING
|
||||
# ========================================================
|
||||
ctx.logger.info("📋 Request Headers:")
|
||||
for header_name, header_value in request.headers.items():
|
||||
# Kürze Authorization-Token für Logs
|
||||
if header_name.lower() == 'authorization':
|
||||
header_value = header_value[:20] + "..." if len(header_value) > 20 else header_value
|
||||
ctx.logger.info(f" {header_name}: {header_value}")
|
||||
|
||||
# ========================================================
|
||||
# 4. REQUEST METADATA LOGGING
|
||||
# ========================================================
|
||||
ctx.logger.info("🔍 Request Metadata:")
|
||||
ctx.logger.info(f" Method: {request.method}")
|
||||
ctx.logger.info(f" Path: {request.path}")
|
||||
ctx.logger.info(f" Query Params: {request.query_params}")
|
||||
|
||||
# ========================================================
|
||||
# 5. TODO: Business-Logik (später)
|
||||
# ========================================================
|
||||
ctx.logger.info("💡 TODO: Hier später Business-Logik implementieren:")
|
||||
ctx.logger.info(" 1. Redis SADD pending_aktennummern")
|
||||
ctx.logger.info(" 2. Optional: Emit Queue-Event")
|
||||
ctx.logger.info(" 3. Optional: Sofort-Trigger für Batch-Sync")
|
||||
|
||||
# ========================================================
|
||||
# 6. ERFOLG
|
||||
# ========================================================
|
||||
ctx.logger.info("=" * 80)
|
||||
ctx.logger.info(f"✅ Event verarbeitet: Akte {aktennummer}")
|
||||
ctx.logger.info("=" * 80)
|
||||
|
||||
return ApiResponse(
|
||||
status_code=200,
|
||||
body={
|
||||
"success": True,
|
||||
"aktennummer": aktennummer,
|
||||
"received_at": datetime.now().isoformat(),
|
||||
"message": "Event logged successfully (exploratory mode)"
|
||||
}
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
ctx.logger.error("=" * 80)
|
||||
ctx.logger.error(f"❌ ERROR in Filesystem Webhook: {e}")
|
||||
ctx.logger.error("=" * 80)
|
||||
ctx.logger.error(f"Exception Type: {type(e).__name__}")
|
||||
ctx.logger.error(f"Exception Message: {str(e)}")
|
||||
|
||||
# Traceback
|
||||
import traceback
|
||||
ctx.logger.error("Traceback:")
|
||||
ctx.logger.error(traceback.format_exc())
|
||||
|
||||
return ApiResponse(
|
||||
status_code=500,
|
||||
body={
|
||||
"success": False,
|
||||
"error": str(e),
|
||||
"error_type": type(e).__name__
|
||||
}
|
||||
)
|
||||
Reference in New Issue
Block a user