Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 40 additions & 77 deletions src/lettermint/endpoints/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,44 +138,6 @@ def rotate_token(self, project_id: str) -> lm_types.ProjectRotateTokenResponse:
),
)

def update_members(
self, project_id: str, data: lm_types.ProjectUpdateMembersRequest
) -> lm_types.ProjectUpdateMembersResponse:
return cast(
lm_types.ProjectUpdateMembersResponse,
self._client.put(
self._path("/projects/{projectId}/members", projectId=project_id),
data=data,
),
)

def add_member(self, project_id: str, team_member_id: str) -> lm_types.ProjectAddMemberResponse:
return cast(
lm_types.ProjectAddMemberResponse,
self._client.post(
self._path(
"/projects/{projectId}/members/{teamMemberId}",
projectId=project_id,
teamMemberId=team_member_id,
),
data={},
),
)

def remove_member(
self, project_id: str, team_member_id: str
) -> lm_types.ProjectRemoveMemberResponse:
return cast(
lm_types.ProjectRemoveMemberResponse,
self._client.delete(
self._path(
"/projects/{projectId}/members/{teamMemberId}",
projectId=project_id,
teamMemberId=team_member_id,
)
),
)

def routes(self, project_id: str, query: Query | None = None) -> lm_types.RouteIndexResponse:
return cast(
lm_types.RouteIndexResponse,
Expand Down Expand Up @@ -263,9 +225,29 @@ def update(self, data: lm_types.TeamUpdateRequest) -> lm_types.TeamUpdateRespons
def usage(self) -> lm_types.TeamUsageResponse:
return cast(lm_types.TeamUsageResponse, self._client.get("/team/usage"))

def roles(self) -> lm_types.TeamRolesResponse:
return cast(lm_types.TeamRolesResponse, self._client.get("/team/roles"))

def members(self, query: Query | None = None) -> lm_types.TeamMembersResponse:
return cast(lm_types.TeamMembersResponse, self._client.get("/team/members", params=query))

def member(self, user_id: str) -> lm_types.TeamMembersShowResponse:
return cast(
lm_types.TeamMembersShowResponse,
self._client.get(self._path("/team/members/{userId}", userId=user_id)),
)

def update_member_assignment(
self, user_id: str, data: lm_types.TeamMembersAssignmentUpdateRequest
) -> lm_types.TeamMembersAssignmentUpdateResponse:
return cast(
lm_types.TeamMembersAssignmentUpdateResponse,
self._client.put(
self._path("/team/members/{userId}/assignment", userId=user_id),
data=data,
),
)


class WebhooksEndpoint(Endpoint):
def list(self, query: Query | None = None) -> lm_types.WebhookIndexResponse:
Expand Down Expand Up @@ -481,45 +463,6 @@ async def rotate_token(self, project_id: str) -> lm_types.ProjectRotateTokenResp
),
)

async def update_members(
self, project_id: str, data: lm_types.ProjectUpdateMembersRequest
) -> lm_types.ProjectUpdateMembersResponse:
return cast(
lm_types.ProjectUpdateMembersResponse,
await self._client.put(
self._path("/projects/{projectId}/members", projectId=project_id), data=data
),
)

async def add_member(
self, project_id: str, team_member_id: str
) -> lm_types.ProjectAddMemberResponse:
return cast(
lm_types.ProjectAddMemberResponse,
await self._client.post(
self._path(
"/projects/{projectId}/members/{teamMemberId}",
projectId=project_id,
teamMemberId=team_member_id,
),
data={},
),
)

async def remove_member(
self, project_id: str, team_member_id: str
) -> lm_types.ProjectRemoveMemberResponse:
return cast(
lm_types.ProjectRemoveMemberResponse,
await self._client.delete(
self._path(
"/projects/{projectId}/members/{teamMemberId}",
projectId=project_id,
teamMemberId=team_member_id,
)
),
)

async def routes(
self, project_id: str, query: Query | None = None
) -> lm_types.RouteIndexResponse:
Expand Down Expand Up @@ -612,11 +555,31 @@ async def update(self, data: lm_types.TeamUpdateRequest) -> lm_types.TeamUpdateR
async def usage(self) -> lm_types.TeamUsageResponse:
return cast(lm_types.TeamUsageResponse, await self._client.get("/team/usage"))

async def roles(self) -> lm_types.TeamRolesResponse:
return cast(lm_types.TeamRolesResponse, await self._client.get("/team/roles"))

async def members(self, query: Query | None = None) -> lm_types.TeamMembersResponse:
return cast(
lm_types.TeamMembersResponse, await self._client.get("/team/members", params=query)
)

