f329f647c7
Co-authored-by: Cursor <cursoragent@cursor.com>
259 lines
6.0 KiB
Python
259 lines
6.0 KiB
Python
"""接口请求与响应。金额在 JSON 里用字符串,避免浮点误差。"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import date, datetime
|
|
from decimal import Decimal
|
|
from typing import Annotated
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field, PlainSerializer
|
|
|
|
from app.models import NodeStatus, OrderStatus, TaskStatus, UserRole, WithdrawalStatus, YieldStatus
|
|
|
|
SN = Annotated[str, Field(min_length=4, max_length=64, pattern=r"^[A-Za-z0-9_-]+$")]
|
|
WALLET = Annotated[str, Field(min_length=4, max_length=128, pattern=r"^[A-Za-z0-9:_-]+$")]
|
|
USERNAME = Annotated[str, Field(min_length=3, max_length=32, pattern=r"^[A-Za-z0-9_]+$")]
|
|
MoneyText = Annotated[Decimal, PlainSerializer(lambda value: format(value, "f"), return_type=str)]
|
|
|
|
|
|
class APIModel(BaseModel):
|
|
model_config = ConfigDict(from_attributes=True)
|
|
|
|
|
|
class UserCreate(APIModel):
|
|
wallet_address: WALLET
|
|
|
|
|
|
class UserOut(APIModel):
|
|
id: int
|
|
wallet_address: str
|
|
username: str | None = None
|
|
role: UserRole = UserRole.USER
|
|
created_at: datetime
|
|
|
|
|
|
class RegisterIn(APIModel):
|
|
wallet_address: WALLET
|
|
username: USERNAME | None = None
|
|
password: str | None = Field(default=None, max_length=72)
|
|
|
|
|
|
class LoginIn(APIModel):
|
|
wallet_address: str | None = Field(default=None, max_length=128)
|
|
username: str | None = Field(default=None, max_length=32)
|
|
password: str | None = Field(default=None, max_length=72)
|
|
|
|
|
|
class TokenOut(APIModel):
|
|
access_token: str
|
|
token_type: str = "bearer"
|
|
role: UserRole
|
|
wallet_address: str
|
|
username: str | None = None
|
|
|
|
|
|
class AdminUserOut(APIModel):
|
|
id: int
|
|
wallet_address: str
|
|
username: str | None
|
|
role: UserRole
|
|
created_at: datetime
|
|
node_count: int
|
|
available_points: MoneyText
|
|
|
|
|
|
class NodeCreate(APIModel):
|
|
wallet_address: WALLET
|
|
sn: SN
|
|
purchase_amount: Decimal = Field(gt=0, max_digits=24, decimal_places=8)
|
|
callback_url: str | None = None
|
|
|
|
|
|
class NodeOut(APIModel):
|
|
id: int
|
|
user_id: int
|
|
sn: str
|
|
purchase_amount: MoneyText
|
|
license_months: int
|
|
licensed_at: datetime
|
|
license_expires_at: datetime
|
|
status: NodeStatus
|
|
last_heartbeat_at: datetime | None
|
|
callback_url: str | None
|
|
|
|
|
|
class NodeView(NodeOut):
|
|
wallet_address: str
|
|
online_rate: MoneyText = Decimal("0")
|
|
today_points: MoneyText = Decimal("0")
|
|
node_token: str | None = None
|
|
activated: bool = False
|
|
|
|
|
|
class HeartbeatIn(APIModel):
|
|
sn: SN
|
|
token: str | None = Field(default=None, max_length=128)
|
|
|
|
|
|
class HeartbeatOut(APIModel):
|
|
sn: str
|
|
status: NodeStatus
|
|
last_heartbeat_at: datetime
|
|
server_time: datetime
|
|
|
|
|
|
class TaskOut(APIModel):
|
|
task_id: str
|
|
task_type: str
|
|
payload: dict
|
|
status: TaskStatus
|
|
dispatched_at: datetime
|
|
deadline_at: datetime
|
|
|
|
|
|
class TaskReportIn(APIModel):
|
|
sn: SN
|
|
task_id: str = Field(min_length=36, max_length=36)
|
|
success: bool
|
|
nonce: str = Field(min_length=8, max_length=128)
|
|
token: str | None = Field(default=None, max_length=128)
|
|
|
|
|
|
class ContributionOut(APIModel):
|
|
sn: str
|
|
yield_date: date
|
|
eligible: bool
|
|
online_seconds: int
|
|
eligible_seconds: int
|
|
online_rate: MoneyText
|
|
tasks_dispatched: int
|
|
tasks_completed: int
|
|
task_response_rate: MoneyText
|
|
online_weight: MoneyText
|
|
task_weight: MoneyText
|
|
performance: MoneyText
|
|
compute_output: MoneyText
|
|
points_delta: MoneyText
|
|
cycle_days: int
|
|
|
|
|
|
class YieldOut(APIModel):
|
|
id: int
|
|
node_id: int
|
|
user_id: int
|
|
yield_date: date
|
|
compute_output: MoneyText
|
|
points_delta: MoneyText
|
|
online_seconds: int
|
|
eligible_seconds: int
|
|
online_rate: MoneyText
|
|
tasks_dispatched: int
|
|
tasks_completed: int
|
|
task_response_rate: MoneyText
|
|
online_weight: MoneyText
|
|
task_weight: MoneyText
|
|
performance: MoneyText
|
|
cycle_days: int
|
|
status: YieldStatus
|
|
is_partial: bool
|
|
created_at: datetime
|
|
|
|
|
|
class SettleOut(APIModel):
|
|
yield_date: date
|
|
created: int
|
|
skipped: int
|
|
total_points: MoneyText
|
|
is_partial: bool
|
|
|
|
|
|
class WithdrawalCreate(APIModel):
|
|
wallet_address: WALLET
|
|
amount: Decimal = Field(gt=0, max_digits=24, decimal_places=8)
|
|
asset_symbol: str = Field(default="POINT", min_length=1, max_length=32)
|
|
|
|
|
|
class MeWithdrawalCreate(APIModel):
|
|
amount: Decimal = Field(gt=0, max_digits=24, decimal_places=8)
|
|
asset_symbol: str = Field(default="POINT", min_length=1, max_length=32)
|
|
|
|
|
|
class MeNodeCreate(APIModel):
|
|
sn: SN
|
|
purchase_amount: Decimal = Field(gt=0, max_digits=24, decimal_places=8)
|
|
callback_url: str | None = None
|
|
|
|
|
|
class OrderCreate(APIModel):
|
|
tx_id: str = Field(min_length=6, max_length=128, pattern=r"^[A-Za-z0-9]+$")
|
|
|
|
|
|
class OrderOut(APIModel):
|
|
id: int
|
|
user_id: int
|
|
amount: MoneyText
|
|
asset_symbol: str
|
|
status: OrderStatus
|
|
tx_id: str
|
|
created_at: datetime
|
|
reviewed_at: datetime | None = None
|
|
sn: str | None = None
|
|
|
|
|
|
class OrderView(OrderOut):
|
|
wallet_address: str
|
|
|
|
|
|
class WithdrawalConfirm(APIModel):
|
|
tx_hash: str = Field(min_length=6, max_length=128, pattern=r"^[A-Za-z0-9]+$")
|
|
|
|
|
|
class WithdrawalReject(APIModel):
|
|
note: str | None = Field(default=None, max_length=500)
|
|
|
|
|
|
class WithdrawalOut(APIModel):
|
|
id: int
|
|
user_id: int
|
|
amount: MoneyText
|
|
asset_symbol: str
|
|
tx_hash: str | None
|
|
status: WithdrawalStatus
|
|
note: str | None
|
|
available_after: MoneyText | None = None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class WithdrawalView(WithdrawalOut):
|
|
wallet_address: str
|
|
|
|
|
|
class BalanceOut(APIModel):
|
|
wallet_address: str
|
|
available_points: MoneyText
|
|
|
|
|
|
class SummaryOut(APIModel):
|
|
users: int
|
|
nodes: int
|
|
online: int
|
|
offline: int
|
|
authorized_amount: MoneyText
|
|
settled_points: MoneyText
|
|
pending_withdrawals: MoneyText
|
|
|
|
|
|
class DashboardOut(APIModel):
|
|
wallet_address: str
|
|
username: str | None
|
|
role: UserRole
|
|
available_points: MoneyText
|
|
settled_points: MoneyText
|
|
today_points: MoneyText
|
|
license_price: MoneyText
|
|
license_asset: str
|
|
nodes: list[NodeView]
|
|
orders: list[OrderOut]
|
|
withdrawals: list[WithdrawalOut]
|