# connect/utils.py import logging from django.template import Template, Context from .models import EventSubscription, DeliveryLog, SUPPORTED_EVENTS from .handlers.webhook import WebhookHandler from .handlers.script import ScriptHandler from apps.plugins.loader import PluginManager logger = logging.getLogger(__name__) HANDLERS = { "webhook": WebhookHandler, "script": ScriptHandler, } def trigger_event(event_name, payload): if event_name not in SUPPORTED_EVENTS: logger.debug(f"Unsupported event '{event_name}' - skipping") return logger.debug( f"Triggering connect event: {event_name} payload_keys={list((payload or {}).keys())}" ) subscriptions = EventSubscription.objects.filter( event=event_name, enabled=True ).select_related("integration") count = subscriptions.count() logger.info(f"Found {count} connect subscription(s) for event '{event_name}'") # First, fetch all subscriptions and trigger for sub in subscriptions: integration = sub.integration if not integration.enabled: logger.debug( f"Skipping disabled integration id={integration.id} name={integration.name}" ) continue # apply optional payload template (only for webhook integrations) # If the rendered template is valid JSON, use that object as the payload. # Otherwise, pass the rendered string as-is. final_payload = payload if integration.type == 'webhook' and sub.payload_template: try: template = Template(sub.payload_template) final_payload = template.render(Context(payload)).strip() except Exception as e: logger.error( f"Payload template render failed for subscription id={sub.id}: {e}" ) final_payload = payload handler_cls = HANDLERS.get(integration.type) if not handler_cls: DeliveryLog.objects.create( subscription=sub, status="failed", request_payload=final_payload, error_message=f"No handler for integration type '{integration.type}'", ) logger.error( f"No handler for integration type '{integration.type}' (integration id={integration.id})" ) continue handler = handler_cls(integration, sub, final_payload) logger.debug( f"Executing handler type={integration.type} integration_id={integration.id} subscription_id={sub.id}" ) try: result = handler.execute() DeliveryLog.objects.create( subscription=sub, status="success" if result.get("success") else "failed", request_payload=final_payload, response_payload=result, ) logger.info( f"Connect delivery succeeded for subscription id={sub.id} integration '{integration.name}'" ) except Exception as e: DeliveryLog.objects.create( subscription=sub, status="failed", request_payload=final_payload, error_message=str(e), ) logger.error( f"Connect delivery failed for subscription id={sub.id} integration '{integration.name}': {e}" ) pm = PluginManager.get() pm.discover_plugins(sync_db=False, use_cache=True) handlers = list(pm.iter_actions_for_event(event_name)) if not handlers: return from apps.plugins.models import PluginConfig handler_keys = {key for key, _ in handlers} enabled_keys = set( PluginConfig.objects.filter(enabled=True, key__in=handler_keys).values_list( "key", flat=True ) ) logger.debug( "Dispatching event '%s' to %d plugin action(s) (%d enabled)", event_name, len(handlers), len(enabled_keys), ) params = {"event": event_name, "payload": payload} for key, action_id in handlers: if key not in enabled_keys: logger.debug( "Skipping disabled plugin id=%s for event '%s'", key, event_name ) continue logger.debug( "Triggering plugin action for event '%s' on plugin id=%s action=%s", event_name, key, action_id, ) try: pm.run_action(key, action_id, params) except Exception: logger.exception( "Plugin action failed for event '%s' on plugin id=%s action=%s", event_name, key, action_id, )