128 lines
3.7 KiB
Python
128 lines
3.7 KiB
Python
|
|
"""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"]
|