Files
TgMessageHook/app/models.py

115 lines
3.0 KiB
Python

from datetime import datetime
from typing import Optional
from pydantic import BaseModel, Field, field_validator, model_validator
class HookCreate(BaseModel):
message: str = Field(..., min_length=1, description="Message body supporting Markdown")
chat_id: str = Field(..., min_length=1, description="Target chat ID or username")
class HookRead(BaseModel):
hook_id: str
message: str
chat_id: str
created_at: datetime
last_triggered_at: Optional[datetime] = None
@property
def action_path(self) -> str:
return f"/action/{self.hook_id}"
class HookResponse(HookRead):
action_url: str
class HookUpdate(BaseModel):
hook_id: Optional[str] = Field(
default=None,
min_length=3,
max_length=64,
pattern=r"^[A-Za-z0-9_-]+$",
description="New hook identifier",
)
chat_id: Optional[str] = Field(
default=None,
min_length=1,
description="Updated target chat ID or username",
)
message: Optional[str] = Field(
default=None,
min_length=1,
description="Updated message body supporting Markdown",
)
@model_validator(mode="after")
def ensure_any_field(cls, values: "HookUpdate") -> "HookUpdate":
if values.hook_id is None and values.chat_id is None and values.message is None:
raise ValueError("Provide at least one field to update")
return values
@field_validator("hook_id", mode="before")
@classmethod
def normalize_hook_id(cls, value: Optional[str]) -> Optional[str]:
if value is None:
return None
trimmed = value.strip()
if not trimmed:
raise ValueError("Hook ID cannot be empty")
return trimmed
@field_validator("chat_id", mode="before")
@classmethod
def normalize_chat_id(cls, value: Optional[str]) -> Optional[str]:
if value is None:
return None
trimmed = value.strip()
if not trimmed:
raise ValueError("Chat ID cannot be empty")
return trimmed
@field_validator("message", mode="before")
@classmethod
def normalize_message(cls, value: Optional[str]) -> Optional[str]:
if value is None:
return None
stripped = value.strip()
if not stripped:
raise ValueError("Message cannot be empty")
return stripped
class LoginStartRequest(BaseModel):
phone_number: Optional[str] = None
class LoginVerifyRequest(BaseModel):
code: str
phone_number: Optional[str] = None
password: Optional[str] = None
class MessageTriggerResponse(BaseModel):
status: str
hook_id: str
chat_id: str
class StatusResponse(BaseModel):
authorized: bool
user: Optional[str]
session_active: bool
phone_number: Optional[str]
code_sent: bool = False
class RecentChat(BaseModel):
chat_id: str
display_name: str
chat_type: str
username: Optional[str] = None
phone_number: Optional[str] = None
last_used_at: Optional[datetime] = None