Skip to content

Commit e61f6bc

Browse files
Merge branch 'master' into fix-listing-2
2 parents c9de24a + 89f3caf commit e61f6bc

File tree

48 files changed

+2570
-553
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+2570
-553
lines changed

api/specs/web-server/_auth.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,8 @@ async def email_confirmation(code: str):
260260

261261
@router.get(
262262
"/auth/captcha",
263-
operation_id="request_captcha",
263+
operation_id="create_captcha",
264264
status_code=status.HTTP_200_OK,
265265
responses={status.HTTP_200_OK: {"content": {"image/png": {}}}},
266266
)
267-
async def request_captcha(): ...
267+
async def create_captcha(): ...

api/specs/web-server/_users.py

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,25 @@
77
from enum import Enum
88
from typing import Annotated
99

10+
from _common import as_query
1011
from fastapi import APIRouter, Depends, status
1112
from models_library.api_schemas_webserver.users import (
1213
MyPermissionGet,
1314
MyProfileGet,
1415
MyProfilePatch,
1516
MyTokenCreate,
1617
MyTokenGet,
17-
UserForAdminGet,
18+
UserAccountApprove,
19+
UserAccountGet,
20+
UserAccountReject,
21+
UserAccountSearchQueryParams,
1822
UserGet,
19-
UsersForAdminSearchQueryParams,
23+
UsersAccountListQueryParams,
2024
UsersSearch,
2125
)
2226
from models_library.api_schemas_webserver.users_preferences import PatchRequestBody
2327
from models_library.generics import Envelope
28+
from models_library.rest_pagination import Page
2429
from models_library.user_preferences import PreferenceIdentifier
2530
from simcore_service_webserver._meta import API_VTAG
2631
from simcore_service_webserver.users._common.schemas import PreRegisteredUserGet
@@ -144,20 +149,46 @@ async def search_users(_body: UsersSearch): ...
144149

145150

146151
@router.get(
147-
"/admin/users:search",
148-
response_model=Envelope[list[UserForAdminGet]],
152+
"/admin/user-accounts",
153+
response_model=Page[UserAccountGet],
149154
tags=_extra_tags,
150155
)
151-
async def search_users_for_admin(
152-
_query: Annotated[UsersForAdminSearchQueryParams, Depends()],
156+
async def list_users_accounts(
157+
_query: Annotated[as_query(UsersAccountListQueryParams), Depends()],
158+
): ...
159+
160+
161+
@router.post(
162+
"/admin/user-accounts:approve",
163+
status_code=status.HTTP_204_NO_CONTENT,
164+
tags=_extra_tags,
165+
)
166+
async def approve_user_account(_body: UserAccountApprove): ...
167+
168+
169+
@router.post(
170+
"/admin/user-accounts:reject",
171+
status_code=status.HTTP_204_NO_CONTENT,
172+
tags=_extra_tags,
173+
)
174+
async def reject_user_account(_body: UserAccountReject): ...
175+
176+
177+
@router.get(
178+
"/admin/user-accounts:search",
179+
response_model=Envelope[list[UserAccountGet]],
180+
tags=_extra_tags,
181+
)
182+
async def search_user_accounts(
183+
_query: Annotated[UserAccountSearchQueryParams, Depends()],
153184
):
154185
# NOTE: see `Search` in `Common Custom Methods` in https://cloud.google.com/apis/design/custom_methods
155186
...
156187

157188

158189
@router.post(
159-
"/admin/users:pre-register",
160-
response_model=Envelope[UserForAdminGet],
190+
"/admin/user-accounts:pre-register",
191+
response_model=Envelope[UserAccountGet],
161192
tags=_extra_tags,
162193
)
163-
async def pre_register_user_for_admin(_body: PreRegisteredUserGet): ...
194+
async def pre_register_user_account(_body: PreRegisteredUserGet): ...

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

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import re
2-
from datetime import date
2+
from datetime import date, datetime
33
from enum import Enum
44
from typing import Annotated, Any, Literal, Self
55

66
import annotated_types
77
from common_library.basic_types import DEFAULT_FACTORY
88
from common_library.dict_tools import remap_keys
9-
from common_library.users_enums import UserStatus
9+
from common_library.users_enums import AccountRequestStatus, UserStatus
1010
from models_library.groups import AccessRightsDict
11+
from models_library.rest_filters import Filters
12+
from models_library.rest_pagination import PageQueryParameters
1113
from pydantic import (
1214
ConfigDict,
1315
EmailStr,
@@ -39,6 +41,7 @@
3941
OutputSchemaWithoutCamelCase,
4042
)
4143
from .groups import MyGroupsGet
44+
from .products import InvitationGenerate
4245
from .users_preferences import AggregatedPreferences
4346

4447
#
@@ -238,7 +241,30 @@ def from_domain_model(cls, data):
238241
return cls.model_validate(data, from_attributes=True)
239242

240243

241-
class UsersForAdminSearchQueryParams(RequestParameters):
244+
class UsersForAdminListFilter(Filters):
245+
# 1. account_request_status: PENDING, REJECTED, APPROVED
246+
# 2. If APPROVED AND user uses the invitation link, then when user is registered,
247+
# it can be in any of these statuses:
248+
# CONFIRMATION_PENDING, ACTIVE, EXPIRED, BANNED, DELETED
249+
#
250+
review_status: Literal["PENDING", "REVIEWED"] | None = None
251+
252+
model_config = ConfigDict(extra="forbid")
253+
254+
255+
class UsersAccountListQueryParams(UsersForAdminListFilter, PageQueryParameters): ...
256+
257+
258+
class UserAccountApprove(InputSchema):
259+
email: EmailStr
260+
invitation: InvitationGenerate | None = None
261+
262+
263+
class UserAccountReject(InputSchema):
264+
email: EmailStr
265+
266+
267+
class UserAccountSearchQueryParams(RequestParameters):
242268
email: Annotated[
243269
str,
244270
Field(
@@ -249,7 +275,7 @@ class UsersForAdminSearchQueryParams(RequestParameters):
249275
]
250276

251277

252-
class UserForAdminGet(OutputSchema):
278+
class UserAccountGet(OutputSchema):
253279
# ONLY for admins
254280
first_name: str | None
255281
last_name: str | None
@@ -269,8 +295,12 @@ class UserForAdminGet(OutputSchema):
269295
),
270296
] = DEFAULT_FACTORY
271297

