-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
128 lines (102 loc) · 4.09 KB
/
app.py
File metadata and controls
128 lines (102 loc) · 4.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
from flask import Flask
from decimal import Decimal
import os
import logging
from logging.handlers import RotatingFileHandler
from pathlib import Path
from db import init_engine_and_session, init_db, close_db
from blueprints.main import main_bp
from blueprints.games import games_bp
from blueprints.members import members_bp
def _resolve_database_url() -> str:
"""
Bevorzugt genau EINE Variable:
- DATABASE_URI
Optional zur Kompatibilität:
- DATABASE_URL
Fallback: sqlite in ./data/database.db (im Container: /app/data, gemountet auf /data)
"""
env_url = os.getenv("DATABASE_URI") or os.getenv("DATABASE_URL")
if env_url:
return env_url
# Default (relativ -> /app/data/database.db; Dockerfile mountet /data als Volume)
return "sqlite:///data/database.db"
def _ensure_sqlite_directory(db_url: str) -> None:
"""
Legt bei SQLite-URLs das Zielverzeichnis an (falls nicht vorhanden).
Unterstützt absolute Pfade (sqlite:////...) und relative (sqlite:///...).
"""
if not db_url.startswith("sqlite:"):
return
# Strip schema
path_part = db_url[len("sqlite:"):].lstrip("/")
# Bei '////ABS' ergibt lstrip('/') -> 'ABS'; wir brauchen den führenden Slash zurück.
if db_url.startswith("sqlite:////"):
fs_path = "/" + path_part # absolut
elif db_url.startswith("sqlite:///"):
# relativ zum Working Directory (systemd/Container: /app)
fs_path = os.path.abspath(path_part)
else:
# andere Formen (z. B. sqlite://) ignorieren
return
# Ordner anlegen
dir_path = Path(fs_path).parent
dir_path.mkdir(parents=True, exist_ok=True)
def _configure_logging(app: Flask) -> None:
"""
Optionales File-Logging für App-Logs.
Gunicorn-Access/Error-Logs werden durch die Service-Parameter geschrieben.
Setze LOG_DIR, um app.log zu aktivieren.
"""
log_dir = os.getenv("LOG_DIR")
if not log_dir:
return
Path(log_dir).mkdir(parents=True, exist_ok=True)
log_file = Path(log_dir) / "app.log"
handler = RotatingFileHandler(log_file, maxBytes=1_000_000, backupCount=3)
handler.setLevel(logging.INFO)
formatter = logging.Formatter("%(asctime)s %(levelname)s [%(name)s] %(message)s")
handler.setFormatter(formatter)
app.logger.setLevel(logging.INFO)
app.logger.addHandler(handler)
# Werkzeug/Request-Logger ebenfalls auf File führen (optional)
logging.getLogger("werkzeug").setLevel(logging.INFO)
logging.getLogger("werkzeug").addHandler(handler)
def create_app():
app = Flask(__name__)
# Geheimnis aus ENV (sonst Default)
app.config["SECRET_KEY"] = os.getenv("SECRET_KEY", "dev-secret-change-me")
# Datenbank-URL auflösen & ggf. Verzeichnis anlegen
db_url = _resolve_database_url()
_ensure_sqlite_directory(db_url)
# Einheitlich nur noch DATABASE_URI in der App führen
app.config["DATABASE_URI"] = db_url
# DB initialisieren
init_engine_and_session(app.config["DATABASE_URI"])
init_db()
app.teardown_appcontext(close_db)
# Optionales File-Logging (ergänzend zu Gunicorn-Logs)
_configure_logging(app)
# Healthcheck-Endpoint (für Docker HEALTHCHECK)
@app.get("/healthz")
def healthz():
return {"status": "ok"}, 200
# Jinja-Filter: Geldformat (2 Nachkommastellen)
@app.template_filter("money")
def money_filter(value):
try:
return f"{Decimal(value):.2f}"
except Exception:
return str(value)
# Blueprints
app.register_blueprint(main_bp)
app.register_blueprint(games_bp, url_prefix="/games")
app.register_blueprint(members_bp, url_prefix="/members")
return app
app = create_app()
if __name__ == "__main__":
# Lokaler Dev-Server (für Entwicklung). Im Deployment übernimmt Gunicorn.
host = os.getenv("FLASK_RUN_HOST", "0.0.0.0")
port = int(os.getenv("FLASK_RUN_PORT", "8000"))
debug = os.getenv("FLASK_DEBUG", "0") == "1"
app.run(host=host, port=port, debug=debug)