refactor(easel): remove TagUtil
This commit is contained in:
@@ -0,0 +1,25 @@
|
|||||||
|
import datetime
|
||||||
|
from typing import Annotated
|
||||||
|
|
||||||
|
from fastapi import Depends, HTTPException, status
|
||||||
|
|
||||||
|
|
||||||
|
def date_parser(date: str) -> datetime.date:
|
||||||
|
if date == "today":
|
||||||
|
return datetime.date.today()
|
||||||
|
elif date == "tomorrow":
|
||||||
|
return datetime.date.today() + datetime.timedelta(days=1)
|
||||||
|
elif date.startswith("day-"):
|
||||||
|
days = int(date.split("-")[-1])
|
||||||
|
return datetime.date.today() + datetime.timedelta(days=days)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
return datetime.date.strptime(date, "%Y-%m-%d")
|
||||||
|
except ValueError as exc:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
detail={"date": f"{exc}"},
|
||||||
|
) from exc
|
||||||
|
|
||||||
|
|
||||||
|
DateDepends = Annotated[datetime.date, Depends(date_parser)]
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
import datetime
|
|
||||||
|
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
|
||||||
from gallery.easel.core import AppRequest
|
from gallery.easel.core import AppRequest
|
||||||
@@ -7,6 +5,8 @@ from gallery.easel.depends.schedule import ScheduleApiDepends
|
|||||||
from gallery.sketch.schedule.api import ScheduleApi
|
from gallery.sketch.schedule.api import ScheduleApi
|
||||||
from gallery.sketch.schedule.model import Channel, Schedule
|
from gallery.sketch.schedule.model import Channel, Schedule
|
||||||
|
|
||||||
|
from ...depends.date import DateDepends
|
||||||
|
|
||||||
router = APIRouter(prefix="/schedule", tags=["Schedule"])
|
router = APIRouter(prefix="/schedule", tags=["Schedule"])
|
||||||
|
|
||||||
|
|
||||||
@@ -22,6 +22,6 @@ async def find_api_schedule_channels(schedule_api: ScheduleApiDepends, query: st
|
|||||||
|
|
||||||
@router.get("/{provider}/{channel}/{date}")
|
@router.get("/{provider}/{channel}/{date}")
|
||||||
async def get_api_schedule_channel_schedule(
|
async def get_api_schedule_channel_schedule(
|
||||||
schedule_api: ScheduleApiDepends, channel: str, date: datetime.date
|
schedule_api: ScheduleApiDepends, channel: str, date: DateDepends
|
||||||
) -> Schedule:
|
) -> Schedule:
|
||||||
return await schedule_api.get_schedule(channel, date)
|
return await schedule_api.get_schedule(channel, date)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import datetime
|
|
||||||
|
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
|
||||||
from gallery.easel.core import AppRequest
|
from gallery.easel.core import AppRequest
|
||||||
@@ -7,6 +5,8 @@ from gallery.easel.depends.weather import WeatherApiDepends
|
|||||||
from gallery.sketch.weather.api import WeatherApi
|
from gallery.sketch.weather.api import WeatherApi
|
||||||
from gallery.sketch.weather.model import Location, WeatherResponse
|
from gallery.sketch.weather.model import Location, WeatherResponse
|
||||||
|
|
||||||
|
from ...depends.date import DateDepends
|
||||||
|
|
||||||
router = APIRouter(prefix="/weather", tags=["Weather"])
|
router = APIRouter(prefix="/weather", tags=["Weather"])
|
||||||
|
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ async def find_api_weather_locations(weather_api: WeatherApiDepends, query: str)
|
|||||||
|
|
||||||
|
|
||||||
@router.get("/{provider}/{location}/day/{date}")
|
@router.get("/{provider}/{location}/day/{date}")
|
||||||
async def get_api_weather_day(weather_api: WeatherApiDepends, location: str, date: datetime.date) -> WeatherResponse:
|
async def get_api_weather_day(weather_api: WeatherApiDepends, location: str, date: DateDepends) -> WeatherResponse:
|
||||||
return await weather_api.get_day(location, date)
|
return await weather_api.get_day(location, date)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
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)
|
|
||||||
else:
|
|
||||||
date = datetime.date.strptime(tag, "%Y-%m-%d")
|
|
||||||
return cls.create_tag(TagType.DAY, date)
|
|
||||||
|
|
||||||
@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)
|
|
||||||
@@ -11,7 +11,6 @@ from gallery.easel.core import AppRequest
|
|||||||
from gallery.version import __version__
|
from gallery.version import __version__
|
||||||
|
|
||||||
from ...translation import _
|
from ...translation import _
|
||||||
from .tag import TagUtil
|
|
||||||
|
|
||||||
ContextProcessor = typing.Callable[[AppRequest], dict[str, typing.Any]]
|
ContextProcessor = typing.Callable[[AppRequest], dict[str, typing.Any]]
|
||||||
|
|
||||||
@@ -32,7 +31,6 @@ def base_context_processor(request: Request) -> dict:
|
|||||||
def build_url(
|
def build_url(
|
||||||
request: Request, *, path: list[str] | None = None, up: int | None = None, query: dict | None = None
|
request: Request, *, path: list[str] | None = None, up: int | None = None, query: dict | None = None
|
||||||
) -> str:
|
) -> str:
|
||||||
print("!", path)
|
|
||||||
parts = urlsplit(str(request.url))
|
parts = urlsplit(str(request.url))
|
||||||
if up:
|
if up:
|
||||||
path = [".."] * up
|
path = [".."] * up
|
||||||
@@ -66,7 +64,6 @@ def build_templates(
|
|||||||
"version": __version__,
|
"version": __version__,
|
||||||
"format_date": format_date,
|
"format_date": format_date,
|
||||||
"datetime": datetime,
|
"datetime": datetime,
|
||||||
"tag_util": TagUtil,
|
|
||||||
"DATE_FORMAT": "E, d MMMM Y",
|
"DATE_FORMAT": "E, d MMMM Y",
|
||||||
"build_url": build_url,
|
"build_url": build_url,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
import datetime
|
|
||||||
from typing import Annotated
|
|
||||||
|
|
||||||
from fastapi import Depends
|
|
||||||
|
|
||||||
from ..common.utils.tag import Tag, TagType, TagUtil
|
|
||||||
|
|
||||||
|
|
||||||
def _resolve_tag(date: datetime.date | None = None, tag: str | None = None) -> Tag:
|
|
||||||
if tag:
|
|
||||||
result = TagUtil.parse_tag(tag)
|
|
||||||
else:
|
|
||||||
date = date or datetime.date.today()
|
|
||||||
result = TagUtil.create_tag(TagType.DAY, date)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
TagDepends = Annotated[Tag, Depends(_resolve_tag)]
|
|
||||||
@@ -7,14 +7,13 @@ from fastapi.responses import HTMLResponse, RedirectResponse
|
|||||||
|
|
||||||
from gallery.easel.core import AppRequest
|
from gallery.easel.core import AppRequest
|
||||||
from gallery.easel.depends.api import api_resolver
|
from gallery.easel.depends.api import api_resolver
|
||||||
|
from gallery.easel.depends.date import DateDepends
|
||||||
from gallery.easel.depends.schedule import ScheduleApiDepends
|
from gallery.easel.depends.schedule import ScheduleApiDepends
|
||||||
from gallery.sketch.bundle import ApiBundle
|
from gallery.sketch.bundle import ApiBundle
|
||||||
from gallery.sketch.schedule.api import ScheduleApi
|
from gallery.sketch.schedule.api import ScheduleApi
|
||||||
from gallery.sketch.schedule.model import Schedule
|
from gallery.sketch.schedule.model import Schedule
|
||||||
|
|
||||||
from ..common.utils.tag import TagType
|
|
||||||
from ..common.utils.template import build_templates
|
from ..common.utils.template import build_templates
|
||||||
from ..depends.tag import TagDepends
|
|
||||||
from .bundle import GROUP_MAP
|
from .bundle import GROUP_MAP
|
||||||
from .filters import timedelta_format
|
from .filters import timedelta_format
|
||||||
|
|
||||||
@@ -61,10 +60,10 @@ async def get_group_default(group_id: str):
|
|||||||
return RedirectResponse(f"{parse.quote(group_id)}/today")
|
return RedirectResponse(f"{parse.quote(group_id)}/today")
|
||||||
|
|
||||||
|
|
||||||
@router.get("/group/{group_id}/{tag}", response_class=HTMLResponse)
|
@router.get("/group/{group_id}/{date}", response_class=HTMLResponse)
|
||||||
async def get_group(request: AppRequest, group_id: str, tag: TagDepends):
|
async def get_group(request: AppRequest, group_id: str, date: DateDepends):
|
||||||
channels = GROUP_MAP.get(group_id, [tuple(item.split(":")) for item in group_id.split(",")])
|
channels = GROUP_MAP.get(group_id, [tuple(item.split(":")) for item in group_id.split(",")])
|
||||||
responses = await _get_group_schedule(request.app.state.api, channels, tag.date)
|
responses = await _get_group_schedule(request.app.state.api, channels, date)
|
||||||
return templates.TemplateResponse(
|
return templates.TemplateResponse(
|
||||||
request=request,
|
request=request,
|
||||||
name="group.html",
|
name="group.html",
|
||||||
@@ -77,12 +76,9 @@ async def get_channel_default(channel: str):
|
|||||||
return RedirectResponse(f"{channel}/today")
|
return RedirectResponse(f"{channel}/today")
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{provider}/{channel}/{tag}", response_class=HTMLResponse)
|
@router.get("/{provider}/{channel}/{date}", response_class=HTMLResponse)
|
||||||
async def get_channel_tag(request: AppRequest, schedule_api: ScheduleApiDepends, channel: str, tag: TagDepends):
|
async def get_channel(request: AppRequest, schedule_api: ScheduleApiDepends, channel: str, date: DateDepends):
|
||||||
if tag.type == TagType.DAY:
|
response = await schedule_api.get_schedule(channel, date)
|
||||||
response = await schedule_api.get_schedule(channel, tag.date)
|
|
||||||
else:
|
|
||||||
raise ValueError(tag)
|
|
||||||
return templates.TemplateResponse(
|
return templates.TemplateResponse(
|
||||||
request=request,
|
request=request,
|
||||||
name="channel.html",
|
name="channel.html",
|
||||||
|
|||||||
@@ -1,102 +1 @@
|
|||||||
import datetime
|
from .route import router
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from fastapi import APIRouter
|
|
||||||
from fastapi.responses import HTMLResponse, RedirectResponse
|
|
||||||
|
|
||||||
from gallery.easel.core import AppRequest
|
|
||||||
from gallery.easel.depends.api import api_resolver
|
|
||||||
from gallery.easel.depends.weather import WeatherApiDepends
|
|
||||||
from gallery.sketch.weather.api import WeatherApi
|
|
||||||
from gallery.sketch.weather.model import WeatherResponse
|
|
||||||
|
|
||||||
from ..common.utils.tag import TagType, TagUtil
|
|
||||||
from ..common.utils.template import build_templates
|
|
||||||
from .filters import cloudness_icon, weather_icon_svg, wind_direction_icon
|
|
||||||
|
|
||||||
|
|
||||||
def context_procesor(request: AppRequest) -> dict:
|
|
||||||
return {
|
|
||||||
"providers": request.app.state.api.get_api_providers(WeatherApi),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
templates = build_templates(
|
|
||||||
Path(__file__).parent / "templates",
|
|
||||||
{
|
|
||||||
"wind_direction_icon": wind_direction_icon,
|
|
||||||
"cloudness_icon": cloudness_icon,
|
|
||||||
"weather_icon_svg": weather_icon_svg,
|
|
||||||
},
|
|
||||||
context_procesor,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def build_weather_response(request: AppRequest, response: WeatherResponse):
|
|
||||||
return templates.TemplateResponse(
|
|
||||||
request=request,
|
|
||||||
name="weather.html",
|
|
||||||
context={
|
|
||||||
"response": response,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
router = APIRouter(prefix="/weather")
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/", response_class=HTMLResponse)
|
|
||||||
async def get_weather_index(request: AppRequest, provider: str | None = None, query: str | None = None):
|
|
||||||
if query and provider:
|
|
||||||
weather_api = api_resolver(WeatherApi)(request, provider)
|
|
||||||
locations = await weather_api.find_locations(query)
|
|
||||||
else:
|
|
||||||
locations = []
|
|
||||||
return templates.TemplateResponse(
|
|
||||||
request=request,
|
|
||||||
name="index.html",
|
|
||||||
context={
|
|
||||||
"locations": locations,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{provider}/{location}", response_class=RedirectResponse)
|
|
||||||
async def get_weather(location: str):
|
|
||||||
return RedirectResponse(f"{location}/tag/today")
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{provider}/{location}/day/{date}", response_class=HTMLResponse)
|
|
||||||
async def get_weather_day(
|
|
||||||
request: AppRequest,
|
|
||||||
weather_api: WeatherApiDepends,
|
|
||||||
location: str,
|
|
||||||
date: datetime.date,
|
|
||||||
):
|
|
||||||
response = await weather_api.get_day(location, date)
|
|
||||||
return build_weather_response(request, response)
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{provider}/{location}/days/{days}", response_class=HTMLResponse)
|
|
||||||
async def get_weather_days(request: AppRequest, weather_api: WeatherApiDepends, location: str, days: int):
|
|
||||||
response = await weather_api.get_days(location, days)
|
|
||||||
return build_weather_response(request, response)
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{provider}/{location}/tag/{tag}", response_class=HTMLResponse)
|
|
||||||
async def get_weather_tag(request: AppRequest, weather_api: WeatherApiDepends, location: str, tag: str):
|
|
||||||
tag_value = TagUtil.parse_tag(tag)
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/zmiyevka-184640/tag/{tag}", response_class=RedirectResponse)
|
|
||||||
async def get_zmiyevka_weather_compat(request: AppRequest):
|
|
||||||
path_parts = request.url.path.split("/")
|
|
||||||
path_parts.insert(2, "gismeteo")
|
|
||||||
return RedirectResponse("/".join(path_parts))
|
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from typing import Literal
|
||||||
|
|
||||||
|
from fastapi import APIRouter
|
||||||
|
from fastapi.responses import HTMLResponse, RedirectResponse
|
||||||
|
|
||||||
|
from gallery.easel.core import AppRequest
|
||||||
|
from gallery.easel.depends.api import api_resolver
|
||||||
|
from gallery.easel.depends.date import DateDepends
|
||||||
|
from gallery.easel.depends.weather import WeatherApiDepends
|
||||||
|
from gallery.sketch.weather.api import WeatherApi
|
||||||
|
from gallery.sketch.weather.model import WeatherResponse
|
||||||
|
|
||||||
|
from ..common.utils.template import build_templates
|
||||||
|
from .filters import cloudness_icon, weather_icon_svg, wind_direction_icon
|
||||||
|
|
||||||
|
|
||||||
|
def context_procesor(request: AppRequest) -> dict:
|
||||||
|
return {
|
||||||
|
"providers": request.app.state.api.get_api_providers(WeatherApi),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
templates = build_templates(
|
||||||
|
Path(__file__).parent / "templates",
|
||||||
|
{
|
||||||
|
"wind_direction_icon": wind_direction_icon,
|
||||||
|
"cloudness_icon": cloudness_icon,
|
||||||
|
"weather_icon_svg": weather_icon_svg,
|
||||||
|
},
|
||||||
|
context_procesor,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def build_weather_response(request: AppRequest, response: WeatherResponse):
|
||||||
|
return templates.TemplateResponse(
|
||||||
|
request=request,
|
||||||
|
name="weather.html",
|
||||||
|
context={"response": response},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
router = APIRouter(prefix="/weather")
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/", response_class=HTMLResponse)
|
||||||
|
async def get_weather_index(request: AppRequest, provider: str | None = None, query: str | None = None):
|
||||||
|
if query and provider:
|
||||||
|
weather_api = api_resolver(WeatherApi)(request, provider)
|
||||||
|
locations = await weather_api.find_locations(query)
|
||||||
|
else:
|
||||||
|
locations = []
|
||||||
|
return templates.TemplateResponse(
|
||||||
|
request=request,
|
||||||
|
name="index.html",
|
||||||
|
context={"locations": locations},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/{provider}/{location}", response_class=RedirectResponse)
|
||||||
|
async def get_weather(location: str):
|
||||||
|
return RedirectResponse(f"{location}/day/today")
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/{provider}/{location}/days/{days}", response_class=HTMLResponse)
|
||||||
|
async def get_weather_days(request: AppRequest, weather_api: WeatherApiDepends, location: str, days: int):
|
||||||
|
response = await weather_api.get_days(location, days)
|
||||||
|
return build_weather_response(request, response)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: tag mode route deprecated, used in tizen app
|
||||||
|
@router.get("/{provider}/{location}/{mode:str}/{date}", response_class=HTMLResponse)
|
||||||
|
async def get_weather_day(
|
||||||
|
request: AppRequest,
|
||||||
|
weather_api: WeatherApiDepends,
|
||||||
|
location: str,
|
||||||
|
date: DateDepends,
|
||||||
|
mode: Literal["day", "tag"], # pylint:disable=unused-argument
|
||||||
|
):
|
||||||
|
response = await weather_api.get_day(location, date)
|
||||||
|
return build_weather_response(request, response)
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}{{_("Weather")}} | {{response.location}} | {{response.date.strftime('%a, %d %B %Y')}}{% endblock %}
|
{% set date = response.date %}
|
||||||
|
|
||||||
|
{% block title %}{{_("Weather")}} | {{response.location}} | {{format_date(response.date, DATE_FORMAT,
|
||||||
|
locale=request.state.language)}}{% endblock %}
|
||||||
|
|
||||||
{% block header %}
|
{% block header %}
|
||||||
<app-link href="/weather"
|
<app-link href="/weather"
|
||||||
@@ -9,18 +12,18 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<h4>
|
<h4>
|
||||||
{% if response.period == 'day' %}
|
{% if response.period == 'day' %}
|
||||||
<a class="icon-link {{'disabled' if response.date == datetime.date.today() else ''}}"
|
<a class="icon-link {{'disabled' if date == datetime.date.today() else ''}}"
|
||||||
href="../tag/{{tag_util.create_tag('day', response.date, -1)}}">
|
href="{{build_url(request, path=['..', date - datetime.timedelta(days=1)])}}">
|
||||||
<i class="bi bi-arrow-left-square"></i>
|
<i class="bi bi-arrow-left-square"></i>
|
||||||
</a>
|
</a>
|
||||||
<a class="icon-link"
|
<a class="icon-link"
|
||||||
href="../tag/days-10">
|
href="{{build_url(request, path=['..', '..', 'days', '10'])}}">
|
||||||
<i class="bi bi-arrow-up-square"></i>
|
<i class="bi bi-arrow-up-square"></i>
|
||||||
</a>
|
</a>
|
||||||
<span class="badge rounded-pill text-bg-secondary fs-6">{{provider}}</span>
|
<span class="badge rounded-pill text-bg-secondary fs-6">{{provider}}</span>
|
||||||
<span>{{response.location}} | {{format_date(response.date, DATE_FORMAT, locale=request.state.language)}}</span>
|
<span>{{response.location}} | {{format_date(response.date, DATE_FORMAT, locale=request.state.language)}}</span>
|
||||||
<a class="icon-link"
|
<a class="icon-link"
|
||||||
href="../tag/{{tag_util.create_tag('day', response.date, 1)}}">
|
href="{{build_url(request, path=['..', date + datetime.timedelta(days=1)])}}">
|
||||||
<i class="bi bi-arrow-right-square"></i>
|
<i class="bi bi-arrow-right-square"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -47,7 +50,7 @@
|
|||||||
{% if response.period == 'days' %}
|
{% if response.period == 'days' %}
|
||||||
<td class="date {{'now' if value.date.date() == datetime.date.today() else ''}}">
|
<td class="date {{'now' if value.date.date() == datetime.date.today() else ''}}">
|
||||||
<span class="value {{'text-danger' if value.date.weekday() in [5,6] else ''}}">
|
<span class="value {{'text-danger' if value.date.weekday() in [5,6] else ''}}">
|
||||||
<a href="../tag/{{tag_util.create_tag('day', value.date.date())}}">
|
<a href="{{build_url(request, path=['..', '..', 'day', value.date.date()])}}">
|
||||||
{{format_date(value.date, 'E d', locale=request.state.language)}}
|
{{format_date(value.date, 'E d', locale=request.state.language)}}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ class RP5WeatherApi(WeatherApi):
|
|||||||
for response in forecast:
|
for response in forecast:
|
||||||
if response.date == date:
|
if response.date == date:
|
||||||
return response
|
return response
|
||||||
|
if date == datetime.date.today():
|
||||||
|
return WeatherResponse(location=location_id, date=date, period="day", values=[])
|
||||||
raise ValueError(f"Unsupported date: {date}")
|
raise ValueError(f"Unsupported date: {date}")
|
||||||
|
|
||||||
async def get_days(self, location_id: str, days: int) -> WeatherResponse:
|
async def get_days(self, location_id: str, days: int) -> WeatherResponse:
|
||||||
|
|||||||
Reference in New Issue
Block a user