From d19363cafb352cb8151b1bf15996a5fdc26b6813 Mon Sep 17 00:00:00 2001 From: mattgd Date: Thu, 14 Nov 2024 14:47:32 -0500 Subject: [PATCH] Add widgets module and widget get token API endpoint. --- tests/test_client.py | 4 +- tests/test_widgets.py | 25 +++++++++ workos/async_client.py | 7 +++ workos/client.py | 7 +++ workos/types/widgets/__init__.py | 2 + workos/types/widgets/widget_scope.py | 4 ++ workos/types/widgets/widget_token_response.py | 7 +++ workos/widgets.py | 55 +++++++++++++++++++ 8 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 tests/test_widgets.py create mode 100644 workos/types/widgets/__init__.py create mode 100644 workos/types/widgets/widget_scope.py create mode 100644 workos/types/widgets/widget_token_response.py create mode 100644 workos/widgets.py diff --git a/tests/test_client.py b/tests/test_client.py index 0e1e868e..e23cf93c 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1,4 +1,3 @@ -from http import client import os import pytest from workos import AsyncWorkOSClient, WorkOSClient @@ -65,6 +64,9 @@ def test_initialize_portal(self, default_client): def test_initialize_user_management(self, default_client): assert bool(default_client.user_management) + def test_initialize_widgets(self, default_client): + assert bool(default_client.widgets) + def test_enforce_trailing_slash_for_base_url( self, ): diff --git a/tests/test_widgets.py b/tests/test_widgets.py new file mode 100644 index 00000000..f008cb95 --- /dev/null +++ b/tests/test_widgets.py @@ -0,0 +1,25 @@ +import pytest + +from workos.widgets import Widgets + + +class TestWidgets(object): + @pytest.fixture(autouse=True) + def setup(self, sync_http_client_for_test): + self.http_client = sync_http_client_for_test + self.widgets = Widgets(http_client=self.http_client) + + @pytest.fixture + def mock_widget_token(self): + return {"token": "abc123456"} + + def test_get_token(self, mock_widget_token, mock_http_client_with_response): + mock_http_client_with_response(self.http_client, mock_widget_token, 201) + + response = self.widgets.get_token( + organization_id="org_01EHQMYV6MBK39QC5PZXHY59C3", + user_id="user_01EHQMYV6MBK39QC5PZXHY59C3", + scopes=["widgets:users-table:manage"], + ) + + assert response.token == "abc123456" diff --git a/workos/async_client.py b/workos/async_client.py index c65af0fd..61e4563e 100644 --- a/workos/async_client.py +++ b/workos/async_client.py @@ -13,6 +13,7 @@ from workos.user_management import AsyncUserManagement from workos.utils.http_client import AsyncHTTPClient from workos.webhooks import WebhooksModule +from workos.widgets import WidgetsModule class AsyncClient(BaseClient): @@ -105,3 +106,9 @@ def user_management(self) -> AsyncUserManagement: http_client=self._http_client, client_configuration=self ) return self._user_management + + @property + def widgets(self) -> WidgetsModule: + raise NotImplementedError( + "Widgets APIs are not yet supported in the async client." + ) diff --git a/workos/client.py b/workos/client.py index e51e167f..b61d3c9e 100644 --- a/workos/client.py +++ b/workos/client.py @@ -13,6 +13,7 @@ from workos.events import Events from workos.user_management import UserManagement from workos.utils.http_client import SyncHTTPClient +from workos.widgets import Widgets class SyncClient(BaseClient): @@ -109,3 +110,9 @@ def user_management(self) -> UserManagement: http_client=self._http_client, client_configuration=self ) return self._user_management + + @property + def widgets(self) -> Widgets: + if not getattr(self, "_widgets", None): + self._widgets = Widgets(http_client=self._http_client) + return self._widgets diff --git a/workos/types/widgets/__init__.py b/workos/types/widgets/__init__.py new file mode 100644 index 00000000..b0972fc1 --- /dev/null +++ b/workos/types/widgets/__init__.py @@ -0,0 +1,2 @@ +from .widget_scope import * +from .widget_token_response import * diff --git a/workos/types/widgets/widget_scope.py b/workos/types/widgets/widget_scope.py new file mode 100644 index 00000000..484f0977 --- /dev/null +++ b/workos/types/widgets/widget_scope.py @@ -0,0 +1,4 @@ +from typing import Literal + + +WidgetScope = Literal["widgets:users-table:manage"] diff --git a/workos/types/widgets/widget_token_response.py b/workos/types/widgets/widget_token_response.py new file mode 100644 index 00000000..3d3af0f0 --- /dev/null +++ b/workos/types/widgets/widget_token_response.py @@ -0,0 +1,7 @@ +from workos.types.workos_model import WorkOSModel + + +class WidgetTokenResponse(WorkOSModel): + """Representation of a WorkOS widget token response.""" + + token: str diff --git a/workos/widgets.py b/workos/widgets.py new file mode 100644 index 00000000..cb0d0c12 --- /dev/null +++ b/workos/widgets.py @@ -0,0 +1,55 @@ +from typing import Protocol, Sequence +from workos.types.widgets.widget_scope import WidgetScope +from workos.types.widgets.widget_token_response import WidgetTokenResponse +from workos.utils.http_client import SyncHTTPClient +from workos.utils.request_helper import REQUEST_METHOD_POST + + +WIDGETS_GENERATE_TOKEN_PATH = "widgets/token" + + +class WidgetsModule(Protocol): + def get_token( + self, + *, + organization_id: str, + user_id: str, + scopes: Sequence[WidgetScope], + ) -> WidgetTokenResponse: + """Generate a new widget token for the specified organization and user with the provided scopes. + + Kwargs: + organization_id (str): The ID of the organization the widget token will be generated for. + user_id (str): The ID of the AuthKit user the widget token will be generated for. + scopes (Sequence[WidgetScope]): The widget scopes for the generated widget token. + + Returns: + WidgetTokenResponse: WidgetTokenResponse object with token string. + """ + ... + + +class Widgets(WidgetsModule): + + _http_client: SyncHTTPClient + + def __init__(self, http_client: SyncHTTPClient): + self._http_client = http_client + + def get_token( + self, + *, + organization_id: str, + user_id: str, + scopes: Sequence[WidgetScope], + ) -> WidgetTokenResponse: + json = { + "organization_id": organization_id, + "user_id": user_id, + "scopes": scopes, + } + response = self._http_client.request( + WIDGETS_GENERATE_TOKEN_PATH, method=REQUEST_METHOD_POST, json=json + ) + + return WidgetTokenResponse.model_validate(response)