refactor(easel): add weather routes

This commit is contained in:
2024-08-11 21:14:01 +03:00
parent 72fd378c40
commit 6db33ca669
13 changed files with 101 additions and 97 deletions

View File

@@ -1,87 +0,0 @@
import datetime
from pathlib import Path
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from gallery.sketch.weather.api import WeatherApi
from gallery.sketch.weather.mock import WEATHER_MOCK_DATA
from gallery.sketch.weather.model import WeatherResponse
from ..util import TagType, TagUtil
from .filters import cloudness_icon, wind_direction_icon
def mount(app: FastAPI):
base_dir = Path(__file__).parent
app.mount("/static", StaticFiles(directory=base_dir / "static"), name="static")
templates = Jinja2Templates(directory=base_dir / "templates")
templates.env.filters["wind_direction_icon"] = wind_direction_icon
templates.env.filters["cloudness_icon"] = cloudness_icon
def build_weather_response(request: Request, response: WeatherResponse):
return templates.TemplateResponse(
request=request,
name="weather.html",
context={
"tag_util": TagUtil,
"datetime": datetime,
"response": response,
},
)
@app.get("/", response_class=RedirectResponse)
async def get_weather_root():
return RedirectResponse("weather")
@app.get("/weather", response_class=HTMLResponse)
async def get_weather_list(request: Request):
weather_api: WeatherApi = request.app.state.weather_api
locations = await weather_api.get_locations()
return templates.TemplateResponse(
request=request,
name="index.html",
context={
"locations": locations,
},
)
@app.get("/weather/{location}", response_class=RedirectResponse)
async def get_weather_default(location: str):
return RedirectResponse(f"{location}/tag/today")
@app.get("/weather/{location}/day/mock", response_class=HTMLResponse)
async def get_weather_day_mock(request: Request):
response = WEATHER_MOCK_DATA.get_response("day")
return build_weather_response(request, response)
@app.get("/weather/{location}/days/mock", response_class=HTMLResponse)
async def get_weather_days_mock(request: Request):
response = WEATHER_MOCK_DATA.get_response("days")
return build_weather_response(request, response)
@app.get("/weather/{location}/day/{date}", response_class=HTMLResponse)
async def get_weather_day(request: Request, location: str, date: datetime.date):
weather_api: WeatherApi = request.app.state.weather_api
response = await weather_api.get_day(location, date)
return build_weather_response(request, response)
@app.get("/weather/{location}/days/{days}", response_class=HTMLResponse)
async def get_weather_days(request: Request, location: str, days: int):
weather_api: WeatherApi = request.app.state.weather_api
response = await weather_api.get_days(location, days)
return build_weather_response(request, response)
@app.get("/weather/{location}/tag/{tag}", response_class=HTMLResponse)
async def get_weather_tag(request: Request, location: str, tag: str):
tag_value = TagUtil.parse_tag(tag)
weather_api: WeatherApi = request.app.state.weather_api
if tag_value.type == TagType.DAY:
response = await weather_api.get_day(location, tag_value.date)
elif tag_value.type == TagType.DAYS:
response = await weather_api.get_days(location, tag_value.days)
else:
raise ValueError(tag)
return build_weather_response(request, response)

View File

