import os import logging from flask import Flask from flask_sqlalchemy import SQLAlchemy from sqlalchemy import text from config import Config logger = logging.getLogger(__name__) db = SQLAlchemy() def create_app(config_class=Config): app = Flask(__name__) app.config.from_object(config_class) # Ensure upload directories exist os.makedirs(app.config["PHOTO_FOLDER"], exist_ok=True) os.makedirs(app.config["QR_FOLDER"], exist_ok=True) os.makedirs(app.config["LOGO_FOLDER"], exist_ok=True) os.makedirs(os.path.dirname(app.config["SQLALCHEMY_DATABASE_URI"].replace("sqlite:///", "")), exist_ok=True) db.init_app(app) from app.routes import main_bp app.register_blueprint(main_bp) with app.app_context(): db.create_all() _migrate_existing_data(app) _create_default_users(app) return app def _column_exists(table_name, column_name): return db.session.execute( text(f"SELECT COUNT(*) FROM pragma_table_info('{table_name}') WHERE name='{column_name}'") ).scalar() def _add_column_if_missing(table_name, column_name, column_def): if not _column_exists(table_name, column_name): db.session.execute(text(f"ALTER TABLE {table_name} ADD COLUMN {column_name} {column_def}")) def _migrate_existing_data(app): """Миграция существующих гостей в дефолтное мероприятие и добавление новых колонок.""" from app.models import Event, Guest try: # Добавляем колонки дизайна билета в таблицу events _add_column_if_missing("events", "ticket_title", "VARCHAR(255)") _add_column_if_missing("events", "ticket_subtitle", "VARCHAR(255)") _add_column_if_missing("events", "ticket_body_text", "TEXT") _add_column_if_missing("events", "ticket_background_color", "VARCHAR(7) DEFAULT '#ffffff'") _add_column_if_missing("events", "ticket_text_color", "VARCHAR(7) DEFAULT '#000000'") _add_column_if_missing("events", "ticket_accent_color", "VARCHAR(7) DEFAULT '#0d6efd'") _add_column_if_missing("events", "ticket_show_qr", "BOOLEAN DEFAULT 1") _add_column_if_missing("events", "ticket_show_photo", "BOOLEAN DEFAULT 0") _add_column_if_missing("events", "ticket_layout", "VARCHAR(20) DEFAULT 'portrait'") _add_column_if_missing("events", "logo_filename", "VARCHAR(255)") # Добавляем колонки ФИО/телефона в таблицу guests _add_column_if_missing("guests", "last_name", "VARCHAR(255)") _add_column_if_missing("guests", "first_name", "VARCHAR(255)") _add_column_if_missing("guests", "middle_name", "VARCHAR(255)") _add_column_if_missing("guests", "phone", "VARCHAR(50)") # Проверяем, есть ли колонка event_id в таблице guests if _column_exists("guests", "event_id"): db.session.commit() return # Миграция гостей уже выполнена # Создаём дефолтное мероприятие для существующих гостей default_event = Event( name=app.config.get("DEFAULT_EVENT_NAME", "Архивное мероприятие"), description="Автоматически созданное мероприятие для существующих гостей", is_active=True, ) db.session.add(default_event) db.session.flush() # Добавляем колонку event_id db.session.execute(text("ALTER TABLE guests ADD COLUMN event_id INTEGER REFERENCES events(id)")) # Привязываем всех существующих гостей к дефолтному мероприятию db.session.execute( text("UPDATE guests SET event_id = :event_id"), {"event_id": default_event.id}, ) # Добавляем колонку event_id в check_ins (опционально) if not _column_exists("check_ins", "event_id"): db.session.execute(text("ALTER TABLE check_ins ADD COLUMN event_id INTEGER REFERENCES events(id)")) db.session.execute( text(""" UPDATE check_ins SET event_id = ( SELECT event_id FROM guests WHERE guests.id = check_ins.guest_id ) """) ) db.session.commit() logger.info(f"Migration completed: existing guests moved to event '{default_event.name}' (id={default_event.id})") except Exception as e: db.session.rollback() logger.warning(f"Migration skipped or failed: {e}") def _create_default_users(app): """Создание начальных пользователей, если в базе нет ни одного.""" from app.models import User try: if User.query.first() is not None: return admin = User( username=app.config.get("ADMIN_USERNAME", "admin"), role="admin", is_active=True, ) admin.set_password(app.config.get("ADMIN_PASSWORD", "admin")) staff = User( username=app.config.get("STAFF_USERNAME", "staff"), role="staff", is_active=True, ) staff.set_password(app.config.get("STAFF_PASSWORD", "staff")) db.session.add(admin) db.session.add(staff) db.session.commit() if app.config.get("ADMIN_PASSWORD") == "admin" or app.config.get("STAFF_PASSWORD") == "staff": logger.warning("Default users created with default passwords. Change them in production!") else: logger.info("Default users 'admin' and 'staff' created from environment variables.") except Exception as e: db.session.rollback() logger.warning(f"Default users creation skipped or failed: {e}")