dograh/api/schemas/telephony_config.py
Abhishek e16f6438bd
feat: refactor telephony to support multiple telephony configurations (#251)
Co-authored-by: Sabiha Khan <sabihak89@gmail.com>
2026-04-29 11:39:57 +05:30

151 lines
4.7 KiB
Python

"""Telephony configuration schemas.
Per-provider request/response classes live next to their providers in
``api/services/telephony/providers/<name>/config.py``. This module re-exports
them and assembles the discriminated union used by API routes.
Adding a new provider requires adding one import here.
"""
from datetime import datetime
from typing import Annotated, List, Optional, Union
from pydantic import BaseModel, ConfigDict, Field
from api.services.telephony.providers.ari.config import (
ARIConfigurationRequest,
ARIConfigurationResponse,
)
from api.services.telephony.providers.cloudonix.config import (
CloudonixConfigurationRequest,
CloudonixConfigurationResponse,
)
from api.services.telephony.providers.plivo.config import (
PlivoConfigurationRequest,
PlivoConfigurationResponse,
)
from api.services.telephony.providers.telnyx.config import (
TelnyxConfigurationRequest,
TelnyxConfigurationResponse,
)
from api.services.telephony.providers.twilio.config import (
TwilioConfigurationRequest,
TwilioConfigurationResponse,
)
from api.services.telephony.providers.vobiz.config import (
VobizConfigurationRequest,
VobizConfigurationResponse,
)
from api.services.telephony.providers.vonage.config import (
VonageConfigurationRequest,
VonageConfigurationResponse,
)
# Discriminated union for incoming save requests. Pydantic dispatches on the
# ``provider`` Literal field of each request class. Replaces the manual
# if/elif chains that used to live in routes/organization.py.
TelephonyConfigRequest = Annotated[
Union[
ARIConfigurationRequest,
CloudonixConfigurationRequest,
PlivoConfigurationRequest,
TelnyxConfigurationRequest,
TwilioConfigurationRequest,
VobizConfigurationRequest,
VonageConfigurationRequest,
],
Field(discriminator="provider"),
]
class TelephonyConfigurationResponse(BaseModel):
"""Top-level telephony configuration response.
Keeps the per-provider field shape that the UI client depends on. When
the UI moves to metadata-driven forms, this can be replaced with a
flat discriminated union.
"""
twilio: Optional[TwilioConfigurationResponse] = None
plivo: Optional[PlivoConfigurationResponse] = None
vonage: Optional[VonageConfigurationResponse] = None
vobiz: Optional[VobizConfigurationResponse] = None
cloudonix: Optional[CloudonixConfigurationResponse] = None
ari: Optional[ARIConfigurationResponse] = None
telnyx: Optional[TelnyxConfigurationResponse] = None
# ---------------------------------------------------------------------------
# Multi-config CRUD schemas
# ---------------------------------------------------------------------------
class TelephonyConfigurationCreateRequest(BaseModel):
"""Body for ``POST /telephony-configs``.
``config`` carries the provider-specific credential fields (the same
discriminated union used by the legacy single-config endpoint). Any
``from_numbers`` on the inner config are ignored — phone numbers are
managed via the dedicated phone-numbers endpoints.
"""
name: str = Field(..., min_length=1, max_length=64)
is_default_outbound: bool = False
config: TelephonyConfigRequest
class TelephonyConfigurationUpdateRequest(BaseModel):
"""Body for ``PUT /telephony-configs/{id}``. Partial update."""
name: Optional[str] = Field(default=None, min_length=1, max_length=64)
config: Optional[TelephonyConfigRequest] = None
class TelephonyConfigurationListItem(BaseModel):
"""One row in ``GET /telephony-configs``."""
model_config = ConfigDict(from_attributes=True)
id: int
name: str
provider: str
is_default_outbound: bool
phone_number_count: int = 0
created_at: datetime
updated_at: datetime
class TelephonyConfigurationDetail(BaseModel):
"""Body of ``GET /telephony-configs/{id}`` — credentials are masked."""
id: int
name: str
provider: str
is_default_outbound: bool
credentials: dict
created_at: datetime
updated_at: datetime
class TelephonyConfigurationListResponse(BaseModel):
configurations: List[TelephonyConfigurationListItem]
__all__ = [
"ARIConfigurationRequest",
"ARIConfigurationResponse",
"CloudonixConfigurationRequest",
"CloudonixConfigurationResponse",
"PlivoConfigurationRequest",
"PlivoConfigurationResponse",
"TelephonyConfigRequest",
"TelephonyConfigurationResponse",
"TelnyxConfigurationRequest",
"TelnyxConfigurationResponse",
"TwilioConfigurationRequest",
"TwilioConfigurationResponse",
"VobizConfigurationRequest",
"VobizConfigurationResponse",
"VonageConfigurationRequest",
"VonageConfigurationResponse",
]