feat: backend core — models, auth, CRUD, tests
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
import uuid
|
||||
|
||||
from pydantic import BaseModel, EmailStr
|
||||
|
||||
|
||||
class UserCreate(BaseModel):
|
||||
email: EmailStr
|
||||
password: str
|
||||
full_name: str
|
||||
|
||||
|
||||
class UserResponse(BaseModel):
|
||||
id: uuid.UUID
|
||||
email: str
|
||||
full_name: str
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class Token(BaseModel):
|
||||
access_token: str
|
||||
refresh_token: str
|
||||
token_type: str = "bearer"
|
||||
|
||||
|
||||
class TokenRefresh(BaseModel):
|
||||
access_token: str
|
||||
token_type: str = "bearer"
|
||||
|
||||
|
||||
class TokenRefreshRequest(BaseModel):
|
||||
refresh_token: str
|
||||
@@ -0,0 +1,31 @@
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.models.category import CategoryType
|
||||
|
||||
|
||||
class CategoryCreate(BaseModel):
|
||||
name: str
|
||||
type: CategoryType
|
||||
color: str | None = None
|
||||
icon: str | None = None
|
||||
|
||||
|
||||
class CategoryUpdate(BaseModel):
|
||||
name: str | None = None
|
||||
color: str | None = None
|
||||
icon: str | None = None
|
||||
|
||||
|
||||
class CategoryResponse(BaseModel):
|
||||
id: uuid.UUID
|
||||
name: str
|
||||
type: CategoryType
|
||||
color: str | None
|
||||
icon: str | None
|
||||
is_default: bool
|
||||
created_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
@@ -0,0 +1,12 @@
|
||||
from typing import Generic, TypeVar
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class PaginatedResponse(BaseModel, Generic[T]):
|
||||
items: list[T]
|
||||
total: int
|
||||
page: int
|
||||
per_page: int
|
||||
@@ -0,0 +1,60 @@
|
||||
import uuid
|
||||
from datetime import date, datetime
|
||||
|
||||
from pydantic import BaseModel, field_validator
|
||||
|
||||
from app.models.transaction import TransactionType
|
||||
from app.schemas.common import PaginatedResponse
|
||||
|
||||
|
||||
class CategoryBrief(BaseModel):
|
||||
id: uuid.UUID
|
||||
name: str
|
||||
color: str | None
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class TransactionCreate(BaseModel):
|
||||
amount_cents: int
|
||||
type: TransactionType
|
||||
category_id: uuid.UUID
|
||||
description: str | None = None
|
||||
transaction_date: date
|
||||
|
||||
@field_validator("amount_cents")
|
||||
@classmethod
|
||||
def amount_must_be_positive(cls, v: int) -> int:
|
||||
if v <= 0:
|
||||
raise ValueError("amount_cents must be greater than 0")
|
||||
return v
|
||||
|
||||
|
||||
class TransactionUpdate(BaseModel):
|
||||
amount_cents: int | None = None
|
||||
type: TransactionType | None = None
|
||||
category_id: uuid.UUID | None = None
|
||||
description: str | None = None
|
||||
transaction_date: date | None = None
|
||||
|
||||
@field_validator("amount_cents")
|
||||
@classmethod
|
||||
def amount_must_be_positive(cls, v: int | None) -> int | None:
|
||||
if v is not None and v <= 0:
|
||||
raise ValueError("amount_cents must be greater than 0")
|
||||
return v
|
||||
|
||||
|
||||
class TransactionResponse(BaseModel):
|
||||
id: uuid.UUID
|
||||
amount_cents: int
|
||||
type: TransactionType
|
||||
description: str | None
|
||||
category: CategoryBrief
|
||||
transaction_date: date
|
||||
created_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
PaginatedTransactions = PaginatedResponse[TransactionResponse]
|
||||
Reference in New Issue
Block a user