Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Contacts API support #325

Merged
merged 3 commits into from
Jan 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
206 changes: 206 additions & 0 deletions nylas/models/contacts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
from dataclasses import dataclass
from enum import Enum
from typing import Optional, List
from typing_extensions import TypedDict, NotRequired

from dataclasses_json import dataclass_json

from nylas.models.list_query_params import ListQueryParams


class ContactType(str, Enum):
work = "work"
home = "home"
other = "other"


class SourceType(str, Enum):
address_book = "address_book"
inbox = "inbox"
domain = "domain"


@dataclass_json
@dataclass
class PhoneNumber:
number: Optional[str] = None
type: Optional[ContactType] = None


@dataclass_json
@dataclass
class PhysicalAddress:
format: Optional[str] = None
street_address: Optional[str] = None
city: Optional[str] = None
postal_code: Optional[str] = None
state: Optional[str] = None
country: Optional[str] = None
type: Optional[ContactType] = None


@dataclass_json
@dataclass
class WebPage:
url: Optional[str] = None
type: Optional[ContactType] = None


@dataclass_json
@dataclass
class ContactEmail:
email: Optional[str] = None
type: Optional[ContactType] = None


@dataclass_json
@dataclass
class ContactGroupId:
id: str


@dataclass_json
@dataclass
class InstantMessagingAddress:
im_address: Optional[str] = None
type: Optional[ContactType] = None


@dataclass_json
@dataclass
class Contact:
id: str
grant_id: str
object: str = "contact"
birthday: Optional[str] = None
company_name: Optional[str] = None
display_name: Optional[str] = None
emails: Optional[List[ContactEmail]] = None
im_addresses: Optional[List[InstantMessagingAddress]] = None
given_name: Optional[str] = None
job_title: Optional[str] = None
manager_name: Optional[str] = None
middle_name: Optional[str] = None
nickname: Optional[str] = None
notes: Optional[str] = None
office_location: Optional[str] = None
picture_url: Optional[str] = None
picture: Optional[str] = None
suffix: Optional[str] = None
surname: Optional[str] = None
source: Optional[SourceType] = None
phone_numbers: Optional[List[PhoneNumber]] = None
physical_addresses: Optional[List[PhysicalAddress]] = None
web_pages: Optional[List[WebPage]] = None
groups: Optional[List[ContactGroupId]] = None


class WriteablePhoneNumber(TypedDict):
number: NotRequired[str]
type: NotRequired[ContactType]


class WriteablePhysicalAddress(TypedDict):
format: NotRequired[str]
street_address: NotRequired[str]
city: NotRequired[str]
postal_code: NotRequired[str]
state: NotRequired[str]
country: NotRequired[str]
type: NotRequired[ContactType]


class WriteableWebPage(TypedDict):
url: NotRequired[str]
type: NotRequired[ContactType]


class WriteableContactEmail(TypedDict):
email: NotRequired[str]
type: NotRequired[ContactType]


class WriteableContactGroupId(TypedDict):
id: str


class WriteableInstantMessagingAddress(TypedDict):
im_address: NotRequired[str]
type: NotRequired[ContactType]


class CreateContactRequest(TypedDict):
birthday: NotRequired[str]
company_name: NotRequired[str]
display_name: NotRequired[str]
emails: NotRequired[List[WriteableContactEmail]]
im_addresses: NotRequired[List[WriteableInstantMessagingAddress]]
given_name: NotRequired[str]
job_title: NotRequired[str]
manager_name: NotRequired[str]
middle_name: NotRequired[str]
nickname: NotRequired[str]
notes: NotRequired[str]
office_location: NotRequired[str]
picture_url: NotRequired[str]
picture: NotRequired[str]
suffix: NotRequired[str]
surname: NotRequired[str]
source: NotRequired[SourceType]
phone_numbers: NotRequired[List[WriteablePhoneNumber]]
physical_addresses: NotRequired[List[WriteablePhysicalAddress]]
web_pages: NotRequired[List[WriteableWebPage]]
groups: NotRequired[List[WriteableContactGroupId]]


UpdateContactRequest = CreateContactRequest


