Files
PrimoGuardBot-/database/models.py
2026-02-17 11:24:55 +07:00

255 lines
8.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
SQLAlchemy модели для банвордов.
"""
from datetime import datetime, timezone
from enum import Enum as PyEnum
from typing import Optional
from sqlalchemy import String, Integer, DateTime, Text, Enum, BigInteger
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
__all__ = (
"Base",
"BanWordType",
"SpamMode",
"BanWord",
"TempBanWord",
"WhitelistWord",
"Admin",
"Setting",
"SpamStat",
"SpamLog",
)
class Base(DeclarativeBase):
"""Базовый класс для всех моделей"""
pass
class BanWordType(str, PyEnum):
"""Типы банвордов"""
SUBSTRING = "substring"
LEMMA = "lemma"
PART = "part"
CONFLICT_SUBSTRING = "conflict_substring"
CONFLICT_LEMMA = "conflict_lemma"
class SpamMode(str, PyEnum):
"""Режимы работы спам-фильтра"""
NORMAL = "normal"
SILENCE = "silence"
CONFLICT = "conflict"
class BanWord(Base):
"""
Постоянные банворды.
Attributes:
id: Уникальный ID
word: Само слово (lowercase)
type: Тип банворда
added_by: Telegram ID добавившего админа
added_at: Дата добавления
reason: Причина добавления
"""
__tablename__ = "banwords"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
word: Mapped[str] = mapped_column(String(255), nullable=False, index=True)
type: Mapped[BanWordType] = mapped_column(
Enum(BanWordType, native_enum=False),
nullable=False,
index=True
)
added_by: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
added_at: Mapped[datetime] = mapped_column(
DateTime,
default=datetime.now,
nullable=False
)
reason: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
def __repr__(self) -> str:
return f"<BanWord(word='{self.word}', type={self.type})>"
class TempBanWord(Base):
"""
Временные банворды (с автоудалением).
Attributes:
id: Уникальный ID
word: Само слово
type: Тип банворда
added_by: ID админа
added_at: Дата добавления
expires_at: Дата истечения
"""
__tablename__ = "temp_banwords"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
word: Mapped[str] = mapped_column(String(255), nullable=False, index=True)
type: Mapped[BanWordType] = mapped_column(
Enum(BanWordType, native_enum=False),
nullable=False
)
added_by: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
added_at: Mapped[datetime] = mapped_column(
DateTime,
default=datetime.now,
nullable=False
)
expires_at: Mapped[datetime] = mapped_column(
DateTime,
nullable=False,
index=True
)
def is_expired(self) -> bool:
"""Проверяет, истёк ли срок"""
return datetime.now() >= self.expires_at
def __repr__(self) -> str:
return f"<TempBanWord(word='{self.word}', expires={self.expires_at})>"
class WhitelistWord(Base):
"""
Белый список (исключения из проверки).
Attributes:
id: Уникальный ID
word: Слово-исключение
added_by: ID админа
added_at: Дата добавления
reason: Причина (например, "ложное срабатывание")
"""
__tablename__ = "whitelist"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
word: Mapped[str] = mapped_column(String(255), nullable=False, unique=True, index=True)
added_by: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
added_at: Mapped[datetime] = mapped_column(
DateTime,
default=datetime.now,
nullable=False
)
reason: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
def __repr__(self) -> str:
return f"<WhitelistWord(word='{self.word}')>"
class Admin(Base):
"""
Дополнительные администраторы бота.
Attributes:
id: Уникальный ID записи
user_id: Telegram ID пользователя (уникальный)
added_by: ID суперадмина, который добавил
added_at: Дата добавления
permissions: JSON со списком прав (для будущего)
"""
__tablename__ = "admins"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
user_id: Mapped[int] = mapped_column(Integer, nullable=False, unique=True, index=True)
added_by: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
added_at: Mapped[datetime] = mapped_column(
DateTime,
default=datetime.now,
nullable=False
)
permissions: Mapped[Optional[str]] = mapped_column(
Text,
default="[]",
nullable=True
)
def __repr__(self) -> str:
return f"<Admin(user_id={self.user_id})>"
class Setting(Base):
"""
Настройки и состояния бота.
Attributes:
key: Ключ настройки (primary key)
value: Значение (JSON string)
updated_at: Дата обновления
Examples:
- silence_until: datetime ISO string
- conflict_until: datetime ISO string
- spam_mode: "normal"/"silence"/"conflict"
"""
__tablename__ = "settings"
key: Mapped[str] = mapped_column(String(100), primary_key=True)
value: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
updated_at: Mapped[datetime] = mapped_column(
DateTime,
default=datetime.now,
onupdate=datetime.now,
nullable=False
)
def __repr__(self) -> str:
return f"<Setting(key='{self.key}', value='{self.value}')>"
class SpamStat(Base):
"""
Статистика удалённых спам-сообщений.
Attributes:
id: Уникальный ID
user_id: Telegram ID отправителя
username: Username отправителя
chat_id: ID чата
message_text: Текст сообщения (до 500 символов)
matched_word: Слово, по которому сработал фильтр
match_type: Тип проверки (substring/lemma/part)
deleted_at: Дата удаления
"""
__tablename__ = "spam_stats"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
user_id: Mapped[int] = mapped_column(Integer, nullable=False, index=True)
username: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
chat_id: Mapped[int] = mapped_column(Integer, nullable=False)
message_text: Mapped[str] = mapped_column(Text, nullable=False)
matched_word: Mapped[str] = mapped_column(String(255), nullable=False)
match_type: Mapped[str] = mapped_column(String(50), nullable=False)
deleted_at: Mapped[datetime] = mapped_column(
DateTime,
default=datetime.now,
nullable=False,
index=True
)
def __repr__(self) -> str:
return f"<SpamStat(user_id={self.user_id}, word='{self.matched_word}')>"
class SpamLog(Base):
"""Модель для логирования срабатываний спам-фильтра"""
__tablename__ = "spam_logs"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
user_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
username: Mapped[str] = mapped_column(String(255), nullable=True)
chat_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
message_text: Mapped[str] = mapped_column(Text, nullable=True)
matched_word: Mapped[str] = mapped_column(String(255), nullable=True) # <-- Должно быть!
match_type: Mapped[str] = mapped_column(String(50), nullable=True) # <-- Должно быть!
timestamp: Mapped[datetime] = mapped_column(
DateTime,
default=lambda: datetime.now(timezone.utc)
)