|
1 | | -from typing import Any, Dict, Optional, Protocol, Sequence |
| 1 | +from typing import Any, Dict, Optional, Protocol, Sequence, Union |
2 | 2 |
|
3 | 3 | from pydantic import TypeAdapter |
| 4 | +from typing_extensions import TypedDict |
4 | 5 |
|
5 | 6 | from workos.types.authorization.environment_role import ( |
6 | 7 | EnvironmentRole, |
7 | 8 | EnvironmentRoleList, |
8 | 9 | ) |
9 | 10 | from workos.types.authorization.organization_role import OrganizationRole |
10 | 11 | from workos.types.authorization.permission import Permission |
| 12 | +from workos.types.authorization.resource import Resource |
11 | 13 | from workos.types.authorization.role import Role, RoleList |
12 | 14 | from workos.types.list_resource import ( |
13 | 15 | ListArgs, |
|
28 | 30 | ) |
29 | 31 |
|
30 | 32 | AUTHORIZATION_PERMISSIONS_PATH = "authorization/permissions" |
| 33 | +AUTHORIZATION_RESOURCES_PATH = "authorization/resources" |
| 34 | + |
| 35 | + |
| 36 | +class ParentResourceById(TypedDict): |
| 37 | + """Identify a parent resource by its WorkOS resource ID.""" |
| 38 | + |
| 39 | + resource_id: str |
| 40 | + |
| 41 | + |
| 42 | +class ParentResourceByExternalId(TypedDict): |
| 43 | + """Identify a parent resource by organization, type, and external ID.""" |
| 44 | + |
| 45 | + organization_id: str |
| 46 | + resource_type: str |
| 47 | + external_id: str |
| 48 | + |
| 49 | + |
| 50 | +ParentResource = Union[ParentResourceById, ParentResourceByExternalId] |
31 | 51 |
|
32 | 52 | _role_adapter: TypeAdapter[Role] = TypeAdapter(Role) |
33 | 53 |
|
@@ -161,6 +181,34 @@ def add_environment_role_permission( |
161 | 181 | permission_slug: str, |
162 | 182 | ) -> SyncOrAsync[EnvironmentRole]: ... |
163 | 183 |
|
| 184 | + # Resources |
| 185 | + |
| 186 | + def get_resource(self, resource_id: str) -> SyncOrAsync[Resource]: ... |
| 187 | + |
| 188 | + def create_resource( |
| 189 | + self, |
| 190 | + *, |
| 191 | + resource_type: str, |
| 192 | + organization_id: str, |
| 193 | + external_id: Optional[str] = None, |
| 194 | + meta: Optional[Dict[str, Any]] = None, |
| 195 | + parent: Optional[ParentResource] = None, |
| 196 | + ) -> SyncOrAsync[Resource]: ... |
| 197 | + |
| 198 | + def update_resource( |
| 199 | + self, |
| 200 | + resource_id: str, |
| 201 | + *, |
| 202 | + meta: Optional[Dict[str, Any]] = None, |
| 203 | + ) -> SyncOrAsync[Resource]: ... |
| 204 | + |
| 205 | + def delete_resource( |
| 206 | + self, |
| 207 | + resource_id: str, |
| 208 | + *, |
| 209 | + cascade_delete: Optional[bool] = None, |
| 210 | + ) -> SyncOrAsync[None]: ... |
| 211 | + |
164 | 212 |
|
165 | 213 | class Authorization(AuthorizationModule): |
166 | 214 | _http_client: SyncHTTPClient |
@@ -437,6 +485,79 @@ def add_environment_role_permission( |
437 | 485 |
|
438 | 486 | return EnvironmentRole.model_validate(response) |
439 | 487 |
|
| 488 | + # Resources |
| 489 | + |
| 490 | + def get_resource(self, resource_id: str) -> Resource: |
| 491 | + response = self._http_client.request( |
| 492 | + f"{AUTHORIZATION_RESOURCES_PATH}/{resource_id}", |
| 493 | + method=REQUEST_METHOD_GET, |
| 494 | + ) |
| 495 | + |
| 496 | + return Resource.model_validate(response) |
| 497 | + |
| 498 | + def create_resource( |
| 499 | + self, |
| 500 | + *, |
| 501 | + resource_type: str, |
| 502 | + organization_id: str, |
| 503 | + external_id: Optional[str] = None, |
| 504 | + meta: Optional[Dict[str, Any]] = None, |
| 505 | + parent: Optional[ParentResource] = None, |
| 506 | + ) -> Resource: |
| 507 | + json: Dict[str, Any] = { |
| 508 | + "resource_type": resource_type, |
| 509 | + "organization_id": organization_id, |
| 510 | + } |
| 511 | + if external_id is not None: |
| 512 | + json["external_id"] = external_id |
| 513 | + if meta is not None: |
| 514 | + json["meta"] = meta |
| 515 | + if parent is not None: |
| 516 | + json["parent"] = parent |
| 517 | + |
| 518 | + response = self._http_client.request( |
| 519 | + AUTHORIZATION_RESOURCES_PATH, |
| 520 | + method=REQUEST_METHOD_POST, |
| 521 | + json=json, |
| 522 | + ) |
| 523 | + |
| 524 | + return Resource.model_validate(response) |
| 525 | + |
| 526 | + def update_resource( |
| 527 | + self, |
| 528 | + resource_id: str, |
| 529 | + *, |
| 530 | + meta: Optional[Dict[str, Any]] = None, |
| 531 | + ) -> Resource: |
| 532 | + json: Dict[str, Any] = {} |
| 533 | + if meta is not None: |
| 534 | + json["meta"] = meta |
| 535 | + |
| 536 | + response = self._http_client.request( |
| 537 | + f"{AUTHORIZATION_RESOURCES_PATH}/{resource_id}", |
| 538 | + method=REQUEST_METHOD_PATCH, |
| 539 | + json=json, |
| 540 | + ) |
| 541 | + |
| 542 | + return Resource.model_validate(response) |
| 543 | + |
| 544 | + def delete_resource( |
| 545 | + self, |
| 546 | + resource_id: str, |
| 547 | + *, |
| 548 | + cascade_delete: Optional[bool] = None, |
| 549 | + ) -> None: |
| 550 | + if cascade_delete is not None: |
| 551 | + self._http_client.delete_with_body( |
| 552 | + f"{AUTHORIZATION_RESOURCES_PATH}/{resource_id}", |
| 553 | + json={"cascade_delete": cascade_delete}, |
| 554 | + ) |
| 555 | + else: |
| 556 | + self._http_client.request( |
| 557 | + f"{AUTHORIZATION_RESOURCES_PATH}/{resource_id}", |
| 558 | + method=REQUEST_METHOD_DELETE, |
| 559 | + ) |
| 560 | + |
440 | 561 |
|
441 | 562 | class AsyncAuthorization(AuthorizationModule): |
442 | 563 | _http_client: AsyncHTTPClient |
@@ -712,3 +833,76 @@ async def add_environment_role_permission( |
712 | 833 | ) |
713 | 834 |
|
714 | 835 | return EnvironmentRole.model_validate(response) |
| 836 | + |
| 837 | + # Resources |
| 838 | + |
| 839 | + async def get_resource(self, resource_id: str) -> Resource: |
| 840 | + response = await self._http_client.request( |
| 841 | + f"{AUTHORIZATION_RESOURCES_PATH}/{resource_id}", |
| 842 | + method=REQUEST_METHOD_GET, |
| 843 | + ) |
| 844 | + |
| 845 | + return Resource.model_validate(response) |
| 846 | + |
| 847 | + async def create_resource( |
| 848 | + self, |
| 849 | + *, |
| 850 | + resource_type: str, |
| 851 | + organization_id: str, |
| 852 | + external_id: Optional[str] = None, |
| 853 | + meta: Optional[Dict[str, Any]] = None, |
| 854 | + parent: Optional[ParentResource] = None, |
| 855 | + ) -> Resource: |
| 856 | + json: Dict[str, Any] = { |
| 857 | + "resource_type": resource_type, |
| 858 | + "organization_id": organization_id, |
| 859 | + } |
| 860 | + if external_id is not None: |
| 861 | + json["external_id"] = external_id |
| 862 | + if meta is not None: |
| 863 | + json["meta"] = meta |
| 864 | + if parent is not None: |
| 865 | + json["parent"] = parent |
| 866 | + |
| 867 | + response = await self._http_client.request( |
| 868 | + AUTHORIZATION_RESOURCES_PATH, |
| 869 | + method=REQUEST_METHOD_POST, |
| 870 | + json=json, |
| 871 | + ) |
| 872 | + |
| 873 | + return Resource.model_validate(response) |
| 874 | + |
| 875 | + async def update_resource( |
| 876 | + self, |
| 877 | + resource_id: str, |
| 878 | + *, |
| 879 | + meta: Optional[Dict[str, Any]] = None, |
| 880 | + ) -> Resource: |
| 881 | + json: Dict[str, Any] = {} |
| 882 | + if meta is not None: |
| 883 | + json["meta"] = meta |
| 884 | + |
| 885 | + response = await self._http_client.request( |
| 886 | + f"{AUTHORIZATION_RESOURCES_PATH}/{resource_id}", |
| 887 | + method=REQUEST_METHOD_PATCH, |
| 888 | + json=json, |
| 889 | + ) |
| 890 | + |
| 891 | + return Resource.model_validate(response) |
| 892 | + |
| 893 | + async def delete_resource( |
| 894 | + self, |
| 895 | + resource_id: str, |
| 896 | + *, |
| 897 | + cascade_delete: Optional[bool] = None, |
| 898 | + ) -> None: |
| 899 | + if cascade_delete is not None: |
| 900 | + await self._http_client.delete_with_body( |
| 901 | + f"{AUTHORIZATION_RESOURCES_PATH}/{resource_id}", |
| 902 | + json={"cascade_delete": cascade_delete}, |
| 903 | + ) |
| 904 | + else: |
| 905 | + await self._http_client.request( |
| 906 | + f"{AUTHORIZATION_RESOURCES_PATH}/{resource_id}", |
| 907 | + method=REQUEST_METHOD_DELETE, |
| 908 | + ) |
0 commit comments