refactor(easel): add weather routes
This commit is contained in:
@@ -4,18 +4,20 @@ from fastapi import FastAPI
|
|||||||
|
|
||||||
from gallery.sketch.weather.api import WeatherApi
|
from gallery.sketch.weather.api import WeatherApi
|
||||||
|
|
||||||
from .route import api, doc, view
|
from .route import doc
|
||||||
|
from .route.api import weather as weather_api_route
|
||||||
|
from .route.view import weather as weather_view_route
|
||||||
|
|
||||||
|
|
||||||
def build_app(weather_api: WeatherApi) -> FastAPI:
|
def build_app(weather_api: WeatherApi) -> FastAPI:
|
||||||
locale.setlocale(locale.LC_TIME, "ru_RU.UTF-8")
|
locale.setlocale(locale.LC_TIME, "ru_RU.UTF-8")
|
||||||
app = FastAPI(
|
app = FastAPI(
|
||||||
title="Weather",
|
title="Gallery",
|
||||||
docs_url=None,
|
docs_url=None,
|
||||||
redoc_url=None,
|
redoc_url=None,
|
||||||
)
|
)
|
||||||
app.state.weather_api = weather_api
|
app.state.weather_api = weather_api
|
||||||
doc.mount(app)
|
doc.mount(app)
|
||||||
api.mount(app)
|
weather_api_route.mount(app)
|
||||||
view.mount(app)
|
weather_view_route.mount(app)
|
||||||
return app
|
return app
|
||||||
|
|||||||
@@ -7,6 +7,11 @@ from gallery.sketch.weather.model import WeatherResponse
|
|||||||
|
|
||||||
|
|
||||||
def mount(app: FastAPI):
|
def mount(app: FastAPI):
|
||||||
|
@app.get("/api/weather/locations")
|
||||||
|
async def get_api_weather_locations(request: Request) -> list[str]:
|
||||||
|
weather_api: WeatherApi = request.app.state.weather_api
|
||||||
|
return await weather_api.get_locations()
|
||||||
|
|
||||||
@app.get("/api/weather/{location}/day/{date}")
|
@app.get("/api/weather/{location}/day/{date}")
|
||||||
async def get_api_weather_day(
|
async def get_api_weather_day(
|
||||||
request: Request, location: str, date: datetime.date
|
request: Request, location: str, date: datetime.date
|
||||||
@@ -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)
|
|
||||||
|
|||||||
85
gallery/easel/route/view/weather/__init__.py
Normal file
85
gallery/easel/route/view/weather/__init__.py
Normal 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)
|
||||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
0
gallery/easel/route/view/weather/static/index.js
Normal file
0
gallery/easel/route/view/weather/static/index.js
Normal file
@@ -9,9 +9,9 @@
|
|||||||
content="ie=edge">
|
content="ie=edge">
|
||||||
<title>Погода</title>
|
<title>Погода</title>
|
||||||
<link rel="stylesheet"
|
<link rel="stylesheet"
|
||||||
href="/static/style.css?v=1">
|
href="/weather/static/style.css?v=1">
|
||||||
<link rel="icon"
|
<link rel="icon"
|
||||||
href="/static/favicon.ico"
|
href="/weather/static/favicon.ico"
|
||||||
type="image/x-icon">
|
type="image/x-icon">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@@ -9,9 +9,9 @@
|
|||||||
content="ie=edge">
|
content="ie=edge">
|
||||||
<title>Погода | {{response.location}} | {{response.date.strftime('%a, %d %B %Y')}}</title>
|
<title>Погода | {{response.location}} | {{response.date.strftime('%a, %d %B %Y')}}</title>
|
||||||
<link rel="stylesheet"
|
<link rel="stylesheet"
|
||||||
href="/static/style.css?v=1">
|
href="/weather/static/style.css?v=1">
|
||||||
<link rel="icon"
|
<link rel="icon"
|
||||||
href="/static/favicon.ico"
|
href="/weather/static/favicon.ico"
|
||||||
type="image/x-icon">
|
type="image/x-icon">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import json
|
import json
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
class MockData:
|
class MockData:
|
||||||
@@ -11,5 +10,5 @@ class MockData:
|
|||||||
return (self._data_dir / f"{key}.html").read_text()
|
return (self._data_dir / f"{key}.html").read_text()
|
||||||
|
|
||||||
def get_json(self, key: str) -> dict:
|
def get_json(self, key: str) -> dict:
|
||||||
data = json.loads((Path(__file__).parent / f"data/{key}.json").read_text())
|
data = json.loads((self._data_dir / f"{key}.json").read_text())
|
||||||
return data
|
return data
|
||||||
|
|||||||
Reference in New Issue
Block a user