272-
# authorization
298+
# pre-registration
299+
pre_registration_id: int | None
273300
invited_by: str | None = None
301+
account_request_status: AccountRequestStatus | None
302+
account_request_reviewed_by: UserID | None = None
303+
account_request_reviewed_at: datetime | None = None
274304

275305
# user status
276306
registered: bool

packages/service-library/src/servicelib/aiohttp/rest_responses.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
from common_library.error_codes import ErrorCodeStr
99
from common_library.json_serialization import json_dumps
1010
from models_library.rest_error import ErrorGet, ErrorItemType
11-
from servicelib.rest_constants import RESPONSE_MODEL_POLICY
1211

1312
from ..aiohttp.status import HTTP_200_OK
1413
from ..mimetype_constants import MIMETYPE_APPLICATION_JSON
14+
from ..rest_constants import RESPONSE_MODEL_POLICY
1515
from ..rest_responses import is_enveloped
1616
from ..status_codes_utils import get_code_description
1717

@@ -54,7 +54,7 @@ def create_http_error(
5454
http_error_cls: type[HTTPError] = web.HTTPInternalServerError,
5555
*,
5656
skip_internal_error_details: bool = False,
57-
error_code: ErrorCodeStr | None = None
57+
error_code: ErrorCodeStr | None = None,
5858
) -> HTTPError:
5959
"""
6060
- Response body conforms OAS schema model
@@ -92,7 +92,8 @@ def create_http_error(
9292
)
9393

9494
return http_error_cls(
95-
reason=reason,
95+
# Multiline not allowed in HTTP reason
96+
reason=reason.replace("\n", " ") if reason else None,
9697
text=json_dumps(
9798
payload,
9899
),

scripts/maintenance/pre_registration.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ async def _pre_register_user(
123123
extras: dict[str, Any] = {},
124124
) -> dict[str, Any]:
125125
"""Pre-register a user in the system"""
126-
path = "/v0/admin/users:pre-register"
126+
path = "/v0/admin/user-accounts:pre-register"
127127

128128
user_data = PreRegisterUserRequest(
129129
firstName=first_name,

services/agent/docker/boot.sh

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ fi
3232

3333
if [ "${SC_BOOT_MODE}" = "debug" ]; then
3434
# NOTE: production does NOT pre-installs debugpy
35-
uv pip install debugpy
35+
if command -v uv >/dev/null 2>&1; then
36+
uv pip install debugpy
37+
else
38+
pip install debugpy
39+
fi
3640
fi
3741

3842
#
@@ -48,7 +52,7 @@ if [ "${SC_BOOT_MODE}" = "debug" ]; then
4852

4953
exec sh -c "
5054
cd services/agent/src/simcore_service_agent && \
51-
python -m debugpy --listen 0.0.0.0:${AGENT_SERVER_REMOTE_DEBUG_PORT} -m uvicorn main:the_app \
55+
python -Xfrozen_modules=off -m debugpy --listen 0.0.0.0:${AGENT_SERVER_REMOTE_DEBUG_PORT} -m uvicorn main:the_app \
5256
--host 0.0.0.0 \
5357
--port 8000 \
5458
--reload \

services/api-server/docker/boot.sh

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ fi
2727

2828
if [ "${SC_BOOT_MODE}" = "debug" ]; then
2929
# NOTE: production does NOT pre-installs debugpy
30-
uv pip install debugpy
30+
if command -v uv >/dev/null 2>&1; then
31+
uv pip install debugpy
32+
else
33+
pip install debugpy
34+
fi
3135
fi
3236

3337
# RUNNING application ----------------------------------------
@@ -40,7 +44,7 @@ if [ "${SC_BOOT_MODE}" = "debug" ]; then
4044

4145
exec sh -c "
4246
cd services/api-server/src/simcore_service_api_server && \
43-
python -m debugpy --listen 0.0.0.0:${API_SERVER_REMOTE_DEBUG_PORT} -m uvicorn main:the_app \
47+
python -Xfrozen_modules=off -m debugpy --listen 0.0.0.0:${API_SERVER_REMOTE_DEBUG_PORT} -m uvicorn main:the_app \
4448
--host 0.0.0.0 \
4549
--reload \
4650
$reload_dir_packages

services/autoscaling/docker/boot.sh

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ fi
3131

3232
if [ "${SC_BOOT_MODE}" = "debug" ]; then
3333
# NOTE: production does NOT pre-installs debugpy
34-
uv pip install debugpy
34+
if command -v uv >/dev/null 2>&1; then
35+
uv pip install debugpy
36+
else
37+
pip install debugpy
38+
fi
3539
fi
3640

3741
#
@@ -47,7 +51,7 @@ if [ "${SC_BOOT_MODE}" = "debug" ]; then
4751

4852
exec sh -c "
4953
cd services/autoscaling/src/simcore_service_autoscaling && \
50-
python -m debugpy --listen 0.0.0.0:${AUTOSCALING_REMOTE_DEBUGGING_PORT} -m uvicorn main:the_app \
54+
python -Xfrozen_modules=off -m debugpy --listen 0.0.0.0:${AUTOSCALING_REMOTE_DEBUGGING_PORT} -m uvicorn main:the_app \
5155
--host 0.0.0.0 \
5256
--reload \
5357
$reload_dir_packages

services/catalog/docker/boot.sh

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ fi
2727

2828
if [ "${SC_BOOT_MODE}" = "debug" ]; then
2929
# NOTE: production does NOT pre-installs debugpy
30-
uv pip install debugpy
30+
if command -v uv >/dev/null 2>&1; then
31+
uv pip install debugpy
32+
else
33+
pip install debugpy
34+
fi
3135
fi
3236

3337
# RUNNING application ----------------------------------------
@@ -40,7 +44,7 @@ if [ "${SC_BOOT_MODE}" = "debug" ]; then
4044

4145
exec sh -c "
4246
cd services/catalog/src/simcore_service_catalog && \
43-
python -m debugpy --listen 0.0.0.0:${CATALOG_REMOTE_DEBUGGING_PORT} -m uvicorn main:the_app \
47+
python -Xfrozen_modules=off -m debugpy --listen 0.0.0.0:${CATALOG_REMOTE_DEBUGGING_PORT} -m uvicorn main:the_app \
4448
--host 0.0.0.0 \
4549
--reload \
4650
$reload_dir_packages

services/clusters-keeper/docker/boot.sh

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ fi
3232

3333
if [ "${SC_BOOT_MODE}" = "debug" ]; then
3434
# NOTE: production does NOT pre-installs debugpy
35-
uv pip install debugpy
35+
if command -v uv >/dev/null 2>&1; then
36+
uv pip install debugpy
37+
else
38+
pip install debugpy
39+
fi
3640
fi
3741

3842
#
@@ -48,7 +52,7 @@ if [ "${SC_BOOT_MODE}" = "debug" ]; then
4852

4953
exec sh -c "
5054
cd services/clusters-keeper/src/simcore_service_clusters_keeper && \
51-
python -m debugpy --listen 0.0.0.0:${CLUSTERS_KEEPER_REMOTE_DEBUGGING_PORT} -m uvicorn main:the_app \
55+
python -Xfrozen_modules=off -m debugpy --listen 0.0.0.0:${CLUSTERS_KEEPER_REMOTE_DEBUGGING_PORT} -m uvicorn main:the_app \
5256
--host 0.0.0.0 \
5357
--reload \
5458
$reload_dir_packages

0 commit comments

Comments
 (0)