Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add GET /organization/:orgId/roles support #392

Merged
merged 2 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions tests/test_organizations.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import pytest
from tests.types.test_auto_pagination_function import TestAutoPaginationFunction
from tests.utils.fixtures.mock_organization import MockOrganization
from tests.utils.fixtures.mock_role import MockRole
from tests.utils.list_resource import list_response_of
from tests.utils.syncify import syncify
from workos.organizations import AsyncOrganizations, Organizations
Expand Down Expand Up @@ -67,6 +68,13 @@ def mock_organizations_multiple_data_pages(self):
]
return list_response_of(data=organizations_list)

@pytest.fixture
def mock_organization_roles(self):
return {
"data": [MockRole(id=str(i)).dict() for i in range(10)],
"object": "list",
}

def test_list_organizations(
self, mock_organizations, capture_and_mock_http_client_request
):
Expand Down Expand Up @@ -227,3 +235,28 @@ def test_list_organizations_auto_pagination_for_multiple_pages(
list_function=self.organizations.list_organizations,
expected_all_page_data=mock_organizations_multiple_data_pages["data"],
)

def test_list_organization_roles(
self, mock_organization_roles, capture_and_mock_http_client_request
):
request_kwargs = capture_and_mock_http_client_request(
self.http_client, mock_organization_roles, 200
)

organization_roles_response = syncify(
self.organizations.list_organization_roles(
organization_id="org_01EHT88Z8J8795GZNQ4ZP1J81T"
)
)

def to_dict(x):
return x.dict()

assert request_kwargs["method"] == "get"
assert request_kwargs["url"].endswith(
"/organizations/org_01EHT88Z8J8795GZNQ4ZP1J81T/roles"
)
assert (
list(map(to_dict, organization_roles_response.data))
== mock_organization_roles["data"]
)
18 changes: 18 additions & 0 deletions tests/utils/fixtures/mock_role.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import datetime

from workos.types.roles.role import OrganizationRole


class MockRole(OrganizationRole):
def __init__(self, id):
now = datetime.datetime.now().isoformat()
super().__init__(
object="role",
id=id,
name="Member",
slug="member",
description="The default member role",
type="EnvironmentRole",
created_at=now,
updated_at=now,
)
17 changes: 17 additions & 0 deletions workos/organizations.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from workos.types.organizations.domain_data_input import DomainDataInput
from workos.types.organizations.list_filters import OrganizationListFilters
from workos.types.roles.role import OrganizationRole, RolesList
from workos.typing.sync_or_async import SyncOrAsync
from workos.utils.http_client import AsyncHTTPClient, SyncHTTPClient
from workos.utils.pagination_order import PaginationOrder
Expand Down Expand Up @@ -223,6 +224,14 @@ def delete_organization(self, organization_id: str) -> None:
method=REQUEST_METHOD_DELETE,
)

def list_organization_roles(self, organization_id: str) -> RolesList:
mattgd marked this conversation as resolved.
Show resolved Hide resolved
response = self._http_client.request(
f"organizations/{organization_id}/roles",
method=REQUEST_METHOD_GET,
)

return RolesList.model_validate(response)
mattgd marked this conversation as resolved.
Show resolved Hide resolved


class AsyncOrganizations(OrganizationsModule):

Expand Down Expand Up @@ -324,3 +333,11 @@ async def delete_organization(self, organization_id: str) -> None:
f"organizations/{organization_id}",
method=REQUEST_METHOD_DELETE,
)

async def list_organization_roles(self, organization_id: str) -> RolesList:
response = await self._http_client.request(
f"organizations/{organization_id}/roles",
method=REQUEST_METHOD_GET,
)

return RolesList.model_validate(response)
22 changes: 21 additions & 1 deletion workos/types/roles/role.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,28 @@
from typing import Literal, Optional, Sequence
from workos.types.workos_model import WorkOSModel

RoleType = Literal["EnvironmentRole", "OrganizationRole"]

class Role(WorkOSModel):

class RoleCommon(WorkOSModel):
object: Literal["role"]
slug: str


# TODO: This is used for events/webhooks only. Rename to EventRole or something similar.
class Role(RoleCommon):
mattgd marked this conversation as resolved.
Show resolved Hide resolved
permissions: Optional[Sequence[str]] = None


class OrganizationRole(RoleCommon):
id: str
name: str
description: Optional[str] = None
type: RoleType
created_at: str
updated_at: str


class RolesList(WorkOSModel):
object: Literal["list"]
data: Sequence[OrganizationRole]
Loading