112 lines
3.0 KiB
Python
112 lines
3.0 KiB
Python
"""Pydantic request/response models for auth and personal inventory."""
|
|
from datetime import datetime
|
|
from typing import Any, Literal
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field
|
|
|
|
from app import config
|
|
|
|
|
|
class RegisterRequest(BaseModel):
|
|
username: str = Field(min_length=3, max_length=32)
|
|
password: str = Field(min_length=8, max_length=128)
|
|
|
|
|
|
class LoginRequest(BaseModel):
|
|
username: str = Field(min_length=1, max_length=32)
|
|
password: str = Field(min_length=1, max_length=128)
|
|
|
|
|
|
class UserOut(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
id: int
|
|
username: str
|
|
created_at: datetime
|
|
|
|
|
|
class AuthResponse(BaseModel):
|
|
user: UserOut
|
|
|
|
|
|
class InventoryAddRequest(BaseModel):
|
|
class_name: str = Field(min_length=1, max_length=255)
|
|
quantity: int = Field(default=1, ge=1, le=config.MAX_QUANTITY)
|
|
notes: str = Field(default="", max_length=config.MAX_NOTES_LENGTH)
|
|
quality: int | None = Field(default=None, ge=1, le=config.MAX_QUALITY)
|
|
|
|
|
|
class InventoryPatchRequest(BaseModel):
|
|
quantity: int | None = Field(default=None, ge=1, le=config.MAX_QUANTITY)
|
|
notes: str | None = Field(default=None, max_length=config.MAX_NOTES_LENGTH)
|
|
visibility: Literal["private", "available"] | None = None
|
|
# Explicit null clears the quality; omitting the field leaves it unchanged.
|
|
quality: int | None = Field(default=None, ge=1, le=config.MAX_QUALITY)
|
|
|
|
|
|
class InventoryEntryOut(BaseModel):
|
|
class_name: str
|
|
name: str
|
|
category: str | None
|
|
type: str | None
|
|
size: int | None
|
|
grade: Any | None = None
|
|
manufacturer: dict | None
|
|
quantity: int
|
|
notes: str
|
|
# Mining/refining quality (1-1000); only meaningful when
|
|
# `quality_applicable` is true. None means the owner has not set it.
|
|
quality: int | None = None
|
|
quality_applicable: bool = False
|
|
# Owner-chosen classification. Unrelated to `available` below.
|
|
visibility: Literal["private", "available"]
|
|
# False when the catalog no longer contains the referenced item (e.g. after
|
|
# a dataset refresh). The row is preserved rather than silently deleted.
|
|
available: bool
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class InventoryPage(BaseModel):
|
|
total: int
|
|
page: int
|
|
page_size: int
|
|
total_pages: int
|
|
items: list[InventoryEntryOut]
|
|
|
|
|
|
class InventorySummary(BaseModel):
|
|
items: int
|
|
quantity: int
|
|
categories: dict[str, int]
|
|
unavailable: int
|
|
|
|
|
|
class AvailableItemOut(BaseModel):
|
|
class_name: str
|
|
name: str
|
|
category: str | None
|
|
type: str | None
|
|
size: int | None
|
|
grade: Any | None = None
|
|
manufacturer: dict | None
|
|
quantity: int
|
|
quality: int | None = None
|
|
quality_applicable: bool = False
|
|
# Public listing: only the owner's display name, never notes.
|
|
username: str
|
|
updated_at: datetime
|
|
|
|
|
|
class AvailablePage(BaseModel):
|
|
total: int
|
|
page: int
|
|
page_size: int
|
|
total_pages: int
|
|
items: list[AvailableItemOut]
|
|
|
|
|
|
class InventoryAddResponse(BaseModel):
|
|
entry: InventoryEntryOut
|
|
created: bool
|