summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app.py41
1 files changed, 31 insertions, 10 deletions
diff --git a/app.py b/app.py
index 2cfc8e8..925ec27 100644
--- a/app.py
+++ b/app.py
@@ -6,6 +6,7 @@ import secrets
import random
from enum import Enum
from dataclasses import dataclass
+import io
import datetime
from contextlib import asynccontextmanager
from typing import Any
@@ -22,14 +23,19 @@ from litestar.contrib.jinja import JinjaTemplateEngine
from litestar.exceptions import HTTPException
from litestar.template.config import TemplateConfig
from litestar.response import Template, Redirect
+from litestar.response.file import ASGIFileResponse
+from litestar.response.streaming import ASGIStreamingResponse
from litestar.static_files import create_static_files_router
from litestar.enums import RequestEncodingType
from litestar.params import Body
from litestar import Request
from litestar.datastructures import State
-# automake calendar invite ics
+import ics
+
+# TODO admin remove attendees
# use url_fors, timezones?
+# error handling, auth errors, sql errors, input validation
class Base(DeclarativeBase):
pass
@@ -57,6 +63,16 @@ class Event(Base):
def get_invites(self):
return json.loads(self.invites)
+ def to_ics(self):
+ c = ics.Calendar()
+ e = ics.Event()
+ e.name = self.title
+ e.begin = self.time
+ e.location = self.location
+ e.description = self.description
+ c.events.add(e)
+ return c
+
@asynccontextmanager
async def db_connection(app: Litestar) -> AsyncGenerator[None, None]:
engine = getattr(app.state, "engine", None)
@@ -85,14 +101,6 @@ parts = [
def gen_iden():
return "-".join(random.choices(parts, k=8))
-iden = 'Weave-Stream-Limber-Exalted-Sluice-Reaper-Myrtle-Incite'
-
-title = 'Hot Pot at the Cafe Cyfrae Violae'
-when = datetime.datetime.fromisoformat("2024-04-07T13:00:00")
-where = '133 E 4th St, Apt 6, New York NY 10003'
-what = "Hot pot, Anxi oolong, baijiu, Hua Zhou."
-EVENTS = {}
-
@get("/")
async def index() -> Template:
return Template(template_name="index.html")
@@ -112,6 +120,19 @@ async def event(state: State, iden: str, password: str = "") -> Template:
context = dict(event=event, manage=manage)
return Template(template_name="event.html", context=context)
+@get("/calendar/{iden:str}")
+async def calendar(state: State, iden: str) -> ASGIStreamingResponse:
+ async with sessionmaker(bind=state.engine) as session:
+ async with session.begin():
+ query = select(Event).where(Event.iden == iden)
+ result = await session.execute(query)
+ event = result.scalar_one()
+ ics = event.to_ics()
+ f = io.StringIO(ics.serialize())
+ return ASGIStreamingResponse(iterator=f, media_type='application/octet-stream', headers={
+ 'Content-Disposition': 'inline; filename=event.ics',
+ })
+
@dataclass
class EditRequest:
title: str
@@ -164,7 +185,6 @@ async def join(state: State, request: Request, iden: str, data: Annotated[JoinRe
result = await session.execute(query)
event = result.scalar_one()
name = data.name
- # TODO if name exists reject
invites = json.loads(event.invites)
invites.append(name)
event.invites = json.dumps(invites)
@@ -177,6 +197,7 @@ app = Litestar(
route_handlers=[
index,
event,
+ calendar,
create,
edit,
join,