feat(rabbits): photo attachments via local volume (#23) #32

Merged
cpressland merged 1 commit from feat/rabbit-photos into main 2026-09-14 12:12:29 +01:00
Collaborator

Closes #23.

Keeping it simple to start, per the issue discussion: local disk storage rather than object storage.

  • Rabbit.photo_filename column + migration
  • app/storage.py: saves uploads under RABBITDB_PHOTOS_DIR (default /data/photos), validates content-type (jpeg/png/webp) and size (<=8MB)
  • /photos static mount serves the photos directory
  • Staff-authenticated POST/DELETE /rabbits/{id}/photo
  • Photo (or placeholder) shown on: rabbit detail, list rows (thumbnail), family tree nodes, and the public adoption form
  • Old file is deleted when a photo is replaced/removed
  • photo_url added to /api/v1/rabbits responses

Companion homelab PR mounts a volume at /opt/podman/rabbitdb:/data/photos and switches the container to run as 1000:1000 (it was running as root before): see cpressland/homelab.

Open questions from the issue (single photo vs gallery, size/format constraints) — went with single photo + jpeg/png/webp up to 8MB as the simple starting point; easy to extend later.

Closes #23. Keeping it simple to start, per the issue discussion: local disk storage rather than object storage. - `Rabbit.photo_filename` column + migration - `app/storage.py`: saves uploads under `RABBITDB_PHOTOS_DIR` (default `/data/photos`), validates content-type (jpeg/png/webp) and size (<=8MB) - `/photos` static mount serves the photos directory - Staff-authenticated `POST`/`DELETE /rabbits/{id}/photo` - Photo (or placeholder) shown on: rabbit detail, list rows (thumbnail), family tree nodes, and the public adoption form - Old file is deleted when a photo is replaced/removed - `photo_url` added to `/api/v1/rabbits` responses Companion homelab PR mounts a volume at `/opt/podman/rabbitdb:/data/photos` and switches the container to run as 1000:1000 (it was running as root before): see cpressland/homelab. Open questions from the issue (single photo vs gallery, size/format constraints) — went with single photo + jpeg/png/webp up to 8MB as the simple starting point; easy to extend later.
feat(rabbits): photo attachments via local volume (#23)
All checks were successful
ci / uv-buildah-build-push (push) Successful in 21s
ci / build (push) Successful in 0s
c900cbd1dd
- Add Rabbit.photo_filename column (nullable, migration in main.py)
- New app/storage.py: local-disk photo storage under RABBITDB_PHOTOS_DIR
  (defaults to /data/photos), validates content-type (jpeg/png/webp) and
  size (<=8MB), random filename per upload
- Mount /photos as a static route serving RABBITDB_PHOTOS_DIR
- Staff-authenticated upload/replace/remove endpoints:
  POST/DELETE /rabbits/{id}/photo, returning the rabbits/_photo.html partial
- Show photo (or placeholder) on rabbit detail page, list rows (thumbnail),
  family tree nodes, and the public adoption form
- Old file is deleted from disk when a photo is replaced or removed
- Expose photo_url on the read-only /api/v1/rabbits endpoints

Local volume storage only for now, per issue discussion; object storage can
be swapped in later behind the same storage.py functions.
cpressland deleted branch feat/rabbit-photos 2026-09-14 12:12:29 +01:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
cpressland/rabbitdb!32
No description provided.