diff --git a/Website/main.py b/Website/main.py index ae17c75..7bcd3ec 100644 --- a/Website/main.py +++ b/Website/main.py @@ -2076,10 +2076,22 @@ def booking_payment(): # Do NOT create an invoice directly. Instead request provisioning via server_steering booking_number = f"BOOK-{datetime.utcnow().strftime('%Y%m%d%H%M%S')}" - # Build a subdomain from the school name (fallback to username) and ensure uniqueness - base = _slugify_subdomain(form_data.get("school_name") or session.get("username") or booking_number) - subdomain = f"{base}-{datetime.utcnow().strftime('%Y%m%d%H%M%S')}" - subdomain = subdomain[:63] + # Build a subdomain from the school name (fallback to username) + # Use lowercase, sanitized school name and check for existing instances. + raw_base = form_data.get("school_name") or session.get("username") or booking_number + base = _slugify_subdomain(raw_base).lower()[:51] + + # Check existing instances and require the user to choose a different name on conflict + try: + existing = steering.instace.list() or [] + except Exception: + existing = [] + + if base in existing: + flash("Die gewünschte Subdomain (aus dem Schulnamen) existiert bereits. Bitte wähle einen anderen Schulnamen.", "error") + return render_template("schnell_buchung.html", **review_data) + + subdomain = base[:63] provision_status = "not_started" provision_port = None @@ -2141,13 +2153,13 @@ def booking_payment(): "source": "booking_payment", } - prov_client = None + req_client = None try: - prov_client, prov_col = _get_collection("provision_requests") - prov_col.insert_one(provision_payload) + req_client, req_col = _get_collection("instance_requests") + req_col.insert_one(provision_payload) finally: - if prov_client: - prov_client.close() + if req_client: + req_client.close() except PyMongoError: flash("Buchungsanfrage konnte nicht gesendet werden.", "error") @@ -2169,20 +2181,20 @@ def booking_payment(): -@app.route('/provision/delete', methods=['POST']) +@app.route('/instance_request/delete', methods=['POST']) @login_required -def provision_delete(): +def instance_request_delete(): prov_id = _sanitize_text(request.form.get("prov_id") or "", 64) if not prov_id: flash("Ungültige Anfrage.", "error") return redirect(url_for("my_invoices")) - prov_client = None + req_client = None try: - prov_client, prov_col = _get_collection("provision_requests") - prov = prov_col.find_one({"_id": ObjectId(prov_id)}) + req_client, req_col = _get_collection("instance_requests") + prov = req_col.find_one({"_id": ObjectId(prov_id)}) if not prov: - flash("Provisionierungsanfrage nicht gefunden.", "error") + flash("Instanz-Anfrage nicht gefunden.", "error") return redirect(url_for("my_invoices")) # Only owner or admin can delete @@ -2190,13 +2202,13 @@ def provision_delete(): flash("Keine Berechtigung zum Löschen dieser Anfrage.", "error") return redirect(url_for("my_invoices")) - prov_col.delete_one({"_id": prov.get("_id")}) - flash("Provisionierungsanfrage gelöscht.", "success") + req_col.delete_one({"_id": prov.get("_id")}) + flash("Instanz-Anfrage gelöscht.", "success") except Exception: - flash("Provisionierungsanfrage konnte nicht gelöscht werden.", "error") + flash("Instanz-Anfrage konnte nicht gelöscht werden.", "error") finally: - if prov_client: - prov_client.close() + if req_client: + req_client.close() return redirect(url_for("my_invoices")) @@ -2776,19 +2788,19 @@ def my_invoices(): if client: client.close() - # Load provisioning requests for this user - provision_requests = [] + # Load instance requests for this user + instance_requests = [] try: - prov_client, prov_col = _get_collection("provision_requests") - provision_requests = list(prov_col.find({"username": session.get("username")}).sort("created_at", -1)) - for item in provision_requests: + req_client, req_col = _get_collection("instance_requests") + instance_requests = list(req_col.find({"username": session.get("username")}).sort("created_at", -1)) + for item in instance_requests: item["id"] = str(item.get("_id")) except PyMongoError: - flash("Provisionierungsanfragen konnten nicht geladen werden.", "error") + flash("Instanz-Anfragen konnten nicht geladen werden.", "error") finally: - if 'prov_client' in locals() and prov_client: - prov_client.close() - return render_template("my_invoices.html", invoices=invoices, provision_requests=provision_requests) + if 'req_client' in locals() and req_client: + req_client.close() + return render_template("my_invoices.html", invoices=invoices, instance_requests=instance_requests) @app.route('/my/instance', methods=['GET', 'POST']) @@ -3140,13 +3152,13 @@ def admin_invoices(): flash("Rechnung angelegt.", "success") elif action == "create_from_provision" and prov_id: - # Create an invoice from a provision request - prov_client = None + # Create an invoice from an instance request + req_client = None try: - prov_client, prov_col = _get_collection("provision_requests") - prov = prov_col.find_one({"_id": ObjectId(prov_id)}) + req_client, req_col = _get_collection("instance_requests") + prov = req_col.find_one({"_id": ObjectId(prov_id)}) if not prov: - flash("Provisionierungsanfrage nicht gefunden.", "error") + flash("Instanz-Anfrage nicht gefunden.", "error") return redirect(url_for("admin_invoices")) username = prov.get("username") or "" @@ -3176,35 +3188,35 @@ def admin_invoices(): } ) - prov_col.update_one({"_id": prov.get("_id")}, {"$set": {"provision_status": "invoice_created", "updated_at": _utc_now_iso()}}) - flash("Rechnung aus Provisionierungsanfrage erstellt.", "success") + req_col.update_one({"_id": prov.get("_id")}, {"$set": {"provision_status": "invoice_created", "updated_at": _utc_now_iso()}}) + flash("Rechnung aus Instanz-Anfrage erstellt.", "success") except Exception: - flash("Fehler beim Erstellen der Rechnung aus Provisionierungsanfrage.", "error") + flash("Fehler beim Erstellen der Rechnung aus Instanz-Anfrage.", "error") finally: - if prov_client: - prov_client.close() + if req_client: + req_client.close() elif action == "update_provision" and prov_id: # Update provision request status (accept/reject/complete) new_status = _sanitize_text(request.form.get("prov_status") or "", 40) - prov_client = None + req_client = None try: - prov_client, prov_col = _get_collection("provision_requests") - prov_col.update_one({"_id": ObjectId(prov_id)}, {"$set": {"provision_status": new_status, "updated_at": _utc_now_iso()}}) - flash("Provisionierungsanfrage aktualisiert.", "success") + req_client, req_col = _get_collection("instance_requests") + req_col.update_one({"_id": ObjectId(prov_id)}, {"$set": {"provision_status": new_status, "updated_at": _utc_now_iso()}}) + flash("Instanz-Anfrage aktualisiert.", "success") except Exception: - flash("Provisionierungsanfrage konnte nicht aktualisiert werden.", "error") + flash("Instanz-Anfrage konnte nicht aktualisiert werden.", "error") finally: - if prov_client: - prov_client.close() + if req_client: + req_client.close() elif action in {"run_provision", "retry_provision", "configure_provision"} and prov_id: # Admin-triggered provisioning actions: start/retry/configure - prov_client = None + req_client = None try: - prov_client, prov_col = _get_collection("provision_requests") - prov = prov_col.find_one({"_id": ObjectId(prov_id)}) + req_client, req_col = _get_collection("instance_requests") + prov = req_col.find_one({"_id": ObjectId(prov_id)}) if not prov: - flash("Provisionierungsanfrage nicht gefunden.", "error") + flash("Instanz-Anfrage nicht gefunden.", "error") return redirect(url_for("admin_invoices")) subdomain = prov.get("subdomain") or _slugify_subdomain(prov.get("booking_data", {}).get("school_name") or prov.get("username") or prov.get("booking_number") or "prov") @@ -3243,25 +3255,25 @@ def admin_invoices(): provision_config_ok = False provision_error = str(e) - prov_col.update_one({"_id": prov.get("_id")}, {"$set": {"provision_status": provision_status, "provision_port": provision_port or "", "provision_config_ok": provision_config_ok, "provision_error": provision_error, "updated_at": _utc_now_iso()}}) + req_col.update_one({"_id": prov.get("_id")}, {"$set": {"provision_status": provision_status, "provision_port": provision_port or "", "provision_config_ok": provision_config_ok, "provision_error": provision_error, "updated_at": _utc_now_iso()}}) flash("Provisionierungsaktion ausgeführt.", "success") except Exception as e: flash(f"Provisionierungsaktion fehlgeschlagen: {str(e)}", "error") finally: - if prov_client: - prov_client.close() + if req_client: + req_client.close() - elif action == "delete_provision" and prov_id: - prov_client = None + elif action == "delete_instance_request" and prov_id: + req_client = None try: - prov_client, prov_col = _get_collection("provision_requests") - prov_col.delete_one({"_id": ObjectId(prov_id)}) - flash("Provisionierungsanfrage gelöscht.", "success") + req_client, req_col = _get_collection("instance_requests") + req_col.delete_one({"_id": ObjectId(prov_id)}) + flash("Instanz-Anfrage gelöscht.", "success") except Exception: - flash("Provisionierungsanfrage konnte nicht gelöscht werden.", "error") + flash("Instanz-Anfrage konnte nicht gelöscht werden.", "error") finally: - if prov_client: - prov_client.close() + if req_client: + req_client.close() elif action == "update" and invoice_id: amount_text = _sanitize_text(request.form.get("amount_eur") or "0", 20) @@ -3315,21 +3327,21 @@ def admin_invoices(): if client: client.close() - # Load provisioning requests for admin review - provision_requests = [] + # Load instance requests for admin review + instance_requests = [] try: - prov_client, prov_col = _get_collection("provision_requests") - provision_requests = list(prov_col.find().sort("created_at", -1)) - for item in provision_requests: + req_client, req_col = _get_collection("instance_requests") + instance_requests = list(req_col.find().sort("created_at", -1)) + for item in instance_requests: item["id"] = str(item.get("_id")) except PyMongoError: - flash("Provisionierungsanfragen konnten nicht geladen werden.", "error") + flash("Instanz-Anfragen konnten nicht geladen werden.", "error") finally: - if 'prov_client' in locals() and prov_client: - prov_client.close() + if 'req_client' in locals() and req_client: + req_client.close() users = _list_users_for_admin() - return render_template("admin_invoices.html", invoices=invoices, users=users, provision_requests=provision_requests) + return render_template("admin_invoices.html", invoices=invoices, users=users, provision_requests=instance_requests) @app.route('/datenschutz') @@ -3337,6 +3349,24 @@ def datenschutz(): return render_template("datenschutz.html") +@app.route('/instance_request/check_subdomain', methods=['GET']) +@login_required +def check_subdomain(): + name = (request.values.get('school_name') or '').strip() + slug = _slugify_subdomain(name) + if not slug: + return jsonify({"available": False, "slug": "", "message": "Ungültiger Name für Subdomain."}) + + try: + existing = steering.instace.list() or [] + except Exception: + existing = [] + + if slug in existing: + return jsonify({"available": False, "slug": slug, "message": "Subdomain bereits vergeben."}) + return jsonify({"available": True, "slug": slug, "message": "Subdomain verfügbar."}) + + @app.route('/impressum') def impressum(): return render_template("impressum.html") diff --git a/Website/templates/admin_invoices.html b/Website/templates/admin_invoices.html index 1e261cb..62d7a29 100644 --- a/Website/templates/admin_invoices.html +++ b/Website/templates/admin_invoices.html @@ -64,7 +64,7 @@ {% endfor %} {% if provision_requests %} -

