feat: add calendar subscription token functionality and ICS generation
- Introduced a new database model for calendar subscription tokens, allowing users to generate unique tokens for accessing their personal calendar. - Implemented API endpoint to return ICS files containing only the subscribing user's duties, enhancing user experience with personalized calendar access. - Added utility functions for generating ICS files from user duties, ensuring proper formatting and timezone handling. - Updated command handlers to support the new calendar link feature, providing users with easy access to their personal calendar subscriptions. - Included unit tests for the new functionality, ensuring reliability and correctness of token generation and ICS file creation.
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
"""FastAPI app: /api/duties and static webapp."""
|
||||
|
||||
import logging
|
||||
from datetime import date, timedelta
|
||||
|
||||
import duty_teller.config as config
|
||||
from fastapi import Depends, FastAPI, Request
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import Response
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
@@ -15,6 +17,8 @@ from duty_teller.api.dependencies import (
|
||||
get_validated_dates,
|
||||
require_miniapp_username,
|
||||
)
|
||||
from duty_teller.api.personal_calendar_ics import build_personal_ics
|
||||
from duty_teller.db.repository import get_duties_for_user, get_user_by_calendar_token
|
||||
from duty_teller.db.schemas import CalendarEvent, DutyWithUser
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -57,6 +61,31 @@ def list_calendar_events(
|
||||
return [CalendarEvent(date=e["date"], summary=e["summary"]) for e in events]
|
||||
|
||||
|
||||
@app.get("/api/calendar/ical/{token}.ics")
|
||||
def get_personal_calendar_ical(
|
||||
token: str,
|
||||
session: Session = Depends(get_db_session),
|
||||
) -> Response:
|
||||
"""
|
||||
Return ICS calendar with only the subscribing user's duties.
|
||||
No Telegram auth; access is by secret token in the URL.
|
||||
"""
|
||||
user = get_user_by_calendar_token(session, token)
|
||||
if user is None:
|
||||
return Response(status_code=404, content="Not found")
|
||||
today = date.today()
|
||||
from_date = (today - timedelta(days=365)).strftime("%Y-%m-%d")
|
||||
to_date = (today + timedelta(days=365 * 2)).strftime("%Y-%m-%d")
|
||||
duties_with_name = get_duties_for_user(
|
||||
session, user.id, from_date=from_date, to_date=to_date
|
||||
)
|
||||
ics_bytes = build_personal_ics(duties_with_name)
|
||||
return Response(
|
||||
content=ics_bytes,
|
||||
media_type="text/calendar; charset=utf-8",
|
||||
)
|
||||
|
||||
|
||||
webapp_path = config.PROJECT_ROOT / "webapp"
|
||||
if webapp_path.is_dir():
|
||||
app.mount("/app", StaticFiles(directory=str(webapp_path), html=True), name="webapp")
|
||||
|
||||
Reference in New Issue
Block a user