test_task_crm/app/api/v1/activities.py

76 lines
2.6 KiB
Python

"""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
from app.services.activity_service import (
ActivityForbiddenError,
ActivityListFilters,
ActivityService,
ActivityValidationError,
)
from app.services.organization_service import OrganizationContext
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"])
@router.get("/", response_model=list[ActivityRead])
async def list_activities(
deal_id: int,
limit: int = Query(50, ge=1, le=200),
offset: int = Query(0, ge=0),
context: OrganizationContext = Depends(get_organization_context),
service: ActivityService = Depends(get_activity_service),
) -> list[ActivityRead]:
"""Fetch paginated activities for the deal within the current organization."""
filters = ActivityListFilters(deal_id=deal_id, limit=limit, offset=offset)
try:
activities = await service.list_activities(filters=filters, context=context)
except ActivityForbiddenError as exc:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
return [ActivityRead.model_validate(activity) for activity in activities]
@router.post("/", response_model=ActivityRead, status_code=status.HTTP_201_CREATED)
async def create_activity_comment(
deal_id: int,
payload: ActivityCommentPayload,
context: OrganizationContext = Depends(get_organization_context),
service: ActivityService = Depends(get_activity_service),
) -> ActivityRead:
"""Add a comment to the deal timeline."""
try:
activity = await service.add_comment(
deal_id=deal_id,
author_id=context.user_id,
text=payload.extract_text(),
context=context,
)
except ActivityValidationError as exc:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
except ActivityForbiddenError as exc:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc)) from exc
return ActivityRead.model_validate(activity)