85 lines
2.7 KiB
Python
85 lines
2.7 KiB
Python
"""App-Factory für den Projekt-Hub.
|
|
|
|
Erzeugt die Flask-App, lädt die Config, bindet die Extensions und registriert
|
|
die Blueprints der einzelnen Mini-App-Module. Jedes neue Modul wird hier per
|
|
register_blueprint(...) eingebunden und über die zentrale Navigations-Registry
|
|
in der Navigation sichtbar gemacht — Kern bleibt unangetastet.
|
|
"""
|
|
|
|
import os
|
|
|
|
from flask import Flask, redirect, url_for
|
|
|
|
from .config import get_config
|
|
from .extensions import db, migrate, login_manager, mail, limiter, csrf
|
|
|
|
|
|
# --- Zentrale Navigations-Registry ---------------------------------------
|
|
# Jedes Modul trägt hier einen Eintrag bei (Label, Endpoint, Icon). base.html
|
|
# rendert daraus die gemeinsame Navigation. Neues Modul = neuer Eintrag.
|
|
NAV_MODULES = [
|
|
{"label": "Projekte", "endpoint": "projects.index", "icon": "📁"},
|
|
]
|
|
|
|
|
|
def create_app(config_name: str | None = None) -> Flask:
|
|
app = Flask(
|
|
__name__,
|
|
instance_relative_config=True,
|
|
instance_path=os.path.join(os.path.dirname(os.path.dirname(__file__)), "instance"),
|
|
)
|
|
app.config.from_object(get_config(config_name))
|
|
|
|
# instance/-Ordner sicherstellen (SQLite-Datei landet hier).
|
|
os.makedirs(app.instance_path, exist_ok=True)
|
|
|
|
# Relativen sqlite-Pfad in den instance/-Ordner umbiegen.
|
|
uri = app.config.get("SQLALCHEMY_DATABASE_URI", "")
|
|
if uri.startswith("sqlite:///") and not uri.startswith("sqlite:////"):
|
|
db_name = uri.replace("sqlite:///", "", 1)
|
|
abs_path = os.path.join(app.instance_path, db_name)
|
|
app.config["SQLALCHEMY_DATABASE_URI"] = f"sqlite:///{abs_path}"
|
|
|
|
_init_extensions(app)
|
|
_register_blueprints(app)
|
|
_register_context(app)
|
|
|
|
@app.route("/")
|
|
def index():
|
|
return redirect(url_for("projects.index"))
|
|
|
|
return app
|
|
|
|
|
|
def _init_extensions(app: Flask) -> None:
|
|
db.init_app(app)
|
|
migrate.init_app(app, db)
|
|
login_manager.init_app(app)
|
|
mail.init_app(app)
|
|
limiter.init_app(app)
|
|
csrf.init_app(app)
|
|
|
|
# Modelle importieren, damit SQLAlchemy/Alembic sie kennen (Autogenerate).
|
|
from . import models # noqa: F401
|
|
from .projects import models as project_models # noqa: F401
|
|
|
|
from .models import User
|
|
|
|
@login_manager.user_loader
|
|
def load_user(user_id):
|
|
return db.session.get(User, int(user_id))
|
|
|
|
|
|
def _register_blueprints(app: Flask) -> None:
|
|
from .auth import bp as auth_bp
|
|
from .projects import bp as projects_bp
|
|
|
|
app.register_blueprint(auth_bp)
|
|
app.register_blueprint(projects_bp)
|
|
|
|
|
|
def _register_context(app: Flask) -> None:
|
|
@app.context_processor
|
|
def inject_nav():
|
|
# Navigations-Registry in allen Templates verfügbar machen.
|
|
return {"nav_modules": NAV_MODULES}
|