additions and corrections for

deployment instructions
This commit is contained in:
2025-09-04 16:45:29 +00:00
parent 86b1bdbd91
commit 76629b8e30
23 changed files with 561 additions and 57 deletions

View File

@@ -13,7 +13,7 @@ RUN apt-get update \
&& rm -rf /var/lib/apt/lists/*
# Kopiert nur die requirements.txt, um den Docker-Cache optimal zu nutzen
COPY requirements.txt .
COPY /server/requirements.txt .
# Installiert die Python-Pakete in ein separates Verzeichnis
RUN pip install --no-cache-dir --prefix="/install" -r requirements.txt
@@ -27,7 +27,7 @@ WORKDIR /app
# Installiert nur die für die Laufzeit notwendigen Systemabhängigkeiten
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
libmariadb-dev-compat locales \
libmariadb-dev-compat locales curl \
&& rm -rf /var/lib/apt/lists/*
# --- Locale konfigurieren ---
@@ -41,7 +41,8 @@ COPY --from=builder /install /usr/local
# --- Applikationscode ---
# Kopiert den Server-Code in das Arbeitsverzeichnis
COPY server/ .
COPY server/ ./server
COPY models/ ./models
# --- Non-Root User anlegen und Rechte setzen ---
ARG USER_ID=1000
@@ -56,5 +57,5 @@ USER infoscreen_taa
EXPOSE 8000
# --- Startbefehl für Gunicorn ---
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8000", "wsgi:app"]
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8000", "server.wsgi:app"]

View File

@@ -1,5 +1,10 @@
# isort: skip_file
from alembic import context
from sqlalchemy import pool
from sqlalchemy import engine_from_config
from logging.config import fileConfig
from dotenv import load_dotenv
from models.models import Base
import os
import sys
sys.path.insert(0, '/workspace')
@@ -8,12 +13,6 @@ print("models dir exists:", os.path.isdir('/workspace/models'))
print("models/models.py exists:", os.path.isfile('/workspace/models/models.py'))
print("models/__init__.py exists:",
os.path.isfile('/workspace/models/__init__.py'))
from models.models import Base
from dotenv import load_dotenv
from logging.config import fileConfig
from sqlalchemy import engine_from_config
from sqlalchemy import pool
from alembic import context
print("sys.path:", sys.path)
print("models dir exists:", os.path.isdir('/workspace/models'))
@@ -27,12 +26,17 @@ env_path = os.path.abspath(os.path.join(
print(f"Loading environment variables from: {env_path}")
load_dotenv(env_path)
# Datenbank-Zugangsdaten aus .env
DB_USER = os.getenv("DB_USER")
DB_PASSWORD = os.getenv("DB_PASSWORD")
DB_HOST = os.getenv("DB_HOST", "localhost")
DB_PORT = os.getenv("DB_PORT", "3306")
DB_NAME = os.getenv("DB_NAME")
DB_CONN = os.getenv("DB_CONN")
if DB_CONN:
DATABASE_URL = DB_CONN
else:
# Datenbank-Zugangsdaten aus .env
DB_USER = os.getenv("DB_USER")
DB_PASSWORD = os.getenv("DB_PASSWORD")
DB_HOST = os.getenv("DB_HOST", "db") # Default jetzt 'db'
DB_PORT = os.getenv("DB_PORT", "3306")
DB_NAME = os.getenv("DB_NAME")
DATABASE_URL = f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
@@ -43,10 +47,6 @@ config = context.config
if config.config_file_name is not None:
fileConfig(config.config_file_name)
DATABASE_URL = (
f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
)
print(f"Using DATABASE_URL: {DATABASE_URL}")
config.set_main_option("sqlalchemy.url", DATABASE_URL)

View File

@@ -1,14 +1,23 @@
import os
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from dotenv import load_dotenv
import os
# Umgebungsvariablen
DB_USER = os.getenv("DB_USER", "infoscreen_admin")
DB_PASSWORD = os.getenv("DB_PASSWORD", "KqtpM7wmNd&mFKs")
DB_HOST = os.getenv("DB_HOST", "db")
DB_NAME = os.getenv("DB_NAME", "infoscreen_by_taa")
# Nur im Dev-Modus .env laden
if os.getenv("ENV", "development") == "development":
load_dotenv(dotenv_path=os.path.join(
os.path.dirname(__file__), '..', '.env'))
# Prod: DB_CONN direkt aus Umgebungsvariable (von Compose gesetzt)
DB_URL = os.getenv("DB_CONN")
if not DB_URL:
# Dev: DB-URL aus Einzelwerten bauen
DB_USER = os.getenv("DB_USER", "infoscreen_admin")
DB_PASSWORD = os.getenv("DB_PASSWORD", "KqtpM7wmNd&mFKs")
DB_HOST = os.getenv("DB_HOST", "db") # IMMER 'db' als Host im Container!
DB_NAME = os.getenv("DB_NAME", "infoscreen_by_taa")
DB_URL = f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}/{DB_NAME}"
DB_URL = f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}/{DB_NAME}"
print(f"Using DB_URL: {DB_URL}") # Debug-Ausgabe
engine = create_engine(DB_URL, echo=False)
Session = sessionmaker(bind=engine)

38
server/init_defaults.py Normal file
View File

@@ -0,0 +1,38 @@
from sqlalchemy import create_engine, text
import os
from dotenv import load_dotenv
import bcrypt
# .env laden
load_dotenv()
DB_URL = f"mysql+pymysql://{os.getenv('DB_USER')}:{os.getenv('DB_PASSWORD')}@{os.getenv('DB_HOST')}:3306/{os.getenv('DB_NAME')}"
engine = create_engine(DB_URL, isolation_level="AUTOCOMMIT")
with engine.connect() as conn:
# Default-Gruppe mit id=1 anlegen, falls nicht vorhanden
result = conn.execute(
text("SELECT COUNT(*) FROM client_groups WHERE id=1"))
if result.scalar() == 0:
conn.execute(
text(
"INSERT INTO client_groups (id, name, is_active) VALUES (1, 'Nicht zugeordnet', 1)")
)
print("✅ Default-Gruppe mit id=1 angelegt.")
# Admin-Benutzer anlegen, falls nicht vorhanden
admin_user = os.getenv("DEFAULT_ADMIN_USERNAME", "infoscreen_admin")
admin_pw = os.getenv("DEFAULT_ADMIN_PASSWORD", "Info_screen_admin25!")
# Passwort hashen wie in init_db.py
hashed_pw = bcrypt.hashpw(admin_pw.encode(
'utf-8'), bcrypt.gensalt()).decode('utf-8')
# Prüfen, ob User existiert
result = conn.execute(text(
"SELECT COUNT(*) FROM users WHERE username=:username"), {"username": admin_user})
if result.scalar() == 0:
# Rolle: 1 = Admin (ggf. anpassen je nach Modell)
conn.execute(
text("INSERT INTO users (username, password_hash, role, is_active) VALUES (:username, :password_hash, 1, 1)"),
{"username": admin_user, "password_hash": hashed_pw}
)
print(f"✅ Admin-Benutzer '{admin_user}' angelegt.")

View File

@@ -5,3 +5,4 @@ PyMySQL>=1.1.1
python-dotenv>=1.1.0
SQLAlchemy>=2.0.41
flask
gunicorn

View File

@@ -1,4 +1,4 @@
from database import Session
from server.database import Session
from models.models import Client, ClientGroup
from flask import Blueprint, request, jsonify
import sys

View File

@@ -1,6 +1,6 @@
from re import A
from flask import Blueprint, request, jsonify, send_from_directory
from database import Session
from server.database import Session
from models.models import EventMedia, MediaType
import os

View File

@@ -1,5 +1,5 @@
from flask import Blueprint, request, jsonify
from database import Session
from server.database import Session
from models.models import Event, EventMedia, MediaType
from datetime import datetime, timezone
from sqlalchemy import and_

View File

@@ -1,7 +1,7 @@
from models.models import Client
# Neue Route: Liefert alle Gruppen mit zugehörigen Clients und deren Alive-Status
from database import Session
from server.database import Session
from models.models import ClientGroup
from flask import Blueprint, request, jsonify
from sqlalchemy import func

View File

@@ -3,7 +3,7 @@ from server.routes.eventmedia import eventmedia_bp
from server.routes.events import events_bp
from server.routes.groups import groups_bp
from server.routes.clients import clients_bp
from database import Session, engine
from server.database import Session, engine
from flask import Flask, jsonify, send_from_directory, request
import glob
import os