Skip to content

Commit b884e65

Browse files
authored
feat: Add Permission.create(*args:User | Group) support (#343)
1 parent 918bd5f commit b884e65

File tree

2 files changed

+167
-15
lines changed

2 files changed

+167
-15
lines changed

src/posit/connect/permissions.py

Lines changed: 80 additions & 15 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, overload
5+
from typing import TYPE_CHECKING, List, Optional, overload
66

77
from requests.sessions import Session as Session
88

@@ -67,36 +67,101 @@ def count(self) -> int:
6767
return len(self.find())
6868

6969
@overload
70-
def create(self, *, principal_guid: str, principal_type: str, role: str) -> Permission:
70+
def create(self, /, *, principal_guid: str, principal_type: str, role: str) -> Permission: ...
71+
72+
@overload
73+
def create(self, principal: User | Group, /, *, role: str) -> Permission: ...
74+
75+
def create(
76+
self,
77+
principal: Optional[User | Group] = None,
78+
/,
79+
**kwargs,
80+
) -> Permission:
7181
"""Create a permission.
7282
7383
Parameters
7484
----------
85+
principal : User | Group
86+
The principal user or group to add.
87+
role : str
88+
The principal role. Currently only `"viewer"` and `"owner"` are supported.
7589
principal_guid : str
90+
User guid or Group guid.
7691
principal_type : str
92+
The principal type. Either `"user"` or `"group"`.
7793
role : str
94+
The principal role. Currently only `"viewer"` and `"owner"` are supported
7895
7996
Returns
8097
-------
8198
Permission
82-
"""
99+
The created permission.
83100
84-
@overload
85-
def create(self, **kwargs) -> Permission:
86-
"""Create a permission.
101+
Examples
102+
--------
103+
```python
104+
from posit import connect
87105
88-
Returns
89-
-------
90-
Permission
91-
"""
106+
client = connect.Client()
107+
content_item = client.content.get(content_guid)
92108
93-
def create(self, **kwargs) -> Permission:
94-
"""Create a permission.
109+
# New permission role
110+
role = "viewer" # Or "owner"
111+
112+
# Example groups and users
113+
groups = client.groups.find(prefix="GROUP_NAME_PREFIX_HERE")
114+
group = groups[0]
115+
user = client.users.get("USER_GUID_HERE")
116+
users_and_groups = [user, *groups]
117+
118+
# Add a group permission
119+
content_item.permissions.create(group, role=role)
120+
# Add a user permission
121+
content_item.permissions.create(user, role=role)
122+
123+
# Add many group and user permissions with the same role
124+
for principal in users_and_groups:
125+
content_item.permissions.create(principal, role=role)
126+
127+
# Add a group permission manually
128+
content_item.permissions.create(
129+
principal_guid=group["guid"],
130+
principal_type="group",
131+
role=role,
132+
)
133+
# Add a user permission manually
134+
content_item.permissions.create(
135+
principal_guid=user["guid"],
136+
principal_type="user",
137+
role=role,
138+
)
95139
96-
Returns
97-
-------
98-
Permission
140+
# Confirm new permissions
141+
content_item.permissions.find()
142+
```
99143
"""
144+
if principal is not None:
145+
# Avoid circular imports
146+
from .groups import Group
147+
from .users import User
148+
149+
if isinstance(principal, User):
150+
principal_type = "user"
151+
elif isinstance(principal, Group):
152+
principal_type = "group"
153+
else:
154+
raise TypeError(f"Invalid argument type: {type(principal).__name__}")
155+
156+
if "principal_guid" in kwargs:
157+
raise ValueError("'principal_guid' can not be defined with `principal` present.")
158+
if "principal_type" in kwargs:
159+
raise ValueError("'principal_guid' can not be defined with `principal` present.")
160+
161+
# Set the corresponding kwargs
162+
kwargs["principal_guid"] = principal["guid"]
163+
kwargs["principal_type"] = principal_type
164+
100165
path = f"v1/content/{self.content_guid}/permissions"
101166
url = self.params.url + path
102167
response = self.params.session.post(url, json=kwargs)

tests/posit/connect/test_permissions.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,93 @@ def test(self):
195195
# assert
196196
assert permission == fake_permission
197197

198+
def test_assertions(self):
199+
# setup
200+
principal_guid = "principal_guid"
201+
content_guid = "content_guid"
202+
client = Client("https://connect.example/__api__", "12345")
203+
permissions = Permissions(client.resource_params, content_guid=content_guid)
204+
user = User(client._ctx, guid=principal_guid)
205+
group = User(client._ctx, guid=principal_guid)
206+
207+
# behavior
208+
with pytest.raises(TypeError, match="str"):
209+
permissions.create( # pyright: ignore[reportCallIssue]
210+
"not a user or group",
211+
)
212+
with pytest.raises(ValueError):
213+
permissions.create( # pyright: ignore[reportCallIssue]
214+
user,
215+
principal_guid=principal_guid,
216+
)
217+
with pytest.raises(ValueError):
218+
permissions.create( # pyright: ignore[reportCallIssue]
219+
user,
220+
principal_type="viewer",
221+
)
222+
223+
@responses.activate
224+
def test_user_group(self):
225+
# data
226+
content_guid = "CONTENT_GUID"
227+
user_guid = "USER_GUID"
228+
group_guid = "GROUP_GUID"
229+
230+
fake_user = {
231+
"principal_guid": user_guid,
232+
"principal_type": "user",
233+
"role": "viewer",
234+
}
235+
fake_group = {
236+
"principal_guid": group_guid,
237+
"principal_type": "group",
238+
"role": "viewer",
239+
}
240+
res_user = responses.post(
241+
f"https://connect.example/__api__/v1/content/{content_guid}/permissions",
242+
json=fake_user,
243+
match=[matchers.json_params_matcher(fake_user)],
244+
)
245+
res_group = responses.post(
246+
f"https://connect.example/__api__/v1/content/{content_guid}/permissions",
247+
json=fake_group,
248+
match=[matchers.json_params_matcher(fake_group)],
249+
)
250+
251+
# setup
252+
client = Client("https://connect.example/__api__", "12345")
253+
permissions = Permissions(client.resource_params, content_guid=content_guid)
254+
user = User(client._ctx, guid=user_guid)
255+
group = Group(client._ctx, guid=group_guid)
256+
257+
# invoke
258+
user_perm = permissions.create(user, role="viewer")
259+
group_perm = permissions.create(group, role="viewer")
260+
261+
created_permissions = [user_perm, group_perm]
262+
263+
# assert
264+
assert res_user.call_count == 1
265+
assert res_group.call_count == 1
266+
267+
for permission in created_permissions:
268+
assert isinstance(permission, Permission)
269+
270+
assert created_permissions == [
271+
Permission(
272+
client.resource_params,
273+
principal_guid=user_guid,
274+
principal_type="user",
275+
role="viewer",
276+
),
277+
Permission(
278+
client.resource_params,
279+
principal_guid=group_guid,
280+
principal_type="group",
281+
role="viewer",
282+
),
283+
]
284+
198285

199286
class TestPermissionsFind:
200287
@responses.activate

0 commit comments

Comments
 (0)