Dieser Commit ist enthalten in:
2025-06-07 23:13:06 +02:00
Ursprung 0379391736
Commit b20a3216fb
8 geänderte Dateien mit 506 neuen und 2 gelöschten Zeilen

Datei anzeigen

@@ -981,6 +981,140 @@ def create_license():
return render_template("index.html", username=session.get('username'))
@app.route("/batch", methods=["GET", "POST"])
@login_required
def batch_licenses():
"""Batch-Generierung mehrerer Lizenzen für einen Kunden"""
if request.method == "POST":
# Formulardaten
name = request.form["customer_name"]
email = request.form["email"]
license_type = request.form["license_type"]
quantity = int(request.form["quantity"])
valid_from = request.form["valid_from"]
valid_until = request.form["valid_until"]
# Sicherheitslimit
if quantity < 1 or quantity > 100:
flash('Anzahl muss zwischen 1 und 100 liegen!', 'error')
return redirect(url_for('batch_licenses'))
conn = get_connection()
cur = conn.cursor()
try:
# Kunde einfügen (falls nicht vorhanden)
cur.execute("""
INSERT INTO customers (name, email, created_at)
VALUES (%s, %s, NOW())
ON CONFLICT (name, email) DO UPDATE SET name=EXCLUDED.name
RETURNING id
""", (name, email))
customer_id = cur.fetchone()[0]
# Lizenzen generieren und speichern
generated_licenses = []
for i in range(quantity):
# Eindeutigen Key generieren
attempts = 0
while attempts < 10:
license_key = generate_license_key(license_type)
cur.execute("SELECT 1 FROM licenses WHERE license_key = %s", (license_key,))
if not cur.fetchone():
break
attempts += 1
# Lizenz einfügen
cur.execute("""
INSERT INTO licenses (license_key, customer_id, license_type,
valid_from, valid_until, is_active, created_at)
VALUES (%s, %s, %s, %s, %s, true, NOW())
RETURNING id
""", (license_key, customer_id, license_type, valid_from, valid_until))
license_id = cur.fetchone()[0]
generated_licenses.append({
'id': license_id,
'key': license_key,
'type': license_type
})
conn.commit()
# Audit-Log
log_audit('CREATE_BATCH', 'license',
new_values={'customer': name, 'quantity': quantity, 'type': license_type},
additional_info=f"Batch-Generierung von {quantity} Lizenzen")
# Session für Export speichern
session['batch_export'] = {
'customer': name,
'email': email,
'licenses': generated_licenses,
'valid_from': valid_from,
'valid_until': valid_until,
'timestamp': datetime.now().isoformat()
}
flash(f'{quantity} Lizenzen erfolgreich generiert!', 'success')
return render_template("batch_result.html",
customer=name,
email=email,
licenses=generated_licenses,
valid_from=valid_from,
valid_until=valid_until)
except Exception as e:
conn.rollback()
logging.error(f"Fehler bei Batch-Generierung: {str(e)}")
flash('Fehler bei der Batch-Generierung!', 'error')
return redirect(url_for('batch_licenses'))
finally:
cur.close()
conn.close()
# GET Request
return render_template("batch_form.html")
@app.route("/batch/export")
@login_required
def export_batch():
"""Exportiert die zuletzt generierten Batch-Lizenzen"""
batch_data = session.get('batch_export')
if not batch_data:
flash('Keine Batch-Daten zum Exportieren vorhanden!', 'error')
return redirect(url_for('batch_licenses'))
# CSV generieren
output = io.StringIO()
output.write('\ufeff') # UTF-8 BOM für Excel
# Header
output.write(f"Kunde: {batch_data['customer']}\n")
output.write(f"E-Mail: {batch_data['email']}\n")
output.write(f"Generiert am: {datetime.fromisoformat(batch_data['timestamp']).strftime('%d.%m.%Y %H:%M')}\n")
output.write(f"Gültig von: {batch_data['valid_from']} bis {batch_data['valid_until']}\n")
output.write("\n")
output.write("Nr;Lizenzschlüssel;Typ\n")
# Lizenzen
for i, license in enumerate(batch_data['licenses'], 1):
typ_text = "Vollversion" if license['type'] == 'full' else "Testversion"
output.write(f"{i};{license['key']};{typ_text}\n")
output.seek(0)
# Audit-Log
log_audit('EXPORT', 'batch_licenses',
additional_info=f"Export von {len(batch_data['licenses'])} Batch-Lizenzen")
return send_file(
io.BytesIO(output.getvalue().encode('utf-8-sig')),
mimetype='text/csv',
as_attachment=True,
download_name=f"batch_licenses_{batch_data['customer'].replace(' ', '_')}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv"
)
@app.route("/licenses")
@login_required
def licenses():