class ListContactsQueryParams(ListQueryParams):
"""
Interface of the query parameters for listing calendars.

Attributes:
limit (NotRequired[int]): The maximum number of objects to return.
This field defaults to 50. The maximum allowed value is 200.
page_token (NotRequired[str]): An identifier that specifies which page of data to return.
This value should be taken from a ListResponse object's next_cursor parameter.
email: Returns the contacts matching the exact contact's email.
phone_number: Returns the contacts matching the contact's exact phone number
source: Returns the contacts matching from the address book or auto-generated contacts from emails.
For example of contacts only from the address book: /contacts?source=address_bookor
for only autogenerated contacts:/contacts?source=inbox`
group: Returns the contacts belonging to the Contact Group matching this ID
recurse: When set to true, returns the contacts also within the specified Contact Group subgroups,
if the group parameter is set.
"""

email: NotRequired[str]
phone_number: NotRequired[str]
source: NotRequired[SourceType]
group: NotRequired[str]
recurse: NotRequired[bool]


class FindContactQueryParams(TypedDict):
profile_picture: NotRequired[bool]


class GroupType(str, Enum):
user = "user"
system = "system"
other = "other"


@dataclass_json
@dataclass
class ContactGroup:
id: str
grant_id: str
object: str = "contact_group"
group_type: Optional[GroupType] = None
name: Optional[str] = None
path: Optional[str] = None


ListContactGroupsQueryParams = ListQueryParams
143 changes: 143 additions & 0 deletions nylas/resources/contacts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
from nylas.handler.api_resources import (
ListableApiResource,
FindableApiResource,
CreatableApiResource,
UpdatableApiResource,
DestroyableApiResource,
)
from nylas.models.contacts import (
Contact,
CreateContactRequest,
UpdateContactRequest,
ListContactsQueryParams,
FindContactQueryParams,
ListContactGroupsQueryParams,
ContactGroup,
)
from nylas.models.response import Response, ListResponse, DeleteResponse


class Contacts(
ListableApiResource,
FindableApiResource,
CreatableApiResource,
UpdatableApiResource,
DestroyableApiResource,
):
def list(
self, identifier: str, query_params: ListContactsQueryParams = None
) -> ListResponse[Contact]:
"""
Return all Contacts.

Attributes:
identifier: The identifier of the Grant to act upon.
query_params: The query parameters to include in the request.

Returns:
The list of contacts.
"""

return super(Contacts, self).list(
path=f"/v3/grants/{identifier}/contacts",
query_params=query_params,
response_type=Contact,
)

def find(
self,
identifier: str,
contact_id: str,
query_params: FindContactQueryParams = None,
) -> Response[Contact]:
"""
Return a Contact.

Attributes:
identifier: The identifier of the Grant to act upon.
contact_id: The ID of the contact to retrieve.
query_params: The query parameters to include in the request.

Returns:
The Contact.
"""
return super(Contacts, self).find(
path=f"/v3/grants/{identifier}/contacts/{contact_id}",
response_type=Contact,
query_params=query_params,
)

def create(
self, identifier: str, request_body: CreateContactRequest
) -> Response[Contact]:
"""
Create a Contact.

Attributes:
identifier: The identifier of the Grant to act upon.
request_body: The values to create the Contact with.

Returns:
The created Contact.
"""
return super(Contacts, self).create(
path=f"/v3/grants/{identifier}/contacts",
response_type=Contact,
request_body=request_body,
)

def update(
self, identifier: str, contact_id: str, request_body: UpdateContactRequest
) -> Response[Contact]:
"""
Update a Contact.

Attributes:
identifier: The identifier of the Grant to act upon.
contact_id: The ID of the Contact to update. Use "primary" to refer to the primary Contact associated with the Grant.
request_body: The values to update the Contact with.

Returns:
The updated Contact.
"""
return super(Contacts, self).update(
path=f"/v3/grants/{identifier}/contacts/{contact_id}",
response_type=Contact,
request_body=request_body,
)

def destroy(self, identifier: str, contact_id: str) -> DeleteResponse:
"""
Delete a Contact.

Attributes:
identifier: The identifier of the Grant to act upon.
contact_id: The ID of the Contact to delete. Use "primary" to refer to the primary Contact associated with the Grant.

Returns:
The deletion response.
"""
return super(Contacts, self).destroy(
path=f"/v3/grants/{identifier}/contacts/{contact_id}"
)

def list_groups(
self, identifier: str, query_params: ListContactGroupsQueryParams = None
) -> ListResponse[ContactGroup]:
"""
Return all contact groups.

Attributes:
identifier: The identifier of the Grant to act upon.
query_params: The query parameters to include in the request.

Returns:
The list of contact groups.
"""
json_response = self._http_client._execute(
method="GET",
path=f"/v3/grants/{identifier}/contacts/groups",
query_params=query_params,
)

return ListResponse.from_dict(json_response, ContactGroup)