async def member(self, user_id: str) -> lm_types.TeamMembersShowResponse:
return cast(
lm_types.TeamMembersShowResponse,
await self._client.get(self._path("/team/members/{userId}", userId=user_id)),
)

async def update_member_assignment(
self, user_id: str, data: lm_types.TeamMembersAssignmentUpdateRequest
) -> lm_types.TeamMembersAssignmentUpdateResponse:
return cast(
lm_types.TeamMembersAssignmentUpdateResponse,
await self._client.put(
self._path("/team/members/{userId}/assignment", userId=user_id),
data=data,
),
)


class AsyncWebhooksEndpoint(AsyncEndpoint):
async def list(self, query: Query | None = None) -> lm_types.WebhookIndexResponse:
Expand Down
50 changes: 44 additions & 6 deletions src/lettermint/endpoints/email.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
else:
from typing_extensions import Self

from ..types import SendBatchEmailResponse, SendEmailResponse
from ..types import SendBatchEmailResponse, SendBatchMailRequest, SendEmailResponse, TlsPolicy
from .endpoint import AsyncEndpoint, Endpoint

if TYPE_CHECKING:
Expand Down Expand Up @@ -207,13 +207,15 @@ def attach(
filename: str,
content: str,
content_id: str | None = None,
content_type: str | None = None,
) -> Self:
"""Attach a file to the email.

Args:
filename: The attachment filename.
content: The base64-encoded file content.
content_id: Optional Content-ID for inline attachments.
content_type: Optional MIME type for the attachment.

Returns:
The current instance for method chaining.
Expand All @@ -233,10 +235,17 @@ def attach(
}
if content_id is not None:
attachment["content_id"] = content_id
if content_type is not None:
attachment["content_type"] = content_type

self._payload["attachments"].append(attachment)
return self

def settings(self, settings: dict[str, bool | TlsPolicy]) -> Self:
"""Set per-email settings that override the selected route."""
self._payload["settings"] = settings
return self

def metadata(self, metadata: dict[str, str]) -> Self:
"""Set metadata for the email.

Expand Down Expand Up @@ -297,10 +306,21 @@ def send(self) -> SendEmailResponse:
finally:
self._reset()

def send_batch(self, payload: list[dict[str, Any]]) -> SendBatchEmailResponse:
def send_batch(self, payload: SendBatchMailRequest) -> SendBatchEmailResponse:
"""Send multiple emails in one batch."""
response: SendBatchEmailResponse = self._client.post("/send/batch", data=payload)
return response
headers: dict[str, str] | None = None
if self._idempotency_key is not None:
headers = {"Idempotency-Key": self._idempotency_key}

try:
response: SendBatchEmailResponse = self._client.post(
"/send/batch",
data=payload,
headers=headers,
)
return response
finally:
self._reset()

def ping(self) -> str:
"""Ping the Sending API."""
Expand Down Expand Up @@ -478,13 +498,15 @@ def attach(
filename: str,
content: str,
content_id: str | None = None,
content_type: str | None = None,
) -> Self:
"""Attach a file to the email.

Args:
filename: The attachment filename.
content: The base64-encoded file content.
content_id: Optional Content-ID for inline attachments.
content_type: Optional MIME type for the attachment.

Returns:
The current instance for method chaining.
Expand All @@ -498,10 +520,17 @@ def attach(
}
if content_id is not None:
attachment["content_id"] = content_id
if content_type is not None:
attachment["content_type"] = content_type

self._payload["attachments"].append(attachment)
return self

def settings(self, settings: dict[str, bool | TlsPolicy]) -> Self:
"""Set per-email settings that override the selected route."""
self._payload["settings"] = settings
return self

def metadata(self, metadata: dict[str, str]) -> Self:
"""Set metadata for the email.

Expand Down Expand Up @@ -554,9 +583,18 @@ async def _send() -> SendEmailResponse:

return _send()

async def send_batch(self, payload: list[dict[str, Any]]) -> SendBatchEmailResponse:
async def send_batch(self, payload: SendBatchMailRequest) -> SendBatchEmailResponse:
"""Send multiple emails in one batch asynchronously."""
response: SendBatchEmailResponse = await self._client.post("/send/batch", data=payload)
headers: dict[str, str] | None = None
if self._idempotency_key is not None:
headers = {"Idempotency-Key": self._idempotency_key}
self._reset()

response: SendBatchEmailResponse = await self._client.post(
"/send/batch",
data=payload,
headers=headers,
)
return response

async def ping(self) -> str:
Expand Down
Loading