"""Notes API endpoints (4 routes).
Swagger reveals one schema (``NoteModel``) for **both** ``POST /note`` and
``PUT /note/{id}``. The SDK reflects that with a single :class:`NoteRequest`.
The endpoint class still exposes :meth:`create` and :meth:`update` as
separate methods because the path and HTTP verb differ.
Discovery chain for ``create``: ``api.lookup.get_refer_categories`` /
``get_refer_category_hierarchy`` returns category UUIDs that feed
:attr:`NoteRequest.category`; ``suggest_users`` returns ``SuggestedUser``
records whose ``id`` feeds :attr:`NoteRequest.assigned_users`.
"""
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from ab.api.models.notes import GlobalNote, NoteRequest, SuggestedUser
from ab.api.base import BaseEndpoint
from ab.api.route import Route
_LIST = Route("GET", "/note", params_model="NotesListParams", response_model="List[GlobalNote]")
_CREATE = Route("POST", "/note", request_model="NoteRequest", response_model="GlobalNote")
_UPDATE = Route("PUT", "/note/{id}", request_model="NoteRequest", response_model="GlobalNote")
_SUGGEST_USERS = Route(
"GET", "/note/suggestUsers", params_model="NotesSuggestUsersParams", response_model="List[SuggestedUser]"
)
[docs]
class NotesEndpoint(BaseEndpoint):
"""Global note operations (ACPortal API).
Forward references:
* ``api.lookup.get_refer_categories`` -> :attr:`NoteRequest.category`
* :meth:`suggest_users` -> :attr:`NoteRequest.assigned_users` (by ``id``)
"""
[docs]
def list(
self,
*,
category: list[str] | None = None,
job_id: str | None = None,
contact_id: int | None = None,
company_id: str | None = None,
) -> list[GlobalNote]:
"""List notes (``GET /note``).
Swagger marks every filter optional, but the **live API requires at
least one** of ``category``, ``job_id``, ``contact_id``, or
``company_id`` -- omitting them all returns HTTP 400. The SDK
relays whatever the caller passes; it does not impose this rule.
Args:
category: One or more category UUIDs (repeated query param).
job_id: Filter to notes attached to this job UUID.
contact_id: Filter to notes attached to this contact ID.
company_id: Filter to notes attached to this company UUID.
Docs: https://ab-sdk.readthedocs.io/en/latest/api/notes/list.html
Query params: NotesListParams
Response model: List[GlobalNote]
"""
return self._request(
_LIST,
params=dict(category=category, job_id=job_id, contact_id=contact_id, company_id=company_id),
)
[docs]
def create(self, *, data: NoteRequest | dict) -> GlobalNote:
"""Create a note (``POST /note``).
Args:
data: Note payload. Accepts a :class:`NoteRequest` instance or
a dict. ``comments`` and ``category`` are **required** by
swagger; the request model enforces this.
Request model: :class:`NoteRequest` (same schema as ``update``).
Docs: https://ab-sdk.readthedocs.io/en/latest/api/notes/create.html
Request model: NoteRequest
Response model: GlobalNote
"""
return self._request(_CREATE, json=data)
[docs]
def update(self, note_id: str, *, data: NoteRequest | dict) -> GlobalNote:
"""Update a note (``PUT /note/{id}``).
The API uses the same :class:`NoteRequest` schema as ``create``, so
``comments`` and ``category`` are required on update too -- partial
updates are not supported by this endpoint.
Args:
note_id: Note identifier (path param).
data: Note payload. Accepts a :class:`NoteRequest` instance or
a dict.
Request model: :class:`NoteRequest` (same schema as ``create``).
Docs: https://ab-sdk.readthedocs.io/en/latest/api/notes/update.html
Request model: NoteRequest
Response model: GlobalNote
"""
return self._request(_UPDATE.bind(id=note_id), json=data)
[docs]
def suggest_users(
self,
search_key: str,
*,
job_franchisee_id: str | None = None,
company_id: str | None = None,
) -> list[SuggestedUser]:
"""Suggest users for mentions (``GET /note/suggestUsers``).
``search_key`` is **required** by swagger; it is positional here so
it cannot be silently omitted.
Returns rows whose ``id`` feeds :attr:`NoteRequest.assigned_users`.
Docs: https://ab-sdk.readthedocs.io/en/latest/api/notes/suggest_users.html
Query params: NotesSuggestUsersParams
Response model: List[SuggestedUser]
"""
return self._request(
_SUGGEST_USERS,
params=dict(search_key=search_key, job_franchisee_id=job_franchisee_id, company_id=company_id),
)