""" Модель пользователя """ import asyncio from dataclasses import dataclass from datetime import datetime from typing import Optional from config.constants import EMPTY_VALUES def escape_html(text: str) -> str: """Экранирование HTML символов""" if not text: return "" return (text .replace('&', '&') .replace('<', '<') .replace('>', '>') .replace('"', '"') .replace("'", ''')) @dataclass class User: """Модель пользователя бота""" id: Optional[int] = None telegram_id: int = None username: Optional[str] = None first_name: str = "" last_name: Optional[str] = None chat_id: int = None profile_link: str = "" is_active: bool = True is_superuser: bool = False created_at: Optional[datetime] = None updated_at: Optional[datetime] = None banned_until: Optional[datetime] = None ban_reason: Optional[str] = None @property def full_name(self) -> str: """Полное имя пользователя""" parts = [] if self.first_name: parts.append(escape_html(self.first_name)) if self.last_name: parts.append(escape_html(self.last_name)) return ' '.join(parts) if parts else 'Неизвестно' @property def display_name(self) -> str: """Отображаемое имя пользователя""" if self.username: return f"@{escape_html(self.username)}" return escape_html(self.full_name) @property def is_banned(self) -> bool: """Проверка, забанен ли пользователь""" if not self.banned_until: return False return datetime.now() < self.banned_until @classmethod def _parse_datetime(cls, date_str) -> Optional[datetime]: """Безопасный парсинг datetime из строки""" if not date_str or date_str in EMPTY_VALUES: return None try: return datetime.fromisoformat(date_str) except (ValueError, TypeError): return None @classmethod async def _parse_datetime_async(cls, date_str) -> Optional[datetime]: """Асинхронный безопасный парсинг datetime из строки""" if not date_str or date_str in EMPTY_VALUES: return None try: loop = asyncio.get_event_loop() return await loop.run_in_executor(None, datetime.fromisoformat, date_str) except (ValueError, TypeError): return None def update_timestamp(self): """Обновление времени последнего обновления""" self.updated_at = datetime.now()