From 261d29abf6a933ec828ab33ecfc38a5e78d0eccb Mon Sep 17 00:00:00 2001 From: AIIrondev Date: Wed, 26 Aug 2026 12:39:27 +0200 Subject: [PATCH] removal of redundant data --- Website/main.py | 189 +++++++++--------------------------------------- 1 file changed, 36 insertions(+), 153 deletions(-) diff --git a/Website/main.py b/Website/main.py index 49fdd71..676570b 100644 --- a/Website/main.py +++ b/Website/main.py @@ -2168,7 +2168,31 @@ def book_option_package(): return redirect(url_for("booking_payment", packages=packages_raw, flow=booking_flow)) -def background_booking_provisioning(app_instance, prov_id, subdomain, modules_to_provision, user_id, school_name, user_email): +ALL_MODULE_KEYS = ["library", "inventory", "student_cards", "terminplan"] +PACKAGE_MODULE_MAP = { + "buecherei": ["library"], + "inventarsystem": ["inventory"], + "terminverwaltung": ["terminplan"], + "starter": ["library", "inventory", "student_cards"], + "advanced": ["library", "inventory", "student_cards", "terminplan"], +} + +def build_module_config_string(package_list: list) -> str: + active_modules = set() + for pkg in package_list: + pkg_key = pkg.strip().lower() + if pkg_key in ALL_MODULE_KEYS: + active_modules.add(pkg_key) + elif pkg_key in PACKAGE_MODULE_MAP: + active_modules.update(PACKAGE_MODULE_MAP[pkg_key]) + + config_parts = [ + f"{mod}={'on' if mod in active_modules else 'off'}" + for mod in ALL_MODULE_KEYS + ] + return " ".join(config_parts) + +def background_booking_provisioning(app_instance, prov_id, subdomain, package_list, user_id, school_name, user_email): """Hintergrund-Worker, der die Tenant-Bereitstellung über das Host-Watcher-Triggersystem auslöst.""" with app_instance.app_context(): req_client, req_col = _get_collection("instance_requests") @@ -2191,23 +2215,26 @@ def background_booking_provisioning(app_instance, prov_id, subdomain, modules_to next_port = max(used_ports) + 1 if used_ports else 10002 admin_password = generate_secure_password() - # 3. Trigger-Datei fuer den Host-Watcher schreiben (ersetzt Instance.new & Instance.edit) + # --- NEU: Generiere den korrekten Modul-String --- + module_config_str = build_module_config_string(package_list) + + # 3. Trigger-Datei fuer den Host-Watcher schreiben os.makedirs(TRIGGER_DIR, exist_ok=True) trigger_file = os.path.join(TRIGGER_DIR, f"{subdomain}.json") trigger_payload = { + "action": "add", # <--- GANZ WICHTIG FÜR DEN WATCHER "request_id": str(prov_id), "slug": subdomain, "port": next_port, "password": admin_password, - "modules": list(modules_to_provision) + "module_config": module_config_str # <--- ERSETZT "modules": list(...) } with open(trigger_file, "w") as f: json.dump(trigger_payload, f) - print(f"[INFO] Trigger-Datei fuer Host-Watcher erstellt: {trigger_file}") - + print(f"[INFO] Trigger-Datei fuer Host-Watcher erstellt: {trigger_file} mit Payload: {trigger_payload}") # 4. Instanz-Eintrag in der Datenbank registrieren domain = f"{subdomain}.invario-software.de" instance_doc = { @@ -2438,17 +2465,14 @@ def booking_payment(): finally: req_client.close() - valid_modules = set(BOOKING_PACKAGE_MAP.keys()) - modules_to_provision = {pkg for pkg in package_list if pkg in valid_modules} - app_obj = current_app._get_current_object() user_id = session.get("user_id") user_email = session.get("email") or form_data.get("contact_email") - # Startet den asynchronen Thread, der die Trigger-Datei ablegt + # Startet den asynchronen Thread. Wir übergeben nun direkt die 'package_list' thread = threading.Thread( target=background_booking_provisioning, - args=(app_obj, prov_id, subdomain, modules_to_provision, user_id, form_data["school_name"], user_email) + args=(app_obj, prov_id, subdomain, package_list, user_id, form_data["school_name"], user_email) ) thread.start() print(f"[INFO] Background Provisioning Trigger gestartet für Subdomain: {subdomain}") @@ -3709,149 +3733,6 @@ def generate_secure_password(length=14): def _utc_now_iso(): return datetime.now(timezone.utc).isoformat() -def _update_request_status(request_id, status, error_message=None): - """ - Updates the status of a provisioning request in the database. - """ - client, col = _get_collection("instance_requests") - try: - update_fields = { - "provision_status": status, - "updated_at": datetime.utcnow() - } - if error_message: - update_fields["last_error"] = error_message - - col.update_one( - {"_id": ObjectId(request_id)}, - {"$set": update_fields} - ) - except Exception as e: - print(f"[ERROR] Failed to update request status: {e}") - finally: - client.close() - - -def _create_instance_record(tenant_slug, port, admin_password): - """ - Creates the final database record for the active instance so the - frontend knows the domain, port, and credentials. - """ - client, col = _get_collection("instances") - try: - # Prevent duplicates if the watcher re-runs - existing = col.find_one({"subdomain": tenant_slug}) - if existing: - return existing["_id"] - - # Fetch the base domain from env variables, fallback to localhost if missing - parent_domain = os.environ.get("INSTANCE_PARENT_DOMAIN", "localhost") - full_domain = f"{tenant_slug}.{parent_domain}" - - new_instance = { - "subdomain": tenant_slug, - "domain": full_domain, - "port": int(port), - "admin_username": "admin", - "admin_password": admin_password, - "created_at": datetime.utcnow(), - "status": "active" - } - result = col.insert_one(new_instance) - return result.inserted_id - except Exception as e: - print(f"[ERROR] Failed to create instance record: {e}") - finally: - client.close() - -def run_tenant_provisioning_async(tenant_slug, next_port, admin_password, user_email, request_id): - """ - Background thread running inside the Flask container. - Drops a trigger payload for the host watcher service. - """ - try: - # 1. Update DB to provisioning state - _update_request_status(request_id, "provisioning") - - # 2. Write trigger file for the host watcher - os.makedirs(TRIGGER_DIR, exist_ok=True) - trigger_file = os.path.join(TRIGGER_DIR, f"{tenant_slug}.json") - - payload = { - "request_id": str(request_id), - "slug": tenant_slug, - "port": next_port, - "password": admin_password - } - - with open(trigger_file, "w") as f: - json.dump(payload, f) - - # 3. Register instance record in MongoDB - _create_instance_record(tenant_slug, next_port, admin_password) - - # 4. Optional: Send accreditation email safely - try: - send_accreditation_email( - recipient=user_email, - domain=f"{tenant_slug}.yourdomain.com", - username="admin", - password=admin_password - ) - except Exception as mail_err: - print(f"[WARN] Mail delivery failed (non-fatal): {mail_err}") - - # Mark request as ready - _update_request_status(request_id, "ready") - - except Exception as e: - print(f"[ERROR] Tenant provisioning failed: {e}") - _update_request_status(request_id, "failed", error_message=str(e)) - -@app.route('/booking_payment_async', methods=['POST']) -@login_required -def booking_payment_async(): - try: - user_id = session.get("user_id") - user_email = session.get("email") - tenant_slug = _slugify_subdomain(request.form.get('tenant_slug')) - school_name = request.form.get('school_name', tenant_slug) - - if not tenant_slug: - return jsonify({"success": False, "error": "Ungültige Subdomain angegeben."}), 400 - - # Datenbank-Eintrag erstellen... - req_client, req_col = _get_collection("instance_requests") - try: - prov_doc = { - "user_id": user_id, - "tenant_slug": tenant_slug, - "school_name": school_name, - "provision_status": "pending", - "created_at": _utc_now_iso(), - "updated_at": _utc_now_iso() - } - prov_id = str(req_col.insert_one(prov_doc).inserted_id) - finally: - req_client.close() - - # Asynchronen Thread starten... - thread = threading.Thread( - target=run_tenant_provisioning_async, - args=(app, user_id, tenant_slug, school_name, user_email, prov_id) - ) - thread.start() - - return jsonify({ - "success": True, - "tenant_slug": tenant_slug, - "request_id": prov_id - }), 200 - - except Exception as e: - # WICHTIG: Fängt jegliche Python-Fehler ab und sendet sauberes JSON statt HTML-Crash - return jsonify({"success": False, "error": str(e)}), 500 - @app.route('/instance_request/status', methods=['GET']) def tenant_status(): """ @@ -3913,6 +3794,8 @@ def tenant_status(): pass return jsonify({"status": "pending"}), 200 + + def main(): app.run(host="0.0.0.0", port=4999, debug=False)