Files
olaper/app.py
SERTY 0a17b31c06
All checks were successful
Test Build / test-build (push) Successful in 25s
added scheduler v2
2025-07-31 03:50:08 +03:00

138 lines
6.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
from flask import Flask, session, request
from sqlalchemy import inspect
from dotenv import load_dotenv
# 1. Загрузка переменных окружения - в самом верху
load_dotenv()
# 2. Импорт расширений из центрального файла
from extensions import scheduler, db, migrate, login_manager, babel
from models import init_encryption
# 3. Фабрика приложений
def create_app():
"""
Создает и конфигурирует экземпляр Flask приложения.
"""
app = Flask(__name__)
if not app.debug:
import logging
from logging.handlers import RotatingFileHandler
# Создаем папку для логов, если ее нет
log_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'data')
os.makedirs(log_dir, exist_ok=True)
log_file = os.path.join(log_dir, 'olaper.log')
# Создаем обработчик, который пишет логи в файл с ротацией
# 10 МБ на файл, храним 5 старых файлов
file_handler = RotatingFileHandler(log_file, maxBytes=1024*1024*10, backupCount=5, encoding='utf-8')
# Устанавливаем формат сообщений
file_handler.setFormatter(logging.Formatter(
'%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
))
# Устанавливаем уровень логирования
file_handler.setLevel(logging.INFO)
# Добавляем обработчик к логгеру приложения
app.logger.addHandler(file_handler)
app.logger.setLevel(logging.INFO)
app.logger.info('Application startup')
# --- Конфигурация приложения ---
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'default-super-secret-key-for-dev')
# --- НАДЕЖНАЯ НАСТРОЙКА ПУТЕЙ ---
# Получаем абсолютный путь к директории, где находится app.py
basedir = os.path.abspath(os.path.dirname(__file__))
# Устанавливаем путь к папке data
data_dir = os.path.join(basedir, os.environ.get('DATA_DIR', 'data'))
# Создаем эту директорию, если ее не существует. Это ключевой момент.
os.makedirs(data_dir, exist_ok=True)
app.config['DATA_DIR'] = data_dir
# Устанавливаем путь к БД
db_path = os.path.join(data_dir, 'app.db')
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL', f"sqlite:///{db_path}")
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['BABEL_DEFAULT_LOCALE'] = 'ru'
app.config['ENCRYPTION_KEY'] = os.environ.get('ENCRYPTION_KEY')
# --- Определяем селектор языка ---
def get_locale():
if 'language' in session:
return session['language']
return request.accept_languages.best_match(['ru', 'en'])
# --- Инициализация расширений с приложением ---
db.init_app(app)
migrate.init_app(app, db)
login_manager.init_app(app)
babel.init_app(app, locale_selector=get_locale)
scheduler.init_app(app)
init_encryption(app)
# --- Регистрация блюпринтов ---
from routes import main_bp, execute_olap_export
app.register_blueprint(main_bp)
login_manager.login_view = 'main.login'
login_manager.login_message = "Пожалуйста, войдите, чтобы получить доступ к этой странице."
login_manager.login_message_category = "info"
with app.app_context():
if inspect(db.engine).has_table('user_config'):
from models import User, UserConfig
from utils import _parse_cron_string
all_configs = UserConfig.query.all()
for config in all_configs:
user_id = config.user_id
mappings = config.mappings
for sheet_title, params in mappings.items():
if isinstance(params, dict):
cron_schedule = params.get('schedule_cron')
if cron_schedule:
job_id = f"user_{user_id}_sheet_{sheet_title}"
try:
if not scheduler.get_job(job_id):
scheduler.add_job(
id=job_id,
func=execute_olap_export,
trigger='cron',
args=[app, user_id, sheet_title],
**_parse_cron_string(cron_schedule)
)
app.logger.info(f"Scheduled job loaded on startup: {job_id} with schedule '{cron_schedule}'")
except Exception as e:
app.logger.error(f"Failed to load job {job_id} with schedule '{cron_schedule}': {e}")
else:
app.logger.warning("Database tables not found. Skipping job loading on startup. Run 'flask init-db' to create the tables.")
scheduler.start()
# --- Регистрация команд CLI ---
from models import User, UserConfig
@app.cli.command('init-db')
def init_db_command():
"""Создает или пересоздает таблицы в базе данных."""
print("Creating database tables...")
db.create_all()
print("Database tables created successfully.")
return app
# --- Точка входа для запуска ---
app = create_app()
if __name__ == '__main__':
# Для прямого запуска через `python app.py` (удобно для отладки)
app.run(host='0.0.0.0', port=int(os.environ.get("PORT", 5005)))