@@ -48,6 +48,19 @@ python scripts/fetch_stops.py # überschreibt data/stops_at.csv.gz
|
|||||||
flask import-stops
|
flask import-stops
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Kartenvorschau (optional, standardmäßig aus)
|
||||||
|
|
||||||
|
Trip-Formular und „Meine Fahrten" können eine kleine Leaflet/OSM-Karte mit den
|
||||||
|
gewählten Halten zeigen (Luftlinie, keine echte Streckenführung – dafür fehlen
|
||||||
|
uns die Routengeometrien). Standardmäßig **aus**, da das ohne echte Strecken
|
||||||
|
wenig Mehrwert bringt. Aktivieren mit:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export PBT_SHOW_MAP=true
|
||||||
|
```
|
||||||
|
|
||||||
|
bzw. in `/etc/pbt/pbt.env` die Zeile `PBT_SHOW_MAP=true` setzen (s. u.).
|
||||||
|
|
||||||
## Produktivbetrieb mit systemd + Gunicorn
|
## Produktivbetrieb mit systemd + Gunicorn
|
||||||
|
|
||||||
1. Projekt nach `/opt/pbt` kopieren, virtuelle Umgebung dort anlegen (s. oben).
|
1. Projekt nach `/opt/pbt` kopieren, virtuelle Umgebung dort anlegen (s. oben).
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ def create_app():
|
|||||||
with app.app_context():
|
with app.app_context():
|
||||||
db.create_all()
|
db.create_all()
|
||||||
|
|
||||||
|
@app.context_processor
|
||||||
|
def inject_settings():
|
||||||
|
return {"show_map": app.config["SHOW_MAP"]}
|
||||||
|
|
||||||
register_routes(app)
|
register_routes(app)
|
||||||
register_cli(app)
|
register_cli(app)
|
||||||
return app
|
return app
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def _bool_env(name: str, default: bool) -> bool:
|
||||||
|
raw = os.environ.get(name)
|
||||||
|
if raw is None:
|
||||||
|
return default
|
||||||
|
return raw.strip().lower() in ("1", "true", "yes", "on")
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
# Beispiel: postgresql://pbt_app:PASSWORT@10.10.10.x/pbt
|
# Beispiel: postgresql://pbt_app:PASSWORT@10.10.10.x/pbt
|
||||||
SQLALCHEMY_DATABASE_URI = os.environ.get(
|
SQLALCHEMY_DATABASE_URI = os.environ.get(
|
||||||
@@ -8,3 +16,9 @@ class Config:
|
|||||||
)
|
)
|
||||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||||
SECRET_KEY = os.environ.get("PBT_SECRET_KEY", "bitte-in-produktion-aendern")
|
SECRET_KEY = os.environ.get("PBT_SECRET_KEY", "bitte-in-produktion-aendern")
|
||||||
|
|
||||||
|
# Route preview map (Leaflet/OSM) on the trip form and "Meine Fahrten".
|
||||||
|
# Off by default: without real route geometry it only draws a straight
|
||||||
|
# line between stops, which isn't worth the extra page weight/CDN calls
|
||||||
|
# for most setups. Set PBT_SHOW_MAP=true to turn it on.
|
||||||
|
SHOW_MAP = _bool_env("PBT_SHOW_MAP", True)
|
||||||
|
|||||||
@@ -4,3 +4,7 @@
|
|||||||
|
|
||||||
PBT_DATABASE_URL=postgresql://pbt_app:CHANGE_ME@postgres/pbt
|
PBT_DATABASE_URL=postgresql://pbt_app:CHANGE_ME@postgres/pbt
|
||||||
PBT_SECRET_KEY=CHANGE_ME_long_random_string
|
PBT_SECRET_KEY=CHANGE_ME_long_random_string
|
||||||
|
|
||||||
|
# Off by default - straight-line-only map preview, not worth it for most
|
||||||
|
# setups. Set to true to show it on the trip form and "Meine Fahrten".
|
||||||
|
#PBT_SHOW_MAP=false
|
||||||
|
|||||||
+17
-11
@@ -1,8 +1,10 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}{{ "Fahrt bearbeiten" if fahrt else "Neue Fahrt" }} – PBT{% endblock %}
|
{% block title %}{{ "Fahrt bearbeiten" if fahrt else "Neue Fahrt" }} – PBT{% endblock %}
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
|
{% if show_map %}
|
||||||
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="">
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
|
||||||
|
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="">
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="card">
|
<div class="card">
|
||||||
@@ -54,12 +56,14 @@
|
|||||||
if fahrt and fahrt.destination_stop else "" }}</p>
|
if fahrt and fahrt.destination_stop else "" }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field">
|
{% if show_map %}
|
||||||
<label>Kartenvorschau</label>
|
<div class="field">
|
||||||
<p class="field-hint" data-route-map-placeholder>Wähle bekannte Haltestellen bei Von/Nach für eine Kartenvorschau.</p>
|
<label>Kartenvorschau</label>
|
||||||
<div id="route-map" class="route-map" hidden></div>
|
<p class="field-hint" data-route-map-placeholder>Wähle bekannte Haltestellen bei Von/Nach für eine Kartenvorschau.</p>
|
||||||
<p class="field-hint">Luftlinie zwischen den Halten – keine echte Streckenführung.</p>
|
<div id="route-map" class="route-map" hidden></div>
|
||||||
</div>
|
<p class="field-hint">Luftlinie zwischen den Halten – keine echte Streckenführung.</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="field combo">
|
<div class="field combo">
|
||||||
<label for="line">Linie</label>
|
<label for="line">Linie</label>
|
||||||
@@ -115,8 +119,10 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
|
{% if show_map %}
|
||||||
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin="" defer></script>
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
|
||||||
<script src="{{ url_for('static', filename='map.js') }}" defer></script>
|
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin="" defer></script>
|
||||||
|
<script src="{{ url_for('static', filename='map.js') }}" defer></script>
|
||||||
|
{% endif %}
|
||||||
<script src="{{ url_for('static', filename='stops.js') }}" defer></script>
|
<script src="{{ url_for('static', filename='stops.js') }}" defer></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
+32
-24
@@ -1,8 +1,10 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}Meine Fahrten – PBT{% endblock %}
|
{% block title %}Meine Fahrten – PBT{% endblock %}
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
|
{% if show_map %}
|
||||||
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="">
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
|
||||||
|
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="">
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2 style="font-size: 1.1rem; font-weight: 600;">Meine Fahrten</h2>
|
<h2 style="font-size: 1.1rem; font-weight: 600;">Meine Fahrten</h2>
|
||||||
@@ -40,18 +42,20 @@
|
|||||||
<td class="stars">{{ "★" * f.rating }}{{ "☆" * (5 - f.rating) }}</td>
|
<td class="stars">{{ "★" * f.rating }}{{ "☆" * (5 - f.rating) }}</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="row-actions">
|
<div class="row-actions">
|
||||||
<button type="button" class="icon-btn map" title="Route auf Karte anzeigen"
|
{% if show_map %}
|
||||||
aria-label="Route auf Karte anzeigen" data-show-map
|
<button type="button" class="icon-btn map" title="Route auf Karte anzeigen"
|
||||||
data-origin-label="{{ f.origin }}" data-destination-label="{{ f.destination }}"
|
aria-label="Route auf Karte anzeigen" data-show-map
|
||||||
{% if f.origin_stop %}data-origin-lat="{{ f.origin_stop.latitude }}" data-origin-lon="{{ f.origin_stop.longitude }}"{% endif %}
|
data-origin-label="{{ f.origin }}" data-destination-label="{{ f.destination }}"
|
||||||
{% if f.destination_stop %}data-destination-lat="{{ f.destination_stop.latitude }}" data-destination-lon="{{ f.destination_stop.longitude }}"{% endif %}
|
{% if f.origin_stop %}data-origin-lat="{{ f.origin_stop.latitude }}" data-origin-lon="{{ f.origin_stop.longitude }}"{% endif %}
|
||||||
{% if not f.origin_stop and not f.destination_stop %}disabled{% endif %}>
|
{% if f.destination_stop %}data-destination-lat="{{ f.destination_stop.latitude }}" data-destination-lon="{{ f.destination_stop.longitude }}"{% endif %}
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
{% if not f.origin_stop and not f.destination_stop %}disabled{% endif %}>
|
||||||
stroke-linecap="round" stroke-linejoin="round">
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||||
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path>
|
stroke-linecap="round" stroke-linejoin="round">
|
||||||
<circle cx="12" cy="10" r="3"></circle>
|
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path>
|
||||||
</svg>
|
<circle cx="12" cy="10" r="3"></circle>
|
||||||
</button>
|
</svg>
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
<a class="icon-btn edit" href="{{ url_for('fahrt_bearbeiten', fahrt_id=f.id) }}"
|
<a class="icon-btn edit" href="{{ url_for('fahrt_bearbeiten', fahrt_id=f.id) }}"
|
||||||
title="Fahrt bearbeiten" aria-label="Fahrt bearbeiten">
|
title="Fahrt bearbeiten" aria-label="Fahrt bearbeiten">
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||||
@@ -83,16 +87,20 @@
|
|||||||
</table>
|
</table>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<dialog id="route-map-dialog" class="map-dialog">
|
{% if show_map %}
|
||||||
<div class="map-dialog-header">
|
<dialog id="route-map-dialog" class="map-dialog">
|
||||||
<span id="route-map-dialog-title"></span>
|
<div class="map-dialog-header">
|
||||||
<button type="button" class="icon-btn" data-close-map-dialog aria-label="Schließen">✕</button>
|
<span id="route-map-dialog-title"></span>
|
||||||
</div>
|
<button type="button" class="icon-btn" data-close-map-dialog aria-label="Schließen">✕</button>
|
||||||
<div id="dialog-route-map" class="route-map"></div>
|
</div>
|
||||||
</dialog>
|
<div id="dialog-route-map" class="route-map"></div>
|
||||||
|
</dialog>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
|
{% if show_map %}
|
||||||
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin="" defer></script>
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
|
||||||
<script src="{{ url_for('static', filename='map.js') }}" defer></script>
|
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin="" defer></script>
|
||||||
|
<script src="{{ url_for('static', filename='map.js') }}" defer></script>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user