dev #11
|
|
@ -1,7 +1,10 @@
|
|||
"""Activity timeline endpoints backed by ActivityService."""
|
||||
"""Activity timeline endpoints and payload schemas."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Literal
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from app.api.deps import get_activity_service, get_organization_context
|
||||
from app.models.activity import ActivityRead
|
||||
|
|
@ -13,7 +16,18 @@ from app.services.activity_service import (
|
|||
)
|
||||
from app.services.organization_service import OrganizationContext
|
||||
|
||||
from .models import ActivityCommentPayload
|
||||
|
||||
class ActivityCommentBody(BaseModel):
|
||||
text: str = Field(..., min_length=1, max_length=2000)
|
||||
|
||||
|
||||
class ActivityCommentPayload(BaseModel):
|
||||
type: Literal["comment"] = "comment"
|
||||
payload: ActivityCommentBody
|
||||
|
||||
def extract_text(self) -> str:
|
||||
return self.payload.text.strip()
|
||||
|
||||
|
||||
router = APIRouter(prefix="/deals/{deal_id}/activities", tags=["activities"])
|
||||
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
"""Activities API package."""
|
||||
from .views import router
|
||||
|
||||
__all__ = ["router"]
|
||||
|
|
@ -1 +0,0 @@
|
|||
"""CRUD helpers for activities (to be implemented)."""
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
"""Pydantic schemas for activity endpoints."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Literal
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class ActivityCommentBody(BaseModel):
|
||||
text: str = Field(..., min_length=1, max_length=2000)
|
||||
|
||||
|
||||
class ActivityCommentPayload(BaseModel):
|
||||
type: Literal["comment"] = "comment"
|
||||
payload: ActivityCommentBody
|
||||
|
||||
def extract_text(self) -> str:
|
||||
return self.payload.text.strip()
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
"""Analytics API package."""
|
||||
from .views import router
|
||||
|
||||
__all__ = ["router"]
|
||||
|
|
@ -1 +0,0 @@
|
|||
"""Analytics CRUD/query helpers placeholder."""
|
||||
|
|
@ -1 +0,0 @@
|
|||
"""Analytics schemas placeholder."""
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
"""Authentication API endpoints."""
|
||||
"""Authentication API endpoints and payloads."""
|
||||
from __future__ import annotations
|
||||
|
||||
from pydantic import BaseModel, EmailStr
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
|
||||
|
|
@ -13,7 +14,13 @@ from app.models.user import UserCreate
|
|||
from app.repositories.user_repo import UserRepository
|
||||
from app.services.auth_service import AuthService, InvalidCredentialsError
|
||||
|
||||
from .models import RegisterRequest
|
||||
|
||||
class RegisterRequest(BaseModel):
|
||||
email: EmailStr
|
||||
password: str
|
||||
name: str
|
||||
organization_name: str
|
||||
|
||||
|
||||
router = APIRouter(prefix="/auth", tags=["auth"])
|
||||
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
"""Auth API package."""
|
||||
from .views import router
|
||||
|
||||
__all__ = ["router"]
|
||||
|
|
@ -1 +0,0 @@
|
|||
"""Auth CRUD/service helpers placeholder."""
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
"""Auth-specific Pydantic schemas."""
|
||||
from __future__ import annotations
|
||||
|
||||
from pydantic import BaseModel, EmailStr
|
||||
|
||||
|
||||
class RegisterRequest(BaseModel):
|
||||
email: EmailStr
|
||||
password: str
|
||||
name: str
|
||||
organization_name: str
|
||||
|
|
@ -1,12 +1,18 @@
|
|||
"""Contact API stubs required by the spec."""
|
||||
"""Contact API stubs and schemas."""
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Depends, Query, status
|
||||
from pydantic import BaseModel, EmailStr
|
||||
|
||||
from app.api.deps import get_organization_context
|
||||
from app.services.organization_service import OrganizationContext
|
||||
|
||||
from .models import ContactCreatePayload
|
||||
|
||||
class ContactCreatePayload(BaseModel):
|
||||
name: str
|
||||
email: EmailStr | None = None
|
||||
phone: str | None = None
|
||||
|
||||
|
||||
router = APIRouter(prefix="/contacts", tags=["contacts"])
|
||||
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
"""Contacts API package."""
|
||||
from .views import router
|
||||
|
||||
__all__ = ["router"]
|
||||
|
|
@ -1 +0,0 @@
|
|||
"""Contacts CRUD placeholder."""
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
"""Contact API schemas."""
|
||||
from __future__ import annotations
|
||||
|
||||
from pydantic import BaseModel, EmailStr
|
||||
|
||||
|
||||
class ContactCreatePayload(BaseModel):
|
||||
name: str
|
||||
email: EmailStr | None = None
|
||||
phone: str | None = None
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
"""Deal API endpoints backed by DealService."""
|
||||
"""Deal API endpoints backed by DealService with inline payload schemas."""
|
||||
from __future__ import annotations
|
||||
|
||||
from decimal import Decimal
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.api.deps import get_deal_repository, get_deal_service, get_organization_context
|
||||
from app.models.deal import DealRead, DealStage, DealStatus
|
||||
from app.models.deal import DealCreate, DealRead, DealStage, DealStatus
|
||||
from app.repositories.deal_repo import DealRepository, DealAccessError, DealQueryParams
|
||||
from app.services.deal_service import (
|
||||
DealService,
|
||||
|
|
@ -16,7 +17,31 @@ from app.services.deal_service import (
|
|||
)
|
||||
from app.services.organization_service import OrganizationContext
|
||||
|
||||
from .models import DealCreatePayload, DealUpdatePayload
|
||||
|
||||
class DealCreatePayload(BaseModel):
|
||||
contact_id: int
|
||||
title: str
|
||||
amount: Decimal | None = None
|
||||
currency: str | None = None
|
||||
owner_id: int | None = None
|
||||
|
||||
def to_domain(self, *, organization_id: int, fallback_owner: int) -> DealCreate:
|
||||
return DealCreate(
|
||||
organization_id=organization_id,
|
||||
contact_id=self.contact_id,
|
||||
owner_id=self.owner_id or fallback_owner,
|
||||
title=self.title,
|
||||
amount=self.amount,
|
||||
currency=self.currency,
|
||||
)
|
||||
|
||||
|
||||
class DealUpdatePayload(BaseModel):
|
||||
status: DealStatus | None = None
|
||||
stage: DealStage | None = None
|
||||
amount: Decimal | None = None
|
||||
currency: str | None = None
|
||||
|
||||
|
||||
router = APIRouter(prefix="/deals", tags=["deals"])
|
||||
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
"""Deals API package."""
|
||||
from .views import router
|
||||
|
||||
__all__ = ["router"]
|
||||
|
|
@ -1 +0,0 @@
|
|||
"""Deal CRUD placeholder."""
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
"""Deal API schemas."""
|
||||
from __future__ import annotations
|
||||
|
||||
from decimal import Decimal
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.models.deal import DealCreate, DealStage, DealStatus
|
||||
|
||||
|
||||
class DealCreatePayload(BaseModel):
|
||||
contact_id: int
|
||||
title: str
|
||||
amount: Decimal | None = None
|
||||
currency: str | None = None
|
||||
owner_id: int | None = None
|
||||
|
||||
def to_domain(self, *, organization_id: int, fallback_owner: int) -> DealCreate:
|
||||
return DealCreate(
|
||||
organization_id=organization_id,
|
||||
contact_id=self.contact_id,
|
||||
owner_id=self.owner_id or fallback_owner,
|
||||
title=self.title,
|
||||
amount=self.amount,
|
||||
currency=self.currency,
|
||||
)
|
||||
|
||||
|
||||
class DealUpdatePayload(BaseModel):
|
||||
status: DealStatus | None = None
|
||||
stage: DealStage | None = None
|
||||
amount: Decimal | None = None
|
||||
currency: str | None = None
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
"""Organizations API package."""
|
||||
from .views import router
|
||||
|
||||
__all__ = ["router"]
|
||||
|
|
@ -1 +0,0 @@
|
|||
"""Organization CRUD placeholder."""
|
||||
|
|
@ -1 +0,0 @@
|
|||
"""Organization API schemas placeholder."""
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
"""Task API endpoints backed by TaskService."""
|
||||
"""Task API endpoints with inline schemas."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date
|
||||
from datetime import date, datetime, time, timezone
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.api.deps import get_organization_context, get_task_service
|
||||
from app.models.task import TaskRead
|
||||
from app.models.task import TaskCreate, TaskRead
|
||||
from app.services.organization_service import OrganizationContext
|
||||
from app.services.task_service import (
|
||||
TaskDueDateError,
|
||||
|
|
@ -16,7 +17,34 @@ from app.services.task_service import (
|
|||
TaskService,
|
||||
)
|
||||
|
||||
from .models import TaskCreatePayload, to_range_boundary
|
||||
|
||||
class TaskCreatePayload(BaseModel):
|
||||
deal_id: int
|
||||
title: str
|
||||
description: str | None = None
|
||||
due_date: date | None = None
|
||||
|
||||
def to_domain(self) -> TaskCreate:
|
||||
return TaskCreate(
|
||||
deal_id=self.deal_id,
|
||||
title=self.title,
|
||||
description=self.description,
|
||||
due_date=_date_to_datetime(self.due_date) if self.due_date else None,
|
||||
)
|
||||
|
||||
|
||||
def to_range_boundary(value: date | None, *, end_of_day: bool) -> datetime | None:
|
||||
"""Convert a date query param to an inclusive datetime boundary."""
|
||||
|
||||
if value is None:
|
||||
return None
|
||||
boundary_time = time(23, 59, 59, 999999) if end_of_day else time(0, 0, 0)
|
||||
return datetime.combine(value, boundary_time, tzinfo=timezone.utc)
|
||||
|
||||
|
||||
def _date_to_datetime(value: date) -> datetime:
|
||||
return datetime.combine(value, time(0, 0, 0), tzinfo=timezone.utc)
|
||||
|
||||
|
||||
router = APIRouter(prefix="/tasks", tags=["tasks"])
|
||||
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
"""Tasks API package."""
|
||||
from .views import router
|
||||
|
||||
__all__ = ["router"]
|
||||
|
|
@ -1 +0,0 @@
|
|||
"""Task CRUD placeholder."""
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
"""Task API schemas and helpers."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date, datetime, time, timezone
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.models.task import TaskCreate
|
||||
|
||||
|
||||
class TaskCreatePayload(BaseModel):
|
||||
deal_id: int
|
||||
title: str
|
||||
description: str | None = None
|
||||
due_date: date | None = None
|
||||
|
||||
def to_domain(self) -> TaskCreate:
|
||||
return TaskCreate(
|
||||
deal_id=self.deal_id,
|
||||
title=self.title,
|
||||
description=self.description,
|
||||
due_date=_date_to_datetime(self.due_date) if self.due_date else None,
|
||||
)
|
||||
|
||||
|
||||
def to_range_boundary(value: date | None, *, end_of_day: bool) -> datetime | None:
|
||||
"""Convert a date query param to an inclusive datetime boundary."""
|
||||
|
||||
if value is None:
|
||||
return None
|
||||
boundary_time = time(23, 59, 59, 999999) if end_of_day else time(0, 0, 0)
|
||||
return datetime.combine(value, boundary_time, tzinfo=timezone.utc)
|
||||
|
||||
|
||||
def _date_to_datetime(value: date) -> datetime:
|
||||
return datetime.combine(value, time(0, 0, 0), tzinfo=timezone.utc)
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
"""Users API package."""
|
||||
from .views import router
|
||||
|
||||
__all__ = ["router"]
|
||||
|
|
@ -1 +0,0 @@
|
|||
"""User CRUD placeholder."""
|
||||
|
|
@ -1 +0,0 @@
|
|||
"""User API schemas placeholder."""
|
||||
Loading…
Reference in New Issue