feat: 添加日历批量操作与客户端时区感知功能,优化前端 UI 交互体验
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
import re
|
||||
from typing import Any
|
||||
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
||||
|
||||
from pydantic import (
|
||||
BaseModel,
|
||||
ConfigDict,
|
||||
Field,
|
||||
StrictInt,
|
||||
ValidationError,
|
||||
field_validator,
|
||||
)
|
||||
|
||||
_RFC3339_WITH_TZ_PATTERN = re.compile(
|
||||
r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$"
|
||||
)
|
||||
|
||||
|
||||
class ClientTimeContext(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
device_timezone: str = Field(
|
||||
...,
|
||||
description="IANA timezone from client device, e.g. America/Los_Angeles.",
|
||||
)
|
||||
client_now_iso: str = Field(
|
||||
...,
|
||||
description="RFC3339 datetime with timezone offset from client device.",
|
||||
)
|
||||
client_epoch_ms: StrictInt = Field(
|
||||
...,
|
||||
ge=0,
|
||||
description="Unix epoch milliseconds from client device.",
|
||||
)
|
||||
|
||||
@field_validator("device_timezone")
|
||||
@classmethod
|
||||
def validate_device_timezone(cls, value: str) -> str:
|
||||
try:
|
||||
ZoneInfo(value)
|
||||
except ZoneInfoNotFoundError as exc:
|
||||
raise ValueError("invalid client_time.device_timezone") from exc
|
||||
return value
|
||||
|
||||
@field_validator("client_now_iso")
|
||||
@classmethod
|
||||
def validate_client_now_iso(cls, value: str) -> str:
|
||||
if not _RFC3339_WITH_TZ_PATTERN.fullmatch(value):
|
||||
raise ValueError("invalid client_time.client_now_iso")
|
||||
normalized = value.replace("Z", "+00:00")
|
||||
try:
|
||||
parsed = datetime.fromisoformat(normalized)
|
||||
except ValueError as exc:
|
||||
raise ValueError("invalid client_time.client_now_iso") from exc
|
||||
if parsed.tzinfo is None:
|
||||
raise ValueError("invalid client_time.client_now_iso")
|
||||
return value
|
||||
|
||||
|
||||
class ForwardedPropsPayload(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
client_time: ClientTimeContext | None = None
|
||||
|
||||
|
||||
def parse_forwarded_props_client_time(
|
||||
forwarded_props: Any,
|
||||
) -> ClientTimeContext | None:
|
||||
if not isinstance(forwarded_props, dict):
|
||||
return None
|
||||
try:
|
||||
payload = ForwardedPropsPayload.model_validate(forwarded_props)
|
||||
except ValidationError as exc:
|
||||
raise ValueError("invalid RunAgentInput.forwardedProps") from exc
|
||||
return payload.client_time
|
||||
Reference in New Issue
Block a user