2024-03-05 09:26:54 +00:00
|
|
|
#!/usr/bin/python3
|
|
|
|
"""Combined update script for various data sources."""
|
|
|
|
|
|
|
|
import asyncio
|
2024-06-15 21:35:18 +01:00
|
|
|
import json
|
2024-03-05 09:26:54 +00:00
|
|
|
import os
|
|
|
|
import smtplib
|
|
|
|
import sys
|
2024-06-15 21:35:18 +01:00
|
|
|
import typing
|
2024-03-05 09:26:54 +00:00
|
|
|
from datetime import date, datetime
|
|
|
|
from email.message import EmailMessage
|
|
|
|
from email.utils import formatdate, make_msgid
|
|
|
|
from time import time
|
|
|
|
|
2024-04-20 07:52:00 +01:00
|
|
|
import flask
|
2024-03-05 09:26:54 +00:00
|
|
|
import requests
|
|
|
|
|
2024-04-18 22:26:04 +01:00
|
|
|
import agenda.fx
|
2024-03-05 09:26:54 +00:00
|
|
|
import agenda.thespacedevs
|
|
|
|
import agenda.types
|
|
|
|
import agenda.uk_holiday
|
|
|
|
import agenda.waste_schedule
|
|
|
|
from agenda import gwr
|
2024-06-15 21:35:18 +01:00
|
|
|
from agenda.types import StrDict
|
2024-04-20 07:52:00 +01:00
|
|
|
from web_view import app
|
2024-03-05 09:26:54 +00:00
|
|
|
|
|
|
|
|
2024-04-20 07:52:00 +01:00
|
|
|
async def update_bank_holidays(config: flask.config.Config) -> None:
|
2024-03-05 09:26:54 +00:00
|
|
|
"""Update cached copy of UK Bank holidays."""
|
|
|
|
t0 = time()
|
2024-04-20 07:52:00 +01:00
|
|
|
events = await agenda.uk_holiday.get_holiday_list(config["DATA_DIR"])
|
2024-03-05 09:26:54 +00:00
|
|
|
time_taken = time() - t0
|
|
|
|
if not sys.stdin.isatty():
|
|
|
|
return
|
|
|
|
print(len(events), "bank holidays in list")
|
|
|
|
print(f"took {time_taken:.1f} seconds")
|
|
|
|
|
|
|
|
|
2024-04-20 07:52:00 +01:00
|
|
|
async def update_bristol_bins(config: flask.config.Config) -> None:
|
2024-03-05 09:26:54 +00:00
|
|
|
"""Update waste schedule from Bristol City Council."""
|
|
|
|
t0 = time()
|
|
|
|
events = await agenda.waste_schedule.get_bristol_gov_uk(
|
2024-04-20 07:52:00 +01:00
|
|
|
date.today(), config["DATA_DIR"], config["BRISTOL_UPRN"], refresh=True
|
2024-03-05 09:26:54 +00:00
|
|
|
)
|
|
|
|
time_taken = time() - t0
|
|
|
|
if not sys.stdin.isatty():
|
|
|
|
return
|
|
|
|
for event in events:
|
|
|
|
print(event)
|
|
|
|
print(f"took {time_taken:.1f} seconds")
|
|
|
|
|
|
|
|
|
2024-04-20 07:52:00 +01:00
|
|
|
def send_mail(config: flask.config.Config, subject: str, body: str) -> None:
|
2024-03-05 09:26:54 +00:00
|
|
|
"""Send an e-mail."""
|
|
|
|
msg = EmailMessage()
|
|
|
|
|
|
|
|
msg["Subject"] = subject
|
2024-04-20 07:52:00 +01:00
|
|
|
msg["To"] = f"{config['NAME']} <{config['MAIL_TO']}>"
|
|
|
|
msg["From"] = f"{config['NAME']} <{config['MAIL_FROM']}>"
|
2024-03-05 09:26:54 +00:00
|
|
|
msg["Date"] = formatdate()
|
|
|
|
msg["Message-ID"] = make_msgid()
|
|
|
|
|
|
|
|
# Add extra mail headers
|
2024-04-20 07:52:00 +01:00
|
|
|
for header, value in config["MAIL_HEADERS"]:
|
2024-03-05 09:26:54 +00:00
|
|
|
msg[header] = value
|
|
|
|
|
|
|
|
msg.set_content(body)
|
|
|
|
|
2024-04-20 07:52:00 +01:00
|
|
|
s = smtplib.SMTP(config["SMTP_HOST"])
|
|
|
|
s.sendmail(config["MAIL_TO"], [config["MAIL_TO"]], msg.as_string())
|
2024-03-05 09:26:54 +00:00
|
|
|
s.quit()
|
|
|
|
|
|
|
|
|
2024-04-20 07:52:00 +01:00
|
|
|
def update_gwr_advance_ticket_date(config: flask.config.Config) -> None:
|
2024-03-05 09:26:54 +00:00
|
|
|
"""Update GWR advance ticket date cache."""
|
2024-04-20 07:52:00 +01:00
|
|
|
filename = os.path.join(config["DATA_DIR"], "advance-tickets.html")
|
2024-03-05 09:26:54 +00:00
|
|
|
existing_html = open(filename).read()
|
|
|
|
existing_date = gwr.extract_weekday_date(existing_html)
|
|
|
|
|
|
|
|
new_html = requests.get(gwr.url).text
|
|
|
|
open(filename, "w").write(new_html)
|
|
|
|
|
|
|
|
new_date = gwr.extract_weekday_date(new_html)
|
|
|
|
|
|
|
|
if existing_date == new_date:
|
|
|
|
if sys.stdin.isatty():
|
|
|
|
print("date has't changed:", existing_date)
|
|
|
|
return
|
|
|
|
|
|
|
|
subject = f"New GWR advance ticket booking date: {new_date}"
|
|
|
|
body = f"""Old date: {existing_date}
|
|
|
|
New date: {new_date}
|
|
|
|
|
|
|
|
{gwr.url}
|
|
|
|
|
|
|
|
Agenda: https://edwardbetts.com/agenda/
|
|
|
|
"""
|
2024-04-20 07:52:00 +01:00
|
|
|
send_mail(config, subject, body)
|
2024-03-05 09:26:54 +00:00
|
|
|
|
|
|
|
|
2024-06-15 21:35:18 +01:00
|
|
|
def report_space_launch_change(
|
2024-06-26 08:48:58 +01:00
|
|
|
config: flask.config.Config, prev_launch: StrDict | None, cur_launch: StrDict | None
|
2024-06-15 21:35:18 +01:00
|
|
|
) -> None:
|
|
|
|
"""Send mail to announce change to space launch data."""
|
2024-06-26 08:48:58 +01:00
|
|
|
if cur_launch:
|
|
|
|
name = cur_launch["name"]
|
|
|
|
else:
|
|
|
|
assert prev_launch
|
|
|
|
name = prev_launch["name"]
|
|
|
|
subject = f"Change to {name}"
|
2024-06-15 21:35:18 +01:00
|
|
|
|
|
|
|
body = f"""
|
|
|
|
A space launch of interest was updated.
|
|
|
|
|
|
|
|
Get ready for two big piles of JSON.
|
|
|
|
|
|
|
|
Old launch data
|
|
|
|
{json.dumps(prev_launch, indent=2)}
|
|
|
|
|
|
|
|
New launch data
|
|
|
|
{json.dumps(cur_launch, indent=2)}
|
|
|
|
"""
|
|
|
|
|
|
|
|
send_mail(config, subject, body)
|
|
|
|
|
|
|
|
|
2024-06-26 08:48:58 +01:00
|
|
|
def get_launch_by_slug(data: StrDict, slug: str) -> StrDict | None:
|
2024-06-15 21:35:18 +01:00
|
|
|
"""Find last update for space launch."""
|
2024-06-26 08:48:58 +01:00
|
|
|
return {item["slug"]: typing.cast(StrDict, item) for item in data["results"]}.get(
|
|
|
|
slug
|
|
|
|
)
|
2024-06-15 21:35:18 +01:00
|
|
|
|
|
|
|
|
2024-04-20 07:52:00 +01:00
|
|
|
def update_thespacedevs(config: flask.config.Config) -> None:
|
2024-03-05 09:26:54 +00:00
|
|
|
"""Update cache of space launch API."""
|
2024-04-20 07:52:00 +01:00
|
|
|
rocket_dir = os.path.join(config["DATA_DIR"], "thespacedevs")
|
2024-03-05 09:26:54 +00:00
|
|
|
|
2024-06-15 21:35:18 +01:00
|
|
|
existing_data = agenda.thespacedevs.load_cached_launches(rocket_dir)
|
|
|
|
prev_launches = {
|
|
|
|
slug: get_launch_by_slug(existing_data, slug)
|
|
|
|
for slug in config["FOLLOW_LAUNCHES"]
|
|
|
|
}
|
|
|
|
|
2024-03-05 09:26:54 +00:00
|
|
|
t0 = time()
|
2024-06-15 21:35:18 +01:00
|
|
|
data = agenda.thespacedevs.next_launch_api_data(rocket_dir)
|
|
|
|
cur_launches = {
|
|
|
|
slug: get_launch_by_slug(data, slug) for slug in config["FOLLOW_LAUNCHES"]
|
|
|
|
}
|
|
|
|
|
|
|
|
for slug in config["FOLLOW_LAUNCHES"]:
|
|
|
|
prev, cur = prev_launches[slug], cur_launches[slug]
|
2024-06-26 08:48:58 +01:00
|
|
|
if prev is None and cur is None:
|
|
|
|
continue
|
|
|
|
if prev and cur and prev["last_updated"] == cur["last_updated"]:
|
|
|
|
continue
|
|
|
|
report_space_launch_change(config, prev, cur)
|
2024-06-15 21:35:18 +01:00
|
|
|
|
2024-03-05 09:26:54 +00:00
|
|
|
time_taken = time() - t0
|
|
|
|
if not sys.stdin.isatty():
|
|
|
|
return
|
2024-06-15 21:35:18 +01:00
|
|
|
rockets = [agenda.thespacedevs.summarize_launch(item) for item in data["results"]]
|
2024-03-05 09:26:54 +00:00
|
|
|
print(len(rockets), "launches")
|
|
|
|
print(f"took {time_taken:.1f} seconds")
|
|
|
|
|
|
|
|
|
2024-04-20 07:52:00 +01:00
|
|
|
def update_gandi(config: flask.config.Config) -> None:
|
2024-03-27 17:47:25 +00:00
|
|
|
"""Retrieve list of domains from gandi.net."""
|
|
|
|
url = "https://api.gandi.net/v5/domain/domains"
|
2024-04-20 07:52:00 +01:00
|
|
|
headers = {"authorization": "Bearer " + config["GANDI_TOKEN"]}
|
|
|
|
filename = os.path.join(config["DATA_DIR"], "gandi_domains.json")
|
2024-03-27 17:47:25 +00:00
|
|
|
|
|
|
|
r = requests.request("GET", url, headers=headers)
|
|
|
|
items = r.json()
|
|
|
|
assert isinstance(items, list)
|
|
|
|
assert all(item["fqdn"] and item["dates"]["registry_ends_at"] for item in items)
|
|
|
|
with open(filename, "w") as out:
|
|
|
|
out.write(r.text)
|
|
|
|
|
|
|
|
|
2024-03-05 09:26:54 +00:00
|
|
|
def main() -> None:
|
|
|
|
"""Update caches."""
|
|
|
|
now = datetime.now()
|
|
|
|
hour = now.hour
|
|
|
|
|
2024-04-20 07:52:00 +01:00
|
|
|
with app.app_context():
|
|
|
|
if hour % 3 == 0:
|
|
|
|
asyncio.run(update_bank_holidays(app.config))
|
|
|
|
asyncio.run(update_bristol_bins(app.config))
|
|
|
|
update_gwr_advance_ticket_date(app.config)
|
|
|
|
update_gandi(app.config)
|
2024-03-05 09:26:54 +00:00
|
|
|
|
2024-04-20 07:52:00 +01:00
|
|
|
if hour % 12 == 0:
|
|
|
|
agenda.fx.get_rates(app.config)
|
2024-04-18 22:26:04 +01:00
|
|
|
|
2024-04-20 07:52:00 +01:00
|
|
|
update_thespacedevs(app.config)
|
2024-03-05 09:26:54 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|