From 08981e08789697389a0673107ec0d07c82943c92 Mon Sep 17 00:00:00 2001 From: Pedro Crespo-Valero <32402063+pcrespov@users.noreply.github.com> Date: Wed, 11 Dec 2024 23:00:02 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=E2=99=BB=EF=B8=8F=20web-api:=20fix?= =?UTF-8?q?es=20adding=20group=20member=20by=20user-name=20and=20some=20cl?= =?UTF-8?q?eanup=20(#6940)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/specs/web-server/_projects_nodes.py | 2 +- api/specs/web-server/_wallets.py | 2 +- .../src/common_library/groups_enums.py | 13 +++ .../service_access_rights.py | 2 +- .../api_schemas_catalog/services.py | 2 +- .../api_schemas_webserver/folders.py | 2 +- .../api_schemas_webserver/folders_v2.py | 2 +- .../api_schemas_webserver/socketio.py | 3 +- .../api_schemas_webserver/wallets.py | 2 +- .../api_schemas_webserver/workspaces.py | 2 +- .../src/models_library/clusters.py | 2 +- .../src/models_library/folders.py | 3 +- .../src/models_library/groups.py | 23 ++--- .../src/models_library/services_access.py | 2 +- .../src/models_library/users.py | 1 - .../src/models_library/workspaces.py | 3 +- .../test_api_schemas_webserver_socketio.py | 3 +- .../tests/with_db/conftest.py | 3 +- .../postgres-database/requirements/prod.txt | 1 + .../models/groups.py | 15 +-- .../helpers/webserver_workspaces.py | 2 +- .../models/schemas/model_adapter.py | 2 +- .../db/repositories/services.py | 10 +- .../models/services_specifications.py | 2 +- services/migration/Dockerfile | 2 +- .../db/payment_users_repo.py | 3 +- services/payments/tests/conftest.py | 2 +- .../tests/unit/test_db_payments_users_repo.py | 3 +- .../tests/unit/test_services_notifier.py | 3 +- .../db_access_layer.py | 3 +- .../folders/_folders_db.py | 3 +- .../garbage_collector/_core_utils.py | 8 +- .../groups/_common/schemas.py | 3 +- .../groups/_groups_api.py | 3 +- .../groups/_groups_db.py | 18 ++-- .../_rabbitmq_exclusive_queue_consumers.py | 2 +- .../projects/_groups_api.py | 3 +- .../projects/_groups_db.py | 2 +- .../projects/_groups_handlers.py | 4 +- .../projects/_nodes_handlers.py | 7 +- .../projects/projects_api.py | 3 +- .../socketio/messages.py | 3 +- .../simcore_service_webserver/tags/schemas.py | 3 +- .../simcore_service_webserver/users/_db.py | 3 +- .../simcore_service_webserver/users/api.py | 3 +- .../simcore_service_webserver/wallets/_db.py | 3 +- .../wallets/_groups_api.py | 9 +- .../wallets/_groups_db.py | 2 +- .../wallets/_groups_handlers.py | 2 +- .../workspaces/_groups_api.py | 9 +- .../workspaces/_groups_db.py | 2 +- .../workspaces/_models.py | 3 +- .../workspaces/_workspaces_db.py | 3 +- .../tests/unit/isolated/test_groups_models.py | 16 +--- .../unit/isolated/test_projects__db_utils.py | 2 +- .../01/groups/test_groups_handlers_users.py | 96 +++++++++++++++++++ 56 files changed, 214 insertions(+), 121 deletions(-) create mode 100644 packages/common-library/src/common_library/groups_enums.py diff --git a/api/specs/web-server/_projects_nodes.py b/api/specs/web-server/_projects_nodes.py index 392a90baf0b..50c2ba73a1a 100644 --- a/api/specs/web-server/_projects_nodes.py +++ b/api/specs/web-server/_projects_nodes.py @@ -21,9 +21,9 @@ ServiceResourcesDict, ) from models_library.generics import Envelope +from models_library.groups import GroupID from models_library.projects import ProjectID from models_library.projects_nodes_io import NodeID -from models_library.users import GroupID from simcore_service_webserver._meta import API_VTAG from simcore_service_webserver.projects._crud_handlers import ProjectPathParams from simcore_service_webserver.projects._nodes_handlers import ( diff --git a/api/specs/web-server/_wallets.py b/api/specs/web-server/_wallets.py index 06ff8d7fc10..c4e490ec711 100644 --- a/api/specs/web-server/_wallets.py +++ b/api/specs/web-server/_wallets.py @@ -27,8 +27,8 @@ WalletPaymentInitiated, ) from models_library.generics import Envelope +from models_library.groups import GroupID from models_library.rest_pagination import Page, PageQueryParameters -from models_library.users import GroupID from models_library.wallets import WalletID from simcore_service_webserver._meta import API_VTAG from simcore_service_webserver.wallets._groups_api import WalletGroupGet diff --git a/packages/common-library/src/common_library/groups_enums.py b/packages/common-library/src/common_library/groups_enums.py new file mode 100644 index 00000000000..215edf335f1 --- /dev/null +++ b/packages/common-library/src/common_library/groups_enums.py @@ -0,0 +1,13 @@ +import enum + + +class GroupType(enum.Enum): + """ + standard: standard group, e.g. any group that is not a primary group or special group such as the everyone group + primary: primary group, e.g. the primary group is the user own defined group that typically only contain the user (same as in linux) + everyone: the only group for all users + """ + + STANDARD = "standard" + PRIMARY = "primary" + EVERYONE = "everyone" diff --git a/packages/models-library/src/models_library/api_schemas_catalog/service_access_rights.py b/packages/models-library/src/models_library/api_schemas_catalog/service_access_rights.py index c56edcd7cf9..b4aa1173adc 100644 --- a/packages/models-library/src/models_library/api_schemas_catalog/service_access_rights.py +++ b/packages/models-library/src/models_library/api_schemas_catalog/service_access_rights.py @@ -1,7 +1,7 @@ from pydantic import BaseModel +from ..groups import GroupID from ..services import ServiceKey, ServiceVersion -from ..users import GroupID class ServiceAccessRightsGet(BaseModel): diff --git a/packages/models-library/src/models_library/api_schemas_catalog/services.py b/packages/models-library/src/models_library/api_schemas_catalog/services.py index 8090edf0ebd..c2551c43cb2 100644 --- a/packages/models-library/src/models_library/api_schemas_catalog/services.py +++ b/packages/models-library/src/models_library/api_schemas_catalog/services.py @@ -6,6 +6,7 @@ from ..boot_options import BootOptions from ..emails import LowerCaseEmailStr +from ..groups import GroupID from ..services_access import ServiceAccessRights, ServiceGroupAccessRightsV2 from ..services_authoring import Author from ..services_enums import ServiceType @@ -18,7 +19,6 @@ ) from ..services_resources import ServiceResourcesDict from ..services_types import ServiceKey, ServiceVersion -from ..users import GroupID from ..utils.change_case import snake_to_camel diff --git a/packages/models-library/src/models_library/api_schemas_webserver/folders.py b/packages/models-library/src/models_library/api_schemas_webserver/folders.py index 092a5cb94fe..dd464718571 100644 --- a/packages/models-library/src/models_library/api_schemas_webserver/folders.py +++ b/packages/models-library/src/models_library/api_schemas_webserver/folders.py @@ -3,8 +3,8 @@ from models_library.basic_types import IDStr from models_library.folders import FolderID +from models_library.groups import GroupID from models_library.projects_access import AccessRights -from models_library.users import GroupID from models_library.utils.common_validators import null_or_none_str_to_none_validator from pydantic import ConfigDict, PositiveInt, field_validator diff --git a/packages/models-library/src/models_library/api_schemas_webserver/folders_v2.py b/packages/models-library/src/models_library/api_schemas_webserver/folders_v2.py index 4a88532848a..adf0766442e 100644 --- a/packages/models-library/src/models_library/api_schemas_webserver/folders_v2.py +++ b/packages/models-library/src/models_library/api_schemas_webserver/folders_v2.py @@ -6,7 +6,7 @@ from ..access_rights import AccessRights from ..basic_types import IDStr from ..folders import FolderID -from ..users import GroupID +from ..groups import GroupID from ..utils.common_validators import null_or_none_str_to_none_validator from ..workspaces import WorkspaceID from ._base import InputSchema, OutputSchema diff --git a/packages/models-library/src/models_library/api_schemas_webserver/socketio.py b/packages/models-library/src/models_library/api_schemas_webserver/socketio.py index 05bd342a4c3..6e3f987198a 100644 --- a/packages/models-library/src/models_library/api_schemas_webserver/socketio.py +++ b/packages/models-library/src/models_library/api_schemas_webserver/socketio.py @@ -1,5 +1,6 @@ from ..basic_types import IDStr -from ..users import GroupID, UserID +from ..groups import GroupID +from ..users import UserID class SocketIORoomStr(IDStr): diff --git a/packages/models-library/src/models_library/api_schemas_webserver/wallets.py b/packages/models-library/src/models_library/api_schemas_webserver/wallets.py index a4f33ab3cad..a69297ef408 100644 --- a/packages/models-library/src/models_library/api_schemas_webserver/wallets.py +++ b/packages/models-library/src/models_library/api_schemas_webserver/wallets.py @@ -5,7 +5,7 @@ from pydantic import ConfigDict, Field, HttpUrl, ValidationInfo, field_validator from ..basic_types import AmountDecimal, IDStr, NonNegativeDecimal -from ..users import GroupID +from ..groups import GroupID from ..wallets import WalletID, WalletStatus from ._base import InputSchema, OutputSchema diff --git a/packages/models-library/src/models_library/api_schemas_webserver/workspaces.py b/packages/models-library/src/models_library/api_schemas_webserver/workspaces.py index 73fb684d3aa..de3b0640b98 100644 --- a/packages/models-library/src/models_library/api_schemas_webserver/workspaces.py +++ b/packages/models-library/src/models_library/api_schemas_webserver/workspaces.py @@ -2,7 +2,7 @@ from typing import NamedTuple from models_library.basic_types import IDStr -from models_library.users import GroupID +from models_library.groups import GroupID from models_library.workspaces import WorkspaceID from pydantic import ConfigDict, PositiveInt diff --git a/packages/models-library/src/models_library/clusters.py b/packages/models-library/src/models_library/clusters.py index 783f82df016..e18f3681b4d 100644 --- a/packages/models-library/src/models_library/clusters.py +++ b/packages/models-library/src/models_library/clusters.py @@ -5,7 +5,7 @@ from pydantic import AnyUrl, BaseModel, ConfigDict, Field, HttpUrl, field_validator from pydantic.types import NonNegativeInt -from .users import GroupID +from .groups import GroupID from .utils.common_validators import create_enums_pre_validator from .utils.enums import StrAutoEnum diff --git a/packages/models-library/src/models_library/folders.py b/packages/models-library/src/models_library/folders.py index 094ea25be92..55431173111 100644 --- a/packages/models-library/src/models_library/folders.py +++ b/packages/models-library/src/models_library/folders.py @@ -12,7 +12,8 @@ ) from .access_rights import AccessRights -from .users import GroupID, UserID +from .groups import GroupID +from .users import UserID from .utils.enums import StrAutoEnum from .workspaces import WorkspaceID diff --git a/packages/models-library/src/models_library/groups.py b/packages/models-library/src/models_library/groups.py index 368f01523ea..797453922f9 100644 --- a/packages/models-library/src/models_library/groups.py +++ b/packages/models-library/src/models_library/groups.py @@ -1,38 +1,27 @@ -import enum from typing import Annotated, Final, NamedTuple, TypeAlias from common_library.basic_types import DEFAULT_FACTORY +from common_library.groups_enums import GroupType as GroupType from pydantic import BaseModel, ConfigDict, EmailStr, Field, field_validator from pydantic.types import PositiveInt from typing_extensions import TypedDict from .basic_types import IDStr -from .users import GroupID, UserID +from .users import UserID from .utils.common_validators import create_enums_pre_validator EVERYONE_GROUP_ID: Final[int] = 1 +GroupID: TypeAlias = PositiveInt -__all__: tuple[str, ...] = ("GroupID",) - - -class GroupTypeInModel(str, enum.Enum): - """ - standard: standard group, e.g. any group that is not a primary group or special group such as the everyone group - primary: primary group, e.g. the primary group is the user own defined group that typically only contain the user (same as in linux) - everyone: the only group for all users - """ - - STANDARD = "standard" - PRIMARY = "primary" - EVERYONE = "everyone" +__all__: tuple[str, ...] = ("GroupType",) class Group(BaseModel): gid: PositiveInt name: str description: str - group_type: Annotated[GroupTypeInModel, Field(alias="type")] + group_type: Annotated[GroupType, Field(alias="type")] thumbnail: str | None inclusion_rules: Annotated[ @@ -43,7 +32,7 @@ class Group(BaseModel): ] = DEFAULT_FACTORY _from_equivalent_enums = field_validator("group_type", mode="before")( - create_enums_pre_validator(GroupTypeInModel) + create_enums_pre_validator(GroupType) ) model_config = ConfigDict(populate_by_name=True) diff --git a/packages/models-library/src/models_library/services_access.py b/packages/models-library/src/models_library/services_access.py index 84dbd7d17a0..248e8f41e85 100644 --- a/packages/models-library/src/models_library/services_access.py +++ b/packages/models-library/src/models_library/services_access.py @@ -4,7 +4,7 @@ from pydantic import BaseModel, ConfigDict, Field -from .users import GroupID +from .groups import GroupID from .utils.change_case import snake_to_camel diff --git a/packages/models-library/src/models_library/users.py b/packages/models-library/src/models_library/users.py index 26bdf3e1798..af532978320 100644 --- a/packages/models-library/src/models_library/users.py +++ b/packages/models-library/src/models_library/users.py @@ -5,7 +5,6 @@ UserID: TypeAlias = PositiveInt UserNameID: TypeAlias = IDStr -GroupID: TypeAlias = PositiveInt FirstNameStr: TypeAlias = Annotated[ diff --git a/packages/models-library/src/models_library/workspaces.py b/packages/models-library/src/models_library/workspaces.py index 6c34efbf790..db4ff387404 100644 --- a/packages/models-library/src/models_library/workspaces.py +++ b/packages/models-library/src/models_library/workspaces.py @@ -12,7 +12,8 @@ ) from .access_rights import AccessRights -from .users import GroupID, UserID +from .groups import GroupID +from .users import UserID from .utils.enums import StrAutoEnum WorkspaceID: TypeAlias = PositiveInt diff --git a/packages/models-library/tests/test_api_schemas_webserver_socketio.py b/packages/models-library/tests/test_api_schemas_webserver_socketio.py index e5dfdbf7eff..a78ebea2432 100644 --- a/packages/models-library/tests/test_api_schemas_webserver_socketio.py +++ b/packages/models-library/tests/test_api_schemas_webserver_socketio.py @@ -3,7 +3,8 @@ import pytest from faker import Faker from models_library.api_schemas_webserver.socketio import SocketIORoomStr -from models_library.users import GroupID, UserID +from models_library.groups import GroupID +from models_library.users import UserID @pytest.fixture diff --git a/packages/notifications-library/tests/with_db/conftest.py b/packages/notifications-library/tests/with_db/conftest.py index 750f3cc24a4..9dda5da676d 100644 --- a/packages/notifications-library/tests/with_db/conftest.py +++ b/packages/notifications-library/tests/with_db/conftest.py @@ -11,8 +11,9 @@ import pytest import sqlalchemy as sa from models_library.basic_types import IDStr +from models_library.groups import GroupID from models_library.products import ProductName -from models_library.users import GroupID, UserID +from models_library.users import UserID from notifications_library._templates import get_default_named_templates from pydantic import validate_call from simcore_postgres_database.models.jinja2_templates import jinja2_templates diff --git a/packages/postgres-database/requirements/prod.txt b/packages/postgres-database/requirements/prod.txt index c4567926c6d..ba22361fcc3 100644 --- a/packages/postgres-database/requirements/prod.txt +++ b/packages/postgres-database/requirements/prod.txt @@ -8,4 +8,5 @@ --requirement _base.txt --requirement _migration.txt +simcore-common-library @ ../common-library/ simcore-postgres-database @ . diff --git a/packages/postgres-database/src/simcore_postgres_database/models/groups.py b/packages/postgres-database/src/simcore_postgres_database/models/groups.py index a70e9fa8db4..940e1a78769 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/groups.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/groups.py @@ -4,27 +4,16 @@ - Groups have a ID, name and a list of users that belong to the group """ -import enum import sqlalchemy as sa +from common_library.groups_enums import GroupType from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.sql import func from ._common import RefActions from .base import metadata - -class GroupType(enum.Enum): - """ - standard: standard group, e.g. any group that is not a primary group or special group such as the everyone group - primary: primary group, e.g. the primary group is the user own defined group that typically only contain the user (same as in linux) - everyone: the only group for all users - """ - - STANDARD = "standard" - PRIMARY = "primary" - EVERYONE = "everyone" - +__all__: tuple[str, ...] = ("GroupType",) groups = sa.Table( "groups", diff --git a/packages/pytest-simcore/src/pytest_simcore/helpers/webserver_workspaces.py b/packages/pytest-simcore/src/pytest_simcore/helpers/webserver_workspaces.py index 3d1f33ab029..1dbe5ebeb42 100644 --- a/packages/pytest-simcore/src/pytest_simcore/helpers/webserver_workspaces.py +++ b/packages/pytest-simcore/src/pytest_simcore/helpers/webserver_workspaces.py @@ -1,6 +1,6 @@ import sqlalchemy as sa from aiohttp import web -from models_library.users import GroupID +from models_library.groups import GroupID from models_library.workspaces import WorkspaceID from simcore_postgres_database.models.workspaces_access_rights import ( workspaces_access_rights, diff --git a/services/api-server/src/simcore_service_api_server/models/schemas/model_adapter.py b/services/api-server/src/simcore_service_api_server/models/schemas/model_adapter.py index 9cc8b768d45..3b88cd82ef7 100644 --- a/services/api-server/src/simcore_service_api_server/models/schemas/model_adapter.py +++ b/services/api-server/src/simcore_service_api_server/models/schemas/model_adapter.py @@ -17,13 +17,13 @@ WalletGetWithAvailableCredits as _WalletGetWithAvailableCredits, ) from models_library.basic_types import IDStr, NonNegativeDecimal +from models_library.groups import GroupID from models_library.resource_tracker import ( PricingPlanClassification, PricingPlanId, PricingUnitId, UnitExtraInfo, ) -from models_library.users import GroupID from models_library.wallets import WalletID, WalletStatus from pydantic import ( BaseModel, diff --git a/services/catalog/src/simcore_service_catalog/db/repositories/services.py b/services/catalog/src/simcore_service_catalog/db/repositories/services.py index e848fb9b164..7cb1b72e333 100644 --- a/services/catalog/src/simcore_service_catalog/db/repositories/services.py +++ b/services/catalog/src/simcore_service_catalog/db/repositories/services.py @@ -10,10 +10,10 @@ from models_library.api_schemas_catalog.services_specifications import ( ServiceSpecifications, ) -from models_library.groups import GroupAtDB, GroupTypeInModel +from models_library.groups import GroupAtDB, GroupID, GroupType from models_library.products import ProductName from models_library.services import ServiceKey, ServiceVersion -from models_library.users import GroupID, UserID +from models_library.users import UserID from psycopg2.errors import ForeignKeyViolation from pydantic import PositiveInt, TypeAdapter, ValidationError from simcore_postgres_database.utils_services import create_select_latest_services_query @@ -597,16 +597,16 @@ async def get_service_specifications( continue # filter by group type group = gid_to_group_map[row.gid] - if (group.group_type == GroupTypeInModel.STANDARD) and _is_newer( + if (group.group_type == GroupType.STANDARD) and _is_newer( teams_specs.get(db_service_spec.gid), db_service_spec, ): teams_specs[db_service_spec.gid] = db_service_spec - elif (group.group_type == GroupTypeInModel.EVERYONE) and _is_newer( + elif (group.group_type == GroupType.EVERYONE) and _is_newer( everyone_specs, db_service_spec ): everyone_specs = db_service_spec - elif (group.group_type == GroupTypeInModel.PRIMARY) and _is_newer( + elif (group.group_type == GroupType.PRIMARY) and _is_newer( primary_specs, db_service_spec ): primary_specs = db_service_spec diff --git a/services/catalog/src/simcore_service_catalog/models/services_specifications.py b/services/catalog/src/simcore_service_catalog/models/services_specifications.py index d53e56a8c56..fc03805537f 100644 --- a/services/catalog/src/simcore_service_catalog/models/services_specifications.py +++ b/services/catalog/src/simcore_service_catalog/models/services_specifications.py @@ -1,8 +1,8 @@ from models_library.api_schemas_catalog.services_specifications import ( ServiceSpecifications, ) +from models_library.groups import GroupID from models_library.services import ServiceKey, ServiceVersion -from models_library.users import GroupID from pydantic import ConfigDict diff --git a/services/migration/Dockerfile b/services/migration/Dockerfile index fe262597d07..33b55d7d5ce 100644 --- a/services/migration/Dockerfile +++ b/services/migration/Dockerfile @@ -62,7 +62,7 @@ WORKDIR /build/packages/postgres-database # install only base 3rd party dependencies RUN \ - --mount=type=bind,source=packages/postgres-database,target=/build/packages/postgres-database,rw \ + --mount=type=bind,source=packages,target=/build/packages,rw \ --mount=type=cache,target=/root/.cache/uv \ uv pip install \ --requirement requirements/prod.txt \ diff --git a/services/payments/src/simcore_service_payments/db/payment_users_repo.py b/services/payments/src/simcore_service_payments/db/payment_users_repo.py index 6a2c53c7be0..ec643ee8bca 100644 --- a/services/payments/src/simcore_service_payments/db/payment_users_repo.py +++ b/services/payments/src/simcore_service_payments/db/payment_users_repo.py @@ -1,6 +1,7 @@ import sqlalchemy as sa from models_library.api_schemas_webserver.wallets import PaymentID -from models_library.users import GroupID, UserID +from models_library.groups import GroupID +from models_library.users import UserID from simcore_postgres_database.models.payments_transactions import payments_transactions from simcore_postgres_database.models.products import products from simcore_postgres_database.models.users import users diff --git a/services/payments/tests/conftest.py b/services/payments/tests/conftest.py index 220e1edc48a..39608fe4e70 100644 --- a/services/payments/tests/conftest.py +++ b/services/payments/tests/conftest.py @@ -9,7 +9,7 @@ import pytest import simcore_service_payments from faker import Faker -from models_library.users import GroupID +from models_library.groups import GroupID from pydantic import TypeAdapter from pytest_simcore.helpers.monkeypatch_envs import setenvs_from_dict from pytest_simcore.helpers.typing_env import EnvVarsDict diff --git a/services/payments/tests/unit/test_db_payments_users_repo.py b/services/payments/tests/unit/test_db_payments_users_repo.py index 51d5f540c6b..4cff0108033 100644 --- a/services/payments/tests/unit/test_db_payments_users_repo.py +++ b/services/payments/tests/unit/test_db_payments_users_repo.py @@ -10,7 +10,8 @@ import pytest from fastapi import FastAPI -from models_library.users import GroupID, UserID +from models_library.groups import GroupID +from models_library.users import UserID from pytest_simcore.helpers.monkeypatch_envs import setenvs_from_dict from pytest_simcore.helpers.postgres_tools import insert_and_get_row_lifespan from pytest_simcore.helpers.typing_env import EnvVarsDict diff --git a/services/payments/tests/unit/test_services_notifier.py b/services/payments/tests/unit/test_services_notifier.py index ee55afa9be3..faeed872a5c 100644 --- a/services/payments/tests/unit/test_services_notifier.py +++ b/services/payments/tests/unit/test_services_notifier.py @@ -18,7 +18,8 @@ ) from models_library.api_schemas_webserver.socketio import SocketIORoomStr from models_library.api_schemas_webserver.wallets import PaymentTransaction -from models_library.users import GroupID, UserID +from models_library.groups import GroupID +from models_library.users import UserID from pydantic import TypeAdapter from pytest_mock import MockerFixture from pytest_simcore.helpers.faker_factories import random_payment_transaction diff --git a/services/storage/src/simcore_service_storage/db_access_layer.py b/services/storage/src/simcore_service_storage/db_access_layer.py index b77504088f1..27f9dfb9214 100644 --- a/services/storage/src/simcore_service_storage/db_access_layer.py +++ b/services/storage/src/simcore_service_storage/db_access_layer.py @@ -42,9 +42,10 @@ import sqlalchemy as sa from aiopg.sa.connection import SAConnection from aiopg.sa.result import ResultProxy, RowProxy +from models_library.groups import GroupID from models_library.projects import ProjectID from models_library.projects_nodes_io import StorageFileID -from models_library.users import GroupID, UserID +from models_library.users import UserID from simcore_postgres_database.models.project_to_groups import project_to_groups from simcore_postgres_database.models.projects import projects from simcore_postgres_database.models.workspaces_access_rights import ( diff --git a/services/web/server/src/simcore_service_webserver/folders/_folders_db.py b/services/web/server/src/simcore_service_webserver/folders/_folders_db.py index dee552377fa..6c78855995e 100644 --- a/services/web/server/src/simcore_service_webserver/folders/_folders_db.py +++ b/services/web/server/src/simcore_service_webserver/folders/_folders_db.py @@ -18,10 +18,11 @@ FolderScope, UserFolderAccessRightsDB, ) +from models_library.groups import GroupID from models_library.products import ProductName from models_library.projects import ProjectID from models_library.rest_ordering import OrderBy, OrderDirection -from models_library.users import GroupID, UserID +from models_library.users import UserID from models_library.workspaces import WorkspaceID, WorkspaceQuery, WorkspaceScope from pydantic import NonNegativeInt from simcore_postgres_database.models.folders_v2 import folders_v2 diff --git a/services/web/server/src/simcore_service_webserver/garbage_collector/_core_utils.py b/services/web/server/src/simcore_service_webserver/garbage_collector/_core_utils.py index 53750a3c27d..a2108766786 100644 --- a/services/web/server/src/simcore_service_webserver/garbage_collector/_core_utils.py +++ b/services/web/server/src/simcore_service_webserver/garbage_collector/_core_utils.py @@ -2,9 +2,9 @@ import asyncpg.exceptions from aiohttp import web -from models_library.groups import Group, GroupTypeInModel +from models_library.groups import Group, GroupID, GroupType from models_library.projects import ProjectID -from models_library.users import GroupID, UserID +from models_library.users import UserID from simcore_postgres_database.errors import DatabaseError from ..groups.api import get_group_from_gid @@ -86,9 +86,9 @@ async def get_new_project_owner_gid( if access_rights[other_gid]["write"] is not True: continue - if group.group_type == GroupTypeInModel.STANDARD: + if group.group_type == GroupType.STANDARD: standard_groups[other_gid] = access_rights[other_gid] - elif group.group_type == GroupTypeInModel.PRIMARY: + elif group.group_type == GroupType.PRIMARY: primary_groups[other_gid] = access_rights[other_gid] _logger.debug( diff --git a/services/web/server/src/simcore_service_webserver/groups/_common/schemas.py b/services/web/server/src/simcore_service_webserver/groups/_common/schemas.py index 872193aaffe..18ab7cba5ff 100644 --- a/services/web/server/src/simcore_service_webserver/groups/_common/schemas.py +++ b/services/web/server/src/simcore_service_webserver/groups/_common/schemas.py @@ -1,7 +1,8 @@ from typing import Literal +from models_library.groups import GroupID from models_library.rest_base import RequestParameters, StrictRequestParameters -from models_library.users import GroupID, UserID +from models_library.users import UserID from pydantic import Field from ..._constants import RQ_PRODUCT_KEY, RQT_USERID_KEY diff --git a/services/web/server/src/simcore_service_webserver/groups/_groups_api.py b/services/web/server/src/simcore_service_webserver/groups/_groups_api.py index 18491ec60bf..465b57c8f80 100644 --- a/services/web/server/src/simcore_service_webserver/groups/_groups_api.py +++ b/services/web/server/src/simcore_service_webserver/groups/_groups_api.py @@ -4,13 +4,14 @@ from models_library.groups import ( AccessRightsDict, Group, + GroupID, GroupMember, GroupsByTypeTuple, StandardGroupCreate, StandardGroupUpdate, ) from models_library.products import ProductName -from models_library.users import GroupID, UserID +from models_library.users import UserID from pydantic import EmailStr from ..users.api import get_user diff --git a/services/web/server/src/simcore_service_webserver/groups/_groups_db.py b/services/web/server/src/simcore_service_webserver/groups/_groups_db.py index 570375f3646..aedc78676d3 100644 --- a/services/web/server/src/simcore_service_webserver/groups/_groups_db.py +++ b/services/web/server/src/simcore_service_webserver/groups/_groups_db.py @@ -3,19 +3,20 @@ import sqlalchemy as sa from aiohttp import web +from common_library.groups_enums import GroupType from models_library.basic_types import IDStr from models_library.groups import ( AccessRightsDict, Group, + GroupID, GroupInfoTuple, GroupMember, GroupsByTypeTuple, StandardGroupCreate, StandardGroupUpdate, ) -from models_library.users import GroupID, UserID +from models_library.users import UserID from simcore_postgres_database.errors import UniqueViolation -from simcore_postgres_database.models.groups import GroupType from simcore_postgres_database.utils_products import execute_get_or_create_product_group from simcore_postgres_database.utils_repos import ( pass_or_acquire_connection, @@ -653,19 +654,18 @@ async def add_new_user_in_group( ) _check_group_permissions(group, user_id, group_id, "write") - query = sa.select(sa.func.count()) - if new_user_id: + query = sa.select(users.c.id) + if new_user_id is not None: query = query.where(users.c.id == new_user_id) - elif new_user_name: + elif new_user_name is not None: query = query.where(users.c.name == new_user_name) else: - msg = "Either user name or id but none provided" + msg = "Expected either user-name or user-ID but none was provided" raise ValueError(msg) # now check the new user exists - users_count = await conn.scalar(query) - if not users_count: - assert new_user_id is not None # nosec + new_user_id = await conn.scalar(query) + if not new_user_id: raise UserInGroupNotFoundError(uid=new_user_id, gid=group_id) # add the new user to the group now diff --git a/services/web/server/src/simcore_service_webserver/notifications/_rabbitmq_exclusive_queue_consumers.py b/services/web/server/src/simcore_service_webserver/notifications/_rabbitmq_exclusive_queue_consumers.py index 048d0162fe3..1ba51262d84 100644 --- a/services/web/server/src/simcore_service_webserver/notifications/_rabbitmq_exclusive_queue_consumers.py +++ b/services/web/server/src/simcore_service_webserver/notifications/_rabbitmq_exclusive_queue_consumers.py @@ -3,6 +3,7 @@ from typing import Final from aiohttp import web +from models_library.groups import GroupID from models_library.rabbitmq_messages import ( EventRabbitMessage, LoggerRabbitMessage, @@ -12,7 +13,6 @@ WalletCreditsMessage, ) from models_library.socketio import SocketMessageDict -from models_library.users import GroupID from pydantic import TypeAdapter from servicelib.logging_utils import log_catch, log_context from servicelib.rabbitmq import RabbitMQClient diff --git a/services/web/server/src/simcore_service_webserver/projects/_groups_api.py b/services/web/server/src/simcore_service_webserver/projects/_groups_api.py index b32a6d15fa1..355b25481f6 100644 --- a/services/web/server/src/simcore_service_webserver/projects/_groups_api.py +++ b/services/web/server/src/simcore_service_webserver/projects/_groups_api.py @@ -2,9 +2,10 @@ from datetime import datetime from aiohttp import web +from models_library.groups import GroupID from models_library.products import ProductName from models_library.projects import ProjectID -from models_library.users import GroupID, UserID +from models_library.users import UserID from pydantic import BaseModel from ..users import api as users_api diff --git a/services/web/server/src/simcore_service_webserver/projects/_groups_db.py b/services/web/server/src/simcore_service_webserver/projects/_groups_db.py index 4355f0c9d92..86d9c83d781 100644 --- a/services/web/server/src/simcore_service_webserver/projects/_groups_db.py +++ b/services/web/server/src/simcore_service_webserver/projects/_groups_db.py @@ -8,8 +8,8 @@ from datetime import datetime from aiohttp import web +from models_library.groups import GroupID from models_library.projects import ProjectID -from models_library.users import GroupID from pydantic import BaseModel, ConfigDict, TypeAdapter from simcore_postgres_database.models.project_to_groups import project_to_groups from simcore_postgres_database.utils_repos import transaction_context diff --git a/services/web/server/src/simcore_service_webserver/projects/_groups_handlers.py b/services/web/server/src/simcore_service_webserver/projects/_groups_handlers.py index a747798100e..bf612944d4b 100644 --- a/services/web/server/src/simcore_service_webserver/projects/_groups_handlers.py +++ b/services/web/server/src/simcore_service_webserver/projects/_groups_handlers.py @@ -6,9 +6,9 @@ import logging from aiohttp import web +from models_library.groups import GroupID from models_library.projects import ProjectID -from models_library.users import GroupID -from pydantic import ConfigDict, BaseModel +from pydantic import BaseModel, ConfigDict from servicelib.aiohttp import status from servicelib.aiohttp.requests_validation import ( parse_request_body_as, diff --git a/services/web/server/src/simcore_service_webserver/projects/_nodes_handlers.py b/services/web/server/src/simcore_service_webserver/projects/_nodes_handlers.py index d5978f794d2..6670ed64442 100644 --- a/services/web/server/src/simcore_service_webserver/projects/_nodes_handlers.py +++ b/services/web/server/src/simcore_service_webserver/projects/_nodes_handlers.py @@ -25,12 +25,11 @@ NodePatch, NodeRetrieve, ) -from models_library.groups import EVERYONE_GROUP_ID, Group, GroupTypeInModel +from models_library.groups import EVERYONE_GROUP_ID, Group, GroupID, GroupType from models_library.projects import Project, ProjectID from models_library.projects_nodes_io import NodeID, NodeIDStr from models_library.services import ServiceKeyVersion from models_library.services_resources import ServiceResourcesDict -from models_library.users import GroupID from models_library.utils.fastapi_encoders import jsonable_encoder from pydantic import BaseModel, Field from servicelib.aiohttp import status @@ -567,7 +566,7 @@ async def get_project_services_access_for_gid( raise GroupNotFoundError(gid=query_params.for_gid) # Update groups to compare based on the type of sharing group - if _sharing_with_group.group_type == GroupTypeInModel.PRIMARY: + if _sharing_with_group.group_type == GroupType.PRIMARY: _user_id = await get_user_id_from_gid( app=request.app, primary_gid=query_params.for_gid ) @@ -576,7 +575,7 @@ async def get_project_services_access_for_gid( ) groups_to_compare.update(set(user_groups_ids)) groups_to_compare.add(query_params.for_gid) - elif _sharing_with_group.group_type == GroupTypeInModel.STANDARD: + elif _sharing_with_group.group_type == GroupType.STANDARD: groups_to_compare = {query_params.for_gid} # Initialize a list for inaccessible services diff --git a/services/web/server/src/simcore_service_webserver/projects/projects_api.py b/services/web/server/src/simcore_service_webserver/projects/projects_api.py index c0d3c8af835..472855677b4 100644 --- a/services/web/server/src/simcore_service_webserver/projects/projects_api.py +++ b/services/web/server/src/simcore_service_webserver/projects/projects_api.py @@ -35,6 +35,7 @@ from models_library.api_schemas_webserver.projects_nodes import NodePatch from models_library.basic_types import KeyIDStr from models_library.errors import ErrorDict +from models_library.groups import GroupID from models_library.products import ProductName from models_library.projects import Project, ProjectID, ProjectIDStr from models_library.projects_access import Owner @@ -59,7 +60,7 @@ ServiceResourcesDictHelpers, ) from models_library.socketio import SocketMessageDict -from models_library.users import GroupID, UserID +from models_library.users import UserID from models_library.utils.fastapi_encoders import jsonable_encoder from models_library.wallets import ZERO_CREDITS, WalletID, WalletInfo from models_library.workspaces import UserWorkspaceAccessRightsDB diff --git a/services/web/server/src/simcore_service_webserver/socketio/messages.py b/services/web/server/src/simcore_service_webserver/socketio/messages.py index 388dd8e6a5b..081cab05377 100644 --- a/services/web/server/src/simcore_service_webserver/socketio/messages.py +++ b/services/web/server/src/simcore_service_webserver/socketio/messages.py @@ -7,8 +7,9 @@ from aiohttp.web import Application from models_library.api_schemas_webserver.socketio import SocketIORoomStr +from models_library.groups import GroupID from models_library.socketio import SocketMessageDict -from models_library.users import GroupID, UserID +from models_library.users import UserID from models_library.utils.fastapi_encoders import jsonable_encoder from servicelib.logging_utils import log_catch from socketio import AsyncServer # type: ignore[import-untyped] diff --git a/services/web/server/src/simcore_service_webserver/tags/schemas.py b/services/web/server/src/simcore_service_webserver/tags/schemas.py index e2d9e2104cd..34ccce7248a 100644 --- a/services/web/server/src/simcore_service_webserver/tags/schemas.py +++ b/services/web/server/src/simcore_service_webserver/tags/schemas.py @@ -3,8 +3,9 @@ from typing import Annotated from models_library.api_schemas_webserver._base import InputSchema, OutputSchema +from models_library.groups import GroupID from models_library.rest_base import RequestParameters, StrictRequestParameters -from models_library.users import GroupID, UserID +from models_library.users import UserID from pydantic import Field, PositiveInt, StringConstraints from servicelib.request_keys import RQT_USERID_KEY from simcore_postgres_database.utils_tags import TagDict diff --git a/services/web/server/src/simcore_service_webserver/users/_db.py b/services/web/server/src/simcore_service_webserver/users/_db.py index 2071034d2e6..f80c4596423 100644 --- a/services/web/server/src/simcore_service_webserver/users/_db.py +++ b/services/web/server/src/simcore_service_webserver/users/_db.py @@ -5,7 +5,8 @@ from aiopg.sa.connection import SAConnection from aiopg.sa.engine import Engine from aiopg.sa.result import ResultProxy, RowProxy -from models_library.users import GroupID, UserBillingDetails, UserID +from models_library.groups import GroupID +from models_library.users import UserBillingDetails, UserID from simcore_postgres_database.models.groups import groups, user_to_groups from simcore_postgres_database.models.products import products from simcore_postgres_database.models.users import UserStatus, users diff --git a/services/web/server/src/simcore_service_webserver/users/api.py b/services/web/server/src/simcore_service_webserver/users/api.py index 623d4f44396..1c1d217a28e 100644 --- a/services/web/server/src/simcore_service_webserver/users/api.py +++ b/services/web/server/src/simcore_service_webserver/users/api.py @@ -20,8 +20,9 @@ MyProfilePrivacyGet, ) from models_library.basic_types import IDStr +from models_library.groups import GroupID from models_library.products import ProductName -from models_library.users import GroupID, UserID +from models_library.users import UserID from pydantic import EmailStr, TypeAdapter, ValidationError from simcore_postgres_database.models.groups import GroupType, groups, user_to_groups from simcore_postgres_database.models.users import UserRole, users diff --git a/services/web/server/src/simcore_service_webserver/wallets/_db.py b/services/web/server/src/simcore_service_webserver/wallets/_db.py index 413b68ff84f..98ec51a658c 100644 --- a/services/web/server/src/simcore_service_webserver/wallets/_db.py +++ b/services/web/server/src/simcore_service_webserver/wallets/_db.py @@ -6,8 +6,9 @@ import logging from aiohttp import web +from models_library.groups import GroupID from models_library.products import ProductName -from models_library.users import GroupID, UserID +from models_library.users import UserID from models_library.wallets import UserWalletDB, WalletDB, WalletID, WalletStatus from simcore_postgres_database.models.groups import user_to_groups from simcore_postgres_database.models.wallet_to_groups import wallet_to_groups diff --git a/services/web/server/src/simcore_service_webserver/wallets/_groups_api.py b/services/web/server/src/simcore_service_webserver/wallets/_groups_api.py index bdace14a9de..5a3dcc0a339 100644 --- a/services/web/server/src/simcore_service_webserver/wallets/_groups_api.py +++ b/services/web/server/src/simcore_service_webserver/wallets/_groups_api.py @@ -2,8 +2,9 @@ from datetime import datetime from aiohttp import web +from models_library.groups import GroupID from models_library.products import ProductName -from models_library.users import GroupID, UserID +from models_library.users import UserID from models_library.wallets import UserWalletDB, WalletID from pydantic import BaseModel, ConfigDict @@ -23,10 +24,8 @@ class WalletGroupGet(BaseModel): delete: bool created: datetime modified: datetime - - model_config = ConfigDict( - from_attributes=True - ) + + model_config = ConfigDict(from_attributes=True) async def create_wallet_group( diff --git a/services/web/server/src/simcore_service_webserver/wallets/_groups_db.py b/services/web/server/src/simcore_service_webserver/wallets/_groups_db.py index 949978a470f..8c2148e05ce 100644 --- a/services/web/server/src/simcore_service_webserver/wallets/_groups_db.py +++ b/services/web/server/src/simcore_service_webserver/wallets/_groups_db.py @@ -7,7 +7,7 @@ from datetime import datetime from aiohttp import web -from models_library.users import GroupID +from models_library.groups import GroupID from models_library.wallets import WalletID from pydantic import BaseModel, TypeAdapter from simcore_postgres_database.models.wallet_to_groups import wallet_to_groups diff --git a/services/web/server/src/simcore_service_webserver/wallets/_groups_handlers.py b/services/web/server/src/simcore_service_webserver/wallets/_groups_handlers.py index ac71f39af41..4ad171090ed 100644 --- a/services/web/server/src/simcore_service_webserver/wallets/_groups_handlers.py +++ b/services/web/server/src/simcore_service_webserver/wallets/_groups_handlers.py @@ -6,7 +6,7 @@ import logging from aiohttp import web -from models_library.users import GroupID +from models_library.groups import GroupID from models_library.wallets import WalletID from pydantic import BaseModel, ConfigDict from servicelib.aiohttp import status diff --git a/services/web/server/src/simcore_service_webserver/workspaces/_groups_api.py b/services/web/server/src/simcore_service_webserver/workspaces/_groups_api.py index cca4da82e4e..2ca935c8967 100644 --- a/services/web/server/src/simcore_service_webserver/workspaces/_groups_api.py +++ b/services/web/server/src/simcore_service_webserver/workspaces/_groups_api.py @@ -2,8 +2,9 @@ from datetime import datetime from aiohttp import web +from models_library.groups import GroupID from models_library.products import ProductName -from models_library.users import GroupID, UserID +from models_library.users import UserID from models_library.workspaces import UserWorkspaceAccessRightsDB, WorkspaceID from pydantic import BaseModel, ConfigDict @@ -24,10 +25,8 @@ class WorkspaceGroupGet(BaseModel): delete: bool created: datetime modified: datetime - - model_config = ConfigDict( - from_attributes=True - ) + + model_config = ConfigDict(from_attributes=True) async def create_workspace_group( diff --git a/services/web/server/src/simcore_service_webserver/workspaces/_groups_db.py b/services/web/server/src/simcore_service_webserver/workspaces/_groups_db.py index b5b969f0db4..d14127d5b37 100644 --- a/services/web/server/src/simcore_service_webserver/workspaces/_groups_db.py +++ b/services/web/server/src/simcore_service_webserver/workspaces/_groups_db.py @@ -8,7 +8,7 @@ from datetime import datetime from aiohttp import web -from models_library.users import GroupID +from models_library.groups import GroupID from models_library.workspaces import WorkspaceID from pydantic import BaseModel, ConfigDict from simcore_postgres_database.models.workspaces_access_rights import ( diff --git a/services/web/server/src/simcore_service_webserver/workspaces/_models.py b/services/web/server/src/simcore_service_webserver/workspaces/_models.py index af35fe4b63f..d2f22a3c878 100644 --- a/services/web/server/src/simcore_service_webserver/workspaces/_models.py +++ b/services/web/server/src/simcore_service_webserver/workspaces/_models.py @@ -2,6 +2,7 @@ from typing import Annotated from models_library.basic_types import IDStr +from models_library.groups import GroupID from models_library.rest_base import RequestParameters, StrictRequestParameters from models_library.rest_filters import Filters, FiltersQueryParameters from models_library.rest_ordering import ( @@ -11,7 +12,7 @@ ) from models_library.rest_pagination import PageQueryParameters from models_library.trash import RemoveQueryParams -from models_library.users import GroupID, UserID +from models_library.users import UserID from models_library.utils.common_validators import empty_str_to_none_pre_validator from models_library.workspaces import WorkspaceID from pydantic import BaseModel, BeforeValidator, ConfigDict, Field diff --git a/services/web/server/src/simcore_service_webserver/workspaces/_workspaces_db.py b/services/web/server/src/simcore_service_webserver/workspaces/_workspaces_db.py index 3835e82f9e0..5264a112419 100644 --- a/services/web/server/src/simcore_service_webserver/workspaces/_workspaces_db.py +++ b/services/web/server/src/simcore_service_webserver/workspaces/_workspaces_db.py @@ -8,9 +8,10 @@ from typing import cast from aiohttp import web +from models_library.groups import GroupID from models_library.products import ProductName from models_library.rest_ordering import OrderBy, OrderDirection -from models_library.users import GroupID, UserID +from models_library.users import UserID from models_library.workspaces import ( UserWorkspaceAccessRightsDB, WorkspaceDB, diff --git a/services/web/server/tests/unit/isolated/test_groups_models.py b/services/web/server/tests/unit/isolated/test_groups_models.py index 9813ca6009c..2e5201422e9 100644 --- a/services/web/server/tests/unit/isolated/test_groups_models.py +++ b/services/web/server/tests/unit/isolated/test_groups_models.py @@ -1,6 +1,4 @@ -import models_library.groups import pytest -import simcore_postgres_database.models.groups from faker import Faker from models_library.api_schemas_webserver._base import OutputSchema from models_library.api_schemas_webserver.groups import ( @@ -14,23 +12,13 @@ AccessRightsDict, Group, GroupMember, - GroupTypeInModel, + GroupType, StandardGroupCreate, StandardGroupUpdate, ) -from models_library.utils.enums import enum_to_dict from pydantic import ValidationError -def test_models_library_and_postgress_database_enums_are_equivalent(): - # For the moment these two libraries they do not have a common library to share these - # basic types so we test here that they are in sync - - assert enum_to_dict( - simcore_postgres_database.models.groups.GroupType - ) == enum_to_dict(models_library.groups.GroupTypeInModel) - - def test_sanitize_legacy_data(): users_group_1 = GroupGet.model_validate( { @@ -66,7 +54,7 @@ def test_output_schemas_from_models(faker: Faker): gid=1, name=faker.word(), description=faker.sentence(), - group_type=GroupTypeInModel.STANDARD, + group_type=GroupType.STANDARD, thumbnail=None, ) output_schema = GroupGet.from_model( diff --git a/services/web/server/tests/unit/isolated/test_projects__db_utils.py b/services/web/server/tests/unit/isolated/test_projects__db_utils.py index cee237fda90..c8c4da57eda 100644 --- a/services/web/server/tests/unit/isolated/test_projects__db_utils.py +++ b/services/web/server/tests/unit/isolated/test_projects__db_utils.py @@ -11,9 +11,9 @@ import pytest from faker import Faker +from models_library.groups import GroupID from models_library.projects_nodes import Node from models_library.services import ServiceKey -from models_library.users import GroupID from models_library.utils.fastapi_encoders import jsonable_encoder from simcore_service_webserver.projects._db_utils import ( DB_EXCLUSIVE_COLUMNS, diff --git a/services/web/server/tests/unit/with_dbs/01/groups/test_groups_handlers_users.py b/services/web/server/tests/unit/with_dbs/01/groups/test_groups_handlers_users.py index 97ebd6e2b51..f018e6fab00 100644 --- a/services/web/server/tests/unit/with_dbs/01/groups/test_groups_handlers_users.py +++ b/services/web/server/tests/unit/with_dbs/01/groups/test_groups_handlers_users.py @@ -6,12 +6,14 @@ from collections.abc import AsyncIterator from contextlib import AsyncExitStack +from typing import AsyncIterable import pytest from aiohttp.test_utils import TestClient from faker import Faker from models_library.api_schemas_webserver.groups import GroupGet, GroupUserGet from models_library.groups import AccessRightsDict, Group, StandardGroupCreate +from pydantic import TypeAdapter from pytest_simcore.helpers.assert_checks import assert_status from pytest_simcore.helpers.webserver_login import LoggedUser, NewUser, UserInfoDict from pytest_simcore.helpers.webserver_parametrizations import ( @@ -19,6 +21,7 @@ standard_role_response, ) from servicelib.aiohttp import status +from servicelib.status_codes_utils import is_2xx_success from simcore_postgres_database.models.users import UserRole from simcore_service_webserver._meta import API_VTAG from simcore_service_webserver.groups._groups_api import ( @@ -514,3 +517,96 @@ async def test_adding_user_to_group_with_upper_case_email( assert not data assert not error + + +@pytest.fixture +async def other_user( + client: TestClient, logged_user: UserInfoDict, is_private_user: bool +) -> AsyncIterable[UserInfoDict]: + # new user different from logged_user + async with NewUser( + { + "name": f"other_than_{logged_user['name']}", + "role": "USER", + "privacy_hide_email": is_private_user, + }, + client.app, + ) as user: + yield user + + +@pytest.mark.acceptance_test( + "https://github.com/ITISFoundation/osparc-simcore/pull/6917" +) +@pytest.mark.parametrize("user_role", [UserRole.USER]) +@pytest.mark.parametrize("is_private_user", [True, False]) +@pytest.mark.parametrize("add_user_by", ["user_email", "user_id", "user_name"]) +async def test_create_organization_and_add_users( + client: TestClient, + user_role: UserRole, + logged_user: UserInfoDict, + other_user: UserInfoDict, + is_private_user: bool, + add_user_by: str, +): + assert client.app + assert logged_user["id"] != 0 + assert logged_user["role"] == user_role.value + + # CREATE GROUP + url = client.app.router["create_group"].url_for() + resp = await client.post( + f"{url}", + json={ + "label": "Amies sans-frontiers", + "description": "A desperate attempt to make some friends", + }, + ) + data, error = await assert_status(resp, status.HTTP_201_CREATED) + + assert not error + group = GroupGet.model_validate(data) + + # i have another user + user_id = other_user["id"] + user_name = other_user["name"] + user_email = other_user["email"] + + assert user_id != logged_user["id"] + assert user_name != logged_user["name"] + assert user_email != logged_user["email"] + + # ADD new user to GROUP + url = client.app.router["add_group_user"].url_for(gid=f"{group.gid}") + + expected_status = status.HTTP_204_NO_CONTENT + match add_user_by: + case "user_email": + param = {"email": user_email} + if is_private_user: + expected_status = status.HTTP_404_NOT_FOUND + case "user_id": + param = {"uid": user_id} + case "user_name": + param = {"userName": user_name} + case _: + pytest.fail(reason=f"parameter {add_user_by} was not accounted for") + + response = await client.post(f"{url}", json=param) + await assert_status(response, expected_status) + + # LIST USERS in GROUP + url = client.app.router["get_all_group_users"].url_for(gid=f"{group.gid}") + response = await client.get(f"{url}") + data, _ = await assert_status(response, status.HTTP_200_OK) + + group_members = TypeAdapter(list[GroupUserGet]).validate_python(data) + if is_2xx_success(expected_status): + assert user_id in [ + u.id for u in group_members + ], "failed to add other-user to the group!" + + # DELETE GROUP + url = client.app.router["delete_group"].url_for(gid=f"{group.gid}") + resp = await client.delete(f"{url}") + await assert_status(resp, status.HTTP_204_NO_CONTENT)