Skip to content

Add contact photo field to API - #3

Open
patrickboxfordpartners wants to merge 1 commit into
David-Parry:trunkfrom
patrickboxfordpartners:feat/contact-photo
Open

Add contact photo field to API#3
patrickboxfordpartners wants to merge 1 commit into
David-Parry:trunkfrom
patrickboxfordpartners:feat/contact-photo

Conversation

@patrickboxfordpartners

Copy link
Copy Markdown
  • Add photo field to Contact model as Text (stores base64 image data)
  • Add photo field to all contact schemas (ContactBase, ContactUpdate)
  • Update example data to include photo field
  • Allows users to upload and store profile pictures with contacts

- Add photo field to Contact model as Text (stores base64 image data)
- Add photo field to all contact schemas (ContactBase, ContactUpdate)
- Update example data to include photo field
- Allows users to upload and store profile pictures with contacts
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Add contact photos to persistence and API schemas

✨ Enhancement 🕐 Less than 10 minutes

Grey Divider

AI Description

• Persist optional base64 contact photos in a text-backed model field.
• Expose photos across create, replace, patch, read schemas and API examples.
Diagram

graph TD
  Client["API Client"] --> Schemas["Contact Schemas"] --> Model["Contact Model"] --> Database[("Contacts Database")]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Object storage with URL reference
  • ➕ Avoids base64 expansion in API and database payloads
  • ➕ Scales better for image delivery and caching
  • ➕ Keeps contact records small
  • ➖ Requires storage infrastructure and lifecycle management
  • ➖ Adds upload authorization and failure-handling complexity
2. Database binary column
  • ➕ Avoids base64 expansion at rest
  • ➕ Keeps photo ownership within the contact database
  • ➖ Still enlarges database records and backups
  • ➖ Requires binary upload and response handling

Recommendation: The text-backed data URI approach is acceptable for a small, self-contained API with tightly bounded image sizes. For production-scale usage, prefer object storage with a URL reference; if retaining base64 storage, add MIME, decoded-size, and data-URI validation to prevent unbounded payloads.

Files changed (2) +8 / -0

Enhancement (2) +8 / -0
models.pyPersist optional contact photo data +1/-0

Persist optional contact photo data

• Adds a nullable Text column to the Contact ORM model for storing base64-encoded image data.

app/models.py

schemas.pyExpose photos throughout contact API contracts +7/-0

Expose photos throughout contact API contracts

• Adds the optional photo data URI field to shared contact schemas and partial updates. The full OpenAPI example now documents the field, while inherited create, replace, and read contracts expose it automatically.

app/schemas.py

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Existing databases cannot upgrade 🐞 Bug ≡ Correctness
Description
Adding Contact.photo only changes SQLAlchemy metadata; startup uses create_all(), which does not
add columns to an existing contacts table. Deployments using the documented persistent SQLite or
PostgreSQL configuration will fail ORM reads and writes because generated contact queries reference
a nonexistent photo column.
Code

app/models.py[33]

+    photo: Mapped[str | None] = mapped_column(Text)
Evidence
The service explicitly supports persistent databases, initializes them only with create_all(), and
all ordinary ORM reads select the complete mapped Contact, including the newly added column. The
test fixture always rebuilds a fresh schema, so it cannot detect this upgrade failure.

app/database.py[48-52]
app/main.py[24-27]
app/main.py[60-68]
app/crud.py[14-20]
app/crud.py[37-58]
tests/conftest.py[15-20]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Existing persistent databases are not upgraded when the new `Contact.photo` ORM column is deployed, so contact queries fail against the old table schema.

## Issue Context
`Base.metadata.create_all()` creates missing tables but does not alter existing ones. Introduce and execute a versioned migration that adds a nullable text `photo` column while preserving existing contact rows.

## Fix Focus Areas
- app/models.py[32-34]
- app/database.py[48-52]
- app/main.py[60-68]
- tests/conftest.py[15-20]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Photo payload is unconstrained 🐞 Bug ☼ Reliability
Description
The photo fields accept arbitrary, unlimited strings rather than validating the promised image data
URI or limiting decoded size. Those values are stored verbatim and included in every ContactRead,
so malformed images are accepted and oversized uploads can inflate database, memory, and list
responses of up to 200 contacts without bound.
Code

