From bd740efbd5b7a4425213e524f929da48656da854 Mon Sep 17 00:00:00 2001 From: Leopoldadmin Date: Wed, 3 Jun 2026 23:52:11 +0000 Subject: [PATCH] Upload app/api/v1/contacts.py --- app/api/v1/contacts.py | 127 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 app/api/v1/contacts.py diff --git a/app/api/v1/contacts.py b/app/api/v1/contacts.py new file mode 100644 index 0000000..907e12c --- /dev/null +++ b/app/api/v1/contacts.py @@ -0,0 +1,127 @@ +"""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"]