diff --git a/hotdog/command/covid.py b/hotdog/command/covid.py index 5adf0e9..c173748 100644 --- a/hotdog/command/covid.py +++ b/hotdog/command/covid.py @@ -8,7 +8,7 @@ from typing import * import requests -from ..functions import localizedtz, reply +from ..functions import localizedtz, react, reply from ..models import Job, Message from ..tz import cest @@ -181,7 +181,7 @@ class Store: for row in self.connection.execute(sql, params): yield Probe.from_row(row) - def find_one(self, term) -> Optional["Probe"]: + def find_one(self, term: str = "%") -> Optional["Probe"]: cond = """ where county_name like ? or state_name like ? @@ -317,11 +317,11 @@ async def update_store(job: Job): store.add(load_data()) -def pfloat(n): +def pfloat(n: float): return f"{n:_.02f}".replace(".", ",") -def as_html(probe, tzname: str, lc: str) -> str: +def as_html(probe: Probe, tzname: str, lc: str) -> str: # now = datetime.now(tz=timezone.utc) # since = now - probe.ts # fmt = "%A" if since.days < 7 else "%x" @@ -348,6 +348,76 @@ def as_html(probe, tzname: str, lc: str) -> str: ) +def top3html(states: List[Probe], counties: List[Probe], tzname: str, lc: str) -> str: + assert len(states) == len(counties) == 3 + posmoji = ("πŸ₯‡", "πŸ₯ˆ", "πŸ₯‰") + date = localizedtz(states[0].ts, "%A, %x", tzname=tzname, lc=lc) + return ( + f"HΓΆchste 7-Tage-Inzidenz von {date}: " + + ", ".join( + ( + f"{medal} {escape(probe.county_name)}" + + f" (πŸ“ˆ {pfloat(probe.cases7_per_100k)})" + ) + for probe, medal in zip(counties, posmoji) + ) + + " β€” " + + ", ".join( + ( + f"{medal} {escape(probe.state_name)}" + + f" (πŸ“ˆ {pfloat(probe.state_cases7_per_100k)})" + ) + for probe, medal in zip(states, posmoji) + ) + ) + + +async def top3(store: Store, message: Message): + latest = store.find_one() + + def top_probes(scope: str, n=3): + sql = f""" + select * + from current + where ts = ? + group by {scope}_name + order by {scope}_cases7_per_100k desc + limit {n} + """ + return [ + Probe.from_row(row) + for row in store.connection.execute(sql, [latest.ts.timestamp()]) + ] + + states = top_probes("state") + counties = top_probes("county") + + if states and counties: + roomconf = message.app.config.l6n[message.room.room_id] + await reply( + message, + html=top3html( + states, counties, tzname=roomconf["timezone"], lc=roomconf["locale"] + ), + ) + else: + await react(message, emoji="πŸ›") + + +async def search(store: Store, message: Message): + assert message.args + + term = "%".join(message.args) + if (probe := store.find_one(f"%{term}%")) : + roomconf = message.app.config.l6n[message.room.room_id] + await reply( + message, + html=as_html(probe, tzname=roomconf["timezone"], lc=roomconf["locale"]), + ) + else: + await reply(message, "No such county or state.", in_thread=True) + + async def handle(message: Message): if message.command not in ("cov", "covid") or not message.args: return @@ -359,12 +429,8 @@ async def handle(message: Message): # return store: Store = message.app.shared["covid.store"] - term = "%".join(message.args) - if (probe := store.find_one(f"%{term}%")) : - roomconf = message.app.config.l6n[message.room.room_id] - await reply( - message, - html=as_html(probe, tzname=roomconf["timezone"], lc=roomconf["locale"]), - ) + + if message.args.get(0) == "top3": + await top3(store, message) else: - await reply(message, "No such county or state.", in_thread=True) + await search(store, message)