agenda/web_view.py

168 lines
4.6 KiB
Python
Executable file

#!/usr/bin/python3
"""Web page to show upcoming events."""
import inspect
import operator
import os.path
import sys
import traceback
import typing
from datetime import date, datetime
import flask
import pycountry
import werkzeug
import werkzeug.debug.tbtools
import yaml
import agenda.data
import agenda.error_mail
import agenda.thespacedevs
import agenda.travel
app = flask.Flask(__name__)
app.debug = False
app.config.from_object("config.default")
agenda.error_mail.setup_error_mail(app)
@app.errorhandler(werkzeug.exceptions.InternalServerError)
def exception_handler(e: werkzeug.exceptions.InternalServerError) -> tuple[str, int]:
"""Handle exception."""
exec_type, exc_value, current_traceback = sys.exc_info()
assert exc_value
tb = werkzeug.debug.tbtools.DebugTraceback(exc_value)
summary = tb.render_traceback_html(include_title=False)
exc_lines = "".join(tb._te.format_exception_only())
last_frame = list(traceback.walk_tb(current_traceback))[-1][0]
last_frame_args = inspect.getargs(last_frame.f_code)
return (
flask.render_template(
"show_error.html",
plaintext=tb.render_traceback_text(),
exception=exc_lines,
exception_type=tb._te.exc_type.__name__,
summary=summary,
last_frame=last_frame,
last_frame_args=last_frame_args,
),
500,
)
@app.route("/")
async def index() -> str:
"""Index page."""
now = datetime.now()
data = await agenda.data.get_data(now, app.config)
return flask.render_template("index.html", today=now.date(), **data)
@app.route("/launches")
async def launch_list() -> str:
"""Web page showing List of space launches."""
now = datetime.now()
data_dir = app.config["DATA_DIR"]
rocket_dir = os.path.join(data_dir, "thespacedevs")
rockets = await agenda.thespacedevs.get_launches(rocket_dir, limit=100)
return flask.render_template("launches.html", rockets=rockets, now=now)
@app.route("/gaps")
async def gaps_page() -> str:
"""List of available gaps."""
now = datetime.now()
data = await agenda.data.get_data(now, app.config)
return flask.render_template("gaps.html", today=now.date(), gaps=data["gaps"])
@app.route("/travel")
def travel_list() -> str:
"""Page showing a list of upcoming travel."""
data_dir = app.config["PERSONAL_DATA"]
flights = agenda.travel.parse_yaml("flights", data_dir)
trains = agenda.travel.parse_yaml("trains", data_dir)
return flask.render_template("travel.html", flights=flights, trains=trains)
def as_date(d: date | datetime) -> date:
"""Date of event."""
return d.date() if isinstance(d, datetime) else d
def get_country(alpha_2: str) -> str | None:
"""Lookup country by alpha-2 country code."""
if not alpha_2:
return None
return typing.cast(str, pycountry.countries.get(alpha_2=alpha_2.upper()))
@app.route("/conference")
def conference_list() -> str:
"""Page showing a list of conferences."""
data_dir = app.config["PERSONAL_DATA"]
filepath = os.path.join(data_dir, "conferences.yaml")
item_list = yaml.safe_load(open(filepath))
today = date.today()
for conf in item_list:
conf["start_date"] = as_date(conf["start"])
conf["end_date"] = as_date(conf["end"])
item_list.sort(key=operator.itemgetter("start_date"))
current = [
conf
for conf in item_list
if conf["start_date"] <= today and conf["end_date"] >= today
]
past = [conf for conf in item_list if conf["end_date"] < today]
future = [conf for conf in item_list if conf["start_date"] > today]
return flask.render_template(
"conference_list.html",
current=current,
past=past,
future=future,
today=today,
get_country=get_country,
)
@app.route("/accommodation")
def accommodation_list() -> str:
"""Page showing a list of past, present and future accommodation."""
data_dir = app.config["PERSONAL_DATA"]
items = agenda.travel.parse_yaml("accommodation", data_dir)
stays_in_2024 = [item for item in items if item["from"].year == 2024]
total_nights_2024 = sum(
(stay["to"].date() - stay["from"].date()).days for stay in stays_in_2024
)
nights_abroad_2024 = sum(
(stay["to"].date() - stay["from"].date()).days
for stay in stays_in_2024
if stay["country"] != "gb"
)
return flask.render_template(
"accommodation.html",
items=items,
total_nights_2024=total_nights_2024,
nights_abroad_2024=nights_abroad_2024,
get_country=get_country,
)
if __name__ == "__main__":
app.run(host="0.0.0.0")