Gerätelimit drin
Dieser Commit ist enthalten in:
@@ -1485,6 +1485,7 @@ def create_license():
|
||||
domain_count = int(request.form.get("domain_count", 1))
|
||||
ipv4_count = int(request.form.get("ipv4_count", 1))
|
||||
phone_count = int(request.form.get("phone_count", 1))
|
||||
device_limit = int(request.form.get("device_limit", 3))
|
||||
|
||||
conn = get_connection()
|
||||
cur = conn.cursor()
|
||||
@@ -1536,11 +1537,11 @@ def create_license():
|
||||
# Lizenz hinzufügen
|
||||
cur.execute("""
|
||||
INSERT INTO licenses (license_key, customer_id, license_type, valid_from, valid_until, is_active,
|
||||
domain_count, ipv4_count, phone_count, is_test)
|
||||
VALUES (%s, %s, %s, %s, %s, TRUE, %s, %s, %s, %s)
|
||||
domain_count, ipv4_count, phone_count, device_limit, is_test)
|
||||
VALUES (%s, %s, %s, %s, %s, TRUE, %s, %s, %s, %s, %s)
|
||||
RETURNING id
|
||||
""", (license_key, customer_id, license_type, valid_from, valid_until,
|
||||
domain_count, ipv4_count, phone_count, is_test))
|
||||
domain_count, ipv4_count, phone_count, device_limit, is_test))
|
||||
license_id = cur.fetchone()[0]
|
||||
|
||||
# Ressourcen zuweisen
|
||||
@@ -1652,6 +1653,7 @@ def create_license():
|
||||
'license_type': license_type,
|
||||
'valid_from': valid_from,
|
||||
'valid_until': valid_until,
|
||||
'device_limit': device_limit,
|
||||
'is_test': is_test
|
||||
})
|
||||
|
||||
@@ -1711,6 +1713,7 @@ def batch_licenses():
|
||||
domain_count = int(request.form.get("domain_count", 1))
|
||||
ipv4_count = int(request.form.get("ipv4_count", 1))
|
||||
phone_count = int(request.form.get("phone_count", 1))
|
||||
device_limit = int(request.form.get("device_limit", 3))
|
||||
|
||||
# Sicherheitslimit
|
||||
if quantity < 1 or quantity > 100:
|
||||
@@ -1803,11 +1806,11 @@ def batch_licenses():
|
||||
cur.execute("""
|
||||
INSERT INTO licenses (license_key, customer_id, license_type, is_test,
|
||||
valid_from, valid_until, is_active,
|
||||
domain_count, ipv4_count, phone_count)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, true, %s, %s, %s)
|
||||
domain_count, ipv4_count, phone_count, device_limit)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, true, %s, %s, %s, %s)
|
||||
RETURNING id
|
||||
""", (license_key, customer_id, license_type, is_test, valid_from, valid_until,
|
||||
domain_count, ipv4_count, phone_count))
|
||||
domain_count, ipv4_count, phone_count, device_limit))
|
||||
license_id = cur.fetchone()[0]
|
||||
|
||||
# Ressourcen für diese Lizenz zuweisen
|
||||
@@ -1983,7 +1986,7 @@ def edit_license(license_id):
|
||||
if request.method == "POST":
|
||||
# Alte Werte für Audit-Log abrufen
|
||||
cur.execute("""
|
||||
SELECT license_key, license_type, valid_from, valid_until, is_active, is_test
|
||||
SELECT license_key, license_type, valid_from, valid_until, is_active, is_test, device_limit
|
||||
FROM licenses WHERE id = %s
|
||||
""", (license_id,))
|
||||
old_license = cur.fetchone()
|
||||
@@ -1995,13 +1998,14 @@ def edit_license(license_id):
|
||||
valid_until = request.form["valid_until"]
|
||||
is_active = request.form.get("is_active") == "on"
|
||||
is_test = request.form.get("is_test") == "on"
|
||||
device_limit = int(request.form.get("device_limit", 3))
|
||||
|
||||
cur.execute("""
|
||||
UPDATE licenses
|
||||
SET license_key = %s, license_type = %s, valid_from = %s,
|
||||
valid_until = %s, is_active = %s, is_test = %s
|
||||
valid_until = %s, is_active = %s, is_test = %s, device_limit = %s
|
||||
WHERE id = %s
|
||||
""", (license_key, license_type, valid_from, valid_until, is_active, is_test, license_id))
|
||||
""", (license_key, license_type, valid_from, valid_until, is_active, is_test, device_limit, license_id))
|
||||
|
||||
conn.commit()
|
||||
|
||||
@@ -2013,7 +2017,8 @@ def edit_license(license_id):
|
||||
'valid_from': str(old_license[2]),
|
||||
'valid_until': str(old_license[3]),
|
||||
'is_active': old_license[4],
|
||||
'is_test': old_license[5]
|
||||
'is_test': old_license[5],
|
||||
'device_limit': old_license[6]
|
||||
},
|
||||
new_values={
|
||||
'license_key': license_key,
|
||||
@@ -2021,7 +2026,8 @@ def edit_license(license_id):
|
||||
'valid_from': valid_from,
|
||||
'valid_until': valid_until,
|
||||
'is_active': is_active,
|
||||
'is_test': is_test
|
||||
'is_test': is_test,
|
||||
'device_limit': device_limit
|
||||
})
|
||||
|
||||
cur.close()
|
||||
@@ -2048,7 +2054,7 @@ def edit_license(license_id):
|
||||
# Get license data
|
||||
cur.execute("""
|
||||
SELECT l.id, l.license_key, c.name, c.email, l.license_type,
|
||||
l.valid_from, l.valid_until, l.is_active, c.id, l.is_test
|
||||
l.valid_from, l.valid_until, l.is_active, c.id, l.is_test, l.device_limit
|
||||
FROM licenses l
|
||||
JOIN customers c ON l.customer_id = c.id
|
||||
WHERE l.id = %s
|
||||
@@ -2343,7 +2349,9 @@ def customers_licenses():
|
||||
END as status,
|
||||
l.domain_count,
|
||||
l.ipv4_count,
|
||||
l.phone_count
|
||||
l.phone_count,
|
||||
l.device_limit,
|
||||
(SELECT COUNT(*) FROM device_registrations WHERE license_id = l.id AND is_active = TRUE) as active_devices
|
||||
FROM licenses l
|
||||
WHERE l.customer_id = %s
|
||||
ORDER BY l.created_at DESC, l.id DESC
|
||||
@@ -2384,7 +2392,9 @@ def api_customer_licenses(customer_id):
|
||||
END as status,
|
||||
l.domain_count,
|
||||
l.ipv4_count,
|
||||
l.phone_count
|
||||
l.phone_count,
|
||||
l.device_limit,
|
||||
(SELECT COUNT(*) FROM device_registrations WHERE license_id = l.id AND is_active = TRUE) as active_devices
|
||||
FROM licenses l
|
||||
WHERE l.customer_id = %s
|
||||
ORDER BY l.created_at DESC, l.id DESC
|
||||
@@ -2434,6 +2444,8 @@ def api_customer_licenses(customer_id):
|
||||
'domain_count': row[7],
|
||||
'ipv4_count': row[8],
|
||||
'phone_count': row[9],
|
||||
'device_limit': row[10],
|
||||
'active_devices': row[11],
|
||||
'resources': resources
|
||||
})
|
||||
|
||||
@@ -3711,6 +3723,218 @@ def bulk_deactivate_licenses():
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'message': str(e)}), 500
|
||||
|
||||
@app.route("/api/license/<int:license_id>/devices")
|
||||
@login_required
|
||||
def get_license_devices(license_id):
|
||||
"""Hole alle registrierten Geräte einer Lizenz"""
|
||||
try:
|
||||
conn = get_connection()
|
||||
cur = conn.cursor()
|
||||
|
||||
# Prüfe ob Lizenz existiert und hole device_limit
|
||||
cur.execute("""
|
||||
SELECT device_limit FROM licenses WHERE id = %s
|
||||
""", (license_id,))
|
||||
license_data = cur.fetchone()
|
||||
|
||||
if not license_data:
|
||||
return jsonify({'success': False, 'message': 'Lizenz nicht gefunden'}), 404
|
||||
|
||||
device_limit = license_data[0]
|
||||
|
||||
# Hole alle Geräte für diese Lizenz
|
||||
cur.execute("""
|
||||
SELECT id, hardware_id, device_name, operating_system,
|
||||
first_seen, last_seen, is_active, ip_address
|
||||
FROM device_registrations
|
||||
WHERE license_id = %s
|
||||
ORDER BY is_active DESC, last_seen DESC
|
||||
""", (license_id,))
|
||||
|
||||
devices = []
|
||||
for row in cur.fetchall():
|
||||
devices.append({
|
||||
'id': row[0],
|
||||
'hardware_id': row[1],
|
||||
'device_name': row[2] or 'Unbekanntes Gerät',
|
||||
'operating_system': row[3] or 'Unbekannt',
|
||||
'first_seen': row[4].strftime('%d.%m.%Y %H:%M') if row[4] else '',
|
||||
'last_seen': row[5].strftime('%d.%m.%Y %H:%M') if row[5] else '',
|
||||
'is_active': row[6],
|
||||
'ip_address': row[7] or '-'
|
||||
})
|
||||
|
||||
cur.close()
|
||||
conn.close()
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'devices': devices,
|
||||
'device_limit': device_limit,
|
||||
'active_count': sum(1 for d in devices if d['is_active'])
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Fehler beim Abrufen der Geräte: {str(e)}")
|
||||
return jsonify({'success': False, 'message': 'Fehler beim Abrufen der Geräte'}), 500
|
||||
|
||||
@app.route("/api/license/<int:license_id>/register-device", methods=["POST"])
|
||||
def register_device(license_id):
|
||||
"""Registriere ein neues Gerät für eine Lizenz"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
hardware_id = data.get('hardware_id')
|
||||
device_name = data.get('device_name', '')
|
||||
operating_system = data.get('operating_system', '')
|
||||
|
||||
if not hardware_id:
|
||||
return jsonify({'success': False, 'message': 'Hardware-ID fehlt'}), 400
|
||||
|
||||
conn = get_connection()
|
||||
cur = conn.cursor()
|
||||
|
||||
# Prüfe ob Lizenz existiert und aktiv ist
|
||||
cur.execute("""
|
||||
SELECT device_limit, is_active, valid_until
|
||||
FROM licenses
|
||||
WHERE id = %s
|
||||
""", (license_id,))
|
||||
license_data = cur.fetchone()
|
||||
|
||||
if not license_data:
|
||||
return jsonify({'success': False, 'message': 'Lizenz nicht gefunden'}), 404
|
||||
|
||||
device_limit, is_active, valid_until = license_data
|
||||
|
||||
# Prüfe ob Lizenz aktiv und gültig ist
|
||||
if not is_active:
|
||||
return jsonify({'success': False, 'message': 'Lizenz ist deaktiviert'}), 403
|
||||
|
||||
if valid_until < datetime.now(ZoneInfo("Europe/Berlin")).date():
|
||||
return jsonify({'success': False, 'message': 'Lizenz ist abgelaufen'}), 403
|
||||
|
||||
# Prüfe ob Gerät bereits registriert ist
|
||||
cur.execute("""
|
||||
SELECT id, is_active FROM device_registrations
|
||||
WHERE license_id = %s AND hardware_id = %s
|
||||
""", (license_id, hardware_id))
|
||||
existing_device = cur.fetchone()
|
||||
|
||||
if existing_device:
|
||||
device_id, is_device_active = existing_device
|
||||
if is_device_active:
|
||||
# Gerät ist bereits aktiv, update last_seen
|
||||
cur.execute("""
|
||||
UPDATE device_registrations
|
||||
SET last_seen = CURRENT_TIMESTAMP,
|
||||
ip_address = %s,
|
||||
user_agent = %s
|
||||
WHERE id = %s
|
||||
""", (get_client_ip(), request.headers.get('User-Agent', ''), device_id))
|
||||
conn.commit()
|
||||
return jsonify({'success': True, 'message': 'Gerät bereits registriert', 'device_id': device_id})
|
||||
else:
|
||||
# Gerät war deaktiviert, prüfe ob wir es reaktivieren können
|
||||
cur.execute("""
|
||||
SELECT COUNT(*) FROM device_registrations
|
||||
WHERE license_id = %s AND is_active = TRUE
|
||||
""", (license_id,))
|
||||
active_count = cur.fetchone()[0]
|
||||
|
||||
if active_count >= device_limit:
|
||||
return jsonify({'success': False, 'message': f'Gerätelimit erreicht ({device_limit} Geräte)'}), 403
|
||||
|
||||
# Reaktiviere das Gerät
|
||||
cur.execute("""
|
||||
UPDATE device_registrations
|
||||
SET is_active = TRUE,
|
||||
last_seen = CURRENT_TIMESTAMP,
|
||||
deactivated_at = NULL,
|
||||
deactivated_by = NULL,
|
||||
ip_address = %s,
|
||||
user_agent = %s
|
||||
WHERE id = %s
|
||||
""", (get_client_ip(), request.headers.get('User-Agent', ''), device_id))
|
||||
conn.commit()
|
||||
return jsonify({'success': True, 'message': 'Gerät reaktiviert', 'device_id': device_id})
|
||||
|
||||
# Neues Gerät - prüfe Gerätelimit
|
||||
cur.execute("""
|
||||
SELECT COUNT(*) FROM device_registrations
|
||||
WHERE license_id = %s AND is_active = TRUE
|
||||
""", (license_id,))
|
||||
active_count = cur.fetchone()[0]
|
||||
|
||||
if active_count >= device_limit:
|
||||
return jsonify({'success': False, 'message': f'Gerätelimit erreicht ({device_limit} Geräte)'}), 403
|
||||
|
||||
# Registriere neues Gerät
|
||||
cur.execute("""
|
||||
INSERT INTO device_registrations
|
||||
(license_id, hardware_id, device_name, operating_system, ip_address, user_agent)
|
||||
VALUES (%s, %s, %s, %s, %s, %s)
|
||||
RETURNING id
|
||||
""", (license_id, hardware_id, device_name, operating_system,
|
||||
get_client_ip(), request.headers.get('User-Agent', '')))
|
||||
device_id = cur.fetchone()[0]
|
||||
|
||||
conn.commit()
|
||||
|
||||
# Audit Log
|
||||
log_audit('DEVICE_REGISTER', 'device', device_id,
|
||||
new_values={'license_id': license_id, 'hardware_id': hardware_id})
|
||||
|
||||
cur.close()
|
||||
conn.close()
|
||||
|
||||
return jsonify({'success': True, 'message': 'Gerät erfolgreich registriert', 'device_id': device_id})
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Fehler bei Geräte-Registrierung: {str(e)}")
|
||||
return jsonify({'success': False, 'message': 'Fehler bei der Registrierung'}), 500
|
||||
|
||||
@app.route("/api/license/<int:license_id>/deactivate-device/<int:device_id>", methods=["POST"])
|
||||
@login_required
|
||||
def deactivate_device(license_id, device_id):
|
||||
"""Deaktiviere ein registriertes Gerät"""
|
||||
try:
|
||||
conn = get_connection()
|
||||
cur = conn.cursor()
|
||||
|
||||
# Prüfe ob das Gerät zu dieser Lizenz gehört
|
||||
cur.execute("""
|
||||
SELECT id FROM device_registrations
|
||||
WHERE id = %s AND license_id = %s AND is_active = TRUE
|
||||
""", (device_id, license_id))
|
||||
|
||||
if not cur.fetchone():
|
||||
return jsonify({'success': False, 'message': 'Gerät nicht gefunden oder bereits deaktiviert'}), 404
|
||||
|
||||
# Deaktiviere das Gerät
|
||||
cur.execute("""
|
||||
UPDATE device_registrations
|
||||
SET is_active = FALSE,
|
||||
deactivated_at = CURRENT_TIMESTAMP,
|
||||
deactivated_by = %s
|
||||
WHERE id = %s
|
||||
""", (session['username'], device_id))
|
||||
|
||||
conn.commit()
|
||||
|
||||
# Audit Log
|
||||
log_audit('DEVICE_DEACTIVATE', 'device', device_id,
|
||||
old_values={'is_active': True},
|
||||
new_values={'is_active': False})
|
||||
|
||||
cur.close()
|
||||
conn.close()
|
||||
|
||||
return jsonify({'success': True, 'message': 'Gerät erfolgreich deaktiviert'})
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Fehler beim Deaktivieren des Geräts: {str(e)}")
|
||||
return jsonify({'success': False, 'message': 'Fehler beim Deaktivieren'}), 500
|
||||
|
||||
@app.route("/api/licenses/bulk-delete", methods=["POST"])
|
||||
@login_required
|
||||
def bulk_delete_licenses():
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren