pltr-cli 0.5.0__py3-none-any.whl → 0.5.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pltr/__init__.py +1 -1
- pltr/cli.py +14 -0
- pltr/commands/connectivity.py +432 -0
- pltr/commands/dataset.py +268 -0
- pltr/commands/project.py +440 -0
- pltr/commands/resource.py +499 -0
- pltr/commands/resource_role.py +454 -0
- pltr/commands/space.py +662 -0
- pltr/services/connectivity.py +305 -0
- pltr/services/dataset.py +243 -8
- pltr/services/project.py +232 -0
- pltr/services/resource.py +289 -0
- pltr/services/resource_role.py +321 -0
- pltr/services/space.py +354 -0
- pltr/utils/formatting.py +108 -1
- {pltr_cli-0.5.0.dist-info → pltr_cli-0.5.1.dist-info}/METADATA +101 -2
- {pltr_cli-0.5.0.dist-info → pltr_cli-0.5.1.dist-info}/RECORD +20 -10
- {pltr_cli-0.5.0.dist-info → pltr_cli-0.5.1.dist-info}/WHEEL +0 -0
- {pltr_cli-0.5.0.dist-info → pltr_cli-0.5.1.dist-info}/entry_points.txt +0 -0
- {pltr_cli-0.5.0.dist-info → pltr_cli-0.5.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Resource Role service wrapper for Foundry SDK filesystem API.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Optional, Dict, List
|
|
6
|
+
|
|
7
|
+
from .base import BaseService
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ResourceRoleService(BaseService):
|
|
11
|
+
"""Service wrapper for Foundry resource role operations using filesystem API."""
|
|
12
|
+
|
|
13
|
+
def _get_service(self) -> Any:
|
|
14
|
+
"""Get the Foundry filesystem service."""
|
|
15
|
+
return self.client.filesystem
|
|
16
|
+
|
|
17
|
+
def grant_role(
|
|
18
|
+
self,
|
|
19
|
+
resource_rid: str,
|
|
20
|
+
principal_id: str,
|
|
21
|
+
principal_type: str,
|
|
22
|
+
role_name: str,
|
|
23
|
+
) -> Dict[str, Any]:
|
|
24
|
+
"""
|
|
25
|
+
Grant a role to a principal on a resource.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
resource_rid: Resource Identifier
|
|
29
|
+
principal_id: Principal (user/group) identifier
|
|
30
|
+
principal_type: Principal type ('User' or 'Group')
|
|
31
|
+
role_name: Role name to grant
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Role grant information
|
|
35
|
+
"""
|
|
36
|
+
try:
|
|
37
|
+
role_grant: Dict[str, Any] = {
|
|
38
|
+
"principal_id": principal_id,
|
|
39
|
+
"principal_type": principal_type,
|
|
40
|
+
"role_name": role_name,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
result = self.service.ResourceRole.grant(
|
|
44
|
+
resource_rid=resource_rid,
|
|
45
|
+
body=role_grant,
|
|
46
|
+
preview=True,
|
|
47
|
+
)
|
|
48
|
+
return self._format_role_grant(result)
|
|
49
|
+
except Exception as e:
|
|
50
|
+
raise RuntimeError(
|
|
51
|
+
f"Failed to grant role '{role_name}' to {principal_type} '{principal_id}' on resource {resource_rid}: {e}"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def revoke_role(
|
|
55
|
+
self,
|
|
56
|
+
resource_rid: str,
|
|
57
|
+
principal_id: str,
|
|
58
|
+
principal_type: str,
|
|
59
|
+
role_name: str,
|
|
60
|
+
) -> None:
|
|
61
|
+
"""
|
|
62
|
+
Revoke a role from a principal on a resource.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
resource_rid: Resource Identifier
|
|
66
|
+
principal_id: Principal (user/group) identifier
|
|
67
|
+
principal_type: Principal type ('User' or 'Group')
|
|
68
|
+
role_name: Role name to revoke
|
|
69
|
+
|
|
70
|
+
Raises:
|
|
71
|
+
RuntimeError: If revocation fails
|
|
72
|
+
"""
|
|
73
|
+
try:
|
|
74
|
+
role_revocation: Dict[str, Any] = {
|
|
75
|
+
"principal_id": principal_id,
|
|
76
|
+
"principal_type": principal_type,
|
|
77
|
+
"role_name": role_name,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
self.service.ResourceRole.revoke(
|
|
81
|
+
resource_rid=resource_rid,
|
|
82
|
+
body=role_revocation,
|
|
83
|
+
preview=True,
|
|
84
|
+
)
|
|
85
|
+
except Exception as e:
|
|
86
|
+
raise RuntimeError(
|
|
87
|
+
f"Failed to revoke role '{role_name}' from {principal_type} '{principal_id}' on resource {resource_rid}: {e}"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
def list_resource_roles(
|
|
91
|
+
self,
|
|
92
|
+
resource_rid: str,
|
|
93
|
+
principal_type: Optional[str] = None,
|
|
94
|
+
page_size: Optional[int] = None,
|
|
95
|
+
page_token: Optional[str] = None,
|
|
96
|
+
) -> List[Dict[str, Any]]:
|
|
97
|
+
"""
|
|
98
|
+
List all roles granted on a resource.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
resource_rid: Resource Identifier
|
|
102
|
+
principal_type: Filter by principal type ('User' or 'Group', optional)
|
|
103
|
+
page_size: Number of items per page (optional)
|
|
104
|
+
page_token: Pagination token (optional)
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
List of role grant information dictionaries
|
|
108
|
+
"""
|
|
109
|
+
try:
|
|
110
|
+
role_grants = []
|
|
111
|
+
list_params: Dict[str, Any] = {"preview": True}
|
|
112
|
+
|
|
113
|
+
if principal_type:
|
|
114
|
+
list_params["principal_type"] = principal_type
|
|
115
|
+
if page_size:
|
|
116
|
+
list_params["page_size"] = page_size
|
|
117
|
+
if page_token:
|
|
118
|
+
list_params["page_token"] = page_token
|
|
119
|
+
|
|
120
|
+
# The list method returns an iterator
|
|
121
|
+
for role_grant in self.service.ResourceRole.list(
|
|
122
|
+
resource_rid, **list_params
|
|
123
|
+
):
|
|
124
|
+
role_grants.append(self._format_role_grant(role_grant))
|
|
125
|
+
return role_grants
|
|
126
|
+
except Exception as e:
|
|
127
|
+
raise RuntimeError(f"Failed to list roles for resource {resource_rid}: {e}")
|
|
128
|
+
|
|
129
|
+
def get_principal_roles(
|
|
130
|
+
self,
|
|
131
|
+
principal_id: str,
|
|
132
|
+
principal_type: str,
|
|
133
|
+
resource_rid: Optional[str] = None,
|
|
134
|
+
page_size: Optional[int] = None,
|
|
135
|
+
page_token: Optional[str] = None,
|
|
136
|
+
) -> List[Dict[str, Any]]:
|
|
137
|
+
"""
|
|
138
|
+
Get all roles granted to a principal, optionally filtered by resource.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
principal_id: Principal (user/group) identifier
|
|
142
|
+
principal_type: Principal type ('User' or 'Group')
|
|
143
|
+
resource_rid: Filter by resource RID (optional)
|
|
144
|
+
page_size: Number of items per page (optional)
|
|
145
|
+
page_token: Pagination token (optional)
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
List of role grant information dictionaries
|
|
149
|
+
"""
|
|
150
|
+
try:
|
|
151
|
+
role_grants = []
|
|
152
|
+
list_params = {
|
|
153
|
+
"principal_id": principal_id,
|
|
154
|
+
"principal_type": principal_type,
|
|
155
|
+
"preview": True,
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if resource_rid:
|
|
159
|
+
list_params["resource_rid"] = resource_rid
|
|
160
|
+
if page_size:
|
|
161
|
+
list_params["page_size"] = page_size
|
|
162
|
+
if page_token:
|
|
163
|
+
list_params["page_token"] = page_token
|
|
164
|
+
|
|
165
|
+
# The get_principal_roles method returns an iterator
|
|
166
|
+
for role_grant in self.service.ResourceRole.get_principal_roles(
|
|
167
|
+
**list_params
|
|
168
|
+
):
|
|
169
|
+
role_grants.append(self._format_role_grant(role_grant))
|
|
170
|
+
return role_grants
|
|
171
|
+
except Exception as e:
|
|
172
|
+
raise RuntimeError(
|
|
173
|
+
f"Failed to get roles for {principal_type} '{principal_id}': {e}"
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
def bulk_grant_roles(
|
|
177
|
+
self,
|
|
178
|
+
resource_rid: str,
|
|
179
|
+
role_grants: List[Dict[str, str]],
|
|
180
|
+
) -> List[Dict[str, Any]]:
|
|
181
|
+
"""
|
|
182
|
+
Grant multiple roles in a single request.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
resource_rid: Resource Identifier
|
|
186
|
+
role_grants: List of role grant specifications, each containing:
|
|
187
|
+
- principal_id: Principal identifier
|
|
188
|
+
- principal_type: 'User' or 'Group'
|
|
189
|
+
- role_name: Role name to grant
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
List of granted role information dictionaries
|
|
193
|
+
"""
|
|
194
|
+
try:
|
|
195
|
+
result = self.service.ResourceRole.bulk_grant(
|
|
196
|
+
resource_rid=resource_rid,
|
|
197
|
+
body={"role_grants": role_grants},
|
|
198
|
+
preview=True,
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
granted_roles = []
|
|
202
|
+
if hasattr(result, "role_grants"):
|
|
203
|
+
for role_grant in result.role_grants:
|
|
204
|
+
granted_roles.append(self._format_role_grant(role_grant))
|
|
205
|
+
|
|
206
|
+
return granted_roles
|
|
207
|
+
except Exception as e:
|
|
208
|
+
raise RuntimeError(
|
|
209
|
+
f"Failed to bulk grant roles on resource {resource_rid}: {e}"
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
def bulk_revoke_roles(
|
|
213
|
+
self,
|
|
214
|
+
resource_rid: str,
|
|
215
|
+
role_revocations: List[Dict[str, str]],
|
|
216
|
+
) -> None:
|
|
217
|
+
"""
|
|
218
|
+
Revoke multiple roles in a single request.
|
|
219
|
+
|
|
220
|
+
Args:
|
|
221
|
+
resource_rid: Resource Identifier
|
|
222
|
+
role_revocations: List of role revocation specifications, each containing:
|
|
223
|
+
- principal_id: Principal identifier
|
|
224
|
+
- principal_type: 'User' or 'Group'
|
|
225
|
+
- role_name: Role name to revoke
|
|
226
|
+
|
|
227
|
+
Raises:
|
|
228
|
+
RuntimeError: If revocation fails
|
|
229
|
+
"""
|
|
230
|
+
try:
|
|
231
|
+
self.service.ResourceRole.bulk_revoke(
|
|
232
|
+
resource_rid=resource_rid,
|
|
233
|
+
body={"role_revocations": role_revocations},
|
|
234
|
+
preview=True,
|
|
235
|
+
)
|
|
236
|
+
except Exception as e:
|
|
237
|
+
raise RuntimeError(
|
|
238
|
+
f"Failed to bulk revoke roles on resource {resource_rid}: {e}"
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
def get_available_roles(self, resource_rid: str) -> List[Dict[str, Any]]:
|
|
242
|
+
"""
|
|
243
|
+
Get all available roles for a resource type.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
resource_rid: Resource Identifier
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
List of available role information dictionaries
|
|
250
|
+
"""
|
|
251
|
+
try:
|
|
252
|
+
roles = []
|
|
253
|
+
for role in self.service.ResourceRole.get_available_roles(
|
|
254
|
+
resource_rid, preview=True
|
|
255
|
+
):
|
|
256
|
+
roles.append(self._format_role_info(role))
|
|
257
|
+
return roles
|
|
258
|
+
except Exception as e:
|
|
259
|
+
raise RuntimeError(
|
|
260
|
+
f"Failed to get available roles for resource {resource_rid}: {e}"
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
def _format_role_grant(self, role_grant: Any) -> Dict[str, Any]:
|
|
264
|
+
"""
|
|
265
|
+
Format role grant information for consistent output.
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
role_grant: Role grant object from Foundry SDK
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
Formatted role grant information dictionary
|
|
272
|
+
"""
|
|
273
|
+
return {
|
|
274
|
+
"resource_rid": getattr(role_grant, "resource_rid", None),
|
|
275
|
+
"principal_id": getattr(role_grant, "principal_id", None),
|
|
276
|
+
"principal_type": getattr(role_grant, "principal_type", None),
|
|
277
|
+
"role_name": getattr(role_grant, "role_name", None),
|
|
278
|
+
"granted_by": getattr(role_grant, "granted_by", None),
|
|
279
|
+
"granted_time": self._format_timestamp(
|
|
280
|
+
getattr(role_grant, "granted_time", None)
|
|
281
|
+
),
|
|
282
|
+
"expires_at": self._format_timestamp(
|
|
283
|
+
getattr(role_grant, "expires_at", None)
|
|
284
|
+
),
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
def _format_role_info(self, role: Any) -> Dict[str, Any]:
|
|
288
|
+
"""
|
|
289
|
+
Format role information for consistent output.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
role: Role object from Foundry SDK
|
|
293
|
+
|
|
294
|
+
Returns:
|
|
295
|
+
Formatted role information dictionary
|
|
296
|
+
"""
|
|
297
|
+
return {
|
|
298
|
+
"name": getattr(role, "name", None),
|
|
299
|
+
"display_name": getattr(role, "display_name", None),
|
|
300
|
+
"description": getattr(role, "description", None),
|
|
301
|
+
"permissions": getattr(role, "permissions", []),
|
|
302
|
+
"is_owner_like": getattr(role, "is_owner_like", False),
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
def _format_timestamp(self, timestamp: Any) -> Optional[str]:
|
|
306
|
+
"""
|
|
307
|
+
Format timestamp for display.
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
timestamp: Timestamp object from SDK
|
|
311
|
+
|
|
312
|
+
Returns:
|
|
313
|
+
Formatted timestamp string or None
|
|
314
|
+
"""
|
|
315
|
+
if timestamp is None:
|
|
316
|
+
return None
|
|
317
|
+
|
|
318
|
+
# Handle different timestamp formats from the SDK
|
|
319
|
+
if hasattr(timestamp, "time"):
|
|
320
|
+
return str(timestamp.time)
|
|
321
|
+
return str(timestamp)
|
pltr/services/space.py
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Space service wrapper for Foundry SDK filesystem API.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Optional, Dict, List
|
|
6
|
+
|
|
7
|
+
from .base import BaseService
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SpaceService(BaseService):
|
|
11
|
+
"""Service wrapper for Foundry space operations using filesystem API."""
|
|
12
|
+
|
|
13
|
+
def _get_service(self) -> Any:
|
|
14
|
+
"""Get the Foundry filesystem service."""
|
|
15
|
+
return self.client.filesystem
|
|
16
|
+
|
|
17
|
+
def create_space(
|
|
18
|
+
self,
|
|
19
|
+
display_name: str,
|
|
20
|
+
organization_rid: str,
|
|
21
|
+
description: Optional[str] = None,
|
|
22
|
+
default_roles: Optional[List[str]] = None,
|
|
23
|
+
role_grants: Optional[List[Dict[str, Any]]] = None,
|
|
24
|
+
) -> Dict[str, Any]:
|
|
25
|
+
"""
|
|
26
|
+
Create a new space.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
display_name: Space display name
|
|
30
|
+
organization_rid: Organization Resource Identifier
|
|
31
|
+
description: Space description (optional)
|
|
32
|
+
default_roles: List of default role names (optional)
|
|
33
|
+
role_grants: List of role grant specifications (optional)
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
Created space information
|
|
37
|
+
"""
|
|
38
|
+
try:
|
|
39
|
+
# Prepare the create request payload
|
|
40
|
+
create_request: Dict[str, Any] = {
|
|
41
|
+
"display_name": display_name,
|
|
42
|
+
"organization_rid": organization_rid,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if description:
|
|
46
|
+
create_request["description"] = description
|
|
47
|
+
if default_roles:
|
|
48
|
+
create_request["default_roles"] = default_roles
|
|
49
|
+
if role_grants:
|
|
50
|
+
create_request["role_grants"] = role_grants
|
|
51
|
+
|
|
52
|
+
space = self.service.Space.create(
|
|
53
|
+
body=create_request,
|
|
54
|
+
preview=True,
|
|
55
|
+
)
|
|
56
|
+
return self._format_space_info(space)
|
|
57
|
+
except Exception as e:
|
|
58
|
+
raise RuntimeError(f"Failed to create space '{display_name}': {e}")
|
|
59
|
+
|
|
60
|
+
def get_space(self, space_rid: str) -> Dict[str, Any]:
|
|
61
|
+
"""
|
|
62
|
+
Get information about a specific space.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
space_rid: Space Resource Identifier
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Space information dictionary
|
|
69
|
+
"""
|
|
70
|
+
try:
|
|
71
|
+
space = self.service.Space.get(space_rid, preview=True)
|
|
72
|
+
return self._format_space_info(space)
|
|
73
|
+
except Exception as e:
|
|
74
|
+
raise RuntimeError(f"Failed to get space {space_rid}: {e}")
|
|
75
|
+
|
|
76
|
+
def list_spaces(
|
|
77
|
+
self,
|
|
78
|
+
organization_rid: Optional[str] = None,
|
|
79
|
+
page_size: Optional[int] = None,
|
|
80
|
+
page_token: Optional[str] = None,
|
|
81
|
+
) -> List[Dict[str, Any]]:
|
|
82
|
+
"""
|
|
83
|
+
List spaces, optionally filtered by organization.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
organization_rid: Organization Resource Identifier to filter by (optional)
|
|
87
|
+
page_size: Number of items per page (optional)
|
|
88
|
+
page_token: Pagination token (optional)
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
List of space information dictionaries
|
|
92
|
+
"""
|
|
93
|
+
try:
|
|
94
|
+
spaces = []
|
|
95
|
+
list_params: Dict[str, Any] = {"preview": True}
|
|
96
|
+
|
|
97
|
+
if organization_rid:
|
|
98
|
+
list_params["organization_rid"] = organization_rid
|
|
99
|
+
if page_size:
|
|
100
|
+
list_params["page_size"] = page_size
|
|
101
|
+
if page_token:
|
|
102
|
+
list_params["page_token"] = page_token
|
|
103
|
+
|
|
104
|
+
# The list method returns an iterator
|
|
105
|
+
for space in self.service.Space.list(**list_params):
|
|
106
|
+
spaces.append(self._format_space_info(space))
|
|
107
|
+
return spaces
|
|
108
|
+
except Exception as e:
|
|
109
|
+
raise RuntimeError(f"Failed to list spaces: {e}")
|
|
110
|
+
|
|
111
|
+
def update_space(
|
|
112
|
+
self,
|
|
113
|
+
space_rid: str,
|
|
114
|
+
display_name: Optional[str] = None,
|
|
115
|
+
description: Optional[str] = None,
|
|
116
|
+
) -> Dict[str, Any]:
|
|
117
|
+
"""
|
|
118
|
+
Update space information.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
space_rid: Space Resource Identifier
|
|
122
|
+
display_name: New display name (optional)
|
|
123
|
+
description: New description (optional)
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
Updated space information
|
|
127
|
+
"""
|
|
128
|
+
update_request: Dict[str, Any] = {}
|
|
129
|
+
if display_name:
|
|
130
|
+
update_request["display_name"] = display_name
|
|
131
|
+
if description:
|
|
132
|
+
update_request["description"] = description
|
|
133
|
+
|
|
134
|
+
if not update_request:
|
|
135
|
+
raise ValueError("At least one field must be provided for update")
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
space = self.service.Space.update(
|
|
139
|
+
space_rid=space_rid,
|
|
140
|
+
body=update_request,
|
|
141
|
+
preview=True,
|
|
142
|
+
)
|
|
143
|
+
return self._format_space_info(space)
|
|
144
|
+
except Exception as e:
|
|
145
|
+
raise RuntimeError(f"Failed to update space {space_rid}: {e}")
|
|
146
|
+
|
|
147
|
+
def delete_space(self, space_rid: str) -> None:
|
|
148
|
+
"""
|
|
149
|
+
Delete a space.
|
|
150
|
+
|
|
151
|
+
Args:
|
|
152
|
+
space_rid: Space Resource Identifier
|
|
153
|
+
|
|
154
|
+
Raises:
|
|
155
|
+
RuntimeError: If deletion fails
|
|
156
|
+
"""
|
|
157
|
+
try:
|
|
158
|
+
self.service.Space.delete(space_rid, preview=True)
|
|
159
|
+
except Exception as e:
|
|
160
|
+
raise RuntimeError(f"Failed to delete space {space_rid}: {e}")
|
|
161
|
+
|
|
162
|
+
def get_spaces_batch(self, space_rids: List[str]) -> List[Dict[str, Any]]:
|
|
163
|
+
"""
|
|
164
|
+
Get multiple spaces in a single request.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
space_rids: List of space RIDs (max 1000)
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
List of space information dictionaries
|
|
171
|
+
"""
|
|
172
|
+
if len(space_rids) > 1000:
|
|
173
|
+
raise ValueError("Maximum batch size is 1000 spaces")
|
|
174
|
+
|
|
175
|
+
try:
|
|
176
|
+
response = self.service.Space.get_batch(body=space_rids, preview=True)
|
|
177
|
+
spaces = []
|
|
178
|
+
for space in response.spaces:
|
|
179
|
+
spaces.append(self._format_space_info(space))
|
|
180
|
+
return spaces
|
|
181
|
+
except Exception as e:
|
|
182
|
+
raise RuntimeError(f"Failed to get spaces batch: {e}")
|
|
183
|
+
|
|
184
|
+
def get_space_members(
|
|
185
|
+
self,
|
|
186
|
+
space_rid: str,
|
|
187
|
+
principal_type: Optional[str] = None,
|
|
188
|
+
page_size: Optional[int] = None,
|
|
189
|
+
page_token: Optional[str] = None,
|
|
190
|
+
) -> List[Dict[str, Any]]:
|
|
191
|
+
"""
|
|
192
|
+
Get all members (users/groups) of a space.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
space_rid: Space Resource Identifier
|
|
196
|
+
principal_type: Filter by principal type ('User' or 'Group', optional)
|
|
197
|
+
page_size: Number of items per page (optional)
|
|
198
|
+
page_token: Pagination token (optional)
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
List of space member information dictionaries
|
|
202
|
+
"""
|
|
203
|
+
try:
|
|
204
|
+
members = []
|
|
205
|
+
list_params: Dict[str, Any] = {"preview": True}
|
|
206
|
+
|
|
207
|
+
if principal_type:
|
|
208
|
+
list_params["principal_type"] = principal_type
|
|
209
|
+
if page_size:
|
|
210
|
+
list_params["page_size"] = page_size
|
|
211
|
+
if page_token:
|
|
212
|
+
list_params["page_token"] = page_token
|
|
213
|
+
|
|
214
|
+
# The get_members method returns an iterator
|
|
215
|
+
for member in self.service.Space.get_members(space_rid, **list_params):
|
|
216
|
+
members.append(self._format_member_info(member))
|
|
217
|
+
return members
|
|
218
|
+
except Exception as e:
|
|
219
|
+
raise RuntimeError(f"Failed to get members for space {space_rid}: {e}")
|
|
220
|
+
|
|
221
|
+
def add_space_member(
|
|
222
|
+
self,
|
|
223
|
+
space_rid: str,
|
|
224
|
+
principal_id: str,
|
|
225
|
+
principal_type: str,
|
|
226
|
+
role_name: str,
|
|
227
|
+
) -> Dict[str, Any]:
|
|
228
|
+
"""
|
|
229
|
+
Add a member to a space with a specific role.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
space_rid: Space Resource Identifier
|
|
233
|
+
principal_id: Principal (user/group) identifier
|
|
234
|
+
principal_type: Principal type ('User' or 'Group')
|
|
235
|
+
role_name: Role name to grant
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
Space member information
|
|
239
|
+
"""
|
|
240
|
+
try:
|
|
241
|
+
member_request: Dict[str, Any] = {
|
|
242
|
+
"principal_id": principal_id,
|
|
243
|
+
"principal_type": principal_type,
|
|
244
|
+
"role_name": role_name,
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
result = self.service.Space.add_member(
|
|
248
|
+
space_rid=space_rid,
|
|
249
|
+
body=member_request,
|
|
250
|
+
preview=True,
|
|
251
|
+
)
|
|
252
|
+
return self._format_member_info(result)
|
|
253
|
+
except Exception as e:
|
|
254
|
+
raise RuntimeError(
|
|
255
|
+
f"Failed to add {principal_type} '{principal_id}' to space {space_rid}: {e}"
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
def remove_space_member(
|
|
259
|
+
self,
|
|
260
|
+
space_rid: str,
|
|
261
|
+
principal_id: str,
|
|
262
|
+
principal_type: str,
|
|
263
|
+
) -> None:
|
|
264
|
+
"""
|
|
265
|
+
Remove a member from a space.
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
space_rid: Space Resource Identifier
|
|
269
|
+
principal_id: Principal (user/group) identifier
|
|
270
|
+
principal_type: Principal type ('User' or 'Group')
|
|
271
|
+
|
|
272
|
+
Raises:
|
|
273
|
+
RuntimeError: If removal fails
|
|
274
|
+
"""
|
|
275
|
+
try:
|
|
276
|
+
member_removal: Dict[str, Any] = {
|
|
277
|
+
"principal_id": principal_id,
|
|
278
|
+
"principal_type": principal_type,
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
self.service.Space.remove_member(
|
|
282
|
+
space_rid=space_rid,
|
|
283
|
+
body=member_removal,
|
|
284
|
+
preview=True,
|
|
285
|
+
)
|
|
286
|
+
except Exception as e:
|
|
287
|
+
raise RuntimeError(
|
|
288
|
+
f"Failed to remove {principal_type} '{principal_id}' from space {space_rid}: {e}"
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
def _format_space_info(self, space: Any) -> Dict[str, Any]:
|
|
292
|
+
"""
|
|
293
|
+
Format space information for consistent output.
|
|
294
|
+
|
|
295
|
+
Args:
|
|
296
|
+
space: Space object from Foundry SDK
|
|
297
|
+
|
|
298
|
+
Returns:
|
|
299
|
+
Formatted space information dictionary
|
|
300
|
+
"""
|
|
301
|
+
return {
|
|
302
|
+
"rid": getattr(space, "rid", None),
|
|
303
|
+
"display_name": getattr(space, "display_name", None),
|
|
304
|
+
"description": getattr(space, "description", None),
|
|
305
|
+
"organization_rid": getattr(space, "organization_rid", None),
|
|
306
|
+
"root_folder_rid": getattr(space, "root_folder_rid", None),
|
|
307
|
+
"created_by": getattr(space, "created_by", None),
|
|
308
|
+
"created_time": self._format_timestamp(
|
|
309
|
+
getattr(space, "created_time", None)
|
|
310
|
+
),
|
|
311
|
+
"modified_by": getattr(space, "modified_by", None),
|
|
312
|
+
"modified_time": self._format_timestamp(
|
|
313
|
+
getattr(space, "modified_time", None)
|
|
314
|
+
),
|
|
315
|
+
"trash_status": getattr(space, "trash_status", None),
|
|
316
|
+
"type": "space",
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
def _format_member_info(self, member: Any) -> Dict[str, Any]:
|
|
320
|
+
"""
|
|
321
|
+
Format space member information for consistent output.
|
|
322
|
+
|
|
323
|
+
Args:
|
|
324
|
+
member: Member object from Foundry SDK
|
|
325
|
+
|
|
326
|
+
Returns:
|
|
327
|
+
Formatted member information dictionary
|
|
328
|
+
"""
|
|
329
|
+
return {
|
|
330
|
+
"space_rid": getattr(member, "space_rid", None),
|
|
331
|
+
"principal_id": getattr(member, "principal_id", None),
|
|
332
|
+
"principal_type": getattr(member, "principal_type", None),
|
|
333
|
+
"role_name": getattr(member, "role_name", None),
|
|
334
|
+
"added_by": getattr(member, "added_by", None),
|
|
335
|
+
"added_time": self._format_timestamp(getattr(member, "added_time", None)),
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
def _format_timestamp(self, timestamp: Any) -> Optional[str]:
|
|
339
|
+
"""
|
|
340
|
+
Format timestamp for display.
|
|
341
|
+
|
|
342
|
+
Args:
|
|
343
|
+
timestamp: Timestamp object from SDK
|
|
344
|
+
|
|
345
|
+
Returns:
|
|
346
|
+
Formatted timestamp string or None
|
|
347
|
+
"""
|
|
348
|
+
if timestamp is None:
|
|
349
|
+
return None
|
|
350
|
+
|
|
351
|
+
# Handle different timestamp formats from the SDK
|
|
352
|
+
if hasattr(timestamp, "time"):
|
|
353
|
+
return str(timestamp.time)
|
|
354
|
+
return str(timestamp)
|