Compare commits
No commits in common. "4e328d401e89089e0c5c8e2e383c359b7b520181" and "b8ed1d5d65928d88710ba3fc56bbc66ab5cd8fc9" have entirely different histories.
4e328d401e
...
b8ed1d5d65
|
@ -90,14 +90,10 @@ def get_rates(config: flask.config.Config) -> dict[str, Decimal]:
|
|||
except httpx.ConnectError:
|
||||
return read_cached_rates(full_path, currencies)
|
||||
|
||||
try:
|
||||
data = json.loads(response.text, parse_float=Decimal)
|
||||
except json.decoder.JSONDecodeError:
|
||||
return read_cached_rates(full_path, currencies)
|
||||
|
||||
with open(os.path.join(fx_dir, filename), "w") as file:
|
||||
file.write(response.text)
|
||||
|
||||
data = json.loads(response.text, parse_float=Decimal)
|
||||
return {
|
||||
cur: Decimal(data["quotes"][f"GBP{cur}"])
|
||||
for cur in currencies
|
||||
|
|
|
@ -136,7 +136,7 @@ def summarize_launch(launch: Launch) -> Summary:
|
|||
"launch_provider": launch_provider,
|
||||
"launch_provider_abbrev": launch_provider_abbrev,
|
||||
"launch_provider_type": get_nested(launch, ["launch_service_provider", "type"]),
|
||||
"rocket": launch["rocket"]["configuration"],
|
||||
"rocket": launch["rocket"]["configuration"]["full_name"],
|
||||
"mission": launch.get("mission"),
|
||||
"mission_name": get_nested(launch, ["mission", "name"]),
|
||||
"pad_name": launch["pad"]["name"],
|
||||
|
@ -174,10 +174,7 @@ def get_launches(
|
|||
existing.sort(reverse=True)
|
||||
|
||||
if refresh or not existing or (now - existing[0][0]).seconds > ttl:
|
||||
try:
|
||||
return next_launch_api(rocket_dir, limit=limit)
|
||||
except Exception:
|
||||
pass # fallback to cached version
|
||||
return next_launch_api(rocket_dir, limit=limit)
|
||||
|
||||
f = existing[0][1]
|
||||
|
||||
|
|
|
@ -12,12 +12,28 @@ from pycountry.db import Country
|
|||
import agenda
|
||||
from agenda import format_list_with_ampersand
|
||||
|
||||
from . import utils
|
||||
|
||||
StrDict = dict[str, typing.Any]
|
||||
DateOrDateTime = datetime.datetime | datetime.date
|
||||
|
||||
|
||||
def as_date(d: DateOrDateTime) -> datetime.date:
|
||||
"""Convert datetime to date."""
|
||||
if isinstance(d, datetime.datetime):
|
||||
return d.date()
|
||||
assert isinstance(d, datetime.date)
|
||||
return d
|
||||
|
||||
|
||||
def as_datetime(d: DateOrDateTime) -> datetime.datetime:
|
||||
"""Date/time of event."""
|
||||
t0 = datetime.datetime.min.time()
|
||||
return (
|
||||
d
|
||||
if isinstance(d, datetime.datetime)
|
||||
else datetime.datetime.combine(d, t0).replace(tzinfo=datetime.timezone.utc)
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class TripElement:
|
||||
"""Trip element."""
|
||||
|
@ -90,20 +106,18 @@ class Trip:
|
|||
def end(self) -> datetime.date | None:
|
||||
"""End date for trip."""
|
||||
max_conference_end = (
|
||||
max(utils.as_date(item["end"]) for item in self.conferences)
|
||||
max(as_date(item["end"]) for item in self.conferences)
|
||||
if self.conferences
|
||||
else datetime.date.min
|
||||
)
|
||||
assert isinstance(max_conference_end, datetime.date)
|
||||
|
||||
arrive = [
|
||||
utils.as_date(item["arrive"]) for item in self.travel if "arrive" in item
|
||||
]
|
||||
arrive = [as_date(item["arrive"]) for item in self.travel if "arrive" in item]
|
||||
travel_end = max(arrive) if arrive else datetime.date.min
|
||||
assert isinstance(travel_end, datetime.date)
|
||||
|
||||
accommodation_end = (
|
||||
max(utils.as_date(item["to"]) for item in self.accommodation)
|
||||
max(as_date(item["to"]) for item in self.accommodation)
|
||||
if self.accommodation
|
||||
else datetime.date.min
|
||||
)
|
||||
|
@ -300,7 +314,7 @@ class Trip:
|
|||
)
|
||||
)
|
||||
|
||||
return sorted(elements, key=lambda e: utils.as_datetime(e.start_time))
|
||||
return sorted(elements, key=lambda e: as_datetime(e.start_time))
|
||||
|
||||
def elements_grouped_by_day(self) -> list[tuple[datetime.date, list[TripElement]]]:
|
||||
"""Group trip elements by day."""
|
||||
|
@ -311,7 +325,7 @@ class Trip:
|
|||
|
||||
for element in self.elements():
|
||||
# Extract the date part of the 'when' attribute
|
||||
day = utils.as_date(element.start_time)
|
||||
day = as_date(element.start_time)
|
||||
grouped_elements[day].append(element)
|
||||
|
||||
# Sort elements within each day
|
||||
|
@ -320,7 +334,7 @@ class Trip:
|
|||
key=lambda e: (
|
||||
e.element_type == "check-in", # check-out elements last
|
||||
e.element_type != "check-out", # check-in elements first
|
||||
utils.as_datetime(e.start_time), # then sort by time
|
||||
as_datetime(e.start_time), # then sort by time
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -389,7 +403,13 @@ class Event:
|
|||
@property
|
||||
def as_datetime(self) -> datetime.datetime:
|
||||
"""Date/time of event."""
|
||||
return utils.as_datetime(self.date)
|
||||
d = self.date
|
||||
t0 = datetime.datetime.min.time()
|
||||
return (
|
||||
d
|
||||
if isinstance(d, datetime.datetime)
|
||||
else datetime.datetime.combine(d, t0).replace(tzinfo=datetime.timezone.utc)
|
||||
)
|
||||
|
||||
@property
|
||||
def has_time(self) -> bool:
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
"""Utility functions."""
|
||||
|
||||
import datetime
|
||||
|
||||
DateOrDateTime = datetime.datetime | datetime.date
|
||||
|
||||
|
||||
def as_date(d: DateOrDateTime) -> datetime.date:
|
||||
"""Convert datetime to date."""
|
||||
if isinstance(d, datetime.datetime):
|
||||
return d.date()
|
||||
assert isinstance(d, datetime.date)
|
||||
return d
|
||||
|
||||
|
||||
def as_datetime(d: DateOrDateTime) -> datetime.datetime:
|
||||
"""Date/time of event."""
|
||||
t0 = datetime.datetime.min.time()
|
||||
return (
|
||||
d
|
||||
if isinstance(d, datetime.datetime)
|
||||
else datetime.datetime.combine(d, t0).replace(tzinfo=datetime.timezone.utc)
|
||||
)
|
|
@ -6,40 +6,7 @@
|
|||
<div class="container-fluid mt-2">
|
||||
<h1>Space launches</h1>
|
||||
|
||||
<h4>Filters</h4>
|
||||
|
||||
<p>Mission type:
|
||||
|
||||
{% if request.args.type %}<a href="{{ request.path }}">🗙</a>{% endif %}
|
||||
|
||||
{% for t in mission_types | sort %}
|
||||
{% if t == request.args.type %}
|
||||
<strong>{{ t }}</strong>
|
||||
{% else %}
|
||||
<a href="?type={{ t }}" class="text-nowrap">
|
||||
{{ t }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if not loop.last %} | {% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
|
||||
<p>Vehicle:
|
||||
{% if request.args.rocket %}<a href="{{ request.path }}">🗙</a>{% endif %}
|
||||
|
||||
{% for r in rockets | sort %}
|
||||
{% if r == request.args.rockets %}
|
||||
<strong>{{ r }}</strong>
|
||||
{% else %}
|
||||
<a href="?rocket={{ r }}" class="text-nowrap">
|
||||
{{ r }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if not loop.last %} | {% endif %}
|
||||
{% endfor %}
|
||||
</p>
|
||||
|
||||
{% for launch in launches %}
|
||||
{% for launch in rockets %}
|
||||
{% set highlight =" bg-primary-subtle" if launch.slug in config.FOLLOW_LAUNCHES else "" %}
|
||||
{% set country = get_country(launch.country_code) %}
|
||||
<div class="row{{highlight}}">
|
||||
|
@ -57,7 +24,7 @@
|
|||
<div class="col">
|
||||
<div>
|
||||
{{ country.flag }}
|
||||
{{ launch.rocket.full_name }}
|
||||
{{ launch.rocket }}
|
||||
–
|
||||
<strong>{{launch.mission.name }}</strong>
|
||||
–
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<td class="text-end">
|
||||
{{ weekend.date.isocalendar().week }}
|
||||
</td>
|
||||
<td class="text-end text-nowrap">
|
||||
<td class="text-end">
|
||||
{{ weekend.date.strftime("%-d %b %Y") }}
|
||||
</td>
|
||||
{% for day in "saturday", "sunday" %}
|
||||
|
|
30
web_view.py
30
web_view.py
|
@ -35,7 +35,7 @@ agenda.error_mail.setup_error_mail(app)
|
|||
|
||||
@app.before_request
|
||||
def handle_auth() -> None:
|
||||
"""Handle authentication and set global user."""
|
||||
"""Handle autentication and set global user."""
|
||||
flask.g.user = UniAuth.auth.get_current_user()
|
||||
|
||||
|
||||
|
@ -145,34 +145,10 @@ def launch_list() -> str:
|
|||
now = datetime.now()
|
||||
data_dir = app.config["DATA_DIR"]
|
||||
rocket_dir = os.path.join(data_dir, "thespacedevs")
|
||||
launches = agenda.thespacedevs.get_launches(rocket_dir, limit=100)
|
||||
|
||||
mission_type_filter = flask.request.args.get("type")
|
||||
rocket_filter = flask.request.args.get("rocket")
|
||||
|
||||
mission_types = {
|
||||
launch["mission"]["type"] for launch in launches if launch["mission"]
|
||||
}
|
||||
|
||||
rockets = {launch["rocket"]["full_name"] for launch in launches}
|
||||
|
||||
launches = [
|
||||
launch
|
||||
for launch in launches
|
||||
if (
|
||||
not mission_type_filter
|
||||
or (launch["mission"] and launch["mission"]["type"] == mission_type_filter)
|
||||
)
|
||||
and (not rocket_filter or launch["rocket"]["full_name"] == rocket_filter)
|
||||
]
|
||||
rockets = agenda.thespacedevs.get_launches(rocket_dir, limit=100)
|
||||
|
||||
return flask.render_template(
|
||||
"launches.html",
|
||||
launches=launches,
|
||||
rockets=rockets,
|
||||
now=now,
|
||||
get_country=agenda.get_country,
|
||||
mission_types=mission_types,
|
||||
"launches.html", rockets=rockets, now=now, get_country=agenda.get_country
|
||||
)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue