Coverage for app / schemas / campaign.py: 98%
59 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-04 06:09 -0500
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-04 06:09 -0500
1from datetime import datetime
2from typing import Optional, List
3from pydantic import BaseModel, Field, field_validator
4from app.db.models import CampaignCategory, CampaignStatus
7class CampaignBase(BaseModel):
8 title: str = Field(..., min_length=1, max_length=100)
9 description: str = Field(..., min_length=1, max_length=5000)
10 category: CampaignCategory
11 goal_amount_usd: int = Field(..., gt=0, description="Goal amount in cents")
12 eth_wallet_address: Optional[str] = Field(None, max_length=42)
13 btc_wallet_address: Optional[str] = Field(None, max_length=62)
14 doge_wallet_address: Optional[str] = Field(None, max_length=34)
15 sol_wallet_address: Optional[str] = Field(None, max_length=44)
16 cover_image_url: Optional[str] = Field(None, max_length=500)
17 end_date: Optional[datetime] = None
19 @field_validator("eth_wallet_address", "btc_wallet_address", "doge_wallet_address", "sol_wallet_address", mode="before")
20 @classmethod
21 def validate_at_least_one_wallet(cls, v, info):
22 return v
25class CampaignCreate(CampaignBase):
26 contact_email: str = Field(..., max_length=255)
28 @field_validator("contact_email")
29 @classmethod
30 def validate_email(cls, v):
31 if "@" not in v:
32 raise ValueError("Invalid email address")
33 return v
36class CampaignUpdate(BaseModel):
37 title: Optional[str] = Field(None, min_length=1, max_length=100)
38 description: Optional[str] = Field(None, min_length=1, max_length=5000)
39 category: Optional[CampaignCategory] = None
40 goal_amount_usd: Optional[int] = Field(None, gt=0)
41 eth_wallet_address: Optional[str] = Field(None, max_length=42)
42 btc_wallet_address: Optional[str] = Field(None, max_length=62)
43 doge_wallet_address: Optional[str] = Field(None, max_length=34)
44 sol_wallet_address: Optional[str] = Field(None, max_length=44)
45 cover_image_url: Optional[str] = Field(None, max_length=500)
46 end_date: Optional[datetime] = None
47 status: Optional[CampaignStatus] = None
50class CampaignResponse(CampaignBase):
51 id: str
52 status: CampaignStatus
53 advocate_count: int = 0
54 current_btc_satoshi: int = 0
55 current_eth_wei: int = 0
56 current_doge_satoshi: int = 0
57 current_sol_lamports: int = 0
58 last_balance_check: Optional[datetime] = None
59 created_at: datetime
60 updated_at: datetime
62 class Config:
63 from_attributes = True
66class CampaignDetailResponse(CampaignResponse):
67 creator_id: str
70class CampaignListResponse(BaseModel):
71 campaigns: List[CampaignResponse]
72 total: int
73 page: int
74 per_page: int