app/schemas.py[R72-75]

+    photo: str | None = Field(
+        default=None,
+        description="Contact photo as base64-encoded image data (data URI format).",
+        examples=["data:image/jpeg;base64,/9j/4AAQSkZJRg..."],
Evidence
Neither added schema field has a content or length constraint; CRUD dumps supplied fields directly
into the ORM, and the inherited read schema serializes photo data in list responses whose page limit
is 200. The FastAPI setup also installs no application-level request-body limit.

app/schemas.py[72-76]
app/schemas.py[114-143]
app/schemas.py[146-150]
app/crud.py[62-85]
app/routers/contacts.py[66-108]
app/main.py[72-89]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Photo input currently accepts arbitrary and unlimited text, allowing invalid image values and resource-exhausting payloads to be persisted and returned by the API.

## Issue Context
Apply the same reusable validator to create/replace and patch schemas. Require an allowed image data-URI MIME type, strict base64 decoding, and a conservative decoded-byte limit; reject invalid or oversized values with validation errors, and add coverage for all mutation paths. Also avoid embedding full image data in collection representations if normal allowed image sizes can make a 200-item page excessive.

## Fix Focus Areas
- app/schemas.py[72-76]
- app/schemas.py[114-143]
- app/schemas.py[146-150]
- app/routers/contacts.py[66-108]
- tests/test_contacts_api.py[1-1]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
Review mode: ⚖️ Balanced: This changes the persisted model and public API schemas, including base64 image storage, so a careful full review is warranted despite the small localized diff.

Grey Divider

Tip of the day
💡 Did you know, you can ask Qodo to dismiss a finding you disagree with, with your reason on record

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread app/models.py
country: Mapped[str | None] = mapped_column(String(120))

notes: Mapped[str | None] = mapped_column(Text)
photo: Mapped[str | None] = mapped_column(Text)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Existing databases cannot upgrade 🐞 Bug ≡ Correctness

Adding Contact.photo only changes SQLAlchemy metadata; startup uses create_all(), which does not
add columns to an existing contacts table. Deployments using the documented persistent SQLite or
PostgreSQL configuration will fail ORM reads and writes because generated contact queries reference
a nonexistent photo column.
Agent Prompt
## Issue description
Existing persistent databases are not upgraded when the new `Contact.photo` ORM column is deployed, so contact queries fail against the old table schema.

## Issue Context
`Base.metadata.create_all()` creates missing tables but does not alter existing ones. Introduce and execute a versioned migration that adds a nullable text `photo` column while preserving existing contact rows.

## Fix Focus Areas
- app/models.py[32-34]
- app/database.py[48-52]
- app/main.py[60-68]
- tests/conftest.py[15-20]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread app/schemas.py
Comment on lines +72 to +75
photo: str | None = Field(
default=None,
description="Contact photo as base64-encoded image data (data URI format).",
examples=["data:image/jpeg;base64,/9j/4AAQSkZJRg..."],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Photo payload is unconstrained 🐞 Bug ☼ Reliability

The photo fields accept arbitrary, unlimited strings rather than validating the promised image data
URI or limiting decoded size. Those values are stored verbatim and included in every ContactRead,
so malformed images are accepted and oversized uploads can inflate database, memory, and list
responses of up to 200 contacts without bound.
Agent Prompt
## Issue description
Photo input currently accepts arbitrary and unlimited text, allowing invalid image values and resource-exhausting payloads to be persisted and returned by the API.

## Issue Context
Apply the same reusable validator to create/replace and patch schemas. Require an allowed image data-URI MIME type, strict base64 decoding, and a conservative decoded-byte limit; reject invalid or oversized values with validation errors, and add coverage for all mutation paths. Also avoid embedding full image data in collection representations if normal allowed image sizes can make a 200-item page excessive.

## Fix Focus Areas
- app/schemas.py[72-76]
- app/schemas.py[114-143]
- app/schemas.py[146-150]
- app/routers/contacts.py[66-108]
- tests/test_contacts_api.py[1-1]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant