6e7e39d101
Critical fixes:
- Event Bus → Workflow auto-trigger: wildcard subscription starts workflows on matching events
- Kommunikation routes: require_permission on all 30+ endpoints (comm:read/write/delete/manage)
- Permissions routes: require_permission('permissions:admin') on all management endpoints
- CompanySearchProvider registered in auto_register_providers()
Medium fixes:
- system_notif events: 10 event_bus.publish() calls added (lead.created, contact.created/updated,
task.created/overdue, mail.received, user.created, workflow.completed, notification.created, backup.*)
- Cron jobs: backup_check (daily), search_index_check (daily), workflow_timeout (5min) registered
- AI tool permission: call_crm_api now requires 'ai:write' permission
- New file: automation/jobs.py with backup_check and search_index_check functions
57 lines
1.9 KiB
Python
57 lines
1.9 KiB
Python
"""In-process event bus for publish/subscribe."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
from collections import defaultdict
|
|
from collections.abc import Callable, Coroutine
|
|
from typing import Any
|
|
|
|
EventHandler = Callable[[dict[str, Any]], Coroutine[Any, Any, None]]
|
|
|
|
|
|
class EventBus:
|
|
"""Simple async event bus for in-process pub/sub."""
|
|
|
|
def __init__(self) -> None:
|
|
self._handlers: dict[str, list[EventHandler]] = defaultdict(list)
|
|
|
|
def subscribe(self, event_name: str, handler: EventHandler) -> None:
|
|
"""Subscribe a handler to an event."""
|
|
self._handlers[event_name].append(handler)
|
|
|
|
def unsubscribe(self, event_name: str, handler: EventHandler) -> None:
|
|
"""Unsubscribe a handler from an event."""
|
|
if event_name in self._handlers:
|
|
self._handlers[event_name] = [h for h in self._handlers[event_name] if h is not handler]
|
|
|
|
async def publish(self, event_name: str, payload: dict[str, Any]) -> None:
|
|
"""Publish an event to all subscribers."""
|
|
handlers = self._handlers.get(event_name, [])
|
|
# Also notify wildcard subscribers (catch-all '*' handlers)
|
|
wildcard_handlers = self._handlers.get('*', [])
|
|
all_handlers = handlers + wildcard_handlers
|
|
tasks = [asyncio.create_task(h(payload)) for h in all_handlers]
|
|
if tasks:
|
|
await asyncio.gather(*tasks, return_exceptions=True)
|
|
|
|
|
|
# Global event bus instance
|
|
_event_bus = EventBus()
|
|
|
|
|
|
def get_event_bus() -> EventBus:
|
|
"""Get the global event bus."""
|
|
return _event_bus
|
|
|
|
|
|
def register_workflow_event_handlers() -> None:
|
|
"""Register workflow event handlers on the global event bus.
|
|
|
|
Subscribes to events that can trigger workflows (user.created, etc.).
|
|
Should be called during application startup.
|
|
"""
|
|
from app.workflows.engine import register_workflow_event_handlers as _register
|
|
|
|
_register()
|