rename project to fhdhview
This commit is contained in:
1 parent
c4d3b6b292
commit
6755875938
51 files changed
+39
-39
No files matched your search
Whitespace-only changes.
@@ -0,0 +1,55 @@
|
||||
# SPDX-FileCopyrightText: 2026 Filmhuis Den Haag
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status
|
||||
from fastapi.responses import FileResponse, JSONResponse
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
|
||||
from fhdhview.api.deps import check_auth, get_session
|
||||
from fhdhview.services.screenwriter.importer import import_sessions
|
||||
from fhdhview.services.screenwriter.parser import XmlParseError, parse_screenwriter_xml
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/admin",
|
||||
tags=["Admin"],
|
||||
dependencies=[Depends(check_auth)]
|
||||
)
|
||||
|
||||
@router.get("", response_class=FileResponse)
|
||||
async def upload_form():
|
||||
return FileResponse(BASE_DIR / "html" / "upload.html")
|
||||
|
||||
|
||||
@router.post("/upload", response_class=JSONResponse)
|
||||
async def upload_file(
|
||||
file: UploadFile = File(...),
|
||||
session: AsyncSession = Depends(get_session)
|
||||
):
|
||||
if not file.filename or not file.filename.lower().endswith(".xml"):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
|
||||
detail="File must be an XML file"
|
||||
)
|
||||
|
||||
contents = await file.read()
|
||||
if len(contents) > 10 * 1024 * 1024:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE,
|
||||
detail="File too large"
|
||||
)
|
||||
|
||||
try:
|
||||
aampos = parse_screenwriter_xml(contents)
|
||||
except XmlParseError as e:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
|
||||
detail=str(e)
|
||||
)
|
||||
|
||||
await import_sessions(aampos, session=session)
|
||||
|
||||
return JSONResponse(content={"filename": file.filename, "size": len(contents)})
|
||||
@@ -0,0 +1,28 @@
|
||||
# SPDX-FileCopyrightText: 2026 Filmhuis Den Haag
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import secrets
|
||||
from collections.abc import AsyncGenerator
|
||||
|
||||
from fastapi import Depends, HTTPException, status
|
||||
from fastapi.security import HTTPBasic, HTTPBasicCredentials
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
|
||||
from fhdhview.core.config import settings
|
||||
from fhdhview.core.database import async_session
|
||||
|
||||
security = HTTPBasic()
|
||||
|
||||
|
||||
async def get_session() -> AsyncGenerator[AsyncSession]:
|
||||
async with async_session() as session:
|
||||
yield session
|
||||
|
||||
|
||||
def check_auth(credentials: HTTPBasicCredentials = Depends(security)):
|
||||
if not secrets.compare_digest(credentials.password.encode(), settings.api_password.encode()):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Invalid credentials",
|
||||
headers={"WWW-Authenticate": "Basic"},
|
||||
)
|
||||
@@ -0,0 +1,36 @@
|
||||
# SPDX-FileCopyrightText: 2026 Filmhuis Den Haag
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
from fastapi import APIRouter, status
|
||||
from pydantic import BaseModel
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/health",
|
||||
tags=["Health"]
|
||||
)
|
||||
|
||||
|
||||
class HealthCheck(BaseModel):
|
||||
"""Response model to validate and return when performing a health check."""
|
||||
|
||||
status: str = "OK"
|
||||
|
||||
|
||||
@router.get(
|
||||
"/",
|
||||
summary="Perform a Health Check",
|
||||
response_description="Return HTTP Status Code 200 (OK)",
|
||||
status_code=status.HTTP_200_OK,
|
||||
response_model=HealthCheck,
|
||||
)
|
||||
def get_health() -> HealthCheck:
|
||||
"""
|
||||
## Perform a Health Check
|
||||
Endpoint to perform a healthcheck on. This endpoint can primarily be used Docker
|
||||
to ensure a robust container orchestration and management is in place. Other
|
||||
services which rely on proper functioning of the API service will not deploy if this
|
||||
endpoint returns any other HTTP status code except 200 (OK).
|
||||
Returns:
|
||||
HealthCheck: Returns a JSON response with the health status
|
||||
"""
|
||||
return HealthCheck(status="OK")
|
||||
@@ -0,0 +1,19 @@
|
||||
# SPDX-FileCopyrightText: 2026 Filmhuis Den Haag
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import APIRouter
|
||||
from fastapi.responses import FileResponse
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/info",
|
||||
tags=["Info"]
|
||||
)
|
||||
|
||||
|
||||
@router.get("", response_class=FileResponse)
|
||||
async def get_info():
|
||||
return FileResponse(BASE_DIR / "html" / "info.html")
|
||||
@@ -0,0 +1,47 @@
|
||||
# SPDX-FileCopyrightText: 2026 Filmhuis Den Haag
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlmodel import col, select
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
|
||||
from fhdhview.api.deps import get_session
|
||||
from fhdhview.core.config import settings
|
||||
from fhdhview.models.screening import Screening
|
||||
from fhdhview.schemas.screening import ScreeningRead
|
||||
|
||||
router = APIRouter(prefix="/screenings", tags=["Screenings"])
|
||||
|
||||
|
||||
@router.get(
|
||||
"",
|
||||
response_model=list[ScreeningRead],
|
||||
summary="Get upcoming screenings for the infodesk"
|
||||
)
|
||||
async def get_infodesk_screenings(
|
||||
session: AsyncSession = Depends(get_session)
|
||||
) -> list[ScreeningRead]:
|
||||
now = datetime.now(tz=ZoneInfo(settings.timezone))
|
||||
today = now.date()
|
||||
|
||||
query = (
|
||||
select(Screening)
|
||||
.where(Screening.start > now - timedelta(minutes=10))
|
||||
.where(Screening.start < today + timedelta(days=1))
|
||||
.order_by(col(Screening.start))
|
||||
.limit(8)
|
||||
)
|
||||
screenings = await session.exec(query)
|
||||
return [ScreeningRead.model_validate(s) for s in screenings.all()]
|
||||
|
||||
|
||||
@router.get(
|
||||
"/prices",
|
||||
response_model=dict,
|
||||
summary="Get pricing information"
|
||||
)
|
||||
async def get_screening_prices() -> dict:
|
||||
return settings.prices
|
||||
Reference in new issue
Block a user