Add complete NexaPantry application structure including: - Docker Compose configuration with PostgreSQL, Redis, FastAPI backend, worker, frontend and Caddy - Environment configuration template with database, auth, and service settings - GitHub Actions CI workflow for backend/frontend linting, testing, auditing and Docker builds - AGPL-3.0 license and comprehensive README with setup, development, and security documentation - Backend
162 lines
4.2 KiB
Python
162 lines
4.2 KiB
Python
from datetime import date, datetime
|
|
|
|
from pydantic import BaseModel, EmailStr, Field
|
|
|
|
|
|
class Message(BaseModel):
|
|
message: str
|
|
|
|
|
|
class SetupStatus(BaseModel):
|
|
needs_setup: bool
|
|
instance: dict | None = None
|
|
|
|
|
|
class SetupCreate(BaseModel):
|
|
name: str = Field(min_length=1, max_length=160)
|
|
email: EmailStr
|
|
password: str = Field(min_length=12, max_length=256)
|
|
language: str
|
|
theme: str
|
|
public_url: str = Field(min_length=1, max_length=500)
|
|
instance_name: str = Field(min_length=1, max_length=160)
|
|
timezone: str = Field(min_length=1, max_length=80)
|
|
|
|
|
|
class LoginRequest(BaseModel):
|
|
email: EmailStr
|
|
password: str = Field(min_length=1, max_length=256)
|
|
|
|
|
|
class UserOut(BaseModel):
|
|
id: str
|
|
email: EmailStr
|
|
name: str
|
|
instance_role: str
|
|
language: str
|
|
theme: str
|
|
timezone: str
|
|
is_active: bool
|
|
onboarding_completed: bool
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class UserCreate(BaseModel):
|
|
email: EmailStr
|
|
name: str = Field(min_length=1, max_length=160)
|
|
role: str = "user"
|
|
send_invite: bool = True
|
|
|
|
|
|
class UserUpdate(BaseModel):
|
|
name: str | None = Field(default=None, min_length=1, max_length=160)
|
|
language: str | None = None
|
|
theme: str | None = None
|
|
timezone: str | None = None
|
|
instance_role: str | None = None
|
|
is_active: bool | None = None
|
|
onboarding_completed: bool | None = None
|
|
|
|
|
|
class InviteAccept(BaseModel):
|
|
token: str
|
|
name: str = Field(min_length=1, max_length=160)
|
|
password: str = Field(min_length=12, max_length=256)
|
|
language: str
|
|
theme: str
|
|
home_name: str | None = Field(default=None, max_length=160)
|
|
join_code: str | None = Field(default=None, max_length=40)
|
|
|
|
|
|
class HomeOut(BaseModel):
|
|
id: str
|
|
name: str
|
|
expiry_warning_days: int
|
|
daily_summary_enabled: bool
|
|
daily_summary_time: str
|
|
role: str | None = None
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class HomeCreate(BaseModel):
|
|
name: str = Field(min_length=1, max_length=160)
|
|
|
|
|
|
class HomeSettingsUpdate(BaseModel):
|
|
name: str | None = Field(default=None, min_length=1, max_length=160)
|
|
expiry_warning_days: int | None = Field(default=None, ge=0, le=60)
|
|
daily_summary_enabled: bool | None = None
|
|
daily_summary_time: str | None = Field(default=None, pattern=r"^\d{2}:\d{2}$")
|
|
|
|
|
|
class JoinCodeOut(BaseModel):
|
|
join_code: str
|
|
expires_at: datetime
|
|
|
|
|
|
class ProductIn(BaseModel):
|
|
name: str = Field(min_length=1, max_length=220)
|
|
barcode: str | None = Field(default=None, max_length=80)
|
|
brand: str | None = Field(default=None, max_length=160)
|
|
category: str = Field(default="Other", max_length=120)
|
|
location: str = Field(default="Pantry", max_length=120)
|
|
quantity: float = Field(default=1, ge=0)
|
|
unit: str = Field(default="pcs", max_length=32)
|
|
expires_at: date | None = None
|
|
min_quantity: float = Field(default=0, ge=0)
|
|
notes: str | None = Field(default=None, max_length=5000)
|
|
image_url: str | None = Field(default=None, max_length=1000)
|
|
|
|
|
|
class ProductOut(ProductIn):
|
|
id: str
|
|
home_id: str
|
|
status: str
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class ShoppingItemIn(BaseModel):
|
|
name: str = Field(min_length=1, max_length=220)
|
|
category: str = Field(default="Other", max_length=120)
|
|
quantity: float = Field(default=1, ge=0)
|
|
unit: str = Field(default="pcs", max_length=32)
|
|
product_id: str | None = None
|
|
|
|
|
|
class ShoppingItemOut(ShoppingItemIn):
|
|
id: str
|
|
home_id: str
|
|
checked: bool
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class MailSettingsIn(BaseModel):
|
|
smtp_host: str | None = Field(default=None, max_length=220)
|
|
smtp_port: int = Field(default=587, ge=1, le=65535)
|
|
smtp_user: str | None = Field(default=None, max_length=220)
|
|
smtp_password: str | None = Field(default=None, max_length=1000)
|
|
use_tls: bool = True
|
|
use_starttls: bool = True
|
|
sender_address: EmailStr | None = None
|
|
sender_name: str = Field(default="NexaPantry", max_length=160)
|
|
|
|
|
|
class MailSettingsOut(BaseModel):
|
|
smtp_host: str | None
|
|
smtp_port: int
|
|
smtp_user: str | None
|
|
has_password: bool
|
|
use_tls: bool
|
|
use_starttls: bool
|
|
sender_address: EmailStr | None
|
|
sender_name: str
|
|
|
|
|
|
class TestMailIn(BaseModel):
|
|
to: EmailStr
|
|
|