@@ -0,0 +1,85 @@
import datetime
from pathlib import Path
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from gallery.sketch.weather.api import WeatherApi
from gallery.sketch.weather.mock import WEATHER_MOCK_DATA
from gallery.sketch.weather.model import WeatherResponse
from .filters import cloudness_icon, wind_direction_icon
from .util import TagType, TagUtil
def mount(app: FastAPI):
base_dir = Path(__file__).parent
app.mount(
"/weather/static", StaticFiles(directory=base_dir / "static"), name="static"
)
templates = Jinja2Templates(directory=base_dir / "templates")
templates.env.filters["wind_direction_icon"] = wind_direction_icon
templates.env.filters["cloudness_icon"] = cloudness_icon
def build_weather_response(request: Request, response: WeatherResponse):
return templates.TemplateResponse(
request=request,
name="weather.html",
context={
"tag_util": TagUtil,
"datetime": datetime,
"response": response,
},
)
@app.get("/weather", response_class=HTMLResponse)
async def get_weather_list(request: Request):
weather_api: WeatherApi = request.app.state.weather_api
locations = await weather_api.get_locations()
return templates.TemplateResponse(
request=request,
name="index.html",
context={
"locations": locations,
},
)
@app.get("/weather/{location}", response_class=RedirectResponse)
async def get_weather_default(location: str):
return RedirectResponse(f"{location}/tag/today")
@app.get("/weather/{location}/day/mock", response_class=HTMLResponse)
async def get_weather_day_mock(request: Request):
response = WEATHER_MOCK_DATA.get_response("day")
return build_weather_response(request, response)
@app.get("/weather/{location}/days/mock", response_class=HTMLResponse)
async def get_weather_days_mock(request: Request):
response = WEATHER_MOCK_DATA.get_response("days")
return build_weather_response(request, response)
@app.get("/weather/{location}/day/{date}", response_class=HTMLResponse)
async def get_weather_day(request: Request, location: str, date: datetime.date):
weather_api: WeatherApi = request.app.state.weather_api
response = await weather_api.get_day(location, date)
return build_weather_response(request, response)
@app.get("/weather/{location}/days/{days}", response_class=HTMLResponse)
async def get_weather_days(request: Request, location: str, days: int):
weather_api: WeatherApi = request.app.state.weather_api
response = await weather_api.get_days(location, days)
return build_weather_response(request, response)
@app.get("/weather/{location}/tag/{tag}", response_class=HTMLResponse)
async def get_weather_tag(request: Request, location: str, tag: str):
tag_value = TagUtil.parse_tag(tag)
weather_api: WeatherApi = request.app.state.weather_api
if tag_value.type == TagType.DAY:
response = await weather_api.get_day(location, tag_value.date)
elif tag_value.type == TagType.DAYS:
response = await weather_api.get_days(location, tag_value.days)
else:
raise ValueError(tag)
return build_weather_response(request, response)

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -9,9 +9,9 @@
content="ie=edge">
<title>Погода</title>
<link rel="stylesheet"
href="/static/style.css?v=1">
href="/weather/static/style.css?v=1">
<link rel="icon"
href="/static/favicon.ico"
href="/weather/static/favicon.ico"
type="image/x-icon">
</head>

View File

@@ -9,9 +9,9 @@
content="ie=edge">
<title>Погода | {{response.location}} | {{response.date.strftime('%a, %d %B %Y')}}</title>
<link rel="stylesheet"
href="/static/style.css?v=1">
href="/weather/static/style.css?v=1">
<link rel="icon"
href="/static/favicon.ico"
href="/weather/static/favicon.ico"
type="image/x-icon">
</head>

View File

@@ -0,0 +1,57 @@
import datetime
from enum import Enum
from typing import NamedTuple
class TagType(str, Enum):
DAY = "day"
DAYS = "days"
class Tag(NamedTuple):
type: TagType
date: datetime.date
days: int = 1
def __str__(self) -> str:
if self.type == TagType.DAY:
today = datetime.date.today()
day = (self.date - today).days
return f"day-{day}"
elif self.type == TagType.DAYS:
return f"days-{self.days}"
else:
raise ValueError(self.type)
class TagUtil:
@classmethod
def parse_tag(cls, tag: str) -> Tag:
if tag == "today":
return Tag(TagType.DAY, datetime.date.today())
elif tag == "tomorrow":
return Tag(TagType.DAY, datetime.date.today() + datetime.timedelta(days=1))
elif tag.startswith("day-"):
days = int(tag.split("-")[-1])
return Tag(
TagType.DAY,
datetime.date.today() + datetime.timedelta(days=days),
)
elif tag.startswith("days-"):
days = int(tag.split("-")[-1])
return Tag(TagType.DAYS, datetime.date.today(), days)
raise ValueError(tag)
@classmethod
def create_tag(
cls,
tag_type: TagType,
date: datetime.date,
day: int = 0,
days: int = 10,
) -> Tag:
if tag_type == TagType.DAY:
return Tag(tag_type, date + datetime.timedelta(days=day))
if tag_type == TagType.DAYS:
return Tag(tag_type, date, days)
raise ValueError(tag_type)