Skip to content

Commit e794057

Browse files
committed
feat: implement user management methods including add, update, and delete functionalities
1 parent ab20d38 commit e794057

File tree

8 files changed

+326
-142
lines changed

8 files changed

+326
-142
lines changed

rapyuta_io_sdk_v2/async_client.py

Lines changed: 72 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
from typing import Any
1717

1818
import httpx
19-
from munch import Munch
2019
from yaml import safe_load
2120

2221
from rapyuta_io_sdk_v2.config import Configuration
@@ -55,6 +54,8 @@
5554
OAuth2UpdateURI,
5655
ServiceAccountList,
5756
ServiceAccount,
57+
)
58+
from rapyuta_io_sdk_v2.models.serviceaccount import (
5859
ServiceAccountToken,
5960
ServiceAccountTokenInfo,
6061
ServiceAccountTokenList,
@@ -251,10 +252,10 @@ async def update_organization(
251252
# ---------------------User--------------------
252253
async def list_users(
253254
self,
254-
organization_guid: str | None = None,
255-
guid: str | None = None,
256255
cont: int = 0,
257256
limit: int = 50,
257+
organization_guid: str | None = None,
258+
guid: str | None = None,
258259
**kwargs,
259260
) -> UserList:
260261
parameters: dict[str, Any] = {
@@ -276,8 +277,26 @@ async def list_users(
276277

277278
return UserList(**result.json())
278279

280+
async def add_user(self, user: User | dict, **kwargs) -> User:
281+
"""Add a User in Organization.
282+
283+
Returns:
284+
User: User details as a user object.
285+
"""
286+
if isinstance(user, dict):
287+
user = User.model_validate(user)
288+
result = await self.c.post(
289+
url=f"{self.v2api_host}/v2/users/",
290+
headers=self.config.get_headers(with_project=False, **kwargs),
291+
body=user.model_dump(by_alias=True),
292+
)
293+
294+
handle_server_errors(result)
295+
296+
return UserList(**result.json())
297+
279298
async def get_myself(self, **kwargs) -> User:
280-
"""Get User details.
299+
"""Get my User details.
281300
282301
Returns:
283302
User: User details as a User object.
@@ -291,16 +310,44 @@ async def get_myself(self, **kwargs) -> User:
291310
handle_server_errors(result)
292311
return User(**result.json())
293312

294-
# Alias for backward compatibility
295-
async def get_user(self, **kwargs) -> User:
296-
"""Get User details. (Alias for get_myself)
313+
async def update_myself(self, body: User | dict[str, Any], **kwargs) -> User:
314+
"""Update my user details.
315+
316+
Args:
317+
body (dict): User details
297318
298319
Returns:
299320
User: User details as a User object.
300321
"""
301-
return await self.get_myself(**kwargs)
322+
if isinstance(body, dict):
323+
body = User.model_validate(body)
302324

303-
async def update_user(self, body: User | dict[str, Any], **kwargs) -> User:
325+
result = await self.c.put(
326+
url=f"{self.v2api_host}/v2/users/me/",
327+
headers=self.config.get_headers(
328+
with_project=False, with_organization=False, **kwargs
329+
),
330+
json=body.model_dump(by_alias=True),
331+
)
332+
handle_server_errors(result)
333+
return User(**result.json())
334+
335+
async def get_user(self, email_id: str, **kwargs) -> User:
336+
"""Get User details.
337+
338+
Returns:
339+
User: User details as a User object.
340+
"""
341+
result = await self.c.get(
342+
url=f"{self.v2api_host}/v2/users/{email_id}",
343+
headers=self.config.get_headers(with_project=False, **kwargs),
344+
)
345+
handle_server_errors(result)
346+
return User(**result.json())
347+
348+
async def update_user(
349+
self, email_id: str, body: User | dict[str, Any], **kwargs
350+
) -> User:
304351
"""Update the user details.
305352
306353
Args:
@@ -313,15 +360,24 @@ async def update_user(self, body: User | dict[str, Any], **kwargs) -> User:
313360
body = User.model_validate(body)
314361

315362
result = await self.c.put(
316-
url=f"{self.v2api_host}/v2/users/me/",
317-
headers=self.config.get_headers(
318-
with_project=False, with_organization=False, **kwargs
319-
),
363+
url=f"{self.v2api_host}/v2/users/{email_id}/",
364+
headers=self.config.get_headers(with_project=False, **kwargs),
320365
json=body.model_dump(by_alias=True),
321366
)
322367
handle_server_errors(result)
323368
return User(**result.json())
324369

370+
async def delete_user(self, email_id: str, **kwargs):
371+
"""
372+
Delete the User
373+
"""
374+
result = await self.c.delete(
375+
url=f"{self.v2api_host}/v2/users/{email_id}/",
376+
headers=self.config.get_headers(with_project=False, **kwargs),
377+
)
378+
handle_server_errors(result)
379+
return None
380+
325381
# ----------------- Projects -----------------
326382
async def list_projects(
327383
self,
@@ -1637,6 +1693,9 @@ async def commit_revision(
16371693
json=config_tree_revision,
16381694
)
16391695

1696+
handle_server_errors(result)
1697+
return result.json()
1698+
16401699
async def get_key_in_revision(
16411700
self,
16421701
tree_name: str,
@@ -1666,9 +1725,6 @@ async def get_key_in_revision(
16661725
# passing it through YAML parser.
16671726
return safe_load(result.text)
16681727

1669-
handle_server_errors(result)
1670-
return result.json()
1671-
16721728
async def put_key_in_revision(
16731729
self,
16741730
tree_name: str,

rapyuta_io_sdk_v2/client.py

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
from typing import Any
1717

1818
import httpx
19-
from munch import Munch
2019
from yaml import safe_load
2120

2221
from rapyuta_io_sdk_v2.config import Configuration
@@ -268,8 +267,26 @@ def list_users(
268267

269268
return UserList(**result.json())
270269

270+
def add_user(self, user: User | dict, **kwargs) -> User:
271+
"""Add a User in Organization.
272+
273+
Returns:
274+
User: User details as a user object.
275+
"""
276+
if isinstance(user, dict):
277+
user = User.model_validate(user)
278+
result = self.c.post(
279+
url=f"{self.v2api_host}/v2/users/",
280+
headers=self.config.get_headers(with_project=False, **kwargs),
281+
body=user.model_dump(by_alias=True),
282+
)
283+
284+
handle_server_errors(result)
285+
286+
return UserList(**result.json())
287+
271288
def get_myself(self, **kwargs) -> User:
272-
"""Get User details.
289+
"""Get my User details.
273290
274291
Returns:
275292
User: User details as a User object.
@@ -283,8 +300,8 @@ def get_myself(self, **kwargs) -> User:
283300
handle_server_errors(result)
284301
return User(**result.json())
285302

286-
def update_user(self, body: User | dict[str, Any], **kwargs) -> User:
287-
"""Update the user details.
303+
def update_myself(self, body: User | dict[str, Any], **kwargs) -> User:
304+
"""Update my user details.
288305
289306
Args:
290307
body (dict): User details
@@ -305,6 +322,50 @@ def update_user(self, body: User | dict[str, Any], **kwargs) -> User:
305322
handle_server_errors(result)
306323
return User(**result.json())
307324

325+
def get_user(self, email_id: str, **kwargs) -> User:
326+
"""Get User details.
327+
328+
Returns:
329+
User: User details as a User object.
330+
"""
331+
result = self.c.get(
332+
url=f"{self.v2api_host}/v2/users/{email_id}",
333+
headers=self.config.get_headers(with_project=False, **kwargs),
334+
)
335+
handle_server_errors(result)
336+
return User(**result.json())
337+
338+
def update_user(self, email_id: str, body: User | dict[str, Any], **kwargs) -> User:
339+
"""Update the user details.
340+
341+
Args:
342+
body (dict): User details
343+
344+
Returns:
345+
User: User details as a User object.
346+
"""
347+
if isinstance(body, dict):
348+
body = User.model_validate(body)
349+
350+
result = self.c.put(
351+
url=f"{self.v2api_host}/v2/users/{email_id}/",
352+
headers=self.config.get_headers(with_project=False, **kwargs),
353+
json=body.model_dump(by_alias=True),
354+
)
355+
handle_server_errors(result)
356+
return User(**result.json())
357+
358+
def delete_user(self, email_id: str, **kwargs):
359+
"""
360+
Delete the User
361+
"""
362+
result = self.c.delete(
363+
url=f"{self.v2api_host}/v2/users/{email_id}/",
364+
headers=self.config.get_headers(with_project=False, **kwargs),
365+
)
366+
handle_server_errors(result)
367+
return None
368+
308369
# -------------------Project-------------------
309370
def get_project(self, project_guid: str | None = None, **kwargs) -> Project:
310371
"""Get a project by its GUID.

tests/async_tests/test_configtree_async.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ async def test_commit_revision_success(async_client, mocker: AsyncMock):
261261

262262

263263
@pytest.mark.asyncio
264-
async def test_get_key_in_revision_str(client, mocker: AsyncMock): # noqa: F811
264+
async def test_get_key_in_revision_str(async_client, mocker: AsyncMock): # noqa: F811
265265
# Mock the httpx.AsyncClient.get method
266266
mock_get = mocker.patch("httpx.AsyncClient.get")
267267

@@ -279,15 +279,15 @@ async def test_get_key_in_revision_str(client, mocker: AsyncMock): # noqa: F811
279279

280280

281281
@pytest.mark.asyncio
282-
async def test_get_key_in_revision_int(client, mocker: AsyncMock): # noqa: F811
282+
async def test_get_key_in_revision_int(async_client, mocker: AsyncMock): # noqa: F811
283283
# Mock the httpx.AsyncClient.get method
284284
mock_get = mocker.patch("httpx.AsyncClient.get")
285285

286286
# Set up the mock response
287287
mock_get.return_value = httpx.Response(status_code=200, text="999")
288288

289289
# Call the get_key_in_revision method
290-
response = await client.get_key_in_revision(
290+
response = await async_client.get_key_in_revision(
291291
tree_name="mock_configtree_name", revision_id="mock_revision_id", key="mock_key"
292292
)
293293

@@ -297,15 +297,15 @@ async def test_get_key_in_revision_int(client, mocker: AsyncMock): # noqa: F811
297297

298298

299299
@pytest.mark.asyncio
300-
async def test_get_key_in_revision_bool(client, mocker: AsyncMock): # noqa: F811
300+
async def test_get_key_in_revision_bool(async_client, mocker: AsyncMock): # noqa: F811
301301
# Mock the httpx.AsyncClient.get method
302302
mock_get = mocker.patch("httpx.AsyncClient.get")
303303

304304
# Set up the mock response
305305
mock_get.return_value = httpx.Response(status_code=200, text="false")
306306

307307
# Call the get_key_in_revision method
308-
response = await client.get_key_in_revision(
308+
response = await async_client.get_key_in_revision(
309309
tree_name="mock_configtree_name", revision_id="mock_revision_id", key="mock_key"
310310
)
311311

tests/async_tests/test_organization_async.py

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,20 @@ async def test_get_organization_success(
2525
# Validate that response is an Organization model object
2626
assert isinstance(response, Organization)
2727
assert response.metadata.name == "test-org"
28-
assert response.metadata.guid == "mock_org_guid"
29-
assert len(response.spec.users) == 2
30-
assert response.spec.users[0].emailID == "[email protected]"
31-
assert response.spec.users[0].roleInOrganization == "viewer"
32-
assert response.spec.users[1].emailID == "[email protected]"
33-
assert response.spec.users[1].roleInOrganization == "admin"
28+
assert response.metadata.guid == "org-testorg123456789abcdef"
29+
assert len(response.spec.members) == 4
30+
# Check first member (ServiceAccount)
31+
assert response.spec.members[0].subject.kind == "ServiceAccount"
32+
assert response.spec.members[0].subject.name == "test-project-builtin-paramsync-sa"
33+
assert response.spec.members[0].roleNames == ["rio-org_member"]
34+
# Check second member (User - admin)
35+
assert response.spec.members[1].subject.kind == "User"
36+
assert response.spec.members[1].subject.name == "[email protected]"
37+
assert response.spec.members[1].roleNames == ["rio-org_admin", "rio-org_member"]
38+
# Check third member (User - member only)
39+
assert response.spec.members[2].subject.kind == "User"
40+
assert response.spec.members[2].subject.name == "[email protected]"
41+
assert response.spec.members[2].roleNames == ["rio-org_member"]
3442

3543

3644
@pytest.mark.asyncio
@@ -63,14 +71,16 @@ async def test_update_organization_success(
6371
)
6472

6573
response = await client.update_organization(
66-
organization_guid="mock_org_guid",
74+
organization_guid="org-testorg123456789abcdef",
6775
body=organization_body,
6876
)
6977

7078
# Validate that response is an Organization model object
7179
assert isinstance(response, Organization)
7280
assert response.metadata.name == "test-org"
73-
assert response.metadata.guid == "mock_org_guid"
74-
assert len(response.spec.users) == 2
75-
assert response.spec.users[0].roleInOrganization == "viewer"
76-
assert response.spec.users[1].roleInOrganization == "admin"
81+
assert response.metadata.guid == "org-testorg123456789abcdef"
82+
assert len(response.spec.members) == 4
83+
# Verify admin member
84+
assert response.spec.members[1].roleNames == ["rio-org_admin", "rio-org_member"]
85+
# Verify regular member
86+
assert response.spec.members[2].roleNames == ["rio-org_member"]

0 commit comments

Comments
 (0)