258 lines
5.9 KiB
Python
258 lines
5.9 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
|
|
sources: list[str]
|
|
|
|
|
|
class PaginatedActivityOut(BaseModel):
|
|
items: list[ActivityOut]
|
|
total: int
|
|
limit: int
|
|
offset: int
|
|
|
|
|
|
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
|
|
source_system: str
|
|
source_url: str | 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
|
|
source_system: str = "rf4-official"
|
|
|
|
|
|
class PublicObservationOut(BaseModel):
|
|
id: UUID
|
|
source_system: str
|
|
source_name: str
|
|
source_url: str
|
|
fish_name: str
|
|
waterbody_name: str
|
|
x: int | None
|
|
y: int | None
|
|
weight_g: int | None
|
|
last_seen_at: datetime
|
|
missing_fields: list[str]
|
|
quality: str
|
|
|
|
|
|
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
|
|
response_status: int | None
|
|
response_etag: str | None
|
|
response_last_modified: str | None
|
|
response_content_type: str | None
|
|
response_bytes: int | None
|
|
not_modified: bool
|
|
|
|
|
|
class ImportRunPublicOut(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
id: UUID
|
|
started_at: datetime
|
|
finished_at: datetime | None
|
|
status: str
|
|
rows_seen: int
|
|
rows_created: int
|
|
rows_updated: int
|
|
not_modified: bool
|
|
|
|
|
|
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 CatchReportAccepted(CatchReportCreated):
|
|
screenshot_upload_token: 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
|
|
screenshot_url: 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
|
|
|
|
|
|
class ExternalObservationOut(BaseModel):
|
|
id: UUID
|
|
source_system: str
|
|
source_external_id: str
|
|
source_url: str
|
|
fish_name: str
|
|
fish_external_id: str | None
|
|
waterbody_name: str
|
|
waterbody_external_id: str | None
|
|
x: int | None
|
|
y: int | None
|
|
weight_g: int | None
|
|
published_at: datetime | None
|
|
last_seen_at: datetime
|
|
status: str
|
|
fish_slug: str | None
|
|
waterbody_slug: str | None
|
|
catch_report_id: UUID | None
|
|
review_note: str | None
|
|
|
|
|
|
class ExternalObservationMapping(BaseModel):
|
|
fish_slug: str
|
|
waterbody_slug: str
|
|
note: str | None = Field(default=None, max_length=1000)
|
|
|
|
|
|
class ExternalAliasSuggestionOut(BaseModel):
|
|
fish_slug: str | None
|
|
waterbody_slug: str | None
|
|
requires_confirmation: bool = True
|
|
|
|
|
|
class ExternalObservationDecision(BaseModel):
|
|
reason: str = Field(min_length=1, max_length=1000)
|
|
|
|
|
|
class ExternalObservationPublished(BaseModel):
|
|
observation_id: UUID
|
|
catch_report_id: UUID
|
|
status: str
|
|
|
|
|
|
class SourceStatusOut(BaseModel):
|
|
source_system: str
|
|
name: str
|
|
status: str
|
|
last_started_at: datetime | None
|
|
last_success_at: datetime | None
|
|
observations: int
|