Improve display of cabins list
This commit is contained in:
parent
70db886a81
commit
944fe24662
23
ferry/__init__.py
Normal file
23
ferry/__init__.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Vehicle:
|
||||||
|
"""What type of vehicle is going on the ferry."""
|
||||||
|
|
||||||
|
type: str
|
||||||
|
registration: str
|
||||||
|
height: int
|
||||||
|
length: int
|
||||||
|
|
||||||
|
|
||||||
|
ports = {
|
||||||
|
"PORTSMOUTH": "GBPME",
|
||||||
|
"PLYMOUTH": "GBPLY",
|
||||||
|
"POOLE": "GBPOO",
|
||||||
|
"CAEN": "FROUI",
|
||||||
|
"CHERBOURG": "FRCER",
|
||||||
|
"ST MALO": "FRSML",
|
||||||
|
}
|
||||||
|
|
||||||
|
port_lookup = {code: name for name, code in ports.items()}
|
86
ferry/api.py
Normal file
86
ferry/api.py
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
"""Interface with the Brittany Ferries API."""
|
||||||
|
|
||||||
|
from typing import Any, TypedDict
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from . import Vehicle
|
||||||
|
|
||||||
|
api_root_url = "https://www.brittany-ferries.co.uk/api/ferry/v1/"
|
||||||
|
|
||||||
|
|
||||||
|
class VehicleDict(TypedDict):
|
||||||
|
"""Description of vechicle in the format expected by the API."""
|
||||||
|
|
||||||
|
type: str
|
||||||
|
registrations: list[str]
|
||||||
|
height: int
|
||||||
|
length: int
|
||||||
|
extras: dict[str, None]
|
||||||
|
|
||||||
|
|
||||||
|
def vehicle_dict(v: Vehicle) -> VehicleDict:
|
||||||
|
"""Return vehicle detail in the format for the Brittany Ferries API."""
|
||||||
|
return {
|
||||||
|
"type": v.type,
|
||||||
|
"registrations": [v.registration],
|
||||||
|
"height": v.height,
|
||||||
|
"length": v.length,
|
||||||
|
"extras": {"rearMountedBikeCarrier": None},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_prices(
|
||||||
|
departure_port: str,
|
||||||
|
arrival_port: str,
|
||||||
|
from_date: str,
|
||||||
|
to_date: str,
|
||||||
|
vehicle: Vehicle,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Call Brittany Ferries API to get details of crossings."""
|
||||||
|
url = api_root_url + "crossing/prices"
|
||||||
|
|
||||||
|
post_data = {
|
||||||
|
"bookingReference": None,
|
||||||
|
"pets": {"smallDogs": 1, "largeDogs": 0, "cats": 0},
|
||||||
|
"passengers": {"adults": 2, "children": 0, "infants": 0},
|
||||||
|
"vehicle": vehicle_dict(vehicle),
|
||||||
|
"departurePort": departure_port,
|
||||||
|
"arrivalPort": arrival_port,
|
||||||
|
"disability": None,
|
||||||
|
"sponsor": None,
|
||||||
|
"fromDate": f"{from_date}T00:00:00",
|
||||||
|
"toDate": f"{to_date}T23:59:59",
|
||||||
|
}
|
||||||
|
|
||||||
|
r = requests.post(url, json=post_data)
|
||||||
|
data: dict[str, Any] = r.json()
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def get_accommodations(
|
||||||
|
departure_port: str,
|
||||||
|
arrival_port: str,
|
||||||
|
departure_date: str,
|
||||||
|
ticket_tier: str,
|
||||||
|
vehicle: Vehicle,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""Grab cabin details."""
|
||||||
|
url = api_root_url + "crossing/accommodations"
|
||||||
|
post_data = {
|
||||||
|
"bookingReference": None,
|
||||||
|
"departurePort": departure_port,
|
||||||
|
"arrivalPort": arrival_port,
|
||||||
|
"departureDate": departure_date,
|
||||||
|
"passengers": {"adults": 2, "children": 0, "infants": 0},
|
||||||
|
"disability": None,
|
||||||
|
"vehicle": vehicle_dict(vehicle),
|
||||||
|
"petCabinsNeeded": True,
|
||||||
|
"ticketTier": ticket_tier,
|
||||||
|
"pets": {"smallDogs": 1, "largeDogs": 0, "cats": 0},
|
||||||
|
"sponsor": None,
|
||||||
|
"offerType": "NONE",
|
||||||
|
}
|
||||||
|
|
||||||
|
json_data: dict[str, Any] = requests.post(url, json=post_data).json()
|
||||||
|
return json_data
|
17
ferry/read_config.py
Normal file
17
ferry/read_config.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import configparser
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
from . import Vehicle
|
||||||
|
|
||||||
|
ferry_config = configparser.ConfigParser()
|
||||||
|
ferry_config.read(os.path.expanduser("~edward/config/brittany-ferries/config"))
|
||||||
|
|
||||||
|
|
||||||
|
def vehicle_from_config(config: configparser.ConfigParser) -> Vehicle:
|
||||||
|
"""Generate a vehicle object from config."""
|
||||||
|
return Vehicle(
|
||||||
|
type=config.get("vehicle", "type"),
|
||||||
|
registration=config.get("vehicle", "registration"),
|
||||||
|
height=config.getint("vehicle", "height"),
|
||||||
|
length=config.getint("vehicle", "length"),
|
||||||
|
)
|
41
main.py
41
main.py
|
@ -9,14 +9,14 @@ import re
|
||||||
from datetime import date, datetime, timedelta
|
from datetime import date, datetime, timedelta
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
import dateutil.parser
|
||||||
import flask
|
import flask
|
||||||
import pytz
|
import pytz
|
||||||
import routes
|
|
||||||
import werkzeug.exceptions
|
import werkzeug.exceptions
|
||||||
from werkzeug.debug.tbtools import get_current_traceback
|
from werkzeug.debug.tbtools import get_current_traceback
|
||||||
from werkzeug.wrappers import Response
|
from werkzeug.wrappers import Response
|
||||||
|
|
||||||
from ferry import ports
|
import ferry
|
||||||
from ferry.api import get_accommodations, get_prices
|
from ferry.api import get_accommodations, get_prices
|
||||||
from ferry.read_config import ferry_config, vehicle_from_config
|
from ferry.read_config import ferry_config, vehicle_from_config
|
||||||
|
|
||||||
|
@ -86,22 +86,19 @@ def show_route(
|
||||||
"""Page showing list of prices."""
|
"""Page showing list of prices."""
|
||||||
prices = get_prices(departure_port, arrival_port)
|
prices = get_prices(departure_port, arrival_port)
|
||||||
|
|
||||||
port_lookup = {code: name for name, code in ports.items()}
|
|
||||||
|
|
||||||
return flask.render_template(
|
return flask.render_template(
|
||||||
"route.html",
|
"route.html",
|
||||||
departure_port=port_lookup[departure_port],
|
departure_port=ferry.port_lookup[departure_port],
|
||||||
arrival_port=port_lookup[arrival_port],
|
arrival_port=ferry.port_lookup[arrival_port],
|
||||||
days=prices["crossings"],
|
days=prices["crossings"],
|
||||||
parse_date=parse_date,
|
parse_date=parse_date,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
def start() -> Response:
|
def start() -> Response | str:
|
||||||
"""Start page."""
|
"""Start page."""
|
||||||
return flask.render_template("index.html")
|
return flask.render_template("index.html")
|
||||||
return flask.redirect(flask.url_for("outbound_page"))
|
|
||||||
|
|
||||||
|
|
||||||
def cabins_url(dep, arr, crossing, ticket_tier):
|
def cabins_url(dep, arr, crossing, ticket_tier):
|
||||||
|
@ -110,8 +107,8 @@ def cabins_url(dep, arr, crossing, ticket_tier):
|
||||||
|
|
||||||
return flask.url_for(
|
return flask.url_for(
|
||||||
"cabins",
|
"cabins",
|
||||||
departure_port=ports[dep],
|
departure_port=ferry.ports[dep],
|
||||||
arrival_port=ports[arr],
|
arrival_port=ferry.ports[arr],
|
||||||
departure_date=utc_dt.strftime("%Y-%m-%dT%H:%M:%S.000Z"),
|
departure_date=utc_dt.strftime("%Y-%m-%dT%H:%M:%S.000Z"),
|
||||||
ticket_tier=ticket_tier,
|
ticket_tier=ticket_tier,
|
||||||
)
|
)
|
||||||
|
@ -150,7 +147,13 @@ def get_prices_with_cache(
|
||||||
filename = cache_filename(params)
|
filename = cache_filename(params)
|
||||||
|
|
||||||
all_data = [
|
all_data = [
|
||||||
(dep, arr, get_prices(ports[dep], ports[arr], start, end, vehicle)["crossings"])
|
(
|
||||||
|
dep,
|
||||||
|
arr,
|
||||||
|
get_prices(ferry.ports[dep], ferry.ports[arr], start, end, vehicle)[
|
||||||
|
"crossings"
|
||||||
|
],
|
||||||
|
)
|
||||||
for dep, arr in selection
|
for dep, arr in selection
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -180,7 +183,7 @@ def build_outbound(section: str) -> str:
|
||||||
"all_routes.html",
|
"all_routes.html",
|
||||||
data=all_data,
|
data=all_data,
|
||||||
days_until_start=get_days_until_start(),
|
days_until_start=get_days_until_start(),
|
||||||
ports=ports,
|
ports=ferry.ports,
|
||||||
parse_date=parse_date,
|
parse_date=parse_date,
|
||||||
from_date=start,
|
from_date=start,
|
||||||
to_date=end,
|
to_date=end,
|
||||||
|
@ -232,7 +235,7 @@ def return_page() -> str:
|
||||||
return flask.render_template(
|
return flask.render_template(
|
||||||
"all_routes.html",
|
"all_routes.html",
|
||||||
data=all_data,
|
data=all_data,
|
||||||
ports=ports,
|
ports=ferry.ports,
|
||||||
days_until_start=get_days_until_start(),
|
days_until_start=get_days_until_start(),
|
||||||
parse_date=parse_date,
|
parse_date=parse_date,
|
||||||
from_date=start,
|
from_date=start,
|
||||||
|
@ -286,22 +289,20 @@ def cabins(
|
||||||
if a["quantityAvailable"] > 0 and a["code"] != "RS"
|
if a["quantityAvailable"] > 0 and a["code"] != "RS"
|
||||||
# and "Inside" not in a["description"]
|
# and "Inside" not in a["description"]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
dep = dateutil.parser.isoparse(departure_date)
|
||||||
|
|
||||||
return flask.render_template(
|
return flask.render_template(
|
||||||
"cabins.html",
|
"cabins.html",
|
||||||
|
port_lookup=ferry.port_lookup,
|
||||||
departure_port=departure_port,
|
departure_port=departure_port,
|
||||||
arrival_port=arrival_port,
|
arrival_port=arrival_port,
|
||||||
departure_date=departure_date,
|
departure_date=dep,
|
||||||
ticket_tier=ticket_tier,
|
ticket_tier=ticket_tier,
|
||||||
accommodations=accommodations,
|
accommodations=accommodations,
|
||||||
pet_accommodations=cabin_data["petAccommodations"],
|
pet_accommodations=cabin_data["petAccommodations"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/routes")
|
|
||||||
def route_list() -> str:
|
|
||||||
"""List of routes."""
|
|
||||||
return flask.render_template("index.html", routes=routes, ports=ports)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(host="0.0.0.0", port=5001)
|
app.run(host="0.0.0.0", port=5001)
|
||||||
|
|
|
@ -29,9 +29,10 @@ a:link {
|
||||||
<body>
|
<body>
|
||||||
<div class="m-3">
|
<div class="m-3">
|
||||||
|
|
||||||
<h1>{{ departure_port }} to {{ arrival_port }}</h1>
|
<h1>{{ port_lookup[departure_port].title() }}
|
||||||
|
to {{ port_lookup[arrival_port].title() }}</h1>
|
||||||
|
|
||||||
<p>{{ departure_date }} {{ ticket_tier }}</p>
|
<p>{{ departure_date.strftime("%A, %d %B %Y %H:%M UTC") }} {{ ticket_tier }}</p>
|
||||||
|
|
||||||
<table class="table w-auto">
|
<table class="table w-auto">
|
||||||
<tr>
|
<tr>
|
||||||
|
|
Loading…
Reference in a new issue