Use path segments for journey result URLs
This commit is contained in:
parent
ce6e8afcc8
commit
1c230ce0d6
3 changed files with 76 additions and 55 deletions
50
app.py
50
app.py
|
|
@ -389,9 +389,15 @@ def _results_url(
|
|||
**params,
|
||||
)
|
||||
if journey_type == "inbound":
|
||||
params["journey_type"] = "inbound"
|
||||
return url_for(
|
||||
"back_results",
|
||||
station_crs=station_crs,
|
||||
slug=slug,
|
||||
travel_date=travel_date,
|
||||
**params,
|
||||
)
|
||||
return url_for(
|
||||
"results",
|
||||
"out_results",
|
||||
station_crs=station_crs,
|
||||
slug=slug,
|
||||
travel_date=travel_date,
|
||||
|
|
@ -463,18 +469,17 @@ def search() -> ResponseReturnValue:
|
|||
return redirect(url_for("index"))
|
||||
|
||||
|
||||
@app.route("/results/<station_crs>/<slug>/<travel_date>")
|
||||
def results(station_crs: str, slug: str, travel_date: str) -> ResponseReturnValue:
|
||||
return _results(
|
||||
station_crs,
|
||||
slug,
|
||||
travel_date,
|
||||
request.args.get("journey_type", "outbound"),
|
||||
request.args.get("return_date"),
|
||||
)
|
||||
@app.route("/results/<station_crs>/<slug>/out/<travel_date>")
|
||||
def out_results(station_crs: str, slug: str, travel_date: str) -> ResponseReturnValue:
|
||||
return _results(station_crs, slug, travel_date, "outbound", None)
|
||||
|
||||
|
||||
@app.route("/results/<station_crs>/<slug>/<travel_date>/return/<return_date>")
|
||||
@app.route("/results/<station_crs>/<slug>/back/<travel_date>")
|
||||
def back_results(station_crs: str, slug: str, travel_date: str) -> ResponseReturnValue:
|
||||
return _results(station_crs, slug, travel_date, "inbound", None)
|
||||
|
||||
|
||||
@app.route("/results/<station_crs>/<slug>/return/<travel_date>/<return_date>")
|
||||
def return_results(
|
||||
station_crs: str, slug: str, travel_date: str, return_date: str
|
||||
) -> ResponseReturnValue:
|
||||
|
|
@ -1108,7 +1113,7 @@ def _results(
|
|||
station_crs=station_crs,
|
||||
slug=slug,
|
||||
travel_date=travel_date,
|
||||
journey_type=journey_type if journey_type == "inbound" else None,
|
||||
path_journey_type="back" if journey_type == "inbound" else "out",
|
||||
)
|
||||
|
||||
summary_html = _build_summary_html(
|
||||
|
|
@ -1331,7 +1336,7 @@ def _results(
|
|||
station_crs=station_crs,
|
||||
slug=slug,
|
||||
travel_date=travel_date,
|
||||
journey_type=journey_type if journey_type == "inbound" else None,
|
||||
path_journey_type="back" if journey_type == "inbound" else "out",
|
||||
)
|
||||
|
||||
return render_template(
|
||||
|
|
@ -1480,15 +1485,20 @@ def api_walkon_fares(
|
|||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
|
||||
@app.route("/api/results_refresh/<station_crs>/<slug>/<travel_date>")
|
||||
def api_results_refresh(station_crs: str, slug: str, travel_date: str) -> Response:
|
||||
return _api_results_refresh(
|
||||
station_crs, slug, travel_date, request.args.get("return_date")
|
||||
)
|
||||
@app.route(
|
||||
"/api/results_refresh/<station_crs>/<slug>/<path_journey_type>/<travel_date>"
|
||||
)
|
||||
def api_results_refresh(
|
||||
station_crs: str, slug: str, path_journey_type: str, travel_date: str
|
||||
) -> Response:
|
||||
if path_journey_type not in {"out", "back"}:
|
||||
abort(404)
|
||||
journey_type = "inbound" if path_journey_type == "back" else "outbound"
|
||||
return _api_results_refresh(station_crs, slug, travel_date, None, journey_type)
|
||||
|
||||
|
||||
@app.route(
|
||||
"/api/results_refresh/<station_crs>/<slug>/<travel_date>/return/<return_date>"
|
||||
"/api/results_refresh/<station_crs>/<slug>/return/<travel_date>/<return_date>"
|
||||
)
|
||||
def api_return_results_refresh(
|
||||
station_crs: str, slug: str, travel_date: str, return_date: str
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ def test_search_redirects_to_results_with_selected_params() -> None:
|
|||
|
||||
assert resp.status_code == 302
|
||||
assert resp.headers["Location"].endswith(
|
||||
"/results/BRI/rotterdam/2026-04-10?min_connection=60&max_connection=120"
|
||||
"/results/BRI/rotterdam/out/2026-04-10?min_connection=60&max_connection=120"
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -91,10 +91,21 @@ def test_search_redirects_return_with_return_date() -> None:
|
|||
|
||||
assert resp.status_code == 302
|
||||
assert resp.headers["Location"].endswith(
|
||||
"/results/BRI/paris/2026-04-10/return/2026-04-17"
|
||||
"/results/BRI/paris/return/2026-04-10/2026-04-17"
|
||||
)
|
||||
|
||||
|
||||
def test_search_redirects_inbound_to_back_path() -> None:
|
||||
client = _client()
|
||||
|
||||
resp = client.get(
|
||||
"/search?journey_type=inbound&destination=paris&travel_date=2026-04-10&station_crs=BRI"
|
||||
)
|
||||
|
||||
assert resp.status_code == 302
|
||||
assert resp.headers["Location"].endswith("/results/BRI/paris/back/2026-04-10")
|
||||
|
||||
|
||||
def test_nr_weekday_cache_key_includes_timetable_period() -> None:
|
||||
key = app_module._nr_weekday_cache_key("to_paddington", "BRI", "2026-06-22")
|
||||
|
||||
|
|
@ -106,7 +117,7 @@ def test_results_shows_same_day_destination_switcher(monkeypatch: Any) -> None:
|
|||
client = _client()
|
||||
|
||||
resp = client.get(
|
||||
"/results/BRI/paris/2026-04-10?min_connection=60&max_connection=120"
|
||||
"/results/BRI/paris/out/2026-04-10?min_connection=60&max_connection=120"
|
||||
)
|
||||
html = resp.get_data(as_text=True)
|
||||
|
||||
|
|
@ -114,11 +125,11 @@ def test_results_shows_same_day_destination_switcher(monkeypatch: Any) -> None:
|
|||
assert "Switch destination for Friday 10 April 2026" in html
|
||||
assert '<span class="chip-current">Paris Gare du Nord</span>' in html
|
||||
assert (
|
||||
"/results/BRI/brussels/2026-04-10?min_connection=60&max_connection=120"
|
||||
"/results/BRI/brussels/out/2026-04-10?min_connection=60&max_connection=120"
|
||||
in html
|
||||
)
|
||||
assert (
|
||||
"/results/BRI/rotterdam/2026-04-10?min_connection=60&max_connection=120"
|
||||
"/results/BRI/rotterdam/out/2026-04-10?min_connection=60&max_connection=120"
|
||||
in html
|
||||
)
|
||||
assert "ES 9014" in html
|
||||
|
|
@ -171,7 +182,7 @@ def test_results_can_render_from_weekday_timetable_cache(monkeypatch: Any) -> No
|
|||
client = _client()
|
||||
|
||||
resp = client.get(
|
||||
"/results/BRI/paris/2026-06-22?min_connection=60&max_connection=120"
|
||||
"/results/BRI/paris/out/2026-06-22?min_connection=60&max_connection=120"
|
||||
)
|
||||
html = resp.get_data(as_text=True)
|
||||
|
||||
|
|
@ -180,7 +191,7 @@ def test_results_can_render_from_weekday_timetable_cache(monkeypatch: Any) -> No
|
|||
assert "10:01 → 13:34" in html
|
||||
assert "ES 9014" in html
|
||||
assert "checking exact timetable" in html
|
||||
assert "/api/results_refresh/BRI/paris/2026-06-22" in html
|
||||
assert "/api/results_refresh/BRI/paris/out/2026-06-22" in html
|
||||
assert "refreshFullResults()" in html
|
||||
assert "window.location.reload()" not in html
|
||||
assert "Checking Eurostar price" in html
|
||||
|
|
@ -268,7 +279,7 @@ def test_results_refresh_reloads_when_exact_timetable_differs(monkeypatch: Any)
|
|||
)
|
||||
client = _client()
|
||||
|
||||
resp = client.get("/api/results_refresh/BRI/paris/2026-06-22")
|
||||
resp = client.get("/api/results_refresh/BRI/paris/out/2026-06-22")
|
||||
body = resp.get_data(as_text=True)
|
||||
|
||||
assert resp.status_code == 200
|
||||
|
|
@ -341,7 +352,7 @@ def test_results_refresh_streams_prices_when_timetable_matches(
|
|||
)
|
||||
client = _client()
|
||||
|
||||
resp = client.get("/api/results_refresh/BRI/paris/2026-06-22")
|
||||
resp = client.get("/api/results_refresh/BRI/paris/out/2026-06-22")
|
||||
body = resp.get_data(as_text=True)
|
||||
|
||||
assert resp.status_code == 200
|
||||
|
|
@ -362,7 +373,7 @@ def test_results_progressive_shell_loads_without_scraping(monkeypatch: Any) -> N
|
|||
monkeypatch.setattr(gwr_fares_scraper, "fetch", fail_fetch)
|
||||
client = _client()
|
||||
|
||||
resp = client.get("/results/BRI/paris/2026-04-10?progressive=1")
|
||||
resp = client.get("/results/BRI/paris/out/2026-04-10?progressive=1")
|
||||
html = resp.get_data(as_text=True)
|
||||
|
||||
assert resp.status_code == 200
|
||||
|
|
@ -379,7 +390,7 @@ def test_return_progressive_shell_formats_return_date(monkeypatch: Any) -> None:
|
|||
monkeypatch.setattr(gwr_fares_scraper, "fetch", fail_fetch)
|
||||
client = _client()
|
||||
|
||||
resp = client.get("/results/BRI/paris/2026-04-10/return/2026-04-17?progressive=1")
|
||||
resp = client.get("/results/BRI/paris/return/2026-04-10/2026-04-17?progressive=1")
|
||||
html = resp.get_data(as_text=True)
|
||||
|
||||
assert resp.status_code == 200
|
||||
|
|
@ -392,7 +403,7 @@ def test_results_title_and_social_meta_include_destination(monkeypatch: Any) ->
|
|||
client = _client()
|
||||
|
||||
resp = client.get(
|
||||
"/results/BRI/lille/2026-04-10?min_connection=60&max_connection=120"
|
||||
"/results/BRI/lille/out/2026-04-10?min_connection=60&max_connection=120"
|
||||
)
|
||||
html = resp.get_data(as_text=True)
|
||||
|
||||
|
|
@ -407,7 +418,7 @@ def test_results_title_and_social_meta_include_destination(monkeypatch: Any) ->
|
|||
'to Lille Europe on Friday 10 April 2026 via Paddington, St Pancras, and Eurostar.">'
|
||||
) in html
|
||||
assert (
|
||||
'<meta property="og:url" content="http://localhost/results/BRI/lille/2026-04-10?min_connection=60&max_connection=120">'
|
||||
'<meta property="og:url" content="http://localhost/results/BRI/lille/out/2026-04-10?min_connection=60&max_connection=120">'
|
||||
in html
|
||||
)
|
||||
|
||||
|
|
@ -498,7 +509,7 @@ def test_results_marks_trips_within_five_minutes_of_fastest_and_slowest(
|
|||
client = _client()
|
||||
|
||||
resp = client.get(
|
||||
"/results/BRI/paris/2026-04-10?min_connection=60&max_connection=120"
|
||||
"/results/BRI/paris/out/2026-04-10?min_connection=60&max_connection=120"
|
||||
)
|
||||
html = resp.get_data(as_text=True)
|
||||
|
||||
|
|
@ -567,7 +578,7 @@ def test_results_shows_only_pre_first_reachable_unreachable_services(
|
|||
client = _client()
|
||||
|
||||
resp = client.get(
|
||||
"/results/BRI/paris/2026-04-10?min_connection=60&max_connection=120"
|
||||
"/results/BRI/paris/out/2026-04-10?min_connection=60&max_connection=120"
|
||||
)
|
||||
html = resp.get_data(as_text=True)
|
||||
|
||||
|
|
@ -583,7 +594,7 @@ def test_results_shows_eurostar_price_and_total(monkeypatch: Any) -> None:
|
|||
client = _client()
|
||||
|
||||
resp = client.get(
|
||||
"/results/BRI/paris/2026-04-10?min_connection=60&max_connection=120"
|
||||
"/results/BRI/paris/out/2026-04-10?min_connection=60&max_connection=120"
|
||||
)
|
||||
html = resp.get_data(as_text=True)
|
||||
|
||||
|
|
@ -640,7 +651,7 @@ def test_results_uses_unique_row_keys_for_same_eurostar(monkeypatch: Any) -> Non
|
|||
client = _client()
|
||||
|
||||
resp = client.get(
|
||||
"/results/BRI/paris/2026-04-10?min_connection=60&max_connection=120"
|
||||
"/results/BRI/paris/out/2026-04-10?min_connection=60&max_connection=120"
|
||||
)
|
||||
html = resp.get_data(as_text=True)
|
||||
|
||||
|
|
@ -685,7 +696,7 @@ def test_results_shows_unreachable_service_when_no_trips(monkeypatch: Any) -> No
|
|||
client = _client()
|
||||
|
||||
resp = client.get(
|
||||
"/results/BRI/paris/2026-04-10?min_connection=60&max_connection=120"
|
||||
"/results/BRI/paris/out/2026-04-10?min_connection=60&max_connection=120"
|
||||
)
|
||||
html = resp.get_data(as_text=True)
|
||||
|
||||
|
|
@ -703,7 +714,7 @@ def test_results_shows_eurostar_plus_price(monkeypatch: Any) -> None:
|
|||
client = _client()
|
||||
|
||||
resp = client.get(
|
||||
"/results/BRI/paris/2026-04-10?min_connection=60&max_connection=120"
|
||||
"/results/BRI/paris/out/2026-04-10?min_connection=60&max_connection=120"
|
||||
)
|
||||
html = resp.get_data(as_text=True)
|
||||
|
||||
|
|
@ -718,7 +729,7 @@ def test_results_selectors_present(monkeypatch: Any) -> None:
|
|||
client = _client()
|
||||
|
||||
resp = client.get(
|
||||
"/results/BRI/paris/2026-04-10?min_connection=60&max_connection=120"
|
||||
"/results/BRI/paris/out/2026-04-10?min_connection=60&max_connection=120"
|
||||
)
|
||||
html = resp.get_data(as_text=True)
|
||||
|
||||
|
|
@ -775,7 +786,7 @@ def test_results_preloads_cached_advance_fares(monkeypatch: Any) -> None:
|
|||
client = _client()
|
||||
|
||||
resp = client.get(
|
||||
"/results/BRI/paris/2026-04-10?min_connection=60&max_connection=120"
|
||||
"/results/BRI/paris/out/2026-04-10?min_connection=60&max_connection=120"
|
||||
)
|
||||
html = resp.get_data(as_text=True)
|
||||
|
||||
|
|
@ -827,7 +838,7 @@ def test_results_inbound_uses_reverse_legs(monkeypatch: Any) -> None:
|
|||
)
|
||||
client = _client()
|
||||
|
||||
resp = client.get("/results/BRI/paris/2026-04-10?journey_type=inbound")
|
||||
resp = client.get("/results/BRI/paris/back/2026-04-10")
|
||||
html = resp.get_data(as_text=True)
|
||||
|
||||
assert resp.status_code == 200
|
||||
|
|
@ -917,7 +928,7 @@ def test_results_return_renders_outbound_and_inbound_tables(monkeypatch: Any) ->
|
|||
)
|
||||
client = _client()
|
||||
|
||||
resp = client.get("/results/BRI/paris/2026-04-10/return/2026-04-17")
|
||||
resp = client.get("/results/BRI/paris/return/2026-04-10/2026-04-17")
|
||||
html = resp.get_data(as_text=True)
|
||||
|
||||
assert resp.status_code == 200
|
||||
|
|
@ -925,11 +936,11 @@ def test_results_return_renders_outbound_and_inbound_tables(monkeypatch: Any) ->
|
|||
assert "Return: Paris Gare du Nord → Bristol Temple Meads" in html
|
||||
assert "Friday 10 April 2026" in html
|
||||
assert "Friday 17 April 2026" in html
|
||||
assert "/results/BRI/paris/2026-04-09/return/2026-04-17" in html
|
||||
assert "/results/BRI/paris/2026-04-11/return/2026-04-17" in html
|
||||
assert "/results/BRI/paris/2026-04-10/return/2026-04-16" in html
|
||||
assert "/results/BRI/paris/2026-04-10/return/2026-04-18" in html
|
||||
assert "/results/BRI/paris/2026-04-10/return/2026-04-17" in html
|
||||
assert "/results/BRI/paris/return/2026-04-09/2026-04-17" in html
|
||||
assert "/results/BRI/paris/return/2026-04-11/2026-04-17" in html
|
||||
assert "/results/BRI/paris/return/2026-04-10/2026-04-16" in html
|
||||
assert "/results/BRI/paris/return/2026-04-10/2026-04-18" in html
|
||||
assert "/results/BRI/paris/return/2026-04-10/2026-04-17" in html
|
||||
assert "journey_type=return" not in html
|
||||
assert "return_date=2026-04-17" not in html
|
||||
assert "Circle 09:10 → KX 09:25" in html
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ def test_single_advance_standard_totals_after_click(single_server: str) -> None:
|
|||
browser = _launch_browser(p)
|
||||
page = browser.new_page()
|
||||
page.goto(
|
||||
f"{single_server}/results/BRI/paris/2026-07-20",
|
||||
f"{single_server}/results/BRI/paris/out/2026-07-20",
|
||||
wait_until="domcontentloaded",
|
||||
)
|
||||
|
||||
|
|
@ -344,7 +344,7 @@ def test_single_next_date_advance_standard_labels_unreachable_rows(
|
|||
page = browser.new_page()
|
||||
page.goto(
|
||||
f"http://127.0.0.1:{server.server_port}"
|
||||
"/results/BRI/brussels/2026-06-16",
|
||||
"/results/BRI/brussels/out/2026-06-16",
|
||||
wait_until="domcontentloaded",
|
||||
)
|
||||
page.get_by_role("link", name="Next →").click()
|
||||
|
|
@ -372,7 +372,7 @@ def test_single_advance_standard_premier_totals_on_initial_url(
|
|||
browser = _launch_browser(p)
|
||||
page = browser.new_page()
|
||||
page.goto(
|
||||
f"{single_server}/results/BRI/paris/2026-07-20"
|
||||
f"{single_server}/results/BRI/paris/out/2026-07-20"
|
||||
"?nr_class=advance_std&es_class=plus",
|
||||
wait_until="domcontentloaded",
|
||||
)
|
||||
|
|
@ -452,7 +452,7 @@ def test_single_advance_first_falls_back_to_walkon_when_unavailable(
|
|||
page = browser.new_page()
|
||||
page.goto(
|
||||
f"http://127.0.0.1:{server.server_port}"
|
||||
"/results/BRI/paris/2026-07-20?nr_class=advance_1st&es_class=standard",
|
||||
"/results/BRI/paris/out/2026-07-20?nr_class=advance_1st&es_class=standard",
|
||||
wait_until="domcontentloaded",
|
||||
)
|
||||
|
||||
|
|
@ -496,7 +496,7 @@ def test_return_advance_first_standard_premier_totals(local_server: str) -> None
|
|||
timeout=10000,
|
||||
)
|
||||
|
||||
assert "/results/BRI/paris/2026-07-20/return/2026-07-27" in page.url
|
||||
assert "/results/BRI/paris/return/2026-07-20/2026-07-27" in page.url
|
||||
assert "journey_type=return" not in page.url
|
||||
assert "return_date=2026-07-27" not in page.url
|
||||
assert "nr_class=advance_1st" in page.url
|
||||
|
|
@ -528,7 +528,7 @@ def test_return_calendar_selects_outbound_before_return(local_server: str) -> No
|
|||
assert "Return: Wed 17 Jun" in page.locator("#cal-hint").inner_text()
|
||||
|
||||
page.locator('button[type="submit"]').click()
|
||||
page.wait_for_url("**/results/BRI/paris/2026-06-10/return/2026-06-17", timeout=10000)
|
||||
page.wait_for_url("**/results/BRI/paris/return/2026-06-10/2026-06-17", timeout=10000)
|
||||
browser.close()
|
||||
|
||||
|
||||
|
|
@ -539,7 +539,7 @@ def test_return_advance_first_standard_premier_totals_on_initial_url(
|
|||
browser = _launch_browser(p)
|
||||
page = browser.new_page()
|
||||
page.goto(
|
||||
f"{local_server}/results/BRI/paris/2026-07-20/return/2026-07-27"
|
||||
f"{local_server}/results/BRI/paris/return/2026-07-20/2026-07-27"
|
||||
"?nr_class=advance_1st&es_class=plus",
|
||||
wait_until="domcontentloaded",
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue