153 lines
7.4 KiB
Python
153 lines
7.4 KiB
Python
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
|
||
|