From d07c7c9e040c1cc098ecfbc7b0cf30355b9f37b3 Mon Sep 17 00:00:00 2001 From: "Joseph T. French" Date: Sun, 2 Aug 2026 23:57:41 -0500 Subject: [PATCH] feat(sdk): regenerate for multi-user orgs Picks up org invitations, graph membership, and per-user repository subscriptions from the API. - new: create_org_invitation, list_org_invitations, revoke_org_invitation, resend_org_invitation, get_invitation_preview - new: graph_members module (list, add, update role, remove) with the GraphRole enum - removed: invite_org_member, whose endpoint was a 501 stub and is replaced by the invitation flow - RegisterRequest gains invite_token; subscription responses expose the subscribing member, and cancel/plan-change accept a target user_id --- .../api/auth/get_invitation_preview.py | 189 ++++++++++++++ .../api/graph_members/__init__.py | 1 + .../api/graph_members/add_graph_member.py | 221 ++++++++++++++++ .../api/graph_members/list_graph_members.py | 204 +++++++++++++++ .../api/graph_members/remove_graph_member.py | 212 ++++++++++++++++ .../graph_members/update_graph_member_role.py | 239 ++++++++++++++++++ .../api/org_members/create_org_invitation.py | 239 ++++++++++++++++++ .../api/org_members/list_org_invitations.py | 200 +++++++++++++++ ...org_member.py => resend_org_invitation.py} | 89 +++---- .../api/org_members/revoke_org_invitation.py | 212 ++++++++++++++++ .../cancel_repository_subscription.py | 24 +- robosystems_client/models/__init__.py | 22 +- .../models/add_graph_member_request.py | 81 ++++++ .../models/cancel_subscription_request.py | 21 ++ ...equest.py => create_invitation_request.py} | 48 ++-- .../models/graph_member_list_response.py | 92 +++++++ .../models/graph_member_response.py | 130 ++++++++++ .../models/graph_member_response_source.py | 9 + robosystems_client/models/graph_role.py | 10 + .../models/graph_subscription_response.py | 21 ++ .../models/invitation_preview_response.py | 89 +++++++ .../models/org_invitation_list_response.py | 92 +++++++ .../models/org_invitation_response.py | 143 +++++++++++ robosystems_client/models/register_request.py | 21 ++ .../update_graph_member_role_request.py | 64 +++++ .../models/upgrade_subscription_request.py | 25 +- 26 files changed, 2604 insertions(+), 94 deletions(-) create mode 100644 robosystems_client/api/auth/get_invitation_preview.py create mode 100644 robosystems_client/api/graph_members/__init__.py create mode 100644 robosystems_client/api/graph_members/add_graph_member.py create mode 100644 robosystems_client/api/graph_members/list_graph_members.py create mode 100644 robosystems_client/api/graph_members/remove_graph_member.py create mode 100644 robosystems_client/api/graph_members/update_graph_member_role.py create mode 100644 robosystems_client/api/org_members/create_org_invitation.py create mode 100644 robosystems_client/api/org_members/list_org_invitations.py rename robosystems_client/api/org_members/{invite_org_member.py => resend_org_invitation.py} (63%) create mode 100644 robosystems_client/api/org_members/revoke_org_invitation.py create mode 100644 robosystems_client/models/add_graph_member_request.py rename robosystems_client/models/{invite_member_request.py => create_invitation_request.py} (58%) create mode 100644 robosystems_client/models/graph_member_list_response.py create mode 100644 robosystems_client/models/graph_member_response.py create mode 100644 robosystems_client/models/graph_member_response_source.py create mode 100644 robosystems_client/models/graph_role.py create mode 100644 robosystems_client/models/invitation_preview_response.py create mode 100644 robosystems_client/models/org_invitation_list_response.py create mode 100644 robosystems_client/models/org_invitation_response.py create mode 100644 robosystems_client/models/update_graph_member_role_request.py diff --git a/robosystems_client/api/auth/get_invitation_preview.py b/robosystems_client/api/auth/get_invitation_preview.py new file mode 100644 index 0000000..2773c82 --- /dev/null +++ b/robosystems_client/api/auth/get_invitation_preview.py @@ -0,0 +1,189 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.http_validation_error import HTTPValidationError +from ...models.invitation_preview_response import InvitationPreviewResponse +from ...types import Response + + +def _get_kwargs( + token: str, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/v1/auth/invitations/{token}".format( + token=quote(str(token), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ErrorResponse | HTTPValidationError | InvitationPreviewResponse | None: + if response.status_code == 200: + response_200 = InvitationPreviewResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ErrorResponse | HTTPValidationError | InvitationPreviewResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + token: str, + *, + client: AuthenticatedClient | Client, +) -> Response[ErrorResponse | HTTPValidationError | InvitationPreviewResponse]: + """Preview Invitation + + Look up a pending org invitation by its token so the registration page can show what is being + joined. Returns 404 for unknown, expired, revoked, or accepted tokens. + + Args: + token (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | HTTPValidationError | InvitationPreviewResponse] + """ + + kwargs = _get_kwargs( + token=token, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + token: str, + *, + client: AuthenticatedClient | Client, +) -> ErrorResponse | HTTPValidationError | InvitationPreviewResponse | None: + """Preview Invitation + + Look up a pending org invitation by its token so the registration page can show what is being + joined. Returns 404 for unknown, expired, revoked, or accepted tokens. + + Args: + token (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | HTTPValidationError | InvitationPreviewResponse + """ + + return sync_detailed( + token=token, + client=client, + ).parsed + + +async def asyncio_detailed( + token: str, + *, + client: AuthenticatedClient | Client, +) -> Response[ErrorResponse | HTTPValidationError | InvitationPreviewResponse]: + """Preview Invitation + + Look up a pending org invitation by its token so the registration page can show what is being + joined. Returns 404 for unknown, expired, revoked, or accepted tokens. + + Args: + token (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | HTTPValidationError | InvitationPreviewResponse] + """ + + kwargs = _get_kwargs( + token=token, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + token: str, + *, + client: AuthenticatedClient | Client, +) -> ErrorResponse | HTTPValidationError | InvitationPreviewResponse | None: + """Preview Invitation + + Look up a pending org invitation by its token so the registration page can show what is being + joined. Returns 404 for unknown, expired, revoked, or accepted tokens. + + Args: + token (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | HTTPValidationError | InvitationPreviewResponse + """ + + return ( + await asyncio_detailed( + token=token, + client=client, + ) + ).parsed diff --git a/robosystems_client/api/graph_members/__init__.py b/robosystems_client/api/graph_members/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/robosystems_client/api/graph_members/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/robosystems_client/api/graph_members/add_graph_member.py b/robosystems_client/api/graph_members/add_graph_member.py new file mode 100644 index 0000000..68e0003 --- /dev/null +++ b/robosystems_client/api/graph_members/add_graph_member.py @@ -0,0 +1,221 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.add_graph_member_request import AddGraphMemberRequest +from ...models.error_response import ErrorResponse +from ...models.graph_member_response import GraphMemberResponse +from ...models.http_validation_error import HTTPValidationError +from ...types import Response + + +def _get_kwargs( + graph_id: str, + *, + body: AddGraphMemberRequest, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/v1/graphs/{graph_id}/members".format( + graph_id=quote(str(graph_id), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ErrorResponse | GraphMemberResponse | HTTPValidationError | None: + if response.status_code == 201: + response_201 = GraphMemberResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ErrorResponse | GraphMemberResponse | HTTPValidationError]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: AddGraphMemberRequest, +) -> Response[ErrorResponse | GraphMemberResponse | HTTPValidationError]: + """Add Graph Member + + Grant a member of the graph's organization access at a chosen role. Requires graph admin. + + Args: + graph_id (str): Graph identifier + body (AddGraphMemberRequest): Request to grant an org member access to a graph. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | GraphMemberResponse | HTTPValidationError] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + *, + client: AuthenticatedClient, + body: AddGraphMemberRequest, +) -> ErrorResponse | GraphMemberResponse | HTTPValidationError | None: + """Add Graph Member + + Grant a member of the graph's organization access at a chosen role. Requires graph admin. + + Args: + graph_id (str): Graph identifier + body (AddGraphMemberRequest): Request to grant an org member access to a graph. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | GraphMemberResponse | HTTPValidationError + """ + + return sync_detailed( + graph_id=graph_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + *, + client: AuthenticatedClient, + body: AddGraphMemberRequest, +) -> Response[ErrorResponse | GraphMemberResponse | HTTPValidationError]: + """Add Graph Member + + Grant a member of the graph's organization access at a chosen role. Requires graph admin. + + Args: + graph_id (str): Graph identifier + body (AddGraphMemberRequest): Request to grant an org member access to a graph. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | GraphMemberResponse | HTTPValidationError] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + *, + client: AuthenticatedClient, + body: AddGraphMemberRequest, +) -> ErrorResponse | GraphMemberResponse | HTTPValidationError | None: + """Add Graph Member + + Grant a member of the graph's organization access at a chosen role. Requires graph admin. + + Args: + graph_id (str): Graph identifier + body (AddGraphMemberRequest): Request to grant an org member access to a graph. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | GraphMemberResponse | HTTPValidationError + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + client=client, + body=body, + ) + ).parsed diff --git a/robosystems_client/api/graph_members/list_graph_members.py b/robosystems_client/api/graph_members/list_graph_members.py new file mode 100644 index 0000000..0baccb5 --- /dev/null +++ b/robosystems_client/api/graph_members/list_graph_members.py @@ -0,0 +1,204 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.graph_member_list_response import GraphMemberListResponse +from ...models.http_validation_error import HTTPValidationError +from ...types import Response + + +def _get_kwargs( + graph_id: str, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/v1/graphs/{graph_id}/members".format( + graph_id=quote(str(graph_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ErrorResponse | GraphMemberListResponse | HTTPValidationError | None: + if response.status_code == 200: + response_200 = GraphMemberListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ErrorResponse | GraphMemberListResponse | HTTPValidationError]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + *, + client: AuthenticatedClient, +) -> Response[ErrorResponse | GraphMemberListResponse | HTTPValidationError]: + """List Graph Members + + All users with access to the graph: explicit grants plus org owners/admins who hold implicit admin. + Requires graph admin. + + Args: + graph_id (str): Graph identifier + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | GraphMemberListResponse | HTTPValidationError] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + *, + client: AuthenticatedClient, +) -> ErrorResponse | GraphMemberListResponse | HTTPValidationError | None: + """List Graph Members + + All users with access to the graph: explicit grants plus org owners/admins who hold implicit admin. + Requires graph admin. + + Args: + graph_id (str): Graph identifier + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | GraphMemberListResponse | HTTPValidationError + """ + + return sync_detailed( + graph_id=graph_id, + client=client, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + *, + client: AuthenticatedClient, +) -> Response[ErrorResponse | GraphMemberListResponse | HTTPValidationError]: + """List Graph Members + + All users with access to the graph: explicit grants plus org owners/admins who hold implicit admin. + Requires graph admin. + + Args: + graph_id (str): Graph identifier + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | GraphMemberListResponse | HTTPValidationError] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + *, + client: AuthenticatedClient, +) -> ErrorResponse | GraphMemberListResponse | HTTPValidationError | None: + """List Graph Members + + All users with access to the graph: explicit grants plus org owners/admins who hold implicit admin. + Requires graph admin. + + Args: + graph_id (str): Graph identifier + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | GraphMemberListResponse | HTTPValidationError + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + client=client, + ) + ).parsed diff --git a/robosystems_client/api/graph_members/remove_graph_member.py b/robosystems_client/api/graph_members/remove_graph_member.py new file mode 100644 index 0000000..a2a348c --- /dev/null +++ b/robosystems_client/api/graph_members/remove_graph_member.py @@ -0,0 +1,212 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.http_validation_error import HTTPValidationError +from ...types import Response + + +def _get_kwargs( + graph_id: str, + user_id: str, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/v1/graphs/{graph_id}/members/{user_id}".format( + graph_id=quote(str(graph_id), safe=""), + user_id=quote(str(user_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ErrorResponse | HTTPValidationError | None: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ErrorResponse | HTTPValidationError]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + user_id: str, + *, + client: AuthenticatedClient, +) -> Response[Any | ErrorResponse | HTTPValidationError]: + """Remove Graph Member + + Revoke an explicit member's access to the graph. Requires graph admin. + + Args: + graph_id (str): Graph identifier + user_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ErrorResponse | HTTPValidationError] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + user_id: str, + *, + client: AuthenticatedClient, +) -> Any | ErrorResponse | HTTPValidationError | None: + """Remove Graph Member + + Revoke an explicit member's access to the graph. Requires graph admin. + + Args: + graph_id (str): Graph identifier + user_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ErrorResponse | HTTPValidationError + """ + + return sync_detailed( + graph_id=graph_id, + user_id=user_id, + client=client, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + user_id: str, + *, + client: AuthenticatedClient, +) -> Response[Any | ErrorResponse | HTTPValidationError]: + """Remove Graph Member + + Revoke an explicit member's access to the graph. Requires graph admin. + + Args: + graph_id (str): Graph identifier + user_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ErrorResponse | HTTPValidationError] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + user_id: str, + *, + client: AuthenticatedClient, +) -> Any | ErrorResponse | HTTPValidationError | None: + """Remove Graph Member + + Revoke an explicit member's access to the graph. Requires graph admin. + + Args: + graph_id (str): Graph identifier + user_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ErrorResponse | HTTPValidationError + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + user_id=user_id, + client=client, + ) + ).parsed diff --git a/robosystems_client/api/graph_members/update_graph_member_role.py b/robosystems_client/api/graph_members/update_graph_member_role.py new file mode 100644 index 0000000..9b60c97 --- /dev/null +++ b/robosystems_client/api/graph_members/update_graph_member_role.py @@ -0,0 +1,239 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.graph_member_response import GraphMemberResponse +from ...models.http_validation_error import HTTPValidationError +from ...models.update_graph_member_role_request import UpdateGraphMemberRoleRequest +from ...types import Response + + +def _get_kwargs( + graph_id: str, + user_id: str, + *, + body: UpdateGraphMemberRoleRequest, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/v1/graphs/{graph_id}/members/{user_id}".format( + graph_id=quote(str(graph_id), safe=""), + user_id=quote(str(user_id), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ErrorResponse | GraphMemberResponse | HTTPValidationError | None: + if response.status_code == 200: + response_200 = GraphMemberResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ErrorResponse | GraphMemberResponse | HTTPValidationError]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + graph_id: str, + user_id: str, + *, + client: AuthenticatedClient, + body: UpdateGraphMemberRoleRequest, +) -> Response[ErrorResponse | GraphMemberResponse | HTTPValidationError]: + """Update Graph Member Role + + Change an explicit member's graph role. Requires graph admin. Implicit org owner/admin access is + managed through org roles. + + Args: + graph_id (str): Graph identifier + user_id (str): + body (UpdateGraphMemberRoleRequest): Request to change a graph member's role. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | GraphMemberResponse | HTTPValidationError] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + user_id=user_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + graph_id: str, + user_id: str, + *, + client: AuthenticatedClient, + body: UpdateGraphMemberRoleRequest, +) -> ErrorResponse | GraphMemberResponse | HTTPValidationError | None: + """Update Graph Member Role + + Change an explicit member's graph role. Requires graph admin. Implicit org owner/admin access is + managed through org roles. + + Args: + graph_id (str): Graph identifier + user_id (str): + body (UpdateGraphMemberRoleRequest): Request to change a graph member's role. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | GraphMemberResponse | HTTPValidationError + """ + + return sync_detailed( + graph_id=graph_id, + user_id=user_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + graph_id: str, + user_id: str, + *, + client: AuthenticatedClient, + body: UpdateGraphMemberRoleRequest, +) -> Response[ErrorResponse | GraphMemberResponse | HTTPValidationError]: + """Update Graph Member Role + + Change an explicit member's graph role. Requires graph admin. Implicit org owner/admin access is + managed through org roles. + + Args: + graph_id (str): Graph identifier + user_id (str): + body (UpdateGraphMemberRoleRequest): Request to change a graph member's role. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | GraphMemberResponse | HTTPValidationError] + """ + + kwargs = _get_kwargs( + graph_id=graph_id, + user_id=user_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + graph_id: str, + user_id: str, + *, + client: AuthenticatedClient, + body: UpdateGraphMemberRoleRequest, +) -> ErrorResponse | GraphMemberResponse | HTTPValidationError | None: + """Update Graph Member Role + + Change an explicit member's graph role. Requires graph admin. Implicit org owner/admin access is + managed through org roles. + + Args: + graph_id (str): Graph identifier + user_id (str): + body (UpdateGraphMemberRoleRequest): Request to change a graph member's role. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | GraphMemberResponse | HTTPValidationError + """ + + return ( + await asyncio_detailed( + graph_id=graph_id, + user_id=user_id, + client=client, + body=body, + ) + ).parsed diff --git a/robosystems_client/api/org_members/create_org_invitation.py b/robosystems_client/api/org_members/create_org_invitation.py new file mode 100644 index 0000000..dd90464 --- /dev/null +++ b/robosystems_client/api/org_members/create_org_invitation.py @@ -0,0 +1,239 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.create_invitation_request import CreateInvitationRequest +from ...models.error_response import ErrorResponse +from ...models.http_validation_error import HTTPValidationError +from ...models.org_invitation_response import OrgInvitationResponse +from ...types import Response + + +def _get_kwargs( + org_id: str, + *, + body: CreateInvitationRequest, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/v1/orgs/{org_id}/invitations".format( + org_id=quote(str(org_id), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ErrorResponse | HTTPValidationError | OrgInvitationResponse | None: + if response.status_code == 201: + response_201 = OrgInvitationResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 409: + response_409 = ErrorResponse.from_dict(response.json()) + + return response_409 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if response.status_code == 501: + response_501 = ErrorResponse.from_dict(response.json()) + + return response_501 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ErrorResponse | HTTPValidationError | OrgInvitationResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + org_id: str, + *, + client: AuthenticatedClient, + body: CreateInvitationRequest, +) -> Response[ErrorResponse | HTTPValidationError | OrgInvitationResponse]: + """Invite Member + + Invite a new user to the organization by email. Disabled by default + (ORG_MEMBER_INVITATIONS_ENABLED=false); returns 501 when disabled. Requires admin or owner role. + Only emails without an existing account can be invited. + + Args: + org_id (str): + body (CreateInvitationRequest): Request to invite a new user to an organization by email. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | HTTPValidationError | OrgInvitationResponse] + """ + + kwargs = _get_kwargs( + org_id=org_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + org_id: str, + *, + client: AuthenticatedClient, + body: CreateInvitationRequest, +) -> ErrorResponse | HTTPValidationError | OrgInvitationResponse | None: + """Invite Member + + Invite a new user to the organization by email. Disabled by default + (ORG_MEMBER_INVITATIONS_ENABLED=false); returns 501 when disabled. Requires admin or owner role. + Only emails without an existing account can be invited. + + Args: + org_id (str): + body (CreateInvitationRequest): Request to invite a new user to an organization by email. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | HTTPValidationError | OrgInvitationResponse + """ + + return sync_detailed( + org_id=org_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + org_id: str, + *, + client: AuthenticatedClient, + body: CreateInvitationRequest, +) -> Response[ErrorResponse | HTTPValidationError | OrgInvitationResponse]: + """Invite Member + + Invite a new user to the organization by email. Disabled by default + (ORG_MEMBER_INVITATIONS_ENABLED=false); returns 501 when disabled. Requires admin or owner role. + Only emails without an existing account can be invited. + + Args: + org_id (str): + body (CreateInvitationRequest): Request to invite a new user to an organization by email. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | HTTPValidationError | OrgInvitationResponse] + """ + + kwargs = _get_kwargs( + org_id=org_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + org_id: str, + *, + client: AuthenticatedClient, + body: CreateInvitationRequest, +) -> ErrorResponse | HTTPValidationError | OrgInvitationResponse | None: + """Invite Member + + Invite a new user to the organization by email. Disabled by default + (ORG_MEMBER_INVITATIONS_ENABLED=false); returns 501 when disabled. Requires admin or owner role. + Only emails without an existing account can be invited. + + Args: + org_id (str): + body (CreateInvitationRequest): Request to invite a new user to an organization by email. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | HTTPValidationError | OrgInvitationResponse + """ + + return ( + await asyncio_detailed( + org_id=org_id, + client=client, + body=body, + ) + ).parsed diff --git a/robosystems_client/api/org_members/list_org_invitations.py b/robosystems_client/api/org_members/list_org_invitations.py new file mode 100644 index 0000000..23f8c93 --- /dev/null +++ b/robosystems_client/api/org_members/list_org_invitations.py @@ -0,0 +1,200 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.http_validation_error import HTTPValidationError +from ...models.org_invitation_list_response import OrgInvitationListResponse +from ...types import Response + + +def _get_kwargs( + org_id: str, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/v1/orgs/{org_id}/invitations".format( + org_id=quote(str(org_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ErrorResponse | HTTPValidationError | OrgInvitationListResponse | None: + if response.status_code == 200: + response_200 = OrgInvitationListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ErrorResponse | HTTPValidationError | OrgInvitationListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + org_id: str, + *, + client: AuthenticatedClient, +) -> Response[ErrorResponse | HTTPValidationError | OrgInvitationListResponse]: + """List Pending Invitations + + Requires admin or owner role. + + Args: + org_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | HTTPValidationError | OrgInvitationListResponse] + """ + + kwargs = _get_kwargs( + org_id=org_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + org_id: str, + *, + client: AuthenticatedClient, +) -> ErrorResponse | HTTPValidationError | OrgInvitationListResponse | None: + """List Pending Invitations + + Requires admin or owner role. + + Args: + org_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | HTTPValidationError | OrgInvitationListResponse + """ + + return sync_detailed( + org_id=org_id, + client=client, + ).parsed + + +async def asyncio_detailed( + org_id: str, + *, + client: AuthenticatedClient, +) -> Response[ErrorResponse | HTTPValidationError | OrgInvitationListResponse]: + """List Pending Invitations + + Requires admin or owner role. + + Args: + org_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ErrorResponse | HTTPValidationError | OrgInvitationListResponse] + """ + + kwargs = _get_kwargs( + org_id=org_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + org_id: str, + *, + client: AuthenticatedClient, +) -> ErrorResponse | HTTPValidationError | OrgInvitationListResponse | None: + """List Pending Invitations + + Requires admin or owner role. + + Args: + org_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ErrorResponse | HTTPValidationError | OrgInvitationListResponse + """ + + return ( + await asyncio_detailed( + org_id=org_id, + client=client, + ) + ).parsed diff --git a/robosystems_client/api/org_members/invite_org_member.py b/robosystems_client/api/org_members/resend_org_invitation.py similarity index 63% rename from robosystems_client/api/org_members/invite_org_member.py rename to robosystems_client/api/org_members/resend_org_invitation.py index ecf1d39..8beff68 100644 --- a/robosystems_client/api/org_members/invite_org_member.py +++ b/robosystems_client/api/org_members/resend_org_invitation.py @@ -8,40 +8,33 @@ from ...client import AuthenticatedClient, Client from ...models.error_response import ErrorResponse from ...models.http_validation_error import HTTPValidationError -from ...models.invite_member_request import InviteMemberRequest -from ...models.org_member_response import OrgMemberResponse +from ...models.org_invitation_response import OrgInvitationResponse from ...types import Response def _get_kwargs( org_id: str, - *, - body: InviteMemberRequest, + invitation_id: str, ) -> dict[str, Any]: - headers: dict[str, Any] = {} _kwargs: dict[str, Any] = { "method": "post", - "url": "/v1/orgs/{org_id}/members".format( + "url": "/v1/orgs/{org_id}/invitations/{invitation_id}/resend".format( org_id=quote(str(org_id), safe=""), + invitation_id=quote(str(invitation_id), safe=""), ), } - _kwargs["json"] = body.to_dict() - - headers["Content-Type"] = "application/json" - - _kwargs["headers"] = headers return _kwargs def _parse_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> ErrorResponse | HTTPValidationError | OrgMemberResponse | None: - if response.status_code == 201: - response_201 = OrgMemberResponse.from_dict(response.json()) +) -> ErrorResponse | HTTPValidationError | OrgInvitationResponse | None: + if response.status_code == 200: + response_200 = OrgInvitationResponse.from_dict(response.json()) - return response_201 + return response_200 if response.status_code == 400: response_400 = ErrorResponse.from_dict(response.json()) @@ -91,7 +84,7 @@ def _parse_response( def _build_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[ErrorResponse | HTTPValidationError | OrgMemberResponse]: +) -> Response[ErrorResponse | HTTPValidationError | OrgInvitationResponse]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, @@ -102,30 +95,30 @@ def _build_response( def sync_detailed( org_id: str, + invitation_id: str, *, client: AuthenticatedClient, - body: InviteMemberRequest, -) -> Response[ErrorResponse | HTTPValidationError | OrgMemberResponse]: - """Invite Member +) -> Response[ErrorResponse | HTTPValidationError | OrgInvitationResponse]: + """Resend Invitation - Disabled by default (ORG_MEMBER_INVITATIONS_ENABLED=false). Returns 501 when disabled. Requires - admin or owner role. + Requires admin or owner role. Rotates the invitation token, extends its expiry, and re-sends the + email. Args: org_id (str): - body (InviteMemberRequest): Request to invite a member to an organization. + invitation_id (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[ErrorResponse | HTTPValidationError | OrgMemberResponse] + Response[ErrorResponse | HTTPValidationError | OrgInvitationResponse] """ kwargs = _get_kwargs( org_id=org_id, - body=body, + invitation_id=invitation_id, ) response = client.get_httpx_client().request( @@ -137,60 +130,60 @@ def sync_detailed( def sync( org_id: str, + invitation_id: str, *, client: AuthenticatedClient, - body: InviteMemberRequest, -) -> ErrorResponse | HTTPValidationError | OrgMemberResponse | None: - """Invite Member +) -> ErrorResponse | HTTPValidationError | OrgInvitationResponse | None: + """Resend Invitation - Disabled by default (ORG_MEMBER_INVITATIONS_ENABLED=false). Returns 501 when disabled. Requires - admin or owner role. + Requires admin or owner role. Rotates the invitation token, extends its expiry, and re-sends the + email. Args: org_id (str): - body (InviteMemberRequest): Request to invite a member to an organization. + invitation_id (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - ErrorResponse | HTTPValidationError | OrgMemberResponse + ErrorResponse | HTTPValidationError | OrgInvitationResponse """ return sync_detailed( org_id=org_id, + invitation_id=invitation_id, client=client, - body=body, ).parsed async def asyncio_detailed( org_id: str, + invitation_id: str, *, client: AuthenticatedClient, - body: InviteMemberRequest, -) -> Response[ErrorResponse | HTTPValidationError | OrgMemberResponse]: - """Invite Member +) -> Response[ErrorResponse | HTTPValidationError | OrgInvitationResponse]: + """Resend Invitation - Disabled by default (ORG_MEMBER_INVITATIONS_ENABLED=false). Returns 501 when disabled. Requires - admin or owner role. + Requires admin or owner role. Rotates the invitation token, extends its expiry, and re-sends the + email. Args: org_id (str): - body (InviteMemberRequest): Request to invite a member to an organization. + invitation_id (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[ErrorResponse | HTTPValidationError | OrgMemberResponse] + Response[ErrorResponse | HTTPValidationError | OrgInvitationResponse] """ kwargs = _get_kwargs( org_id=org_id, - body=body, + invitation_id=invitation_id, ) response = await client.get_async_httpx_client().request(**kwargs) @@ -200,31 +193,31 @@ async def asyncio_detailed( async def asyncio( org_id: str, + invitation_id: str, *, client: AuthenticatedClient, - body: InviteMemberRequest, -) -> ErrorResponse | HTTPValidationError | OrgMemberResponse | None: - """Invite Member +) -> ErrorResponse | HTTPValidationError | OrgInvitationResponse | None: + """Resend Invitation - Disabled by default (ORG_MEMBER_INVITATIONS_ENABLED=false). Returns 501 when disabled. Requires - admin or owner role. + Requires admin or owner role. Rotates the invitation token, extends its expiry, and re-sends the + email. Args: org_id (str): - body (InviteMemberRequest): Request to invite a member to an organization. + invitation_id (str): Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - ErrorResponse | HTTPValidationError | OrgMemberResponse + ErrorResponse | HTTPValidationError | OrgInvitationResponse """ return ( await asyncio_detailed( org_id=org_id, + invitation_id=invitation_id, client=client, - body=body, ) ).parsed diff --git a/robosystems_client/api/org_members/revoke_org_invitation.py b/robosystems_client/api/org_members/revoke_org_invitation.py new file mode 100644 index 0000000..791790f --- /dev/null +++ b/robosystems_client/api/org_members/revoke_org_invitation.py @@ -0,0 +1,212 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.error_response import ErrorResponse +from ...models.http_validation_error import HTTPValidationError +from ...types import Response + + +def _get_kwargs( + org_id: str, + invitation_id: str, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/v1/orgs/{org_id}/invitations/{invitation_id}".format( + org_id=quote(str(org_id), safe=""), + invitation_id=quote(str(invitation_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ErrorResponse | HTTPValidationError | None: + if response.status_code == 204: + response_204 = cast(Any, None) + return response_204 + + if response.status_code == 400: + response_400 = ErrorResponse.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ErrorResponse.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ErrorResponse.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ErrorResponse.from_dict(response.json()) + + return response_404 + + if response.status_code == 422: + response_422 = HTTPValidationError.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = ErrorResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = ErrorResponse.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ErrorResponse | HTTPValidationError]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + org_id: str, + invitation_id: str, + *, + client: AuthenticatedClient, +) -> Response[Any | ErrorResponse | HTTPValidationError]: + """Revoke Invitation + + Requires admin or owner role. Only pending invitations can be revoked. + + Args: + org_id (str): + invitation_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ErrorResponse | HTTPValidationError] + """ + + kwargs = _get_kwargs( + org_id=org_id, + invitation_id=invitation_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + org_id: str, + invitation_id: str, + *, + client: AuthenticatedClient, +) -> Any | ErrorResponse | HTTPValidationError | None: + """Revoke Invitation + + Requires admin or owner role. Only pending invitations can be revoked. + + Args: + org_id (str): + invitation_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ErrorResponse | HTTPValidationError + """ + + return sync_detailed( + org_id=org_id, + invitation_id=invitation_id, + client=client, + ).parsed + + +async def asyncio_detailed( + org_id: str, + invitation_id: str, + *, + client: AuthenticatedClient, +) -> Response[Any | ErrorResponse | HTTPValidationError]: + """Revoke Invitation + + Requires admin or owner role. Only pending invitations can be revoked. + + Args: + org_id (str): + invitation_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ErrorResponse | HTTPValidationError] + """ + + kwargs = _get_kwargs( + org_id=org_id, + invitation_id=invitation_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + org_id: str, + invitation_id: str, + *, + client: AuthenticatedClient, +) -> Any | ErrorResponse | HTTPValidationError | None: + """Revoke Invitation + + Requires admin or owner role. Only pending invitations can be revoked. + + Args: + org_id (str): + invitation_id (str): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ErrorResponse | HTTPValidationError + """ + + return ( + await asyncio_detailed( + org_id=org_id, + invitation_id=invitation_id, + client=client, + ) + ).parsed diff --git a/robosystems_client/api/subscriptions/cancel_repository_subscription.py b/robosystems_client/api/subscriptions/cancel_repository_subscription.py index 043e89e..da779bf 100644 --- a/robosystems_client/api/subscriptions/cancel_repository_subscription.py +++ b/robosystems_client/api/subscriptions/cancel_repository_subscription.py @@ -106,9 +106,9 @@ def sync_detailed( Cancel a shared repository subscription. Two modes via the `immediate` flag: omit it (default `false`) to cancel at period end (access stays until the period closes); pass `true` with - `confirm=` to stop access right away. For user graphs, use `POST - /v1/graphs/{graph_id}/operations/delete-graph` — this endpoint rejects user graphs. Requires org - owner role. + `confirm=` to stop access right away. Members cancel their own subscription; org owners and + admins can cancel any member's by passing `user_id`. For user graphs, use `POST + /v1/graphs/{graph_id}/operations/delete-graph` — this endpoint rejects user graphs. Args: graph_id (str): Repository name (e.g., 'sec', 'industry') @@ -149,9 +149,9 @@ def sync( Cancel a shared repository subscription. Two modes via the `immediate` flag: omit it (default `false`) to cancel at period end (access stays until the period closes); pass `true` with - `confirm=` to stop access right away. For user graphs, use `POST - /v1/graphs/{graph_id}/operations/delete-graph` — this endpoint rejects user graphs. Requires org - owner role. + `confirm=` to stop access right away. Members cancel their own subscription; org owners and + admins can cancel any member's by passing `user_id`. For user graphs, use `POST + /v1/graphs/{graph_id}/operations/delete-graph` — this endpoint rejects user graphs. Args: graph_id (str): Repository name (e.g., 'sec', 'industry') @@ -187,9 +187,9 @@ async def asyncio_detailed( Cancel a shared repository subscription. Two modes via the `immediate` flag: omit it (default `false`) to cancel at period end (access stays until the period closes); pass `true` with - `confirm=` to stop access right away. For user graphs, use `POST - /v1/graphs/{graph_id}/operations/delete-graph` — this endpoint rejects user graphs. Requires org - owner role. + `confirm=` to stop access right away. Members cancel their own subscription; org owners and + admins can cancel any member's by passing `user_id`. For user graphs, use `POST + /v1/graphs/{graph_id}/operations/delete-graph` — this endpoint rejects user graphs. Args: graph_id (str): Repository name (e.g., 'sec', 'industry') @@ -228,9 +228,9 @@ async def asyncio( Cancel a shared repository subscription. Two modes via the `immediate` flag: omit it (default `false`) to cancel at period end (access stays until the period closes); pass `true` with - `confirm=` to stop access right away. For user graphs, use `POST - /v1/graphs/{graph_id}/operations/delete-graph` — this endpoint rejects user graphs. Requires org - owner role. + `confirm=` to stop access right away. Members cancel their own subscription; org owners and + admins can cancel any member's by passing `user_id`. For user graphs, use `POST + /v1/graphs/{graph_id}/operations/delete-graph` — this endpoint rejects user graphs. Args: graph_id (str): Repository name (e.g., 'sec', 'industry') diff --git a/robosystems_client/models/__init__.py b/robosystems_client/models/__init__.py index 0c7ddb0..dd0189f 100644 --- a/robosystems_client/models/__init__.py +++ b/robosystems_client/models/__init__.py @@ -1,6 +1,7 @@ """Contains all the data models used in inputs/outputs""" from .account_info import AccountInfo +from .add_graph_member_request import AddGraphMemberRequest from .add_publish_list_members_operation import AddPublishListMembersOperation from .analytical_statement_fact_row import AnalyticalStatementFactRow from .api_key_info import APIKeyInfo @@ -107,6 +108,7 @@ from .create_forecast_request import CreateForecastRequest from .create_forecast_request_scenario_kind import CreateForecastRequestScenarioKind from .create_graph_request import CreateGraphRequest +from .create_invitation_request import CreateInvitationRequest from .create_legacy_arm import CreateLegacyArm from .create_legacy_arm_block_type import CreateLegacyArmBlockType from .create_legacy_arm_payload import CreateLegacyArmPayload @@ -252,6 +254,9 @@ from .graph_capacity_response import GraphCapacityResponse from .graph_info import GraphInfo from .graph_limits_response import GraphLimitsResponse +from .graph_member_list_response import GraphMemberListResponse +from .graph_member_response import GraphMemberResponse +from .graph_member_response_source import GraphMemberResponseSource from .graph_metadata import GraphMetadata from .graph_metrics_response import GraphMetricsResponse from .graph_metrics_response_health_status import GraphMetricsResponseHealthStatus @@ -260,6 +265,7 @@ GraphMetricsResponseRelationshipCounts, ) from .graph_metrics_response_storage import GraphMetricsResponseStorage +from .graph_role import GraphRole from .graph_subscription_response import GraphSubscriptionResponse from .graph_subscription_tier import GraphSubscriptionTier from .graph_subscriptions import GraphSubscriptions @@ -284,7 +290,7 @@ from .initialize_ledger_request import InitializeLedgerRequest from .initialize_ledger_response import InitializeLedgerResponse from .instance_usage import InstanceUsage -from .invite_member_request import InviteMemberRequest +from .invitation_preview_response import InvitationPreviewResponse from .invoice import Invoice from .invoice_line_item import InvoiceLineItem from .invoices_response import InvoicesResponse @@ -582,6 +588,8 @@ from .org_detail_response_graphs_item import OrgDetailResponseGraphsItem from .org_detail_response_limits_type_0 import OrgDetailResponseLimitsType0 from .org_detail_response_members_item import OrgDetailResponseMembersItem +from .org_invitation_list_response import OrgInvitationListResponse +from .org_invitation_response import OrgInvitationResponse from .org_limits_response import OrgLimitsResponse from .org_limits_response_current_usage import OrgLimitsResponseCurrentUsage from .org_list_response import OrgListResponse @@ -801,6 +809,7 @@ from .update_forecast_request_scenario_kind_type_0 import ( UpdateForecastRequestScenarioKindType0, ) +from .update_graph_member_role_request import UpdateGraphMemberRoleRequest from .update_journal_entry_request import UpdateJournalEntryRequest from .update_journal_entry_request_type_type_0 import UpdateJournalEntryRequestTypeType0 from .update_legacy_arm import UpdateLegacyArm @@ -842,6 +851,7 @@ __all__ = ( "AccountInfo", + "AddGraphMemberRequest", "AddPublishListMembersOperation", "AnalyticalStatementFactRow", "APIKeyInfo", @@ -930,6 +940,7 @@ "CreateForecastRequest", "CreateForecastRequestScenarioKind", "CreateGraphRequest", + "CreateInvitationRequest", "CreateLegacyArm", "CreateLegacyArmBlockType", "CreateLegacyArmPayload", @@ -1049,12 +1060,16 @@ "GraphCapacityResponse", "GraphInfo", "GraphLimitsResponse", + "GraphMemberListResponse", + "GraphMemberResponse", + "GraphMemberResponseSource", "GraphMetadata", "GraphMetricsResponse", "GraphMetricsResponseHealthStatus", "GraphMetricsResponseNodeCounts", "GraphMetricsResponseRelationshipCounts", "GraphMetricsResponseStorage", + "GraphRole", "GraphSubscriptionResponse", "GraphSubscriptions", "GraphSubscriptionTier", @@ -1077,7 +1092,7 @@ "InitializeLedgerRequest", "InitializeLedgerResponse", "InstanceUsage", - "InviteMemberRequest", + "InvitationPreviewResponse", "Invoice", "InvoiceLineItem", "InvoicesResponse", @@ -1229,6 +1244,8 @@ "OrgDetailResponseGraphsItem", "OrgDetailResponseLimitsType0", "OrgDetailResponseMembersItem", + "OrgInvitationListResponse", + "OrgInvitationResponse", "OrgLimitsResponse", "OrgLimitsResponseCurrentUsage", "OrgListResponse", @@ -1400,6 +1417,7 @@ "UpdateForecastArm", "UpdateForecastRequest", "UpdateForecastRequestScenarioKindType0", + "UpdateGraphMemberRoleRequest", "UpdateJournalEntryRequest", "UpdateJournalEntryRequestTypeType0", "UpdateLegacyArm", diff --git a/robosystems_client/models/add_graph_member_request.py b/robosystems_client/models/add_graph_member_request.py new file mode 100644 index 0000000..57625b3 --- /dev/null +++ b/robosystems_client/models/add_graph_member_request.py @@ -0,0 +1,81 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.graph_role import GraphRole +from ..types import UNSET, Unset + +T = TypeVar("T", bound="AddGraphMemberRequest") + + +@_attrs_define +class AddGraphMemberRequest: + """Request to grant an org member access to a graph. + + Attributes: + user_id (str): User to grant access to (must belong to the graph's organization) + role (GraphRole | Unset): Ordered per-graph roles: viewer < member < admin. + """ + + user_id: str + role: GraphRole | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + user_id = self.user_id + + role: str | Unset = UNSET + if not isinstance(self.role, Unset): + role = self.role.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "user_id": user_id, + } + ) + if role is not UNSET: + field_dict["role"] = role + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + user_id = d.pop("user_id") + + _role = d.pop("role", UNSET) + role: GraphRole | Unset + if isinstance(_role, Unset): + role = UNSET + else: + role = GraphRole(_role) + + add_graph_member_request = cls( + user_id=user_id, + role=role, + ) + + add_graph_member_request.additional_properties = d + return add_graph_member_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/cancel_subscription_request.py b/robosystems_client/models/cancel_subscription_request.py index 76bf05e..e43468f 100644 --- a/robosystems_client/models/cancel_subscription_request.py +++ b/robosystems_client/models/cancel_subscription_request.py @@ -26,10 +26,13 @@ class CancelSubscriptionRequest: False. confirm (None | str | Unset): Required when immediate=True. Must equal the subscription's resource_id (e.g. graph_id) to confirm intent. + user_id (None | str | Unset): Organization member whose subscription to cancel. Defaults to the caller; + canceling another member's requires org owner or admin. """ immediate: bool | Unset = False confirm: None | str | Unset = UNSET + user_id: None | str | Unset = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: @@ -41,6 +44,12 @@ def to_dict(self) -> dict[str, Any]: else: confirm = self.confirm + user_id: None | str | Unset + if isinstance(self.user_id, Unset): + user_id = UNSET + else: + user_id = self.user_id + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update({}) @@ -48,6 +57,8 @@ def to_dict(self) -> dict[str, Any]: field_dict["immediate"] = immediate if confirm is not UNSET: field_dict["confirm"] = confirm + if user_id is not UNSET: + field_dict["user_id"] = user_id return field_dict @@ -65,9 +76,19 @@ def _parse_confirm(data: object) -> None | str | Unset: confirm = _parse_confirm(d.pop("confirm", UNSET)) + def _parse_user_id(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + user_id = _parse_user_id(d.pop("user_id", UNSET)) + cancel_subscription_request = cls( immediate=immediate, confirm=confirm, + user_id=user_id, ) cancel_subscription_request.additional_properties = d diff --git a/robosystems_client/models/invite_member_request.py b/robosystems_client/models/create_invitation_request.py similarity index 58% rename from robosystems_client/models/invite_member_request.py rename to robosystems_client/models/create_invitation_request.py index 9a0446c..2a8dd8b 100644 --- a/robosystems_client/models/invite_member_request.py +++ b/robosystems_client/models/create_invitation_request.py @@ -1,7 +1,7 @@ from __future__ import annotations from collections.abc import Mapping -from typing import Any, TypeVar, cast +from typing import Any, TypeVar from attrs import define as _attrs_define from attrs import field as _attrs_field @@ -9,32 +9,28 @@ from ..models.org_role import OrgRole from ..types import UNSET, Unset -T = TypeVar("T", bound="InviteMemberRequest") +T = TypeVar("T", bound="CreateInvitationRequest") @_attrs_define -class InviteMemberRequest: - """Request to invite a member to an organization. +class CreateInvitationRequest: + """Request to invite a new user to an organization by email. Attributes: email (str): - role (None | OrgRole | Unset): Default: OrgRole.MEMBER. + role (OrgRole | Unset): """ email: str - role: None | OrgRole | Unset = OrgRole.MEMBER + role: OrgRole | Unset = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: email = self.email - role: None | str | Unset - if isinstance(self.role, Unset): - role = UNSET - elif isinstance(self.role, OrgRole): + role: str | Unset = UNSET + if not isinstance(self.role, Unset): role = self.role.value - else: - role = self.role field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) @@ -53,30 +49,20 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: d = dict(src_dict) email = d.pop("email") - def _parse_role(data: object) -> None | OrgRole | Unset: - if data is None: - return data - if isinstance(data, Unset): - return data - try: - if not isinstance(data, str): - raise TypeError() - role_type_0 = OrgRole(data) - - return role_type_0 - except (TypeError, ValueError, AttributeError, KeyError): - pass - return cast(None | OrgRole | Unset, data) - - role = _parse_role(d.pop("role", UNSET)) + _role = d.pop("role", UNSET) + role: OrgRole | Unset + if isinstance(_role, Unset): + role = UNSET + else: + role = OrgRole(_role) - invite_member_request = cls( + create_invitation_request = cls( email=email, role=role, ) - invite_member_request.additional_properties = d - return invite_member_request + create_invitation_request.additional_properties = d + return create_invitation_request @property def additional_keys(self) -> list[str]: diff --git a/robosystems_client/models/graph_member_list_response.py b/robosystems_client/models/graph_member_list_response.py new file mode 100644 index 0000000..b3cc127 --- /dev/null +++ b/robosystems_client/models/graph_member_list_response.py @@ -0,0 +1,92 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.graph_member_response import GraphMemberResponse + + +T = TypeVar("T", bound="GraphMemberListResponse") + + +@_attrs_define +class GraphMemberListResponse: + """All users with access to a graph. + + Attributes: + members (list[GraphMemberResponse]): + total (int): + graph_id (str): + """ + + members: list[GraphMemberResponse] + total: int + graph_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + members = [] + for members_item_data in self.members: + members_item = members_item_data.to_dict() + members.append(members_item) + + total = self.total + + graph_id = self.graph_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "members": members, + "total": total, + "graph_id": graph_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.graph_member_response import GraphMemberResponse + + d = dict(src_dict) + members = [] + _members = d.pop("members") + for members_item_data in _members: + members_item = GraphMemberResponse.from_dict(members_item_data) + + members.append(members_item) + + total = d.pop("total") + + graph_id = d.pop("graph_id") + + graph_member_list_response = cls( + members=members, + total=total, + graph_id=graph_id, + ) + + graph_member_list_response.additional_properties = d + return graph_member_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/graph_member_response.py b/robosystems_client/models/graph_member_response.py new file mode 100644 index 0000000..0b28eaf --- /dev/null +++ b/robosystems_client/models/graph_member_response.py @@ -0,0 +1,130 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.graph_member_response_source import GraphMemberResponseSource +from ..models.graph_role import GraphRole +from ..types import UNSET, Unset + +T = TypeVar("T", bound="GraphMemberResponse") + + +@_attrs_define +class GraphMemberResponse: + """A user with access to a graph. + + Attributes: + user_id (str): + name (str): + email (str): + role (GraphRole): Ordered per-graph roles: viewer < member < admin. + source (GraphMemberResponseSource): 'explicit' for a direct grant; 'org_role' for implicit admin held by org + owners/admins + granted_at (datetime.datetime | None | Unset): When the explicit grant was created (null for implicit access) + """ + + user_id: str + name: str + email: str + role: GraphRole + source: GraphMemberResponseSource + granted_at: datetime.datetime | None | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + user_id = self.user_id + + name = self.name + + email = self.email + + role = self.role.value + + source = self.source.value + + granted_at: None | str | Unset + if isinstance(self.granted_at, Unset): + granted_at = UNSET + elif isinstance(self.granted_at, datetime.datetime): + granted_at = self.granted_at.isoformat() + else: + granted_at = self.granted_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "user_id": user_id, + "name": name, + "email": email, + "role": role, + "source": source, + } + ) + if granted_at is not UNSET: + field_dict["granted_at"] = granted_at + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + user_id = d.pop("user_id") + + name = d.pop("name") + + email = d.pop("email") + + role = GraphRole(d.pop("role")) + + source = GraphMemberResponseSource(d.pop("source")) + + def _parse_granted_at(data: object) -> datetime.datetime | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + granted_at_type_0 = datetime.datetime.fromisoformat(data) + + return granted_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None | Unset, data) + + granted_at = _parse_granted_at(d.pop("granted_at", UNSET)) + + graph_member_response = cls( + user_id=user_id, + name=name, + email=email, + role=role, + source=source, + granted_at=granted_at, + ) + + graph_member_response.additional_properties = d + return graph_member_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/graph_member_response_source.py b/robosystems_client/models/graph_member_response_source.py new file mode 100644 index 0000000..38d19de --- /dev/null +++ b/robosystems_client/models/graph_member_response_source.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class GraphMemberResponseSource(str, Enum): + EXPLICIT = "explicit" + ORG_ROLE = "org_role" + + def __str__(self) -> str: + return str(self.value) diff --git a/robosystems_client/models/graph_role.py b/robosystems_client/models/graph_role.py new file mode 100644 index 0000000..f9ef9a3 --- /dev/null +++ b/robosystems_client/models/graph_role.py @@ -0,0 +1,10 @@ +from enum import Enum + + +class GraphRole(str, Enum): + ADMIN = "admin" + MEMBER = "member" + VIEWER = "viewer" + + def __str__(self) -> str: + return str(self.value) diff --git a/robosystems_client/models/graph_subscription_response.py b/robosystems_client/models/graph_subscription_response.py index e45515a..e993bc8 100644 --- a/robosystems_client/models/graph_subscription_response.py +++ b/robosystems_client/models/graph_subscription_response.py @@ -25,6 +25,8 @@ class GraphSubscriptionResponse: status (str): Subscription status base_price_cents (int): Base price in cents created_at (str): Creation timestamp + user_id (None | str | Unset): Organization member the subscription belongs to. Set for repository subscriptions, + which are billed to the org but granted per user. current_period_start (None | str | Unset): Current billing period start current_period_end (None | str | Unset): Current billing period end started_at (None | str | Unset): Subscription start date @@ -43,6 +45,7 @@ class GraphSubscriptionResponse: status: str base_price_cents: int created_at: str + user_id: None | str | Unset = UNSET current_period_start: None | str | Unset = UNSET current_period_end: None | str | Unset = UNSET started_at: None | str | Unset = UNSET @@ -70,6 +73,12 @@ def to_dict(self) -> dict[str, Any]: created_at = self.created_at + user_id: None | str | Unset + if isinstance(self.user_id, Unset): + user_id = UNSET + else: + user_id = self.user_id + current_period_start: None | str | Unset if isinstance(self.current_period_start, Unset): current_period_start = UNSET @@ -121,6 +130,8 @@ def to_dict(self) -> dict[str, Any]: "created_at": created_at, } ) + if user_id is not UNSET: + field_dict["user_id"] = user_id if current_period_start is not UNSET: field_dict["current_period_start"] = current_period_start if current_period_end is not UNSET: @@ -157,6 +168,15 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: created_at = d.pop("created_at") + def _parse_user_id(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + user_id = _parse_user_id(d.pop("user_id", UNSET)) + def _parse_current_period_start(data: object) -> None | str | Unset: if data is None: return data @@ -223,6 +243,7 @@ def _parse_operation_id(data: object) -> None | str | Unset: status=status, base_price_cents=base_price_cents, created_at=created_at, + user_id=user_id, current_period_start=current_period_start, current_period_end=current_period_end, started_at=started_at, diff --git a/robosystems_client/models/invitation_preview_response.py b/robosystems_client/models/invitation_preview_response.py new file mode 100644 index 0000000..7e27c04 --- /dev/null +++ b/robosystems_client/models/invitation_preview_response.py @@ -0,0 +1,89 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.org_role import OrgRole + +T = TypeVar("T", bound="InvitationPreviewResponse") + + +@_attrs_define +class InvitationPreviewResponse: + """Public preview of an invitation, looked up by its token. + + Attributes: + org_name (str): + email (str): + role (OrgRole): + expires_at (datetime.datetime): + """ + + org_name: str + email: str + role: OrgRole + expires_at: datetime.datetime + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + org_name = self.org_name + + email = self.email + + role = self.role.value + + expires_at = self.expires_at.isoformat() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "org_name": org_name, + "email": email, + "role": role, + "expires_at": expires_at, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + org_name = d.pop("org_name") + + email = d.pop("email") + + role = OrgRole(d.pop("role")) + + expires_at = datetime.datetime.fromisoformat(d.pop("expires_at")) + + invitation_preview_response = cls( + org_name=org_name, + email=email, + role=role, + expires_at=expires_at, + ) + + invitation_preview_response.additional_properties = d + return invitation_preview_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/org_invitation_list_response.py b/robosystems_client/models/org_invitation_list_response.py new file mode 100644 index 0000000..2ef23e5 --- /dev/null +++ b/robosystems_client/models/org_invitation_list_response.py @@ -0,0 +1,92 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.org_invitation_response import OrgInvitationResponse + + +T = TypeVar("T", bound="OrgInvitationListResponse") + + +@_attrs_define +class OrgInvitationListResponse: + """List of pending organization invitations response. + + Attributes: + invitations (list[OrgInvitationResponse]): + total (int): + org_id (str): + """ + + invitations: list[OrgInvitationResponse] + total: int + org_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + invitations = [] + for invitations_item_data in self.invitations: + invitations_item = invitations_item_data.to_dict() + invitations.append(invitations_item) + + total = self.total + + org_id = self.org_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "invitations": invitations, + "total": total, + "org_id": org_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.org_invitation_response import OrgInvitationResponse + + d = dict(src_dict) + invitations = [] + _invitations = d.pop("invitations") + for invitations_item_data in _invitations: + invitations_item = OrgInvitationResponse.from_dict(invitations_item_data) + + invitations.append(invitations_item) + + total = d.pop("total") + + org_id = d.pop("org_id") + + org_invitation_list_response = cls( + invitations=invitations, + total=total, + org_id=org_id, + ) + + org_invitation_list_response.additional_properties = d + return org_invitation_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/org_invitation_response.py b/robosystems_client/models/org_invitation_response.py new file mode 100644 index 0000000..a725925 --- /dev/null +++ b/robosystems_client/models/org_invitation_response.py @@ -0,0 +1,143 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.org_role import OrgRole + +T = TypeVar("T", bound="OrgInvitationResponse") + + +@_attrs_define +class OrgInvitationResponse: + """Organization invitation response. + + Attributes: + id (str): + org_id (str): + email (str): + role (OrgRole): + status (str): + invited_by_user_id (str): + invited_by_name (None | str): + created_at (datetime.datetime): + expires_at (datetime.datetime): + is_expired (bool): + """ + + id: str + org_id: str + email: str + role: OrgRole + status: str + invited_by_user_id: str + invited_by_name: None | str + created_at: datetime.datetime + expires_at: datetime.datetime + is_expired: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + org_id = self.org_id + + email = self.email + + role = self.role.value + + status = self.status + + invited_by_user_id = self.invited_by_user_id + + invited_by_name: None | str + invited_by_name = self.invited_by_name + + created_at = self.created_at.isoformat() + + expires_at = self.expires_at.isoformat() + + is_expired = self.is_expired + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "org_id": org_id, + "email": email, + "role": role, + "status": status, + "invited_by_user_id": invited_by_user_id, + "invited_by_name": invited_by_name, + "created_at": created_at, + "expires_at": expires_at, + "is_expired": is_expired, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = d.pop("id") + + org_id = d.pop("org_id") + + email = d.pop("email") + + role = OrgRole(d.pop("role")) + + status = d.pop("status") + + invited_by_user_id = d.pop("invited_by_user_id") + + def _parse_invited_by_name(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + invited_by_name = _parse_invited_by_name(d.pop("invited_by_name")) + + created_at = datetime.datetime.fromisoformat(d.pop("created_at")) + + expires_at = datetime.datetime.fromisoformat(d.pop("expires_at")) + + is_expired = d.pop("is_expired") + + org_invitation_response = cls( + id=id, + org_id=org_id, + email=email, + role=role, + status=status, + invited_by_user_id=invited_by_user_id, + invited_by_name=invited_by_name, + created_at=created_at, + expires_at=expires_at, + is_expired=is_expired, + ) + + org_invitation_response.additional_properties = d + return org_invitation_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/register_request.py b/robosystems_client/models/register_request.py index 6cebfe8..0daf8fe 100644 --- a/robosystems_client/models/register_request.py +++ b/robosystems_client/models/register_request.py @@ -20,12 +20,15 @@ class RegisterRequest: email (str): User's email address password (str): User's password (must meet security requirements) captcha_token (None | str | Unset): CAPTCHA verification token (required in production) + invite_token (None | str | Unset): Org invitation token from an invitation email. When present, the new user + joins the inviting organization at the invited role instead of receiving a personal organization. """ name: str email: str password: str captcha_token: None | str | Unset = UNSET + invite_token: None | str | Unset = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: @@ -41,6 +44,12 @@ def to_dict(self) -> dict[str, Any]: else: captcha_token = self.captcha_token + invite_token: None | str | Unset + if isinstance(self.invite_token, Unset): + invite_token = UNSET + else: + invite_token = self.invite_token + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( @@ -52,6 +61,8 @@ def to_dict(self) -> dict[str, Any]: ) if captcha_token is not UNSET: field_dict["captcha_token"] = captcha_token + if invite_token is not UNSET: + field_dict["invite_token"] = invite_token return field_dict @@ -73,11 +84,21 @@ def _parse_captcha_token(data: object) -> None | str | Unset: captcha_token = _parse_captcha_token(d.pop("captcha_token", UNSET)) + def _parse_invite_token(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + invite_token = _parse_invite_token(d.pop("invite_token", UNSET)) + register_request = cls( name=name, email=email, password=password, captcha_token=captcha_token, + invite_token=invite_token, ) register_request.additional_properties = d diff --git a/robosystems_client/models/update_graph_member_role_request.py b/robosystems_client/models/update_graph_member_role_request.py new file mode 100644 index 0000000..6ca99b7 --- /dev/null +++ b/robosystems_client/models/update_graph_member_role_request.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.graph_role import GraphRole + +T = TypeVar("T", bound="UpdateGraphMemberRoleRequest") + + +@_attrs_define +class UpdateGraphMemberRoleRequest: + """Request to change a graph member's role. + + Attributes: + role (GraphRole): Ordered per-graph roles: viewer < member < admin. + """ + + role: GraphRole + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + role = self.role.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "role": role, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + role = GraphRole(d.pop("role")) + + update_graph_member_role_request = cls( + role=role, + ) + + update_graph_member_role_request.additional_properties = d + return update_graph_member_role_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/robosystems_client/models/upgrade_subscription_request.py b/robosystems_client/models/upgrade_subscription_request.py index 0269bee..9d907aa 100644 --- a/robosystems_client/models/upgrade_subscription_request.py +++ b/robosystems_client/models/upgrade_subscription_request.py @@ -1,11 +1,13 @@ from __future__ import annotations from collections.abc import Mapping -from typing import Any, TypeVar +from typing import Any, TypeVar, cast from attrs import define as _attrs_define from attrs import field as _attrs_field +from ..types import UNSET, Unset + T = TypeVar("T", bound="UpgradeSubscriptionRequest") @@ -15,14 +17,23 @@ class UpgradeSubscriptionRequest: Attributes: new_plan_name (str): New plan name to change to + user_id (None | str | Unset): Organization member whose subscription to change. Defaults to the caller; + targeting another member requires org owner or admin. """ new_plan_name: str + user_id: None | str | Unset = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: new_plan_name = self.new_plan_name + user_id: None | str | Unset + if isinstance(self.user_id, Unset): + user_id = UNSET + else: + user_id = self.user_id + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update( @@ -30,6 +41,8 @@ def to_dict(self) -> dict[str, Any]: "new_plan_name": new_plan_name, } ) + if user_id is not UNSET: + field_dict["user_id"] = user_id return field_dict @@ -38,8 +51,18 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: d = dict(src_dict) new_plan_name = d.pop("new_plan_name") + def _parse_user_id(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + user_id = _parse_user_id(d.pop("user_id", UNSET)) + upgrade_subscription_request = cls( new_plan_name=new_plan_name, + user_id=user_id, ) upgrade_subscription_request.additional_properties = d