This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
# Отправка сообщений через Telegram бота
|
||||
|
||||
## Описание
|
||||
|
||||
В проект добавлена возможность отправки сообщений пользователям Telegram через бота по их ID. Функциональность включает:
|
||||
|
||||
1. **API endpoint** для отправки сообщений из других скриптов
|
||||
2. **Интерфейс в веб-приложении** для отправки сообщений через браузер
|
||||
3. **Обработку ошибок** и логирование всех операций
|
||||
|
||||
## Использование через веб-интерфейс
|
||||
|
||||
В заголовке страницы "Управление постами VK и событиями" добавлены два поля:
|
||||
|
||||
- **ID пользователя** - числовой ID пользователя в Telegram
|
||||
- **Сообщение** - текст сообщения для отправки
|
||||
- **Кнопка "Отправить"** - отправляет сообщение через бота
|
||||
|
||||
### Особенности интерфейса:
|
||||
|
||||
- Поля проверяются на заполненность перед отправкой
|
||||
- ID пользователя проверяется на корректность (должен быть числом)
|
||||
- Поддержка отправки по клавише Enter
|
||||
- Индикатор загрузки во время отправки
|
||||
- Автоматическая очистка полей после успешной отправки
|
||||
|
||||
## Использование через API
|
||||
|
||||
### Endpoint
|
||||
|
||||
```
|
||||
POST /send_message
|
||||
```
|
||||
|
||||
### Параметры запроса
|
||||
|
||||
```json
|
||||
{
|
||||
"user_id": 123456789,
|
||||
"message": "Текст сообщения"
|
||||
}
|
||||
```
|
||||
|
||||
### Ответы
|
||||
|
||||
**Успешная отправка (200):**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Сообщение отправлено успешно"
|
||||
}
|
||||
```
|
||||
|
||||
**Ошибка (400):**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": "Описание ошибки"
|
||||
}
|
||||
```
|
||||
|
||||
### Пример использования из Python
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
def send_telegram_message(user_id, message):
|
||||
url = "http://localhost:8443/send_message"
|
||||
data = {
|
||||
"user_id": user_id,
|
||||
"message": message
|
||||
}
|
||||
|
||||
response = requests.post(url, json=data)
|
||||
result = response.json()
|
||||
|
||||
if result["success"]:
|
||||
print("Сообщение отправлено успешно!")
|
||||
else:
|
||||
print(f"Ошибка: {result['error']}")
|
||||
```
|
||||
|
||||
### Пример использования из командной строки
|
||||
|
||||
```bash
|
||||
# Используя curl
|
||||
curl -X POST http://localhost:8443/send_message \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"user_id": 123456789, "message": "Привет!"}'
|
||||
|
||||
# Используя примерный скрипт
|
||||
python send_telegram_example.py 123456789 "Привет! Это тестовое сообщение."
|
||||
```
|
||||
|
||||
## Обработка ошибок
|
||||
|
||||
Система обрабатывает следующие типы ошибок:
|
||||
|
||||
1. **403 Forbidden** - Пользователь заблокировал бота или не начал с ним диалог
|
||||
2. **400 Bad Request** - Неверный ID пользователя
|
||||
3. **429 Too Many Requests** - Превышен лимит отправки сообщений
|
||||
4. **Пустое сообщение** - Не указан текст сообщения
|
||||
5. **Неверный формат ID** - user_id не является числом
|
||||
|
||||
Все ошибки логируются в файл логов с указанием типа ошибки и ID пользователя.
|
||||
|
||||
## Логирование
|
||||
|
||||
Все операции отправки сообщений записываются в лог с указанием:
|
||||
|
||||
- Времени операции
|
||||
- ID пользователя
|
||||
- Статуса отправки (успех/ошибка)
|
||||
- Краткого описания ошибки (при наличии)
|
||||
|
||||
Пример записи в логе:
|
||||
```
|
||||
[2024-01-15 10:30:45] [TG_bot] ИНФО: Сообщение отправлено: Привет! Это тестовое сообщение... (Пользователь user_123456789)
|
||||
```
|
||||
|
||||
## Требования
|
||||
|
||||
- Telegram бот должен быть запущен и подключен через webhook
|
||||
- Пользователь должен начать диалог с ботом (отправить команду /start)
|
||||
- Пользователь не должен заблокировать бота
|
||||
|
||||
## Безопасность
|
||||
|
||||
- API endpoint доступен только для POST запросов
|
||||
- Проверка корректности входных данных
|
||||
- Логирование всех попыток отправки для аудита
|
||||
- Обработка ошибок без раскрытия внутренней информации системы
|
||||
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Пример скрипта для отправки сообщений через Telegram бота
|
||||
Использование: python send_telegram_example.py <user_id> <message>
|
||||
"""
|
||||
|
||||
import sys
|
||||
import requests
|
||||
import json
|
||||
|
||||
def send_message(user_id, message_text, bot_url="http://localhost:8443"):
|
||||
"""
|
||||
Отправляет сообщение пользователю через Telegram бота
|
||||
|
||||
Args:
|
||||
user_id (int): ID пользователя в Telegram
|
||||
message_text (str): Текст сообщения
|
||||
bot_url (str): URL бота (по умолчанию localhost:8443)
|
||||
|
||||
Returns:
|
||||
tuple: (success: bool, message: str)
|
||||
"""
|
||||
try:
|
||||
url = f"{bot_url}/send_message"
|
||||
data = {
|
||||
"user_id": user_id,
|
||||
"message": message_text
|
||||
}
|
||||
|
||||
response = requests.post(url, json=data, timeout=10)
|
||||
result = response.json()
|
||||
|
||||
if response.status_code == 200 and result.get("success"):
|
||||
return True, result.get("message", "Сообщение отправлено успешно")
|
||||
else:
|
||||
return False, result.get("error", "Неизвестная ошибка")
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
return False, f"Ошибка сети: {e}"
|
||||
except json.JSONDecodeError as e:
|
||||
return False, f"Ошибка парсинга ответа: {e}"
|
||||
except Exception as e:
|
||||
return False, f"Неожиданная ошибка: {e}"
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 3:
|
||||
print("Использование: python send_telegram_example.py <user_id> <message>")
|
||||
print("Пример: python send_telegram_example.py 123456789 'Привет! Это тестовое сообщение.'")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
user_id = int(sys.argv[1])
|
||||
except ValueError:
|
||||
print("Ошибка: user_id должен быть числом")
|
||||
sys.exit(1)
|
||||
|
||||
message_text = sys.argv[2]
|
||||
|
||||
print(f"Отправка сообщения пользователю {user_id}: {message_text}")
|
||||
|
||||
success, result_message = send_message(user_id, message_text)
|
||||
|
||||
if success:
|
||||
print(f"✅ {result_message}")
|
||||
else:
|
||||
print(f"❌ {result_message}")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -388,6 +388,18 @@
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#">Управление постами VK и событиями</a>
|
||||
|
||||
<!-- Поля для отправки сообщений через бота -->
|
||||
<div class="navbar-nav me-auto">
|
||||
<div class="d-flex align-items-center">
|
||||
<input type="text" class="form-control form-control-sm me-2" id="telegram-user-id" placeholder="ID пользователя" style="width: 150px;">
|
||||
<input type="text" class="form-control form-control-sm me-2" id="telegram-message" placeholder="Сообщение" style="width: 200px;">
|
||||
<button class="btn btn-outline-light btn-sm" id="send-telegram-btn">
|
||||
<i class="fas fa-paper-plane me-1"></i> Отправить
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
@@ -2103,6 +2115,77 @@
|
||||
window.hideProcessingMessage = hideProcessingMessage;
|
||||
window.unlinkPostFromEvent = unlinkPostFromEvent;
|
||||
window.unlinkEventFromPost = unlinkEventFromPost;
|
||||
|
||||
// Функция для отправки сообщения через Telegram бота
|
||||
async function sendTelegramMessage() {
|
||||
const userId = document.getElementById('telegram-user-id').value.trim();
|
||||
const message = document.getElementById('telegram-message').value.trim();
|
||||
|
||||
// Проверяем, что оба поля заполнены
|
||||
if (!userId || !message) {
|
||||
alert('Пожалуйста, заполните оба поля: ID пользователя и сообщение');
|
||||
return;
|
||||
}
|
||||
|
||||
// Проверяем, что user_id является числом
|
||||
if (isNaN(userId)) {
|
||||
alert('ID пользователя должен быть числом');
|
||||
return;
|
||||
}
|
||||
|
||||
// Показываем индикатор загрузки
|
||||
const sendBtn = document.getElementById('send-telegram-btn');
|
||||
const originalText = sendBtn.innerHTML;
|
||||
sendBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i> Отправка...';
|
||||
sendBtn.disabled = true;
|
||||
|
||||
try {
|
||||
const response = await fetch('/send_message', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
user_id: parseInt(userId),
|
||||
message: message
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
alert('Сообщение отправлено успешно!');
|
||||
// Очищаем поля
|
||||
document.getElementById('telegram-user-id').value = '';
|
||||
document.getElementById('telegram-message').value = '';
|
||||
} else {
|
||||
alert('Ошибка отправки сообщения: ' + result.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Ошибка при отправке сообщения:', error);
|
||||
alert('Произошла ошибка при отправке сообщения. Проверьте консоль для подробностей.');
|
||||
} finally {
|
||||
// Восстанавливаем кнопку
|
||||
sendBtn.innerHTML = originalText;
|
||||
sendBtn.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Добавляем обработчик события для кнопки отправки
|
||||
document.getElementById('send-telegram-btn').addEventListener('click', sendTelegramMessage);
|
||||
|
||||
// Добавляем обработчик для отправки по Enter в полях
|
||||
document.getElementById('telegram-user-id').addEventListener('keypress', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
document.getElementById('telegram-message').focus();
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('telegram-message').addEventListener('keypress', function(e) {
|
||||
if (e.key === 'Enter') {
|
||||
sendTelegramMessage();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
// Column resizer setup
|
||||
|
||||
@@ -733,6 +733,49 @@ def send_post_message(chat_id, text, image_url=None, reply_markup=None):
|
||||
logger.error(f"Ошибка отправки сообщения: {e}")
|
||||
return False
|
||||
|
||||
def send_direct_message(user_id, message_text):
|
||||
"""Отправляет сообщение пользователю по ID с обработкой ошибок"""
|
||||
try:
|
||||
# Проверяем, что сообщение не пустое
|
||||
if not message_text or not message_text.strip():
|
||||
error_msg = "Пустое сообщение"
|
||||
logger.warning(error_msg)
|
||||
log_event("error", f"user_{user_id}", message=error_msg)
|
||||
return False, error_msg
|
||||
|
||||
# Отправляем сообщение
|
||||
bot.send_message(
|
||||
user_id,
|
||||
message_text,
|
||||
parse_mode='HTML'
|
||||
)
|
||||
|
||||
# Логируем успешную отправку
|
||||
log_event("info", f"user_{user_id}", message=f"Сообщение отправлено: {message_text[:50]}...")
|
||||
logger.info(f"Сообщение успешно отправлено пользователю {user_id}")
|
||||
return True, "Сообщение отправлено успешно"
|
||||
|
||||
except telebot.apihelper.ApiTelegramException as e:
|
||||
error_msg = f"Ошибка Telegram API: {e}"
|
||||
logger.error(error_msg)
|
||||
log_event("error", f"user_{user_id}", message=error_msg)
|
||||
|
||||
# Определяем тип ошибки для более информативного ответа
|
||||
if e.error_code == 403:
|
||||
return False, "Пользователь заблокировал бота или не начал с ним диалог"
|
||||
elif e.error_code == 400:
|
||||
return False, "Неверный ID пользователя"
|
||||
elif e.error_code == 429:
|
||||
return False, "Превышен лимит отправки сообщений"
|
||||
else:
|
||||
return False, f"Ошибка Telegram: {e.description}"
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Неожиданная ошибка при отправке сообщения: {e}"
|
||||
logger.error(error_msg)
|
||||
log_event("error", f"user_{user_id}", message=error_msg)
|
||||
return False, f"Неожиданная ошибка: {str(e)}"
|
||||
|
||||
def send_management_message(chat_id, post_id, user_id, user_name):
|
||||
"""Отправляет сообщение для управления подпиской на посты"""
|
||||
try:
|
||||
@@ -1234,6 +1277,44 @@ def webhook():
|
||||
log_event("error", "system", message=error_msg)
|
||||
return "Internal Server Error", 500
|
||||
|
||||
@app.route('/send_message', methods=['POST'])
|
||||
def send_message_api():
|
||||
"""API endpoint для отправки сообщений через бота"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
|
||||
if not data:
|
||||
return {"success": False, "error": "Отсутствуют данные"}, 400
|
||||
|
||||
user_id = data.get('user_id')
|
||||
message_text = data.get('message')
|
||||
|
||||
if not user_id:
|
||||
return {"success": False, "error": "Не указан user_id"}, 400
|
||||
|
||||
if not message_text:
|
||||
return {"success": False, "error": "Не указан текст сообщения"}, 400
|
||||
|
||||
# Проверяем, что user_id является числом
|
||||
try:
|
||||
user_id = int(user_id)
|
||||
except (ValueError, TypeError):
|
||||
return {"success": False, "error": "user_id должен быть числом"}, 400
|
||||
|
||||
# Отправляем сообщение
|
||||
success, result_message = send_direct_message(user_id, message_text)
|
||||
|
||||
if success:
|
||||
return {"success": True, "message": result_message}, 200
|
||||
else:
|
||||
return {"success": False, "error": result_message}, 400
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Ошибка в API отправки сообщений: {e}"
|
||||
logger.error(error_msg)
|
||||
log_event("error", "system", message=error_msg)
|
||||
return {"success": False, "error": "Внутренняя ошибка сервера"}, 500
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Логируем запуск бота
|
||||
log_event("system", "system", message="Бот запущен")
|
||||
|
||||
Reference in New Issue
Block a user