Skip to content

Commit 34e6cc5

Browse files
Rasmus Welanderdiocas
authored andcommitted
Add filter creation methods
1 parent 301af47 commit 34e6cc5

File tree

4 files changed

+244
-1
lines changed

4 files changed

+244
-1
lines changed

cs3client/group.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
"""
88

99
import logging
10+
from typing import Optional
11+
1012
import cs3.identity.group.v1beta1.resources_pb2 as cs3igr
1113
import cs3.identity.group.v1beta1.group_api_pb2 as cs3ig
1214
import cs3.identity.user.v1beta1.resources_pb2 as cs3iur
@@ -122,3 +124,26 @@ def find_groups(self, auth_token: tuple, filters) -> list[cs3igr.Group]:
122124
self._status_code_handler.handle_errors(res.status, "find groups")
123125
self._log.debug(f'msg="Invoked FindGroups" filter="{filter}" trace="{res.status.trace}"')
124126
return res.groups
127+
128+
@classmethod
129+
def create_find_group_filter(cls, filter_type: str, query: Optional[str], group_type: Optional[str]) -> cs3ig.Filter:
130+
"""
131+
Create a filter for finding groups.
132+
133+
:param filter_type: The type of filter to create. Supported types: TYPE_GROUPTYPE, TYPE_QUERY.
134+
:param query: The query string for TYPE_QUERY filter, or GROUP_TYPE_FEDERATED/GROUP_TYPE_REGULAR for TYPE_GROUPTYPE.
135+
:return: A filter object.
136+
:raises: ValueError (Unsupported filter type)
137+
"""
138+
filter_type_value = cs3ig.Filter.Type.Value(filter_type.upper())
139+
if filter_type_value == cs3ig.Filter.Type.TYPE_QUERY:
140+
if query is None:
141+
raise ValueError("query must be provided for TYPE_QUERY filter")
142+
return cs3ig.Filter(type=filter_type_value, query=query)
143+
elif filter_type_value == cs3ig.Filter.Type.TYPE_GROUPTYPE:
144+
if group_type is None:
145+
raise ValueError("group_type must be provided for TYPE_GROUPTYPE filter")
146+
group_type_value = cs3igr.GroupType.Value(group_type.upper())
147+
return cs3ig.Filter(type=filter_type_value, grouptype=group_type_value)
148+
else:
149+
raise ValueError(f"Unsupported filter type: {filter_type}")

cs3client/user.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
"""
88

99
import logging
10+
from typing import Optional
11+
1012
import cs3.identity.user.v1beta1.resources_pb2 as cs3iur
1113
import cs3.identity.user.v1beta1.user_api_pb2 as cs3iu
1214
from cs3.gateway.v1beta1.gateway_api_pb2_grpc import GatewayAPIStub
@@ -106,3 +108,27 @@ def find_users(self, auth_token: tuple, filters) -> list[cs3iur.User]:
106108
self._status_code_handler.handle_errors(res.status, "find users")
107109
self._log.debug(f'msg="Invoked FindUsers" filter="{filter}" trace="{res.status.trace}"')
108110
return res.users
111+
112+
@classmethod
113+
def create_find_user_filter(cls, filter_type: str, query: Optional[str] = None, user_type: Optional[str] = None) -> cs3iu.Filter:
114+
"""
115+
Create a filter for finding users.
116+
117+
:param filter_type: The type of filter to create. Supported types: TYPE_QUERY, TYPE_USER_TYPE.
118+
:param query: The query string for TYPE_QUERY filter.
119+
:param user_type: The user type for TYPE_USER_TYPE filter. Supported types: USER_TYPE_PRIMARY,
120+
USER_TYPE_SECONDARY, USER_TYPE_SERVICE, USER_TYPE_GUEST, USER_TYPE_FEDERATED, USER_TYPE_LIGHTWEIGHT,
121+
USER_TYPE_SPACE_OWNER.
122+
:return: A filter object.
123+
:raises: ValueError (Unsupported filter type)
124+
"""
125+
filter_type = cs3iu.Filter.Type.Value(filter_type.upper())
126+
if filter_type == cs3iu.Filter.Type.TYPE_QUERY:
127+
return cs3iu.Filter(type=filter_type, query=query)
128+
elif filter_type == cs3iu.Filter.Type.TYPE_USERTYPE:
129+
if user_type is None:
130+
raise ValueError("user_type must be provided for TYPE_USERTYPE filter")
131+
user_type = cs3iur.UserType.Value(user_type.upper())
132+
return cs3iu.Filter(type=filter_type, usertype=user_type)
133+
else:
134+
raise ValueError(f"Unsupported filter type: {filter_type}")

tests/test_group.py

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
import cs3.rpc.v1beta1.code_pb2 as cs3code
1414
import cs3.identity.group.v1beta1.group_api_pb2 as cs3ig
1515
import cs3.identity.group.v1beta1.resources_pb2 as cs3igr
16+
from cs3client.group import Group
17+
18+
1619

