"""Public contract for the kommunikation plugin. Exposes only the symbols that other builtins plugins need. Importers should use:: from app.plugins.builtins.contracts import get_contract komm = get_contract("kommunikation") if komm: await komm.send_message(db, tenant_id, ...) instead of importing from internal modules directly. """ from __future__ import annotations from typing import Any from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.plugins.builtins.contracts import get_contract_registry from app.plugins.builtins.kommunikation.miniapp_registry import ( MiniAppDef, MiniAppRegistry, get_miniapp_registry, reset_miniapp_registry, ) from app.plugins.builtins.kommunikation.models import ( CommConversation, CommMessage, CommParticipant, ) from app.plugins.builtins.kommunikation.participant_registry import ( ParticipantHandler, get_participant_registry, ) from app.plugins.builtins.kommunikation.services import ( create_plugin_room, find_locked_room_id, get_conversation, get_messages, parse_mentions, send_message, ) from app.plugins.builtins.kommunikation.services import post_system_message as _post_system_message class KommunikationContract: """Public API surface for the kommunikation plugin. Exposes functions, classes, and model types that other plugins are allowed to use. Internal implementation details remain private to the plugin package. """ contract_name = "kommunikation" # ─── services ─── parse_mentions = staticmethod(parse_mentions) get_conversation = staticmethod(get_conversation) get_messages = staticmethod(get_messages) send_message = staticmethod(send_message) create_plugin_room = staticmethod(create_plugin_room) find_locked_room_id = staticmethod(find_locked_room_id) # ─── participant registry ─── get_participant_registry = staticmethod(get_participant_registry) ParticipantHandler = ParticipantHandler # ─── mini-app registry ─── MiniAppRegistry = MiniAppRegistry MiniAppDef = MiniAppDef get_miniapp_registry = staticmethod(get_miniapp_registry) reset_miniapp_registry = staticmethod(reset_miniapp_registry) post_system_message = staticmethod(_post_system_message) # ─── models (read-only for queries) ─── CommConversation = CommConversation CommMessage = CommMessage CommParticipant = CommParticipant @staticmethod async def dsar_collect( db: AsyncSession, tenant_id: Any, user_id: Any ) -> dict[str, Any]: """GDPR Art. 15: collect communication messages sent by the user.""" comm_messages = ( await db.execute( select(CommMessage).where( CommMessage.sender_id == user_id, CommMessage.tenant_id == tenant_id, ).limit(1000) ) ).scalars().all() return { "comm_messages": [ { "id": str(m.id), "sender_type": m.sender_type, "content": m.content[:500], "created_at": m.created_at.isoformat() if m.created_at else None, } for m in comm_messages ] } # ─── Workspace Scopes contribution (Phase N4) ─── @staticmethod def workspace_scopes() -> list[dict]: """Scope-Dimensionen des communication-Moduls: Räume-Teilmengen (N4).""" return [ { "module_key": "communication", "dimensions": [ { "key": "conversation_ids", "label": "Räume", "control": "multiselect", "options": [], "value_source": { "endpoint": "/api/v1/comm/conversations", "items_path": "items", "value_key": "id", "label_key": "title", }, }, ], } ] # ─── self-registration ─── _contract = KommunikationContract() get_contract_registry().register("kommunikation", _contract) __all__ = [ "KommunikationContract", "ParticipantHandler", "get_participant_registry", "MiniAppRegistry", "MiniAppDef", "get_miniapp_registry", "reset_miniapp_registry", "parse_mentions", "get_conversation", "get_messages", "send_message", "create_plugin_room", "find_locked_room_id", "CommConversation", "CommMessage", "CommParticipant", ]