diff --git a/agenda/__init__.py b/agenda/__init__.py index baf8813..63b6e7d 100644 --- a/agenda/__init__.py +++ b/agenda/__init__.py @@ -2,6 +2,7 @@ from datetime import date, datetime, time +import pycountry import pytz uk_tz = pytz.timezone("Europe/London") @@ -10,3 +11,23 @@ uk_tz = pytz.timezone("Europe/London") def uk_time(d: date, t: time) -> datetime: """Combine time and date for UK timezone.""" return uk_tz.localize(datetime.combine(d, t)) + + +def format_list_with_ampersand(items: list[str]) -> str: + """Join a list of strings with commas and an ampersand.""" + if len(items) > 1: + return ", ".join(items[:-1]) + " & " + items[-1] + elif items: + return items[0] + return "" + + +def get_country(alpha_2: str) -> pycountry.db.Country | None: + """Lookup country by alpha-2 country code.""" + if not alpha_2: + return None + if alpha_2 == "xk": + return pycountry.db.Country(flag="\U0001F1FD\U0001F1F0", name="Kosovo") + + country: pycountry.db.Country = pycountry.countries.get(alpha_2=alpha_2.upper()) + return country diff --git a/agenda/conference.py b/agenda/conference.py index 13d6a42..513a225 100644 --- a/agenda/conference.py +++ b/agenda/conference.py @@ -18,6 +18,7 @@ class Conference: location: str start: date | datetime end: date | datetime + trip: date | None = None country: str | None = None venue: str | None = None address: str | None = None diff --git a/agenda/data.py b/agenda/data.py index a508c39..04de858 100644 --- a/agenda/data.py +++ b/agenda/data.py @@ -36,9 +36,7 @@ from . import ( uk_tz, waste_schedule, ) -from .types import Event, Holiday - -StrDict = dict[str, typing.Any] +from .types import Event, Holiday, StrDict here = dateutil.tz.tzlocal() diff --git a/agenda/types.py b/agenda/types.py index ce58d3a..e3d5801 100644 --- a/agenda/types.py +++ b/agenda/types.py @@ -2,6 +2,53 @@ import dataclasses import datetime +import typing + +from pycountry.db import Country + +import agenda +from agenda import format_list_with_ampersand + +StrDict = dict[str, typing.Any] + + +@dataclasses.dataclass +class Trip: + """Trip.""" + + date: datetime.date + travel: list[StrDict] = dataclasses.field(default_factory=list) + accommodation: list[StrDict] = dataclasses.field(default_factory=list) + conferences: list[StrDict] = dataclasses.field(default_factory=list) + + @property + def title(self) -> str: + """Trip title.""" + names = ( + format_list_with_ampersand([conf["name"] for conf in self.conferences]) + or "[no conferences in trip]" + ) + return f'{names} ({self.date.strftime("%b %Y")})' + + @property + def countries(self) -> set[Country]: + """Trip countries.""" + found: set[Country] = set() + for item in self.conferences + self.accommodation: + if "country" not in item: + continue + country = agenda.get_country(item["country"]) + assert country + found.add(country) + + return found + + @property + def countries_str(self) -> str: + """List of countries visited on this trip.""" + return format_list_with_ampersand( + [f"{c.flag} {c.name}" for c in self.countries] + ) @dataclasses.dataclass diff --git a/templates/accommodation.html b/templates/accommodation.html index 29e5bfa..5d85bc4 100644 --- a/templates/accommodation.html +++ b/templates/accommodation.html @@ -1,4 +1,5 @@ {% extends "base.html" %} +{% from "macros.html" import accommodation_row with context %} {% block style %} {% set column_count = 7 %} {% endblock %} -{% macro row(item, badge) %} -{% set country = get_country(item.country) %} -{% set nights = (item.to.date() - item.from.date()).days %} -