"""Pydantic request/response models for bincio.serve.""" from __future__ import annotations from typing import Optional from pydantic import BaseModel, Field class LoginRequest(BaseModel): handle: str = Field(..., description="User handle (username)") password: str = Field(..., description="User password") class LoginResponse(BaseModel): ok: bool = Field(True, description="Success flag") handle: str = Field(..., description="User handle") display_name: str = Field(..., description="User's display name") class ResetPasswordRequest(BaseModel): handle: str = Field(..., description="User handle") code: str = Field(..., description="Reset code (24 hours valid)") password: str = Field(..., description="New password (min 8 chars)") class RegisterRequest(BaseModel): code: str = Field(..., description="Invite code") handle: str = Field(..., description="Desired username (lowercase, 1-30 chars)") password: str = Field(..., description="Password (min 8 characters)") display_name: str = Field(default="", description="Full name (optional, defaults to handle)") class RegisterResponse(BaseModel): ok: bool = Field(True, description="Success flag") handle: str = Field(..., description="New user's handle") class CurrentUserResponse(BaseModel): handle: str = Field(..., description="User handle") display_name: str = Field(..., description="User's display name") is_admin: bool = Field(..., description="Whether user is an admin") wiki_access: bool = Field(default=True, description="Whether user has wiki access") activity_access: bool = Field(default=False, description="Whether user has activity access") store_originals_default: bool = Field( default=True, description="Instance-wide default for storing original files" ) dem_configured: bool = Field(default=False, description="Whether DEM elevation lookup is configured") class ActivityEditRequest(BaseModel): title: str | None = Field(default=None, description="Activity title") description: str | None = Field(default=None, description="Activity description (markdown)") sport: str | None = Field(default=None, description="Sport type") sub_sport: str | None = Field(default=None, description="Sport sub-category") private: bool | None = Field(default=None, description="Hide from public feed") highlight: bool | None = Field(default=None, description="Mark as favorite") gear: str | None = Field(default=None, description="Gear used") class ActivityEditResponse(BaseModel): ok: bool = Field(True, description="Success flag") class ResetPasswordCodeResponse(BaseModel): ok: bool = Field(True, description="Success flag") code: str = Field(..., description="One-time reset code") expires_in_hours: int = Field(24, description="Code validity period in hours") class GenericResponse(BaseModel): ok: bool = Field(True, description="Success flag") class CreateSegmentRequest(BaseModel): name: str = Field(..., description="Segment name") sport: Optional[str] = Field(default=None, description="Sport filter") polyline: list[list[float]] = Field(..., description="[[lat, lon], ...] GPS points") distance_m: float = Field(..., description="Segment length in metres") class CreateInviteRequest(BaseModel): grants_activity: bool = Field(default=False) class IdeaBody(BaseModel): title: str body: str = "" class IdeaCommentBody(BaseModel): comment: str = ""