import uuid from datetime import datetime from typing import Any from pydantic import ConfigDict, Field from common.enums import LocalContentStatus, LocalContentType, LocalSource from common.models.gmodel import Res_WebPacketProtocol, WebPacketProtocol class LocalContentData(WebPacketProtocol): model_config = ConfigDict(from_attributes=True) local_content_id: uuid.UUID region_code: str content_type: LocalContentType source: LocalSource external_id: str | None = None title: str | None = None body: dict[str, Any] status: LocalContentStatus collected_at: datetime | None = None published_at: datetime | None = None display_start_at: datetime | None = None display_end_at: datetime | None = None class PlaceContentData(WebPacketProtocol): """업장 반경 주변정보 1건(admin 목록용).""" model_config = ConfigDict(from_attributes=True) place_content_id: uuid.UUID place_id: uuid.UUID content_type: LocalContentType external_id: str title: str body: dict[str, Any] distance_m: int has_image: bool hidden: bool display_end_at: datetime | None = None collected_at: datetime | None = None class ResPlaceContentList(Res_WebPacketProtocol): contents: list[PlaceContentData] = [] class ReqHidePlaceContent(WebPacketProtocol): hidden: bool class ReqPublishLocalContent(WebPacketProtocol): content_ids: list[uuid.UUID] = Field(min_length=1, max_length=100) class ReqUpdateLocalContent(WebPacketProtocol): title: str | None = Field(default=None, min_length=1, max_length=300) body: dict[str, Any] | None = None display_start_at: datetime | None = None display_end_at: datetime | None = None class ResLocalContentList(Res_WebPacketProtocol): contents: list[LocalContentData] = [] class ResSyncPlace(Res_WebPacketProtocol): """업장 반경 동기화 결과 — 종류별로 **남긴** 건수(반경·기간 필터 뒤). changed 는 값이 바뀌었는지.""" festivals: int = 0 attractions: int = 0 restaurants: int = 0 courses: int = 0 changed: bool = False class ResLocalGuide(Res_WebPacketProtocol): """에디터 캔버스가 그리는 지역 가이드. ★ 항목 모양은 발행 payload 의 LocalContents 와 **동일**하다 (services/site_payload._local 을 그대로 거친다) — 캔버스와 발행본이 다른 목록을 보이면 안 된다.""" attractions: list[dict[str, Any]] = [] restaurants: list[dict[str, Any]] = [] festivals: list[dict[str, Any]] = [] courses: list[dict[str, Any]] = [] # ★ 1박2일·2박3일 각 5개(services/itinerary_llm_service). 발행본 payload.local.itineraries 와 # **같은 값**이다 — 캔버스가 다른 목록을 보이면 "미리보기와 다르다"가 된다. itineraries: list[dict[str, Any]] = [] synced_at: str | None = None class WeatherData(WebPacketProtocol): temperature: float weather_code: int wind_speed: float | None = None observed_at: str timezone: str | None = None latitude: float longitude: float class ResWeather(Res_WebPacketProtocol): weather: WeatherData | None = None cached: bool = False stale: bool = False