Provisionierungsanfragen

+

Instanz-Anfragen

{% for prov in provision_requests %}

{{ prov.booking_number or prov.booking_number }}

@@ -105,7 +105,7 @@
- +
diff --git a/Website/templates/my_invoices.html b/Website/templates/my_invoices.html index 94c0f10..73e6645 100644 --- a/Website/templates/my_invoices.html +++ b/Website/templates/my_invoices.html @@ -46,8 +46,8 @@
-

Provisionierungsanfragen

-

Hier siehst du den Status deiner angeforderten Instanzen/ Buchungen, die vom Admin geprüft werden.

+

Instanz-Anfragen

+

Hier siehst du den Status deiner angeforderten Instanzen/Buchungen, die vom Admin geprüft werden.

@@ -62,7 +62,7 @@ - {% for prov in provision_requests %} + {% for prov in instance_requests %} {{ prov.booking_number or prov.booking_number }} {{ prov.package_label or prov.package }} @@ -70,7 +70,7 @@ {{ '%.2f'|format(prov.amount_eur or 0) }} EUR {{ prov.provision_status or 'not_started' }} -
+
diff --git a/Website/templates/schnell_buchung.html b/Website/templates/schnell_buchung.html index 4760d77..8e723c3 100644 --- a/Website/templates/schnell_buchung.html +++ b/Website/templates/schnell_buchung.html @@ -208,6 +208,7 @@
+
@@ -242,10 +243,54 @@
- + Zurück zu den Preisen
+ {% endblock %} \ No newline at end of file