From e9dfb6e293834e5efc63b62745c20beabc5680d7 Mon Sep 17 00:00:00 2001 From: Gilles Soulier Date: Sun, 24 May 2026 16:04:21 +0200 Subject: [PATCH] =?UTF-8?q?feat(todos):=20domains[],=20photo=5Fpath,=20gps?= =?UTF-8?q?=5Flat/lng=20=E2=80=94=20mod=C3=A8le,=20schemas,=20API,=20tri?= =?UTF-8?q?=20par=20date?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Modèle SQLAlchemy : ajout de domains (ARRAY), photo_path, gps_lat, gps_lng ; import Float - Schemas Pydantic : domain → domains dans TodoCreate, TodoUpdate, TodoResponse ; ajout photo_path, gps_lat, gps_lng - API GET /api/todos : filtre domain (param URL) redirigé vers domains.contains([domain]) sur le champ ARRAY - Tests : domain → domains dans les payloads POST ; assertion domains == ["informatique"] dans test_creer_todo --- backend/app/api/todos.py | 2 +- backend/app/models/todos.py | 6 +++++- backend/app/schemas/todos.py | 15 ++++++++++++--- backend/tests/test_todos.py | 7 ++++--- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/backend/app/api/todos.py b/backend/app/api/todos.py index f03392b..61e26fc 100644 --- a/backend/app/api/todos.py +++ b/backend/app/api/todos.py @@ -25,7 +25,7 @@ async def list_todos( ): conditions = [] if domain: - conditions.append(TodoItem.domain == domain) + conditions.append(TodoItem.domains.contains([domain])) if status: conditions.append(TodoItem.status == status) if priority: diff --git a/backend/app/models/todos.py b/backend/app/models/todos.py index 1887d1e..754c74c 100644 --- a/backend/app/models/todos.py +++ b/backend/app/models/todos.py @@ -1,6 +1,6 @@ import uuid from datetime import datetime -from sqlalchemy import String, Text, Integer, TIMESTAMP, text +from sqlalchemy import String, Text, Integer, Float, TIMESTAMP, text from sqlalchemy.dialects.postgresql import UUID, ARRAY from sqlalchemy.orm import Mapped, mapped_column from app.core.database import Base @@ -15,8 +15,12 @@ class TodoItem(Base): body: Mapped[str | None] = mapped_column(Text) url: Mapped[str | None] = mapped_column(Text) domain: Mapped[str | None] = mapped_column(String(50)) + domains: Mapped[list[str]] = mapped_column(ARRAY(String(50)), server_default=text("'{}'::varchar[]")) category: Mapped[str | None] = mapped_column(String(50)) tags: Mapped[list[str]] = mapped_column(ARRAY(String(50)), server_default=text("'{}'::varchar[]")) + photo_path: Mapped[str | None] = mapped_column(Text) + gps_lat: Mapped[float | None] = mapped_column(Float) + gps_lng: Mapped[float | None] = mapped_column(Float) status: Mapped[str] = mapped_column(String(20), server_default="pending") priority: Mapped[str] = mapped_column(String(10), server_default="medium") due_date: Mapped[datetime | None] = mapped_column(TIMESTAMP(timezone=True)) diff --git a/backend/app/schemas/todos.py b/backend/app/schemas/todos.py index 6666bd9..104b2e6 100644 --- a/backend/app/schemas/todos.py +++ b/backend/app/schemas/todos.py @@ -8,24 +8,30 @@ class TodoCreate(BaseModel): title: str body: str | None = None url: str | None = None - domain: str | None = None + domains: list[str] = Field(default_factory=list) category: str | None = None tags: list[str] = Field(default_factory=list) status: Literal["pending", "done", "cancelled"] = "pending" priority: Literal["low", "medium", "high"] = "medium" due_date: datetime | None = None + photo_path: str | None = None + gps_lat: float | None = None + gps_lng: float | None = None class TodoUpdate(BaseModel): title: str | None = None body: str | None = None url: str | None = None - domain: str | None = None + domains: list[str] | None = None category: str | None = None tags: list[str] | None = None status: Literal["pending", "done", "cancelled"] | None = None priority: Literal["low", "medium", "high"] | None = None due_date: datetime | None = None + photo_path: str | None = None + gps_lat: float | None = None + gps_lng: float | None = None class PostponeRequest(BaseModel): @@ -39,7 +45,7 @@ class TodoResponse(BaseModel): title: str body: str | None url: str | None - domain: str | None + domains: list[str] category: str | None tags: list[str] status: str @@ -49,3 +55,6 @@ class TodoResponse(BaseModel): created_at: datetime updated_at: datetime | None owner_id: uuid.UUID | None + photo_path: str | None + gps_lat: float | None + gps_lng: float | None diff --git a/backend/tests/test_todos.py b/backend/tests/test_todos.py index 83bf50d..ba1c433 100644 --- a/backend/tests/test_todos.py +++ b/backend/tests/test_todos.py @@ -13,7 +13,7 @@ async def cleanup(db_session): async def test_creer_todo(client): resp = await client.post("/api/todos/", json={ "title": "TEST_tâche simple", - "domain": "informatique", + "domains": ["informatique"], "priority": "high", }) assert resp.status_code == 201 @@ -22,6 +22,7 @@ async def test_creer_todo(client): assert data["status"] == "pending" assert data["postponed_count"] == 0 assert data["tags"] == [] + assert data["domains"] == ["informatique"] async def test_lister_todos_filtre_status(client): @@ -36,8 +37,8 @@ async def test_lister_todos_filtre_status(client): async def test_lister_todos_filtre_domaine(client): - await client.post("/api/todos/", json={"title": "TEST_info", "domain": "informatique"}) - await client.post("/api/todos/", json={"title": "TEST_jardin", "domain": "jardin"}) + await client.post("/api/todos/", json={"title": "TEST_info", "domains": ["informatique"]}) + await client.post("/api/todos/", json={"title": "TEST_jardin", "domains": ["jardin"]}) resp = await client.get("/api/todos/?domain=informatique&status=") assert resp.status_code == 200