Files
leocrm/app/api/v1/activities.py
T

165 lines
4.9 KiB
Python
Raw Normal View History

2026-06-03 23:52:11 +00:00
"""Activity API endpoints."""
from __future__ import annotations
from fastapi import APIRouter, Depends, HTTPException, Query, Response, status
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.db import get_db
from app.core.deps import get_current_user
from app.models.activity import ActivityType
from app.models.user import User
from app.schemas.activity import (
ActivityCompleteRequest,
ActivityCreate,
ActivityOut,
ActivityUpdate,
)
from app.services.activity_service import (
NoParentException,
)
from app.services.activity_service import (
2026-06-03 23:52:11 +00:00
complete_activity as svc_complete_activity,
)
from app.services.activity_service import (
2026-06-03 23:52:11 +00:00
create_activity as svc_create_activity,
)
from app.services.activity_service import (
2026-06-03 23:52:11 +00:00
get_activity as svc_get_activity,
)
from app.services.activity_service import (
2026-06-03 23:52:11 +00:00
list_activities as svc_list_activities,
)
from app.services.activity_service import (
2026-06-03 23:52:11 +00:00
soft_delete_activity as svc_soft_delete_activity,
)
from app.services.activity_service import (
2026-06-03 23:52:11 +00:00
update_activity as svc_update_activity,
)
router = APIRouter(prefix="/activities", tags=["activities"])
@router.post(
"/",
response_model=ActivityOut,
status_code=status.HTTP_201_CREATED,
summary="Create a new activity (polymorphic parent: account/contact/deal)",
)
async def create_activity(
payload: ActivityCreate,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
) -> ActivityOut:
try:
activity = await svc_create_activity(
db, payload, org_id=current_user.org_id, owner_id=current_user.id
)
except NoParentException as e:
raise HTTPException(status_code=422, detail=str(e)) from e
return ActivityOut.model_validate(activity)
@router.get(
"/",
response_model=list[ActivityOut],
summary="List activities (paginated, filterable)",
)
async def list_activities(
skip: int = Query(0, ge=0),
limit: int = Query(20, ge=1, le=100),
type: ActivityType | None = None,
owner_id: int | None = None,
overdue: bool | None = None,
completed: bool | None = None,
2026-06-03 23:52:11 +00:00
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
) -> list[ActivityOut]:
activities = await svc_list_activities(
db,
org_id=current_user.org_id,
skip=skip,
limit=limit,
type=type,
owner_id=owner_id,
overdue=overdue,
completed=completed,
)
return [ActivityOut.model_validate(a) for a in activities]
@router.get(
"/{activity_id}",
response_model=ActivityOut,
summary="Get one activity",
)
async def get_activity(
activity_id: int,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
) -> ActivityOut:
activity = await svc_get_activity(db, activity_id, org_id=current_user.org_id)
2026-06-03 23:52:11 +00:00
if activity is None:
raise HTTPException(status_code=404, detail="Activity not found")
return ActivityOut.model_validate(activity)
@router.patch(
"/{activity_id}",
response_model=ActivityOut,
summary="Update an activity",
)
async def update_activity(
activity_id: int,
payload: ActivityUpdate,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
) -> ActivityOut:
activity = await svc_get_activity(db, activity_id, org_id=current_user.org_id)
2026-06-03 23:52:11 +00:00
if activity is None:
raise HTTPException(status_code=404, detail="Activity not found")
try:
updated = await svc_update_activity(db, activity, payload)
except NoParentException as e:
raise HTTPException(status_code=422, detail=str(e)) from e
return ActivityOut.model_validate(updated)
@router.patch(
"/{activity_id}/complete",
response_model=ActivityOut,
summary="Mark an activity as completed",
)
async def complete_activity(
activity_id: int,
payload: ActivityCompleteRequest,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
) -> ActivityOut:
activity = await svc_get_activity(db, activity_id, org_id=current_user.org_id)
2026-06-03 23:52:11 +00:00
if activity is None:
raise HTTPException(status_code=404, detail="Activity not found")
updated = await svc_complete_activity(db, activity, payload)
return ActivityOut.model_validate(updated)
@router.delete(
"/{activity_id}",
status_code=status.HTTP_204_NO_CONTENT,
response_class=Response,
summary="Soft-delete an activity",
)
async def delete_activity(
activity_id: int,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
) -> Response:
activity = await svc_get_activity(db, activity_id, org_id=current_user.org_id)
2026-06-03 23:52:11 +00:00
if activity is None:
raise HTTPException(status_code=404, detail="Activity not found")
await svc_soft_delete_activity(db, activity)
return Response(status_code=status.HTTP_204_NO_CONTENT)
__all__ = ["router"]