1720
from cs3client.exceptions import (
1821
AuthenticationException,
@@ -192,4 +195,95 @@ def test_get_group_by_claim(
192195
group_instance.get_group_by_claim(auth_token, claim, value)
193196
else:
194197
result = group_instance.get_group_by_claim(auth_token, claim, value)
195-
assert result == group_data
198+
assert result == group_data
199+
200+
201+
@pytest.mark.parametrize(
202+
"filter_type, query, group_type, expected_exception",
203+
[
204+
("TYPE_QUERY", "test_group", None, None),
205+
("TYPE_GROUPTYPE", None, "GROUP_TYPE_FEDERATED", None),
206+
("TYPE_GROUPTYPE", None, "GROUP_TYPE_REGULAR", None),
207+
("TYPE_GROUPTYPE", None, None, ValueError),
208+
("TYPE_INVALID", "test", None, ValueError),
209+
],
210+
)
211+
def test_create_find_group_filter(filter_type, query, group_type, expected_exception):
212+
"""Test the create_find_group_filter classmethod."""
213+
214+
if expected_exception:
215+
with pytest.raises(expected_exception):
216+
Group.create_find_group_filter(filter_type, query, group_type)
217+
else:
218+
result = Group.create_find_group_filter(filter_type, query, group_type)
219+
assert result is not None
220+
assert isinstance(result, cs3ig.Filter)
221+
222+
223+
@pytest.mark.parametrize(
224+
"status_code, status_message, expected_exception, groups, filter_type, query, group_type",
225+
[
226+
(cs3code.CODE_OK, None, None, [Mock(), Mock()], "TYPE_QUERY", "test_group", None),
227+
(cs3code.CODE_OK, None, None, [Mock()], "TYPE_GROUPTYPE", None, "GROUP_TYPE_FEDERATED"),
228+
(cs3code.CODE_OK, None, None, [Mock()], "TYPE_GROUPTYPE", None, "GROUP_TYPE_REGULAR"),
229+
(cs3code.CODE_NOT_FOUND, "error", NotFoundException, None, "TYPE_QUERY", "nonexistent", None),
230+
(cs3code.CODE_UNAUTHENTICATED, "error", AuthenticationException, None, "TYPE_QUERY", "test", None),
231+
(-2, "error", UnknownException, None, "TYPE_GROUPTYPE", None, "GROUP_TYPE_REGULAR"),
232+
],
233+
)
234+
def test_find_groups_with_filter_creation(
235+
group_instance, status_code, status_message, expected_exception, groups, filter_type, query, group_type # noqa: F811 (not a redefinition)
236+
):
237+
"""Test find_groups using the create_find_group_filter classmethod."""
238+
239+
# Create filter using the classmethod
240+
group_filter = Group.create_find_group_filter(filter_type, query, group_type)
241+
filters = [group_filter]
242+
243+
mock_response = Mock()
244+
mock_response.status.code = status_code
245+
mock_response.status.message = status_message
246+
mock_response.groups = groups
247+
auth_token = ('x-access-token', "some_token")
248+
249+
with patch.object(group_instance._gateway, "FindGroups", return_value=mock_response):
250+
if expected_exception:
251+
with pytest.raises(expected_exception):
252+
group_instance.find_groups(auth_token, filters)
253+
else:
254+
result = group_instance.find_groups(auth_token, filters)
255+
assert result == groups
256+
257+
258+
@pytest.mark.parametrize(
259+
"status_code, status_message, expected_exception, groups",
260+
[
261+
(cs3code.CODE_OK, None, None, [Mock(), Mock()]),
262+
(cs3code.CODE_NOT_FOUND, "error", NotFoundException, None),
263+
(cs3code.CODE_UNAUTHENTICATED, "error", AuthenticationException, None),
264+
(-2, "error", UnknownException, None),
265+
],
266+
)
267+
def test_find_groups_with_multiple_filters(
268+
group_instance, status_code, status_message, expected_exception, groups # noqa: F811 (not a redefinition)
269+
):
270+
"""Test find_groups with multiple filters using the create_find_group_filter classmethod."""
271+
272+
# Create multiple filters using the classmethod
273+
filter1 = Group.create_find_group_filter("TYPE_QUERY", "test", None)
274+
filter2 = Group.create_find_group_filter("TYPE_GROUPTYPE", None, "GROUP_TYPE_FEDERATED")
275+
filters = [filter1, filter2]
276+
277+
mock_response = Mock()
278+
mock_response.status.code = status_code
279+
mock_response.status.message = status_message
280+
mock_response.groups = groups
281+
auth_token = ('x-access-token', "some_token")
282+
283+
with patch.object(group_instance._gateway, "FindGroups", return_value=mock_response):
284+
if expected_exception:
285+
with pytest.raises(expected_exception):
286+
group_instance.find_groups(auth_token, filters)
287+
else:
288+
result = group_instance.find_groups(auth_token, filters)
289+
assert result == groups

tests/test_user.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import cs3.rpc.v1beta1.code_pb2 as cs3code
1414
import cs3.identity.user.v1beta1.user_api_pb2 as cs3iu
1515
import cs3.identity.user.v1beta1.resources_pb2 as cs3iur
16+
from cs3client.user import User
17+
1618

1719
from cs3client.exceptions import (
1820
AuthenticationException,
@@ -145,3 +147,99 @@ def test_find_users(
145147
else:
146148
result = user_instance.find_users(auth_token, filters)
147149
assert result == users
150+
151+
152+
@pytest.mark.parametrize(
153+
"filter_type, query, user_type, expected_exception",
154+
[
155+
("TYPE_QUERY", "test_user", None, None),
156+
("TYPE_USERTYPE", None, "USER_TYPE_PRIMARY", None),
157+
("TYPE_USERTYPE", None, "USER_TYPE_SECONDARY", None),
158+
("TYPE_USERTYPE", None, "USER_TYPE_SERVICE", None),
159+
("TYPE_USERTYPE", None, "USER_TYPE_GUEST", None),
160+
("TYPE_USERTYPE", None, "USER_TYPE_FEDERATED", None),
161+
("TYPE_USERTYPE", None, "USER_TYPE_LIGHTWEIGHT", None),
162+
("TYPE_USERTYPE", None, "USER_TYPE_SPACE_OWNER", None),
163+
("TYPE_USERTYPE", None, None, ValueError),
164+
("TYPE_INVALID", "test", None, ValueError),
165+
],
166+
)
167+
def test_create_find_user_filter(filter_type, query, user_type, expected_exception):
168+
"""Test the create_find_user_filter classmethod."""
169+
170+
if expected_exception:
171+
with pytest.raises(expected_exception):
172+
User.create_find_user_filter(filter_type, query, user_type)
173+
else:
174+
result = User.create_find_user_filter(filter_type, query, user_type)
175+
assert result is not None
176+
assert isinstance(result, cs3iu.Filter)
177+
178+
179+
@pytest.mark.parametrize(
180+
"status_code, status_message, expected_exception, users, filter_type, query, user_type",
181+
[
182+
(cs3code.CODE_OK, None, None, [Mock(), Mock()], "TYPE_QUERY", "test_user", None),
183+
(cs3code.CODE_OK, None, None, [Mock()], "TYPE_USERTYPE", None, "USER_TYPE_PRIMARY"),
184+
(cs3code.CODE_OK, None, None, [Mock()], "TYPE_USERTYPE", None, "USER_TYPE_FEDERATED"),
185+
(cs3code.CODE_NOT_FOUND, "error", NotFoundException, None, "TYPE_QUERY", "nonexistent", None),
186+
(cs3code.CODE_UNAUTHENTICATED, "error", AuthenticationException, None, "TYPE_QUERY", "test", None),
187+
(-2, "error", UnknownException, None, "TYPE_USERTYPE", None, "USER_TYPE_SERVICE"),
188+
],
189+
)
190+
def test_find_users_with_filter_creation(
191+
user_instance, status_code, status_message, expected_exception, users, filter_type, query, user_type # noqa: F811 (not a redefinition)
192+
):
193+
"""Test find_users using the create_find_user_filter classmethod."""
194+
195+
# Create filter using the classmethod
196+
user_filter = User.create_find_user_filter(filter_type, query, user_type)
197+
filters = [user_filter]
198+
199+
mock_response = Mock()
200+
mock_response.status.code = status_code
201+
mock_response.status.message = status_message
202+
mock_response.users = users
203+
auth_token = ('x-access-token', "some_token")
204+
205+
with patch.object(user_instance._gateway, "FindUsers", return_value=mock_response):
206+
if expected_exception:
207+
with pytest.raises(expected_exception):
208+
user_instance.find_users(auth_token, filters)
209+
else:
210+
result = user_instance.find_users(auth_token, filters)
211+
assert result == users
212+
213+
214+
@pytest.mark.parametrize(
215+
"status_code, status_message, expected_exception, users",
216+
[
217+
(cs3code.CODE_OK, None, None, [Mock(), Mock()]),
218+
(cs3code.CODE_NOT_FOUND, "error", NotFoundException, None),
219+
(cs3code.CODE_UNAUTHENTICATED, "error", AuthenticationException, None),
220+
(-2, "error", UnknownException, None),
221+
],
222+
)
223+
def test_find_users_with_multiple_filters(
224+
user_instance, status_code, status_message, expected_exception, users # noqa: F811 (not a redefinition)
225+
):
226+
"""Test find_users with multiple filters using the create_find_user_filter classmethod."""
227+
228+
# Create multiple filters using the classmethod
229+
filter1 = User.create_find_user_filter("TYPE_QUERY", "test", None)
230+
filter2 = User.create_find_user_filter("TYPE_USERTYPE", None, "USER_TYPE_PRIMARY")
231+
filters = [filter1, filter2]
232+
233+
mock_response = Mock()
234+
mock_response.status.code = status_code
235+
mock_response.status.message = status_message
236+
mock_response.users = users
237+
auth_token = ('x-access-token', "some_token")
238+
239+
with patch.object(user_instance._gateway, "FindUsers", return_value=mock_response):
240+
if expected_exception:
241+
with pytest.raises(expected_exception):
242+
user_instance.find_users(auth_token, filters)
243+
else:
244+
result = user_instance.find_users(auth_token, filters)
245+
assert result == users

0 commit comments

Comments
 (0)