Files
nouri-App/nouri/__init__.py
T

121 lines
4.2 KiB
Python

from __future__ import annotations
import os
import secrets
from datetime import date, timedelta
from pathlib import Path
from flask import Flask, g, send_from_directory
from . import db
from .admin import admin_bp
from .auth import auth_bp
from .constants import (
BUILDER_DESCRIPTIONS,
BUILDER_LABELS,
BUILDER_OPTIONS,
DAYPARTS,
DEFAULT_CATEGORIES,
ITEM_KIND_LABELS,
ITEM_KIND_SINGULAR_LABELS,
NOTIFICATION_CHANNEL_OPTIONS,
ROLE_LABELS,
VISIBILITY_DESCRIPTIONS,
VISIBILITY_LABELS,
WEEKDAY_OPTIONS,
)
from .main import main_bp
WEEKDAY_NAMES = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"]
WEEKDAY_SHORT_NAMES = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
def load_secret_key(data_dir: Path) -> str:
env_secret = os.environ.get("NOURI_SECRET_KEY")
if env_secret:
return env_secret
secret_path = data_dir / ".secret_key"
if secret_path.exists():
return secret_path.read_text(encoding="utf-8").strip()
secret_value = secrets.token_hex(24)
try:
with secret_path.open("x", encoding="utf-8") as handle:
handle.write(secret_value)
except FileExistsError:
return secret_path.read_text(encoding="utf-8").strip()
return secret_value
def create_app() -> Flask:
root_dir = Path(__file__).resolve().parent.parent
data_dir = Path(os.environ.get("NOURI_DATA_DIR", root_dir / "data")).resolve()
upload_dir = data_dir / "uploads"
db_path = data_dir / "nouri.sqlite3"
data_dir.mkdir(parents=True, exist_ok=True)
upload_dir.mkdir(parents=True, exist_ok=True)
app = Flask(__name__, instance_relative_config=False)
app.config.update(
SECRET_KEY=load_secret_key(data_dir),
DATABASE_PATH=str(db_path),
DATA_DIR=str(data_dir),
UPLOAD_FOLDER=str(upload_dir),
MAX_CONTENT_LENGTH=int(os.environ.get("NOURI_MAX_UPLOAD_MB", "5")) * 1024 * 1024,
PERMANENT_SESSION_LIFETIME=timedelta(days=30),
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE="Lax",
APP_VERSION="0.5.0",
VAPID_PUBLIC_KEY=os.environ.get("NOURI_VAPID_PUBLIC_KEY", ""),
VAPID_PRIVATE_KEY=os.environ.get("NOURI_VAPID_PRIVATE_KEY", ""),
VAPID_SUBJECT=os.environ.get("NOURI_VAPID_SUBJECT", "mailto:mail@hnz.io"),
)
db.init_app(app)
db.init_db_if_needed(app)
app.register_blueprint(auth_bp)
app.register_blueprint(admin_bp)
app.register_blueprint(main_bp)
@app.context_processor
def inject_globals() -> dict[str, object]:
return {
"item_kind_labels": ITEM_KIND_LABELS,
"item_kind_singular_labels": ITEM_KIND_SINGULAR_LABELS,
"category_suggestions": DEFAULT_CATEGORIES,
"builder_labels": BUILDER_LABELS,
"builder_descriptions": BUILDER_DESCRIPTIONS,
"builder_options": BUILDER_OPTIONS,
"daypart_suggestions": DAYPARTS,
"visibility_labels": VISIBILITY_LABELS,
"visibility_descriptions": VISIBILITY_DESCRIPTIONS,
"role_labels": ROLE_LABELS,
"weekday_options": WEEKDAY_OPTIONS,
"notification_channel_options": NOTIFICATION_CHANNEL_OPTIONS,
"today": date.today(),
"app_version": app.config["APP_VERSION"],
"push_public_key": app.config["VAPID_PUBLIC_KEY"],
"push_available": bool(app.config["VAPID_PUBLIC_KEY"] and app.config["VAPID_PRIVATE_KEY"]),
"weekday_name": lambda value: WEEKDAY_NAMES[value.weekday()],
"weekday_short_name": lambda value: WEEKDAY_SHORT_NAMES[value.weekday()],
"is_admin": lambda: bool(getattr(g, "user", None)) and g.user["role"] == "admin",
}
@app.get("/uploads/<path:filename>")
def uploaded_file(filename: str):
return send_from_directory(app.config["UPLOAD_FOLDER"], filename)
@app.get("/app.webmanifest")
def webmanifest():
return send_from_directory(root_dir / "nouri" / "static" / "pwa", "app.webmanifest", mimetype="application/manifest+json")
@app.get("/service-worker.js")
def service_worker():
return send_from_directory(root_dir / "nouri" / "static" / "pwa", "service-worker.js", mimetype="application/javascript")
return app