Files
Priceflow/app/schemas.py
T
Claude 933cb2e66f feat: Improve search config + rename Dashboard + fix SearXNG
SearXNG:
- Fix tini not found error by calling entrypoint.sh directly
- Keep limiter.toml creation at container startup

UI Changes:
- Rename "Tableau de bord" to "Suivis produits" in navigation
- Move CSS selector configuration from item modal to Settings page
- Add price_selector field to search sites configuration
- Display CSS selector badge on site cards

Backend:
- Add price_selector column to SearchSite model and schemas
- Update init.sql with search_sites table and migration for existing DBs
2025-11-22 13:24:28 +00:00

124 lines
3.0 KiB
Python

from datetime import datetime
from pydantic import BaseModel, ConfigDict
class NotificationProfileCreate(BaseModel):
name: str
apprise_url: str
notify_on_price_drop: bool = True
notify_on_target_price: bool = True
price_drop_threshold_percent: float = 10.0
notify_on_stock_change: bool = True
check_interval_minutes: int = 60
class NotificationProfileUpdate(NotificationProfileCreate):
pass
class NotificationProfileResponse(NotificationProfileCreate):
id: int
model_config = ConfigDict(from_attributes=True)
class ItemCreate(BaseModel):
url: str
name: str
selector: str | None = None
target_price: float | None = None
check_interval_minutes: int = 60
tags: str | None = None
description: str | None = None
notification_profile_id: int | None = None
class ItemResponse(ItemCreate):
id: int
current_price: float | None
in_stock: bool | None
current_price_confidence: float | None = None
in_stock_confidence: float | None = None
is_active: bool
last_checked: datetime | None
is_refreshing: bool = False
last_error: str | None = None
screenshot_url: str | None = None
model_config = ConfigDict(from_attributes=True)
class SettingsUpdate(BaseModel):
key: str
value: str
# === Search Sites Schemas ===
class SearchSiteCreate(BaseModel):
name: str
domain: str
logo_url: str | None = None
category: str | None = None
is_active: bool = True
priority: int = 0
requires_js: bool = False
price_selector: str | None = None
class SearchSiteUpdate(BaseModel):
name: str | None = None
domain: str | None = None
logo_url: str | None = None
category: str | None = None
is_active: bool | None = None
priority: int | None = None
requires_js: bool | None = None
price_selector: str | None = None
class SearchSiteResponse(BaseModel):
id: int
name: str
domain: str
logo_url: str | None = None
category: str | None = None
is_active: bool
priority: int
requires_js: bool
price_selector: str | None = None
created_at: datetime | None = None
updated_at: datetime | None = None
model_config = ConfigDict(from_attributes=True)
# === Search Results Schemas ===
class SearchQuery(BaseModel):
query: str
site_ids: list[int] | None = None # If None, use all active sites
max_results: int = 20
class SearchResultItem(BaseModel):
"""Un produit trouvé lors de la recherche"""
url: str
title: str
price: float | None = None
currency: str = "EUR"
in_stock: bool | None = None
image_url: str | None = None
site_name: str
site_domain: str
confidence: float | None = None
error: str | None = None
class SearchProgress(BaseModel):
"""Progression de la recherche pour SSE"""
status: str # "searching", "scraping", "completed", "error"
total: int
completed: int
current_site: str | None = None
results: list[SearchResultItem] = []
message: str | None = None