neuschreiben der app.py nach refectoring

This commit is contained in:
Nirodan
2025-06-17 11:36:12 +02:00
parent e0b77c890e
commit 4c6872a866
+15 -187
View File
@@ -1,112 +1,29 @@
from flask import Flask, request, render_template, jsonify, redirect, send_from_directory from flask import Flask, send_from_directory, redirect
from backend.db_config import lade_db_config, speichere_db_config, teste_verbindung, initialisiere_admin_user
from datetime import datetime, timedelta
from jwt import decode, ExpiredSignatureError, InvalidTokenError
import time
import os import os
import jwt
import logging
from logging.handlers import RotatingFileHandler
app = Flask(__name__) from util.logger import logger
app.template_folder = "templates" from util.db_config import is_configured, load_config, test_connection
SECRET_KEY = "bitte_hier_dein_geheimes_passwort_setzen" # Achtung: später z.B. aus .env from util.setup_routes import setup_blueprint
from auth import auth_bp
from tools import md5_blueprint
CONFIG_PATH = "config/db_config.json" app = Flask(__name__, template_folder="templates")
MAX_WAIT = 30 # In Sekunden
WAIT_INTERVAL = 10
# 📦 Blueprints registrieren
app.register_blueprint(setup_blueprint)
app.register_blueprint(auth_bp)
app.register_blueprint(md5_blueprint)
# Logging-Zielpfade # 🌐 React-Frontend ausliefern
log_dir = "Tools"
os.makedirs(log_dir, exist_ok=True)
# App-Log (alles ab INFO)
app_log_handler = RotatingFileHandler(
os.path.join(log_dir, "app.log"), maxBytes=1_000_000, backupCount=3
)
app_log_handler.setLevel(logging.INFO)
app_log_handler.setFormatter(logging.Formatter(
"%(asctime)s [%(levelname)s] %(message)s"))
# Error-Log (nur ERROR)
error_log_handler = RotatingFileHandler(
os.path.join(log_dir, "error.log"), maxBytes=1_000_000, backupCount=3
)
error_log_handler.setLevel(logging.ERROR)
error_log_handler.setFormatter(logging.Formatter(
"%(asctime)s [%(levelname)s] %(message)s"))
# Logging-Grundkonfiguration
logging.basicConfig(
level=logging.INFO,
handlers=[
app_log_handler,
error_log_handler,
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
def ist_konfiguriert():
return os.path.exists(CONFIG_PATH)
def versuche_verbindung_mit_warten():
elapsed = 0
if not ist_konfiguriert():
logger.warning("⚠️ Noch keine Konfiguration gefunden.")
return False
config = lade_db_config()
while not teste_verbindung(config) and elapsed < MAX_WAIT:
logger.info(f"🔄 DB nicht erreichbar warte {WAIT_INTERVAL}s...")
time.sleep(WAIT_INTERVAL)
elapsed += WAIT_INTERVAL
if elapsed >= MAX_WAIT:
logger.error("❌ Maximale Wartezeit überschritten DB nicht erreichbar.")
return elapsed < MAX_WAIT
@app.route('/api/status')
def status():
if not ist_konfiguriert():
return jsonify({"status": "init", "db_connected": False})
elif teste_verbindung(lade_db_config()):
return jsonify({"status": "ready", "db_connected": True})
else:
return jsonify({"status": "error", "db_connected": False})
@app.route('/setup', methods=['GET', 'POST'])
def setup():
if request.method == 'POST':
db_config = {
"host": request.form['host'],
"port": int(request.form['port']),
"user": request.form['user'],
"password": request.form['password'],
"database": request.form['database']
}
speichere_db_config(db_config)
if teste_verbindung(db_config):
initialisiere_admin_user(db_config)
logger.info("✅ Setup erfolgreich, Admin-User erstellt.")
return redirect('/')
else:
logger.error("❌ Setup fehlgeschlagen DB-Verbindung nicht möglich.")
return "Verbindung fehlgeschlagen. Bitte zurück und prüfen.", 500
return render_template('setup.html')
@app.route('/', defaults={'path': ''}) @app.route('/', defaults={'path': ''})
@app.route('/<path:path>') @app.route('/<path:path>')
def serve_react(path): def serve_frontend(path):
if not ist_konfiguriert() or not teste_verbindung(lade_db_config()): if not is_configured() or not test_connection(load_config()):
return redirect('/setup') return redirect('/setup')
# setup und API dürfen nicht von React überdeckt werden
if path.startswith('setup') or path.startswith('api'): if path.startswith('setup') or path.startswith('api'):
return redirect(f'/{path}') return redirect(f'/{path}')
# Pfad zu frontend/dist absolut auflösen
dist_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'frontend', 'dist')) dist_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'frontend', 'dist'))
file_path = os.path.join(dist_dir, path) file_path = os.path.join(dist_dir, path)
@@ -115,96 +32,7 @@ def serve_react(path):
else: else:
return send_from_directory(dist_dir, 'index.html') return send_from_directory(dist_dir, 'index.html')
@app.route('/api/login', methods=['POST'])
def login():
from mysql.connector import connect
from werkzeug.security import check_password_hash
data = request.get_json()
username = data.get('username')
password = data.get('password')
try:
config = lade_db_config()
conn = connect(**config)
cursor = conn.cursor(dictionary=True)
cursor.execute("SELECT * FROM users WHERE username = %s", (username,))
user = cursor.fetchone()
cursor.close()
conn.close()
if user and check_password_hash(user['password'], password):
logger.info(f"✅ Login erfolgreich: {username}")
payload = {
"username": user['username'],
"role": user['role'],
"exp": datetime.utcnow() + timedelta(minutes=60)
}
token = jwt.encode(payload, SECRET_KEY, algorithm="HS256")
return jsonify({
"token": token,
"role": user['role']
})
logger.warning(f"⛔ Login fehlgeschlagen: {username}")
return jsonify({"message": "Login fehlgeschlagen"}), 401
except Exception as e:
logger.error(f"[Login-Fehler] {e}")
return jsonify({"message": "Serverfehler"}), 500
@app.route('/api/logout', methods=['POST'])
def logout():
return jsonify({"message": "Logout erfolgreich"})
def verify_token():
auth_header = request.headers.get("Authorization", "")
if not auth_header.startswith("Bearer "):
logger.warning("🔐 Kein gültiger Bearer-Header")
return None
token = auth_header.replace("Bearer ", "")
try:
decoded = decode(token, SECRET_KEY, algorithms=["HS256"])
return decoded
except ExpiredSignatureError:
logger.warning("🔐 Token abgelaufen")
return None
except InvalidTokenError:
logger.warning("🔐 Ungültiger Token")
return None
@app.route('/api/hash/md5', methods=['POST'])
def hash_md5():
logger.info("🔁 /api/hash/md5 aufgerufen")
user = verify_token()
if not user:
logger.warning("⛔ Nicht autorisiert")
return jsonify({"message": "Nicht autorisiert"}), 401
try:
data = request.get_json()
logger.debug(f"📩 Payload: {data}")
password = data.get("password", "")
import hashlib
result = hashlib.md5(password.encode()).hexdigest()
logger.info(f"✅ Hash erstellt von {user['username']}")
return jsonify({
"md5": result,
"by": user['username']
})
except Exception as e:
logger.error(f"❌ Fehler beim Hashen: {e}")
return jsonify({"message": "Fehler beim Hashen"}), 500
if __name__ == '__main__': if __name__ == '__main__':
os.makedirs("config", exist_ok=True) os.makedirs("config", exist_ok=True)
app.run(host='0.0.0.0', port=5000, debug=True) # debug=True nur für Entwicklung, nicht in Produktion verwenden! app.run(host='0.0.0.0', port=5000, debug=True)