feat(app/view): add tag routing
This commit is contained in:
57
weather/app/route/util.py
Normal file
57
weather/app/route/util.py
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import datetime
|
||||||
|
from enum import Enum
|
||||||
|
from typing import NamedTuple, Optional
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
@@ -6,10 +6,10 @@ from fastapi.responses import HTMLResponse, RedirectResponse
|
|||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
|
|
||||||
from gismeteo import datehelp
|
|
||||||
from gismeteo.location import LOCATION_BUNDLE
|
from gismeteo.location import LOCATION_BUNDLE
|
||||||
from gismeteo.mock import MOCK_DATA
|
from gismeteo.mock import MOCK_DATA
|
||||||
from weather.api import WeatherApi
|
from weather.api import WeatherApi
|
||||||
|
from weather.app.route.util import TagType, TagUtil
|
||||||
from weather.model import WeatherResponse
|
from weather.model import WeatherResponse
|
||||||
|
|
||||||
from .filters import cloudness_icon, wind_direction_icon
|
from .filters import cloudness_icon, wind_direction_icon
|
||||||
@@ -27,6 +27,7 @@ def mount(app: FastAPI):
|
|||||||
request=request,
|
request=request,
|
||||||
name="weather.html",
|
name="weather.html",
|
||||||
context={
|
context={
|
||||||
|
"tag_util": TagUtil,
|
||||||
"datetime": datetime,
|
"datetime": datetime,
|
||||||
"response": response,
|
"response": response,
|
||||||
},
|
},
|
||||||
@@ -48,7 +49,7 @@ def mount(app: FastAPI):
|
|||||||
|
|
||||||
@app.get("/weather/{location}", response_class=RedirectResponse)
|
@app.get("/weather/{location}", response_class=RedirectResponse)
|
||||||
async def get_weather_default(location: str):
|
async def get_weather_default(location: str):
|
||||||
return RedirectResponse(f"{location}/day/{datetime.date.today()}")
|
return RedirectResponse(f"{location}/tag/today")
|
||||||
|
|
||||||
@app.get("/weather/{location}/day/mock", response_class=HTMLResponse)
|
@app.get("/weather/{location}/day/mock", response_class=HTMLResponse)
|
||||||
async def get_weather_day_mock(request: Request):
|
async def get_weather_day_mock(request: Request):
|
||||||
@@ -71,3 +72,15 @@ def mount(app: FastAPI):
|
|||||||
weather_api: WeatherApi = request.app.state.weather_api
|
weather_api: WeatherApi = request.app.state.weather_api
|
||||||
response = await weather_api.get_days(location, days)
|
response = await weather_api.get_days(location, days)
|
||||||
return build_weather_response(request, response)
|
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)
|
||||||
|
|||||||
@@ -19,12 +19,12 @@
|
|||||||
<h3>
|
<h3>
|
||||||
{% if response.period == 'day' %}
|
{% if response.period == 'day' %}
|
||||||
<a class="button {{'disabled' if response.date == datetime.date.today() else ''}}"
|
<a class="button {{'disabled' if response.date == datetime.date.today() else ''}}"
|
||||||
href="{{response.date - datetime.timedelta(days=1)}}">⬅️</a>
|
href="../tag/{{tag_util.create_tag('day', response.date, -1)}}">⬅️</a>
|
||||||
<a class="button"
|
<a class="button"
|
||||||
href="../days/10">⬆️</a>
|
href="../tag/days-10">⬆️</a>
|
||||||
<span>{{response.location}} | {{response.date.strftime('%a, %d %B %Y')}}</span>
|
<span>{{response.location}} | {{response.date.strftime('%a, %d %B %Y')}}</span>
|
||||||
<a class="button"
|
<a class="button"
|
||||||
href="{{response.date + datetime.timedelta(days=1)}}">➡️</a>
|
href="../tag/{{tag_util.create_tag('day', response.date, 1)}}">➡️</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if response.period == 'days' %}
|
{% if response.period == 'days' %}
|
||||||
<span>{{response.location}} | {{response.date.strftime('%a, %d %B %Y')}}</span>
|
<span>{{response.location}} | {{response.date.strftime('%a, %d %B %Y')}}</span>
|
||||||
@@ -42,9 +42,12 @@
|
|||||||
</td>
|
</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if response.period == 'days' %}
|
{% if response.period == 'days' %}
|
||||||
<td
|
<td class="date {{'now' if value.date.date() == datetime.date.today() else ''}}">
|
||||||
class="date {{'now' if value.date.date() == datetime.date.today() else ''}}">
|
<span class="value">
|
||||||
<span class="value"><a href="../day/{{value.date.date()}}">{{value.date.strftime('%a %d')}}</a></span>
|
<a href="../tag/{{tag_util.create_tag('day', value.date.date())}}">
|
||||||
|
{{value.date.strftime('%a %d')}}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
</td>
|
</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
22
weather/util.py
Normal file
22
weather/util.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import datetime
|
||||||
|
|
||||||
|
from weather.model import Cloudness, Precipitation, Sky, WeatherValue, WindDirection
|
||||||
|
|
||||||
|
|
||||||
|
def build_weather_value(date: datetime.datetime) -> WeatherValue:
|
||||||
|
return WeatherValue(
|
||||||
|
date=date,
|
||||||
|
sky=Sky(
|
||||||
|
cloudness=Cloudness.CLEAR,
|
||||||
|
precipitation=Precipitation.NO,
|
||||||
|
thunder=False,
|
||||||
|
fog=False,
|
||||||
|
),
|
||||||
|
temperature=[],
|
||||||
|
wind_speed=0,
|
||||||
|
wind_gust=0,
|
||||||
|
wind_direction=WindDirection.CALM,
|
||||||
|
precipitation=0,
|
||||||
|
pressure=[],
|
||||||
|
humidity=0,
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user