feat: Entferne nicht mehr benötigte Skripte für Test-Drucker, Debug-Login und schnelle Datenbank-Reparatur
This commit is contained in:
106
backend/app/utils/create_test_printers.py
Normal file
106
backend/app/utils/create_test_printers.py
Normal file
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script zum Erstellen von Test-Druckern für die MYP Plattform
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
sys.path.append('.')
|
||||
|
||||
from models import *
|
||||
from datetime import datetime
|
||||
|
||||
def create_test_printers():
|
||||
"""Erstellt Test-Drucker in der Datenbank."""
|
||||
|
||||
# Verbindung zur Datenbank
|
||||
db_session = get_db_session()
|
||||
|
||||
# Test-Drucker Daten
|
||||
test_printers = [
|
||||
{
|
||||
'name': 'Mercedes-Benz FDM Pro #01',
|
||||
'model': 'Ultimaker S5 Pro',
|
||||
'location': 'Werkhalle Sindelfingen',
|
||||
'plug_ip': '192.168.10.101',
|
||||
'status': 'available',
|
||||
'active': True
|
||||
},
|
||||
{
|
||||
'name': 'Mercedes-Benz FDM #02',
|
||||
'model': 'Prusa MK3S+',
|
||||
'location': 'Entwicklungszentrum Stuttgart',
|
||||
'plug_ip': '192.168.10.102',
|
||||
'status': 'printing',
|
||||
'active': True
|
||||
},
|
||||
{
|
||||
'name': 'Mercedes-Benz SLA #01',
|
||||
'model': 'Formlabs Form 3+',
|
||||
'location': 'Prototypenlabor',
|
||||
'plug_ip': '192.168.10.103',
|
||||
'status': 'available',
|
||||
'active': True
|
||||
},
|
||||
{
|
||||
'name': 'Mercedes-Benz Industrial #01',
|
||||
'model': 'Stratasys F370',
|
||||
'location': 'Industriehalle Bremen',
|
||||
'plug_ip': '192.168.10.104',
|
||||
'status': 'maintenance',
|
||||
'active': False
|
||||
},
|
||||
{
|
||||
'name': 'Mercedes-Benz Rapid #01',
|
||||
'model': 'Bambu Lab X1 Carbon',
|
||||
'location': 'Designabteilung',
|
||||
'plug_ip': '192.168.10.105',
|
||||
'status': 'offline',
|
||||
'active': True
|
||||
},
|
||||
{
|
||||
'name': 'Mercedes-Benz SLS #01',
|
||||
'model': 'HP Jet Fusion 5200',
|
||||
'location': 'Produktionszentrum Berlin',
|
||||
'plug_ip': '192.168.10.106',
|
||||
'status': 'available',
|
||||
'active': True
|
||||
}
|
||||
]
|
||||
try:
|
||||
created_count = 0
|
||||
for printer_data in test_printers:
|
||||
# Prüfen ob Drucker bereits existiert
|
||||
existing = db_session.query(Printer).filter_by(name=printer_data['name']).first()
|
||||
if not existing:
|
||||
printer = Printer(
|
||||
name=printer_data['name'],
|
||||
model=printer_data['model'],
|
||||
location=printer_data['location'],
|
||||
plug_ip=printer_data['plug_ip'],
|
||||
status=printer_data['status'],
|
||||
active=printer_data['active'],
|
||||
created_at=datetime.now()
|
||||
)
|
||||
db_session.add(printer)
|
||||
created_count += 1
|
||||
print(f"✅ Drucker '{printer_data['name']}' erstellt")
|
||||
else:
|
||||
print(f"ℹ️ Drucker '{printer_data['name']}' existiert bereits")
|
||||
|
||||
db_session.commit()
|
||||
|
||||
total_count = db_session.query(Printer).count()
|
||||
print(f"\n🎉 {created_count} neue Test-Drucker erstellt!")
|
||||
print(f"📊 Insgesamt {total_count} Drucker in der Datenbank.")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Fehler beim Erstellen der Test-Drucker: {str(e)}")
|
||||
db_session.rollback()
|
||||
finally:
|
||||
db_session.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("🚀 Erstelle Test-Drucker für MYP Plattform...")
|
||||
create_test_printers()
|
||||
print("✅ Fertig!")
|
199
backend/app/utils/debug_login.py
Normal file
199
backend/app/utils/debug_login.py
Normal file
@@ -0,0 +1,199 @@
|
||||
#!/usr/bin/env python3.11
|
||||
"""
|
||||
Debug-Script für Login-Probleme
|
||||
Prüft Admin-Benutzer und Passwort-Hashing
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
# Path für imports setzen
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
from models import get_db_session, User, create_initial_admin
|
||||
import bcrypt
|
||||
|
||||
def debug_admin_user():
|
||||
"""Prüft den Admin-Benutzer in der Datenbank"""
|
||||
print("=== DEBUG: Admin-Benutzer Analyse ===")
|
||||
|
||||
try:
|
||||
db_session = get_db_session()
|
||||
|
||||
# Alle Benutzer anzeigen
|
||||
users = db_session.query(User).all()
|
||||
print(f"\n📊 Gefundene Benutzer: {len(users)}")
|
||||
|
||||
for user in users:
|
||||
print(f"\n👤 Benutzer ID: {user.id}")
|
||||
print(f" Email: {user.email}")
|
||||
print(f" Username: {user.username}")
|
||||
print(f" Name: {user.name}")
|
||||
print(f" Role: {user.role}")
|
||||
print(f" Is Admin: {user.is_admin}")
|
||||
print(f" Active: {user.active}")
|
||||
print(f" Password Hash: {user.password_hash[:20]}...")
|
||||
print(f" Created: {user.created_at}")
|
||||
|
||||
# Admin-Benutzer spezifisch prüfen
|
||||
admin_email = "admin@mercedes-benz.com"
|
||||
admin_username = "admin"
|
||||
|
||||
print(f"\n🔍 Suche nach Admin-Benutzer:")
|
||||
print(f" Email: {admin_email}")
|
||||
print(f" Username: {admin_username}")
|
||||
|
||||
# Suche nach E-Mail
|
||||
admin_by_email = db_session.query(User).filter(User.email == admin_email).first()
|
||||
if admin_by_email:
|
||||
print(f"✅ Admin gefunden per E-Mail: {admin_by_email.email}")
|
||||
else:
|
||||
print(f"❌ Kein Admin mit E-Mail {admin_email} gefunden")
|
||||
|
||||
# Suche nach Username
|
||||
admin_by_username = db_session.query(User).filter(User.username == admin_username).first()
|
||||
if admin_by_username:
|
||||
print(f"✅ Admin gefunden per Username: {admin_by_username.username}")
|
||||
else:
|
||||
print(f"❌ Kein Admin mit Username {admin_username} gefunden")
|
||||
|
||||
db_session.close()
|
||||
|
||||
return admin_by_email or admin_by_username
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Fehler beim Datenbankzugriff: {str(e)}")
|
||||
return None
|
||||
|
||||
def test_password_verification(user, test_password="744563017196A"):
|
||||
"""Testet die Passwort-Verifikation"""
|
||||
print(f"\n=== DEBUG: Passwort-Test ===")
|
||||
print(f"Test-Passwort: {test_password}")
|
||||
|
||||
if not user:
|
||||
print("❌ Kein Benutzer für Passwort-Test vorhanden")
|
||||
return False
|
||||
|
||||
try:
|
||||
# Manueller bcrypt-Test
|
||||
password_bytes = test_password.encode('utf-8')
|
||||
hash_bytes = user.password_hash.encode('utf-8')
|
||||
|
||||
print(f"Password Bytes: {password_bytes}")
|
||||
print(f"Hash (first 50 chars): {user.password_hash[:50]}")
|
||||
|
||||
# Test mit bcrypt
|
||||
is_valid_bcrypt = bcrypt.checkpw(password_bytes, hash_bytes)
|
||||
print(f"✅ bcrypt.checkpw() Ergebnis: {is_valid_bcrypt}")
|
||||
|
||||
# Test mit User-Methode
|
||||
is_valid_user_method = user.check_password(test_password)
|
||||
print(f"✅ user.check_password() Ergebnis: {is_valid_user_method}")
|
||||
|
||||
return is_valid_bcrypt and is_valid_user_method
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Fehler beim Passwort-Test: {str(e)}")
|
||||
return False
|
||||
|
||||
def recreate_admin():
|
||||
"""Erstellt den Admin-Benutzer neu"""
|
||||
print(f"\n=== DEBUG: Admin-Benutzer neu erstellen ===")
|
||||
|
||||
try:
|
||||
success = create_initial_admin(
|
||||
email="admin@mercedes-benz.com",
|
||||
password="744563017196A",
|
||||
name="System Administrator",
|
||||
username="admin"
|
||||
)
|
||||
|
||||
if success:
|
||||
print("✅ Admin-Benutzer erfolgreich erstellt/aktualisiert")
|
||||
else:
|
||||
print("❌ Fehler beim Erstellen des Admin-Benutzers")
|
||||
|
||||
return success
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Fehler beim Erstellen des Admins: {str(e)}")
|
||||
return False
|
||||
|
||||
def test_login_credentials():
|
||||
"""Testet verschiedene Login-Kombinationen"""
|
||||
print(f"\n=== DEBUG: Login-Kombinationen testen ===")
|
||||
|
||||
test_combinations = [
|
||||
("admin@mercedes-benz.com", "744563017196A"),
|
||||
("admin", "744563017196A"),
|
||||
]
|
||||
|
||||
db_session = get_db_session()
|
||||
|
||||
for email_or_username, password in test_combinations:
|
||||
print(f"\n🔍 Teste: {email_or_username} / {password}")
|
||||
|
||||
# Simuliere Login-Logic aus app.py
|
||||
user = db_session.query(User).filter(
|
||||
(User.username == email_or_username) | (User.email == email_or_username)
|
||||
).first()
|
||||
|
||||
if user:
|
||||
print(f"✅ Benutzer gefunden: {user.email} ({user.username})")
|
||||
|
||||
if user.check_password(password):
|
||||
print(f"✅ Passwort korrekt!")
|
||||
print(f"✅ Login wäre erfolgreich für: {user.email}")
|
||||
else:
|
||||
print(f"❌ Passwort falsch!")
|
||||
else:
|
||||
print(f"❌ Kein Benutzer mit {email_or_username} gefunden")
|
||||
|
||||
db_session.close()
|
||||
|
||||
def check_rate_limiting():
|
||||
"""Prüft Rate Limiting Status"""
|
||||
print(f"\n=== DEBUG: Rate Limiting Status ===")
|
||||
|
||||
# Simuliere localStorage-Werte (die wären normalerweise im Browser)
|
||||
# In einer echten Anwendung würden diese aus der Datenbank oder einem Cache kommen
|
||||
print("ℹ️ Rate Limiting wird client-seitig im localStorage verwaltet")
|
||||
print("ℹ️ Überprüfen Sie Ihren Browser-localStorage:")
|
||||
print(" - loginAttempts: sollte < 5 sein")
|
||||
print(" - lastAttemptTime: Zeit des letzten Versuchs")
|
||||
print("\n💡 Tipp: Öffnen Sie Entwicklertools > Application > Local Storage")
|
||||
print(" und löschen Sie 'loginAttempts' und 'lastAttemptTime' Einträge")
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("🚀 MYP Login Debug-Tool gestartet")
|
||||
print("=" * 50)
|
||||
|
||||
# 1. Admin-Benutzer prüfen
|
||||
admin_user = debug_admin_user()
|
||||
|
||||
# 2. Passwort-Verifikation testen
|
||||
if admin_user:
|
||||
test_password_verification(admin_user)
|
||||
|
||||
# 3. Admin neu erstellen falls Probleme
|
||||
if not admin_user:
|
||||
print("\n⚠️ Kein Admin gefunden - erstelle neuen Admin...")
|
||||
recreate_admin()
|
||||
admin_user = debug_admin_user()
|
||||
if admin_user:
|
||||
test_password_verification(admin_user)
|
||||
|
||||
# 4. Login-Kombinationen testen
|
||||
test_login_credentials()
|
||||
|
||||
# 5. Rate Limiting prüfen
|
||||
check_rate_limiting()
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
print("🎯 Debug abgeschlossen!")
|
||||
print("\n💡 Lösungsvorschläge:")
|
||||
print("1. Verwenden Sie admin@mercedes-benz.com + 744563017196A")
|
||||
print("2. Oder verwenden Sie admin + 744563017196A")
|
||||
print("3. Löschen Sie Rate-Limiting im Browser localStorage")
|
||||
print("4. Prüfen Sie die Browser-Konsole auf JavaScript-Fehler")
|
226
backend/app/utils/quick_fix.py
Normal file
226
backend/app/utils/quick_fix.py
Normal file
@@ -0,0 +1,226 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Schnelle Datenbank-Reparatur für kritische Fehler
|
||||
"""
|
||||
|
||||
import sqlite3
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
# Datenbankpfad
|
||||
DATABASE_PATH = "database/myp.db"
|
||||
|
||||
def quick_fix_database():
|
||||
"""Behebt die kritischsten Datenbankprobleme sofort"""
|
||||
print("🔧 Starte schnelle Datenbank-Reparatur...")
|
||||
|
||||
if not os.path.exists(DATABASE_PATH):
|
||||
print(f"❌ Datenbankdatei nicht gefunden: {DATABASE_PATH}")
|
||||
return False
|
||||
|
||||
try:
|
||||
# Backup erstellen
|
||||
backup_path = f"{DATABASE_PATH}.emergency_backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
|
||||
import shutil
|
||||
shutil.copy2(DATABASE_PATH, backup_path)
|
||||
print(f"✅ Emergency-Backup erstellt: {backup_path}")
|
||||
|
||||
# Verbindung zur Datenbank
|
||||
conn = sqlite3.connect(DATABASE_PATH)
|
||||
cursor = conn.cursor()
|
||||
|
||||
print("🔧 Repariere Datenbank-Schema...")
|
||||
|
||||
# 1. Fehlende Spalte duration_minutes zu guest_requests hinzufügen
|
||||
try:
|
||||
cursor.execute("ALTER TABLE guest_requests ADD COLUMN duration_minutes INTEGER")
|
||||
print("✅ Spalte duration_minutes zu guest_requests hinzugefügt")
|
||||
except sqlite3.OperationalError as e:
|
||||
if "duplicate column name" in str(e).lower():
|
||||
print("ℹ️ Spalte duration_minutes bereits vorhanden")
|
||||
else:
|
||||
print(f"⚠️ Fehler bei duration_minutes: {e}")
|
||||
|
||||
# 2. Fehlende Spalten zu users hinzufügen
|
||||
user_columns = [
|
||||
("username", "VARCHAR(100) UNIQUE"),
|
||||
("updated_at", "DATETIME DEFAULT CURRENT_TIMESTAMP"),
|
||||
("department", "VARCHAR(100)"),
|
||||
("position", "VARCHAR(100)"),
|
||||
("phone", "VARCHAR(50)"),
|
||||
("bio", "TEXT")
|
||||
]
|
||||
|
||||
for column_name, column_def in user_columns:
|
||||
try:
|
||||
cursor.execute(f"ALTER TABLE users ADD COLUMN {column_name} {column_def}")
|
||||
print(f"✅ Spalte {column_name} zu users hinzugefügt")
|
||||
except sqlite3.OperationalError as e:
|
||||
if "duplicate column name" in str(e).lower():
|
||||
print(f"ℹ️ Spalte {column_name} bereits vorhanden")
|
||||
else:
|
||||
print(f"⚠️ Fehler bei {column_name}: {e}")
|
||||
|
||||
# 3. Fehlende Spalten zu printers hinzufügen
|
||||
printer_columns = [
|
||||
("plug_username", "VARCHAR(100) DEFAULT 'admin'"),
|
||||
("plug_password", "VARCHAR(100) DEFAULT 'admin'"),
|
||||
("last_checked", "DATETIME")
|
||||
]
|
||||
|
||||
for column_name, column_def in printer_columns:
|
||||
try:
|
||||
cursor.execute(f"ALTER TABLE printers ADD COLUMN {column_name} {column_def}")
|
||||
print(f"✅ Spalte {column_name} zu printers hinzugefügt")
|
||||
except sqlite3.OperationalError as e:
|
||||
if "duplicate column name" in str(e).lower():
|
||||
print(f"ℹ️ Spalte {column_name} bereits vorhanden")
|
||||
else:
|
||||
print(f"⚠️ Fehler bei {column_name}: {e}")
|
||||
|
||||
# 4. Username für bestehende User setzen (falls NULL)
|
||||
try:
|
||||
cursor.execute("UPDATE users SET username = email WHERE username IS NULL")
|
||||
updated_users = cursor.rowcount
|
||||
if updated_users > 0:
|
||||
print(f"✅ Username für {updated_users} Benutzer gesetzt")
|
||||
except Exception as e:
|
||||
print(f"⚠️ Fehler beim Setzen der Usernames: {e}")
|
||||
|
||||
# 5. Drucker-Daten nachtragen
|
||||
print("🖨️ Trage Drucker nach...")
|
||||
|
||||
# Prüfen ob bereits Drucker vorhanden sind
|
||||
cursor.execute("SELECT COUNT(*) FROM printers")
|
||||
printer_count = cursor.fetchone()[0]
|
||||
|
||||
if printer_count == 0:
|
||||
# Standard-Drucker hinzufügen
|
||||
printers_to_add = [
|
||||
{
|
||||
'name': 'Printer 1',
|
||||
'model': 'P115',
|
||||
'location': 'Werk 040 - Berlin - TBA',
|
||||
'ip_address': '192.168.0.100',
|
||||
'mac_address': '98:254A:E1:2001',
|
||||
'plug_ip': '192.168.0.100',
|
||||
'plug_username': 'admin',
|
||||
'plug_password': 'admin',
|
||||
'status': 'offline',
|
||||
'active': 1
|
||||
},
|
||||
{
|
||||
'name': 'Printer 2',
|
||||
'model': 'P115',
|
||||
'location': 'Werk 040 - Berlin - TBA',
|
||||
'ip_address': '192.168.0.101',
|
||||
'mac_address': '98:254A:E1:2002',
|
||||
'plug_ip': '192.168.0.101',
|
||||
'plug_username': 'admin',
|
||||
'plug_password': 'admin',
|
||||
'status': 'offline',
|
||||
'active': 1
|
||||
},
|
||||
{
|
||||
'name': 'Printer 3',
|
||||
'model': 'P115',
|
||||
'location': 'Werk 040 - Berlin - TBA',
|
||||
'ip_address': '192.168.0.102',
|
||||
'mac_address': '98:254A:E1:2003',
|
||||
'plug_ip': '192.168.0.102',
|
||||
'plug_username': 'admin',
|
||||
'plug_password': 'admin',
|
||||
'status': 'offline',
|
||||
'active': 1
|
||||
},
|
||||
{
|
||||
'name': 'Printer 4',
|
||||
'model': 'P115',
|
||||
'location': 'Werk 040 - Berlin - TBA',
|
||||
'ip_address': '192.168.0.103',
|
||||
'mac_address': '98:254A:E1:2004',
|
||||
'plug_ip': '192.168.0.103',
|
||||
'plug_username': 'admin',
|
||||
'plug_password': 'admin',
|
||||
'status': 'offline',
|
||||
'active': 1
|
||||
},
|
||||
{
|
||||
'name': 'Printer 5',
|
||||
'model': 'P115',
|
||||
'location': 'Werk 040 - Berlin - TBA',
|
||||
'ip_address': '192.168.0.104',
|
||||
'mac_address': '98:254A:E1:2005',
|
||||
'plug_ip': '192.168.0.104',
|
||||
'plug_username': 'admin',
|
||||
'plug_password': 'admin',
|
||||
'status': 'offline',
|
||||
'active': 1
|
||||
},
|
||||
{
|
||||
'name': 'Printer 6',
|
||||
'model': 'P115',
|
||||
'location': 'Werk 040 - Berlin - TBA',
|
||||
'ip_address': '192.168.0.106',
|
||||
'mac_address': '98:254A:E1:2006',
|
||||
'plug_ip': '192.168.0.106',
|
||||
'plug_username': 'admin',
|
||||
'plug_password': 'admin',
|
||||
'status': 'offline',
|
||||
'active': 1
|
||||
}
|
||||
]
|
||||
|
||||
for printer in printers_to_add:
|
||||
try:
|
||||
cursor.execute("""
|
||||
INSERT INTO printers (name, model, location, ip_address, mac_address, plug_ip, plug_username, plug_password, status, active, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""", (
|
||||
printer['name'], printer['model'], printer['location'],
|
||||
printer['ip_address'], printer['mac_address'], printer['plug_ip'],
|
||||
printer['plug_username'], printer['plug_password'],
|
||||
printer['status'], printer['active'], datetime.now()
|
||||
))
|
||||
print(f"✅ Drucker {printer['name']} hinzugefügt")
|
||||
except Exception as e:
|
||||
print(f"⚠️ Fehler beim Hinzufügen von {printer['name']}: {e}")
|
||||
else:
|
||||
print(f"ℹ️ {printer_count} Drucker bereits vorhanden")
|
||||
|
||||
# 6. Optimierungen
|
||||
print("🔧 Führe Datenbankoptimierungen durch...")
|
||||
try:
|
||||
# Indizes erstellen
|
||||
indices = [
|
||||
"CREATE INDEX IF NOT EXISTS idx_users_email ON users(email)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_users_username ON users(username)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_jobs_user_id ON jobs(user_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_jobs_printer_id ON jobs(printer_id)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_jobs_status ON jobs(status)",
|
||||
"CREATE INDEX IF NOT EXISTS idx_guest_requests_status ON guest_requests(status)"
|
||||
]
|
||||
|
||||
for index_sql in indices:
|
||||
cursor.execute(index_sql)
|
||||
|
||||
# Statistiken aktualisieren
|
||||
cursor.execute("ANALYZE")
|
||||
print("✅ Datenbankoptimierungen abgeschlossen")
|
||||
|
||||
except Exception as e:
|
||||
print(f"⚠️ Fehler bei Optimierungen: {e}")
|
||||
|
||||
# Änderungen speichern
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
print("✅ Schnelle Datenbank-Reparatur erfolgreich abgeschlossen!")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Kritischer Fehler bei der Reparatur: {str(e)}")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
quick_fix_database()
|
293
backend/app/utils/update_requirements.py
Normal file
293
backend/app/utils/update_requirements.py
Normal file
@@ -0,0 +1,293 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
MYP Platform - Requirements Update Script
|
||||
Aktualisiert die Requirements basierend auf tatsächlich verwendeten Imports
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import ast
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
from typing import Set, List, Dict
|
||||
|
||||
def get_imports_from_file(file_path: Path) -> Set[str]:
|
||||
"""Extrahiert alle Import-Statements aus einer Python-Datei."""
|
||||
imports = set()
|
||||
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
tree = ast.parse(content)
|
||||
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.Import):
|
||||
for alias in node.names:
|
||||
imports.add(alias.name.split('.')[0])
|
||||
elif isinstance(node, ast.ImportFrom):
|
||||
if node.module:
|
||||
imports.add(node.module.split('.')[0])
|
||||
|
||||
except Exception as e:
|
||||
print(f"Fehler beim Parsen von {file_path}: {e}")
|
||||
|
||||
return imports
|
||||
|
||||
def get_all_imports(project_root: Path) -> Set[str]:
|
||||
"""Sammelt alle Imports aus dem Projekt."""
|
||||
all_imports = set()
|
||||
|
||||
# Wichtige Dateien analysieren
|
||||
important_files = [
|
||||
'app.py',
|
||||
'models.py',
|
||||
'utils/rate_limiter.py',
|
||||
'utils/job_scheduler.py',
|
||||
'utils/queue_manager.py',
|
||||
'utils/ssl_manager.py',
|
||||
'utils/security.py',
|
||||
'utils/permissions.py',
|
||||
'utils/analytics.py',
|
||||
'utils/template_helpers.py',
|
||||
'utils/logging_config.py'
|
||||
]
|
||||
|
||||
for file_path in important_files:
|
||||
full_path = project_root / file_path
|
||||
if full_path.exists():
|
||||
imports = get_imports_from_file(full_path)
|
||||
all_imports.update(imports)
|
||||
print(f"✓ Analysiert: {file_path} ({len(imports)} Imports)")
|
||||
|
||||
return all_imports
|
||||
|
||||
def get_package_mapping() -> Dict[str, str]:
|
||||
"""Mapping von Import-Namen zu PyPI-Paketnamen."""
|
||||
return {
|
||||
'flask': 'Flask',
|
||||
'flask_login': 'Flask-Login',
|
||||
'flask_wtf': 'Flask-WTF',
|
||||
'sqlalchemy': 'SQLAlchemy',
|
||||
'werkzeug': 'Werkzeug',
|
||||
'bcrypt': 'bcrypt',
|
||||
'cryptography': 'cryptography',
|
||||
'PyP100': 'PyP100',
|
||||
'redis': 'redis',
|
||||
'requests': 'requests',
|
||||
'jinja2': 'Jinja2',
|
||||
'markupsafe': 'MarkupSafe',
|
||||
'itsdangerous': 'itsdangerous',
|
||||
'psutil': 'psutil',
|
||||
'click': 'click',
|
||||
'blinker': 'blinker',
|
||||
'pywin32': 'pywin32',
|
||||
'pytest': 'pytest',
|
||||
'gunicorn': 'gunicorn'
|
||||
}
|
||||
|
||||
def get_current_versions() -> Dict[str, str]:
|
||||
"""Holt die aktuell installierten Versionen."""
|
||||
versions = {}
|
||||
|
||||
try:
|
||||
result = subprocess.run(['pip', 'list', '--format=freeze'],
|
||||
capture_output=True, text=True)
|
||||
|
||||
for line in result.stdout.strip().split('\n'):
|
||||
if '==' in line:
|
||||
package, version = line.split('==', 1)
|
||||
versions[package.lower()] = version
|
||||
|
||||
except Exception as e:
|
||||
print(f"Fehler beim Abrufen der Versionen: {e}")
|
||||
|
||||
return versions
|
||||
|
||||
def check_package_availability(package: str, version: str = None) -> bool:
|
||||
"""Prüft, ob ein Paket in der angegebenen Version verfügbar ist."""
|
||||
try:
|
||||
if version:
|
||||
cmd = ['pip', 'index', 'versions', package]
|
||||
else:
|
||||
cmd = ['pip', 'show', package]
|
||||
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
return result.returncode == 0
|
||||
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def generate_requirements(imports: Set[str], versions: Dict[str, str]) -> List[str]:
|
||||
"""Generiert die Requirements-Liste."""
|
||||
package_mapping = get_package_mapping()
|
||||
requirements = []
|
||||
|
||||
# Standard-Bibliotheken, die nicht installiert werden müssen
|
||||
stdlib_modules = {
|
||||
'os', 'sys', 'logging', 'atexit', 'datetime', 'time', 'subprocess',
|
||||
'json', 'signal', 'threading', 'functools', 'typing', 'contextlib',
|
||||
'secrets', 'hashlib', 'calendar', 'random', 'socket', 'ipaddress',
|
||||
'enum', 'dataclasses', 'concurrent', 'collections'
|
||||
}
|
||||
|
||||
# Lokale Module ausschließen
|
||||
local_modules = {
|
||||
'models', 'utils', 'config', 'blueprints'
|
||||
}
|
||||
|
||||
# Nur externe Pakete berücksichtigen
|
||||
external_imports = imports - stdlib_modules - local_modules
|
||||
|
||||
for import_name in sorted(external_imports):
|
||||
package_name = package_mapping.get(import_name, import_name)
|
||||
|
||||
# Version aus installierten Paketen holen
|
||||
version = versions.get(package_name.lower())
|
||||
|
||||
if version and check_package_availability(package_name, version):
|
||||
if package_name == 'pywin32':
|
||||
requirements.append(f"{package_name}=={version}; sys_platform == \"win32\"")
|
||||
else:
|
||||
requirements.append(f"{package_name}=={version}")
|
||||
else:
|
||||
print(f"⚠️ Paket {package_name} nicht gefunden oder Version unbekannt")
|
||||
|
||||
return requirements
|
||||
|
||||
def write_requirements_file(requirements: List[str], output_file: Path):
|
||||
"""Schreibt die Requirements in eine Datei."""
|
||||
header = """# MYP Platform - Python Dependencies
|
||||
# Basierend auf tatsächlich verwendeten Imports in app.py
|
||||
# Automatisch generiert am: {date}
|
||||
# Installiere mit: pip install -r requirements.txt
|
||||
|
||||
# ===== CORE FLASK FRAMEWORK =====
|
||||
# Direkt in app.py verwendet
|
||||
{flask_requirements}
|
||||
|
||||
# ===== DATENBANK =====
|
||||
# SQLAlchemy für Datenbankoperationen (models.py, app.py)
|
||||
{db_requirements}
|
||||
|
||||
# ===== SICHERHEIT UND AUTHENTIFIZIERUNG =====
|
||||
# Werkzeug für Passwort-Hashing und Utilities (app.py)
|
||||
{security_requirements}
|
||||
|
||||
# ===== SMART PLUG STEUERUNG =====
|
||||
# PyP100 für TP-Link Tapo Smart Plugs (utils/job_scheduler.py)
|
||||
{smartplug_requirements}
|
||||
|
||||
# ===== RATE LIMITING UND CACHING =====
|
||||
# Redis für Rate Limiting (utils/rate_limiter.py) - optional
|
||||
{cache_requirements}
|
||||
|
||||
# ===== HTTP REQUESTS =====
|
||||
# Requests für HTTP-Anfragen (utils/queue_manager.py, utils/debug_drucker_erkennung.py)
|
||||
{http_requirements}
|
||||
|
||||
# ===== TEMPLATE ENGINE =====
|
||||
# Jinja2 und MarkupSafe (automatisch mit Flask installiert, aber explizit für utils/template_helpers.py)
|
||||
{template_requirements}
|
||||
|
||||
# ===== SYSTEM MONITORING =====
|
||||
# psutil für System-Monitoring (utils/debug_utils.py, utils/debug_cli.py)
|
||||
{monitoring_requirements}
|
||||
|
||||
# ===== ZUSÄTZLICHE CORE ABHÄNGIGKEITEN =====
|
||||
# Click für CLI-Kommandos (automatisch mit Flask)
|
||||
{core_requirements}
|
||||
|
||||
# ===== WINDOWS-SPEZIFISCHE ABHÄNGIGKEITEN =====
|
||||
# Nur für Windows-Systeme erforderlich
|
||||
{windows_requirements}
|
||||
|
||||
# ===== OPTIONAL: ENTWICKLUNG UND TESTING =====
|
||||
# Nur für Entwicklungsumgebung
|
||||
{dev_requirements}
|
||||
|
||||
# ===== OPTIONAL: PRODUKTIONS-SERVER =====
|
||||
# Gunicorn für Produktionsumgebung
|
||||
{prod_requirements}
|
||||
"""
|
||||
|
||||
# Requirements kategorisieren
|
||||
flask_reqs = [r for r in requirements if any(x in r.lower() for x in ['flask'])]
|
||||
db_reqs = [r for r in requirements if 'SQLAlchemy' in r]
|
||||
security_reqs = [r for r in requirements if any(x in r for x in ['Werkzeug', 'bcrypt', 'cryptography'])]
|
||||
smartplug_reqs = [r for r in requirements if 'PyP100' in r]
|
||||
cache_reqs = [r for r in requirements if 'redis' in r]
|
||||
http_reqs = [r for r in requirements if 'requests' in r]
|
||||
template_reqs = [r for r in requirements if any(x in r for x in ['Jinja2', 'MarkupSafe', 'itsdangerous'])]
|
||||
monitoring_reqs = [r for r in requirements if 'psutil' in r]
|
||||
core_reqs = [r for r in requirements if any(x in r for x in ['click', 'blinker'])]
|
||||
windows_reqs = [r for r in requirements if 'sys_platform' in r]
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
content = header.format(
|
||||
date=datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
||||
flask_requirements='\n'.join(flask_reqs) or '# Keine Flask-spezifischen Requirements',
|
||||
db_requirements='\n'.join(db_reqs) or '# Keine Datenbank-Requirements',
|
||||
security_requirements='\n'.join(security_reqs) or '# Keine Sicherheits-Requirements',
|
||||
smartplug_requirements='\n'.join(smartplug_reqs) or '# Keine Smart Plug Requirements',
|
||||
cache_requirements='\n'.join(cache_reqs) or '# Keine Cache-Requirements',
|
||||
http_requirements='\n'.join(http_reqs) or '# Keine HTTP-Requirements',
|
||||
template_requirements='\n'.join(template_reqs) or '# Keine Template-Requirements',
|
||||
monitoring_requirements='\n'.join(monitoring_reqs) or '# Keine Monitoring-Requirements',
|
||||
core_requirements='\n'.join(core_reqs) or '# Keine Core-Requirements',
|
||||
windows_requirements='\n'.join(windows_reqs) or '# Keine Windows-Requirements',
|
||||
dev_requirements='pytest==8.3.4; extra == "dev"\npytest-cov==6.0.0; extra == "dev"',
|
||||
prod_requirements='gunicorn==23.0.0; extra == "prod"'
|
||||
)
|
||||
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
def main():
|
||||
"""Hauptfunktion."""
|
||||
print("🔄 MYP Platform Requirements Update")
|
||||
print("=" * 50)
|
||||
|
||||
# Projekt-Root ermitteln
|
||||
project_root = Path(__file__).parent
|
||||
|
||||
print(f"📁 Projekt-Verzeichnis: {project_root}")
|
||||
|
||||
# Imports sammeln
|
||||
print("\n📋 Sammle Imports aus wichtigen Dateien...")
|
||||
imports = get_all_imports(project_root)
|
||||
|
||||
print(f"\n📦 Gefundene externe Imports: {len(imports)}")
|
||||
for imp in sorted(imports):
|
||||
print(f" - {imp}")
|
||||
|
||||
# Aktuelle Versionen abrufen
|
||||
print("\n🔍 Prüfe installierte Versionen...")
|
||||
versions = get_current_versions()
|
||||
|
||||
# Requirements generieren
|
||||
print("\n⚙️ Generiere Requirements...")
|
||||
requirements = generate_requirements(imports, versions)
|
||||
|
||||
# Requirements-Datei schreiben
|
||||
output_file = project_root / 'requirements.txt'
|
||||
write_requirements_file(requirements, output_file)
|
||||
|
||||
print(f"\n✅ Requirements aktualisiert: {output_file}")
|
||||
print(f"📊 {len(requirements)} Pakete in requirements.txt")
|
||||
|
||||
# Zusammenfassung
|
||||
print("\n📋 Generierte Requirements:")
|
||||
for req in requirements:
|
||||
print(f" - {req}")
|
||||
|
||||
print("\n🎉 Requirements-Update abgeschlossen!")
|
||||
print("\nNächste Schritte:")
|
||||
print("1. pip install -r requirements.txt")
|
||||
print("2. Anwendung testen")
|
||||
print("3. requirements-dev.txt und requirements-prod.txt bei Bedarf anpassen")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Reference in New Issue
Block a user