Löschen Lizenz Schutz
Dieser Commit ist enthalten in:
@@ -375,9 +375,11 @@ def deactivate_device(license_id, device_id):
|
||||
@api_bp.route("/licenses/bulk-delete", methods=["POST"])
|
||||
@login_required
|
||||
def bulk_delete_licenses():
|
||||
"""Lösche mehrere Lizenzen gleichzeitig"""
|
||||
"""Lösche mehrere Lizenzen gleichzeitig mit Sicherheitsprüfungen"""
|
||||
data = request.get_json()
|
||||
license_ids = data.get('license_ids', [])
|
||||
# Accept both 'ids' (from frontend) and 'license_ids' for compatibility
|
||||
license_ids = data.get('ids', data.get('license_ids', []))
|
||||
force_delete = data.get('force', False)
|
||||
|
||||
if not license_ids:
|
||||
return jsonify({'error': 'Keine Lizenzen ausgewählt'}), 400
|
||||
@@ -387,35 +389,120 @@ def bulk_delete_licenses():
|
||||
|
||||
try:
|
||||
deleted_count = 0
|
||||
skipped_licenses = []
|
||||
active_licenses = []
|
||||
recently_used_licenses = []
|
||||
|
||||
for license_id in license_ids:
|
||||
# Hole Lizenz-Info für Audit
|
||||
cur.execute("SELECT license_key FROM licenses WHERE id = %s", (license_id,))
|
||||
# Hole vollständige Lizenz-Info
|
||||
cur.execute("""
|
||||
SELECT l.id, l.license_key, l.is_active, l.is_test,
|
||||
c.name as customer_name
|
||||
FROM licenses l
|
||||
LEFT JOIN customers c ON l.customer_id = c.id
|
||||
WHERE l.id = %s
|
||||
""", (license_id,))
|
||||
result = cur.fetchone()
|
||||
|
||||
if result:
|
||||
license_key = result[0]
|
||||
if not result:
|
||||
continue
|
||||
|
||||
# Lösche Sessions
|
||||
cur.execute("DELETE FROM sessions WHERE license_key = %s", (license_key,))
|
||||
|
||||
# Lösche Geräte-Registrierungen
|
||||
license_id, license_key, is_active, is_test, customer_name = result
|
||||
|
||||
# Safety check: Don't delete active licenses unless forced
|
||||
if is_active and not force_delete:
|
||||
active_licenses.append(f"{license_key} ({customer_name})")
|
||||
skipped_licenses.append(license_id)
|
||||
continue
|
||||
|
||||
# Check for recent activity (heartbeats in last 24 hours)
|
||||
if not force_delete:
|
||||
try:
|
||||
cur.execute("""
|
||||
SELECT COUNT(*)
|
||||
FROM license_heartbeats
|
||||
WHERE license_id = %s
|
||||
AND timestamp > NOW() - INTERVAL '24 hours'
|
||||
""", (license_id,))
|
||||
recent_heartbeats = cur.fetchone()[0]
|
||||
|
||||
if recent_heartbeats > 0:
|
||||
recently_used_licenses.append(f"{license_key} ({recent_heartbeats} activities)")
|
||||
skipped_licenses.append(license_id)
|
||||
continue
|
||||
except:
|
||||
# If heartbeats table doesn't exist, continue
|
||||
pass
|
||||
|
||||
# Check for active devices
|
||||
if not force_delete:
|
||||
try:
|
||||
cur.execute("""
|
||||
SELECT COUNT(*)
|
||||
FROM activations
|
||||
WHERE license_id = %s
|
||||
AND is_active = true
|
||||
""", (license_id,))
|
||||
active_devices = cur.fetchone()[0]
|
||||
|
||||
if active_devices > 0:
|
||||
recently_used_licenses.append(f"{license_key} ({active_devices} active devices)")
|
||||
skipped_licenses.append(license_id)
|
||||
continue
|
||||
except:
|
||||
# If activations table doesn't exist, continue
|
||||
pass
|
||||
|
||||
# Delete associated data
|
||||
cur.execute("DELETE FROM sessions WHERE license_key = %s", (license_key,))
|
||||
|
||||
try:
|
||||
cur.execute("DELETE FROM device_registrations WHERE license_id = %s", (license_id,))
|
||||
except:
|
||||
pass
|
||||
|
||||
# Lösche Lizenz
|
||||
cur.execute("DELETE FROM licenses WHERE id = %s", (license_id,))
|
||||
try:
|
||||
cur.execute("DELETE FROM license_heartbeats WHERE license_id = %s", (license_id,))
|
||||
except:
|
||||
pass
|
||||
|
||||
# Audit-Log
|
||||
log_audit('BULK_DELETE', 'license', license_id,
|
||||
old_values={'license_key': license_key})
|
||||
|
||||
deleted_count += 1
|
||||
try:
|
||||
cur.execute("DELETE FROM activations WHERE license_id = %s", (license_id,))
|
||||
except:
|
||||
pass
|
||||
|
||||
# Delete the license
|
||||
cur.execute("DELETE FROM licenses WHERE id = %s", (license_id,))
|
||||
|
||||
# Audit-Log
|
||||
log_audit('BULK_DELETE', 'license', license_id,
|
||||
old_values={
|
||||
'license_key': license_key,
|
||||
'customer_name': customer_name,
|
||||
'was_active': is_active,
|
||||
'forced': force_delete
|
||||
})
|
||||
|
||||
deleted_count += 1
|
||||
|
||||
conn.commit()
|
||||
|
||||
# Build response message
|
||||
message = f"{deleted_count} Lizenz(en) gelöscht."
|
||||
warnings = []
|
||||
|
||||
if active_licenses:
|
||||
warnings.append(f"Aktive Lizenzen übersprungen: {', '.join(active_licenses[:3])}{'...' if len(active_licenses) > 3 else ''}")
|
||||
|
||||
if recently_used_licenses:
|
||||
warnings.append(f"Kürzlich genutzte Lizenzen übersprungen: {', '.join(recently_used_licenses[:3])}{'...' if len(recently_used_licenses) > 3 else ''}")
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'deleted_count': deleted_count
|
||||
'deleted_count': deleted_count,
|
||||
'skipped_count': len(skipped_licenses),
|
||||
'message': message,
|
||||
'warnings': warnings
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren