Compare commits
2 commits
e0735b4185
...
fd34190368
Author | SHA1 | Date | |
---|---|---|---|
Edward Betts | fd34190368 | ||
Edward Betts | 4a990a9fe5 |
184
agenda/trip.py
Normal file
184
agenda/trip.py
Normal file
|
@ -0,0 +1,184 @@
|
||||||
|
import operator
|
||||||
|
import os
|
||||||
|
from datetime import date
|
||||||
|
|
||||||
|
import flask
|
||||||
|
|
||||||
|
from agenda import travel
|
||||||
|
from agenda.types import StrDict, Trip
|
||||||
|
|
||||||
|
|
||||||
|
def load_travel(travel_type: str) -> list[StrDict]:
|
||||||
|
"""Read flight and train journeys."""
|
||||||
|
data_dir = flask.current_app.config["PERSONAL_DATA"]
|
||||||
|
items = travel.parse_yaml(travel_type + "s", data_dir)
|
||||||
|
for item in items:
|
||||||
|
item["type"] = travel_type
|
||||||
|
return items
|
||||||
|
|
||||||
|
|
||||||
|
def load_trains() -> list[StrDict]:
|
||||||
|
"""Load trains."""
|
||||||
|
data_dir = flask.current_app.config["PERSONAL_DATA"]
|
||||||
|
|
||||||
|
trains = load_travel("train")
|
||||||
|
stations = travel.parse_yaml("stations", data_dir)
|
||||||
|
by_name = {station["name"]: station for station in stations}
|
||||||
|
|
||||||
|
for train in trains:
|
||||||
|
assert train["from"] in by_name
|
||||||
|
assert train["to"] in by_name
|
||||||
|
train["from_station"] = by_name[train["from"]]
|
||||||
|
train["to_station"] = by_name[train["to"]]
|
||||||
|
|
||||||
|
for leg in train["legs"]:
|
||||||
|
assert leg["from"] in by_name
|
||||||
|
assert leg["to"] in by_name
|
||||||
|
leg["from_station"] = by_name[leg["from"]]
|
||||||
|
leg["to_station"] = by_name[leg["to"]]
|
||||||
|
|
||||||
|
return trains
|
||||||
|
|
||||||
|
|
||||||
|
def load_flights() -> list[StrDict]:
|
||||||
|
"""Load flights."""
|
||||||
|
data_dir = flask.current_app.config["PERSONAL_DATA"]
|
||||||
|
flights = load_travel("flight")
|
||||||
|
airports = travel.parse_yaml("airports", data_dir)
|
||||||
|
for flight in flights:
|
||||||
|
if flight["from"] in airports:
|
||||||
|
flight["from_airport"] = airports[flight["from"]]
|
||||||
|
if flight["to"] in airports:
|
||||||
|
flight["to_airport"] = airports[flight["to"]]
|
||||||
|
return flights
|
||||||
|
|
||||||
|
|
||||||
|
def build_trip_list() -> list[Trip]:
|
||||||
|
"""Generate list of trips."""
|
||||||
|
trips: dict[date, Trip] = {}
|
||||||
|
|
||||||
|
data_dir = flask.current_app.config["PERSONAL_DATA"]
|
||||||
|
|
||||||
|
travel_items = sorted(
|
||||||
|
load_flights() + load_trains(), key=operator.itemgetter("depart")
|
||||||
|
)
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"travel": travel_items,
|
||||||
|
"accommodation": travel.parse_yaml("accommodation", data_dir),
|
||||||
|
"conferences": travel.parse_yaml("conferences", data_dir),
|
||||||
|
"events": travel.parse_yaml("events", data_dir),
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, item_list in data.items():
|
||||||
|
assert isinstance(item_list, list)
|
||||||
|
for item in item_list:
|
||||||
|
if not (start := item.get("trip")):
|
||||||
|
continue
|
||||||
|
if start not in trips:
|
||||||
|
trips[start] = Trip(start=start)
|
||||||
|
getattr(trips[start], key).append(item)
|
||||||
|
|
||||||
|
return [trip for _, trip in sorted(trips.items())]
|
||||||
|
|
||||||
|
|
||||||
|
def collect_trip_coordinates(trip: Trip) -> list[StrDict]:
|
||||||
|
"""Extract and deduplicate airport and station coordinates from trip."""
|
||||||
|
stations = {}
|
||||||
|
station_list = []
|
||||||
|
airports = {}
|
||||||
|
for t in trip.travel:
|
||||||
|
if t["type"] == "train":
|
||||||
|
station_list += [t["from_station"], t["to_station"]]
|
||||||
|
for leg in t["legs"]:
|
||||||
|
station_list.append(leg["from_station"])
|
||||||
|
station_list.append(leg["to_station"])
|
||||||
|
else:
|
||||||
|
assert t["type"] == "flight"
|
||||||
|
for field in "from_airport", "to_airport":
|
||||||
|
if field in t:
|
||||||
|
airports[t[field]["iata"]] = t[field]
|
||||||
|
|
||||||
|
for s in station_list:
|
||||||
|
if s["uic"] in stations:
|
||||||
|
continue
|
||||||
|
stations[s["uic"]] = s
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"name": s["name"],
|
||||||
|
"type": "station",
|
||||||
|
"latitude": s["latitude"],
|
||||||
|
"longitude": s["longitude"],
|
||||||
|
}
|
||||||
|
for s in stations.values()
|
||||||
|
] + [
|
||||||
|
{
|
||||||
|
"name": s["name"],
|
||||||
|
"type": "airport",
|
||||||
|
"latitude": s["latitude"],
|
||||||
|
"longitude": s["longitude"],
|
||||||
|
}
|
||||||
|
for s in airports.values()
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def latlon_tuple(stop: StrDict) -> tuple[float, float]:
|
||||||
|
"""Given a transport stop return the lat/lon as a tuple."""
|
||||||
|
return (stop["latitude"], stop["longitude"])
|
||||||
|
|
||||||
|
|
||||||
|
def read_geojson(filename: str) -> str:
|
||||||
|
"""Read GeoJSON from file."""
|
||||||
|
data_dir = flask.current_app.config["PERSONAL_DATA"]
|
||||||
|
return open(os.path.join(data_dir, "train_routes", filename + ".geojson")).read()
|
||||||
|
|
||||||
|
|
||||||
|
def get_trip_routes(trip: Trip) -> list[StrDict]:
|
||||||
|
"""Get routes for given trip to show on map."""
|
||||||
|
routes = []
|
||||||
|
seen_geojson = set()
|
||||||
|
for t in trip.travel:
|
||||||
|
if t["type"] == "flight":
|
||||||
|
if "from_airport" not in t or "to_airport" not in t:
|
||||||
|
continue
|
||||||
|
fly_from, fly_to = t["from_airport"], t["to_airport"]
|
||||||
|
key = "_".join(["flight"] + sorted([fly_from["iata"], fly_to["iata"]]))
|
||||||
|
routes.append(
|
||||||
|
{
|
||||||
|
"type": "flight",
|
||||||
|
"key": key,
|
||||||
|
"from": latlon_tuple(fly_from),
|
||||||
|
"to": latlon_tuple(fly_to),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
assert t["type"] == "train"
|
||||||
|
for leg in t["legs"]:
|
||||||
|
train_from, train_to = leg["from_station"], leg["to_station"]
|
||||||
|
geojson_filename = train_from.get("routes", {}).get(train_to["uic"])
|
||||||
|
key = "_".join(["train"] + sorted([train_from["name"], train_to["name"]]))
|
||||||
|
if not geojson_filename:
|
||||||
|
routes.append(
|
||||||
|
{
|
||||||
|
"type": "train",
|
||||||
|
"key": key,
|
||||||
|
"from": latlon_tuple(train_from),
|
||||||
|
"to": latlon_tuple(train_to),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if geojson_filename in seen_geojson:
|
||||||
|
continue
|
||||||
|
seen_geojson.add(geojson_filename)
|
||||||
|
|
||||||
|
routes.append(
|
||||||
|
{
|
||||||
|
"type": "train",
|
||||||
|
"key": key,
|
||||||
|
"geojson_filename": geojson_filename,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return routes
|
|
@ -5,6 +5,11 @@
|
||||||
{% set row = { "flight": flight_row, "train": train_row } %}
|
{% set row = { "flight": flight_row, "train": train_row } %}
|
||||||
|
|
||||||
{% block style %}
|
{% block style %}
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
|
||||||
|
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
|
||||||
|
crossorigin=""/>
|
||||||
|
|
||||||
{% set conference_column_count = 6 %}
|
{% set conference_column_count = 6 %}
|
||||||
{% set accommodation_column_count = 7 %}
|
{% set accommodation_column_count = 7 %}
|
||||||
{% set travel_column_count = 7 %}
|
{% set travel_column_count = 7 %}
|
||||||
|
@ -33,6 +38,13 @@
|
||||||
.grid-item {
|
.grid-item {
|
||||||
/* Additional styling for grid items can go here */
|
/* Additional styling for grid items can go here */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#map {
|
||||||
|
height: 80vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
@ -79,11 +91,69 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="p-2">
|
<div class="p-2">
|
||||||
|
|
||||||
|
<div id="map"></div>
|
||||||
|
|
||||||
<h1>Trips</h1>
|
<h1>Trips</h1>
|
||||||
{{ section("Current", current, "attending") }}
|
{{ section("Current", current, "attending") }}
|
||||||
{{ section("Future", future, "going") }}
|
{{ section("Future", future, "going") }}
|
||||||
{{ section("Past", past|reverse, "went") }}
|
{{ section("Past", past|reverse, "went") }}
|
||||||
</div>
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
|
||||||
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
|
||||||
|
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
|
||||||
|
crossorigin=""></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var future_coordinates = {{ future_coordinates | tojson }};
|
||||||
|
var future_routes = {{ future_routes | tojson }};
|
||||||
|
|
||||||
|
// Initialize the map
|
||||||
|
var map = L.map('map').fitBounds(future_coordinates.map(function(station) {
|
||||||
|
return [station.latitude, station.longitude];
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Set up the tile layer
|
||||||
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
|
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
var stationIcon = L.divIcon({
|
||||||
|
className: 'custom-div-icon',
|
||||||
|
html: "<div style='font-size: 24px;'>🚉</div>",
|
||||||
|
iconSize: [30, 42],
|
||||||
|
});
|
||||||
|
|
||||||
|
var airportIcon = L.divIcon({
|
||||||
|
className: 'custom-div-icon',
|
||||||
|
html: "<div style='font-size: 24px;'>✈️</div>",
|
||||||
|
iconSize: [30, 42],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add markers with appropriate icons to the map
|
||||||
|
future_coordinates.forEach(function(item) {
|
||||||
|
var icon = item.type === "station" ? stationIcon : airportIcon;
|
||||||
|
var marker = L.marker([item.latitude, item.longitude], { icon: icon }).addTo(map);
|
||||||
|
marker.bindPopup(item.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Draw routes
|
||||||
|
future_routes.forEach(function(route) {
|
||||||
|
if (route.geojson) {
|
||||||
|
// If route is defined as GeoJSON
|
||||||
|
L.geoJSON(JSON.parse(route.geojson), {
|
||||||
|
style: function(feature) {
|
||||||
|
return {color: route.type === "train" ? "blue" : "blue"}; // Green for trains, blue for flights
|
||||||
|
}
|
||||||
|
}).addTo(map);
|
||||||
|
} else {
|
||||||
|
// If route is defined by 'from' and 'to' coordinates
|
||||||
|
var color = route.type === "train" ? "blue" : "red"; // Green for trains, red for flights
|
||||||
|
L.polyline([route.from, route.to], {color: color}).addTo(map);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
207
web_view.py
207
web_view.py
|
@ -17,8 +17,8 @@ import yaml
|
||||||
import agenda.data
|
import agenda.data
|
||||||
import agenda.error_mail
|
import agenda.error_mail
|
||||||
import agenda.thespacedevs
|
import agenda.thespacedevs
|
||||||
|
import agenda.trip
|
||||||
from agenda import format_list_with_ampersand, travel
|
from agenda import format_list_with_ampersand, travel
|
||||||
from agenda.types import StrDict, Trip
|
|
||||||
|
|
||||||
app = flask.Flask(__name__)
|
app = flask.Flask(__name__)
|
||||||
app.debug = False
|
app.debug = False
|
||||||
|
@ -155,84 +155,10 @@ def accommodation_list() -> str:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def load_travel(travel_type: str) -> list[StrDict]:
|
|
||||||
"""Read flight and train journeys."""
|
|
||||||
data_dir = app.config["PERSONAL_DATA"]
|
|
||||||
items = travel.parse_yaml(travel_type + "s", data_dir)
|
|
||||||
for item in items:
|
|
||||||
item["type"] = travel_type
|
|
||||||
return items
|
|
||||||
|
|
||||||
|
|
||||||
def load_trains() -> list[StrDict]:
|
|
||||||
"""Load trains."""
|
|
||||||
data_dir = app.config["PERSONAL_DATA"]
|
|
||||||
|
|
||||||
trains = load_travel("train")
|
|
||||||
stations = travel.parse_yaml("stations", data_dir)
|
|
||||||
by_name = {station["name"]: station for station in stations}
|
|
||||||
|
|
||||||
for train in trains:
|
|
||||||
assert train["from"] in by_name
|
|
||||||
assert train["to"] in by_name
|
|
||||||
train["from_station"] = by_name[train["from"]]
|
|
||||||
train["to_station"] = by_name[train["to"]]
|
|
||||||
|
|
||||||
for leg in train["legs"]:
|
|
||||||
assert leg["from"] in by_name
|
|
||||||
assert leg["to"] in by_name
|
|
||||||
leg["from_station"] = by_name[leg["from"]]
|
|
||||||
leg["to_station"] = by_name[leg["to"]]
|
|
||||||
|
|
||||||
return trains
|
|
||||||
|
|
||||||
|
|
||||||
def load_flights() -> list[StrDict]:
|
|
||||||
"""Load flights."""
|
|
||||||
data_dir = app.config["PERSONAL_DATA"]
|
|
||||||
flights = load_travel("flight")
|
|
||||||
airports = travel.parse_yaml("airports", data_dir)
|
|
||||||
for flight in flights:
|
|
||||||
if flight["from"] in airports:
|
|
||||||
flight["from_airport"] = airports[flight["from"]]
|
|
||||||
if flight["to"] in airports:
|
|
||||||
flight["to_airport"] = airports[flight["to"]]
|
|
||||||
return flights
|
|
||||||
|
|
||||||
|
|
||||||
def build_trip_list() -> list[Trip]:
|
|
||||||
"""Generate list of trips."""
|
|
||||||
trips: dict[date, Trip] = {}
|
|
||||||
|
|
||||||
data_dir = app.config["PERSONAL_DATA"]
|
|
||||||
|
|
||||||
travel_items = sorted(
|
|
||||||
load_flights() + load_trains(), key=operator.itemgetter("depart")
|
|
||||||
)
|
|
||||||
|
|
||||||
data = {
|
|
||||||
"travel": travel_items,
|
|
||||||
"accommodation": travel.parse_yaml("accommodation", data_dir),
|
|
||||||
"conferences": travel.parse_yaml("conferences", data_dir),
|
|
||||||
"events": travel.parse_yaml("events", data_dir),
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, item_list in data.items():
|
|
||||||
assert isinstance(item_list, list)
|
|
||||||
for item in item_list:
|
|
||||||
if not (start := item.get("trip")):
|
|
||||||
continue
|
|
||||||
if start not in trips:
|
|
||||||
trips[start] = Trip(start=start)
|
|
||||||
getattr(trips[start], key).append(item)
|
|
||||||
|
|
||||||
return [trip for _, trip in sorted(trips.items())]
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/trip")
|
@app.route("/trip")
|
||||||
def trip_list() -> str:
|
def trip_list() -> str:
|
||||||
"""Page showing a list of trips."""
|
"""Page showing a list of trips."""
|
||||||
trip_list = build_trip_list()
|
trip_list = agenda.trip.build_trip_list()
|
||||||
|
|
||||||
today = date.today()
|
today = date.today()
|
||||||
current = [
|
current = [
|
||||||
|
@ -244,117 +170,45 @@ def trip_list() -> str:
|
||||||
past = [item for item in trip_list if (item.end or item.start) < today]
|
past = [item for item in trip_list if (item.end or item.start) < today]
|
||||||
future = [item for item in trip_list if item.start > today]
|
future = [item for item in trip_list if item.start > today]
|
||||||
|
|
||||||
|
future_coordinates = []
|
||||||
|
seen_future_coordinates: set[tuple[str, str]] = set()
|
||||||
|
future_routes = []
|
||||||
|
seen_future_routes: set[str] = set()
|
||||||
|
for trip in future:
|
||||||
|
for stop in agenda.trip.collect_trip_coordinates(trip):
|
||||||
|
key = (stop["type"], stop["name"])
|
||||||
|
if key in seen_future_coordinates:
|
||||||
|
continue
|
||||||
|
future_coordinates.append(stop)
|
||||||
|
seen_future_coordinates.add(key)
|
||||||
|
|
||||||
|
for route in agenda.trip.get_trip_routes(trip):
|
||||||
|
if route["key"] in seen_future_routes:
|
||||||
|
continue
|
||||||
|
future_routes.append(route)
|
||||||
|
seen_future_routes.add(route["key"])
|
||||||
|
|
||||||
|
for route in future_routes:
|
||||||
|
if "geojson_filename" in route:
|
||||||
|
route["geojson"] = agenda.trip.read_geojson(route.pop("geojson_filename"))
|
||||||
|
|
||||||
return flask.render_template(
|
return flask.render_template(
|
||||||
"trips.html",
|
"trips.html",
|
||||||
current=current,
|
current=current,
|
||||||
past=past,
|
past=past,
|
||||||
future=future,
|
future=future,
|
||||||
|
future_coordinates=future_coordinates,
|
||||||
|
future_routes=future_routes,
|
||||||
today=today,
|
today=today,
|
||||||
get_country=agenda.get_country,
|
get_country=agenda.get_country,
|
||||||
format_list_with_ampersand=format_list_with_ampersand,
|
format_list_with_ampersand=format_list_with_ampersand,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def collect_trip_coordinates(trip: Trip) -> list[StrDict]:
|
|
||||||
"""Extract and deduplicate airport and station coordinates from trip."""
|
|
||||||
stations = {}
|
|
||||||
station_list = []
|
|
||||||
airports = {}
|
|
||||||
for t in trip.travel:
|
|
||||||
if t["type"] == "train":
|
|
||||||
station_list += [t["from_station"], t["to_station"]]
|
|
||||||
for leg in t["legs"]:
|
|
||||||
station_list.append(leg["from_station"])
|
|
||||||
station_list.append(leg["to_station"])
|
|
||||||
else:
|
|
||||||
assert t["type"] == "flight"
|
|
||||||
for field in "from_airport", "to_airport":
|
|
||||||
if field in t:
|
|
||||||
airports[t[field]["iata"]] = t[field]
|
|
||||||
|
|
||||||
for s in station_list:
|
|
||||||
if s["uic"] in stations:
|
|
||||||
continue
|
|
||||||
stations[s["uic"]] = s
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
"name": s["name"],
|
|
||||||
"type": "station",
|
|
||||||
"latitude": s["latitude"],
|
|
||||||
"longitude": s["longitude"],
|
|
||||||
}
|
|
||||||
for s in stations.values()
|
|
||||||
] + [
|
|
||||||
{
|
|
||||||
"name": s["name"],
|
|
||||||
"type": "airport",
|
|
||||||
"latitude": s["latitude"],
|
|
||||||
"longitude": s["longitude"],
|
|
||||||
}
|
|
||||||
for s in airports.values()
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def latlon_tuple(stop: StrDict) -> tuple[float, float]:
|
|
||||||
"""Given a transport stop return the lat/lon as a tuple."""
|
|
||||||
return (stop["latitude"], stop["longitude"])
|
|
||||||
|
|
||||||
|
|
||||||
def read_geojson(filename: str) -> str:
|
|
||||||
data_dir = app.config["PERSONAL_DATA"]
|
|
||||||
return open(os.path.join(data_dir, "train_routes", filename + ".geojson")).read()
|
|
||||||
|
|
||||||
|
|
||||||
def get_trip_routes(trip: Trip) -> list[StrDict]:
|
|
||||||
routes = []
|
|
||||||
seen_geojson = set()
|
|
||||||
for t in trip.travel:
|
|
||||||
if t["type"] == "flight":
|
|
||||||
if "from_airport" not in t or "to_airport" not in t:
|
|
||||||
continue
|
|
||||||
fly_from, fly_to = t["from_airport"], t["to_airport"]
|
|
||||||
routes.append(
|
|
||||||
{
|
|
||||||
"type": "flight",
|
|
||||||
"from": latlon_tuple(fly_from),
|
|
||||||
"to": latlon_tuple(fly_to),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
else:
|
|
||||||
assert t["type"] == "train"
|
|
||||||
for leg in t["legs"]:
|
|
||||||
train_from, train_to = leg["from_station"], leg["to_station"]
|
|
||||||
geojson_filename = train_from.get("routes", {}).get(train_to["uic"])
|
|
||||||
if not geojson_filename:
|
|
||||||
routes.append(
|
|
||||||
{
|
|
||||||
"type": "train",
|
|
||||||
"from": latlon_tuple(train_from),
|
|
||||||
"to": latlon_tuple(train_to),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if geojson_filename in seen_geojson:
|
|
||||||
continue
|
|
||||||
seen_geojson.add(geojson_filename)
|
|
||||||
|
|
||||||
routes.append(
|
|
||||||
{
|
|
||||||
"type": "train",
|
|
||||||
"geojson": read_geojson(geojson_filename),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return routes
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/trip/<start>")
|
@app.route("/trip/<start>")
|
||||||
def trip_page(start: str) -> str:
|
def trip_page(start: str) -> str:
|
||||||
"""Individual trip page."""
|
"""Individual trip page."""
|
||||||
trip_list = build_trip_list()
|
trip_list = agenda.trip.build_trip_list()
|
||||||
today = date.today()
|
today = date.today()
|
||||||
|
|
||||||
trip = next((trip for trip in trip_list if trip.start.isoformat() == start), None)
|
trip = next((trip for trip in trip_list if trip.start.isoformat() == start), None)
|
||||||
|
@ -362,8 +216,11 @@ def trip_page(start: str) -> str:
|
||||||
if not trip:
|
if not trip:
|
||||||
flask.abort(404)
|
flask.abort(404)
|
||||||
|
|
||||||
coordinates = collect_trip_coordinates(trip)
|
coordinates = agenda.trip.collect_trip_coordinates(trip)
|
||||||
routes = get_trip_routes(trip)
|
routes = agenda.trip.get_trip_routes(trip)
|
||||||
|
for route in routes:
|
||||||
|
if "geojson_filename" in route:
|
||||||
|
route["geojson"] = agenda.trip.read_geojson(route.pop("geojson_filename"))
|
||||||
|
|
||||||
return flask.render_template(
|
return flask.render_template(
|
||||||
"trip_page.html",
|
"trip_page.html",
|
||||||
|
|
Loading…
Reference in a new issue