Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
355e696
doc
pcrespov Apr 22, 2025
f9efd1e
🎨 [Admin] Add endpoint to list users for admin with approval filter
pcrespov Apr 22, 2025
8c903e1
drafts tests
pcrespov Apr 22, 2025
7952c8b
🎨 [Admin] Implement endpoint to list users for admin with pagination …
pcrespov Apr 22, 2025
b43e829
🎨 [Database] Add account_request_status column to users_pre_registrat…
pcrespov Apr 22, 2025
b12f6fb
drafts repository
pcrespov Apr 22, 2025
ca24939
drafts service layer
pcrespov Apr 22, 2025
3307c30
cleanup
pcrespov Apr 24, 2025
377b43f
✨ [Users] Enhance admin user listing with invited_by field and regist…
pcrespov Apr 24, 2025
0204522
migration
pcrespov Apr 24, 2025
9b245c4
fixes migration
pcrespov Apr 24, 2025
ee3e70f
drafting tests
pcrespov Apr 24, 2025
6c83310
rename
pcrespov May 15, 2025
b267059
rename
pcrespov May 15, 2025
2d335cf
@odeimaiz review: adapting web-api
pcrespov May 19, 2025
a873bbd
creates tests
pcrespov May 19, 2025
b3f0181
refactor: update pk_value handling in insert functions to support None
pcrespov May 19, 2025
6513314
feat: enhance pre-registration details with product name and foreign …
pcrespov May 19, 2025
30d6398
feat: add new pre-registration columns and update related user handling
pcrespov May 19, 2025
f7678e1
feat: enhance user listing with product name and account request stat…
pcrespov May 20, 2025
299e946
refactor: improve code readability by restructuring class inheritance…
pcrespov May 20, 2025
f510d06
fix: correct primary key column references and ensure proper type cas…
pcrespov May 20, 2025
19f5d7f
feat: add account request review fields and update approval workflow …
pcrespov May 20, 2025
85c53c7
Merge branch 'master' into is23/web-api-list-users-for-admin
pcrespov May 21, 2025
e183057
rm
pcrespov May 21, 2025
d5a45ea
cleanup
pcrespov May 21, 2025
6f8d5a5
list_user_pre_registartion
pcrespov May 21, 2025
6a60b04
✨ users: Enhance user pre-registration with optional linking to exist…
pcrespov May 21, 2025
d4f19cf
split tests
pcrespov May 21, 2025
cc88388
✨ users: Refactor user search and listing functions to merge pre-regi…
pcrespov May 21, 2025
9e1c2ec
✨ users: Update user schema and repository queries to use 'created_by…
pcrespov May 21, 2025
dc4e942
testing listing users as admin
pcrespov May 21, 2025
99e97b5
✨ users: Implement user account approval functionality with appropria…
pcrespov May 21, 2025
5b0a63e
✨ users: Add account request status fields and update user approval/r…
pcrespov May 21, 2025
22cf0e2
✨ users: Update account request status handling in API and tests
pcrespov May 21, 2025
785cabb
implements reject_user_account
pcrespov May 21, 2025
9ca901b
Merge branch 'master' into is23/web-api-list-users-for-admin
pcrespov May 22, 2025
fb77a5f
cleanup
pcrespov May 22, 2025
7e9d985
changes filter
pcrespov May 22, 2025
9b7f1cc
simplify tests
pcrespov May 22, 2025
4f967a4
services/webserver api version: 0.65.0 → 0.66.0
pcrespov May 22, 2025
d6d80c4
fixes mypy
pcrespov May 22, 2025
eeca483
fixes tests
pcrespov May 22, 2025
71c247c
adds invitation options
pcrespov May 22, 2025
c43cbdf
returns pre-registration
pcrespov May 22, 2025
fb8bc84
update API endpoint for fetching pending users to use review_status q…
pcrespov May 22, 2025
726b768
fixes
pcrespov May 22, 2025
5926529
fix tests
pcrespov May 22, 2025
542d787
refactor: remove unused ResendConfirmationCode and update response mo…
pcrespov May 22, 2025
14beb76
fixes all tests
pcrespov May 22, 2025
5b7a620
Merge branch 'master' into is23/web-api-list-users-for-admin
pcrespov May 22, 2025
2b5daee
rename as user-account
pcrespov May 22, 2025
dd3fa41
plural
pcrespov May 22, 2025
2050ef0
mode names
pcrespov May 22, 2025
3e21fc7
cleanup
pcrespov May 22, 2025
4f2e55d
cleanup doc
pcrespov May 22, 2025
c1f3eaf
fixe pylint
pcrespov May 22, 2025
c33cda9
fixes tests
pcrespov May 22, 2025
9dda27d
Merge branch 'master' into is23/web-api-list-users-for-admin
pcrespov May 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions api/specs/web-server/_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,8 @@ async def email_confirmation(code: str):

