Files
crm-system/app/api/v1/contacts.py
T

128 lines
3.7 KiB
Python
Raw Normal View History

"""Contact API endpoints."""
from __future__ import annotations
from typing import Optional
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.user import User
from app.schemas.contact import ContactCreate, ContactOut, ContactUpdate
from app.services.contact_service import (
InvalidAccount,
create_contact as svc_create_contact,
get_contact as svc_get_contact,
list_contacts as svc_list_contacts,
soft_delete_contact as svc_soft_delete_contact,
update_contact as svc_update_contact,
)
router = APIRouter(prefix="/contacts", tags=["contacts"])
@router.post(
"/",
response_model=ContactOut,
status_code=status.HTTP_201_CREATED,
summary="Create a new contact",
)
async def create_contact(
payload: ContactCreate,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
) -> ContactOut:
try:
contact = await svc_create_contact(
db, payload, org_id=current_user.org_id, owner_id=current_user.id
)
except InvalidAccount as e:
raise HTTPException(status_code=404, detail=str(e)) from e
return ContactOut.model_validate(contact)
@router.get(
"/",
response_model=list[ContactOut],
summary="List contacts (paginated, filterable)",
)
async def list_contacts(
skip: int = Query(0, ge=0),
limit: int = Query(20, ge=1, le=100),
account_id: Optional[int] = None,
owner_id: Optional[int] = None,
q: Optional[str] = None,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
) -> list[ContactOut]:
contacts = await svc_list_contacts(
db,
org_id=current_user.org_id,
skip=skip,
limit=limit,
account_id=account_id,
owner_id=owner_id,
q=q,
)
return [ContactOut.model_validate(c) for c in contacts]
@router.get(
"/{contact_id}",
response_model=ContactOut,
summary="Get one contact",
)
async def get_contact(
contact_id: int,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
) -> ContactOut:
contact = await svc_get_contact(db, contact_id, org_id=current_user.org_id)
if contact is None:
raise HTTPException(status_code=404, detail="Contact not found")
return ContactOut.model_validate(contact)
@router.patch(
"/{contact_id}",
response_model=ContactOut,
summary="Update a contact",
)
async def update_contact(
contact_id: int,
payload: ContactUpdate,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
) -> ContactOut:
contact = await svc_get_contact(db, contact_id, org_id=current_user.org_id)
if contact is None:
raise HTTPException(status_code=404, detail="Contact not found")
try:
updated = await svc_update_contact(db, contact, payload)
except InvalidAccount as e:
raise HTTPException(status_code=404, detail=str(e)) from e
return ContactOut.model_validate(updated)
@router.delete(
"/{contact_id}",
status_code=status.HTTP_204_NO_CONTENT,
response_class=Response,
summary="Soft-delete a contact",
)
async def delete_contact(
contact_id: int,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
) -> Response:
contact = await svc_get_contact(db, contact_id, org_id=current_user.org_id)
if contact is None:
raise HTTPException(status_code=404, detail="Contact not found")
await svc_soft_delete_contact(db, contact)
return Response(status_code=status.HTTP_204_NO_CONTENT)
__all__ = ["router"]