Refactoring - Fix1
Dieser Commit ist enthalten in:
BIN
v2_adminpanel/routes/__pycache__/__init__.cpython-312.pyc
Normale Datei
BIN
v2_adminpanel/routes/__pycache__/__init__.cpython-312.pyc
Normale Datei
Binäre Datei nicht angezeigt.
BIN
v2_adminpanel/routes/__pycache__/customer_routes.cpython-312.pyc
Normale Datei
BIN
v2_adminpanel/routes/__pycache__/customer_routes.cpython-312.pyc
Normale Datei
Binäre Datei nicht angezeigt.
@@ -20,8 +20,9 @@ admin_bp = Blueprint('admin', __name__)
|
||||
@login_required
|
||||
def dashboard():
|
||||
try:
|
||||
with get_db_connection() as conn:
|
||||
with get_db_cursor(conn) as cur:
|
||||
conn = get_connection()
|
||||
cur = conn.cursor()
|
||||
try:
|
||||
# Hole Statistiken mit sicheren Defaults
|
||||
# Anzahl aktiver Lizenzen
|
||||
cur.execute("SELECT COUNT(*) FROM licenses WHERE is_active = true")
|
||||
@@ -123,6 +124,9 @@ def dashboard():
|
||||
hourly_sessions=hourly_sessions,
|
||||
resource_stats=resource_stats,
|
||||
username=session.get('username'))
|
||||
finally:
|
||||
cur.close()
|
||||
conn.close()
|
||||
|
||||
except Exception as e:
|
||||
current_app.logger.error(f"Dashboard error: {str(e)}")
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import os
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from zoneinfo import ZoneInfo
|
||||
@@ -12,6 +13,11 @@ from models import get_customers, get_customer_by_id
|
||||
# Create Blueprint
|
||||
customer_bp = Blueprint('customers', __name__)
|
||||
|
||||
# Test route
|
||||
@customer_bp.route("/test-customers")
|
||||
def test_customers():
|
||||
return "Customer blueprint is working!"
|
||||
|
||||
|
||||
@customer_bp.route("/customers")
|
||||
@login_required
|
||||
@@ -23,9 +29,6 @@ def customers():
|
||||
@customer_bp.route("/customer/edit/<int:customer_id>", methods=["GET", "POST"])
|
||||
@login_required
|
||||
def edit_customer(customer_id):
|
||||
conn = get_connection()
|
||||
cur = conn.cursor()
|
||||
|
||||
if request.method == "POST":
|
||||
try:
|
||||
# Get current customer data for comparison
|
||||
@@ -34,51 +37,44 @@ def edit_customer(customer_id):
|
||||
flash('Kunde nicht gefunden!', 'error')
|
||||
return redirect(url_for('customers.customers'))
|
||||
|
||||
# Update customer data
|
||||
new_values = {
|
||||
'name': request.form['name'],
|
||||
'email': request.form['email'],
|
||||
'phone': request.form.get('phone', ''),
|
||||
'address': request.form.get('address', ''),
|
||||
'notes': request.form.get('notes', '')
|
||||
}
|
||||
|
||||
cur.execute("""
|
||||
UPDATE customers
|
||||
SET name = %s, email = %s, phone = %s, address = %s, notes = %s
|
||||
WHERE id = %s
|
||||
""", (
|
||||
new_values['name'],
|
||||
new_values['email'],
|
||||
new_values['phone'],
|
||||
new_values['address'],
|
||||
new_values['notes'],
|
||||
customer_id
|
||||
))
|
||||
|
||||
conn.commit()
|
||||
|
||||
# Log changes
|
||||
log_audit('UPDATE', 'customer', customer_id,
|
||||
old_values={
|
||||
'name': current_customer['name'],
|
||||
'email': current_customer['email'],
|
||||
'phone': current_customer.get('phone', ''),
|
||||
'address': current_customer.get('address', ''),
|
||||
'notes': current_customer.get('notes', '')
|
||||
},
|
||||
new_values=new_values)
|
||||
|
||||
flash('Kunde erfolgreich aktualisiert!', 'success')
|
||||
return redirect(url_for('customers.customers'))
|
||||
|
||||
with get_db_connection() as conn:
|
||||
cur = conn.cursor()
|
||||
try:
|
||||
# Update customer data (nur name und email existieren in der DB)
|
||||
new_values = {
|
||||
'name': request.form['name'],
|
||||
'email': request.form['email']
|
||||
}
|
||||
|
||||
cur.execute("""
|
||||
UPDATE customers
|
||||
SET name = %s, email = %s
|
||||
WHERE id = %s
|
||||
""", (
|
||||
new_values['name'],
|
||||
new_values['email'],
|
||||
customer_id
|
||||
))
|
||||
|
||||
conn.commit()
|
||||
|
||||
# Log changes
|
||||
log_audit('UPDATE', 'customer', customer_id,
|
||||
old_values={
|
||||
'name': current_customer['name'],
|
||||
'email': current_customer['email']
|
||||
},
|
||||
new_values=new_values)
|
||||
|
||||
flash('Kunde erfolgreich aktualisiert!', 'success')
|
||||
return redirect(url_for('customers.customers'))
|
||||
finally:
|
||||
cur.close()
|
||||
|
||||
except Exception as e:
|
||||
conn.rollback()
|
||||
logging.error(f"Fehler beim Aktualisieren des Kunden: {str(e)}")
|
||||
flash('Fehler beim Aktualisieren des Kunden!', 'error')
|
||||
finally:
|
||||
cur.close()
|
||||
conn.close()
|
||||
return redirect(url_for('customers.customers'))
|
||||
|
||||
# GET request
|
||||
customer_data = get_customer_by_id(customer_id)
|
||||
@@ -100,15 +96,12 @@ def create_customer():
|
||||
# Insert new customer
|
||||
name = request.form['name']
|
||||
email = request.form['email']
|
||||
phone = request.form.get('phone', '')
|
||||
address = request.form.get('address', '')
|
||||
notes = request.form.get('notes', '')
|
||||
|
||||
cur.execute("""
|
||||
INSERT INTO customers (name, email, phone, address, notes, created_at)
|
||||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
INSERT INTO customers (name, email, created_at)
|
||||
VALUES (%s, %s, %s)
|
||||
RETURNING id
|
||||
""", (name, email, phone, address, notes, datetime.now()))
|
||||
""", (name, email, datetime.now()))
|
||||
|
||||
customer_id = cur.fetchone()[0]
|
||||
conn.commit()
|
||||
@@ -117,10 +110,7 @@ def create_customer():
|
||||
log_audit('CREATE', 'customer', customer_id,
|
||||
new_values={
|
||||
'name': name,
|
||||
'email': email,
|
||||
'phone': phone,
|
||||
'address': address,
|
||||
'notes': notes
|
||||
'email': email
|
||||
})
|
||||
|
||||
flash(f'Kunde {name} erfolgreich erstellt!', 'success')
|
||||
@@ -187,49 +177,69 @@ def delete_customer(customer_id):
|
||||
@login_required
|
||||
def customers_licenses():
|
||||
"""Zeigt die Übersicht von Kunden und deren Lizenzen"""
|
||||
conn = get_connection()
|
||||
cur = conn.cursor()
|
||||
import logging
|
||||
import psycopg2
|
||||
logging.info("=== CUSTOMERS-LICENSES ROUTE CALLED ===")
|
||||
|
||||
try:
|
||||
# Hole alle Kunden mit ihren Lizenzen
|
||||
cur.execute("""
|
||||
SELECT
|
||||
c.id as customer_id,
|
||||
c.name as customer_name,
|
||||
c.email as customer_email,
|
||||
c.created_at as customer_created,
|
||||
COUNT(l.id) as license_count,
|
||||
COUNT(CASE WHEN l.active = true THEN 1 END) as active_licenses,
|
||||
COUNT(CASE WHEN l.is_test = true THEN 1 END) as test_licenses,
|
||||
MAX(l.created_at) as last_license_created
|
||||
FROM customers c
|
||||
LEFT JOIN licenses l ON c.id = l.customer_id
|
||||
GROUP BY c.id, c.name, c.email, c.created_at
|
||||
ORDER BY c.name
|
||||
""")
|
||||
# Direkte Verbindung ohne Helper-Funktionen
|
||||
conn = psycopg2.connect(
|
||||
host=os.getenv("POSTGRES_HOST", "postgres"),
|
||||
port=os.getenv("POSTGRES_PORT", "5432"),
|
||||
dbname=os.getenv("POSTGRES_DB"),
|
||||
user=os.getenv("POSTGRES_USER"),
|
||||
password=os.getenv("POSTGRES_PASSWORD")
|
||||
)
|
||||
conn.set_client_encoding('UTF8')
|
||||
cur = conn.cursor()
|
||||
|
||||
customers = []
|
||||
for row in cur.fetchall():
|
||||
customers.append({
|
||||
'id': row[0],
|
||||
'name': row[1],
|
||||
'email': row[2],
|
||||
'created_at': row[3],
|
||||
'license_count': row[4],
|
||||
'active_licenses': row[5],
|
||||
'test_licenses': row[6],
|
||||
'last_license_created': row[7]
|
||||
})
|
||||
|
||||
return render_template("customers_licenses.html", customers=customers)
|
||||
try:
|
||||
# Hole alle Kunden mit ihren Lizenzen
|
||||
cur.execute("""
|
||||
SELECT
|
||||
c.id,
|
||||
c.name,
|
||||
c.email,
|
||||
c.created_at,
|
||||
COUNT(l.id),
|
||||
COUNT(CASE WHEN l.is_active = true THEN 1 END),
|
||||
COUNT(CASE WHEN l.is_test = true THEN 1 END),
|
||||
MAX(l.created_at)
|
||||
FROM customers c
|
||||
LEFT JOIN licenses l ON c.id = l.customer_id
|
||||
GROUP BY c.id, c.name, c.email, c.created_at
|
||||
ORDER BY c.name
|
||||
""")
|
||||
|
||||
customers = []
|
||||
results = cur.fetchall()
|
||||
logging.info(f"=== QUERY RETURNED {len(results)} ROWS ===")
|
||||
|
||||
for idx, row in enumerate(results):
|
||||
logging.info(f"Row {idx}: Type={type(row)}, Length={len(row) if hasattr(row, '__len__') else 'N/A'}")
|
||||
customers.append({
|
||||
'id': row[0],
|
||||
'name': row[1],
|
||||
'email': row[2],
|
||||
'created_at': row[3],
|
||||
'license_count': row[4],
|
||||
'active_licenses': row[5],
|
||||
'test_licenses': row[6],
|
||||
'last_license_created': row[7]
|
||||
})
|
||||
|
||||
return render_template("customers_licenses.html", customers=customers)
|
||||
|
||||
finally:
|
||||
cur.close()
|
||||
conn.close()
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Fehler beim Laden der Kunden-Lizenz-Übersicht: {str(e)}")
|
||||
flash('Fehler beim Laden der Daten!', 'error')
|
||||
import traceback
|
||||
error_details = f"Fehler beim Laden der Kunden-Lizenz-Übersicht: {str(e)}\nType: {type(e)}\nTraceback: {traceback.format_exc()}"
|
||||
logging.error(error_details)
|
||||
flash(f'Datenbankfehler: {str(e)}', 'error')
|
||||
return redirect(url_for('admin.dashboard'))
|
||||
finally:
|
||||
cur.close()
|
||||
conn.close()
|
||||
|
||||
|
||||
@customer_bp.route("/api/customer/<int:customer_id>/licenses")
|
||||
@@ -251,17 +261,17 @@ def api_customer_licenses(customer_id):
|
||||
l.id,
|
||||
l.license_key,
|
||||
l.license_type,
|
||||
l.active,
|
||||
l.is_active,
|
||||
l.is_test,
|
||||
l.valid_from,
|
||||
l.valid_until,
|
||||
l.device_limit,
|
||||
l.created_at,
|
||||
(SELECT COUNT(*) FROM sessions s WHERE s.license_key = l.license_key AND s.active = true) as active_sessions,
|
||||
(SELECT COUNT(DISTINCT device_id) FROM sessions s WHERE s.license_key = l.license_key) as registered_devices,
|
||||
(SELECT COUNT(*) FROM sessions s WHERE s.license_key = l.license_key AND s.is_active = true) as active_sessions,
|
||||
(SELECT COUNT(DISTINCT hardware_id) FROM sessions s WHERE s.license_key = l.license_key) as registered_devices,
|
||||
CASE
|
||||
WHEN l.valid_until < CURRENT_DATE THEN 'expired'
|
||||
WHEN l.active = false THEN 'inactive'
|
||||
WHEN l.is_active = false THEN 'inactive'
|
||||
ELSE 'active'
|
||||
END as status
|
||||
FROM licenses l
|
||||
@@ -314,7 +324,7 @@ def api_customer_quick_stats(customer_id):
|
||||
cur.execute("""
|
||||
SELECT
|
||||
COUNT(l.id) as total_licenses,
|
||||
COUNT(CASE WHEN l.active = true THEN 1 END) as active_licenses,
|
||||
COUNT(CASE WHEN l.is_active = true THEN 1 END) as active_licenses,
|
||||
COUNT(CASE WHEN l.is_test = true THEN 1 END) as test_licenses,
|
||||
SUM(l.device_limit) as total_device_limit
|
||||
FROM licenses l
|
||||
|
||||
@@ -133,54 +133,55 @@ def resources():
|
||||
def add_resource():
|
||||
"""Neue Ressource hinzufügen"""
|
||||
if request.method == 'POST':
|
||||
conn = get_connection()
|
||||
cur = conn.cursor()
|
||||
|
||||
try:
|
||||
resource_type = request.form['resource_type']
|
||||
resource_value = request.form['resource_value'].strip()
|
||||
is_test = 'is_test' in request.form
|
||||
|
||||
# Prüfe ob Ressource bereits existiert
|
||||
cur.execute("""
|
||||
SELECT id FROM resource_pools
|
||||
WHERE resource_type = %s AND resource_value = %s
|
||||
""", (resource_type, resource_value))
|
||||
|
||||
if cur.fetchone():
|
||||
flash(f'Ressource {resource_value} existiert bereits!', 'error')
|
||||
return redirect(url_for('resources.add_resource'))
|
||||
|
||||
# Füge neue Ressource hinzu
|
||||
cur.execute("""
|
||||
INSERT INTO resource_pools (resource_type, resource_value, status, is_test, created_by)
|
||||
VALUES (%s, %s, 'available', %s, %s)
|
||||
RETURNING id
|
||||
""", (resource_type, resource_value, is_test, session['username']))
|
||||
|
||||
resource_id = cur.fetchone()[0]
|
||||
conn.commit()
|
||||
|
||||
# Audit-Log
|
||||
log_audit('CREATE', 'resource', resource_id,
|
||||
new_values={
|
||||
'resource_type': resource_type,
|
||||
'resource_value': resource_value,
|
||||
'is_test': is_test
|
||||
})
|
||||
|
||||
flash(f'Ressource {resource_value} erfolgreich hinzugefügt!', 'success')
|
||||
return redirect(url_for('resources.resources'))
|
||||
|
||||
with get_db_connection() as conn:
|
||||
cur = conn.cursor()
|
||||
try:
|
||||
resource_type = request.form['resource_type']
|
||||
resource_value = request.form['resource_value'].strip()
|
||||
is_test = 'is_test' in request.form
|
||||
|
||||
# Prüfe ob Ressource bereits existiert
|
||||
cur.execute("""
|
||||
SELECT id FROM resource_pools
|
||||
WHERE resource_type = %s AND resource_value = %s
|
||||
""", (resource_type, resource_value))
|
||||
|
||||
if cur.fetchone():
|
||||
flash(f'Ressource {resource_value} existiert bereits!', 'error')
|
||||
return redirect(url_for('resources.add_resource'))
|
||||
|
||||
# Füge neue Ressource hinzu (ohne created_by)
|
||||
cur.execute("""
|
||||
INSERT INTO resource_pools (resource_type, resource_value, status, is_test, status_changed_by)
|
||||
VALUES (%s, %s, 'available', %s, %s)
|
||||
RETURNING id
|
||||
""", (resource_type, resource_value, is_test, session.get('username', 'system')))
|
||||
|
||||
resource_id = cur.fetchone()[0]
|
||||
conn.commit()
|
||||
|
||||
# Audit-Log
|
||||
log_audit('CREATE', 'resource', resource_id,
|
||||
new_values={
|
||||
'resource_type': resource_type,
|
||||
'resource_value': resource_value,
|
||||
'is_test': is_test
|
||||
})
|
||||
|
||||
flash(f'Ressource {resource_value} erfolgreich hinzugefügt!', 'success')
|
||||
return redirect(url_for('resources.resources'))
|
||||
finally:
|
||||
cur.close()
|
||||
|
||||
except Exception as e:
|
||||
conn.rollback()
|
||||
import traceback
|
||||
logging.error(f"Fehler beim Hinzufügen der Ressource: {str(e)}")
|
||||
flash('Fehler beim Hinzufügen der Ressource!', 'error')
|
||||
finally:
|
||||
cur.close()
|
||||
conn.close()
|
||||
logging.error(f"Traceback: {traceback.format_exc()}")
|
||||
flash(f'Fehler: {str(e)}', 'error')
|
||||
return redirect(url_for('resources.resources'))
|
||||
|
||||
return render_template('add_resource.html')
|
||||
return render_template('add_resources.html')
|
||||
|
||||
|
||||
@resource_bp.route('/resources/quarantine/<int:resource_id>', methods=['POST'])
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren