refactor(kommunikation): split god-object services.py into 6 focused sub-modules with re-export facade — behavior identical (comm suite 132P/1F/6E pre-existing, failures byte-identical to pre-split baseline)
Check Cross-Plugin Imports / check (push) Has been cancelled
Check Cross-Plugin Imports / check (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
"""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 ───
|
||||
Reference in New Issue
Block a user