Skip to content

Commit 1c3fc29

Browse files
Fix user resource API inconsistencies (#346)
1 parent cf33e65 commit 1c3fc29

File tree

9 files changed

+230
-8
lines changed

9 files changed

+230
-8
lines changed
Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,51 @@
1+
from pydantic import StrictStr
2+
13
from conductor.asyncio_client.http.api import UserResourceApi
4+
from conductor.asyncio_client.adapters.models import UpsertUserRequestAdapter as UpsertUserRequest
5+
6+
7+
class UserResourceApiAdapter(UserResourceApi):
8+
async def get_granted_permissions(
9+
self,
10+
user_id: StrictStr,
11+
*args,
12+
**kwargs,
13+
) -> object:
14+
# Convert empty user_id to None to prevent sending invalid data to server
15+
if not user_id:
16+
user_id = None
17+
return await super().get_granted_permissions(user_id=user_id, *args, **kwargs)
18+
19+
async def get_user(
20+
self,
21+
id: StrictStr,
22+
*args,
23+
**kwargs,
24+
) -> object:
25+
# Convert empty user id to None to prevent sending invalid data to server
26+
if not id:
27+
id = None
28+
return await super().get_user(id=id, *args, **kwargs)
229

30+
async def upsert_user(
31+
self,
32+
id: StrictStr,
33+
upsert_user_request: UpsertUserRequest,
34+
*args,
35+
**kwargs,
36+
) -> object:
37+
# Convert empty user id to None to prevent sending invalid data to server
38+
if not id:
39+
id = None
40+
return await super().upsert_user(id=id, upsert_user_request=upsert_user_request, *args, **kwargs)
341

4-
class UserResourceApiAdapter(UserResourceApi): ...
42+
async def delete_user(
43+
self,
44+
id: StrictStr,
45+
*args,
46+
**kwargs,
47+
) -> object:
48+
# Convert empty user id to None to prevent sending invalid data to server
49+
if not id:
50+
id = None
51+
return await super().delete_user(id=id, *args, **kwargs)

src/conductor/asyncio_client/adapters/models/conductor_user_adapter.py

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

33
from typing import Any, Dict, List, Optional
44

5+
from pydantic import Field, StrictBool
56
from typing_extensions import Self
67

78
from conductor.asyncio_client.http.models import ConductorUser
@@ -10,6 +11,9 @@
1011
class ConductorUserAdapter(ConductorUser):
1112
groups: Optional[List["GroupAdapter"]] = None
1213
roles: Optional[List["RoleAdapter"]] = None
14+
orkes_app: Optional[StrictBool] = Field(default=None, alias="orkesApp")
15+
orkes_api_gateway: Optional[StrictBool] = Field(default=None, alias="orkesApiGateway")
16+
contact_information: Optional[Dict[Any, str]] = Field(default=None, alias="contactInformation")
1317

1418
@classmethod
1519
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
@@ -39,12 +43,19 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
3943
else None
4044
),
4145
"uuid": obj.get("uuid"),
46+
"orkesApp": obj.get("orkesApp"),
47+
"orkesApiGateway": obj.get("orkesApiGateway"),
48+
"contactInformation": obj.get("contactInformation"),
4249
}
4350
)
4451
return _obj
4552

4653

47-
from conductor.asyncio_client.adapters.models.group_adapter import GroupAdapter # noqa: E402
48-
from conductor.asyncio_client.adapters.models.role_adapter import RoleAdapter # noqa: E402
54+
from conductor.asyncio_client.adapters.models.group_adapter import ( # noqa: E402
55+
GroupAdapter,
56+
)
57+
from conductor.asyncio_client.adapters.models.role_adapter import ( # noqa: E402
58+
RoleAdapter,
59+
)
4960

5061
ConductorUserAdapter.model_rebuild(raise_errors=False)

