Fetch stops from OpenStreetMap
Deploy PBT / deploy (push) Successful in 16s

This commit is contained in:
2026-09-10 21:44:45 +02:00
parent 0ebf13aacf
commit 2a6e9c690b
14 changed files with 666 additions and 9 deletions
+73 -3
View File
@@ -1,6 +1,6 @@
from datetime import date
from flask import Flask, render_template, redirect, url_for, request, flash
from flask import Flask, render_template, redirect, url_for, request, flash, jsonify
from flask_login import (
LoginManager,
login_user,
@@ -10,7 +10,8 @@ from flask_login import (
)
from config import Config
from models import db, User, Trip, VERKEHRSMITTEL_OPTIONEN
from models import db, User, Trip, Stop, VERKEHRSMITTEL_OPTIONEN
from stops_import import normalize_name, register_cli
login_manager = LoginManager()
login_manager.login_view = "login"
@@ -27,6 +28,7 @@ def create_app():
db.create_all()
register_routes(app)
register_cli(app)
return app
@@ -97,6 +99,70 @@ def register_routes(app):
)
return render_template("dashboard.html", fahrten=fahrten)
@app.route("/api/stops")
@login_required
def api_stops():
"""Autocomplete for the origin/destination fields."""
query = request.args.get("q", "").strip()
if len(query) < 2:
return jsonify([])
needle = normalize_name(query).replace("\\", "\\\\")
needle = needle.replace("%", r"\%").replace("_", r"\_")
order = (db.func.length(Stop.name), Stop.name)
results = (
Stop.query.filter(Stop.name_normalized.like(needle + "%", escape="\\"))
.order_by(*order)
.limit(8)
.all()
)
if len(results) < 8:
seen = {stop.id for stop in results}
for stop in (
Stop.query.filter(
Stop.name_normalized.like("%" + needle + "%", escape="\\")
)
.order_by(*order)
.limit(20)
.all()
):
if stop.id not in seen:
results.append(stop)
if len(results) >= 8:
break
return jsonify(
[
{
"id": stop.id,
"name": stop.name,
"type": stop.stop_type,
"municipality": stop.municipality,
"lat": stop.latitude,
"lon": stop.longitude,
}
for stop in results
]
)
def parse_trip_date(raw_value):
raw_value = (raw_value or "").strip()
try:
return date.fromisoformat(raw_value) if raw_value else date.today()
except ValueError:
return date.today()
def resolve_stop_id(raw_id):
"""Return a valid Stop.id for a submitted value, or None (free text)."""
if not raw_id:
return None
try:
stop = db.session.get(Stop, int(raw_id))
except (TypeError, ValueError):
return None
return stop.id if stop is not None else None
@app.route("/fahrt/neu", methods=["GET", "POST"])
@login_required
def neue_fahrt():
@@ -106,8 +172,12 @@ def register_routes(app):
transport_mode=request.form["transport_mode"],
line=request.form.get("line", "").strip(),
origin=request.form["origin"].strip(),
origin_stop_id=resolve_stop_id(request.form.get("origin_stop_id")),
destination=request.form["destination"].strip(),
trip_date=request.form.get("trip_date") or date.today(),
destination_stop_id=resolve_stop_id(
request.form.get("destination_stop_id")
),
trip_date=parse_trip_date(request.form.get("trip_date")),
rating=int(request.form["rating"]),
comment=request.form.get("comment", "").strip(),
)