feat: full backend (untested)
This commit is contained in:
127
backend/src/app/main.py
Normal file
127
backend/src/app/main.py
Normal file
@@ -0,0 +1,127 @@
|
||||
import logging
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import Depends, FastAPI, HTTPException
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.availability_service import calculate_availability
|
||||
from app.database import get_db
|
||||
from app.ics_service import sync_all_calendars, sync_participant_calendar
|
||||
from app.models import Participant
|
||||
from app.schemas import (
|
||||
AvailabilityRequest,
|
||||
AvailabilityResponse,
|
||||
ParticipantCreate,
|
||||
ParticipantResponse,
|
||||
SyncResponse,
|
||||
)
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
app = FastAPI(title="Common Availability API")
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
async def health_check():
|
||||
return {"status": "healthy"}
|
||||
|
||||
|
||||
@app.post("/api/participants", response_model=ParticipantResponse)
|
||||
async def create_participant(
|
||||
data: ParticipantCreate, db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
existing = await db.execute(
|
||||
select(Participant).where(Participant.email == data.email)
|
||||
)
|
||||
if existing.scalar_one_or_none():
|
||||
raise HTTPException(status_code=400, detail="Email already registered")
|
||||
|
||||
participant = Participant(
|
||||
name=data.name,
|
||||
email=data.email,
|
||||
ics_url=data.ics_url,
|
||||
)
|
||||
db.add(participant)
|
||||
await db.commit()
|
||||
await db.refresh(participant)
|
||||
|
||||
try:
|
||||
await sync_participant_calendar(db, participant)
|
||||
except Exception as e:
|
||||
logger.warning(f"Initial sync failed for {participant.email}: {e}")
|
||||
|
||||
return participant
|
||||
|
||||
|
||||
@app.get("/api/participants", response_model=list[ParticipantResponse])
|
||||
async def list_participants(db: AsyncSession = Depends(get_db)):
|
||||
result = await db.execute(select(Participant))
|
||||
return result.scalars().all()
|
||||
|
||||
|
||||
@app.get("/api/participants/{participant_id}", response_model=ParticipantResponse)
|
||||
async def get_participant(participant_id: UUID, db: AsyncSession = Depends(get_db)):
|
||||
result = await db.execute(
|
||||
select(Participant).where(Participant.id == participant_id)
|
||||
)
|
||||
participant = result.scalar_one_or_none()
|
||||
if not participant:
|
||||
raise HTTPException(status_code=404, detail="Participant not found")
|
||||
return participant
|
||||
|
||||
|
||||
@app.delete("/api/participants/{participant_id}")
|
||||
async def delete_participant(participant_id: UUID, db: AsyncSession = Depends(get_db)):
|
||||
result = await db.execute(
|
||||
select(Participant).where(Participant.id == participant_id)
|
||||
)
|
||||
participant = result.scalar_one_or_none()
|
||||
if not participant:
|
||||
raise HTTPException(status_code=404, detail="Participant not found")
|
||||
|
||||
await db.delete(participant)
|
||||
await db.commit()
|
||||
return {"status": "deleted"}
|
||||
|
||||
|
||||
@app.post("/api/availability", response_model=AvailabilityResponse)
|
||||
async def get_availability(
|
||||
request: AvailabilityRequest, db: AsyncSession = Depends(get_db)
|
||||
):
|
||||
slots = await calculate_availability(db, request.participant_ids)
|
||||
return {"slots": slots}
|
||||
|
||||
|
||||
@app.post("/api/sync", response_model=SyncResponse)
|
||||
async def sync_calendars(db: AsyncSession = Depends(get_db)):
|
||||
result = await db.execute(select(Participant))
|
||||
participants = result.scalars().all()
|
||||
results = await sync_all_calendars(db, list(participants))
|
||||
return {"results": results}
|
||||
|
||||
|
||||
@app.post("/api/sync/{participant_id}")
|
||||
async def sync_participant(participant_id: UUID, db: AsyncSession = Depends(get_db)):
|
||||
result = await db.execute(
|
||||
select(Participant).where(Participant.id == participant_id)
|
||||
)
|
||||
participant = result.scalar_one_or_none()
|
||||
if not participant:
|
||||
raise HTTPException(status_code=404, detail="Participant not found")
|
||||
|
||||
try:
|
||||
count = await sync_participant_calendar(db, participant)
|
||||
return {"status": "success", "blocks_synced": count}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
Reference in New Issue
Block a user