Астат ты не вознесешься

This commit is contained in:
2026-02-18 01:43:22 +07:00
parent 59a3a7b46a
commit 5d350d0885
15 changed files with 1489 additions and 183 deletions

View File

@@ -11,6 +11,7 @@ from sqlalchemy.ext.asyncio import (
AsyncEngine
)
from configs import settings
from middleware.loggers import logger
from .models import Base
@@ -26,7 +27,7 @@ class Database:
session_factory: Фабрика сессий
"""
def __init__(self, db_path: str = "banwords.db"):
def __init__(self, db_path: str = settings.DATABASE_PATH):
"""
Args:
db_path: Путь к SQLite файлу
@@ -99,7 +100,7 @@ class Database:
_db_instance: Database | None = None
def get_db(db_path: str = "banwords.db") -> Database:
def get_db(db_path: str = settings.DATABASE_PATH) -> Database:
"""
Возвращает глобальный экземпляр Database (Singleton).

View File

@@ -623,6 +623,98 @@ class BanWordsManager:
await session.rollback()
return False
# === AUTO COMMENTS ===
async def get_auto_comment_settings(self, channel_id: int) -> dict:
"""
Получает настройки автокомментариев для канала.
Args:
channel_id: ID канала
Returns:
dict: Настройки или значения по умолчанию
"""
from configs import settings
auto_comment = await self.repo.get_auto_comment(channel_id)
if auto_comment and auto_comment.is_enabled:
return {
'text': auto_comment.text,
'button_text': auto_comment.button_text,
'button_url': auto_comment.button_url,
'photo_url': auto_comment.photo_url,
'is_enabled': auto_comment.is_enabled,
}
# Возвращаем настройки по умолчанию из .env
return {
'text': settings.AUTO_COMMENT_TEXT,
'button_text': settings.AUTO_COMMENT_BUTTON_TEXT,
'button_url': settings.AUTO_COMMENT_BUTTON_URL,
'photo_url': settings.AUTO_COMMENT_PHOTO_URL,
'is_enabled': False, # По умолчанию выключено
}
async def save_auto_comment_settings(
self,
channel_id: int,
text: str,
button_text: str,
button_url: str,
photo_url: str,
updated_by: Optional[int] = None
) -> bool:
"""Сохраняет настройки автокомментариев"""
return await self.repo.set_auto_comment(
channel_id=channel_id,
text=text,
button_text=button_text,
button_url=button_url,
photo_url=photo_url,
updated_by=updated_by,
is_enabled=True
)
async def update_auto_comment_text(
self,
channel_id: int,
text: str,
updated_by: Optional[int] = None
) -> bool:
"""Обновляет текст автокомментария"""
return await self.repo.update_auto_comment_field(
channel_id, 'text', text, updated_by
)
async def update_auto_comment_button(
self,
channel_id: int,
button_text: str,
button_url: str,
updated_by: Optional[int] = None
) -> bool:
"""Обновляет кнопку автокомментария"""
success_text = await self.repo.update_auto_comment_field(
channel_id, 'button_text', button_text, updated_by
)
success_url = await self.repo.update_auto_comment_field(
channel_id, 'button_url', button_url, updated_by
)
return success_text and success_url
async def update_auto_comment_photo(
self,
channel_id: int,
photo_url: str,
updated_by: Optional[int] = None
) -> bool:
"""Обновляет фото автокомментария"""
return await self.repo.update_auto_comment_field(
channel_id, 'photo_url', photo_url, updated_by
)
# Глобальный экземпляр менеджера
_manager_instance: Optional[BanWordsManager] = None

View File

@@ -19,6 +19,7 @@ __all__ = (
"Setting",
"SpamStat",
"SpamLog",
"AutoComment",
)
@@ -252,3 +253,44 @@ class SpamLog(Base):
DateTime,
default=lambda: datetime.now(timezone.utc)
)
class AutoComment(Base):
"""
Настройки автокомментариев для каналов.
Attributes:
id: Уникальный ID
channel_id: ID канала (-100...)
text: Текст комментария (HTML)
button_text: Текст кнопки
button_url: URL кнопки
photo_url: URL фото для preview
is_enabled: Включены ли автокомментарии для этого канала
created_at: Дата создания
updated_at: Дата последнего обновления
updated_by: ID админа, который последним изменил
"""
__tablename__ = "auto_comments"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
channel_id: Mapped[int] = mapped_column(BigInteger, nullable=False, unique=True, index=True)
text: Mapped[str] = mapped_column(Text, nullable=False)
button_text: Mapped[str] = mapped_column(String(100), nullable=False)
button_url: Mapped[str] = mapped_column(String(500), nullable=False)
photo_url: Mapped[str] = mapped_column(String(500), nullable=False)
is_enabled: Mapped[bool] = mapped_column(Integer, default=1, nullable=False)
created_at: Mapped[datetime] = mapped_column(
DateTime,
default=lambda: datetime.now(timezone.utc),
nullable=False
)
updated_at: Mapped[datetime] = mapped_column(
DateTime,
default=lambda: datetime.now(timezone.utc),
onupdate=lambda: datetime.now(timezone.utc),
nullable=False
)
updated_by: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
def __repr__(self) -> str:
return f"<AutoComment(channel_id={self.channel_id}, enabled={self.is_enabled})>"

View File

@@ -2,7 +2,7 @@
Repository для работы с банвордами через SQLAlchemy ORM.
"""
from typing import Set, List, Optional
from datetime import datetime, timedelta
from datetime import datetime, timedelta, timezone
from sqlalchemy import select, delete, func, and_
@@ -15,7 +15,8 @@ from .models import (
Admin,
Setting,
SpamStat,
BanWordType
BanWordType,
AutoComment
)
__all__ = ("BanWordsRepository",)
@@ -796,3 +797,252 @@ class BanWordsRepository:
log_type="DATABASE"
)
return {}
# === AUTO COMMENTS ===
async def get_auto_comment(self, channel_id: int) -> Optional['AutoComment']:
"""
Получает настройки автокомментариев для канала.
Args:
channel_id: ID канала
Returns:
AutoComment или None
"""
try:
async with self.db.get_session() as session:
result = await session.execute(
select(AutoComment).where(AutoComment.channel_id == channel_id)
)
return result.scalar_one_or_none()
except Exception as e:
logger.error(
f"Ошибка получения автокомментария: {e}",
log_type="DATABASE"
)
return None
async def set_auto_comment(
self,
channel_id: int,
text: str,
button_text: str,
button_url: str,
photo_url: str,
updated_by: Optional[int] = None,
is_enabled: bool = True
) -> bool:
"""
Сохраняет или обновляет настройки автокомментариев.
Args:
channel_id: ID канала
text: Текст комментария
button_text: Текст кнопки
button_url: URL кнопки
photo_url: URL фото
updated_by: ID админа
is_enabled: Включены ли комментарии
Returns:
bool: True если успешно
"""
try:
async with self.db.get_session() as session:
# Проверяем существование
result = await session.execute(
select(AutoComment).where(AutoComment.channel_id == channel_id)
)
auto_comment = result.scalar_one_or_none()
if auto_comment:
# Обновляем существующую
auto_comment.text = text
auto_comment.button_text = button_text
auto_comment.button_url = button_url
auto_comment.photo_url = photo_url
auto_comment.is_enabled = is_enabled
auto_comment.updated_by = updated_by
auto_comment.updated_at = datetime.now(timezone.utc)
else:
# Создаём новую
auto_comment = AutoComment(
channel_id=channel_id,
text=text,
button_text=button_text,
button_url=button_url,
photo_url=photo_url,
is_enabled=is_enabled,
updated_by=updated_by
)
session.add(auto_comment)
await session.commit()
logger.info(
f"Автокомментарий для канала {channel_id} обновлён",
log_type="DATABASE"
)
return True
except Exception as e:
logger.error(
f"Ошибка сохранения автокомментария: {e}",
log_type="DATABASE"
)
return False
async def update_auto_comment_field(
self,
channel_id: int,
field: str,
value: str,
updated_by: Optional[int] = None
) -> bool:
"""
Обновляет одно поле автокомментария.
Args:
channel_id: ID канала
field: Имя поля (text, button_text, button_url, photo_url)
value: Новое значение
updated_by: ID админа
Returns:
bool: True если успешно
"""
try:
async with self.db.get_session() as session:
result = await session.execute(
select(AutoComment).where(AutoComment.channel_id == channel_id)
)
auto_comment = result.scalar_one_or_none()
if not auto_comment:
return False
# Обновляем поле
if hasattr(auto_comment, field):
setattr(auto_comment, field, value)
auto_comment.updated_by = updated_by
auto_comment.updated_at = datetime.now(timezone.utc)
await session.commit()
logger.info(
f"Поле '{field}' автокомментария для канала {channel_id} обновлено",
log_type="DATABASE"
)
return True
else:
logger.error(
f"Поле '{field}' не существует в AutoComment",
log_type="DATABASE"
)
return False
except Exception as e:
logger.error(
f"Ошибка обновления поля автокомментария: {e}",
log_type="DATABASE"
)
return False
async def toggle_auto_comment(
self,
channel_id: int,
is_enabled: bool,
updated_by: Optional[int] = None
) -> bool:
"""
Включает/выключает автокомментарии для канала.
Args:
channel_id: ID канала
is_enabled: True - включить, False - выключить
updated_by: ID админа
Returns:
bool: True если успешно
"""
try:
async with self.db.get_session() as session:
result = await session.execute(
select(AutoComment).where(AutoComment.channel_id == channel_id)
)
auto_comment = result.scalar_one_or_none()
if not auto_comment:
return False
auto_comment.is_enabled = is_enabled
auto_comment.updated_by = updated_by
auto_comment.updated_at = datetime.now(timezone.utc)
await session.commit()
logger.info(
f"Автокомментарии для канала {channel_id} {'включены' if is_enabled else 'выключены'}",
log_type="DATABASE"
)
return True
except Exception as e:
logger.error(
f"Ошибка переключения автокомментария: {e}",
log_type="DATABASE"
)
return False
async def get_all_auto_comments(self) -> list['AutoComment']:
"""
Получает все настройки автокомментариев.
Returns:
List[AutoComment]: Список всех автокомментариев
"""
try:
async with self.db.get_session() as session:
result = await session.execute(select(AutoComment))
return list(result.scalars().all())
except Exception as e:
logger.error(
f"Ошибка получения всех автокомментариев: {e}",
log_type="DATABASE"
)
return []
async def delete_auto_comment(self, channel_id: int) -> bool:
"""
Удаляет настройки автокомментариев для канала.
Args:
channel_id: ID канала
Returns:
bool: True если удалено
"""
try:
async with self.db.get_session() as session:
result = await session.execute(
delete(AutoComment).where(AutoComment.channel_id == channel_id)
)
await session.commit()
deleted = result.rowcount > 0
if deleted:
logger.info(
f"Автокомментарий для канала {channel_id} удалён",
log_type="DATABASE"
)
return deleted
except Exception as e:
logger.error(
f"Ошибка удаления автокомментария: {e}",
log_type="DATABASE"
)
return False