Files
MessageGateway/app/core/messengers/telegram.py
Sergey Antropov b90def35ed Initial commit: Message Gateway project
- FastAPI приложение для отправки мониторинговых алертов в мессенджеры
- Поддержка Telegram и MAX/VK
- Интеграция с Grafana, Zabbix, AlertManager
- Автоматическое создание тикетов в Jira
- Управление группами мессенджеров через API
- Декораторы для авторизации и скрытия эндпоинтов
- Подробная документация в папке docs/

Автор: Сергей Антропов
Сайт: https://devops.org.ru
2025-11-12 20:25:11 +03:00

256 lines
10 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.

"""
Адаптер для работы с Telegram через MessengerClient интерфейс.
Автор: Сергей Антропов
Сайт: https://devops.org.ru
"""
import logging
import io
from typing import Optional, Union, Dict, Any
from telegram import InlineKeyboardMarkup
from app.core.messengers.base import MessengerClient
from app.core.telegram_client import TelegramClient
from app.core.button_utils import convert_dict_to_telegram_buttons
logger = logging.getLogger(__name__)
class TelegramMessengerClient(MessengerClient):
"""Адаптер для Telegram, реализующий интерфейс MessengerClient."""
def __init__(self, bot_token: Optional[str] = None):
"""
Инициализация клиента Telegram.
Args:
bot_token: Токен бота Telegram. Если не указан, используется из настроек.
"""
self._client = TelegramClient(bot_token=bot_token)
@property
def messenger_type(self) -> str:
"""Тип мессенджера."""
return "telegram"
@property
def supports_threads(self) -> bool:
"""Telegram поддерживает треды."""
return True
async def send_message(
self,
chat_id: Union[str, int],
text: str,
thread_id: Optional[int] = None,
reply_markup: Optional[Dict[str, Any]] = None,
disable_web_page_preview: bool = True,
parse_mode: str = "HTML",
**kwargs
) -> bool:
"""
Отправить текстовое сообщение в Telegram.
Args:
chat_id: ID чата или группы (преобразуется в int).
text: Текст сообщения.
thread_id: ID треда в группе (опционально).
reply_markup: Клавиатура с кнопками (опционально).
disable_web_page_preview: Отключить превью ссылок.
parse_mode: Режим парсинга (HTML, Markdown).
**kwargs: Дополнительные параметры (игнорируются).
Returns:
True если сообщение отправлено успешно, False в противном случае.
"""
# Преобразуем chat_id в int
chat_id_int = int(chat_id) if isinstance(chat_id, str) else chat_id
# Преобразуем reply_markup из Dict в InlineKeyboardMarkup, если нужно
telegram_reply_markup = None
if reply_markup:
if isinstance(reply_markup, InlineKeyboardMarkup):
telegram_reply_markup = reply_markup
elif isinstance(reply_markup, dict):
# Преобразуем словарь в InlineKeyboardMarkup
telegram_reply_markup = convert_dict_to_telegram_buttons(reply_markup)
return await self._client.send_message(
chat_id=chat_id_int,
text=text,
message_thread_id=thread_id,
reply_markup=telegram_reply_markup,
disable_web_page_preview=disable_web_page_preview,
parse_mode=parse_mode
)
async def send_photo(
self,
chat_id: Union[str, int],
photo: Union[str, bytes],
caption: Optional[str] = None,
thread_id: Optional[int] = None,
parse_mode: str = "HTML",
**kwargs
) -> bool:
"""
Отправить фото в Telegram.
Args:
chat_id: ID чата или группы (преобразуется в int).
photo: Путь к файлу, URL, bytes или BytesIO объект с фото.
caption: Подпись к фото (опционально).
thread_id: ID треда в группе (опционально).
parse_mode: Режим парсинга (HTML, Markdown).
**kwargs: Дополнительные параметры (игнорируются).
Returns:
True если фото отправлено успешно, False в противном случае.
"""
chat_id_int = int(chat_id) if isinstance(chat_id, str) else chat_id
# Преобразуем bytes в BytesIO, если нужно
if isinstance(photo, bytes):
photo = io.BytesIO(photo)
return await self._client.send_photo(
chat_id=chat_id_int,
photo=photo,
caption=caption,
message_thread_id=thread_id,
parse_mode=parse_mode
)
async def send_video(
self,
chat_id: Union[str, int],
video: Union[str, bytes],
caption: Optional[str] = None,
thread_id: Optional[int] = None,
parse_mode: str = "HTML",
duration: Optional[int] = None,
width: Optional[int] = None,
height: Optional[int] = None,
**kwargs
) -> bool:
"""
Отправить видео в Telegram.
Args:
chat_id: ID чата или группы (преобразуется в int).
video: Путь к файлу, URL, bytes или BytesIO объект с видео.
caption: Подпись к видео (опционально).
thread_id: ID треда в группе (опционально).
parse_mode: Режим парсинга (HTML, Markdown).
duration: Длительность видео в секундах (опционально).
width: Ширина видео (опционально).
height: Высота видео (опционально).
**kwargs: Дополнительные параметры (игнорируются).
Returns:
True если видео отправлено успешно, False в противном случае.
"""
chat_id_int = int(chat_id) if isinstance(chat_id, str) else chat_id
# Преобразуем bytes в BytesIO, если нужно
if isinstance(video, bytes):
video = io.BytesIO(video)
return await self._client.send_video(
chat_id=chat_id_int,
video=video,
caption=caption,
message_thread_id=thread_id,
parse_mode=parse_mode,
duration=duration,
width=width,
height=height
)
async def send_audio(
self,
chat_id: Union[str, int],
audio: Union[str, bytes],
caption: Optional[str] = None,
thread_id: Optional[int] = None,
parse_mode: str = "HTML",
duration: Optional[int] = None,
performer: Optional[str] = None,
title: Optional[str] = None,
**kwargs
) -> bool:
"""
Отправить аудио в Telegram.
Args:
chat_id: ID чата или группы (преобразуется в int).
audio: Путь к файлу, URL, bytes или BytesIO объект с аудио.
caption: Подпись к аудио (опционально).
thread_id: ID треда в группе (опционально).
parse_mode: Режим парсинга (HTML, Markdown).
duration: Длительность аудио в секундах (опционально).
performer: Исполнитель (опционально).
title: Название трека (опционально).
**kwargs: Дополнительные параметры (игнорируются).
Returns:
True если аудио отправлено успешно, False в противном случае.
"""
chat_id_int = int(chat_id) if isinstance(chat_id, str) else chat_id
# Преобразуем bytes в BytesIO, если нужно
if isinstance(audio, bytes):
audio = io.BytesIO(audio)
return await self._client.send_audio(
chat_id=chat_id_int,
audio=audio,
caption=caption,
message_thread_id=thread_id,
parse_mode=parse_mode,
duration=duration,
performer=performer,
title=title
)
async def send_document(
self,
chat_id: Union[str, int],
document: Union[str, bytes],
caption: Optional[str] = None,
thread_id: Optional[int] = None,
parse_mode: str = "HTML",
filename: Optional[str] = None,
**kwargs
) -> bool:
"""
Отправить документ в Telegram.
Args:
chat_id: ID чата или группы (преобразуется в int).
document: Путь к файлу, URL, bytes или BytesIO объект с документом.
caption: Подпись к документу (опционально).
thread_id: ID треда в группе (опционально).
parse_mode: Режим парсинга (HTML, Markdown).
filename: Имя файла (опционально).
**kwargs: Дополнительные параметры (игнорируются).
Returns:
True если документ отправлен успешно, False в противном случае.
"""
chat_id_int = int(chat_id) if isinstance(chat_id, str) else chat_id
# Преобразуем bytes в BytesIO, если нужно
if isinstance(document, bytes):
document = io.BytesIO(document)
return await self._client.send_document(
chat_id=chat_id_int,
document=document,
caption=caption,
message_thread_id=thread_id,
parse_mode=parse_mode,
filename=filename
)