This commit is contained in:
+27
-5
@@ -129,12 +129,34 @@ python send_telegram_example.py 123456789 "Привет! Это тестовое
|
|||||||
|
|
||||||
Система обрабатывает следующие типы ошибок:
|
Система обрабатывает следующие типы ошибок:
|
||||||
|
|
||||||
|
### HTTP ошибки:
|
||||||
1. **401 Unauthorized** - Неверный или отсутствующий API токен
|
1. **401 Unauthorized** - Неверный или отсутствующий API токен
|
||||||
2. **403 Forbidden** - Пользователь заблокировал бота или не начал с ним диалог
|
2. **400 Bad Request** - Неверный ID пользователя или отсутствующие данные
|
||||||
3. **400 Bad Request** - Неверный ID пользователя или отсутствующие данные
|
3. **500 Internal Server Error** - Внутренняя ошибка сервера
|
||||||
4. **429 Too Many Requests** - Превышен лимит отправки сообщений
|
|
||||||
5. **Пустое сообщение** - Не указан текст сообщения
|
### Коды ошибок API:
|
||||||
6. **Неверный формат ID** - user_id не является числом
|
- `INVALID_TOKEN` - Неверный токен аутентификации
|
||||||
|
- `NO_DATA` - Отсутствуют данные в запросе
|
||||||
|
- `NO_USER_ID` - Не указан ID пользователя
|
||||||
|
- `NO_MESSAGE` - Не указан текст сообщения
|
||||||
|
- `INVALID_USER_ID` - user_id не является числом
|
||||||
|
- `TELEGRAM_ERROR` - Ошибка Telegram API
|
||||||
|
- `INTERNAL_ERROR` - Внутренняя ошибка сервера
|
||||||
|
|
||||||
|
### Ошибки Telegram API:
|
||||||
|
1. **403 Forbidden** - Пользователь заблокировал бота или не начал с ним диалог
|
||||||
|
2. **400 Bad Request** - Неверный ID пользователя
|
||||||
|
3. **429 Too Many Requests** - Превышен лимит отправки сообщений
|
||||||
|
4. **404 Not Found** - Пользователь не найден
|
||||||
|
|
||||||
|
### Диагностика в веб-интерфейсе
|
||||||
|
|
||||||
|
Веб-интерфейс предоставляет подробную диагностику ошибок:
|
||||||
|
- **Время ответа** сервера
|
||||||
|
- **HTTP статус** код
|
||||||
|
- **Код ошибки** API
|
||||||
|
- **Конкретные предложения** по решению проблемы
|
||||||
|
- **Автоматическое скрытие** уведомлений
|
||||||
|
|
||||||
Все ошибки логируются в файл логов с указанием типа ошибки и ID пользователя.
|
Все ошибки логируются в файл логов с указанием типа ошибки и ID пользователя.
|
||||||
|
|
||||||
|
|||||||
+194
-5
@@ -2125,13 +2125,13 @@
|
|||||||
|
|
||||||
// Проверяем, что оба поля заполнены
|
// Проверяем, что оба поля заполнены
|
||||||
if (!userId || !message) {
|
if (!userId || !message) {
|
||||||
alert('Пожалуйста, заполните оба поля: ID пользователя и сообщение');
|
showTelegramError('Пожалуйста, заполните оба поля: ID пользователя и сообщение', 'VALIDATION_ERROR');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Проверяем, что user_id является числом
|
// Проверяем, что user_id является числом
|
||||||
if (isNaN(userId)) {
|
if (isNaN(userId)) {
|
||||||
alert('ID пользователя должен быть числом');
|
showTelegramError('ID пользователя должен быть числом', 'VALIDATION_ERROR');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2141,6 +2141,11 @@
|
|||||||
sendBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i> Отправка...';
|
sendBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i> Отправка...';
|
||||||
sendBtn.disabled = true;
|
sendBtn.disabled = true;
|
||||||
|
|
||||||
|
// Скрываем предыдущие ошибки
|
||||||
|
hideTelegramError();
|
||||||
|
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`http://localhost:${BOT_PORT}/send_message`, {
|
const response = await fetch(`http://localhost:${BOT_PORT}/send_message`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -2154,19 +2159,63 @@
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const responseTime = Date.now() - startTime;
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
alert('Сообщение отправлено успешно!');
|
showTelegramSuccess('Сообщение отправлено успешно!', responseTime);
|
||||||
// Очищаем поля
|
// Очищаем поля
|
||||||
document.getElementById('telegram-user-id').value = '';
|
document.getElementById('telegram-user-id').value = '';
|
||||||
document.getElementById('telegram-message').value = '';
|
document.getElementById('telegram-message').value = '';
|
||||||
} else {
|
} else {
|
||||||
alert('Ошибка отправки сообщения: ' + result.error);
|
const errorCode = result.error_code || 'UNKNOWN_ERROR';
|
||||||
|
showTelegramError(`Ошибка отправки сообщения: ${result.error}`, 'API_ERROR', {
|
||||||
|
status: response.status,
|
||||||
|
responseTime: responseTime,
|
||||||
|
userId: userId,
|
||||||
|
errorCode: errorCode
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Обрабатываем HTTP ошибки
|
||||||
|
let errorText = '';
|
||||||
|
try {
|
||||||
|
const errorResult = await response.json();
|
||||||
|
errorText = errorResult.error || 'Неизвестная ошибка';
|
||||||
|
} catch (e) {
|
||||||
|
errorText = `HTTP ${response.status}: ${response.statusText}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
showTelegramError(`Ошибка сервера: ${errorText}`, 'HTTP_ERROR', {
|
||||||
|
status: response.status,
|
||||||
|
statusText: response.statusText,
|
||||||
|
responseTime: responseTime,
|
||||||
|
userId: userId
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
const responseTime = Date.now() - startTime;
|
||||||
console.error('Ошибка при отправке сообщения:', error);
|
console.error('Ошибка при отправке сообщения:', error);
|
||||||
alert('Произошла ошибка при отправке сообщения. Проверьте консоль для подробностей.');
|
|
||||||
|
let errorType = 'NETWORK_ERROR';
|
||||||
|
let errorMessage = 'Ошибка сети при отправке сообщения';
|
||||||
|
|
||||||
|
if (error.name === 'TypeError' && error.message.includes('fetch')) {
|
||||||
|
errorMessage = 'Не удается подключиться к серверу бота. Проверьте, что бот запущен.';
|
||||||
|
errorType = 'CONNECTION_ERROR';
|
||||||
|
} else if (error.name === 'AbortError') {
|
||||||
|
errorMessage = 'Запрос был прерван по таймауту';
|
||||||
|
errorType = 'TIMEOUT_ERROR';
|
||||||
|
}
|
||||||
|
|
||||||
|
showTelegramError(errorMessage, errorType, {
|
||||||
|
errorName: error.name,
|
||||||
|
errorMessage: error.message,
|
||||||
|
responseTime: responseTime,
|
||||||
|
userId: userId
|
||||||
|
});
|
||||||
} finally {
|
} finally {
|
||||||
// Восстанавливаем кнопку
|
// Восстанавливаем кнопку
|
||||||
sendBtn.innerHTML = originalText;
|
sendBtn.innerHTML = originalText;
|
||||||
@@ -2174,6 +2223,146 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Функция для показа успешного результата
|
||||||
|
function showTelegramSuccess(message, responseTime) {
|
||||||
|
const alertDiv = document.createElement('div');
|
||||||
|
alertDiv.className = 'alert alert-success alert-dismissible fade show position-fixed';
|
||||||
|
alertDiv.style.cssText = 'top: 20px; right: 20px; z-index: 9999; min-width: 300px;';
|
||||||
|
alertDiv.innerHTML = `
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<i class="fas fa-check-circle me-2"></i>
|
||||||
|
<div>
|
||||||
|
<strong>Успех!</strong><br>
|
||||||
|
${message}<br>
|
||||||
|
<small class="text-muted">Время ответа: ${responseTime}мс</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||||
|
`;
|
||||||
|
document.body.appendChild(alertDiv);
|
||||||
|
|
||||||
|
// Автоматически скрываем через 5 секунд
|
||||||
|
setTimeout(() => {
|
||||||
|
if (alertDiv.parentNode) {
|
||||||
|
alertDiv.remove();
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Функция для показа ошибки с подробной диагностикой
|
||||||
|
function showTelegramError(message, errorType, details = {}) {
|
||||||
|
const alertDiv = document.createElement('div');
|
||||||
|
alertDiv.className = 'alert alert-danger alert-dismissible fade show position-fixed';
|
||||||
|
alertDiv.style.cssText = 'top: 20px; right: 20px; z-index: 9999; min-width: 400px; max-width: 600px;';
|
||||||
|
|
||||||
|
let diagnosticInfo = '';
|
||||||
|
let suggestions = '';
|
||||||
|
|
||||||
|
// Генерируем диагностическую информацию в зависимости от типа ошибки
|
||||||
|
switch (errorType) {
|
||||||
|
case 'VALIDATION_ERROR':
|
||||||
|
suggestions = '<strong>Решение:</strong> Проверьте правильность введенных данных';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'API_ERROR':
|
||||||
|
diagnosticInfo = `
|
||||||
|
<div class="mt-2">
|
||||||
|
<small class="text-muted">
|
||||||
|
<strong>Диагностика:</strong><br>
|
||||||
|
• Статус: ${details.status || 'N/A'}<br>
|
||||||
|
• Время ответа: ${details.responseTime || 'N/A'}мс<br>
|
||||||
|
• ID пользователя: ${details.userId || 'N/A'}<br>
|
||||||
|
• Код ошибки: ${details.errorCode || 'N/A'}
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Специфичные предложения в зависимости от кода ошибки
|
||||||
|
switch (details.errorCode) {
|
||||||
|
case 'INVALID_TOKEN':
|
||||||
|
suggestions = '<strong>Решение:</strong> Проблема с аутентификацией. Проверьте настройки токена в системе.';
|
||||||
|
break;
|
||||||
|
case 'NO_DATA':
|
||||||
|
case 'NO_USER_ID':
|
||||||
|
case 'NO_MESSAGE':
|
||||||
|
case 'INVALID_USER_ID':
|
||||||
|
suggestions = '<strong>Решение:</strong> Проверьте правильность заполнения полей формы.';
|
||||||
|
break;
|
||||||
|
case 'TELEGRAM_ERROR':
|
||||||
|
suggestions = '<strong>Возможные причины:</strong><br>• Пользователь заблокировал бота<br>• Неверный ID пользователя<br>• Пользователь не начал диалог с ботом<br>• Превышен лимит отправки сообщений';
|
||||||
|
break;
|
||||||
|
case 'INTERNAL_ERROR':
|
||||||
|
suggestions = '<strong>Решение:</strong> Внутренняя ошибка сервера. Проверьте логи бота или обратитесь к администратору.';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
suggestions = '<strong>Возможные причины:</strong><br>• Пользователь заблокировал бота<br>• Неверный ID пользователя<br>• Пользователь не начал диалог с ботом';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'HTTP_ERROR':
|
||||||
|
diagnosticInfo = `
|
||||||
|
<div class="mt-2">
|
||||||
|
<small class="text-muted">
|
||||||
|
<strong>Диагностика:</strong><br>
|
||||||
|
• HTTP статус: ${details.status || 'N/A'} ${details.statusText || ''}<br>
|
||||||
|
• Время ответа: ${details.responseTime || 'N/A'}мс<br>
|
||||||
|
• ID пользователя: ${details.userId || 'N/A'}
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
if (details.status === 401) {
|
||||||
|
suggestions = '<strong>Решение:</strong> Проблема с аутентификацией. Проверьте настройки токена.';
|
||||||
|
} else if (details.status === 500) {
|
||||||
|
suggestions = '<strong>Решение:</strong> Внутренняя ошибка сервера. Проверьте логи бота.';
|
||||||
|
} else {
|
||||||
|
suggestions = '<strong>Решение:</strong> Проверьте статус сервера и настройки подключения.';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'CONNECTION_ERROR':
|
||||||
|
suggestions = '<strong>Решение:</strong><br>• Проверьте, что бот запущен на порту ' + BOT_PORT + '<br>• Проверьте сетевые настройки<br>• Убедитесь, что сервер доступен';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'TIMEOUT_ERROR':
|
||||||
|
suggestions = '<strong>Решение:</strong> Попробуйте еще раз или проверьте стабильность соединения';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'NETWORK_ERROR':
|
||||||
|
suggestions = '<strong>Решение:</strong> Проверьте интернет-соединение и доступность сервера';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
alertDiv.innerHTML = `
|
||||||
|
<div class="d-flex align-items-start">
|
||||||
|
<i class="fas fa-exclamation-triangle me-2 mt-1"></i>
|
||||||
|
<div class="flex-grow-1">
|
||||||
|
<strong>Ошибка отправки сообщения</strong><br>
|
||||||
|
${message}
|
||||||
|
${diagnosticInfo}
|
||||||
|
<div class="mt-2">
|
||||||
|
${suggestions}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||||
|
`;
|
||||||
|
|
||||||
|
document.body.appendChild(alertDiv);
|
||||||
|
|
||||||
|
// Автоматически скрываем через 10 секунд для ошибок
|
||||||
|
setTimeout(() => {
|
||||||
|
if (alertDiv.parentNode) {
|
||||||
|
alertDiv.remove();
|
||||||
|
}
|
||||||
|
}, 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Функция для скрытия ошибок
|
||||||
|
function hideTelegramError() {
|
||||||
|
const existingAlerts = document.querySelectorAll('.alert.position-fixed');
|
||||||
|
existingAlerts.forEach(alert => alert.remove());
|
||||||
|
}
|
||||||
|
|
||||||
// Добавляем обработчик события для кнопки отправки
|
// Добавляем обработчик события для кнопки отправки
|
||||||
document.getElementById('send-telegram-btn').addEventListener('click', sendTelegramMessage);
|
document.getElementById('send-telegram-btn').addEventListener('click', sendTelegramMessage);
|
||||||
|
|
||||||
|
|||||||
+14
-12
@@ -762,13 +762,15 @@ def send_direct_message(user_id, message_text):
|
|||||||
|
|
||||||
# Определяем тип ошибки для более информативного ответа
|
# Определяем тип ошибки для более информативного ответа
|
||||||
if e.error_code == 403:
|
if e.error_code == 403:
|
||||||
return False, "Пользователь заблокировал бота или не начал с ним диалог"
|
return False, f"Пользователь {user_id} заблокировал бота или не начал с ним диалог. Попросите пользователя отправить команду /start боту."
|
||||||
elif e.error_code == 400:
|
elif e.error_code == 400:
|
||||||
return False, "Неверный ID пользователя"
|
return False, f"Неверный ID пользователя: {user_id}. Проверьте правильность ID."
|
||||||
elif e.error_code == 429:
|
elif e.error_code == 429:
|
||||||
return False, "Превышен лимит отправки сообщений"
|
return False, f"Превышен лимит отправки сообщений для пользователя {user_id}. Попробуйте позже."
|
||||||
|
elif e.error_code == 404:
|
||||||
|
return False, f"Пользователь {user_id} не найден. Проверьте правильность ID."
|
||||||
else:
|
else:
|
||||||
return False, f"Ошибка Telegram: {e.description}"
|
return False, f"Ошибка Telegram API (код {e.error_code}): {e.description}"
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_msg = f"Неожиданная ошибка при отправке сообщения: {e}"
|
error_msg = f"Неожиданная ошибка при отправке сообщения: {e}"
|
||||||
@@ -1285,42 +1287,42 @@ def send_message_api():
|
|||||||
if api_token != WEBHOOK_SECRET:
|
if api_token != WEBHOOK_SECRET:
|
||||||
logger.warning("Неверный API токен!")
|
logger.warning("Неверный API токен!")
|
||||||
log_event("security", "system", message="Попытка доступа к API с неверным токеном")
|
log_event("security", "system", message="Попытка доступа к API с неверным токеном")
|
||||||
return {"success": False, "error": "Unauthorized"}, 401
|
return {"success": False, "error": "Unauthorized", "error_code": "INVALID_TOKEN"}, 401
|
||||||
|
|
||||||
try:
|
try:
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
|
|
||||||
if not data:
|
if not data:
|
||||||
return {"success": False, "error": "Отсутствуют данные"}, 400
|
return {"success": False, "error": "Отсутствуют данные", "error_code": "NO_DATA"}, 400
|
||||||
|
|
||||||
user_id = data.get('user_id')
|
user_id = data.get('user_id')
|
||||||
message_text = data.get('message')
|
message_text = data.get('message')
|
||||||
|
|
||||||
if not user_id:
|
if not user_id:
|
||||||
return {"success": False, "error": "Не указан user_id"}, 400
|
return {"success": False, "error": "Не указан user_id", "error_code": "NO_USER_ID"}, 400
|
||||||
|
|
||||||
if not message_text:
|
if not message_text:
|
||||||
return {"success": False, "error": "Не указан текст сообщения"}, 400
|
return {"success": False, "error": "Не указан текст сообщения", "error_code": "NO_MESSAGE"}, 400
|
||||||
|
|
||||||
# Проверяем, что user_id является числом
|
# Проверяем, что user_id является числом
|
||||||
try:
|
try:
|
||||||
user_id = int(user_id)
|
user_id = int(user_id)
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
return {"success": False, "error": "user_id должен быть числом"}, 400
|
return {"success": False, "error": "user_id должен быть числом", "error_code": "INVALID_USER_ID"}, 400
|
||||||
|
|
||||||
# Отправляем сообщение
|
# Отправляем сообщение
|
||||||
success, result_message = send_direct_message(user_id, message_text)
|
success, result_message = send_direct_message(user_id, message_text)
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
return {"success": True, "message": result_message}, 200
|
return {"success": True, "message": result_message, "user_id": user_id}, 200
|
||||||
else:
|
else:
|
||||||
return {"success": False, "error": result_message}, 400
|
return {"success": False, "error": result_message, "user_id": user_id, "error_code": "TELEGRAM_ERROR"}, 400
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_msg = f"Ошибка в API отправки сообщений: {e}"
|
error_msg = f"Ошибка в API отправки сообщений: {e}"
|
||||||
logger.error(error_msg)
|
logger.error(error_msg)
|
||||||
log_event("error", "system", message=error_msg)
|
log_event("error", "system", message=error_msg)
|
||||||
return {"success": False, "error": "Внутренняя ошибка сервера"}, 500
|
return {"success": False, "error": "Внутренняя ошибка сервера", "error_code": "INTERNAL_ERROR"}, 500
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# Логируем запуск бота
|
# Логируем запуск бота
|
||||||
|
|||||||
Reference in New Issue
Block a user