170 lines
5.2 KiB
Python
170 lines
5.2 KiB
Python
from __future__ import annotations
|
||
|
||
from datetime import datetime
|
||
from enum import Enum
|
||
from typing import Optional
|
||
|
||
from pydantic import BaseModel, Field
|
||
|
||
|
||
# ── Enums ──────────────────────────────────────────────────────────────────────
|
||
|
||
class ChannelType(str, Enum):
|
||
telegram = "telegram"
|
||
whatsapp = "whatsapp"
|
||
sms = "sms"
|
||
|
||
|
||
class MessageStatus(str, Enum):
|
||
pending = "pending"
|
||
sent = "sent"
|
||
delivered = "delivered"
|
||
read = "read"
|
||
failed = "failed"
|
||
|
||
|
||
class MessageDirection(str, Enum):
|
||
inbound = "inbound"
|
||
outbound = "outbound"
|
||
|
||
|
||
# ── Contact ────────────────────────────────────────────────────────────────────
|
||
|
||
class ContactCreate(BaseModel):
|
||
name: str = Field(..., min_length=1, max_length=255)
|
||
phone: Optional[str] = None
|
||
email: Optional[str] = None
|
||
telegram_id: Optional[str] = None
|
||
telegram_username: Optional[str] = None
|
||
whatsapp_phone: Optional[str] = None
|
||
notes: Optional[str] = None
|
||
|
||
|
||
class ContactUpdate(BaseModel):
|
||
name: Optional[str] = Field(None, min_length=1, max_length=255)
|
||
phone: Optional[str] = None
|
||
email: Optional[str] = None
|
||
telegram_id: Optional[str] = None
|
||
telegram_username: Optional[str] = None
|
||
whatsapp_phone: Optional[str] = None
|
||
notes: Optional[str] = None
|
||
|
||
|
||
class ContactResponse(BaseModel):
|
||
model_config = {"from_attributes": True}
|
||
|
||
id: str
|
||
name: str
|
||
phone: Optional[str] = None
|
||
email: Optional[str] = None
|
||
telegram_id: Optional[str] = None
|
||
telegram_username: Optional[str] = None
|
||
whatsapp_phone: Optional[str] = None
|
||
notes: Optional[str] = None
|
||
created_at: datetime
|
||
updated_at: Optional[datetime] = None
|
||
|
||
|
||
# ── Message ────────────────────────────────────────────────────────────────────
|
||
|
||
class SendMessageRequest(BaseModel):
|
||
channel: ChannelType
|
||
# Empfänger – je nach Kanal eines der Felder befüllen
|
||
recipient_phone: Optional[str] = Field(None, description="Telefonnummer für WhatsApp/SMS (E.164: +49…)")
|
||
recipient_telegram_id: Optional[str] = Field(None, description="Telegram Chat-ID")
|
||
# Optional: Kontakt-ID aus der DB
|
||
contact_id: Optional[str] = None
|
||
text: str = Field(..., min_length=1, max_length=4096)
|
||
reply_to_id: Optional[str] = None
|
||
|
||
|
||
class MessageResponse(BaseModel):
|
||
model_config = {"from_attributes": True}
|
||
|
||
id: str
|
||
conversation_id: str
|
||
sender_id: Optional[str] = None
|
||
channel: ChannelType
|
||
channel_message_id: Optional[str] = None
|
||
direction: MessageDirection
|
||
text: str
|
||
status: MessageStatus
|
||
error_message: Optional[str] = None
|
||
created_at: datetime
|
||
sent_at: Optional[datetime] = None
|
||
delivered_at: Optional[datetime] = None
|
||
read_at: Optional[datetime] = None
|
||
|
||
|
||
# ── Conversation ───────────────────────────────────────────────────────────────
|
||
|
||
class ConversationResponse(BaseModel):
|
||
model_config = {"from_attributes": True}
|
||
|
||
id: str
|
||
channel: ChannelType
|
||
channel_conversation_id: Optional[str] = None
|
||
title: Optional[str] = None
|
||
is_group: bool
|
||
is_archived: bool
|
||
last_message_at: Optional[datetime] = None
|
||
created_at: datetime
|
||
last_message: Optional[MessageResponse] = None
|
||
unread_count: int = 0
|
||
contact_id: Optional[str] = None
|
||
|
||
|
||
# ── Channel Status ─────────────────────────────────────────────────────────────
|
||
|
||
class ChannelStatusResponse(BaseModel):
|
||
channel: ChannelType
|
||
enabled: bool
|
||
connected: bool
|
||
detail: Optional[str] = None
|
||
|
||
|
||
class SystemStatusResponse(BaseModel):
|
||
channels: list[ChannelStatusResponse]
|
||
database: bool
|
||
timestamp: datetime
|
||
|
||
# ── Auth / User ─────────────────────────────────────────────────────────────
|
||
|
||
class UserRole(str, Enum):
|
||
admin = "admin"
|
||
user = "user"
|
||
|
||
|
||
class LoginRequest(BaseModel):
|
||
username: str = Field(..., min_length=1, max_length=64)
|
||
password: str = Field(..., min_length=1)
|
||
|
||
|
||
class TokenResponse(BaseModel):
|
||
access_token: str
|
||
token_type: str = "bearer"
|
||
username: str
|
||
role: UserRole
|
||
|
||
|
||
class UserCreate(BaseModel):
|
||
username: str = Field(..., min_length=1, max_length=64)
|
||
password: str = Field(..., min_length=6)
|
||
role: UserRole = UserRole.user
|
||
|
||
|
||
class UserUpdate(BaseModel):
|
||
password: Optional[str] = Field(None, min_length=6)
|
||
role: Optional[UserRole] = None
|
||
is_active: Optional[bool] = None
|
||
|
||
|
||
class UserResponse(BaseModel):
|
||
model_config = {"from_attributes": True}
|
||
|
||
id: str
|
||
username: str
|
||
role: UserRole
|
||
is_active: bool
|
||
created_at: datetime
|