chore: initial project setup with backend, frontend, and infrastructure
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
This commit is contained in:
161
backend/app/schemas/common.py
Normal file
161
backend/app/schemas/common.py
Normal file
@@ -0,0 +1,161 @@
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user