Skip to content

Commit fe59018

Browse files
FGA_2: listResources(), get/update/delete resource_by_external_id (#569)
1 parent 8dd434f commit fe59018

File tree

2 files changed

+526
-0
lines changed

2 files changed

+526
-0
lines changed

src/workos/authorization.py

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,19 @@ class _Unset(Enum):
3939

4040
AUTHORIZATION_PERMISSIONS_PATH = "authorization/permissions"
4141
AUTHORIZATION_RESOURCES_PATH = "authorization/resources"
42+
AUTHORIZATION_ORGANIZATIONS_PATH = "authorization/organizations"
43+
44+
45+
class ResourceListFilters(ListArgs, total=False):
46+
organization_id: Optional[str]
47+
resource_type_slug: Optional[str]
48+
parent_resource_id: Optional[str]
49+
parent_resource_type_slug: Optional[str]
50+
parent_external_id: Optional[str]
51+
search: Optional[str]
52+
53+
54+
ResourcesListResource = WorkOSListResource[Resource, ResourceListFilters, ListMetadata]
4255

4356

4457
class ParentResourceById(TypedDict):
@@ -214,6 +227,47 @@ def delete_resource(
214227
cascade_delete: Optional[bool] = None,
215228
) -> SyncOrAsync[None]: ...
216229

230+
def list_resources(
231+
self,
232+
*,
233+
organization_id: Optional[str] = None,
234+
resource_type_slug: Optional[str] = None,
235+
parent_resource_id: Optional[str] = None,
236+
parent_resource_type_slug: Optional[str] = None,
237+
parent_external_id: Optional[str] = None,
238+
search: Optional[str] = None,
239+
limit: int = DEFAULT_LIST_RESPONSE_LIMIT,
240+
before: Optional[str] = None,
241+
after: Optional[str] = None,
242+
order: PaginationOrder = "desc",
243+
) -> SyncOrAsync[ResourcesListResource]: ...
244+
245+
def get_resource_by_external_id(
246+
self,
247+
organization_id: str,
248+
resource_type: str,
249+
external_id: str,
250+
) -> SyncOrAsync[Resource]: ...
251+
252+
def update_resource_by_external_id(
253+
self,
254+
organization_id: str,
255+
resource_type: str,
256+
external_id: str,
257+
*,
258+
name: Optional[str] = None,
259+
description: Optional[str] = None,
260+
) -> SyncOrAsync[Resource]: ...
261+
262+
def delete_resource_by_external_id(
263+
self,
264+
organization_id: str,
265+
resource_type: str,
266+
external_id: str,
267+
*,
268+
cascade_delete: Optional[bool] = None,
269+
) -> SyncOrAsync[None]: ...
270+
217271

218272
class Authorization(AuthorizationModule):
219273
_http_client: SyncHTTPClient
@@ -568,6 +622,106 @@ def delete_resource(
568622
method=REQUEST_METHOD_DELETE,
569623
)
570624

625+
def list_resources(
626+
self,
627+
*,
628+
organization_id: Optional[str] = None,
629+
resource_type_slug: Optional[str] = None,
630+
parent_resource_id: Optional[str] = None,
631+
parent_resource_type_slug: Optional[str] = None,
632+
parent_external_id: Optional[str] = None,
633+
search: Optional[str] = None,
634+
limit: int = DEFAULT_LIST_RESPONSE_LIMIT,
635+
before: Optional[str] = None,
636+
after: Optional[str] = None,
637+
order: PaginationOrder = "desc",
638+
) -> ResourcesListResource:
639+
list_params: ResourceListFilters = {
640+
"limit": limit,
641+
"before": before,
642+
"after": after,
643+
"order": order,
644+
}
645+
if organization_id is not None:
646+
list_params["organization_id"] = organization_id
647+
if resource_type_slug is not None:
648+
list_params["resource_type_slug"] = resource_type_slug
649+
if parent_resource_id is not None:
650+
list_params["parent_resource_id"] = parent_resource_id
651+
if parent_resource_type_slug is not None:
652+
list_params["parent_resource_type_slug"] = parent_resource_type_slug
653+
if parent_external_id is not None:
654+
list_params["parent_external_id"] = parent_external_id
655+
if search is not None:
656+
list_params["search"] = search
657+
658+
response = self._http_client.request(
659+
AUTHORIZATION_RESOURCES_PATH,
660+
method=REQUEST_METHOD_GET,
661+
params=list_params,
662+
)
663+
664+
return WorkOSListResource[Resource, ResourceListFilters, ListMetadata](
665+
list_method=self.list_resources,
666+
list_args=list_params,
667+
**ListPage[Resource](**response).model_dump(),
668+
)
669+
670+
def get_resource_by_external_id(
671+
self,
672+
organization_id: str,
673+
resource_type: str,
674+
external_id: str,
675+
) -> Resource:
676+
response = self._http_client.request(
677+
f"{AUTHORIZATION_ORGANIZATIONS_PATH}/{organization_id}/resources/{resource_type}/{external_id}",
678+
method=REQUEST_METHOD_GET,
679+
)
680+
681+
return Resource.model_validate(response)
682+
683+
def update_resource_by_external_id(
684+
self,
685+
organization_id: str,
686+
resource_type: str,
687+
external_id: str,
688+
*,
689+
name: Optional[str] = None,
690+
description: Optional[str] = None,
691+
) -> Resource:
692+
json: Dict[str, Any] = {}
693+
if name is not None:
694+
json["name"] = name
695+
if description is not None:
696+
json["description"] = description
697+
698+
response = self._http_client.request(
699+
f"{AUTHORIZATION_ORGANIZATIONS_PATH}/{organization_id}/resources/{resource_type}/{external_id}",
700+
method=REQUEST_METHOD_PATCH,
701+
json=json,
702+
)
703+
704+
return Resource.model_validate(response)
705+
706+
def delete_resource_by_external_id(
707+
self,
708+
organization_id: str,
709+
resource_type: str,
710+
external_id: str,
711+
*,
712+
cascade_delete: Optional[bool] = None,
713+
) -> None:
714+
path = f"{AUTHORIZATION_ORGANIZATIONS_PATH}/{organization_id}/resources/{resource_type}/{external_id}"
715+
params: Dict[str, bool] = {}
716+
if cascade_delete is not None:
717+
params["cascade_delete"] = cascade_delete
718+
719+
self._http_client.request(
720+
path,
721+
method=REQUEST_METHOD_DELETE,
722+
params=params if params else None,
723+
)
724+
571725

572726
class AsyncAuthorization(AuthorizationModule):
573727
_http_client: AsyncHTTPClient
@@ -921,3 +1075,103 @@ async def delete_resource(
9211075
f"{AUTHORIZATION_RESOURCES_PATH}/{resource_id}",
9221076
method=REQUEST_METHOD_DELETE,
9231077
)
1078+
1079+
async def list_resources(
1080+
self,
1081+
*,
1082+
organization_id: Optional[str] = None,
1083+
resource_type_slug: Optional[str] = None,
1084+
parent_resource_id: Optional[str] = None,
1085+
parent_resource_type_slug: Optional[str] = None,
1086+
parent_external_id: Optional[str] = None,
1087+
search: Optional[str] = None,
1088+
limit: int = DEFAULT_LIST_RESPONSE_LIMIT,
1089+
before: Optional[str] = None,
1090+
after: Optional[str] = None,
1091+
order: PaginationOrder = "desc",
1092+
) -> ResourcesListResource:
1093+
list_params: ResourceListFilters = {
1094+
"limit": limit,
1095+
"before": before,
1096+
"after": after,
1097+
"order": order,
1098+
}
1099+
if organization_id is not None:
1100+
list_params["organization_id"] = organization_id
1101+
if resource_type_slug is not None:
1102+
list_params["resource_type_slug"] = resource_type_slug
1103+
if parent_resource_id is not None:
1104+
list_params["parent_resource_id"] = parent_resource_id
1105+
if parent_resource_type_slug is not None:
1106+
list_params["parent_resource_type_slug"] = parent_resource_type_slug
1107+
if parent_external_id is not None:
1108+
list_params["parent_external_id"] = parent_external_id
1109+
if search is not None:
1110+
list_params["search"] = search
1111+
1112+
response = await self._http_client.request(
1113+
AUTHORIZATION_RESOURCES_PATH,
1114+
method=REQUEST_METHOD_GET,
1115+
params=list_params,
1116+
)
1117+
1118+
return WorkOSListResource[Resource, ResourceListFilters, ListMetadata](
1119+
list_method=self.list_resources,
1120+
list_args=list_params,
1121+
**ListPage[Resource](**response).model_dump(),
1122+
)
1123+
1124+
async def get_resource_by_external_id(
1125+
self,
1126+
organization_id: str,
1127+
resource_type: str,
1128+
external_id: str,
1129+
) -> Resource:
1130+
response = await self._http_client.request(
1131+
f"{AUTHORIZATION_ORGANIZATIONS_PATH}/{organization_id}/resources/{resource_type}/{external_id}",
1132+
method=REQUEST_METHOD_GET,
1133+
)
1134+
1135+
return Resource.model_validate(response)
1136+
1137+
async def update_resource_by_external_id(
1138+
self,
1139+
organization_id: str,
1140+
resource_type: str,
1141+
external_id: str,
1142+
*,
1143+
name: Optional[str] = None,
1144+
description: Optional[str] = None,
1145+
) -> Resource:
1146+
json: Dict[str, Any] = {}
1147+
if name is not None:
1148+
json["name"] = name
1149+
if description is not None:
1150+
json["description"] = description
1151+
1152+
response = await self._http_client.request(
1153+
f"{AUTHORIZATION_ORGANIZATIONS_PATH}/{organization_id}/resources/{resource_type}/{external_id}",
1154+
method=REQUEST_METHOD_PATCH,
1155+
json=json,
1156+
)
1157+
1158+
return Resource.model_validate(response)
1159+
1160+
async def delete_resource_by_external_id(
1161+
self,
1162+
organization_id: str,
1163+
resource_type: str,
1164+
external_id: str,
1165+
*,
1166+
cascade_delete: Optional[bool] = None,
1167+
) -> None:
1168+
path = f"{AUTHORIZATION_ORGANIZATIONS_PATH}/{organization_id}/resources/{resource_type}/{external_id}"
1169+
params: Dict[str, bool] = {}
1170+
if cascade_delete is not None:
1171+
params["cascade_delete"] = cascade_delete
1172+
1173+
await self._http_client.request(
1174+
path,
1175+
method=REQUEST_METHOD_DELETE,
1176+
params=params if params else None,
1177+
)

0 commit comments

Comments
 (0)