Files
leocrm/app/plugins/builtins/kommunikation/participants.py
T

128 lines
3.5 KiB
Python

"""Participant management for the kommunikation plugin."""
from __future__ import annotations
import logging
import uuid
from datetime import UTC, datetime
from typing import Any
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.event_bus import get_event_bus
from app.plugins.builtins.kommunikation.models import (
CommParticipant,
)
from app.plugins.builtins.kommunikation.serializers import participant_to_response
logger = logging.getLogger(__name__)
# ─── participants ───
async def add_participant(
db: AsyncSession,
tenant_id: uuid.UUID,
conversation_id: uuid.UUID,
participant_id: str,
participant_type: str = "user",
role: str = "member",
display_name: str | None = None,
) -> dict[str, Any] | None:
"""Add a participant to a conversation."""
try:
pid = uuid.UUID(participant_id) if participant_type == "user" else None
except ValueError:
return None
existing = await db.execute(
select(CommParticipant).where(
CommParticipant.conversation_id == conversation_id,
CommParticipant.participant_id == pid if pid else CommParticipant.participant_type == participant_type,
CommParticipant.participant_type == participant_type,
CommParticipant.left_at.is_(None),
)
)
if existing.scalar_one_or_none() is not None:
return None # Already a participant
p = CommParticipant(
tenant_id=tenant_id,
conversation_id=conversation_id,
participant_id=pid,
participant_type=participant_type,
role=role,
display_name=display_name,
)
db.add(p)
await db.flush()
# Publish event
event_bus = get_event_bus()
await event_bus.publish("participant.joined", {
"conversation_id": str(conversation_id),
"participant_id": participant_id,
"participant_type": participant_type,
"tenant_id": str(tenant_id),
})
return participant_to_response(p)
async def remove_participant(
db: AsyncSession,
conversation_id: uuid.UUID,
participant_id: uuid.UUID,
) -> bool:
"""Remove a participant from a conversation (set left_at)."""
result = await db.execute(
select(CommParticipant).where(
CommParticipant.conversation_id == conversation_id,
CommParticipant.participant_id == participant_id,
CommParticipant.participant_type == "user",
CommParticipant.left_at.is_(None),
)
)
p = result.scalar_one_or_none()
if p is None:
return False
p.left_at = datetime.now(UTC)
await db.flush()
event_bus = get_event_bus()
await event_bus.publish("participant.left", {
"conversation_id": str(conversation_id),
"participant_id": str(participant_id),
})
return True
async def change_role(
db: AsyncSession,
conversation_id: uuid.UUID,
participant_id: uuid.UUID,
new_role: str,
) -> dict[str, Any] | None:
"""Change a participant's role."""
result = await db.execute(
select(CommParticipant).where(
CommParticipant.conversation_id == conversation_id,
CommParticipant.participant_id == participant_id,
CommParticipant.participant_type == "user",
CommParticipant.left_at.is_(None),
)
)
p = result.scalar_one_or_none()
if p is None:
return None
p.role = new_role
await db.flush()
return participant_to_response(p)
# ─── Messages ───