429 lines
14 KiB
Python
429 lines
14 KiB
Python
from pydantic import BaseModel, Field, field_validator
|
|
|
|
|
|
class TodoCreate(BaseModel):
|
|
title: str = Field(..., min_length=1, max_length=100)
|
|
|
|
|
|
class TodoUpdate(BaseModel):
|
|
title: str | None = Field(default=None, min_length=1, max_length=100)
|
|
done: bool | None = None
|
|
|
|
|
|
class Todo(BaseModel):
|
|
id: int
|
|
title: str
|
|
done: bool = False
|
|
|
|
|
|
class UserCreate(BaseModel):
|
|
name: str = Field(..., min_length=1, max_length=80)
|
|
phone: str = Field(..., min_length=5, max_length=20, pattern=r"^[0-9+\-\s]+$")
|
|
nickname: str | None = Field(default=None, max_length=60)
|
|
avatar: str | None = Field(default=None, max_length=300)
|
|
is_admin: bool = False
|
|
total_spent: float = Field(default=0, ge=0)
|
|
|
|
|
|
class UserUpdate(BaseModel):
|
|
name: str | None = Field(default=None, min_length=1, max_length=80)
|
|
phone: str | None = Field(default=None, min_length=5, max_length=20, pattern=r"^[0-9+\-\s]+$")
|
|
nickname: str | None = Field(default=None, max_length=60)
|
|
avatar: str | None = Field(default=None, max_length=300)
|
|
is_admin: bool | None = None
|
|
total_spent: float | None = Field(default=None, ge=0)
|
|
|
|
|
|
class User(BaseModel):
|
|
id: int
|
|
registered_at: str
|
|
name: str
|
|
phone: str | None = None
|
|
nickname: str | None = None
|
|
avatar: str | None = None
|
|
is_admin: bool = False
|
|
total_spent: float = 0
|
|
|
|
|
|
class AuthUser(BaseModel):
|
|
id: int
|
|
username: str
|
|
name: str
|
|
is_admin: bool = False
|
|
|
|
|
|
class CaptchaResponse(BaseModel):
|
|
captcha_id: str
|
|
challenge: str
|
|
expires_in: int
|
|
|
|
|
|
class LoginRequest(BaseModel):
|
|
username: str = Field(..., min_length=1, max_length=80)
|
|
password: str = Field(..., min_length=1, max_length=128)
|
|
captcha_id: str | None = Field(default=None, max_length=80)
|
|
captcha_code: str | None = Field(default=None, max_length=20)
|
|
|
|
|
|
class LoginResponse(BaseModel):
|
|
expires_in: int
|
|
user: AuthUser
|
|
requires_second_verification: bool = False
|
|
security_notice: str | None = None
|
|
|
|
|
|
class TempleCreate(BaseModel):
|
|
name: str = Field(..., min_length=1, max_length=100)
|
|
location: str | None = Field(default=None, max_length=160)
|
|
contact_phone: str | None = Field(default=None, max_length=30)
|
|
description: str | None = Field(default=None, max_length=500)
|
|
is_active: bool = True
|
|
|
|
|
|
class TempleUpdate(BaseModel):
|
|
name: str | None = Field(default=None, min_length=1, max_length=100)
|
|
location: str | None = Field(default=None, max_length=160)
|
|
contact_phone: str | None = Field(default=None, max_length=30)
|
|
description: str | None = Field(default=None, max_length=500)
|
|
is_active: bool | None = None
|
|
|
|
|
|
class Temple(BaseModel):
|
|
id: int
|
|
name: str
|
|
location: str | None = None
|
|
contact_phone: str | None = None
|
|
description: str | None = None
|
|
is_active: bool = True
|
|
|
|
|
|
class ProductSpec(BaseModel):
|
|
name: str = Field(..., min_length=1, max_length=80)
|
|
price: float = Field(default=0, ge=0)
|
|
stock: int = Field(default=0, ge=0)
|
|
sort_order: int = Field(default=0, ge=0)
|
|
is_chaodu: bool = False
|
|
|
|
|
|
class ProductBase(BaseModel):
|
|
name: str = Field(..., min_length=1, max_length=120)
|
|
alias: str | None = Field(default=None, max_length=80)
|
|
description: str | None = Field(default=None, max_length=500)
|
|
payment_button_name: str = Field(default="立即支付", min_length=1, max_length=30)
|
|
donation_button_name: str = Field(default="随喜", min_length=1, max_length=30)
|
|
sort_order: int = Field(default=0, ge=0)
|
|
show_participant_count: bool = False
|
|
cover_image: str | None = Field(default=None, max_length=500)
|
|
images: list[str] = Field(default_factory=list, max_length=10)
|
|
listed_at: str | None = Field(default=None, max_length=30)
|
|
sale_starts_at: str | None = Field(default=None, max_length=30)
|
|
sale_ends_at: str | None = Field(default=None, max_length=30)
|
|
delisted_at: str | None = Field(default=None, max_length=30)
|
|
show_countdown: bool = False
|
|
show_on_home: bool = False
|
|
specs: list[ProductSpec] = Field(default_factory=list)
|
|
details_html: str | None = None
|
|
share_title: str | None = Field(default=None, max_length=120)
|
|
share_description: str | None = Field(default=None, max_length=300)
|
|
share_image: str | None = Field(default=None, max_length=500)
|
|
merit_certificate_reserved: bool = False
|
|
auto_process: bool = False
|
|
is_active: bool = True
|
|
sales_count: int = Field(default=0, ge=0)
|
|
|
|
@field_validator("images")
|
|
@classmethod
|
|
def validate_images_count(cls, value: list[str]) -> list[str]:
|
|
if len(value) > 10:
|
|
raise ValueError("Product images cannot exceed 10")
|
|
return value
|
|
|
|
|
|
class ProductCreate(ProductBase):
|
|
pass
|
|
|
|
|
|
class ProductUpdate(BaseModel):
|
|
name: str | None = Field(default=None, min_length=1, max_length=120)
|
|
alias: str | None = Field(default=None, max_length=80)
|
|
description: str | None = Field(default=None, max_length=500)
|
|
payment_button_name: str | None = Field(default=None, min_length=1, max_length=30)
|
|
donation_button_name: str | None = Field(default=None, min_length=1, max_length=30)
|
|
sort_order: int | None = Field(default=None, ge=0)
|
|
show_participant_count: bool | None = None
|
|
cover_image: str | None = Field(default=None, max_length=500)
|
|
images: list[str] | None = Field(default=None, max_length=10)
|
|
listed_at: str | None = Field(default=None, max_length=30)
|
|
sale_starts_at: str | None = Field(default=None, max_length=30)
|
|
sale_ends_at: str | None = Field(default=None, max_length=30)
|
|
delisted_at: str | None = Field(default=None, max_length=30)
|
|
show_countdown: bool | None = None
|
|
show_on_home: bool | None = None
|
|
specs: list[ProductSpec] | None = None
|
|
details_html: str | None = None
|
|
share_title: str | None = Field(default=None, max_length=120)
|
|
share_description: str | None = Field(default=None, max_length=300)
|
|
share_image: str | None = Field(default=None, max_length=500)
|
|
merit_certificate_reserved: bool | None = None
|
|
auto_process: bool | None = None
|
|
is_active: bool | None = None
|
|
sales_count: int | None = Field(default=None, ge=0)
|
|
|
|
@field_validator("images")
|
|
@classmethod
|
|
def validate_images_count(cls, value: list[str] | None) -> list[str] | None:
|
|
if value is not None and len(value) > 10:
|
|
raise ValueError("Product images cannot exceed 10")
|
|
return value
|
|
|
|
|
|
class Product(BaseModel):
|
|
id: int
|
|
temple_id: int
|
|
name: str
|
|
alias: str | None = None
|
|
description: str | None = None
|
|
payment_button_name: str = "立即支付"
|
|
donation_button_name: str = "随喜"
|
|
sort_order: int = 0
|
|
show_participant_count: bool = False
|
|
cover_image: str | None = None
|
|
images: list[str] = Field(default_factory=list)
|
|
listed_at: str | None = None
|
|
sale_starts_at: str | None = None
|
|
sale_ends_at: str | None = None
|
|
delisted_at: str | None = None
|
|
show_countdown: bool = False
|
|
show_on_home: bool = False
|
|
specs: list[ProductSpec] = Field(default_factory=list)
|
|
details_html: str | None = None
|
|
share_title: str | None = None
|
|
share_description: str | None = None
|
|
share_image: str | None = None
|
|
merit_certificate_reserved: bool = False
|
|
auto_process: bool = False
|
|
is_active: bool = True
|
|
sales_count: int = 0
|
|
status: str
|
|
|
|
|
|
class UploadResponse(BaseModel):
|
|
url: str
|
|
object_key: str
|
|
|
|
|
|
class FeatureIconBase(BaseModel):
|
|
title: str = Field(..., min_length=1, max_length=80)
|
|
icon_url: str = Field(..., min_length=1, max_length=500)
|
|
target_type: str = Field(default="link", pattern=r"^(link|app)$")
|
|
target_url: str | None = Field(default=None, max_length=500)
|
|
product_id: int | None = Field(default=None, ge=1)
|
|
sort_order: int = Field(default=0, ge=0)
|
|
is_active: bool = True
|
|
|
|
@field_validator("target_url")
|
|
@classmethod
|
|
def trim_target_url(cls, value: str | None) -> str | None:
|
|
if value is None:
|
|
return None
|
|
value = value.strip()
|
|
return value or None
|
|
|
|
|
|
class FeatureIconCreate(FeatureIconBase):
|
|
pass
|
|
|
|
|
|
class FeatureIconUpdate(BaseModel):
|
|
title: str | None = Field(default=None, min_length=1, max_length=80)
|
|
icon_url: str | None = Field(default=None, min_length=1, max_length=500)
|
|
target_type: str | None = Field(default=None, pattern=r"^(link|app)$")
|
|
target_url: str | None = Field(default=None, max_length=500)
|
|
product_id: int | None = Field(default=None, ge=1)
|
|
sort_order: int | None = Field(default=None, ge=0)
|
|
is_active: bool | None = None
|
|
|
|
@field_validator("target_url")
|
|
@classmethod
|
|
def trim_target_url(cls, value: str | None) -> str | None:
|
|
if value is None:
|
|
return None
|
|
value = value.strip()
|
|
return value or None
|
|
|
|
|
|
class FeatureIcon(BaseModel):
|
|
id: int
|
|
temple_id: int
|
|
title: str
|
|
icon_url: str
|
|
target_type: str
|
|
target_url: str | None = None
|
|
product_id: int | None = None
|
|
product_name: str | None = None
|
|
sort_order: int = 0
|
|
is_active: bool = True
|
|
|
|
|
|
class FeatureIconCopyRequest(BaseModel):
|
|
source_temple_id: int = Field(..., ge=1)
|
|
icon_ids: list[int] = Field(..., min_length=1)
|
|
|
|
|
|
class AdSlotBase(BaseModel):
|
|
name: str = Field(..., min_length=1, max_length=100)
|
|
code: str = Field(..., min_length=1, max_length=80, pattern=r"^[a-zA-Z0-9_-]+$")
|
|
description: str | None = Field(default=None, max_length=300)
|
|
sort_order: int = Field(default=0, ge=0)
|
|
is_active: bool = True
|
|
|
|
|
|
class AdSlotCreate(AdSlotBase):
|
|
pass
|
|
|
|
|
|
class AdSlotUpdate(BaseModel):
|
|
name: str | None = Field(default=None, min_length=1, max_length=100)
|
|
code: str | None = Field(default=None, min_length=1, max_length=80, pattern=r"^[a-zA-Z0-9_-]+$")
|
|
description: str | None = Field(default=None, max_length=300)
|
|
sort_order: int | None = Field(default=None, ge=0)
|
|
is_active: bool | None = None
|
|
|
|
|
|
class AdSlot(BaseModel):
|
|
id: int
|
|
temple_id: int
|
|
name: str
|
|
code: str
|
|
description: str | None = None
|
|
sort_order: int = 0
|
|
is_active: bool = True
|
|
|
|
|
|
class AdBase(BaseModel):
|
|
slot_id: int = Field(..., ge=1)
|
|
title: str = Field(..., min_length=1, max_length=100)
|
|
image_url: str = Field(..., min_length=1, max_length=500)
|
|
target_type: str = Field(default="link", pattern=r"^(link|app)$")
|
|
target_url: str | None = Field(default=None, max_length=500)
|
|
product_id: int | None = Field(default=None, ge=1)
|
|
sort_order: int = Field(default=0, ge=0)
|
|
is_active: bool = True
|
|
|
|
@field_validator("target_url")
|
|
@classmethod
|
|
def trim_target_url(cls, value: str | None) -> str | None:
|
|
if value is None:
|
|
return None
|
|
value = value.strip()
|
|
return value or None
|
|
|
|
|
|
class AdCreate(AdBase):
|
|
pass
|
|
|
|
|
|
class AdUpdate(BaseModel):
|
|
slot_id: int | None = Field(default=None, ge=1)
|
|
title: str | None = Field(default=None, min_length=1, max_length=100)
|
|
image_url: str | None = Field(default=None, min_length=1, max_length=500)
|
|
target_type: str | None = Field(default=None, pattern=r"^(link|app)$")
|
|
target_url: str | None = Field(default=None, max_length=500)
|
|
product_id: int | None = Field(default=None, ge=1)
|
|
sort_order: int | None = Field(default=None, ge=0)
|
|
is_active: bool | None = None
|
|
|
|
@field_validator("target_url")
|
|
@classmethod
|
|
def trim_target_url(cls, value: str | None) -> str | None:
|
|
if value is None:
|
|
return None
|
|
value = value.strip()
|
|
return value or None
|
|
|
|
|
|
class Ad(BaseModel):
|
|
id: int
|
|
temple_id: int
|
|
slot_id: int
|
|
slot_name: str | None = None
|
|
slot_code: str | None = None
|
|
title: str
|
|
image_url: str
|
|
target_type: str
|
|
target_url: str | None = None
|
|
product_id: int | None = None
|
|
product_name: str | None = None
|
|
sort_order: int = 0
|
|
is_active: bool = True
|
|
|
|
|
|
class RitualServiceCreate(BaseModel):
|
|
name: str = Field(..., min_length=1, max_length=120)
|
|
description: str | None = Field(default=None, max_length=500)
|
|
price: float = Field(default=0, ge=0)
|
|
is_active: bool = True
|
|
|
|
|
|
class RitualServiceUpdate(BaseModel):
|
|
name: str | None = Field(default=None, min_length=1, max_length=120)
|
|
description: str | None = Field(default=None, max_length=500)
|
|
price: float | None = Field(default=None, ge=0)
|
|
is_active: bool | None = None
|
|
|
|
|
|
class RitualService(BaseModel):
|
|
id: int
|
|
temple_id: int
|
|
name: str
|
|
description: str | None = None
|
|
price: float = 0
|
|
is_active: bool = True
|
|
|
|
|
|
class OrderCreate(BaseModel):
|
|
customer_name: str = Field(..., min_length=1, max_length=80)
|
|
customer_phone: str | None = Field(default=None, max_length=30)
|
|
order_type: str = Field(default="product", pattern=r"^(product|ritual)$")
|
|
item_name: str = Field(..., min_length=1, max_length=120)
|
|
amount: float = Field(default=0, ge=0)
|
|
status: str = Field(default="pending", pattern=r"^(pending|paid|completed|cancelled)$")
|
|
|
|
|
|
class OrderUpdate(BaseModel):
|
|
customer_name: str | None = Field(default=None, min_length=1, max_length=80)
|
|
customer_phone: str | None = Field(default=None, max_length=30)
|
|
order_type: str | None = Field(default=None, pattern=r"^(product|ritual)$")
|
|
item_name: str | None = Field(default=None, min_length=1, max_length=120)
|
|
amount: float | None = Field(default=None, ge=0)
|
|
status: str | None = Field(default=None, pattern=r"^(pending|paid|completed|cancelled)$")
|
|
|
|
|
|
class Order(BaseModel):
|
|
id: int
|
|
temple_id: int
|
|
customer_name: str
|
|
customer_phone: str | None = None
|
|
order_type: str
|
|
item_name: str
|
|
amount: float = 0
|
|
status: str
|
|
created_at: str
|
|
|
|
|
|
class WeChatJSAPIPayRequest(BaseModel):
|
|
order_id: int
|
|
openid: str = Field(..., min_length=1, max_length=128)
|
|
description: str | None = Field(default=None, max_length=127)
|
|
|
|
|
|
class WeChatJSAPIPayResponse(BaseModel):
|
|
appId: str
|
|
timeStamp: str
|
|
nonceStr: str
|
|
package: str
|
|
signType: str
|
|
paySign: str
|
|
out_trade_no: str
|
|
prepay_id: str
|