From df884f55f100120054ec5848f191211c5b452809 Mon Sep 17 00:00:00 2001 From: stijndcl Date: Thu, 22 Sep 2022 02:04:34 +0200 Subject: [PATCH] Covid api requests --- didier/cogs/other.py | 23 +++++++++++++---- didier/data/apis/disease_sh.py | 38 ++++++++++++++++++++++++++++ didier/data/apis/urban_dictionary.py | 13 +++------- didier/data/embeds/disease_sh.py | 33 ++++++++++++++++++++++++ didier/utils/http/requests.py | 6 ++--- 5 files changed, 96 insertions(+), 17 deletions(-) create mode 100644 didier/data/apis/disease_sh.py create mode 100644 didier/data/embeds/disease_sh.py diff --git a/didier/cogs/other.py b/didier/cogs/other.py index 20c4fd8..dff1376 100644 --- a/didier/cogs/other.py +++ b/didier/cogs/other.py @@ -7,7 +7,7 @@ from discord.ext import commands from database.crud.links import get_link_by_name from database.schemas import Link from didier import Didier -from didier.data.apis import inspirobot, urban_dictionary +from didier.data.apis import disease_sh, inspirobot, urban_dictionary from didier.data.embeds.google import GoogleSearch from didier.data.scrapers import google @@ -20,16 +20,29 @@ class Other(commands.Cog): def __init__(self, client: Didier): self.client = client + @commands.hybrid_command(name="corona", aliases=["covid", "rona"]) + async def covid(self, ctx: commands.Context, country: str = "Belgium"): + """Show Covid-19 info for a specific country. + + By default, this will fetch the numbers for Belgium. + + To get worldwide stats, use `all`, `global`, `world`, or `worldwide`. + """ + async with ctx.typing(): + if country.lower() in ["all", "global", "world", "worldwide"]: + data = await disease_sh.get_global_info(self.client.http_session) + else: + data = await disease_sh.get_country_info(self.client.http_session, country) + + await ctx.reply(str(data), mention_author=False) + @commands.hybrid_command( name="define", aliases=["ud", "urban"], description="Look up the definition of a word on the Urban Dictionary" ) async def define(self, ctx: commands.Context, *, query: str): """Look up the definition of `query` on the Urban Dictionary.""" async with ctx.typing(): - status_code, definitions = await urban_dictionary.lookup(self.client.http_session, query) - if not definitions: - return await ctx.reply(f"Something went wrong (status {status_code})") - + definitions = await urban_dictionary.lookup(self.client.http_session, query) await ctx.reply(embed=definitions[0].to_embed(), mention_author=False) @commands.hybrid_command(name="google", description="Google search") diff --git a/didier/data/apis/disease_sh.py b/didier/data/apis/disease_sh.py new file mode 100644 index 0000000..809cdcb --- /dev/null +++ b/didier/data/apis/disease_sh.py @@ -0,0 +1,38 @@ +from aiohttp import ClientSession + +from didier.data.embeds.disease_sh import CovidData +from didier.utils.http.requests import ensure_get + +__all__ = ["get_country_info", "get_global_info"] + + +async def get_country_info(http_session: ClientSession, country: str) -> CovidData: + """Fetch the info for a given country for today and yesterday""" + endpoint = f"https://disease.sh/v3/covid-19/countries/{country}" + + params = {"yesterday": 0, "strict": 1, "allowNull": 0} + async with ensure_get(http_session, endpoint, params=params) as response: + today = response + + params["yesterday"] = 1 + async with ensure_get(http_session, endpoint, params=params) as response: + yesterday = response + + data = {"today": today, "yesterday": yesterday} + return CovidData.parse_obj(data) + + +async def get_global_info(http_session: ClientSession) -> CovidData: + """Fetch the global info for today and yesterday""" + endpoint = "https://disease.sh/v3/covid-19/all" + + params = {"yesterday": 0, "allowNull": 0} + async with ensure_get(http_session, endpoint, params=params) as response: + today = response + + params["yesterday"] = 1 + async with ensure_get(http_session, endpoint, params=params) as response: + yesterday = response + + data = {"today": today, "yesterday": yesterday} + return CovidData.parse_obj(data) diff --git a/didier/data/apis/urban_dictionary.py b/didier/data/apis/urban_dictionary.py index e0ebf15..6d81934 100644 --- a/didier/data/apis/urban_dictionary.py +++ b/didier/data/apis/urban_dictionary.py @@ -1,8 +1,7 @@ -from http import HTTPStatus - from aiohttp import ClientSession from didier.data.embeds.urban_dictionary import Definition +from didier.utils.http.requests import ensure_get __all__ = ["lookup", "PER_PAGE"] @@ -10,13 +9,9 @@ __all__ = ["lookup", "PER_PAGE"] PER_PAGE = 10 -async def lookup(http_session: ClientSession, query: str) -> tuple[int, list[Definition]]: +async def lookup(http_session: ClientSession, query: str) -> list[Definition]: """Fetch the Urban Dictionary definitions for a given word""" url = "https://api.urbandictionary.com/v0/define" - async with http_session.get(url, params={"term": query}) as response: - if response.status != HTTPStatus.OK: - return response.status, [] - - response_json = await response.json() - return 200, list(map(Definition.parse_obj, response_json["list"])) + async with ensure_get(http_session, url, params={"term": query}) as response: + return list(map(Definition.parse_obj, response["list"])) diff --git a/didier/data/embeds/disease_sh.py b/didier/data/embeds/disease_sh.py new file mode 100644 index 0000000..4056ec6 --- /dev/null +++ b/didier/data/embeds/disease_sh.py @@ -0,0 +1,33 @@ +import discord +from overrides import overrides +from pydantic import BaseModel, Field + +from didier.data.embeds.base import EmbedPydantic + +__all__ = ["CovidData"] + + +class _CovidNumbers(BaseModel): + """Covid information for a country""" + + updated: int + country: str = "Worldwide" + cases: int + today_cases: int = Field(alias="todayCases") + deaths: int + today_deaths: int = Field(alias="todayDeaths") + recovered: int + todayRecovered: int = Field(alias="todayRecovered") + active: int + tests: int + + +class CovidData(EmbedPydantic): + """Covid information from two days combined into one model""" + + today: _CovidNumbers + yesterday: _CovidNumbers + + @overrides + def to_embed(self, **kwargs) -> discord.Embed: + pass diff --git a/didier/utils/http/requests.py b/didier/utils/http/requests.py index ffcb498..4d1ef76 100644 --- a/didier/utils/http/requests.py +++ b/didier/utils/http/requests.py @@ -1,6 +1,6 @@ import logging from contextlib import asynccontextmanager -from typing import AsyncGenerator +from typing import AsyncGenerator, Optional from aiohttp import ClientResponse, ClientSession, ContentTypeError @@ -19,10 +19,10 @@ def request_successful(response: ClientResponse) -> bool: @asynccontextmanager async def ensure_get( - http_session: ClientSession, endpoint: str, *, log_exceptions: bool = True + http_session: ClientSession, endpoint: str, *, params: Optional[dict] = None, log_exceptions: bool = True ) -> AsyncGenerator[dict, None]: """Context manager that automatically raises an exception if a GET-request fails""" - async with http_session.get(endpoint) as response: + async with http_session.get(endpoint, params=params) as response: try: content = await response.json() except ContentTypeError: