Skip to content

Commit ab5a4d5

Browse files
committed
Simplify user/group permissions destroying to only accept a single permission (to follow same cadence)
1 parent 7dd0a5e commit ab5a4d5

File tree

8 files changed

+145
-190
lines changed

8 files changed

+145
-190
lines changed

integration/tests/posit/connect/test_content_item_permissions.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import pytest
2+
13
from posit import connect
24
from posit.connect.content import ContentItem
35

@@ -59,11 +61,9 @@ def assert_permissions_match_guids(permissions, objs_with_guid):
5961
)
6062

6163
# Remove permissions (and from some that isn't an owner)
62-
destroyed_permissions = self.content.permissions.destroy(self.user_aron, self.user_bill)
63-
assert_permissions_match_guids(
64-
destroyed_permissions,
65-
[self.user_aron],
66-
)
64+
self.content.permissions.destroy(self.user_aron)
65+
with pytest.raises(ValueError):
66+
self.content.permissions.destroy(self.user_bill)
6767

6868
# Prove they have been removed
6969
assert_permissions_match_guids(

src/posit/connect/permissions.py

Lines changed: 38 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,15 @@ def find(self, **kwargs) -> List[Permission]:
111111
"""
112112
path = f"v1/content/{self.content_guid}/permissions"
113113
url = self.params.url + path
114-
response = self.params.session.get(url, json=kwargs)
114+
response = self.params.session.get(url)
115+
kwargs_items = kwargs.items()
115116
results = response.json()
117+
if len(kwargs_items) > 0:
118+
results = [
119+
result
120+
for result in results
121+
if isinstance(result, dict) and (result.items() >= kwargs_items)
122+
]
116123
return [Permission(self.params, **result) for result in results]
117124

118125
def find_one(self, **kwargs) -> Permission | None:
@@ -142,25 +149,18 @@ def get(self, uid: str) -> Permission:
142149
response = self.params.session.get(url)
143150
return Permission(self.params, **response.json())
144151

145-
def destroy(self, *permissions: str | Group | User | Permission) -> list[Permission]:
146-
"""Remove supplied content item permissions.
152+
def destroy(self, permission: str | Group | User | Permission, /) -> None:
153+
"""Remove supplied content item permission.
147154
148-
Removes all provided permissions from the content item's permissions. If a permission isn't
149-
found, it is silently ignored.
155+
Removes provided permission from the content item's permissions.
150156
151157
Parameters
152158
----------
153-
*permissions : str | Group | User | Permission
154-
The content item permissions to remove. If a `str` is received, it is compared against
159+
permission : str | Group | User | Permission
160+
The content item permission to remove. If a `str` is received, it is compared against
155161
the `Permissions`'s `principal_guid`. If a `Group` or `User` is received, the associated
156162
`Permission` will be removed.
157163
158-
Returns
159-
-------
160-
list[Permission]
161-
The removed permissions. If a permission is not found, there is nothing to remove and
162-
it is not included in the returned list.
163-
164164
Examples
165165
--------
166166
```python
@@ -175,51 +175,46 @@ def destroy(self, *permissions: str | Group | User | Permission) -> list[Permiss
175175
############################
176176
177177
client = connect.Client()
178+
content_item = client.content.get(content_guid)
178179
179180
# Remove a single permission by principal_guid
180-
client.content.get(content_guid).permissions.destroy(principal_guid)
181+
content_item.permissions.destroy(principal_guid)
181182
182183
# Remove by user (if principal_guid is a user)
183184
user = client.users.get(principal_guid)
184-
client.content.get(content_guid).permissions.destroy(user)
185+
content_item.permissions.destroy(user)
185186
186187
# Remove by group (if principal_guid is a group)
187188
group = client.groups.get(principal_guid)
188-
client.content.get(content_guid).permissions.destroy(group)
189+
content_item.permissions.destroy(group)
189190
190191
# Remove all groups with a matching prefix name
191192
groups = client.groups.find(prefix=group_name_prefix)
192-
client.content.get(content_guid).permissions.destroy(*groups)
193+
for group in groups:
194+
content_item.permissions.destroy(group)
193195
194196
# Confirm new permissions
195-
client.content.get(content_guid).permissions.find()
197+
content_item.permissions.find()
196198
```
197199
"""
198200
from .groups import Group
199201
from .users import User
200202

201-
if len(permissions) == 0:
202-
raise ValueError("Expected at least one `permission` to remove")
203-
204-
principal_guids: set[str] = set()
205-
206-
for arg in permissions:
207-
if isinstance(arg, str):
208-
principal_guid = arg
209-
elif isinstance(arg, (Group, User)):
210-
principal_guid: str = arg["guid"]
211-
elif isinstance(arg, Permission):
212-
principal_guid: str = arg["principal_guid"]
213-
else:
214-
raise TypeError(
215-
f"destroy() expected argument type 'str', 'User', 'Group', or 'Permission' but got '{type(arg).__name__}'",
216-
)
217-
principal_guids.add(principal_guid)
218-
219-
destroyed_permissions: list[Permission] = []
220-
for permission in self.find():
221-
if permission["principal_guid"] in principal_guids:
222-
permission.destroy()
223-
destroyed_permissions.append(permission)
224-
225-
return destroyed_permissions
203+
if isinstance(permission, str):
204+
permission_obj = self.get(permission)
205+
elif isinstance(permission, (Group, User)):
206+
principal_guid: str = permission["guid"]
207+
permission_obj = self.find_one(
208+
principal_guid=principal_guid,
209+
)
210+
print("Barret!", permission, principal_guid, permission_obj)
211+
if permission_obj is None:
212+
raise ValueError(f"Permission with principal_guid '{principal_guid}' not found.")
213+
elif isinstance(permission, Permission):
214+
permission_obj = permission
215+
else:
216+
raise TypeError(
217+
f"destroy() expected `permission=` to have type `str | User | Group | Permission`. Received `{permission}` of type `{type(permission)}`.",
218+
)
219+
220+
permission_obj.destroy()

src/posit/connect/users.py

Lines changed: 25 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from __future__ import annotations
44

5-
from typing import TYPE_CHECKING, List, Literal, Optional, overload
5+
from typing import TYPE_CHECKING, List, Literal
66

77
from typing_extensions import NotRequired, Required, TypedDict, Unpack
88

@@ -169,26 +169,14 @@ def __init__(self, ctx: Context, user_guid: str) -> None:
169169
self._ctx: Context = ctx
170170
self._user_guid: str = user_guid
171171

172-
@overload
173-
def add(self, group: Group, /) -> None: ...
174-
@overload
175-
def add(self, /, *, group_guid: str) -> None: ...
176-
177-
def add(self, group: Optional[Group] = None, /, *, group_guid: Optional[str] = None) -> None:
172+
def add(self, group: str | Group) -> None:
178173
"""
179174
Add the user to the specified group.
180175
181176
Parameters
182177
----------
183-
group : Group
184-
The groups to which the user will be added. Only one of `group=` or `group_guid=` can
185-
be provided.
186-
group_guid : str
187-
The unique identifier (guid) of the group to which the user will be added.
188-
189-
Returns
190-
-------
191-
None
178+
group : str | Group
179+
The group guid or `Group` object to which the user will be added.
192180
193181
Examples
194182
--------
@@ -212,57 +200,35 @@ def add(self, group: Optional[Group] = None, /, *, group_guid: Optional[str] = N
212200
user.groups.add(group)
213201
214202
# Add the user to a group by GUID
215-
user.groups.add(group_guid="GROUP_GUID_HERE")
203+
user.groups.add("GROUP_GUID_HERE")
216204
```
217205
218206
See Also
219207
--------
220208
* https://docs.posit.co/connect/api/#post-/v1/groups/-group_guid-/members
221209
"""
222-
if group is not None:
223-
from .groups import Group
224-
225-
if group_guid:
226-
raise ValueError("Only one of `group=` or `group_guid` may be be provided.")
210+
from .groups import Group
227211

228-
if not isinstance(group, Group):
229-
raise TypeError(
230-
f"`group=` is not an instance of Group. Received {group}",
231-
)
212+
if isinstance(group, Group):
232213
group.members.add(user_guid=self._user_guid)
233214
return
234215

235-
if not group_guid:
236-
raise ValueError("Only one of `group=` or `group_guid` may be be provided.")
237-
group = self._ctx.client.groups.get(group_guid)
238-
group.members.add(user_guid=self._user_guid)
216+
if not isinstance(group, str):
217+
raise TypeError(f"`group=` must be a `str | Group`. Received {group}")
218+
if not group:
219+
raise ValueError("`group=` must not be empty.")
239220

240-
@overload
241-
def delete(self, group: Group, /) -> None: ...
242-
@overload
243-
def delete(self, /, *, group_guid: str) -> None: ...
221+
group_obj = self._ctx.client.groups.get(group)
222+
group_obj.members.add(user_guid=self._user_guid)
244223

245-
def delete(
246-
self,
247-
group: Optional[Group] = None,
248-
/,
249-
*,
250-
group_guid: Optional[str] = None,
251-
) -> None:
224+
def delete(self, group: str | Group) -> None:
252225
"""
253226
Remove the user from the specified group.
254227
255228
Parameters
256229
----------
257-
group : Group
258-
The groups to which the user will be added. Only one of `group=` or `group_guid=` can
259-
be provided.
260-
group_guid : str
261-
The unique identifier (guid) of the group from which the user will be removed.
262-
263-
Returns
264-
-------
265-
None
230+
group : str | Group
231+
The group to which the user will be added.
266232
267233
Examples
268234
--------
@@ -286,33 +252,26 @@ def delete(
286252
user.groups.delete(group)
287253
288254
# Remove the user from a group by GUID
289-
user.groups.delete(group_guid="GROUP_GUID_HERE")
255+
user.groups.delete("GROUP_GUID_HERE")
290256
```
291257
292258
See Also
293259
--------
294260
* https://docs.posit.co/connect/api/#delete-/v1/groups/-group_guid-/members/-user_guid-
295261
"""
296-
if group is not None:
297-
from .groups import Group
298-
299-
if group_guid:
300-
raise ValueError("Only one of `group=` or `group_guid=` may be be provided.")
262+
from .groups import Group
301263

302-
if not isinstance(group, Group):
303-
raise TypeError(
304-
f"`group=` is not an instance of Group. Received {group}",
305-
)
264+
if isinstance(group, Group):
306265
group.members.delete(user_guid=self._user_guid)
307266
return
308267

309-
if not isinstance(group_guid, str):
310-
raise TypeError("`group_guid=` must be a string. Received {user}")
311-
if not group_guid:
312-
raise ValueError("`group_guid=` must not be empty.")
268+
if not isinstance(group, str):
269+
raise TypeError(f"`group=` must be a `str | Group`. Received {group}")
270+
if not group:
271+
raise ValueError("`group=` must not be empty.")
313272

314-
group = self._ctx.client.groups.get(group_guid)
315-
group.members.delete(user_guid=self._user_guid)
273+
group_obj = self._ctx.client.groups.get(group)
274+
group_obj.members.delete(user_guid=self._user_guid)
316275

317276
def find(self) -> List[Group]:
318277
"""
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
[
2-
{
3-
"id": 94,
4-
"content_guid": "f2f37341-e21d-3d80-c698-a935ad614066",
5-
"principal_guid": "78974391-d89f-4f11-916a-ba50cfe993db",
6-
"principal_type": "user",
7-
"role": "owner"
8-
},
9-
{
10-
"id": 59,
11-
"content_guid": "f2f37341-e21d-3d80-c698-a935ad614066",
12-
"principal_guid": "75b95fc0-ae02-4d85-8732-79a845143eed",
13-
"principal_type": "group",
14-
"role": "viewer"
15-
}
2+
{
3+
"id": 94,
4+
"content_guid": "f2f37341-e21d-3d80-c698-a935ad614066",
5+
"principal_guid": "20a79ce3-6e87-4522-9faf-be24228800a4",
6+
"principal_type": "user",
7+
"role": "owner"
8+
},
9+
{
10+
"id": 59,
11+
"content_guid": "f2f37341-e21d-3d80-c698-a935ad614066",
12+
"principal_guid": "6f300623-1e0c-48e6-a473-ddf630c0c0c3",
13+
"principal_type": "group",
14+
"role": "viewer"
15+
}
1616
]
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"id": 59,
3+
"content_guid": "f2f37341-e21d-3d80-c698-a935ad614066",
4+
"principal_guid": "6f300623-1e0c-48e6-a473-ddf630c0c0c3",
5+
"principal_type": "group",
6+
"role": "viewer"
7+
}
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"id": 94,
3-
"content_guid": "f2f37341-e21d-3d80-c698-a935ad614066",
4-
"principal_guid": "78974391-d89f-4f11-916a-ba50cfe993db",
5-
"principal_type": "user",
6-
"role": "owner"
2+
"id": "94",
3+
"content_guid": "f2f37341-e21d-3d80-c698-a935ad614066",
4+
"principal_guid": "20a79ce3-6e87-4522-9faf-be24228800a4",
5+
"principal_type": "user",
6+
"role": "owner"
77
}

0 commit comments

Comments
 (0)