add actions bot
This commit is contained in:
+13
-12
@@ -1,4 +1,6 @@
|
||||
from aiohttp_socks import ProxyConnector
|
||||
import aiohttp
|
||||
from aiogram import Bot
|
||||
from aiogram import F, Router, types
|
||||
from aiogram.enums import ContentType
|
||||
|
||||
@@ -16,9 +18,9 @@ router = Router()
|
||||
|
||||
|
||||
class MessageHandler:
|
||||
def __init__(self):
|
||||
def __init__(self, bot: Bot):
|
||||
self.api_client = ApiClient()
|
||||
self.bot_actions = BotActions()
|
||||
self.bot_actions = BotActions(bot)
|
||||
self.logger = get_logger(__name__)
|
||||
|
||||
async def handle_text_message(self, message: types.Message) -> bool:
|
||||
@@ -29,16 +31,17 @@ class MessageHandler:
|
||||
:return: True, если обработка успешна, иначе False
|
||||
"""
|
||||
try:
|
||||
print(message.text)
|
||||
response = await self.api_client.check_message(message.text)
|
||||
print(response)
|
||||
if response:
|
||||
category = response.get('category')
|
||||
likelihood = response.get('likelihood')
|
||||
|
||||
if likelihood > 0.7:
|
||||
chat_id = str(message.chat.id)
|
||||
await self.bot_actions.handle_actions(chat_id, category, message)
|
||||
await self.bot_actions.handle_actions(
|
||||
message.chat.id,
|
||||
category,
|
||||
message
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"Ошибка при обработке текста: {e}")
|
||||
@@ -68,9 +71,8 @@ class MessageHandler:
|
||||
likelihood = response.get('likelihood')
|
||||
|
||||
if likelihood > 0.7:
|
||||
chat_id = str(message.chat.id)
|
||||
await self.bot_actions.handle_actions(
|
||||
chat_id,
|
||||
message.chat.id,
|
||||
category,
|
||||
message
|
||||
)
|
||||
@@ -91,7 +93,7 @@ class MessageHandler:
|
||||
f"socks5://{BOT_PROXY_USER}:{BOT_PROXY_PASSWORD}"
|
||||
f"@{BOT_PROXY_IP}:{BOT_PROXY_SOCKS5_PORT}"
|
||||
)
|
||||
connector = aiohttp.ProxyConnector.from_url(proxy_url)
|
||||
connector = ProxyConnector.from_url(proxy_url)
|
||||
|
||||
async with aiohttp.ClientSession(connector=connector) as session:
|
||||
async with session.get(url) as response:
|
||||
@@ -103,8 +105,7 @@ class MessageHandler:
|
||||
|
||||
|
||||
@router.message(
|
||||
F.content_type == ContentType.TEXT or
|
||||
F.content_type == ContentType.PHOTO
|
||||
F.content_type != ContentType.CONTACT
|
||||
)
|
||||
async def on_message(message: types.Message):
|
||||
"""
|
||||
@@ -113,7 +114,7 @@ async def on_message(message: types.Message):
|
||||
:param message: Объект сообщения Telegram
|
||||
:return: None
|
||||
"""
|
||||
handler = MessageHandler()
|
||||
handler = MessageHandler(message.bot)
|
||||
|
||||
if message.text:
|
||||
await handler.handle_text_message(message)
|
||||
|
||||
+275
-2
@@ -1,3 +1,276 @@
|
||||
from datetime import timedelta
|
||||
from typing import Union
|
||||
|
||||
from aiogram import Bot
|
||||
from aiogram.types import Message, Chat, ChatPermissions
|
||||
from aiogram.exceptions import TelegramBadRequest
|
||||
|
||||
from bot.utils.db import UseDB
|
||||
from bot.utils.logger import get_logger, log_event
|
||||
|
||||
|
||||
class BotActions:
|
||||
def __init__(self):
|
||||
pass
|
||||
"""
|
||||
Класс для получения действий из базы данных и выполнения их в Telegram
|
||||
"""
|
||||
|
||||
def __init__(self, bot: Bot) -> None:
|
||||
"""
|
||||
Инициализация класса
|
||||
|
||||
:param bot: Bot - объект бота aiogram
|
||||
"""
|
||||
self.db = UseDB("telegram_bot")
|
||||
self.bot = bot
|
||||
self.logger = get_logger(__name__)
|
||||
|
||||
@staticmethod
|
||||
def format_duration(seconds: int) -> str:
|
||||
"""
|
||||
Преобразует количество секунд в строку с единицами измерения времени.
|
||||
|
||||
:param seconds: Количество секунд
|
||||
:return: Строка с отформатированным временем
|
||||
"""
|
||||
units = [
|
||||
('неделя', 'недели', 'недель', 60 * 60 * 24 * 7),
|
||||
('день', 'дня', 'дней', 60 * 60 * 24),
|
||||
('час', 'часа', 'часов', 60 * 60),
|
||||
('минута', 'минуты', 'минут', 60),
|
||||
('секунда', 'секунды', 'секунд', 1)
|
||||
]
|
||||
|
||||
result = []
|
||||
|
||||
for singular, few, many, unit_seconds in units:
|
||||
if seconds >= unit_seconds:
|
||||
count = seconds // unit_seconds
|
||||
seconds %= unit_seconds
|
||||
|
||||
if count % 10 == 1 and count % 100 != 11:
|
||||
name = singular
|
||||
elif 2 <= count % 10 <= 4 and (count % 100 < 10 or count % 100 >= 20):
|
||||
name = few
|
||||
else:
|
||||
name = many
|
||||
|
||||
result.append(f"{count} {name}")
|
||||
|
||||
return ', '.join(result) if result else "0 секунд"
|
||||
|
||||
def get_actions(
|
||||
self,
|
||||
chat_id: int,
|
||||
detected_type: str,
|
||||
user_id: int
|
||||
) -> list[Union[str, dict]]:
|
||||
"""
|
||||
Получение списка действий для бота
|
||||
|
||||
:param chat_id: int - ID чата
|
||||
:param detected_type: str - тип обнаруженного контента
|
||||
(например, nsfw, spam, mat)
|
||||
:param user_id: int - ID пользователя
|
||||
:return: List[Union[str, dict]] - список действий
|
||||
например ['delete', {'mute': 7800}]
|
||||
"""
|
||||
query = {"chat_id": str(chat_id)}
|
||||
document = self.db.find_document(query)
|
||||
|
||||
if not document:
|
||||
return []
|
||||
|
||||
chat_data = document[0]
|
||||
|
||||
if user_id in chat_data.get("ignored_users", []):
|
||||
return []
|
||||
|
||||
possible_types = ["drawings", "hentai", "porn", "sexy"]
|
||||
if detected_type not in possible_types:
|
||||
actions = chat_data.get(
|
||||
"actions",
|
||||
{}
|
||||
).get(detected_type, {}).get("actions", [])
|
||||
else:
|
||||
actions = chat_data.get("actions", {}).get("nsfw", {}).get("actions", [])
|
||||
return actions
|
||||
|
||||
async def delete_message(self, message: Message, detected_type: str) -> None:
|
||||
"""
|
||||
Удаление сообщения
|
||||
|
||||
:param message: Message - сообщение для удаления
|
||||
:param detected_type: str - тип обнаруженного контента
|
||||
"""
|
||||
await message.reply(
|
||||
text=(
|
||||
f"Ваше сообщение удалено. Причина: **{detected_type}**.\n"
|
||||
"Пожалуйста, соблюдайте правила сообщества."
|
||||
),
|
||||
parse_mode="Markdown",
|
||||
disable_notification=True
|
||||
)
|
||||
|
||||
try:
|
||||
await message.delete()
|
||||
except TelegramBadRequest:
|
||||
self.logger.warning(
|
||||
"Не удалось удалить сообщение, возможно, у бота нет прав."
|
||||
)
|
||||
return
|
||||
|
||||
self.logger.info(
|
||||
f"Сообщение пользователя удалено ботом, "
|
||||
f"так как обнаружено: {detected_type}"
|
||||
)
|
||||
await log_event(
|
||||
chat=message.chat,
|
||||
user=message.from_user,
|
||||
reason=detected_type,
|
||||
performed_by="system",
|
||||
event_description="Сообщение пользователя удалено"
|
||||
)
|
||||
|
||||
async def ban_user(
|
||||
self,
|
||||
user_id: int,
|
||||
chat: Chat,
|
||||
detected_type: str,
|
||||
message: Message
|
||||
) -> None:
|
||||
"""
|
||||
Забанить пользователя
|
||||
|
||||
:param user_id: int - ID пользователя
|
||||
:param chat: Chat - объект чата
|
||||
:param detected_type: str - тип обнаруженного контента
|
||||
:param message: Message - сообщение, связанное с нарушением
|
||||
"""
|
||||
reason = (
|
||||
f"Пользователь заблокирован, "
|
||||
f"так как обнаружено нарушение: **{detected_type}**.\n"
|
||||
"Если вы считаете, что это ошибка, обратитесь к администратору."
|
||||
)
|
||||
try:
|
||||
await message.bot.send_message(
|
||||
chat_id=message.chat.id,
|
||||
text=reason,
|
||||
parse_mode="Markdown"
|
||||
)
|
||||
await self.bot.ban_chat_member(
|
||||
chat_id=chat.id,
|
||||
user_id=user_id
|
||||
)
|
||||
except TelegramBadRequest:
|
||||
self.logger.warning("Не удалось забанить пользователя.")
|
||||
return
|
||||
|
||||
await self.bot.send_message(
|
||||
chat_id=chat.id,
|
||||
text=(
|
||||
f"Пользователь {user_id} был заблокирован.\n"
|
||||
f"Причина: **{detected_type}**.\n"
|
||||
"Пожалуйста, соблюдайте правила сообщества."
|
||||
),
|
||||
parse_mode="Markdown"
|
||||
)
|
||||
|
||||
self.logger.info(
|
||||
f"Пользователь забанен через бота, так как обнаружено: {detected_type}"
|
||||
)
|
||||
await log_event(
|
||||
chat=chat,
|
||||
user=user_id,
|
||||
reason=detected_type,
|
||||
performed_by="system",
|
||||
event_description="Пользователь забанен"
|
||||
)
|
||||
|
||||
async def restrict_user(
|
||||
self,
|
||||
user_id: int,
|
||||
chat: Chat,
|
||||
duration: int,
|
||||
detected_type: str
|
||||
) -> None:
|
||||
"""
|
||||
Ограничить пользователя (аналог мута)
|
||||
|
||||
:param user_id: int - ID пользователя
|
||||
:param chat: Chat - объект чата
|
||||
:param duration: int - длительность ограничения в секундах
|
||||
:param detected_type: str - тип обнаруженного контента
|
||||
"""
|
||||
until_date = timedelta(seconds=duration)
|
||||
restricted_permissions = ChatPermissions(
|
||||
can_send_messages=False,
|
||||
can_send_media_messages=False,
|
||||
can_send_polls=False,
|
||||
can_send_other_messages=False,
|
||||
can_add_web_page_previews=False,
|
||||
can_change_info=False,
|
||||
can_invite_users=False,
|
||||
can_pin_messages=False
|
||||
)
|
||||
|
||||
try:
|
||||
await self.bot.restrict_chat_member(
|
||||
chat_id=chat.id,
|
||||
user_id=user_id,
|
||||
permissions=restricted_permissions,
|
||||
until_date=until_date
|
||||
)
|
||||
except TelegramBadRequest:
|
||||
self.logger.warning("Не удалось ограничить пользователя.")
|
||||
return
|
||||
|
||||
await self.bot.send_message(
|
||||
chat_id=chat.id,
|
||||
text=(
|
||||
f"Пользователь был ограничен на {self.format_duration(duration)}.\n"
|
||||
f"Причина: **{detected_type}**.\n"
|
||||
"Пожалуйста, соблюдайте правила сообщества."
|
||||
),
|
||||
parse_mode="Markdown"
|
||||
)
|
||||
|
||||
self.logger.info(
|
||||
f"Пользователь ограничен через бота, так как обнаружено: {detected_type}"
|
||||
)
|
||||
await log_event(
|
||||
chat=chat,
|
||||
user=user_id,
|
||||
reason=detected_type,
|
||||
performed_by="system",
|
||||
event_description="Пользователь ограничен"
|
||||
)
|
||||
|
||||
async def handle_actions(
|
||||
self,
|
||||
chat_id: int,
|
||||
detected_type: str,
|
||||
message: Message
|
||||
) -> None:
|
||||
"""
|
||||
Обработка действий, найденных в базе данных
|
||||
|
||||
:param chat_id: int - ID чата
|
||||
:param detected_type: str - тип обнаруженного контента
|
||||
:param message: Message - сообщение, связанное с обнаруженным контентом
|
||||
"""
|
||||
user_id = message.from_user.id
|
||||
actions = self.get_actions(chat_id, detected_type, user_id)
|
||||
|
||||
for action in actions:
|
||||
if action == "delete":
|
||||
await self.delete_message(message, detected_type)
|
||||
elif action == "ban":
|
||||
await self.ban_user(user_id, message.chat, detected_type, message)
|
||||
elif isinstance(action, dict) and "mute" in action:
|
||||
duration = action["mute"]
|
||||
await self.restrict_user(
|
||||
user_id,
|
||||
message.chat,
|
||||
duration,
|
||||
detected_type
|
||||
)
|
||||
|
||||
@@ -39,3 +39,24 @@ configure_logger()
|
||||
|
||||
def get_logger(name: str) -> logger:
|
||||
return logger.bind(name=name)
|
||||
|
||||
|
||||
async def log_event(
|
||||
chat,
|
||||
user,
|
||||
reason,
|
||||
performed_by,
|
||||
event_description
|
||||
):
|
||||
"""
|
||||
Логирует событие в канале логов и записывает его в базу данных.
|
||||
|
||||
:param chat: discord.Guild - объект сервера Discord
|
||||
:param user: discord.Member - пользователь, к которому относится событие
|
||||
:param reason: str - причина события
|
||||
:param performed_by: discord.Member или str - пользователь, совершивший действие,
|
||||
либо "system", если действие автоматическое
|
||||
:param event_description: str - описание события (например, "Пользователь забанен")
|
||||
:return: None
|
||||
"""
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user