Restructure project
This commit is contained in:
parent
8209049486
commit
4af54f3287
@ -18,4 +18,4 @@ COPY main.py /app/
|
|||||||
COPY static/ /app/static/
|
COPY static/ /app/static/
|
||||||
COPY templates/ /app/templates/
|
COPY templates/ /app/templates/
|
||||||
|
|
||||||
ENTRYPOINT ["poetry", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "5000", "--use-colors"]
|
ENTRYPOINT ["poetry", "run", "uvicorn", "fabcal.app:app", "--host", "0.0.0.0", "--port", "5000", "--use-colors"]
|
||||||
|
0
fabcal/__init__.py
Normal file
0
fabcal/__init__.py
Normal file
33
fabcal/app.py
Normal file
33
fabcal/app.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import locale
|
||||||
|
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
from fastapi.staticfiles import StaticFiles
|
||||||
|
from fastapi_cache import FastAPICache
|
||||||
|
from fastapi_cache.backends.inmemory import InMemoryBackend
|
||||||
|
|
||||||
|
from fabcal.routers import api_v1, frontend
|
||||||
|
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
app.mount("/static", StaticFiles(directory="static"), name="static")
|
||||||
|
|
||||||
|
app.include_router(api_v1.router, prefix="/api/v1")
|
||||||
|
app.include_router(frontend.router, prefix="")
|
||||||
|
|
||||||
|
app.add_middleware(
|
||||||
|
CORSMiddleware,
|
||||||
|
allow_origins=[
|
||||||
|
"https://fablab-altmuehlfranken.de",
|
||||||
|
"https://www.fablab-altmuehlfranken.de",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
locale.setlocale(locale.LC_TIME, locale.getlocale())
|
||||||
|
|
||||||
|
|
||||||
|
@app.on_event("startup")
|
||||||
|
async def startup():
|
||||||
|
FastAPICache.init(InMemoryBackend())
|
@ -1,53 +1,16 @@
|
|||||||
import base64
|
|
||||||
import locale
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from datetime import date, datetime, timedelta, timezone
|
from datetime import date, datetime, timedelta, timezone
|
||||||
from typing import List, NamedTuple
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import babel.dates
|
|
||||||
import recurring_ical_events
|
import recurring_ical_events
|
||||||
|
|
||||||
from fastapi import FastAPI
|
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
|
||||||
from fastapi.requests import Request
|
|
||||||
from fastapi.responses import Response
|
|
||||||
from fastapi.staticfiles import StaticFiles
|
|
||||||
from fastapi.templating import Jinja2Templates
|
|
||||||
from fastapi_cache import FastAPICache
|
|
||||||
from fastapi_cache.backends.inmemory import InMemoryBackend
|
|
||||||
from fastapi_cache.decorator import cache
|
from fastapi_cache.decorator import cache
|
||||||
from icalendar import Calendar, vText
|
from icalendar import Calendar, vText
|
||||||
|
|
||||||
|
from fabcal.models import CalendarEvent
|
||||||
app = FastAPI()
|
|
||||||
|
|
||||||
app.mount("/static", StaticFiles(directory="static"), name="static")
|
|
||||||
|
|
||||||
templates = Jinja2Templates(directory="templates")
|
|
||||||
|
|
||||||
app.add_middleware(
|
|
||||||
CORSMiddleware,
|
|
||||||
allow_origins=[
|
|
||||||
"https://fablab-altmuehlfranken.de",
|
|
||||||
"https://www.fablab-altmuehlfranken.de",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
locale.setlocale(locale.LC_TIME, locale.getlocale())
|
|
||||||
|
|
||||||
|
|
||||||
def get_calendar_url():
|
|
||||||
url = os.environ["CALENDAR_URL"]
|
|
||||||
|
|
||||||
# convenience feature
|
|
||||||
url = url.replace("webcal://", "https://")
|
|
||||||
|
|
||||||
return url
|
|
||||||
|
|
||||||
|
|
||||||
def sanitize(data: str):
|
def sanitize(data: str):
|
||||||
@ -60,6 +23,15 @@ def sanitize(data: str):
|
|||||||
return cal.to_ical()
|
return cal.to_ical()
|
||||||
|
|
||||||
|
|
||||||
|
def get_calendar_url():
|
||||||
|
url = os.environ["CALENDAR_URL"]
|
||||||
|
|
||||||
|
# convenience feature
|
||||||
|
url = url.replace("webcal://", "https://")
|
||||||
|
|
||||||
|
return url
|
||||||
|
|
||||||
|
|
||||||
# caching strings works better than caching calendar objects
|
# caching strings works better than caching calendar objects
|
||||||
@cache(expire=120)
|
@cache(expire=120)
|
||||||
async def get_data() -> str:
|
async def get_data() -> str:
|
||||||
@ -71,18 +43,6 @@ async def get_data() -> str:
|
|||||||
return sanitize(await response.text())
|
return sanitize(await response.text())
|
||||||
|
|
||||||
|
|
||||||
class CalendarEvent(NamedTuple):
|
|
||||||
start: datetime
|
|
||||||
end: datetime
|
|
||||||
# just a convenience thing, we want to keep start/date as datetime and save the client from guessing this themselves
|
|
||||||
all_day_event: bool
|
|
||||||
summary: str
|
|
||||||
description: str
|
|
||||||
location: str
|
|
||||||
color: str
|
|
||||||
uid: str
|
|
||||||
|
|
||||||
|
|
||||||
def get_tzinfo():
|
def get_tzinfo():
|
||||||
return timezone(timedelta(hours=1))
|
return timezone(timedelta(hours=1))
|
||||||
|
|
||||||
@ -163,16 +123,6 @@ async def get_future_events():
|
|||||||
return future_events
|
return future_events
|
||||||
|
|
||||||
|
|
||||||
@app.get("/events.ics")
|
|
||||||
async def ics():
|
|
||||||
return Response(
|
|
||||||
await get_data(),
|
|
||||||
headers={
|
|
||||||
"content-type": "text/calendar",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def group_by_date(events: List[CalendarEvent]):
|
def group_by_date(events: List[CalendarEvent]):
|
||||||
grouped_events: OrderedDict[date, List[CalendarEvent]] = OrderedDict()
|
grouped_events: OrderedDict[date, List[CalendarEvent]] = OrderedDict()
|
||||||
|
|
||||||
@ -185,41 +135,3 @@ def group_by_date(events: List[CalendarEvent]):
|
|||||||
grouped_events[start_date].append(event)
|
grouped_events[start_date].append(event)
|
||||||
|
|
||||||
return grouped_events
|
return grouped_events
|
||||||
|
|
||||||
|
|
||||||
@app.get("/embed-sidebar.html")
|
|
||||||
async def embed(request: Request, max_width: str = None):
|
|
||||||
# await asyncio.sleep(1)
|
|
||||||
|
|
||||||
events = await get_future_events()
|
|
||||||
|
|
||||||
grouped_events = list(group_by_date(events).items())
|
|
||||||
|
|
||||||
# couple of helpers
|
|
||||||
def localized_abbreviated_month(dt: datetime):
|
|
||||||
return babel.dates.format_datetime(dt, format="%b", locale="de_DE")
|
|
||||||
|
|
||||||
# couple of helpers
|
|
||||||
def localized_abbreviated_weekday(dt: datetime):
|
|
||||||
return babel.dates.format_datetime(dt, format="%b", locale="de_DE")
|
|
||||||
|
|
||||||
def base64_encode(s: str):
|
|
||||||
return base64.b64encode(s.encode()).decode()
|
|
||||||
|
|
||||||
return templates.TemplateResponse(
|
|
||||||
"embed-sidebar.html",
|
|
||||||
context={
|
|
||||||
"request": request,
|
|
||||||
"grouped_events": grouped_events,
|
|
||||||
"dir": dir,
|
|
||||||
"localized_abbreviated_month": localized_abbreviated_month,
|
|
||||||
"localized_abbreviated_weekday": localized_abbreviated_weekday,
|
|
||||||
"base64_encode": base64_encode,
|
|
||||||
"max_width": max_width,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@app.on_event("startup")
|
|
||||||
async def startup():
|
|
||||||
FastAPICache.init(InMemoryBackend())
|
|
14
fabcal/models.py
Normal file
14
fabcal/models.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from typing import NamedTuple
|
||||||
|
|
||||||
|
|
||||||
|
class CalendarEvent(NamedTuple):
|
||||||
|
start: datetime
|
||||||
|
end: datetime
|
||||||
|
# just a convenience thing, we want to keep start/date as datetime and save the client from guessing this themselves
|
||||||
|
all_day_event: bool
|
||||||
|
summary: str
|
||||||
|
description: str
|
||||||
|
location: str
|
||||||
|
color: str
|
||||||
|
uid: str
|
4
fabcal/routers/__init__.py
Normal file
4
fabcal/routers/__init__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
from starlette.templating import Jinja2Templates
|
||||||
|
|
||||||
|
|
||||||
|
templates = Jinja2Templates(directory="templates")
|
17
fabcal/routers/api_v1.py
Normal file
17
fabcal/routers/api_v1.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
from fastapi import APIRouter
|
||||||
|
from starlette.responses import Response
|
||||||
|
|
||||||
|
from fabcal.calendar_client import get_data
|
||||||
|
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/events.ics")
|
||||||
|
async def events():
|
||||||
|
return Response(
|
||||||
|
await get_data(),
|
||||||
|
headers={
|
||||||
|
"content-type": "text/calendar",
|
||||||
|
},
|
||||||
|
)
|
45
fabcal/routers/frontend.py
Normal file
45
fabcal/routers/frontend.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import base64
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
import babel.dates
|
||||||
|
|
||||||
|
from fastapi import APIRouter
|
||||||
|
from fastapi.requests import Request
|
||||||
|
from fastapi.responses import HTMLResponse
|
||||||
|
|
||||||
|
from fabcal.calendar_client import get_future_events, group_by_date
|
||||||
|
from fabcal.routers import templates
|
||||||
|
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/embed-sidebar.html", response_class=HTMLResponse)
|
||||||
|
async def embed(request: Request, max_width: str = None):
|
||||||
|
events = await get_future_events()
|
||||||
|
|
||||||
|
grouped_events = list(group_by_date(events).items())
|
||||||
|
|
||||||
|
# couple of helpers
|
||||||
|
def localized_abbreviated_month(dt: datetime):
|
||||||
|
return babel.dates.format_datetime(dt, format="%b", locale="de_DE")
|
||||||
|
|
||||||
|
# couple of helpers
|
||||||
|
def localized_abbreviated_weekday(dt: datetime):
|
||||||
|
return babel.dates.format_datetime(dt, format="%b", locale="de_DE")
|
||||||
|
|
||||||
|
def base64_encode(s: str):
|
||||||
|
return base64.b64encode(s.encode()).decode()
|
||||||
|
|
||||||
|
return templates.TemplateResponse(
|
||||||
|
"embed-sidebar.html",
|
||||||
|
context={
|
||||||
|
"request": request,
|
||||||
|
"grouped_events": grouped_events,
|
||||||
|
"dir": dir,
|
||||||
|
"localized_abbreviated_month": localized_abbreviated_month,
|
||||||
|
"localized_abbreviated_weekday": localized_abbreviated_weekday,
|
||||||
|
"base64_encode": base64_encode,
|
||||||
|
},
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user