Files
olaper/app.py
SERTY 38f35d1915
All checks were successful
Test Build / test-build (push) Successful in 2s
fix old config format
2025-07-30 19:17:16 +03:00

118 lines
5.1 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__)
# --- Конфигурация приложения ---
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
all_configs = UserConfig.query.all()
for config in all_configs:
user_id = config.user_id
mappings = config.mappings
for sheer_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_{sheer_title}"
try:
scheduler.add_job(
id=job_id,
func=execute_olap_export,
trigger='cron',
args=[user_id, sheer_title],
**_parse_cron_string(cron_schedule)
)
app.logger.info(f"Job {job_id} loaded on startup.")
except Exception as e:
app.logger.error(f"Failed to load job {job_id}: {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()
# --- Вспомогательная функция для парсинга cron ---
def _parse_cron_string(cron_str):
"""Парсит строку cron в словарь для APScheduler."""
parts = cron_str.split()
if len(parts) != 5:
raise ValueError("Invalid cron string format. Expected 5 parts.")
keys = ['minute', 'hour', 'day', 'month', 'day_of_week']
return {keys[i]: part for i, part in enumerate(parts)}
if __name__ == '__main__':
# Для прямого запуска через `python app.py` (удобно для отладки)
app.run(host='0.0.0.0', port=int(os.environ.get("PORT", 5005)))