From e2f7a9925fa7e06b318d42c8480056a8e885fe63 Mon Sep 17 00:00:00 2001 From: "Evgeny (Krymmy) Momotov" Date: Tue, 11 Nov 2025 11:29:58 +0300 Subject: [PATCH] [ADD] data_models.py --- src/AsteriskAPIManager/data_models.py | 123 ++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 src/AsteriskAPIManager/data_models.py diff --git a/src/AsteriskAPIManager/data_models.py b/src/AsteriskAPIManager/data_models.py new file mode 100644 index 0000000..5ec292b --- /dev/null +++ b/src/AsteriskAPIManager/data_models.py @@ -0,0 +1,123 @@ +import re +from pydantic import BaseModel, Field, validator +from typing import Optional + +class User(BaseModel): + id: Optional[int] = Field(description="Идентификатор (автоматический)", default=None) + username: str = Field(max_length=150, description="Пользовательское имя", example="john_doe") + #password: str = Field(max_length=255, description="Пароль", example="secret123") + email: str = Field(max_length=254, default="", description="Электронная почта", example="john@example.com") + first_name: str = Field(max_length=150, default="", description="Имя", example="John") + last_name: str = Field(max_length=150, default="", description="Фамилия", example="Doe") + #is_staff: bool = Field(default=False, description="Статус администратора") + #is_active: bool = Field(default=False, description="Активен") + #is_superuser: bool = Field(default=False, description="Суперпользователь") + #date_joined: str = Field(description="Дата создания", example="2024-01-01T12:00:00") + #last_login: Optional[str] = Field(null=True, default=None, description="Последний вход") + + @validator("email") + def validate_email(cls, v): + if v and "@" not in v or "." not in v: + raise ValueError("Некорректный email") + return v + + @validator("username") + def validate_username(cls, v): + if len(v) > 150: + raise ValueError("Имя пользователя слишком длинное (максимум 150 символов)") + return v + + @validator("first_name") + def validate_first_name(cls, v): + if v and len(v) > 150: + raise ValueError("Имя слишком длинное (максимум 150 символов)") + return v + + @validator("last_name") + def validate_last_name(cls, v): + if v and len(v) > 150: + raise ValueError("Фамилия слишком длинная (максимум 150 символов)") + return v + + class Config: + extra = "forbid" + from_attributes = True + + + +class SIPAccount(BaseModel): + """ + SIP-аккаунт. + """ + unique_id: str = Field(description="Уникальный идентификатор", example="00000000-0000-0000-0000-000000000000") + id: Optional[int] = Field(description="Идентификатор (автоматический)", default=None) + created_at: Optional[str] = Field(description="Дата создания", example="2024-01-01T12:00:00") + updated_at: Optional[str] = Field(description="Дата обновления", example="2024-01-01T12:00:00") + + owner: Optional[User] = Field(description="Владелец") + name: str = Field(max_length=255, description="Название", example="SIP-аккаунт-1") + is_registered: bool = Field(default=False, description="Зарегистрирован") + username: str = Field(max_length=40, description="Имя SIP клиента", example="user123") + password: Optional[str] = Field(max_length=80, null=True, blank=True, description="Пароль (открытый, временно)") + enc_password: Optional[bytes] = Field(null=True, blank=True, description="Зашифрованный пароль") + + server_url: str = Field( + max_length=215, + description="URL сервера", + example="https://192.168.1.100:5060" + ) + port: Optional[int] = Field(null=True, blank=True, description="Порт", ge=0, le=65535) + internal_number: Optional[str] = Field(max_length=255, null=True, blank=True, description="Внутренний номер") + endpoint_name: Optional[str] = Field(max_length=255, null=True, blank=True, description="Имя конечной точки") + + @validator("server_url") + def validate_server_url(cls, v): + if not v: + return v + # Проверяем, содержит ли строка URL (в формате http:// или https://) + if v.startswith("http://") or v.startswith("https://"): + return v + # Проверяем, является ли это IPv4 (простая проверкаDetails) + parts = v.strip().split(':') + if len(parts) == 1: + ip_part = parts[0] + if re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$", ip_part): + # Проверяем, что каждая часть от 0 до 255 + ip_parts = [int(x) for x in ip_part.split('.')] + if all(0 <= part <= 255 for part in ip_parts): + return v + raise ValueError("Invalid server URL format (must be http(s):// or IPv4 address)") + + @validator("username") + def validate_username(cls, v): + if len(v) > 40: + raise ValueError("Username too long (max 40 characters)") + return v + + @validator("name") + def validate_name(cls, v): + if len(v) > 255: + raise ValueError("Name too long (max 255 characters)") + return v + + @validator("internal_number") + def validate_internal_number(cls, v): + if v and len(v) > 255: + raise ValueError("Internal number too long (max 255 characters)") + return v + + @validator("endpoint_name") + def validate_endpoint_name(cls, v): + if v and len(v) > 255: + raise ValueError("Endpoint name too long (max 255 characters)") + return v + + @validator("port") + def validate_port(cls, v): + if v is not None and not (0 <= v <= 65535): + raise ValueError("Port must be between 0 and 65535") + return v + + class Config: + extra = "forbid" + from_attributes = True \ No newline at end of file