import logging import sqlite3 from flask import Flask, request, jsonify, redirect, url_for from flask_login import LoginManager import config from frontend.dashboard import bp_dashboard from backend.api import bp_api from backend.auth import bp_auth, User from backend_locks import db_lock from config import DB_PATH, TZ from utilities.database import db from utilities.telegram_utilities import extract_region_number, format_message login_manager = LoginManager() def create_app(): app = Flask(__name__, static_url_path='/telezab/static', template_folder='templates') app.config['SECRET_KEY'] = config.SECRET_KEY # Замените на надежный секретный ключ app.config['SESSION_COOKIE_SECURE'] = config.SESSION_COOKIE_SECURE # Убедитесь, что установлено значение True app.config['SESSION_COOKIE_HTTPONLY'] = config.SESSION_COOKIE_HTTPONLY # Убедитесь, что установлено значение True app.config['SESSION_COOKIE_SAMESITE'] = config.SESSION_COOKIE_SAMESITE app.config['SESSION_REFRESH_EACH_REQUEST'] = False app.config['PERMANENT_SESSION_LIFETIME'] = config.PERMANENT_SESSION_LIFETIME app.config['SESSION_COOKIE_MAX_AGE'] = 3600 app.config['TIMEZONE'] = TZ @login_manager.unauthorized_handler def unauthorized(): logging.debug("Unauthorized access detected") if request.path.startswith('/telezab/rest/api'): return jsonify({'error': 'Не авторизован'}), 401 else: return redirect(url_for('auth.login')) app.register_blueprint(bp_dashboard) app.register_blueprint(bp_auth) app.register_blueprint(bp_api) app.config['SQLALCHEMY_DATABASE_URI'] = config.SQLALCHEMY_DATABASE_URI app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db.init_app(app) with app.app_context(): db.create_all() login_manager.init_app(app) # Инициализация login_manager @login_manager.user_loader def load_user(user_id): return User(user_id) return app app = create_app() @app.route('/telezab/webhook', methods=['POST']) def webhook(): try: # Получаем данные и логируем data = request.get_json() app.logger.info(f"Получены данные: {data}") # Работа с базой данных в блоке синхронизации with db_lock: conn = sqlite3.connect(DB_PATH) cursor = conn.cursor() # Проверяем количество записей в таблице событий cursor.execute('SELECT COUNT(*) FROM events') count = cursor.fetchone()[0] app.logger.debug(f"Текущее количество записей в таблице events: {count}") # Если записей >= 200, удаляем самое старое событие if count >= 200: query = 'DELETE FROM events WHERE id = (SELECT MIN(id) FROM events)' app.logger.debug(f"Удаление старого события: {query}") cursor.execute(query) # Извлечение номера региона из поля host region_id = extract_region_number(data.get("host")) if region_id is None: app.logger.error(f"Не удалось извлечь номер региона из host: {data.get('host')}") return jsonify({"status": "error", "message": "Invalid host format"}), 400 app.logger.debug(f"Извлечён номер региона: {region_id}") # Запрос подписчиков для отправки уведомления в зависимости от уровня критичности if data['severity'] == 'Disaster': # Авария 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"Выполнение запроса: {query} для region_id={region_id}") cursor.execute(query, (region_id,)) results = cursor.fetchall() app.logger.debug(f"Найдено подписчиков: {len(results)} для региона {region_id}") # Проверка статуса региона (активен или нет) query = 'SELECT active FROM regions WHERE region_id = ?' cursor.execute(query, (region_id,)) region_row = cursor.fetchone() if region_row and region_row[0]: # Если регион активен app.logger.debug(f"Регион {region_id} активен. Начинаем рассылку сообщений.") message = format_message(data) undelivered = False # Отправляем сообщения подписчикам for chat_id, username in results: formatted_message = message.replace('\n', ' ').replace('\r', '') app.logger.info( f"Формирование сообщения для пользователя {username} (chat_id={chat_id}) [{formatted_message}]") try: from utilities.rabbitmq import send_to_queue send_to_queue({'chat_id': chat_id, 'username': username, 'message': message}) app.logger.debug(f"Сообщение поставлено в очередь для {chat_id} (@{username})") except Exception as e: app.logger.error(f"Ошибка при отправке сообщения для {chat_id} (@{username}): {e}") undelivered = True # Сохранение события, если были проблемы с доставкой if undelivered: query = 'INSERT OR IGNORE INTO events (hash, data, delivered) VALUES (?, ?, ?)' app.logger.debug( f"Сохранение события в базе данных: {query} (delivered={False})") cursor.execute(query, (str(data), False)) # Коммитим изменения в базе данных conn.commit() app.logger.debug("Изменения в базе данных успешно сохранены.") conn.close() # Возвращаем успешный ответ return jsonify({"status": "success"}), 200 except sqlite3.OperationalError as e: app.logger.error(f"Ошибка операции с базой данных: {e}") return jsonify({"status": "error", "message": "Ошибка работы с базой данных"}), 500 except ValueError as e: app.logger.error(f"Ошибка значения: {e}") return jsonify({"status": "error", "message": "Некорректные данные"}), 400 except Exception as e: app.logger.error(f"Неожиданная ошибка: {e}") return jsonify({"status": "error", "message": "Внутренняя ошибка сервера"}), 500