@router.get(
"/auth/captcha",
operation_id="request_captcha",
operation_id="create_captcha",
status_code=status.HTTP_200_OK,
responses={status.HTTP_200_OK: {"content": {"image/png": {}}}},
)
async def request_captcha(): ...
async def create_captcha(): ...
49 changes: 40 additions & 9 deletions api/specs/web-server/_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,25 @@
from enum import Enum
from typing import Annotated

from _common import as_query
from fastapi import APIRouter, Depends, status
from models_library.api_schemas_webserver.users import (
MyPermissionGet,
MyProfileGet,
MyProfilePatch,
MyTokenCreate,
MyTokenGet,
UserForAdminGet,
UserAccountApprove,
UserAccountGet,
UserAccountReject,
UserAccountSearchQueryParams,
UserGet,
UsersForAdminSearchQueryParams,
UsersAccountListQueryParams,
UsersSearch,
)
from models_library.api_schemas_webserver.users_preferences import PatchRequestBody
from models_library.generics import Envelope
from models_library.rest_pagination import Page
from models_library.user_preferences import PreferenceIdentifier
from simcore_service_webserver._meta import API_VTAG
from simcore_service_webserver.users._common.schemas import PreRegisteredUserGet
Expand Down Expand Up @@ -144,20 +149,46 @@ async def search_users(_body: UsersSearch): ...


@router.get(
"/admin/users:search",
response_model=Envelope[list[UserForAdminGet]],
"/admin/user-accounts",
response_model=Page[UserAccountGet],
tags=_extra_tags,
)
async def search_users_for_admin(
_query: Annotated[UsersForAdminSearchQueryParams, Depends()],
async def list_users_accounts(
_query: Annotated[as_query(UsersAccountListQueryParams), Depends()],
): ...


@router.post(
"/admin/user-accounts:approve",
status_code=status.HTTP_204_NO_CONTENT,
tags=_extra_tags,
)
async def approve_user_account(_body: UserAccountApprove): ...


@router.post(
"/admin/user-accounts:reject",
status_code=status.HTTP_204_NO_CONTENT,
tags=_extra_tags,
)
async def reject_user_account(_body: UserAccountReject): ...


@router.get(
"/admin/user-accounts:search",
response_model=Envelope[list[UserAccountGet]],
tags=_extra_tags,
)
async def search_user_accounts(
_query: Annotated[UserAccountSearchQueryParams, Depends()],
):
# NOTE: see `Search` in `Common Custom Methods` in https://cloud.google.com/apis/design/custom_methods
...


@router.post(
"/admin/users:pre-register",
response_model=Envelope[UserForAdminGet],
"/admin/user-accounts:pre-register",
response_model=Envelope[UserAccountGet],
tags=_extra_tags,
)
async def pre_register_user_for_admin(_body: PreRegisteredUserGet): ...
async def pre_register_user_account(_body: PreRegisteredUserGet): ...
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import re
from datetime import date
from datetime import date, datetime
from enum import Enum
from typing import Annotated, Any, Literal, Self

import annotated_types
from common_library.basic_types import DEFAULT_FACTORY
from common_library.dict_tools import remap_keys
from common_library.users_enums import UserStatus
from common_library.users_enums import AccountRequestStatus, UserStatus
from models_library.groups import AccessRightsDict
from models_library.rest_filters import Filters
from models_library.rest_pagination import PageQueryParameters
from pydantic import (
ConfigDict,
EmailStr,
Expand Down Expand Up @@ -39,6 +41,7 @@
OutputSchemaWithoutCamelCase,
)
from .groups import MyGroupsGet
from .products import InvitationGenerate
from .users_preferences import AggregatedPreferences

#
Expand Down Expand Up @@ -238,7 +241,30 @@ def from_domain_model(cls, data):
return cls.model_validate(data, from_attributes=True)


class UsersForAdminSearchQueryParams(RequestParameters):
class UsersForAdminListFilter(Filters):
# 1. account_request_status: PENDING, REJECTED, APPROVED
# 2. If APPROVED AND user uses the invitation link, then when user is registered,
# it can be in any of these statuses:
# CONFIRMATION_PENDING, ACTIVE, EXPIRED, BANNED, DELETED
#
review_status: Literal["PENDING", "REVIEWED"] | None = None

model_config = ConfigDict(extra="forbid")


class UsersAccountListQueryParams(UsersForAdminListFilter, PageQueryParameters): ...


class UserAccountApprove(InputSchema):
email: EmailStr
invitation: InvitationGenerate | None = None


class UserAccountReject(InputSchema):
email: EmailStr


class UserAccountSearchQueryParams(RequestParameters):
email: Annotated[
str,
Field(
Expand All @@ -249,7 +275,7 @@ class UsersForAdminSearchQueryParams(RequestParameters):
]


class UserForAdminGet(OutputSchema):
class UserAccountGet(OutputSchema):
# ONLY for admins
first_name: str | None
last_name: str | None
Expand All @@ -269,8 +295,12 @@ class UserForAdminGet(OutputSchema):
),
] = DEFAULT_FACTORY

