Files
rf4-spotter/apps/api/app/schemas.py
T

157 lines
3.7 KiB
Python

from __future__ import annotations
from datetime import datetime
from uuid import UUID
from pydantic import BaseModel, ConfigDict, Field, field_validator
class FishOut(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: UUID
slug: str
name_ru: str
trophy_weight_g: int | None
class WaterbodyOut(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: UUID
slug: str
name_ru: str
unlock_level: int | None
class BaitOut(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: UUID
name: str
normalized_name: str
kind: str
class ActivityOut(BaseModel):
spot_id: UUID
waterbody_slug: str
waterbody: str
fish_slug: str
fish: str
x: int
y: int
best_bait: str | None
catches: int
unique_players: int
average_weight_g: int
max_weight_g: int
last_confirmed_at: datetime
activity_score: int
confidence_score: int
explanation: str
class CatchOut(BaseModel):
id: UUID
fish: str
weight_g: int
bait: str | None
player_name: str | None
caught_at: datetime | None
reported_at: datetime
retrieve_method: str | None
retrieve_speed: int | None
class SpotOut(BaseModel):
id: UUID
waterbody_slug: str
waterbody: str
x: int
y: int
description: str | None
catches_24h: int
catches_3d: int
catches_7d: int
top_baits: list[str]
class OfficialRecordOut(BaseModel):
id: UUID
fish: str
weight_g: int
waterbody: str
bait: str | None
player_name: str | None
record_date: datetime | None
category: str | None
region: str | None
source_url: str | None
class ImportRunOut(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: UUID
started_at: datetime
finished_at: datetime | None
status: str
source_url: str
rows_seen: int
rows_created: int
rows_updated: int
error_summary: str | None
class CatchReportCreate(BaseModel):
fish_slug: str
waterbody_slug: str
x: int = Field(ge=-10_000, le=10_000)
y: int = Field(ge=-10_000, le=10_000)
weight_g: int = Field(gt=0, le=3_000_000)
bait_name: str | None = Field(default=None, max_length=200)
fishing_method: str | None = Field(default=None, max_length=50)
rig_type: str | None = Field(default=None, max_length=100)
retrieve_method: str | None = Field(default=None, max_length=100)
retrieve_speed: int | None = Field(default=None, ge=0, le=100)
caught_at: datetime | None = None
player_name: str | None = Field(default=None, max_length=100)
source_url: str | None = Field(default=None, max_length=1000)
comment: str | None = Field(default=None, max_length=1000)
website: str = Field(default="", max_length=200)
@field_validator("fish_slug", "waterbody_slug")
@classmethod
def nonempty_slug(cls, value: str) -> str:
value = value.strip()
if not value:
raise ValueError("must not be empty")
return value
class CatchReportCreated(BaseModel):
id: UUID
moderation_status: str
class AdminCatchReportOut(BaseModel):
id: UUID
fish: str
waterbody: str
coordinates: str
weight_g: int
bait: str | None
player_name: str | None
reported_at: datetime
moderation_status: str
comment: str | None
class ModerationUpdate(BaseModel):
status: str
reason: str | None = Field(default=None, max_length=1000)
@field_validator("status")
@classmethod
def known_status(cls, value: str) -> str:
if value not in {"approved", "rejected", "pending"}:
raise ValueError("unknown moderation status")
return value