c6d9a3b8b6
- Auth via Authelia OIDC (public client + PKCE) with signed session cookies - SQLite DB for users, rides, and insights (SQLAlchemy) - Garage S3 for GPX file storage (boto3) - All API endpoints scoped to authenticated user - Dockerfile + docker-compose.yml with Garage service - Frontend auth check: redirects to /auth/login on 401, shows user badge Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
37 lines
1.1 KiB
Python
37 lines
1.1 KiB
Python
import os
|
|
|
|
import boto3
|
|
from botocore.config import Config
|
|
|
|
S3_ENDPOINT = os.getenv("S3_ENDPOINT")
|
|
S3_BUCKET = os.getenv("S3_BUCKET", "bikeslop-gpx")
|
|
S3_ACCESS_KEY = os.getenv("S3_ACCESS_KEY")
|
|
S3_SECRET_KEY = os.getenv("S3_SECRET_KEY")
|
|
|
|
|
|
def get_s3_client():
|
|
if not S3_ENDPOINT or not S3_ACCESS_KEY or not S3_SECRET_KEY:
|
|
raise RuntimeError(
|
|
"S3 not configured — set S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY"
|
|
)
|
|
return boto3.client(
|
|
"s3",
|
|
endpoint_url=S3_ENDPOINT,
|
|
aws_access_key_id=S3_ACCESS_KEY,
|
|
aws_secret_access_key=S3_SECRET_KEY,
|
|
config=Config(signature_version="s3v4"),
|
|
)
|
|
|
|
|
|
def upload_gpx(user_id: str, filename: str, data: bytes) -> str:
|
|
s3_key = f"users/{user_id}/{filename}"
|
|
client = get_s3_client()
|
|
client.put_object(Bucket=S3_BUCKET, Key=s3_key, Body=data, ContentType="application/gpx+xml")
|
|
return s3_key
|
|
|
|
|
|
def download_gpx(s3_key: str) -> bytes:
|
|
client = get_s3_client()
|
|
response = client.get_object(Bucket=S3_BUCKET, Key=s3_key)
|
|
return response["Body"].read()
|