# authorization
# pre-registration
pre_registration_id: int | None
invited_by: str | None = None
account_request_status: AccountRequestStatus | None
account_request_reviewed_by: UserID | None = None
account_request_reviewed_at: datetime | None = None

# user status
registered: bool
Expand Down
2 changes: 1 addition & 1 deletion scripts/maintenance/pre_registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ async def _pre_register_user(
extras: dict[str, Any] = {},
) -> dict[str, Any]:
"""Pre-register a user in the system"""
path = "/v0/admin/users:pre-register"
path = "/v0/admin/user-accounts:pre-register"

user_data = PreRegisterUserRequest(
firstName=first_name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1059,27 +1059,27 @@ qx.Class.define("osparc.data.Resources", {
endpoints: {
search: {
method: "GET",
url: statics.API + "/admin/users:search?email={email}"
url: statics.API + "/admin/user-accounts:search?email={email}"
},
getPendingUsers: {
method: "GET",
url: statics.API + "/admin/users?status=PENDING"
url: statics.API + "/admin/user-accounts?review_status=PENDING"
},
approveUser: {
method: "POST",
url: statics.API + "/admin/users:approve"
url: statics.API + "/admin/user-accounts:approve"
},
rejectUser: {
method: "POST",
url: statics.API + "/admin/users:reject"
url: statics.API + "/admin/user-accounts:reject"
},
resendConfirmationEmail: {
method: "POST",
url: statics.API + "/admin/users:resendConfirmationEmail"
url: statics.API + "/admin/user-accounts:resendConfirmationEmail"
},
preRegister: {
method: "POST",
url: statics.API + "/admin/users:pre-register"
url: statics.API + "/admin/user-accounts:pre-register"
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion services/web/server/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.65.0
0.66.0
6 changes: 3 additions & 3 deletions services/web/server/setup.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.65.0
current_version = 0.66.0
commit = True
message = services/webserver api version: {current_version} → {new_version}
tag = False
Expand All @@ -13,13 +13,13 @@ commit_args = --no-verify
addopts = --strict-markers
asyncio_mode = auto
asyncio_default_fixture_loop_scope = function
markers =
markers =
slow: marks tests as slow (deselect with '-m "not slow"')
acceptance_test: "marks tests as 'acceptance tests' i.e. does the system do what the user expects? Typically those are workflows."
testit: "marks test to run during development"
heavy_load: "mark tests that require large amount of data"

[mypy]
plugins =
plugins =
pydantic.mypy
sqlalchemy.ext.mypy.plugin
Loading
Loading