from typing import Any, ClassVar, Optional
from pydantic import model_validator
from wxc_sdk.base import ApiModel, E164Number
from wxc_sdk.base import SafeEnum as Enum
from wxc_sdk.common.schedules import ScheduleType
__all__ = ['SelectiveScheduleLevel', 'SelectiveFrom', 'SelectiveCriteria', 'SelectiveCrit']
[docs]
class SelectiveScheduleLevel(str, Enum):
group = 'GROUP'
global_ = 'GLOBAL'
location = 'LOCATION'
people = 'PEOPLE'
[docs]
class SelectiveFrom(str, Enum):
#: Criteria applies to all incoming numbers.
any_phone_number = 'ANY_PHONE_NUMBER'
#: Criteria applies only for specific incoming numbers.
select_phone_numbers = 'SELECT_PHONE_NUMBERS'
#: The criteria applies to any internal number.
any_internal = 'ANY_INTERNAL'
#: The criteria applies to any external number.
any_external = 'ANY_EXTERNAL'
[docs]
class SelectiveCriteria(ApiModel):
#: Unique identifier for criteria.
id: Optional[str] = None
#: Name of the location's schedule which determines when the sequential ring is in effect. Creating criteria
#: without schedule_name nor schedule_type creates a criteria for all hours all days
schedule_name: Optional[str] = None
#: This indicates the type of schedule. Creating criteria without schedule_name nor schedule_type creates a
#: criteria for all hours all days
schedule_type: Optional[ScheduleType] = None
#: This indicates the level of the schedule specified by `scheduleName`.
schedule_level: Optional[SelectiveScheduleLevel] = None
#: This indicates if criteria are applicable for calls from any phone number or selected phone numbers.
calls_from: Optional[SelectiveFrom] = None
#: When `true` incoming calls from private numbers are allowed. This is only applicable when `callsFrom` is set to
#: `SELECT_PHONE_NUMBERS`.
anonymous_callers_enabled: Optional[bool] = None
#: When `true` incoming calls from unavailable numbers are allowed. This is only applicable when `callsFrom` is set
#: to `SELECT_PHONE_NUMBERS`.
unavailable_callers_enabled: Optional[bool] = None
#: When callsFrom is set to `SELECT_PHONE_NUMBERS`, indicates a list of incoming phone numbers for which the
#: criteria apply.
phone_numbers: Optional[list[E164Number]] = None
#: When set to `true` selective treatment enabled for calls that meet the current criteria. Criteria with
#: `enabled` set to `false` take priority.
enabled: Optional[bool] = None
# attribute for enabled
_enabled_attr: ClassVar[str] = None
# attribute for phone number list
_phone_numbers: ClassVar[str] = None
@classmethod
def __pydantic_init_subclass__(cls, **kwargs: Any) -> None:
"""
Verify that the class has the required attributes
"""
super().__pydantic_init_subclass__(**kwargs)
if cls._enabled_attr is None:
raise TypeError('_enabled_attr has to be defined')
if cls._phone_numbers is None:
raise TypeError('_phone_numbers has to be defined')
@model_validator(mode='before')
@classmethod
def val_enabled(cls, data: dict) -> dict:
"""
this class is used for multiple selective cases where there are different *_enabled fields.
* ring_enabled
* accept_enabled
* forward_enabled
also the attribute phone_numbers in one case is called numbers.
This is to "normalize the data before validation"
:meta private:
"""
if cls == SelectiveCriteria:
raise TypeError(f'{cls.__name__} is not meant to be used directly. You can only instantiate subclasses.')
if cls._enabled_attr in data:
data['enabled'] = data.pop(cls._enabled_attr)
if cls._phone_numbers in data:
data['phoneNumbers'] = data.pop(cls._phone_numbers)
return data
def update(self) -> dict:
"""
data for update
:meta private:
"""
data = self.model_dump(mode='json', by_alias=True, exclude_none=True,
exclude={'id'})
if 'enabled' in data:
data[self._enabled_attr] = data.pop('enabled')
if 'phoneNumbers' in data:
data[self._phone_numbers] = data.pop('phoneNumbers')
return data
class SelectiveSource(str, Enum):
#: Criteria applies to all incoming numbers.
all_numbers = 'ALL_NUMBERS'
#: Criteria applies only for specific incoming numbers.
specific_numbers = 'SPECIFIC_NUMBERS'
[docs]
class SelectiveCrit(ApiModel):
#: Unique identifier for criteria.
id: Optional[str] = None
#: Name of the location's schedule which determines when the sequential ring is in effect.
schedule_name: Optional[str] = None
#: Indicates if criteria are applicable for calls from any phone number or specific phone number.
source: Optional[SelectiveSource] = None
#: When set to `true` selective treatment is enabled for calls that meet the current criteria. Criteria with
#: `enabled` set to `false` take priority.
enabled: Optional[bool] = None
@model_validator(mode='before')
@classmethod
def val_enabled(cls, data: dict) -> dict:
"""
'enabled' is actually something like *_enabled.
This is to "normalize the data before validation"
:meta private:
"""
enabled_attr = next(enabled_attr for enabled_attr in data if enabled_attr.endswith('Enabled'))
data['enabled'] = data.pop(enabled_attr)
return data