Skip to content

Commit 2004c66

Browse files
committed
connects other search options
1 parent 2073214 commit 2004c66

File tree

4 files changed

+73
-15
lines changed

4 files changed

+73
-15
lines changed

packages/models-library/src/models_library/api_schemas_webserver/users.py

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import re
2+
from ast import TypeAlias
23
from datetime import date, datetime
34
from enum import Enum
4-
from typing import Annotated, Any, Literal, Self
5+
from typing import Annotated, Any, Literal, Self, TypeAlias
56

67
import annotated_types
78
from common_library.basic_types import DEFAULT_FACTORY
@@ -18,6 +19,7 @@
1819
StringConstraints,
1920
ValidationInfo,
2021
field_validator,
22+
model_validator,
2123
)
2224
from pydantic.config import JsonDict
2325

@@ -313,15 +315,40 @@ class UserAccountReject(InputSchema):
313315
email: EmailStr
314316

315317

318+
GlobString: TypeAlias = Annotated[
319+
str,
320+
StringConstraints(
321+
min_length=3, max_length=200, strip_whitespace=True, pattern=r"^[^%]*$"
322+
),
323+
]
324+
325+
316326
class UserAccountSearchQueryParams(RequestParameters):
317327
email: Annotated[
318-
str,
328+
GlobString | None,
319329
Field(
320-
min_length=3,
321-
max_length=200,
322330
description="complete or glob pattern for an email",
323331
),
324-
]
332+
] = None
333+
primary_group_id: Annotated[
334+
GroupID | None,
335+
Field(
336+
description="Filter by primary group ID",
337+
),
338+
] = None
339+
user_name: Annotated[
340+
GlobString | None,
341+
Field(
342+
description="complete or glob pattern for a username",
343+
),
344+
] = None
345+
346+
@model_validator(mode="after")
347+
def _validate_at_least_one_filter(self) -> Self:
348+
if not any([self.email, self.primary_group_id, self.user_name]):
349+
msg = "At least one filter (email, primary_group_id, or user_name) must be provided"
350+
raise ValueError(msg)
351+
return self
325352

326353

327354
class UserAccountGet(OutputSchema):

services/web/server/src/simcore_service_webserver/users/_accounts_service.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ async def pre_register_user(
3636
) -> UserAccountGet:
3737

3838
found = await search_users_accounts(
39-
app, email_glob=profile.email, product_name=product_name, include_products=False
39+
app,
40+
filter_by_email_glob=profile.email,
41+
product_name=product_name,
42+
include_products=False,
4043
)
4144
if found:
4245
raise AlreadyPreRegisteredError(num_found=len(found), email=profile.email)
@@ -70,7 +73,10 @@ async def pre_register_user(
7073
)
7174

7275
found = await search_users_accounts(
73-
app, email_glob=profile.email, product_name=product_name, include_products=False
76+
app,
77+
filter_by_email_glob=profile.email,
78+
product_name=product_name,
79+
include_products=False,
7480
)
7581

7682
assert len(found) == 1 # nosec
@@ -143,7 +149,9 @@ async def list_user_accounts(
143149
async def search_users_accounts(
144150
app: web.Application,
145151
*,
146-
email_glob: str,
152+
filter_by_email_glob: str | None = None,
153+
filter_by_primary_group_id: int | None = None,
154+
filter_by_user_name_glob: str | None = None,
147155
product_name: ProductName | None = None,
148156
include_products: bool = False,
149157
) -> list[UserAccountGet]:
@@ -156,6 +164,14 @@ async def search_users_accounts(
156164
no caller or context is available.
157165
"""
158166

167+
if (
168+
filter_by_email_glob is None
169+
and filter_by_user_name_glob is None
170+
and filter_by_primary_group_id is None
171+
):
172+
msg = "At least one filter (email glob, user name like, or primary group ID) must be provided"
173+
raise ValueError(msg)
174+
159175
def _glob_to_sql_like(glob_pattern: str) -> str:
160176
# Escape SQL LIKE special characters in the glob pattern
161177
sql_like_pattern = glob_pattern.replace("%", r"\%").replace("_", r"\_")
@@ -164,7 +180,15 @@ def _glob_to_sql_like(glob_pattern: str) -> str:
164180

165181
rows = await _accounts_repository.search_merged_pre_and_registered_users(
166182
get_asyncpg_engine(app),
167-
filter_by_email_like=_glob_to_sql_like(email_glob),
183+
filter_by_email_like=(
184+
_glob_to_sql_like(filter_by_email_glob) if filter_by_email_glob else None
185+
),
186+
filter_by_primary_group_id=filter_by_primary_group_id,
187+
filter_by_user_name_like=(
188+
_glob_to_sql_like(filter_by_user_name_glob)
189+
if filter_by_user_name_glob
190+
else None
191+
),
168192
product_name=product_name,
169193
)
170194

services/web/server/src/simcore_service_webserver/users/_controller/rest/accounts_rest.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,11 @@ async def search_user_accounts(request: web.Request) -> web.Response:
113113
)
114114

115115
found = await _accounts_service.search_users_accounts(
116-
request.app, email_glob=query_params.email, include_products=True
116+
request.app,
117+
filter_by_email_glob=query_params.email,
118+
filter_by_primary_group_id=query_params.primary_group_id,
119+
filter_by_user_name_glob=query_params.user_name,
120+
include_products=True,
117121
)
118122

119123
return envelope_json_response(
@@ -214,7 +218,7 @@ async def approve_user_account(request: web.Request) -> web.Response:
214218
# get pre-registration data
215219
found = await _accounts_service.search_users_accounts(
216220
request.app,
217-
email_glob=approval_data.email,
221+
filter_by_email_glob=approval_data.email,
218222
product_name=req_ctx.product_name,
219223
include_products=False,
220224
)
@@ -270,7 +274,7 @@ async def reject_user_account(request: web.Request) -> web.Response:
270274
# get pre-registration data
271275
found = await _accounts_service.search_users_accounts(
272276
request.app,
273-
email_glob=rejection_data.email,
277+
filter_by_email_glob=rejection_data.email,
274278
product_name=req_ctx.product_name,
275279
include_products=False,
276280
)

services/web/server/tests/unit/with_dbs/03/users/test_users_accounts_service.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,10 @@ async def test_search_users_as_admin_real_user(
8383

8484
# Act
8585
found_users = await _accounts_service.search_users_accounts(
86-
app, email_glob=user_email, product_name=product_name, include_products=False
86+
app,
87+
filter_by_email_glob=user_email,
88+
product_name=product_name,
89+
include_products=False,
8790
)
8891

8992
# Assert
@@ -112,7 +115,7 @@ async def test_search_users_as_admin_pre_registered_user(
112115

113116
# Act
114117
found_users = await _accounts_service.search_users_accounts(
115-
app, email_glob=pre_registered_email, product_name=product_name
118+
app, filter_by_email_glob=pre_registered_email, product_name=product_name
116119
)
117120

118121
# Assert
@@ -165,7 +168,7 @@ async def test_search_users_as_admin_wildcard(
165168

166169
# Act - search with wildcard for the domain
167170
found_users = await _accounts_service.search_users_accounts(
168-
app, email_glob=f"*{email_domain}", product_name=product_name
171+
app, filter_by_email_glob=f"*{email_domain}", product_name=product_name
169172
)
170173

171174
# Assert

0 commit comments

Comments
 (0)