DB Sortsystem
Dieser Commit ist enthalten in:
@@ -1323,8 +1323,31 @@ def licenses():
|
||||
filter_type = request.args.get('type', '')
|
||||
filter_status = request.args.get('status', '')
|
||||
page = request.args.get('page', 1, type=int)
|
||||
sort = request.args.get('sort', 'valid_until')
|
||||
order = request.args.get('order', 'desc')
|
||||
per_page = 20
|
||||
|
||||
# Whitelist für erlaubte Sortierfelder
|
||||
allowed_sort_fields = {
|
||||
'id': 'l.id',
|
||||
'license_key': 'l.license_key',
|
||||
'customer': 'c.name',
|
||||
'email': 'c.email',
|
||||
'type': 'l.license_type',
|
||||
'valid_from': 'l.valid_from',
|
||||
'valid_until': 'l.valid_until',
|
||||
'status': 'status',
|
||||
'active': 'l.is_active'
|
||||
}
|
||||
|
||||
# Validierung
|
||||
if sort not in allowed_sort_fields:
|
||||
sort = 'valid_until'
|
||||
if order not in ['asc', 'desc']:
|
||||
order = 'desc'
|
||||
|
||||
sort_field = allowed_sort_fields[sort]
|
||||
|
||||
# SQL Query mit optionaler Suche und Filtern
|
||||
query = """
|
||||
SELECT l.id, l.license_key, c.name, c.email, l.license_type,
|
||||
@@ -1374,7 +1397,20 @@ def licenses():
|
||||
|
||||
# Pagination
|
||||
offset = (page - 1) * per_page
|
||||
query += " ORDER BY l.valid_until DESC LIMIT %s OFFSET %s"
|
||||
|
||||
# Spezialbehandlung für berechnete Felder
|
||||
if sort == 'status':
|
||||
# Für Status müssen wir die CASE-Bedingung in ORDER BY wiederholen
|
||||
query += f""" ORDER BY
|
||||
CASE
|
||||
WHEN l.is_active = FALSE THEN 'deaktiviert'
|
||||
WHEN l.valid_until < CURRENT_DATE THEN 'abgelaufen'
|
||||
WHEN l.valid_until < CURRENT_DATE + INTERVAL '30 days' THEN 'läuft bald ab'
|
||||
ELSE 'aktiv'
|
||||
END {order.upper()} LIMIT %s OFFSET %s"""
|
||||
else:
|
||||
query += f" ORDER BY {sort_field} {order.upper()} LIMIT %s OFFSET %s"
|
||||
|
||||
params.extend([per_page, offset])
|
||||
|
||||
cur.execute(query, params)
|
||||
@@ -1394,6 +1430,8 @@ def licenses():
|
||||
page=page,
|
||||
total_pages=total_pages,
|
||||
total=total,
|
||||
sort=sort,
|
||||
order=order,
|
||||
username=session.get('username'))
|
||||
|
||||
@app.route("/license/edit/<int:license_id>", methods=["GET", "POST"])
|
||||
@@ -1508,8 +1546,28 @@ def customers():
|
||||
# Parameter
|
||||
search = request.args.get('search', '').strip()
|
||||
page = request.args.get('page', 1, type=int)
|
||||
sort = request.args.get('sort', 'created_at')
|
||||
order = request.args.get('order', 'desc')
|
||||
per_page = 20
|
||||
|
||||
# Whitelist für erlaubte Sortierfelder
|
||||
allowed_sort_fields = {
|
||||
'id': 'c.id',
|
||||
'name': 'c.name',
|
||||
'email': 'c.email',
|
||||
'created_at': 'c.created_at',
|
||||
'licenses': 'license_count',
|
||||
'active_licenses': 'active_licenses'
|
||||
}
|
||||
|
||||
# Validierung
|
||||
if sort not in allowed_sort_fields:
|
||||
sort = 'created_at'
|
||||
if order not in ['asc', 'desc']:
|
||||
order = 'desc'
|
||||
|
||||
sort_field = allowed_sort_fields[sort]
|
||||
|
||||
# SQL Query mit optionaler Suche
|
||||
base_query = """
|
||||
SELECT c.id, c.name, c.email, c.created_at,
|
||||
@@ -1544,9 +1602,9 @@ def customers():
|
||||
|
||||
# Pagination
|
||||
offset = (page - 1) * per_page
|
||||
query = base_query + """
|
||||
query = base_query + f"""
|
||||
GROUP BY c.id, c.name, c.email, c.created_at
|
||||
ORDER BY c.created_at DESC
|
||||
ORDER BY {sort_field} {order.upper()}
|
||||
LIMIT %s OFFSET %s
|
||||
"""
|
||||
params.extend([per_page, offset])
|
||||
@@ -1566,6 +1624,8 @@ def customers():
|
||||
page=page,
|
||||
total_pages=total_pages,
|
||||
total=total,
|
||||
sort=sort,
|
||||
order=order,
|
||||
username=session.get('username'))
|
||||
|
||||
@app.route("/customer/edit/<int:customer_id>", methods=["GET", "POST"])
|
||||
@@ -1678,8 +1738,44 @@ def sessions():
|
||||
conn = get_connection()
|
||||
cur = conn.cursor()
|
||||
|
||||
# Sortierparameter
|
||||
active_sort = request.args.get('active_sort', 'last_heartbeat')
|
||||
active_order = request.args.get('active_order', 'desc')
|
||||
ended_sort = request.args.get('ended_sort', 'ended_at')
|
||||
ended_order = request.args.get('ended_order', 'desc')
|
||||
|
||||
# Whitelist für erlaubte Sortierfelder - Aktive Sessions
|
||||
active_sort_fields = {
|
||||
'customer': 'c.name',
|
||||
'license': 'l.license_key',
|
||||
'ip': 's.ip_address',
|
||||
'started': 's.started_at',
|
||||
'last_heartbeat': 's.last_heartbeat',
|
||||
'inactive': 'minutes_inactive'
|
||||
}
|
||||
|
||||
# Whitelist für erlaubte Sortierfelder - Beendete Sessions
|
||||
ended_sort_fields = {
|
||||
'customer': 'c.name',
|
||||
'license': 'l.license_key',
|
||||
'ip': 's.ip_address',
|
||||
'started': 's.started_at',
|
||||
'ended_at': 's.ended_at',
|
||||
'duration': 'duration_minutes'
|
||||
}
|
||||
|
||||
# Validierung
|
||||
if active_sort not in active_sort_fields:
|
||||
active_sort = 'last_heartbeat'
|
||||
if ended_sort not in ended_sort_fields:
|
||||
ended_sort = 'ended_at'
|
||||
if active_order not in ['asc', 'desc']:
|
||||
active_order = 'desc'
|
||||
if ended_order not in ['asc', 'desc']:
|
||||
ended_order = 'desc'
|
||||
|
||||
# Aktive Sessions abrufen
|
||||
cur.execute("""
|
||||
cur.execute(f"""
|
||||
SELECT s.id, s.session_id, l.license_key, c.name, s.ip_address,
|
||||
s.user_agent, s.started_at, s.last_heartbeat,
|
||||
EXTRACT(EPOCH FROM (NOW() - s.last_heartbeat))/60 as minutes_inactive
|
||||
@@ -1687,12 +1783,12 @@ def sessions():
|
||||
JOIN licenses l ON s.license_id = l.id
|
||||
JOIN customers c ON l.customer_id = c.id
|
||||
WHERE s.is_active = TRUE
|
||||
ORDER BY s.last_heartbeat DESC
|
||||
ORDER BY {active_sort_fields[active_sort]} {active_order.upper()}
|
||||
""")
|
||||
active_sessions = cur.fetchall()
|
||||
|
||||
# Inaktive Sessions der letzten 24 Stunden
|
||||
cur.execute("""
|
||||
cur.execute(f"""
|
||||
SELECT s.id, s.session_id, l.license_key, c.name, s.ip_address,
|
||||
s.started_at, s.ended_at,
|
||||
EXTRACT(EPOCH FROM (s.ended_at - s.started_at))/60 as duration_minutes
|
||||
@@ -1701,7 +1797,7 @@ def sessions():
|
||||
JOIN customers c ON l.customer_id = c.id
|
||||
WHERE s.is_active = FALSE
|
||||
AND s.ended_at > NOW() - INTERVAL '24 hours'
|
||||
ORDER BY s.ended_at DESC
|
||||
ORDER BY {ended_sort_fields[ended_sort]} {ended_order.upper()}
|
||||
LIMIT 50
|
||||
""")
|
||||
recent_sessions = cur.fetchall()
|
||||
@@ -1712,6 +1808,10 @@ def sessions():
|
||||
return render_template("sessions.html",
|
||||
active_sessions=active_sessions,
|
||||
recent_sessions=recent_sessions,
|
||||
active_sort=active_sort,
|
||||
active_order=active_order,
|
||||
ended_sort=ended_sort,
|
||||
ended_order=ended_order,
|
||||
username=session.get('username'))
|
||||
|
||||
@app.route("/session/end/<int:session_id>", methods=["POST"])
|
||||
@@ -1914,8 +2014,27 @@ def audit_log():
|
||||
filter_action = request.args.get('action', '').strip()
|
||||
filter_entity = request.args.get('entity', '').strip()
|
||||
page = request.args.get('page', 1, type=int)
|
||||
sort = request.args.get('sort', 'timestamp')
|
||||
order = request.args.get('order', 'desc')
|
||||
per_page = 50
|
||||
|
||||
# Whitelist für erlaubte Sortierfelder
|
||||
allowed_sort_fields = {
|
||||
'timestamp': 'timestamp',
|
||||
'username': 'username',
|
||||
'action': 'action',
|
||||
'entity': 'entity_type',
|
||||
'ip': 'ip_address'
|
||||
}
|
||||
|
||||
# Validierung
|
||||
if sort not in allowed_sort_fields:
|
||||
sort = 'timestamp'
|
||||
if order not in ['asc', 'desc']:
|
||||
order = 'desc'
|
||||
|
||||
sort_field = allowed_sort_fields[sort]
|
||||
|
||||
# SQL Query mit optionalen Filtern
|
||||
query = """
|
||||
SELECT id, timestamp, username, action, entity_type, entity_id,
|
||||
@@ -1946,7 +2065,7 @@ def audit_log():
|
||||
|
||||
# Pagination
|
||||
offset = (page - 1) * per_page
|
||||
query += " ORDER BY timestamp DESC LIMIT %s OFFSET %s"
|
||||
query += f" ORDER BY {sort_field} {order.upper()} LIMIT %s OFFSET %s"
|
||||
params.extend([per_page, offset])
|
||||
|
||||
cur.execute(query, params)
|
||||
@@ -1974,6 +2093,8 @@ def audit_log():
|
||||
page=page,
|
||||
total_pages=total_pages,
|
||||
total=total,
|
||||
sort=sort,
|
||||
order=order,
|
||||
username=session.get('username'))
|
||||
|
||||
@app.route("/backups")
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren