diff --git a/.gitignore b/.gitignore
index e351bea..7652792 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,10 @@
/TODO.txt
/logs
/__pycache__
-/venv
\ No newline at end of file
+/venv
+/app.log
+/logs/
+/logs/app.log
+/logs/error.log
+/db/
+/db/telezab.db
diff --git a/telezab.py b/telezab.py
index 8fef4cd..662855e 100644
--- a/telezab.py
+++ b/telezab.py
@@ -1,9 +1,11 @@
import os
-from flask import Flask, request, jsonify
+from functools import partial
+from flask import Flask, request, jsonify, render_template
import schedule
from dotenv import load_dotenv
import hashlib
import telebot
+from telebot import types
import logging
from logging.config import dictConfig
import zipfile
@@ -24,6 +26,45 @@ import re
# Load environment variables
load_dotenv()
+
+# Функция для загрузки значения из файла
+def load_value_from_file(file_name):
+ try:
+ with open(file_name, 'r') as file:
+ return file.read().strip()
+ except FileNotFoundError:
+ return None
+
+
+# Функция для получения переменной из окружения или файла
+def get_variable_value(variable_name):
+ # Попытка получить значение из окружения
+ value = os.getenv(variable_name)
+
+ # Если переменная окружения не установлена, попробуем загрузить из файла
+ if not value:
+ file_value = "file_" + variable_name
+ value = os.getenv(file_value)
+ with open(value, 'r') as file:
+ value = file.read()
+ return value
+ return value
+
+
+# Загрузка переменных окружения или значений из файлов
+TOKEN = get_variable_value('TELEGRAM_TOKEN')
+ZABBIX_API_TOKEN = get_variable_value('ZABBIX_API_TOKEN')
+ZABBIX_URL = get_variable_value('ZABBIX_URL')
+
+
+# Проверка наличия всех необходимых переменных
+if not TOKEN or not ZABBIX_URL or not ZABBIX_API_TOKEN:
+ raise ValueError("One or more required environment variables are missing")
+
+os.makedirs('logs', exist_ok=True)
+os.makedirs('db', exist_ok=True)
+
+
class UTF8StreamHandler(logging.StreamHandler):
def __init__(self, stream=None):
super().__init__(stream)
@@ -37,8 +78,9 @@ class UTF8StreamHandler(logging.StreamHandler):
# Определение пути к основному лог-файлу
LOG_FILE = 'logs/app.log'
-
-
+ERROR_LOG_FILE = 'logs/error.log'
+DB_PATH = 'db/telezab.db'
+SUPPORT_EMAIL = "shiftsupport-rtmis@rtmis.ru"
# Определение функции архивирования логов
def archive_old_logs():
@@ -59,7 +101,6 @@ def archive_old_logs():
os.remove(LOG_FILE)
-
class FilterByMessage(logging.Filter):
def filter(self, record):
# Фильтруем сообщения, содержащие 'Received 1 new updates'
@@ -67,28 +108,41 @@ class FilterByMessage(logging.Filter):
# Initialize Flask application
-app = Flask(__name__)
+app = Flask(__name__, template_folder='templates')
# Настройка логирования
dictConfig({
'version': 1,
+ 'disable_existing_loggers': False, # Включаем, чтобы избежать дублирования логов
'formatters': {
'default': {
'format': '[%(asctime)s] %(levelname)s %(module)s: %(message)s',
},
+ 'error': {
+ 'format': '[%(asctime)s] %(levelname)s %(module)s: %(message)s',
+ },
},
'handlers': {
'console': {
- 'class': 'telezab.UTF8StreamHandler', # Замените на путь к вашему классу UTF8StreamHandler
- 'stream': 'ext://sys.stdout', # Вывод в консоль
+ 'class': 'telezab.UTF8StreamHandler',
+ 'stream': 'ext://sys.stdout',
'formatter': 'default',
'filters': ['filter_by_message']
},
'file': {
'class': 'logging.FileHandler',
- 'filename': 'app.log', # Запись в файл
+ 'filename': 'logs/app.log', # Указываем путь к общим логам
'formatter': 'default',
- 'encoding': 'utf-8', # Кодировка файла
+ 'encoding': 'utf-8',
+ 'filters': ['filter_by_message']
+ },
+ 'error_file': {
+ 'class': 'logging.FileHandler',
+ 'filename': 'logs/error.log', # Указываем путь к логам ошибок
+ 'formatter': 'error',
+ 'encoding': 'utf-8',
+ 'filters': ['filter_by_message'],
+ 'level': 'ERROR' # Логи ошибок будут записываться в отдельный файл
},
},
'filters': {
@@ -98,19 +152,19 @@ dictConfig({
},
'loggers': {
'flask': {
- 'level': 'DEBUG',
- 'handlers': ['console', 'file'],
+ 'level': 'WARNING',
+ 'handlers': ['file', 'error_file'], # Записываем логи во все файлы
'propagate': False,
},
'telebot': {
- 'level': 'DEBUG',
- 'handlers': ['console', 'file'],
+ 'level': 'WARNING',
+ 'handlers': ['file', 'error_file'], # Логи Telebot
'propagate': False,
},
},
'root': {
- 'level': 'DEBUG',
- 'handlers': ['console', 'file'],
+ 'level': 'WARNING',
+ 'handlers': ['file', 'error_file'], # Корневой логгер пишет в файлы
}
})
@@ -118,15 +172,6 @@ dictConfig({
app.logger.setLevel(logging.DEBUG)
# Настройка pyTelegramBotAPI logger
telebot.logger = logging.getLogger('telebot')
-# Get the token from environment variables
-TOKEN = os.getenv('TELEGRAM_TOKEN')
-ZABBIX_URL = os.getenv('ZABBIX_URL')
-ZABBIX_API_TOKEN = os.getenv('ZABBIX_API_TOKEN')
-
-if not TOKEN or not ZABBIX_URL or not ZABBIX_API_TOKEN:
- raise ValueError("One or more required environment variables are missing")
-
-ADMIN_CHAT_IDS = os.getenv('ADMIN_CHAT_IDS', '').split(',')
bot = telebot.TeleBot(TOKEN)
@@ -145,14 +190,12 @@ user_states = {}
user_timers = {}
-
-
def init_db():
global st
st = datetime.now()
try:
with db_lock:
- conn = sqlite3.connect('telezab.db')
+ conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
# Create events table
@@ -169,12 +212,19 @@ def init_db():
username TEXT,
active BOOLEAN DEFAULT TRUE,
skip BOOLEAN DEFAULT FALSE,
+ disaster_only BOOLEAN DEFAULT FALSE,
UNIQUE(chat_id, region_id))''')
# Create whitelist table
cursor.execute('''CREATE TABLE IF NOT EXISTS whitelist (
- chat_id INTEGER PRIMARY KEY)''')
+ chat_id INTEGER PRIMARY KEY,
+ username TEXT,
+ user_email TEXT)''')
+ # Create whitelist table
+ cursor.execute('''CREATE TABLE IF NOT EXISTS admins (
+ chat_id INTEGER PRIMARY KEY,
+ username TEXT)''')
# Create regions table with active flag
cursor.execute('''CREATE TABLE IF NOT EXISTS regions (
region_id TEXT PRIMARY KEY,
@@ -213,7 +263,7 @@ def hash_data(data):
# Check if user is in whitelist
def is_whitelisted(chat_id):
with db_lock:
- conn = sqlite3.connect('telezab.db')
+ conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
query = 'SELECT COUNT(*) FROM whitelist WHERE chat_id = ?'
telebot.logger.debug(f"Executing query: {query} with chat_id={chat_id}")
@@ -226,19 +276,32 @@ def is_whitelisted(chat_id):
# Add user to whitelist
def add_to_whitelist(chat_id, username):
with db_lock:
- conn = sqlite3.connect('telezab.db')
+ conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
query = 'INSERT OR IGNORE INTO whitelist (chat_id, username) VALUES (?, ?)'
telebot.logger.debug(f"Executing query: {query} with chat_id={chat_id}, username={username}")
- cursor.execute(query, (chat_id, username))
+ try:
+ cursor.execute(query, (chat_id, username))
+ conn.commit()
+ except Exception as e:
+ telebot.logger.error(f"Error during add to whitelist: {e}")
+ finally:
+ conn.close()
+
+def rundeck_add_to_whitelist(chat_id, username, user_email):
+ with db_lock:
+ conn = sqlite3.connect(DB_PATH)
+ cursor = conn.cursor()
+ query = 'INSERT OR IGNORE INTO whitelist (chat_id, username, user_email) VALUES (?, ?, ?)'
+ telebot.logger.debug(f"Executing query: {query} with chat_id={chat_id}, username={username}, email={user_email}")
+ cursor.execute(query, (chat_id, username, user_email))
conn.commit()
- conn.close()
# Remove user from whitelist
def remove_from_whitelist(chat_id):
with db_lock:
- conn = sqlite3.connect('telezab.db')
+ conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
query = 'DELETE FROM whitelist WHERE chat_id = ?'
telebot.logger.debug(f"Executing query: {query} with chat_id={chat_id}")
@@ -246,11 +309,20 @@ def remove_from_whitelist(chat_id):
conn.commit()
conn.close()
+def get_admins():
+ with db_lock:
+ conn = sqlite3.connect(DB_PATH)
+ cursor = conn.cursor()
+ cursor.execute('SELECT chat_id FROM admins')
+ admins = cursor.fetchall()
+ admins = [i[0] for i in admins]
+ conn.close()
+ return admins
# Get list of regions
def get_regions():
with db_lock:
- conn = sqlite3.connect('telezab.db')
+ conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute('SELECT region_id, region_name FROM regions WHERE active = TRUE ORDER BY region_id')
regions = cursor.fetchall()
@@ -260,7 +332,7 @@ def get_regions():
def get_sorted_regions():
with db_lock:
- conn = sqlite3.connect('telezab.db')
+ conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute('SELECT region_id, region_name FROM regions WHERE active = TRUE')
regions = cursor.fetchall()
@@ -274,7 +346,7 @@ def get_sorted_regions():
# Check if region exists
def region_exists(region_id):
with db_lock:
- conn = sqlite3.connect('telezab.db')
+ conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute('SELECT COUNT(*) FROM regions WHERE region_id = ? AND active = TRUE', (region_id,))
count = cursor.fetchone()[0]
@@ -285,7 +357,7 @@ def region_exists(region_id):
# Get list of regions a user is subscribed to
def get_user_subscribed_regions(chat_id):
with db_lock:
- conn = sqlite3.connect('telezab.db')
+ conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute('''
SELECT regions.region_id, regions.region_name
@@ -302,7 +374,7 @@ def get_user_subscribed_regions(chat_id):
# Check if user is subscribed to a region
def is_subscribed(chat_id, region_id):
with db_lock:
- conn = sqlite3.connect('telezab.db')
+ conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute('''
SELECT COUNT(*)
@@ -323,7 +395,7 @@ def log_user_event(chat_id, username, action):
timestamp = time.strftime('%Y-%m-%d %H:%M:%S')
try:
with db_lock:
- conn = sqlite3.connect('telezab.db')
+ conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
query = 'INSERT INTO user_events (chat_id, username, action, timestamp) VALUES (?, ?, ?, ?)'
telebot.logger.debug(f"Executing query: {query} with chat_id={chat_id}, username={username}, action={action}, timestamp={timestamp}")
@@ -348,7 +420,7 @@ def set_user_state(chat_id, state):
def start_settings_timer(chat_id):
if chat_id in user_timers:
user_timers[chat_id].cancel()
- timer = Timer(30, transition_to_notification_mode, [chat_id])
+ timer = Timer(300, transition_to_notification_mode, [chat_id])
user_timers[chat_id] = timer
timer.start()
@@ -382,39 +454,37 @@ def show_main_menu(chat_id):
bot.send_message(chat_id, "Выберите действие:", reply_markup=markup)
+def create_settings_keyboard(chat_id, admins_list):
+ markup = telebot.types.ReplyKeyboardMarkup(one_time_keyboard=True, resize_keyboard=True)
+ # Линия 1: "Подписаться", "Отписаться"
+ markup.row('Подписаться','Отписаться','Мои подписки')
+ markup.row('Активные регионы','Режим уведомлений')
+ if chat_id in admins_list:
+ markup.row('Добавить регион', 'Удалить регион')
+ markup.row('Назад')
+ return markup
+
+
# Settings menu for users
def show_settings_menu(chat_id):
- markup = telebot.types.ReplyKeyboardMarkup(one_time_keyboard=True, resize_keyboard=True)
- if str(chat_id) in ADMIN_CHAT_IDS:
- markup.add('Подписаться', 'Отписаться', 'Мои подписки', 'Активные регионы', 'Добавить регион', 'Удалить регион', 'Назад')
- markup.add('Тестовое событие', 'Тест триггеров')
- else:
- markup.add('Подписаться', 'Отписаться', 'Мои подписки', 'Активные регионы', 'Назад')
+ if not is_whitelisted(chat_id):
+ bot.send_message(chat_id, "Вы неавторизованы для использования этого бота")
+ return
+
+ admins_list = get_admins()
+ markup = create_settings_keyboard(chat_id, admins_list)
+
bot.send_message(chat_id, "Вы находитесь в режиме настроек. Выберите действие:", reply_markup=markup)
-# Handle /start command
-@bot.message_handler(commands=['start'])
-def handle_start(message):
- chat_id = message.chat.id
- username = message.from_user.username
- if username:
- username = f"@{username}"
- else:
- username = "N/A"
-
- set_user_state(chat_id, NOTIFICATION_MODE)
- show_main_menu(chat_id)
-
- telebot.logger.info(f"User {chat_id} ({username}) started with command /start.")
-
-
# Handle menu button presses
@bot.message_handler(func=lambda message: True)
def handle_menu_selection(message):
chat_id = message.chat.id
text = message.text.strip().lower()
-
+ if not is_whitelisted(chat_id) and text not in ['регистрация', '/start']:
+ bot.send_message(chat_id, "Вы неавторизованы для использования этого бота.")
+ return
if user_states.get(chat_id, NOTIFICATION_MODE) == SETTINGS_MODE:
reset_settings_timer(chat_id)
handle_settings_menu_selection(message)
@@ -437,9 +507,12 @@ def handle_menu_selection(message):
def handle_settings_menu_selection(message):
chat_id = message.chat.id
text = message.text.strip().lower()
+ if not is_whitelisted(chat_id):
+ bot.send_message(chat_id, "Вы неавторизованы для использования этого бота.")
+ return
reset_settings_timer(chat_id)
-
+ admins_list = get_admins()
if text == 'подписаться':
handle_subscribe(message)
elif text == 'отписаться':
@@ -448,13 +521,15 @@ def handle_settings_menu_selection(message):
handle_my_subscriptions(message)
elif text == 'активные регионы':
handle_active_regions(message)
- elif text == 'добавить регион' and str(chat_id) in ADMIN_CHAT_IDS:
+ elif text == 'режим уведомлений':
+ handle_notification_mode(message)
+ elif text == 'добавить регион' and chat_id in admins_list:
prompt_admin_for_region(chat_id, 'add')
- elif text == 'удалить регион' and str(chat_id) in ADMIN_CHAT_IDS:
+ elif text == 'удалить регион' and chat_id in admins_list:
prompt_admin_for_region(chat_id, 'remove')
- elif text == 'тестовое событие' and str(chat_id) in ADMIN_CHAT_IDS:
+ elif text == 'тестовое событие' and chat_id in admins_list:
simulate_event(message)
- elif text == 'тест триггеров' and str(chat_id) in ADMIN_CHAT_IDS:
+ elif text == 'тест триггеров' and chat_id in admins_list:
simulate_triggers(message)
elif text == 'назад':
set_user_state(chat_id, NOTIFICATION_MODE)
@@ -493,15 +568,17 @@ def process_subscription(message, chat_id, username):
valid_region_ids = get_regions()
valid_region_ids = [region[0] for region in valid_region_ids]
with db_lock:
- conn = sqlite3.connect('telezab.db')
+ conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
for region_id in region_ids:
region_id = region_id.strip()
if not region_id.isdigit() or region_id not in valid_region_ids:
- bot.send_message(chat_id, f"Регион с ID {region_id} не существует или недопустимый формат. Введите только существующие номера регионов.")
+ bot.send_message(chat_id,
+ f"Регион с ID {region_id} не существует или недопустимый формат. Введите только существующие номера регионов.")
return show_settings_menu(chat_id)
query = 'INSERT OR IGNORE INTO subscriptions (chat_id, region_id, username, active) VALUES (?, ?, ?, TRUE)'
- telebot.logger.debug(f"Executing query: {query} with chat_id={chat_id}, region_id={region_id}, username={username}")
+ telebot.logger.debug(
+ f"Executing query: {query} with chat_id={chat_id}, region_id={region_id}, username={username}")
cursor.execute(query, (chat_id, region_id, username))
if cursor.rowcount == 0:
query = 'UPDATE subscriptions SET active = TRUE WHERE chat_id = ? AND region_id = ?'
@@ -544,7 +621,7 @@ def process_unsubscription(message, chat_id):
valid_region_ids = get_user_subscribed_regions(chat_id)
valid_region_ids = [region[0] for region in valid_region_ids]
with db_lock:
- conn = sqlite3.connect('telezab.db')
+ conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
for region_id in region_ids:
region_id = region_id.strip()
@@ -566,17 +643,22 @@ def process_unsubscription(message, chat_id):
# Handle /help command to provide instructions
@bot.message_handler(commands=['help'])
def handle_help(message):
+ chat_id = message.chat.id
+ if not is_whitelisted(chat_id):
+ bot.send_message(chat_id, "Вы неавторизованы для использования этого бота.")
+ return
help_text = (
- "/start - Показать меню бота\n"
- "Настройки - Перейти в режим настроек и управлять подписками\n"
- "Помощь - Показать это сообщение"
+ '/start - Показать меню бота\n'
+ 'Настройки - Перейти в режим настроек и управления подписками\n'
+ 'Активные тригеры - Получение активных проблем за последние 24 часа\n'
+ 'Помощь - Описание всех возможностей бота'
+
)
- bot.send_message(message.chat.id, help_text)
+ bot.send_message(message.chat.id, help_text, parse_mode="html")
show_main_menu(message.chat.id)
# Handle /register command for new user registration
-@bot.message_handler(commands=['register'])
def handle_register(message):
chat_id = message.chat.id
username = message.from_user.username
@@ -586,60 +668,9 @@ def handle_register(message):
username = "N/A"
bot.send_message(chat_id,
- f"Ваш chat ID: {chat_id}, ваше имя пользователя: {username}. Запрос на одобрение отправлен администратору.")
+ f"Ваш chat ID: {chat_id}\nВаше имя пользователя: {username}\nДля продолжения регистрации необходимо отправить письмо на почту {SUPPORT_EMAIL}\nВ теме письма указать Telegram Bot\nВ теле письма указать полученные данные")
log_user_event(chat_id, username, "Requested registration")
- for admin_chat_id in ADMIN_CHAT_IDS:
- markup = telebot.types.InlineKeyboardMarkup()
- markup.add(
- telebot.types.InlineKeyboardButton(text="Подтвердить", callback_data=f"approve_{chat_id}_{username}"),
- telebot.types.InlineKeyboardButton(text="Отменить", callback_data=f"decline_{chat_id}_{username}")
- )
- bot.send_message(
- admin_chat_id,
- f"Пользователь {username} ({chat_id}) запрашивает регистрацию. Вы подтверждаете это действие?",
- reply_markup=markup
- )
-
-
-@bot.callback_query_handler(func=lambda call: call.data.startswith("approve_") or call.data.startswith("decline_"))
-def handle_admin_response(call):
- action, chat_id, username = call.data.split("_")
- if action == "approve":
- add_to_whitelist(int(chat_id), username)
- bot.send_message(chat_id, "Ваша регистрация одобрена администратором.")
- bot.send_message(call.message.chat.id, f"Пользователь {username} ({chat_id}) добавлен в белый список.")
- log_user_event(chat_id, username, "Approved registration")
- elif action == "decline":
- bot.send_message(chat_id, "Ваша регистрация отклонена администратором.")
- bot.send_message(call.message.chat.id, f"Пользователь {username} ({chat_id}) отклонен.")
- log_user_event(chat_id, username, "Declined registration")
- bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, reply_markup=None)
- bot.answer_callback_query(call.id)
-
-
-
-def process_register(message, chat_id, username):
- if message.text.lower() == 'отмена':
- bot.send_message(chat_id, "Регистрация отменена.")
- show_main_menu(chat_id)
- return
-
- if message.text.lower() == 'подтвердить регистрацию':
- for admin_chat_id in ADMIN_CHAT_IDS:
- markup = telebot.types.ReplyKeyboardMarkup(one_time_keyboard=True, resize_keyboard=True)
- markup.add(f'/add_whitelist {chat_id}', 'Отмена')
- bot.send_message(
- admin_chat_id,
- f"Пользователь {username} ({chat_id}) запрашивает регистрацию.\n"
- f"Вы подтверждаете это действие?",
- reply_markup=markup
- )
- bot.send_message(chat_id, "Запрос отправлен администратору для одобрения.")
- telebot.logger.info(f"User {chat_id} ({username}) requested registration.")
- else:
- bot.send_message(chat_id, "Некорректный выбор. Регистрация отменена.")
- show_main_menu(chat_id)
# Handle admin region management commands
@@ -658,7 +689,7 @@ def process_add_region(message):
try:
region_id, region_name = message.text.split()[0], ' '.join(message.text.split()[1:])
with db_lock:
- conn = sqlite3.connect('telezab.db')
+ conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
query = 'SELECT region_name, active FROM regions WHERE region_id = ?'
telebot.logger.debug(f"Executing query: {query} with region_id={region_id}")
@@ -705,7 +736,7 @@ def handle_region_action(call):
return show_settings_menu(chat_id)
with db_lock:
- conn = sqlite3.connect('telezab.db')
+ conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
if action == "replace":
query = 'UPDATE regions SET region_name = ?, active = TRUE WHERE region_id = ?'
@@ -733,7 +764,7 @@ def process_remove_region(message):
try:
region_id = message.text.split()[0]
with db_lock:
- conn = sqlite3.connect('telezab.db')
+ conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
# Проверка существования региона
query = 'SELECT COUNT(*) FROM regions WHERE region_id = ?'
@@ -757,6 +788,7 @@ def process_remove_region(message):
bot.send_message(chat_id, "Неверный формат. Используйте: ")
show_settings_menu(chat_id)
+
# Handle displaying active subscriptions for a user
def handle_my_subscriptions(message):
chat_id = message.chat.id
@@ -790,15 +822,25 @@ def handle_active_regions(message):
regions_list = format_regions_list(regions)
bot.send_message(chat_id, f"Активные регионы:\n{regions_list}")
show_settings_menu(chat_id)
-
-
# RabbitMQ configuration
RABBITMQ_HOST = os.getenv('RABBITMQ_HOST', 'localhost')
RABBITMQ_QUEUE = 'telegram_notifications'
def rabbitmq_connection():
- connection = pika.BlockingConnection(pika.ConnectionParameters(RABBITMQ_HOST))
+ # Создаем объект учетных данных
+ credentials = pika.PlainCredentials('admin', 'admin')
+
+ # Указываем параметры подключения, включая учетные данные
+ parameters = pika.ConnectionParameters(
+ host=RABBITMQ_HOST,
+ credentials=credentials, # Передаем учетные данные
+ heartbeat=600, # Интервал heartbeat для поддержания соединения
+ blocked_connection_timeout=300 # Таймаут блокировки соединения
+ )
+
+ # Создаем подключение и канал
+ connection = pika.BlockingConnection(parameters)
channel = connection.channel()
channel.queue_declare(queue=RABBITMQ_QUEUE, durable=True)
return connection, channel
@@ -839,7 +881,14 @@ async def send_message(chat_id, message, is_notification=False):
try:
if is_notification:
await rate_limit_semaphore.acquire()
- await run_in_executor(bot.send_message, chat_id, message)
+ parse_mode = 'HTML'
+
+ # Используем partial для передачи именованных аргументов в bot.send_message
+ func_with_args = partial(bot.send_message, chat_id=chat_id, text=message, parse_mode=parse_mode)
+
+ # Передаем подготовленную функцию в run_in_executor
+ await run_in_executor(func_with_args)
+
except telebot.apihelper.ApiTelegramException as e:
if "429" in str(e):
telebot.logger.warning(f"Rate limit exceeded for chat_id {chat_id}. Retrying...")
@@ -847,14 +896,16 @@ async def send_message(chat_id, message, is_notification=False):
await send_message(chat_id, message, is_notification)
else:
telebot.logger.error(f"Failed to send message to {chat_id}: {e}")
+ telebot.logger.error(f"Detailed Error: {e}", exc_info=True) # Добавлено логирование исключения
except Exception as e:
- telebot.logger.error(f"Error sending message to {chat_id}: {e}")
+ telebot.logger.error(f"Unexpected error while sending message to {chat_id}: {e}", exc_info=True)
await check_telegram_api()
finally:
if is_notification:
rate_limit_semaphore.release()
+
async def send_notification_message(chat_id, message):
await send_message(chat_id, message, is_notification=True)
@@ -894,7 +945,7 @@ def webhook():
event_hash = hash_data(data)
with db_lock:
- conn = sqlite3.connect('telezab.db')
+ conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute('SELECT COUNT(*) FROM events')
count = cursor.fetchone()[0]
@@ -910,12 +961,17 @@ def webhook():
app.logger.error(f"Failed to extract region number from host: {data.get('host')}")
return jsonify({"status": "error", "message": "Invalid host format"}), 400
- # Fetch chat_ids to send the alert
- query = 'SELECT chat_id, username FROM subscriptions WHERE region_id = ? AND active = TRUE AND skip = FALSE'
+ # Fetch chat_ids to send the alert based on disaster_only flag
+ if data['severity'] == '5': # Авария
+ query = 'SELECT chat_id,username FROM subscriptions WHERE region_id = ? AND active = TRUE'
+ else: # Высокая
+ query = 'SELECT chat_id,username FROM subscriptions WHERE region_id = ? AND active = TRUE AND disaster_only = FALSE'
+
app.logger.debug(f"Executing query: {query} with region_id={region_id}")
cursor.execute(query, (region_id,))
results = cursor.fetchall()
+
# Check if the region is active
query = 'SELECT active FROM regions WHERE region_id = ?'
cursor.execute(query, (region_id,))
@@ -967,40 +1023,159 @@ def format_message(data):
if data['status'].upper() == "PROBLEM":
message = (
- f"⚠️ {data['host']} ({data["ip"]})\n"
+ f"⚠️ {data['host']} ({data['ip']})\n"
f"{data['msg']}\n"
f"Критичность: {data['severity']}"
)
if 'link' in data:
- message += f'\nURL: {data['link']}'
+ message += f'\nURL: Ссылка на график'
return message
else:
message = (
- f"✅ {data['host']} ({data["ip"]})\n"
- f"{data['msg']}\n"
- f"Критичность: {data['severity']}\n"
- f"Проблема устранена!\n"
- f"Время устранения проблемы: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(int(data['date_reception'])))}"
+ f"✅ {data['host']} ({data['ip']})\n"
+ f"Описание: {data['msg']}\n"
+ f"Критичность: {data['severity']}\n"
+ f"Проблема устранена!\n"
+ f"Время устранения проблемы: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(int(data['date_reception'])))}\n"
)
+ if 'link' in data:
+ message += f'URL: Ссылка на график'
return message
except KeyError as e:
app.logger.error(f"Missing key in data: {e}")
raise ValueError(f"Missing key in data: {e}")
+@bot.callback_query_handler(func=lambda call: call.data.startswith("notification_mode_"))
+def handle_notification_mode_selection(call):
+ chat_id = call.message.chat.id
+ message_id = call.message.message_id
+ mode = call.data.split("_")[2]
+
+ # Убираем клавиатуру
+ bot.edit_message_reply_markup(chat_id=chat_id, message_id=message_id, reply_markup=None)
+
+ # Обновляем режим уведомлений
+ disaster_only = True if mode == "disaster" else False
+
+ try:
+ with db_lock:
+ conn = sqlite3.connect(DB_PATH)
+ cursor = conn.cursor()
+ query = 'UPDATE subscriptions SET disaster_only = ? WHERE chat_id = ?'
+ cursor.execute(query, (disaster_only, chat_id))
+ conn.commit()
+
+ mode_text = "Только Авария" if disaster_only else "Все события"
+ bot.send_message(chat_id, f"Режим уведомлений успешно изменён на: {mode_text}")
+ except Exception as e:
+ telebot.logger.error(f"Error updating notification mode for {chat_id}: {e}")
+ bot.send_message(chat_id, "Произошла ошибка при изменении режима уведомлений.")
+ finally:
+ conn.close()
+
+ bot.answer_callback_query(call.id)
+
+@bot.message_handler(func=lambda message: message.text.lower() == 'режим уведомлений')
+def handle_notification_mode(message):
+ chat_id = message.chat.id
+ if not is_whitelisted(chat_id):
+ bot.send_message(chat_id, "Вы неавторизованы для использования этого бота")
+ return
+
+ markup = types.InlineKeyboardMarkup()
+ markup.add(types.InlineKeyboardButton(text="Все события", callback_data="notification_mode_all"))
+ markup.add(types.InlineKeyboardButton(text="Только Авария", callback_data="notification_mode_disaster"))
+
+ bot.send_message(chat_id, "Выберите какой режим уведомлений вы хотите:\n"
+ "1. Все события - В этом режиме вы получаете все события с критическим уровнем 'Высокая' и 'Авария'.\n"
+ "2. Авария - В этом режиме вы получаете только события уровня 'Авария'.", reply_markup=markup)
+
+
@app.route('/add_user', methods=['POST'])
def add_user():
data = request.get_json()
telegram_id = data.get('telegram_id')
chat_id = data.get('chat_id')
+ user_email = data.get('user_email')
- if telegram_id and chat_id:
- add_to_whitelist(chat_id, telegram_id)
+ if telegram_id and chat_id and user_email:
+ rundeck_add_to_whitelist(chat_id, telegram_id, user_email)
app.logger.info(f"User {telegram_id} added to whitelist.")
- return jsonify({"status": "success"}), 200
+ bot.send_message(chat_id, "Регистрация пройдена успешна.")
+ return jsonify({"status": "success","msg": f"User {telegram_id} with {user_email} added successfull"}), 200
else:
app.logger.error("Invalid data received for adding user.")
return jsonify({"status": "failure", "reason": "Invalid data"}), 400
+#Получение информации по текущим юзерам
+@app.route('/users/get_users', methods=['GET'])
+def get_users():
+ try:
+ with db_lock:
+ conn = sqlite3.connect(DB_PATH)
+ cursor = conn.cursor()
+
+ # Получение пользователей из таблицы whitelist
+ cursor.execute('SELECT * FROM whitelist')
+ users = cursor.fetchall()
+ users_dict = {id: {'id': id, 'username': username, 'email': email, 'events': [], 'worker': '', 'subscriptions': []}
+ for id, username, email in users}
+
+ # Получение событий из таблицы user_events
+ cursor.execute('SELECT chat_id, username, action, timestamp FROM user_events')
+ events = cursor.fetchall()
+
+ # Обработка событий и добавление их в соответствующего пользователя
+ for chat_id, username, action, timestamp in events:
+ if chat_id in users_dict:
+ event = {'type': action, 'date': timestamp}
+ if "Subscribed to region" in action:
+ region = action.split(": ")[-1] # Получаем регион из текста
+ event['region'] = region
+ users_dict[chat_id]['events'].append(event)
+
+ # Получение активных подписок из таблицы subscription
+ cursor.execute('SELECT chat_id, region_id FROM subscriptions WHERE active = 1')
+ subscriptions = cursor.fetchall()
+
+ # Добавление подписок к соответствующему пользователю
+ for chat_id, region_id in subscriptions:
+ if chat_id in users_dict:
+ users_dict[chat_id]['subscriptions'].append(str(region_id))
+
+ # Формирование worker из email (Имя Фамилия)
+ for user in users_dict.values():
+ email = user['email']
+ name_parts = email.split('@')[0].split('.')
+ if len(name_parts) >= 2:
+ user['worker'] = f"{name_parts[0].capitalize()} {name_parts[1].capitalize()}"
+ if len(name_parts) == 3:
+ user['worker'] += f" {name_parts[2][0].capitalize()}."
+
+ conn.commit()
+ conn.close()
+
+ # Преобразование в список с упорядоченными ключами
+ result = []
+ for user in users_dict.values():
+ ordered_user = {
+ 'email': user['email'],
+ 'username': user['username'],
+ 'id': user['id'],
+ 'worker': user['worker'],
+ 'events': user['events'],
+ 'subscriptions': ', '.join(user['subscriptions']) # Объединяем регионы в строку через запятую
+ }
+ result.append(ordered_user)
+
+ return jsonify(result)
+ except Exception as e:
+ return jsonify({'status': 'error', 'message': str(e)}), 500
+
+@app.route('/users/view', methods=['GET'])
+def view_users():
+ # noinspection PyUnresolvedReferences
+ return render_template('users.html')
# Обработчик для переключения уровня логирования Flask
@@ -1044,141 +1219,252 @@ def toggle_telebot_debug():
except Exception as e:
return jsonify({'status': 'error', 'message': str(e)}), 500
-# Handle active triggers
+# Фаза 1: Запрос активных триггеров и выбор региона с постраничным переключением
def handle_active_triggers(message):
chat_id = message.chat.id
- regions = get_user_subscribed_regions(chat_id)
- regions_per_page = 3
+ regions = get_user_subscribed_regions(chat_id) # Функция для получения доступных регионов
+ if not regions:
+ bot.send_message(chat_id, "У вас нет подписанных регионов.")
+ return
+
start_index = 0
-
- markup = create_region_markup(regions, start_index, regions_per_page)
- bot.send_message(chat_id, "По какому региону хотите получить активные проблемы:", reply_markup=markup)
+ markup = create_region_keyboard(regions, start_index)
+ bot.send_message(chat_id, "Выберите регион для получения активных триггеров:", reply_markup=markup)
-def create_region_markup(regions, start_index, regions_per_page):
- markup = telebot.types.InlineKeyboardMarkup()
+def create_region_keyboard(regions, start_index, regions_per_page=5):
+ markup = types.InlineKeyboardMarkup()
end_index = min(start_index + regions_per_page, len(regions))
- buttons = []
+ # Создаём кнопки для регионов
for i in range(start_index, end_index):
region_id, region_name = regions[i]
- buttons.append(telebot.types.InlineKeyboardButton(text=region_id, callback_data=f"region_{region_id}"))
+ button = types.InlineKeyboardButton(text=f"{region_name}", callback_data=f"region_{region_id}")
+ markup.add(button)
- prev_button = telebot.types.InlineKeyboardButton(text="<", callback_data=f"prev_{start_index}") if start_index > 0 else None
- next_button = telebot.types.InlineKeyboardButton(text=">", callback_data=f"next_{start_index}") if end_index < len(regions) else None
+ # Добавляем кнопки для переключения страниц
+ navigation_row = []
+ if start_index > 0:
+ navigation_row.append(types.InlineKeyboardButton(text="<", callback_data=f"prev_{start_index}"))
+ if end_index < len(regions):
+ navigation_row.append(types.InlineKeyboardButton(text=">", callback_data=f"next_{end_index}"))
- row_buttons = [prev_button] + buttons + [next_button]
- row_buttons = [btn for btn in row_buttons if btn is not None] # Remove None values
+ if navigation_row:
+ markup.row(*navigation_row)
- markup.row(*row_buttons)
return markup
-@bot.callback_query_handler(func=lambda call: call.data.startswith("region_"))
-def handle_region_selection(call):
- region_id = call.data.split("_")[1]
+@bot.callback_query_handler(func=lambda call: call.data.startswith("region_") or call.data.startswith("prev_") or call.data.startswith("next_"))
+def handle_region_pagination(call):
+ chat_id = call.message.chat.id
+ message_id = call.message.message_id
+ data = call.data
+
+ # Убираем клавиатуру, если регион был выбран
+ if data.startswith("region_"):
+ bot.edit_message_reply_markup(chat_id=chat_id, message_id=message_id, reply_markup=None)
+
+ regions = get_user_subscribed_regions(chat_id)
+ regions_per_page = 5
+
+ if data.startswith("region_"):
+ region_id = data.split("_")[1]
+ handle_region_selection(call, region_id)
+ elif data.startswith("prev_") or data.startswith("next_"):
+ direction, index = data.split("_")
+ index = int(index)
+
+ start_index = max(0, index - regions_per_page) if direction == "prev" else min(len(regions) - regions_per_page, index)
+ markup = create_region_keyboard(regions, start_index, regions_per_page)
+ bot.edit_message_reply_markup(chat_id, call.message.message_id, reply_markup=markup)
+
+ bot.answer_callback_query(call.id)
+
+
+
+# Фаза 2: Обработка выбора региона и предложить выбор группы
+def handle_region_selection(call, region_id):
chat_id = call.message.chat.id
try:
- # Получение всех групп хостов, содержащих region_id в названии
+ # Получаем группы хостов для выбранного региона
zapi = ZabbixAPI(ZABBIX_URL)
zapi.login(api_token=ZABBIX_API_TOKEN)
- host_groups = zapi.hostgroup.get(
- output=["groupid", "name"],
- search={"name": region_id}
- )
-
- # Фильтрация групп хостов, исключая те, в названии которых есть "test"
+ host_groups = zapi.hostgroup.get(output=["groupid", "name"], search={"name": region_id})
filtered_groups = [group for group in host_groups if 'test' not in group['name'].lower()]
+ # Если нет групп
if not filtered_groups:
- bot.send_message(chat_id, "Нет групп хостов, соответствующих данному региону.")
- bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, reply_markup=None)
- bot.answer_callback_query(call.id)
+ bot.send_message(chat_id, "Нет групп хостов для этого региона.")
+ return_to_main_menu(chat_id)
return
- # Отправка списка групп хостов пользователю в виде кнопок
- markup = telebot.types.InlineKeyboardMarkup()
+ # Создаем клавиатуру с выбором группы или всех групп
+ markup = types.InlineKeyboardMarkup()
for group in filtered_groups:
- markup.add(telebot.types.InlineKeyboardButton(text=group['name'], callback_data=f"group_{group['groupid']}"))
+ markup.add(types.InlineKeyboardButton(text=group['name'], callback_data=f"group_{group['groupid']}"))
+ markup.add(types.InlineKeyboardButton(text="Все группы региона", callback_data=f"all_groups_{region_id}"))
- bot.send_message(chat_id, f"Найдены следующие группы хостов для региона {region_id}:", reply_markup=markup)
+ bot.send_message(chat_id, "Выберите группу хостов или получите триггеры по всем группам региона:", reply_markup=markup)
except Exception as e:
- telebot.logger.error(f"Error connecting to Zabbix API: {e}")
- bot.send_message(chat_id, "Не удалось подключиться к Zabbix API. Пожалуйста, попробуйте позже.")
+ bot.send_message(chat_id, "Ошибка при подключении к Zabbix API.")
+ return_to_main_menu(chat_id)
- bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, reply_markup=None)
- bot.answer_callback_query(call.id)
-@bot.callback_query_handler(func=lambda call: call.data.startswith("group_"))
-def handle_group_selection(call):
- group_id = call.data.split("_")[1]
+# Фаза 3: Обработка выбора группы/всех групп и запрос периода
+@bot.callback_query_handler(func=lambda call: call.data.startswith("group_") or call.data.startswith("all_groups_"))
+def handle_group_or_all_groups(call):
chat_id = call.message.chat.id
+ message_id = call.message.message_id
- try:
- # Получение триггеров для выбранной группы хостов
- triggers = get_zabbix_triggers(group_id)
- if triggers is None:
- bot.send_message(chat_id, "Не удалось подключиться к Zabbix API. Пожалуйста, попробуйте позже.")
- elif not triggers:
- bot.send_message(chat_id, "Нет активных проблем по указанной группе уровня HIGH и DISASTER за последние 24 часа.")
- else:
- for trigger in triggers:
- bot.send_message(chat_id, trigger, parse_mode="html")
- time.sleep(1/5)
- except Exception as e:
- telebot.logger.error(f"Error processing group selection: {e}")
- bot.send_message(chat_id, "Произошла ошибка при обработке вашего запроса. Пожалуйста, попробуйте позже.")
+ # Убираем клавиатуру после выбора группы
+ bot.edit_message_reply_markup(chat_id=chat_id, message_id=message_id, reply_markup=None)
- bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, reply_markup=None)
- bot.answer_callback_query(call.id)
+ # Если выбрана конкретная группа
+ if call.data.startswith("group_"):
+ group_id = call.data.split("_")[1]
+ get_triggers_for_group(chat_id, group_id) # Сразу получаем триггеры для группы
+
+ # Если выбраны все группы региона
+ elif call.data.startswith("all_groups_"):
+ region_id = call.data.split("_")[2]
+ get_triggers_for_all_groups(chat_id, region_id) # Сразу получаем триггеры для всех групп региона
-@bot.callback_query_handler(func=lambda call: call.data.startswith("prev_") or call.data.startswith("next_"))
-def handle_pagination(call):
- direction, index = call.data.split("_")
- index = int(index)
- regions = get_user_subscribed_regions(call.message.chat.id)
- regions_per_page = 3
- if direction == "prev":
- start_index = max(0, index - regions_per_page)
+# # Фаза 4: Обработка выбора периода и отправка триггеров
+# @bot.callback_query_handler(func=lambda call: call.data.startswith("period_"))
+# def handle_period_selection(call):
+# chat_id = call.message.chat.id
+# message_id = call.message.message_id
+# data = call.data
+#
+# # Убираем клавиатуру, чтобы избежать повторных срабатываний
+# bot.edit_message_reply_markup(chat_id=chat_id, message_id=message_id, reply_markup=None)
+#
+#
+# # Извлекаем количество часов и оставшуюся часть данных
+# period_prefix, period_hours, group_or_all_data = data.split("_", 2)
+#
+# try:
+# # Преобразуем количество часов в целое число
+# hours = int(period_hours)
+#
+# # Определяем, что было выбрано (группа или все группы региона)
+# if group_or_all_data.startswith("group_"):
+# group_id = group_or_all_data.split("_")[1]
+# get_triggers_for_group(chat_id, group_id)
+# elif group_or_all_data.startswith("all_groups_"):
+# region_id = group_or_all_data.split("_")[2]
+# get_triggers_for_all_groups(chat_id, region_id)
+# except ValueError as e:
+# bot.send_message(chat_id, "Произошла ошибка при выборе периода. Попробуйте снова.")
+# telebot.logger.error(f"Error processing period selection: {e}")
+
+
+
+# Вспомогательная функция: получение триггеров для группы
+def get_triggers_for_group(chat_id, group_id):
+ triggers = get_zabbix_triggers(group_id) # Получаем все активные триггеры без периода
+ if not triggers:
+ bot.send_message(chat_id, f"Нет активных триггеров.")
else:
- start_index = min(len(regions) - regions_per_page, index + regions_per_page)
+ send_triggers_to_user(triggers, chat_id)
- markup = create_region_markup(regions, start_index, regions_per_page)
- bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, reply_markup=markup)
- bot.answer_callback_query(call.id) # Завершение обработки callback
+def get_triggers_for_all_groups(chat_id, region_id):
+ try:
+ zapi = ZabbixAPI(ZABBIX_URL)
+ zapi.login(api_token=ZABBIX_API_TOKEN)
+
+ host_groups = zapi.hostgroup.get(output=["groupid", "name"], search={"name": region_id})
+ filtered_groups = [group for group in host_groups if 'test' not in group['name'].lower()]
+
+ all_triggers = []
+ for group in filtered_groups:
+ triggers = get_zabbix_triggers(group['groupid'])
+ if triggers:
+ all_triggers.extend(triggers)
+
+ if all_triggers:
+ send_triggers_to_user(all_triggers, chat_id)
+ else:
+ bot.send_message(chat_id, f"Нет активных триггеров.")
+ except Exception as e:
+ bot.send_message(chat_id, "Ошибка при получении триггеров.")
+ return_to_main_menu(chat_id)
+
+
+
+# Вспомогательная функция: отправка триггеров пользователю
+def send_triggers_to_user(triggers, chat_id):
+ for trigger in triggers:
+ bot.send_message(chat_id, trigger, parse_mode="html")
+ time.sleep(1 / 5)
+
+
+# Вспомогательная функция: возврат в главное меню
+def return_to_main_menu(chat_id):
+ markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
+ markup.add(types.KeyboardButton("Вернуться в меню"))
+ bot.send_message(chat_id, "Вы можете вернуться в главное меню.", reply_markup=markup)
+
+
+def escape_telegram_chars(text):
+ """
+ Экранирует запрещённые символы для Telegram API:
+ < -> <
+ > -> >
+ & -> &
+ Также проверяет на наличие запрещённых HTML-тегов и другие проблемы с форматированием.
+ """
+ replacements = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"', # Для кавычек
+ }
+
+ # Применяем замены
+ for char, replacement in replacements.items():
+ text = text.replace(char, replacement)
+
+ return text
def get_zabbix_triggers(group_id):
try:
- # Создайте подключение к вашему Zabbix серверу
zapi = ZabbixAPI(ZABBIX_URL)
zapi.login(api_token=ZABBIX_API_TOKEN)
- # Получение триггеров уровня "Высокая" и "Авария" за последние 24 часа для указанной группы хостов
- time_from = int(time.time()) - 24 * 3600 # последние 24 часа
- time_till = int(time.time())
+ # Рассчитываем временной диапазон на основе переданного количества часов
+ # time_from = int(time.time()) - period * 3600 # последние N часов
+ # time_till = int(time.time())
+
+ telebot.logger.info(f"Fetching triggers for group {group_id}")
+
+ # Получение триггеров
triggers = zapi.trigger.get(
output=["triggerid", "description", "priority"],
selectHosts=["hostid", "name"],
groupids=group_id,
- filter={"priority": ["4", "5"], "value": "1"},
+ filter={"priority": ["4", "5"], "value": "1"}, # Высокий приоритет и авария
only_true=1,
active=1,
withLastEventUnacknowledged=1,
- time_from=time_from,
- time_till=time_till,
+ # time_from=time_from, # Устанавливаем временной фильтр
+ # time_till=time_till,
expandDescription=1,
expandComment=1,
selectItems=["itemid", "lastvalue"],
selectLastEvent=["clock"]
)
+ telebot.logger.info(f"Found {len(triggers)} triggers for group {group_id}")
+
# Московское время
moskva_tz = timezone('Europe/Moscow')
@@ -1188,30 +1474,24 @@ def get_zabbix_triggers(group_id):
}
trigger_messages = []
- current_time = datetime.now(moskva_tz)
- one_day_ago = current_time - timedelta(days=1)
for trigger in triggers:
- # Получаем время последнего события
event_time_epoch = int(trigger['lastEvent']['clock'])
event_time = datetime.fromtimestamp(event_time_epoch, tz=moskva_tz)
- # Проверяем, не старше ли событие чем на сутки
- if event_time < one_day_ago:
- continue
-
- description = trigger['description']
+ description = escape_telegram_chars(trigger['description'])
host = trigger['hosts'][0]['name']
priority = priority_map.get(trigger['priority'], 'Неизвестно')
-
- # Генерация ссылки на график
+ # Получаем itemids
item_ids = [item['itemid'] for item in trigger['items']]
- graph_links = []
- for item_id in item_ids:
- graph_link = f'Ссылка на график'
- graph_links.append(graph_link)
- graph_links_str = "\n".join(graph_links)
+
+ telebot.logger.info(f"Trigger {trigger['triggerid']} on host {host} has itemids: {item_ids}")
+
+ # Формируем ссылку для batchgraph
+ batchgraph_link = f"{ZABBIX_URL}/history.php?action=batchgraph&"
+ batchgraph_link += "&".join([f"itemids[{item_id}]={item_id}" for item_id in item_ids])
+ batchgraph_link += "&graphtype=0"
# Заменяем {HOST.NAME} на имя хоста
description = description.replace("{HOST.NAME}", host)
@@ -1228,21 +1508,16 @@ def get_zabbix_triggers(group_id):
f"Критичность: {priority}\n"
f"Описание: {description}\n"
f"Время создания: {event_time_formatted}\n"
- f"{graph_links_str}")
+ # f"ItemIDs: {', '.join(item_ids)}\n"
+ f'URL: Ссылка на график')
trigger_messages.append(message)
return trigger_messages
except Exception as e:
- telebot.logger.error(f"Error connecting to Zabbix API: {e}")
+ telebot.logger.error(f"Error fetching triggers for group {group_id}: {e}")
return None
-
-async def send_group_messages(chat_id, messages):
- for message in messages:
- await send_message(chat_id, message, is_notification=True)
- await asyncio.sleep(1) # Delay between messages to comply with rate limit
-
# Test functions for admin
def simulate_event(message):
chat_id = message.chat.id
@@ -1255,7 +1530,6 @@ def simulate_event(message):
"status": "Авария!"
}
-
app.logger.info(f"Simulating event: {test_event}")
# Use requests to simulate a POST request
response = requests.post('http://localhost:5000/webhook', json=test_event)
@@ -1279,7 +1553,8 @@ def simulate_triggers(message):
def run_polling():
- bot.polling(non_stop=True, interval=0)
+ bot.infinity_polling(timeout=10, long_polling_timeout = 5)
+
# Запуск Flask-приложения
def run_flask():
@@ -1293,11 +1568,11 @@ def schedule_jobs():
schedule.run_pending()
time.sleep(60) # Проверять раз в минуту
+
# Основная функция для запуска
def main():
# Инициализация базы данных
init_db()
- print('Bootstrap wait...')
# Запуск Flask и бота в отдельных потоках
Thread(target=run_flask, daemon=True).start()
@@ -1307,6 +1582,6 @@ def main():
# Запуск асинхронных задач
asyncio.run(consume_from_queue())
-if __name__ == '__main__':
- main()
+if __name__ == '__main__':
+ main()
\ No newline at end of file