Refactor: split serve/server.py (3220 lines) into focused modules
serve/server.py is now 69 lines — app factory, middleware, and router
registration only.
New modules:
deps.py (168 lines) — module-level globals + auth dependency functions
models.py (85 lines) — all Pydantic request/response models
tasks.py (136 lines) — background workers and job tracker
routers/ — one file per domain (10 routers, ~2750 lines total)
auth.py, me.py, admin.py, activities.py, uploads.py,
segments.py, strava.py, garmin.py, ideas.py, feed.py
cli.py updated to set globals on deps instead of server.
88 new regression tests in tests/serve/ cover auth guards and key
behaviours for every router; 294 total passing after the split.
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
"""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")
|
||||
store_originals_default: bool = Field(
|
||||
default=True,
|
||||
description="Instance-wide default for storing original files"
|
||||
)
|
||||
|
||||
|
||||
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 = ""
|
||||
Reference in New Issue
Block a user