115 lines
3.0 KiB
Python
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
|