src/conductor/asyncio_client/orkes/orkes_authorization_client.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ async def update_user(
5151
async def get_user(self, user_id: str) -> ConductorUser:
5252
"""Get user by ID"""
5353
user = await self.user_api.get_user(id=user_id)
54-
print(user)
5554

5655
return ConductorUser.from_dict(user)
5756

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,27 @@
11
from conductor.client.codegen.api.user_resource_api import UserResourceApi
22

33

4-
class UserResourceApiAdapter(UserResourceApi): ...
4+
class UserResourceApiAdapter(UserResourceApi):
5+
def get_granted_permissions(self, user_id, **kwargs):
6+
# Convert empty user_id to None to prevent sending invalid data to server
7+
if not user_id:
8+
user_id = None
9+
return super().get_granted_permissions(user_id=user_id, **kwargs)
10+
11+
def get_user(self, id, **kwargs):
12+
# Convert empty user id to None to prevent sending invalid data to server
13+
if not id:
14+
id = None
15+
return super().get_user(id=id, **kwargs)
16+
17+
def upsert_user(self, upsert_user_request, id, **kwargs):
18+
# Convert empty user id to None to prevent sending invalid data to server
19+
if not id:
20+
id = None
21+
return super().upsert_user(id=id, body=upsert_user_request, **kwargs)
22+
23+
def delete_user(self, id, **kwargs):
24+
# Convert empty user id to None to prevent sending invalid data to server
25+
if not id:
26+
id = None
27+
return super().delete_user(id=id, **kwargs)
Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,78 @@
11
from conductor.client.codegen.models import ConductorUser
22

33

4-
class ConductorUserAdapter(ConductorUser): ...
4+
class ConductorUserAdapter(ConductorUser):
5+
swagger_types = {
6+
**ConductorUser.swagger_types,
7+
"orkes_app": "bool",
8+
"orkes_api_gateway": "bool",
9+
"contact_information": "dict(str, str)",
10+
}
11+
12+
attribute_map = {
13+
**ConductorUser.attribute_map,
14+
"orkes_app": "orkesApp",
15+
"orkes_api_gateway": "orkesApiGateway",
16+
"contact_information": "contactInformation",
17+
}
18+
19+
def __init__(
20+
self,
21+
application_user=None,
22+
encrypted_id=None,
23+
encrypted_id_display_value=None,
24+
groups=None,
25+
id=None,
26+
name=None,
27+
orkes_workers_app=None,
28+
roles=None,
29+
uuid=None,
30+
orkes_app=None,
31+
orkes_api_gateway=None,
32+
contact_information=None,
33+
):
34+
super().__init__(
35+
application_user,
36+
encrypted_id,
37+
encrypted_id_display_value,
38+
groups,
39+
id,
40+
name,
41+
orkes_workers_app,
42+
roles,
43+
uuid,
44+
)
45+
self._orkes_app = None
46+
self._orkes_api_gateway = None
47+
self._contact_information = None
48+
49+
if orkes_app is not None:
50+
self.orkes_app = orkes_app
51+
if orkes_api_gateway is not None:
52+
self.orkes_api_gateway = orkes_api_gateway
53+
if contact_information is not None:
54+
self.contact_information = contact_information
55+
56+
@property
57+
def orkes_app(self):
58+
return self._orkes_app
59+
60+
@orkes_app.setter
61+
def orkes_app(self, orkes_app):
62+
self._orkes_app = orkes_app
63+
64+
@property
65+
def orkes_api_gateway(self):
66+
return self._orkes_api_gateway
67+
68+
@orkes_api_gateway.setter
69+
def orkes_api_gateway(self, orkes_api_gateway):
70+
self._orkes_api_gateway = orkes_api_gateway
71+
72+
@property
73+
def contact_information(self):
74+
return self._contact_information
75+
76+
@contact_information.setter
77+
def contact_information(self, contact_information):
78+
self._contact_information = contact_information

src/conductor/client/adapters/models/task_result_adapter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from conductor.client.adapters.models.task_exec_log_adapter import \
22
TaskExecLogAdapter
33
from conductor.client.codegen.models.task_result import TaskResult
4-
from conductor.client.http.models.task_result_status import TaskResultStatus
4+
from conductor.shared.http.enums.task_result_status import TaskResultStatus
55

66

77
class TaskResultAdapter(TaskResult):

src/conductor/client/helpers/helper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import six
88
from requests.structures import CaseInsensitiveDict
99

10-
import conductor.client.http.models as http_models
1110
from conductor.client.configuration.configuration import Configuration
1211
from conductor.client.codegen import rest
1312

@@ -84,6 +83,7 @@ def __deserialize(self, data, klass):
8483
if klass in self.NATIVE_TYPES_MAPPING:
8584
klass = self.NATIVE_TYPES_MAPPING[klass]
8685
else:
86+
import conductor.client.http.models as http_models
8787
klass = getattr(http_models, klass)
8888

8989
if klass in self.PRIMITIVE_TYPES:

tests/unit/orkes/test_async_authorization_client.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,13 +258,30 @@ async def test_get_user(mocker, authorization_client, conductor_user_adapter):
258258
assert user.uuid == USER_UUID
259259

260260

261+
@pytest.mark.asyncio
262+
async def test_get_user_with_empty_string(mocker, authorization_client, conductor_user_adapter):
263+
from conductor.asyncio_client.http.api import UserResourceApi
264+
mock = mocker.patch.object(UserResourceApi, "get_user")
265+
mock.return_value = conductor_user_adapter
266+
await authorization_client.get_user("")
267+
mock.assert_called_with(id=None)
268+
269+
261270
@pytest.mark.asyncio
262271
async def test_delete_user(mocker, authorization_client):
263272
mock = mocker.patch.object(UserResourceApiAdapter, "delete_user")
264273
await authorization_client.delete_user(USER_ID)
265274
mock.assert_called_with(id=USER_ID)
266275

267276

277+
@pytest.mark.asyncio
278+
async def test_delete_user_with_empty_string(mocker, authorization_client):
279+
from conductor.asyncio_client.http.api import UserResourceApi
280+
mock = mocker.patch.object(UserResourceApi, "delete_user")
281+
await authorization_client.delete_user("")
282+
mock.assert_called_with(id=None)
283+
284+
268285
@pytest.mark.asyncio
269286
async def test_list_users_with_apps(mocker, authorization_client, conductor_user_adapter):
270287
mock = mocker.patch.object(UserResourceApiAdapter, "list_users")
@@ -295,6 +312,16 @@ async def test_upsert_user(mocker, authorization_client, conductor_user_adapter)
295312
assert user.uuid == USER_UUID
296313

297314

315+
@pytest.mark.asyncio
316+
async def test_upsert_user_with_empty_string(mocker, authorization_client, conductor_user_adapter):
317+
from conductor.asyncio_client.http.api import UserResourceApi
318+
mock = mocker.patch.object(UserResourceApi, "upsert_user")
319+
upsert_req = UpsertUserRequestAdapter(name=USER_NAME, roles=["ADMIN"])
320+
mock.return_value = conductor_user_adapter
321+
await authorization_client.upsert_user("", upsert_req)
322+
mock.assert_called_with(id=None, upsert_user_request=upsert_req)
323+
324+
298325
@pytest.mark.asyncio
299326
async def test_create_group(mocker, authorization_client, group_adapter):
300327
mock = mocker.patch.object(GroupResourceApiAdapter, "upsert_group")
@@ -484,6 +511,15 @@ async def test_get_group_permissions(mocker, authorization_client: OrkesAuthoriz
484511
}
485512

486513

514+
@pytest.mark.asyncio
515+
async def test_get_granted_permissions_for_user_with_empty_string(mocker, authorization_client):
516+
from conductor.asyncio_client.http.api import UserResourceApi
517+
mock = mocker.patch.object(UserResourceApi, "get_granted_permissions")
518+
mock.return_value = {"grantedAccess": []}
519+
await authorization_client.get_granted_permissions_for_user("")
520+
mock.assert_called_with(user_id=None)
521+
522+
487523
@pytest.mark.asyncio
488524
async def test_create_access_key_empty_string_converts_to_none(mocker, authorization_client):
489525
from conductor.asyncio_client.http.api.application_resource_api import (

tests/unit/orkes/test_authorization_client.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,15 @@ def test_upsert_user(mocker, authorization_client, conductor_user, roles):
312312
assert user.roles == roles
313313

314314

315+
def test_upsert_user_with_empty_string(mocker, authorization_client, conductor_user, roles):
316+
from conductor.client.codegen.api.user_resource_api import UserResourceApi
317+
mock = mocker.patch.object(UserResourceApi, "upsert_user")
318+
upsert_req = UpsertUserRequest(USER_NAME, ["ADMIN"])
319+
mock.return_value = conductor_user.to_dict()
320+
authorization_client.upsert_user(upsert_req, "")
321+
mock.assert_called_with(id=None, body=upsert_req)
322+
323+
315324
def test_get_user(mocker, authorization_client, conductor_user, roles):
316325
mock = mocker.patch.object(UserResourceApi, "get_user")
317326
mock.return_value = conductor_user.to_dict()
@@ -323,6 +332,14 @@ def test_get_user(mocker, authorization_client, conductor_user, roles):
323332
assert user.roles == roles
324333

325334

335+
def test_get_user_with_empty_string(mocker, authorization_client, conductor_user):
336+
from conductor.client.codegen.api.user_resource_api import UserResourceApi
337+
mock = mocker.patch.object(UserResourceApi, "get_user")
338+
mock.return_value = conductor_user.to_dict()
339+
authorization_client.get_user("")
340+
mock.assert_called_with(id=None)
341+
342+
326343
def test_list_users_with_apps(mocker, authorization_client, conductor_user):
327344
mock = mocker.patch.object(UserResourceApi, "list_users")
328345
mock.return_value = [conductor_user]
@@ -345,6 +362,13 @@ def test_delete_user(mocker, authorization_client):
345362
mock.assert_called_with(USER_ID)
346363

347364

365+
def test_delete_user_with_empty_string(mocker, authorization_client):
366+
from conductor.client.codegen.api.user_resource_api import UserResourceApi
367+
mock = mocker.patch.object(UserResourceApi, "delete_user")
368+
authorization_client.delete_user("")
369+
mock.assert_called_with(id=None)
370+
371+
348372
def test_upsert_group(mocker, authorization_client, conductor_group, group_roles):
349373
mock = mocker.patch.object(GroupResourceApi, "upsert_group")
350374
upsertReq = UpsertGroupRequest(GROUP_NAME, ["USER"])
@@ -453,6 +477,14 @@ def test_get_granted_permissions_for_user(mocker, authorization_client):
453477
assert perms == [expected_perm]
454478

455479

480+
def test_get_granted_permissions_for_user_with_empty_string(mocker, authorization_client):
481+
from conductor.client.codegen.api.user_resource_api import UserResourceApi
482+
mock = mocker.patch.object(UserResourceApi, "get_granted_permissions")
483+
mock.return_value = {"grantedAccess": []}
484+
authorization_client.get_granted_permissions_for_user("")
485+
mock.assert_called_with(user_id=None)
486+
487+
456488
def test_get_permissions(mocker, authorization_client):
457489
mock = mocker.patch.object(AuthorizationResourceApi, "get_permissions")
458490
mock.return_value = {

0 commit comments

Comments
 (0)