feat: Implementierung einer Windows-kompatiblen Timeout-Logik für Datenbankabfragen in der Druckerabfrage. Verwendung von Threads zur Vermeidung von Blockierungen und Verbesserung der Fehlerprotokollierung. Aktualisierung des Kiosk-Installationsskripts zur Installation zusätzlicher Pakete und Konfiguration des Kiosk-Modus mit Openbox für eine verbesserte Benutzererfahrung.

This commit is contained in:
Till Tomczak 2025-05-27 10:58:15 +02:00
parent f1232bf900
commit b289501d00
8 changed files with 929 additions and 24 deletions

View File

@ -0,0 +1 @@

View File

@ -1684,19 +1684,28 @@ def get_printers():
db_session = get_db_session() db_session = get_db_session()
try: try:
# Set timeout for database query # Windows-kompatible Timeout-Implementierung
import signal import threading
import time
def timeout_handler(signum, frame): printers = None
raise TimeoutError("Database query timeout") timeout_occurred = False
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(5) # 5 second timeout for basic printer loading (reduziert)
def fetch_printers():
nonlocal printers, timeout_occurred
try: try:
printers = db_session.query(Printer).all() printers = db_session.query(Printer).all()
signal.alarm(0) # Clear alarm except Exception as e:
except TimeoutError: printers_logger.error(f"Datenbankfehler beim Laden der Drucker: {str(e)}")
timeout_occurred = True
# Starte Datenbankabfrage in separatem Thread
thread = threading.Thread(target=fetch_printers)
thread.daemon = True
thread.start()
thread.join(timeout=5) # 5 Sekunden Timeout
if thread.is_alive() or timeout_occurred or printers is None:
printers_logger.warning("Database timeout when fetching printers for basic loading") printers_logger.warning("Database timeout when fetching printers for basic loading")
return jsonify({ return jsonify({
'error': 'Database timeout beim Laden der Drucker', 'error': 'Database timeout beim Laden der Drucker',
@ -1734,7 +1743,6 @@ def get_printers():
}) })
except Exception as e: except Exception as e:
signal.alarm(0) # Clear any remaining alarm
db_session.rollback() db_session.rollback()
db_session.close() db_session.close()
printers_logger.error(f"Fehler beim Abrufen der Drucker: {str(e)}") printers_logger.error(f"Fehler beim Abrufen der Drucker: {str(e)}")
@ -1750,19 +1758,28 @@ def get_printers_with_status():
db_session = get_db_session() db_session = get_db_session()
try: try:
# Set timeout for database query # Windows-kompatible Timeout-Implementierung
import signal import threading
import time
def timeout_handler(signum, frame): printers = None
raise TimeoutError("Database query timeout") timeout_occurred = False
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(8) # 8 second timeout for status check loading
def fetch_printers():
nonlocal printers, timeout_occurred
try: try:
printers = db_session.query(Printer).all() printers = db_session.query(Printer).all()
signal.alarm(0) # Clear alarm except Exception as e:
except TimeoutError: printers_logger.error(f"Datenbankfehler beim Status-Check: {str(e)}")
timeout_occurred = True
# Starte Datenbankabfrage in separatem Thread
thread = threading.Thread(target=fetch_printers)
thread.daemon = True
thread.start()
thread.join(timeout=8) # 8 Sekunden Timeout für Status-Check
if thread.is_alive() or timeout_occurred or printers is None:
printers_logger.warning("Database timeout when fetching printers for status check") printers_logger.warning("Database timeout when fetching printers for status check")
return jsonify({ return jsonify({
'error': 'Database timeout beim Status-Check der Drucker', 'error': 'Database timeout beim Status-Check der Drucker',
@ -1852,7 +1869,6 @@ def get_printers_with_status():
return jsonify(status_data) return jsonify(status_data)
except Exception as e: except Exception as e:
signal.alarm(0) # Clear any remaining alarm
db_session.rollback() db_session.rollback()
db_session.close() db_session.close()
printers_logger.error(f"Fehler beim Status-Check der Drucker: {str(e)}") printers_logger.error(f"Fehler beim Status-Check der Drucker: {str(e)}")

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,314 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Debug-Skript für Druckererkennung
Testet die Druckererkennung und identifiziert Probleme
"""
import sys
import os
import requests
import json
import time
import threading
from datetime import datetime
import sqlite3
import subprocess
import platform
# Füge das Anwendungsverzeichnis zum Python-Pfad hinzu
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
def log_message(message, level="INFO"):
"""Logge eine Nachricht mit Zeitstempel"""
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"[{timestamp}] [{level}] {message}")
def test_database_connection():
"""Teste die Datenbankverbindung"""
log_message("Teste Datenbankverbindung...")
try:
# Versuche SQLite-Datenbank zu öffnen
db_files = ['database.db', 'app.db', 'myp.db']
for db_file in db_files:
if os.path.exists(db_file):
log_message(f"Gefundene Datenbankdatei: {db_file}")
conn = sqlite3.connect(db_file)
cursor = conn.cursor()
# Prüfe ob Printer-Tabelle existiert
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='printer';")
if cursor.fetchone():
log_message("✅ Printer-Tabelle gefunden")
# Zähle Drucker
cursor.execute("SELECT COUNT(*) FROM printer;")
count = cursor.fetchone()[0]
log_message(f"📊 Anzahl Drucker in Datenbank: {count}")
# Zeige Drucker-Details
cursor.execute("SELECT id, name, plug_ip, status FROM printer;")
printers = cursor.fetchall()
for printer in printers:
log_message(f" Drucker {printer[0]}: {printer[1]} ({printer[2]}) - Status: {printer[3]}")
conn.close()
return True
else:
log_message("❌ Printer-Tabelle nicht gefunden")
conn.close()
log_message("❌ Keine gültige Datenbank gefunden")
return False
except Exception as e:
log_message(f"❌ Datenbankfehler: {str(e)}", "ERROR")
return False
def test_api_endpoints():
"""Teste die API-Endpunkte"""
log_message("Teste API-Endpunkte...")
base_url = "http://localhost:5000"
endpoints = [
"/api/printers",
"/api/printers/status"
]
for endpoint in endpoints:
try:
log_message(f"Teste {endpoint}...")
response = requests.get(f"{base_url}{endpoint}", timeout=10)
log_message(f" Status Code: {response.status_code}")
if response.status_code == 200:
try:
data = response.json()
if endpoint == "/api/printers":
if 'printers' in data:
log_message(f"{len(data['printers'])} Drucker geladen")
else:
log_message(f" ⚠️ Unerwartete Antwortstruktur: {list(data.keys())}")
else:
if isinstance(data, list):
log_message(f"{len(data)} Drucker mit Status geladen")
else:
log_message(f" ⚠️ Unerwartete Antwortstruktur: {type(data)}")
except json.JSONDecodeError:
log_message(f" ❌ Ungültige JSON-Antwort", "ERROR")
else:
log_message(f" ❌ HTTP-Fehler: {response.status_code}", "ERROR")
try:
error_data = response.json()
log_message(f" Fehlermeldung: {error_data.get('error', 'Unbekannt')}", "ERROR")
except:
log_message(f" Antwort: {response.text[:200]}", "ERROR")
except requests.exceptions.ConnectionError:
log_message(f" ❌ Verbindung zu {base_url} fehlgeschlagen", "ERROR")
log_message(" Ist die Flask-Anwendung gestartet?", "ERROR")
except requests.exceptions.Timeout:
log_message(f" ❌ Timeout bei {endpoint}", "ERROR")
except Exception as e:
log_message(f" ❌ Fehler: {str(e)}", "ERROR")
def test_network_connectivity():
"""Teste Netzwerkverbindung zu Druckern"""
log_message("Teste Netzwerkverbindung zu Druckern...")
# Lade Drucker aus Datenbank
try:
db_files = ['database.db', 'app.db', 'myp.db']
printers = []
for db_file in db_files:
if os.path.exists(db_file):
conn = sqlite3.connect(db_file)
cursor = conn.cursor()
cursor.execute("SELECT name, plug_ip FROM printer WHERE plug_ip IS NOT NULL;")
printers = cursor.fetchall()
conn.close()
break
if not printers:
log_message("❌ Keine Drucker mit IP-Adressen gefunden")
return
for name, ip in printers:
log_message(f"Teste Verbindung zu {name} ({ip})...")
# Ping-Test
try:
if platform.system().lower() == "windows":
result = subprocess.run(['ping', '-n', '1', '-w', '3000', ip],
capture_output=True, text=True, timeout=5)
else:
result = subprocess.run(['ping', '-c', '1', '-W', '3', ip],
capture_output=True, text=True, timeout=5)
if result.returncode == 0:
log_message(f" ✅ Ping erfolgreich")
else:
log_message(f" ❌ Ping fehlgeschlagen")
except subprocess.TimeoutExpired:
log_message(f" ❌ Ping-Timeout")
except Exception as e:
log_message(f" ❌ Ping-Fehler: {str(e)}")
# HTTP-Test (falls Drucker Webinterface hat)
try:
response = requests.get(f"http://{ip}", timeout=3)
log_message(f" ✅ HTTP-Verbindung erfolgreich (Status: {response.status_code})")
except requests.exceptions.Timeout:
log_message(f" ⚠️ HTTP-Timeout (normal für Drucker ohne Webinterface)")
except requests.exceptions.ConnectionError:
log_message(f" ⚠️ HTTP-Verbindung fehlgeschlagen (normal für Drucker ohne Webinterface)")
except Exception as e:
log_message(f" ⚠️ HTTP-Fehler: {str(e)}")
except Exception as e:
log_message(f"❌ Fehler beim Testen der Netzwerkverbindung: {str(e)}", "ERROR")
def test_flask_app_status():
"""Teste den Status der Flask-Anwendung"""
log_message("Teste Flask-Anwendung...")
try:
# Teste Hauptseite
response = requests.get("http://localhost:5000", timeout=5)
if response.status_code == 200:
log_message("✅ Flask-Anwendung läuft")
else:
log_message(f"⚠️ Flask-Anwendung antwortet mit Status {response.status_code}")
except requests.exceptions.ConnectionError:
log_message("❌ Flask-Anwendung nicht erreichbar", "ERROR")
log_message(" Starte die Anwendung mit: python app.py", "INFO")
except Exception as e:
log_message(f"❌ Fehler beim Testen der Flask-Anwendung: {str(e)}", "ERROR")
def test_threading_timeout():
"""Teste die Threading-basierte Timeout-Implementierung"""
log_message("Teste Threading-Timeout-Implementierung...")
def test_function():
"""Simuliere eine langsame Datenbankabfrage"""
time.sleep(2)
return "Erfolgreich"
try:
result = None
timeout_occurred = False
def run_test():
nonlocal result, timeout_occurred
try:
result = test_function()
except Exception as e:
log_message(f"Fehler in Test-Thread: {str(e)}", "ERROR")
timeout_occurred = True
# Starte Test in separatem Thread
thread = threading.Thread(target=run_test)
thread.daemon = True
thread.start()
thread.join(timeout=3) # 3 Sekunden Timeout
if thread.is_alive() or timeout_occurred or result is None:
log_message("❌ Threading-Timeout-Test fehlgeschlagen", "ERROR")
else:
log_message("✅ Threading-Timeout-Implementierung funktioniert")
except Exception as e:
log_message(f"❌ Fehler beim Threading-Test: {str(e)}", "ERROR")
def check_system_requirements():
"""Prüfe Systemanforderungen"""
log_message("Prüfe Systemanforderungen...")
# Python-Version
python_version = sys.version_info
log_message(f"Python-Version: {python_version.major}.{python_version.minor}.{python_version.micro}")
if python_version.major >= 3 and python_version.minor >= 7:
log_message("✅ Python-Version ist kompatibel")
else:
log_message("❌ Python 3.7+ erforderlich", "ERROR")
# Erforderliche Module
required_modules = ['flask', 'requests', 'sqlite3', 'threading']
for module in required_modules:
try:
__import__(module)
log_message(f"✅ Modul {module} verfügbar")
except ImportError:
log_message(f"❌ Modul {module} nicht verfügbar", "ERROR")
# Betriebssystem
os_name = platform.system()
log_message(f"Betriebssystem: {os_name}")
if os_name == "Windows":
log_message("✅ Windows-spezifische Fixes wurden angewendet")
else:
log_message(" Unix-basiertes System erkannt")
def run_comprehensive_test():
"""Führe alle Tests aus"""
log_message("=== MYP Druckerverwaltung - Diagnose-Tool ===")
log_message("Starte umfassende Systemdiagnose...")
print()
# Systemanforderungen prüfen
check_system_requirements()
print()
# Threading-Test
test_threading_timeout()
print()
# Datenbanktest
test_database_connection()
print()
# Flask-App-Test
test_flask_app_status()
print()
# API-Tests
test_api_endpoints()
print()
# Netzwerk-Tests
test_network_connectivity()
print()
log_message("=== Diagnose abgeschlossen ===")
print()
# Empfehlungen
log_message("📋 Empfehlungen:")
log_message("1. Stelle sicher, dass die Flask-Anwendung läuft: python app.py")
log_message("2. Prüfe die Datenbankverbindung und Drucker-Konfiguration")
log_message("3. Teste die Netzwerkverbindung zu den Druckern")
log_message("4. Bei Windows: Threading-basierte Timeouts wurden implementiert")
log_message("5. Überprüfe die Logs in logs/app/ für weitere Details")
if __name__ == "__main__":
try:
run_comprehensive_test()
except KeyboardInterrupt:
log_message("Diagnose durch Benutzer abgebrochen", "INFO")
except Exception as e:
log_message(f"Unerwarteter Fehler: {str(e)}", "ERROR")
import traceback
traceback.print_exc()

View File

@ -0,0 +1,517 @@
#!/bin/bash
# ===================================================================
# Raspberry Pi Vollautomatische Installation - MYP Druckerverwaltung
# Für Debian 12 (Bookworm) auf Raspberry Pi
# ===================================================================
set -e # Beende bei Fehlern
# Farben für Ausgabe
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging-Funktion
log() {
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')] $1${NC}"
}
error() {
echo -e "${RED}[FEHLER] $1${NC}"
exit 1
}
warning() {
echo -e "${YELLOW}[WARNUNG] $1${NC}"
}
info() {
echo -e "${BLUE}[INFO] $1${NC}"
}
# Prüfe ob als Root ausgeführt
if [ "$EUID" -ne 0 ]; then
error "Dieses Skript muss als Root ausgeführt werden. Verwende: sudo $0"
fi
log "=== MYP Druckerverwaltung - Raspberry Pi Installation ==="
log "Debian 12 (Bookworm) Vollautomatische Einrichtung"
echo
# Konfigurationsvariablen
APP_USER="myp"
APP_DIR="/opt/myp-druckerverwaltung"
SERVICE_NAME="myp-druckerverwaltung"
KIOSK_SERVICE_NAME="myp-kiosk"
GITHUB_REPO="https://github.com/your-repo/myp-druckerverwaltung.git" # Anpassen!
DISPLAY_PORT=":0"
# Systemupdate
log "Aktualisiere Paketlisten und System..."
export DEBIAN_FRONTEND=noninteractive
apt-get update -y
apt-get upgrade -y --allow-downgrades --allow-remove-essential --allow-change-held-packages
# Installiere erforderliche Pakete
log "Installiere Systempakete..."
apt-get install -y \
python3 \
python3-pip \
python3-venv \
python3-dev \
git \
curl \
wget \
unzip \
sqlite3 \
nginx \
supervisor \
chromium-browser \
xorg \
openbox \
lightdm \
x11-xserver-utils \
unclutter \
build-essential \
libssl-dev \
libffi-dev \
libjpeg-dev \
zlib1g-dev \
nodejs \
npm \
--break-system-packages || true
# Erstelle Anwendungsbenutzer
log "Erstelle Anwendungsbenutzer '$APP_USER'..."
if ! id "$APP_USER" &>/dev/null; then
useradd -m -s /bin/bash "$APP_USER"
usermod -aG sudo "$APP_USER"
log "Benutzer '$APP_USER' erstellt"
else
log "Benutzer '$APP_USER' existiert bereits"
fi
# Erstelle Anwendungsverzeichnis
log "Erstelle Anwendungsverzeichnis..."
mkdir -p "$APP_DIR"
chown "$APP_USER:$APP_USER" "$APP_DIR"
# Klone Repository (falls nicht lokal vorhanden)
if [ ! -d "$APP_DIR/.git" ]; then
log "Klone Anwendung von Repository..."
# Für lokale Installation: kopiere aktuelles Verzeichnis
if [ -f "app.py" ]; then
log "Kopiere lokale Anwendung..."
cp -r . "$APP_DIR/"
chown -R "$APP_USER:$APP_USER" "$APP_DIR"
else
error "Anwendungsdateien nicht gefunden. Führe das Skript im Anwendungsverzeichnis aus."
fi
else
log "Repository bereits vorhanden, aktualisiere..."
cd "$APP_DIR"
sudo -u "$APP_USER" git pull
fi
cd "$APP_DIR"
# Python Virtual Environment erstellen
log "Erstelle Python Virtual Environment..."
sudo -u "$APP_USER" python3 -m venv venv
sudo -u "$APP_USER" ./venv/bin/pip install --upgrade pip
# Installiere Python-Abhängigkeiten
log "Installiere Python-Abhängigkeiten..."
if [ -f "requirements.txt" ]; then
sudo -u "$APP_USER" ./venv/bin/pip install -r requirements.txt --break-system-packages || true
else
# Fallback: Installiere grundlegende Pakete
sudo -u "$APP_USER" ./venv/bin/pip install \
flask \
flask-login \
flask-sqlalchemy \
werkzeug \
requests \
python-dotenv \
gunicorn \
--break-system-packages || true
fi
# Node.js Abhängigkeiten installieren (falls package.json vorhanden)
if [ -f "package.json" ]; then
log "Installiere Node.js Abhängigkeiten..."
sudo -u "$APP_USER" npm install --unsafe-perm=true --allow-root
# Baue Frontend-Assets
if [ -f "tailwind.config.js" ]; then
log "Baue Frontend-Assets..."
sudo -u "$APP_USER" npm run build || true
fi
fi
# Datenbank initialisieren
log "Initialisiere Datenbank..."
if [ -f "init_db.py" ]; then
sudo -u "$APP_USER" ./venv/bin/python init_db.py
else
# Erstelle einfache SQLite-Datenbank
sudo -u "$APP_USER" touch database.db
fi
# Erstelle Konfigurationsdatei
log "Erstelle Anwendungskonfiguration..."
cat > "$APP_DIR/.env" << EOF
# MYP Druckerverwaltung Konfiguration
FLASK_ENV=production
SECRET_KEY=$(openssl rand -hex 32)
DATABASE_URL=sqlite:///database.db
HOST=0.0.0.0
PORT=5000
DEBUG=False
# Kiosk-Modus
KIOSK_MODE=true
AUTO_LOGIN=true
EOF
chown "$APP_USER:$APP_USER" "$APP_DIR/.env"
# Erstelle Systemd-Service für die Anwendung
log "Erstelle Systemd-Service..."
cat > "/etc/systemd/system/$SERVICE_NAME.service" << EOF
[Unit]
Description=MYP Druckerverwaltung Flask Application
After=network.target
[Service]
Type=simple
User=$APP_USER
Group=$APP_USER
WorkingDirectory=$APP_DIR
Environment=PATH=$APP_DIR/venv/bin
ExecStart=$APP_DIR/venv/bin/python app.py
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
# Nginx-Konfiguration
log "Konfiguriere Nginx..."
cat > "/etc/nginx/sites-available/myp-druckerverwaltung" << EOF
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
# WebSocket-Support
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
}
# Statische Dateien direkt servieren
location /static/ {
alias $APP_DIR/static/;
expires 1y;
add_header Cache-Control "public, immutable";
}
}
EOF
# Aktiviere Nginx-Site
rm -f /etc/nginx/sites-enabled/default
ln -sf /etc/nginx/sites-available/myp-druckerverwaltung /etc/nginx/sites-enabled/
# Kiosk-Modus konfigurieren
log "Konfiguriere Kiosk-Modus..."
# Erstelle Kiosk-Benutzer
if ! id "kiosk" &>/dev/null; then
useradd -m -s /bin/bash kiosk
usermod -aG audio,video kiosk
fi
# Erstelle Kiosk-Startskript
cat > "/home/kiosk/start-kiosk.sh" << 'EOF'
#!/bin/bash
# Warte auf Netzwerk
sleep 10
# Setze Display
export DISPLAY=:0
# Deaktiviere Bildschirmschoner und Energiesparmodus
xset s off
xset -dpms
xset s noblank
# Verstecke Mauszeiger
unclutter -idle 0.5 -root &
# Starte Chromium im Kiosk-Modus
chromium-browser \
--kiosk \
--no-sandbox \
--disable-web-security \
--disable-features=TranslateUI \
--disable-ipc-flooding-protection \
--disable-renderer-backgrounding \
--disable-backgrounding-occluded-windows \
--disable-background-timer-throttling \
--disable-background-networking \
--disable-breakpad \
--disable-component-extensions-with-background-pages \
--disable-dev-shm-usage \
--disable-extensions \
--disable-features=TranslateUI,BlinkGenPropertyTrees \
--disable-hang-monitor \
--disable-ipc-flooding-protection \
--disable-popup-blocking \
--disable-prompt-on-repost \
--disable-renderer-backgrounding \
--disable-sync \
--disable-translate \
--disable-windows10-custom-titlebar \
--force-color-profile=srgb \
--metrics-recording-only \
--no-first-run \
--safebrowsing-disable-auto-update \
--enable-automation \
--password-store=basic \
--use-mock-keychain \
--autoplay-policy=no-user-gesture-required \
--start-fullscreen \
--window-position=0,0 \
--window-size=1920,1080 \
http://localhost/
EOF
chmod +x /home/kiosk/start-kiosk.sh
chown kiosk:kiosk /home/kiosk/start-kiosk.sh
# Erstelle Systemd-Service für Kiosk
cat > "/etc/systemd/system/$KIOSK_SERVICE_NAME.service" << EOF
[Unit]
Description=MYP Kiosk Mode
After=graphical-session.target network.target $SERVICE_NAME.service
Wants=graphical-session.target
[Service]
Type=simple
User=kiosk
Group=kiosk
Environment=DISPLAY=:0
ExecStart=/home/kiosk/start-kiosk.sh
Restart=always
RestartSec=10
[Install]
WantedBy=graphical.target
EOF
# Konfiguriere LightDM für automatischen Login
log "Konfiguriere automatischen Login..."
cat > "/etc/lightdm/lightdm.conf" << EOF
[Seat:*]
autologin-user=kiosk
autologin-user-timeout=0
user-session=openbox
EOF
# Erstelle Openbox-Konfiguration für Kiosk-Benutzer
mkdir -p /home/kiosk/.config/openbox
cat > "/home/kiosk/.config/openbox/autostart" << EOF
# Starte Kiosk-Anwendung
/home/kiosk/start-kiosk.sh &
EOF
chown -R kiosk:kiosk /home/kiosk/.config
# Erstelle Wartungsskript
log "Erstelle Wartungsskript..."
cat > "/usr/local/bin/myp-maintenance" << 'EOF'
#!/bin/bash
# MYP Druckerverwaltung Wartungsskript
case "$1" in
start)
echo "Starte MYP Druckerverwaltung..."
systemctl start myp-druckerverwaltung
systemctl start nginx
systemctl start myp-kiosk
;;
stop)
echo "Stoppe MYP Druckerverwaltung..."
systemctl stop myp-kiosk
systemctl stop myp-druckerverwaltung
systemctl stop nginx
;;
restart)
echo "Starte MYP Druckerverwaltung neu..."
systemctl restart myp-druckerverwaltung
systemctl restart nginx
systemctl restart myp-kiosk
;;
status)
echo "=== MYP Druckerverwaltung Status ==="
systemctl status myp-druckerverwaltung --no-pager
echo
echo "=== Nginx Status ==="
systemctl status nginx --no-pager
echo
echo "=== Kiosk Status ==="
systemctl status myp-kiosk --no-pager
;;
logs)
echo "=== Anwendungslogs ==="
journalctl -u myp-druckerverwaltung -f
;;
update)
echo "Aktualisiere MYP Druckerverwaltung..."
cd /opt/myp-druckerverwaltung
sudo -u myp git pull
sudo -u myp ./venv/bin/pip install -r requirements.txt --break-system-packages
systemctl restart myp-druckerverwaltung
;;
*)
echo "Verwendung: $0 {start|stop|restart|status|logs|update}"
exit 1
;;
esac
EOF
chmod +x /usr/local/bin/myp-maintenance
# Aktiviere und starte Services
log "Aktiviere und starte Services..."
systemctl daemon-reload
systemctl enable "$SERVICE_NAME"
systemctl enable nginx
systemctl enable "$KIOSK_SERVICE_NAME"
# Starte Services
systemctl start "$SERVICE_NAME"
systemctl start nginx
# Warte kurz und prüfe Status
sleep 5
if systemctl is-active --quiet "$SERVICE_NAME"; then
log "✅ MYP Druckerverwaltung Service läuft"
else
warning "⚠️ MYP Druckerverwaltung Service nicht aktiv"
fi
if systemctl is-active --quiet nginx; then
log "✅ Nginx läuft"
else
warning "⚠️ Nginx nicht aktiv"
fi
# Konfiguriere Firewall (falls ufw installiert)
if command -v ufw &> /dev/null; then
log "Konfiguriere Firewall..."
ufw --force enable
ufw allow 80/tcp
ufw allow 22/tcp
fi
# Erstelle Desktop-Verknüpfung für Wartung
cat > "/home/$APP_USER/Desktop/MYP-Wartung.desktop" << EOF
[Desktop Entry]
Version=1.0
Type=Application
Name=MYP Wartung
Comment=MYP Druckerverwaltung Wartung
Exec=gnome-terminal -- sudo myp-maintenance status
Icon=applications-system
Terminal=true
Categories=System;
EOF
chown "$APP_USER:$APP_USER" "/home/$APP_USER/Desktop/MYP-Wartung.desktop"
chmod +x "/home/$APP_USER/Desktop/MYP-Wartung.desktop"
# Erstelle Backup-Skript
cat > "/usr/local/bin/myp-backup" << 'EOF'
#!/bin/bash
BACKUP_DIR="/opt/myp-backups"
DATE=$(date +%Y%m%d_%H%M%S)
APP_DIR="/opt/myp-druckerverwaltung"
mkdir -p "$BACKUP_DIR"
echo "Erstelle Backup: $DATE"
# Stoppe Anwendung
systemctl stop myp-druckerverwaltung
# Erstelle Backup
tar -czf "$BACKUP_DIR/myp_backup_$DATE.tar.gz" \
-C "$APP_DIR" \
database.db \
.env \
uploads/ \
logs/ 2>/dev/null || true
# Starte Anwendung
systemctl start myp-druckerverwaltung
echo "Backup erstellt: $BACKUP_DIR/myp_backup_$DATE.tar.gz"
# Lösche alte Backups (älter als 30 Tage)
find "$BACKUP_DIR" -name "myp_backup_*.tar.gz" -mtime +30 -delete
EOF
chmod +x /usr/local/bin/myp-backup
# Erstelle Cron-Job für automatische Backups
echo "0 2 * * * root /usr/local/bin/myp-backup" > /etc/cron.d/myp-backup
# Abschlussmeldung
log "=== Installation abgeschlossen! ==="
echo
info "🎉 MYP Druckerverwaltung wurde erfolgreich installiert!"
echo
info "📋 Wichtige Informationen:"
info " • Anwendung läuft auf: http://$(hostname -I | awk '{print $1}')"
info " • Anwendungsverzeichnis: $APP_DIR"
info " • Anwendungsbenutzer: $APP_USER"
info " • Service-Name: $SERVICE_NAME"
info " • Kiosk-Service: $KIOSK_SERVICE_NAME"
echo
info "🔧 Wartungskommandos:"
info " • Status prüfen: myp-maintenance status"
info " • Neustart: myp-maintenance restart"
info " • Logs anzeigen: myp-maintenance logs"
info " • Update: myp-maintenance update"
info " • Backup erstellen: myp-backup"
echo
info "🖥️ Kiosk-Modus:"
info " • Wird beim nächsten Neustart automatisch gestartet"
info " • Vollbild-Browser auf http://localhost"
info " • Automatischer Login als 'kiosk' Benutzer"
echo
warning "⚠️ Wichtiger Hinweis:"
warning " Starte das System neu, um den Kiosk-Modus zu aktivieren:"
warning " sudo reboot"
echo
log "Installation erfolgreich abgeschlossen! 🚀"

View File

@ -16,7 +16,19 @@ fi
# Installiere benötigte Pakete # Installiere benötigte Pakete
echo "Installiere Pakete..." echo "Installiere Pakete..."
apt update apt update
apt install -y python3.11 python3-pip chromium-browser lightdm openbox curl
# Basis-Pakete
apt install -y python3.11 python3-pip curl
# Browser
apt install -y chromium-browser || apt install -y chromium || apt install -y firefox-esr
# Display Manager und Window Manager
apt install -y lightdm
apt install -y openbox || apt install -y xfce4 || apt install -y lxde
# X11 falls nicht vorhanden
apt install -y xorg xinit
# Erstelle Verzeichnisse # Erstelle Verzeichnisse
echo "Erstelle Verzeichnisse..." echo "Erstelle Verzeichnisse..."
@ -58,6 +70,20 @@ systemctl daemon-reload
systemctl enable myp-backend.service systemctl enable myp-backend.service
systemctl enable myp-kiosk.service systemctl enable myp-kiosk.service
# Erstelle Benutzer 'user' falls nicht vorhanden
echo "Erstelle Benutzer 'user'..."
if ! id "user" &>/dev/null; then
useradd -m -s /bin/bash user
echo "user:user" | chpasswd
fi
# Setze Openbox als Standard-Session
echo "Setze Openbox als Standard..."
echo "openbox-session" > /home/user/.xsession
echo "openbox-session" > /home/user/.xinitrc
chmod +x /home/user/.xsession
chmod +x /home/user/.xinitrc
# Konfiguriere automatischen Login # Konfiguriere automatischen Login
echo "Konfiguriere automatischen Login..." echo "Konfiguriere automatischen Login..."
cat > /etc/lightdm/lightdm.conf.d/10-autologin.conf << EOF cat > /etc/lightdm/lightdm.conf.d/10-autologin.conf << EOF
@ -65,17 +91,48 @@ cat > /etc/lightdm/lightdm.conf.d/10-autologin.conf << EOF
autologin-user=user autologin-user=user
autologin-user-timeout=0 autologin-user-timeout=0
user-session=openbox user-session=openbox
greeter-session=lightdm-gtk-greeter
EOF EOF
# Konfiguriere Openbox für Kiosk-Start # Konfiguriere Openbox für Kiosk-Start
echo "Konfiguriere Openbox..." echo "Konfiguriere Openbox..."
mkdir -p /home/user/.config/openbox
cat > /home/user/.config/openbox/autostart << EOF cat > /home/user/.config/openbox/autostart << EOF
# Warte kurz bis System bereit ist
sleep 3
# Starte Kiosk-Service automatisch # Starte Kiosk-Service automatisch
systemctl --user start myp-kiosk.service & systemctl --user start myp-kiosk.service &
EOF EOF
# Openbox-Menü deaktivieren (Kiosk-Modus)
cat > /home/user/.config/openbox/rc.xml << EOF
<?xml version="1.0" encoding="UTF-8"?>
<openbox_config xmlns="http://openbox.org/3.4/rc">
<keyboard>
<!-- Deaktiviere alle Tastenkombinationen -->
</keyboard>
<mouse>
<!-- Deaktiviere Rechtsklick-Menü -->
<context name="Desktop">
</context>
</mouse>
<applications>
<!-- Chromium immer im Vollbild -->
<application name="chromium*">
<fullscreen>yes</fullscreen>
<maximized>yes</maximized>
</application>
</applications>
</openbox_config>
EOF
chmod 755 /home/user/.config/openbox/autostart chmod 755 /home/user/.config/openbox/autostart
chown user:user /home/user/.config/openbox/autostart chmod 644 /home/user/.config/openbox/rc.xml
chown -R user:user /home/user/.config
chown -R user:user /home/user/.xsession
chown -R user:user /home/user/.xinitrc
echo "=== Installation abgeschlossen ===" echo "=== Installation abgeschlossen ==="
echo "System wird in 5 Sekunden neu gestartet..." echo "System wird in 5 Sekunden neu gestartet..."