146 lines
5.9 KiB
Python
146 lines
5.9 KiB
Python
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}")
|