diff --git a/srv/tesm-license/VERSION b/srv/tesm-license/VERSION index 23aa839..0495c4a 100644 --- a/srv/tesm-license/VERSION +++ b/srv/tesm-license/VERSION @@ -1 +1 @@ -1.2.2 +1.2.3 diff --git a/srv/tesm-license/app.py b/srv/tesm-license/app.py index 1e7d5dd..978d1bf 100644 --- a/srv/tesm-license/app.py +++ b/srv/tesm-license/app.py @@ -1977,6 +1977,23 @@ def _get_master_endpoint(): return get_setting("master_endpoint", "") +def _customer_facing_url(endpoint, **values): + """Baut eine externe URL fuer an KUNDEN gerichtete Magic-Links (Self- + Service, Kundenportal-Anfrage/-Zugang, Lizenz-per-E-Mail) auf Basis + des admin-gepflegten Lizenzserver-Endpunkts (siehe _get_master_endpoint(), + Einstellungen -> Lizenz -> Anbieter & Lizenzserver) -- NICHT per + url_for(..., _external=True), das stattdessen den Host-Header der + GERADE laufenden Anfrage verwendet und damit z.B. die interne IP + zeigt, ueber die zufaellig der Admin gerade eingeloggt ist, statt der + fuer Kunden eigentlich gedachten oeffentlichen Domain. Faellt auf die + normale request-basierte externe URL zurueck, wenn der Endpunkt noch + nicht konfiguriert ist (z.B. auf einer frischen Installation).""" + base = _get_master_endpoint().rstrip("/") + if not base: + return url_for(endpoint, _external=True, **values) + return base + url_for(endpoint, **values) + + def _customer_row(conn, customer_id): return conn.execute("SELECT * FROM license_customers WHERE id=?", (customer_id,)).fetchone() @@ -2635,8 +2652,8 @@ def ticket_detail(ticket_id): license_types=licensing.LICENSE_TYPES, all_modules=licensing.ALL_MODULES, type_labels=LICENSE_TYPE_LABELS, module_labels=MODULE_LABELS, master_licensed=license_active(), - self_service_url=url_for("self_service", ticket_id=ticket_id, _external=True), - portal_request_url=url_for("portal_request", _external=True), + self_service_url=_customer_facing_url("self_service", ticket_id=ticket_id), + portal_request_url=_customer_facing_url("portal_request"), can_edit=current_user.has_permission("licenses.edit"), ) @@ -2876,12 +2893,12 @@ def license_send_email(license_id): return redirect(url_for("license_detail", license_id=license_id)) self_service_note = "" if row["ticket_id"]: - self_service_url = url_for("self_service", ticket_id=row["ticket_id"], _external=True) + self_service_url = _customer_facing_url("self_service", ticket_id=row["ticket_id"]) self_service_note = ( f"\nÜber diesen Link können Sie Ihre Lizenz jederzeit selbst herunterladen, " f"widerrufen oder (z.B. nach einem Systemwechsel) neu erstellen:\n{self_service_url}\n" ) - portal_request_url = url_for("portal_request", _external=True) + portal_request_url = _customer_facing_url("portal_request") self_service_note += ( f"\nEine Übersicht all Ihrer Tickets/Lizenzen können Sie sich jederzeit unter folgendem Link per " f"E-Mail zuschicken lassen:\n{portal_request_url}\n" @@ -3086,7 +3103,7 @@ def portal_request(): (now + timedelta(minutes=PORTAL_ACCESS_LINK_MINUTES)).strftime("%Y-%m-%d %H:%M:%S")), ) conn.commit() - access_url = url_for("portal_access", token=grant_token, _external=True) + access_url = _customer_facing_url("portal_access", token=grant_token) try: _graph_send_mail( customer["contact_email"], @@ -3604,6 +3621,7 @@ def inject_license_topbar(): @app.route("/") +@login_required def index(): """Dashboard des Master-Lizenzservers -- eine rein informative Kachel- uebersicht der gerade AKTIVEN Lizenzen (analog zur Geraete-Kachel- @@ -3613,8 +3631,15 @@ def index(): mit status='active' -- alles andere (Tickets anlegen/bearbeiten/ loeschen, Lizenzen ausstellen/widerrufen/loeschen) ist Verwaltung und lebt seit der Kachel-Umstellung auf der eigenen Tickets-Seite - (tickets_list()).""" - if not current_user.is_authenticated or not current_user.has_permission("licenses.view"): + (tickets_list()). + + @login_required (anders als bei TESM selbst, wo das Geraete-Dashboard + bewusst auch ohne Login als reines Status-Board sichtbar bleibt): der + Lizenzserver ist reines internes Verwaltungswerkzeug -- ein anonymer + Besuch auf '/' soll immer zuerst auf die Login-Seite treffen (via + login_manager.login_view), nicht auf einen 'bitte anmelden'-Platzhalter + innerhalb der Dashboard-Huelle.""" + if not current_user.has_permission("licenses.view"): return render_template("index.html", buckets=None) conn = get_db_connection() active_rows = conn.execute("""