Skip to content

Commit 12ee4b5

Browse files
authored
Merge branch 'master' into enh/handle-non-existing-services
2 parents f4de3a8 + b04091c commit 12ee4b5

29 files changed

+7
-281
lines changed

.github/workflows/ci-testing-deploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2656,7 +2656,7 @@ jobs:
26562656
if: ${{ always() }}
26572657
needs:
26582658
[
2659-
system-test-e2e,
2659+
# system-test-e2e, NOTE: not required, until Odei will have a look
26602660
system-test-e2e-playwright,
26612661
system-test-environment-setup,
26622662
system-test-public-api,

services/web/server/src/simcore_service_webserver/projects/_controller/projects_rest.py

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
from servicelib.redis import get_project_locked_state
2929

3030
from ..._meta import API_VTAG as VTAG
31-
from ...catalog import catalog_service
3231
from ...login.decorators import login_required
3332
from ...redis import get_redis_lock_manager_client_sdk
3433
from ...resource_manager.user_sessions import PROJECT_ID_KEY, managed_resource
@@ -39,7 +38,6 @@
3938
from .. import _crud_api_create, _crud_api_read, _projects_service
4039
from .._permalink_service import update_or_pop_permalink_in_project
4140
from ..models import ProjectDict
42-
from ..utils import are_project_services_available, get_project_unavailable_services
4341
from . import _rest_utils
4442
from ._rest_exceptions import handle_plugin_requests_exceptions
4543
from ._rest_schemas import (
@@ -271,10 +269,6 @@ async def get_project(request: web.Request):
271269
req_ctx = AuthenticatedRequestContext.model_validate(request)
272270
path_params = parse_request_path_parameters_as(ProjectPathParams, request)
273271

274-
user_available_services = await catalog_service.get_services_for_user_in_product(
275-
request.app, user_id=req_ctx.user_id, product_name=req_ctx.product_name
276-
)
277-
278272
project = await _projects_service.get_project_for_user(
279273
request.app,
280274
project_uuid=f"{path_params.project_id}",
@@ -283,21 +277,6 @@ async def get_project(request: web.Request):
283277
include_trashed_by_primary_gid=True,
284278
)
285279

286-
if not are_project_services_available(project, user_available_services):
287-
unavilable_services = get_project_unavailable_services(
288-
project, user_available_services
289-
)
290-
formatted_services = ", ".join(
291-
f"{service}:{version}" for service, version in unavilable_services
292-
)
293-
# TODO: lack of permissions should be notified with https://httpstatuses.com/403 web.HTTPForbidden
294-
raise web.HTTPNotFound(
295-
reason=(
296-
f"Project '{path_params.project_id}' uses unavailable services. Please ask "
297-
f"for permission for the following services {formatted_services}"
298-
)
299-
)
300-
301280
# Adds permalink
302281
await update_or_pop_permalink_in_project(request, project)
303282

services/web/server/src/simcore_service_webserver/projects/_crud_api_read.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
)
2323
from simcore_postgres_database.webserver_models import ProjectType as ProjectTypeDB
2424

25-
from ..catalog import catalog_service
2625
from ..folders import _folders_repository
2726
from ..workspaces.api import check_user_workspace_access
2827
from . import _projects_service
@@ -120,10 +119,6 @@ async def list_projects( # pylint: disable=too-many-arguments
120119
) -> tuple[list[ProjectDict], int]:
121120
db = ProjectDBAPI.get_from_app_context(app)
122121

123-
user_available_services = await catalog_service.get_services_for_user_in_product(
124-
app, user_id=user_id, product_name=product_name
125-
)
126-
127122
workspace_is_private = True
128123
if workspace_id:
129124
await check_user_workspace_access(
@@ -165,7 +160,6 @@ async def list_projects( # pylint: disable=too-many-arguments
165160
filter_by_template_type=(
166161
ProjectTemplateTypeDB(template_type) if template_type else None
167162
),
168-
filter_by_services=user_available_services,
169163
filter_trashed=trashed,
170164
filter_hidden=show_hidden,
171165
# composed attrs
@@ -202,17 +196,12 @@ async def list_projects_full_depth(
202196
) -> tuple[list[ProjectDict], int]:
203197
db = ProjectDBAPI.get_from_app_context(app)
204198

205-
user_available_services = await catalog_service.get_services_for_user_in_product(
206-
app, user_id=user_id, product_name=product_name
207-
)
208-
209199
db_projects, db_project_types, total_number_projects = await db.list_projects_dicts(
210200
product_name=product_name,
211201
user_id=user_id,
212202
workspace_query=WorkspaceQuery(workspace_scope=WorkspaceScope.ALL),
213203
folder_query=FolderQuery(folder_scope=FolderScope.ALL),
214204
filter_trashed=trashed,
215-
filter_by_services=user_available_services,
216205
filter_by_project_type=ProjectType.STANDARD,
217206
search_by_multi_columns=search_by_multi_columns,
218207
search_by_project_name=search_by_project_name,

services/web/server/src/simcore_service_webserver/projects/_projects_repository_legacy.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,6 @@ async def list_projects_dicts( # pylint: disable=too-many-arguments,too-many-st
573573
# attribute filters
574574
filter_by_project_type: ProjectType | None = None,
575575
filter_by_template_type: ProjectTemplateType | None = None,
576-
filter_by_services: list[dict] | None = None,
577576
filter_published: bool | None = None,
578577
filter_hidden: bool | None = False,
579578
filter_trashed: bool | None = False,
@@ -670,9 +669,7 @@ async def list_projects_dicts( # pylint: disable=too-many-arguments,too-many-st
670669

671670
prjs, prj_types = await self._execute_without_permission_check(
672671
conn,
673-
user_id=user_id,
674672
select_projects_query=combined_query.offset(offset).limit(limit),
675-
filter_by_services=filter_by_services,
676673
)
677674

678675
return (

services/web/server/src/simcore_service_webserver/projects/_projects_repository_legacy_utils.py

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,9 @@
1212
from models_library.projects import ProjectAtDB, ProjectID, ProjectTemplateType
1313
from models_library.projects_nodes import Node
1414
from models_library.projects_nodes_io import NodeIDStr
15-
from models_library.users import UserID
1615
from models_library.utils.change_case import camel_to_snake, snake_to_camel
1716
from pydantic import ValidationError
1817
from simcore_postgres_database.models.project_to_groups import project_to_groups
19-
from simcore_postgres_database.models.projects_to_products import projects_to_products
2018
from simcore_postgres_database.webserver_models import ProjectType, projects
2119
from sqlalchemy.dialects.postgresql import insert as pg_insert
2220
from sqlalchemy.sql.selectable import CompoundSelect, Select
@@ -32,7 +30,7 @@
3230
ProjectNotFoundError,
3331
)
3432
from .models import ProjectDict
35-
from .utils import are_project_services_available, find_changed_node_keys
33+
from .utils import find_changed_node_keys
3634

3735
logger = logging.getLogger(__name__)
3836

@@ -189,10 +187,8 @@ async def _upsert_tags_in_project(
189187
async def _execute_without_permission_check(
190188
self,
191189
conn: SAConnection,
192-
user_id: UserID,
193190
*,
194191
select_projects_query: Select | CompoundSelect,
195-
filter_by_services: list[dict] | None = None,
196192
) -> tuple[list[dict[str, Any]], list[ProjectType]]:
197193
api_projects: list[dict] = [] # API model-compatible projects
198194
db_projects: list[dict] = [] # DB model-compatible projects
@@ -218,19 +214,6 @@ async def _execute_without_permission_check(
218214
prj: dict[str, Any] = dict(row.items())
219215
prj.pop("product_name", None)
220216

221-
if (
222-
filter_by_services is not None
223-
# This checks only old projects that are not in the projects_to_products table.
224-
and row[projects_to_products.c.product_name] is None
225-
and not are_project_services_available(prj, filter_by_services)
226-
):
227-
logger.warning(
228-
"Project %s will not be listed for user %s since it has no access rights"
229-
" for one or more of the services that includes.",
230-
f"{row.id=}",
231-
f"{user_id=}",
232-
)
233-
continue
234217
db_projects.append(prj)
235218

236219
# NOTE: DO NOT nest _get_tags_by_project in async loop above !!!

services/web/server/src/simcore_service_webserver/projects/utils.py

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -189,42 +189,6 @@ def is_graph_equal(
189189
return True
190190

191191

192-
def are_project_services_available(
193-
project: dict[str, Any], available_services: list[dict[str, str]]
194-
) -> bool:
195-
if not project["workbench"]:
196-
# empty project
197-
return True
198-
199-
# list services in project
200-
needed_services = {
201-
(srv["key"], srv["version"]) for _, srv in project["workbench"].items()
202-
}
203-
204-
# list available services
205-
available_services_set = {
206-
(srv["key"], srv["version"]) for srv in available_services
207-
}
208-
209-
return needed_services.issubset(available_services_set)
210-
211-
212-
def get_project_unavailable_services(
213-
project: dict[str, Any], available_services: list[dict[str, Any]]
214-
) -> set[tuple[str, str]]:
215-
# get project services
216-
required: set[tuple[str, str]] = {
217-
(s["key"], s["version"]) for _, s in project["workbench"].items()
218-
}
219-
220-
# get available services
221-
available: set[tuple[str, str]] = {
222-
(s["key"], s["version"]) for s in available_services
223-
}
224-
225-
return required - available
226-
227-
228192
def extract_dns_without_default_port(url: URL) -> str:
229193
port = "" if url.port == 80 else f":{url.port}"
230194
return f"{url.host}{port}"

services/web/server/tests/unit/with_dbs/02/test_projects_cancellations.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,11 @@ async def test_copying_large_project_and_aborting_correctly_removes_new_project(
9797
standard_groups: list[dict[str, str]],
9898
user_project: dict[str, Any],
9999
expected: ExpectedResponse,
100-
catalog_subsystem_mock: Callable[[list[ProjectDict]], None],
101100
slow_storage_subsystem_mock: MockedStorageSubsystem,
102101
project_db_cleaner: None,
103102
mocked_dynamic_services_interface: dict[str, MagicMock],
104103
):
105104
assert client.app
106-
catalog_subsystem_mock([user_project])
107105
# initiate a project copy that will last long (simulated by a long running storage)
108106
# POST /v0/projects
109107
create_url = client.app.router["create_project"].url_for()
@@ -150,13 +148,11 @@ async def test_copying_large_project_and_retrieving_copy_task(
150148
standard_groups: list[dict[str, str]],
151149
user_project: dict[str, Any],
152150
expected: ExpectedResponse,
153-
catalog_subsystem_mock: Callable[[list[ProjectDict]], None],
154151
slow_storage_subsystem_mock: MockedStorageSubsystem,
155152
project_db_cleaner: None,
156153
mocked_dynamic_services_interface: dict[str, MagicMock],
157154
):
158155
assert client.app
159-
catalog_subsystem_mock([user_project])
160156

161157
# initiate a project copy that will last long (simulated by a long running storage)
162158
# POST /v0/projects
@@ -198,13 +194,11 @@ async def test_creating_new_project_from_template_without_copying_data_creates_s
198194
standard_groups: list[dict[str, str]],
199195
template_project: dict[str, Any],
200196
expected: ExpectedResponse,
201-
catalog_subsystem_mock: Callable[[list[ProjectDict]], None],
202197
slow_storage_subsystem_mock: MockedStorageSubsystem,
203198
project_db_cleaner: None,
204199
request_create_project: Callable[..., Awaitable[ProjectDict]],
205200
):
206201
assert client.app
207-
catalog_subsystem_mock([template_project])
208202
# create a project from another without copying data shall not call in the storage API
209203
# POST /v0/projects
210204
await request_create_project(
@@ -249,13 +243,11 @@ async def test_creating_new_project_as_template_without_copying_data_creates_ske
249243
standard_groups: list[dict[str, str]],
250244
user_project: dict[str, Any],
251245
expected: ExpectedResponse,
252-
catalog_subsystem_mock: Callable[[list[ProjectDict]], None],
253246
slow_storage_subsystem_mock: MockedStorageSubsystem,
254247
project_db_cleaner: None,
255248
request_create_project: Callable[..., Awaitable[ProjectDict]],
256249
):
257250
assert client.app
258-
catalog_subsystem_mock([user_project])
259251
# create a project from another without copying data shall not call in the storage API
260252
# POST /v0/projects
261253
await request_create_project(

services/web/server/tests/unit/with_dbs/02/test_projects_crud_handlers.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -194,10 +194,8 @@ async def test_list_projects(
194194
user_project: dict[str, Any],
195195
template_project: dict[str, Any],
196196
expected: HTTPStatus,
197-
catalog_subsystem_mock: Callable[[list[ProjectDict]], None],
198197
director_v2_service_mock: aioresponses,
199198
):
200-
catalog_subsystem_mock([user_project, template_project])
201199
data, *_ = await _list_and_assert_projects(client, expected)
202200

203201
if data:
@@ -344,7 +342,6 @@ async def test_list_projects_with_innaccessible_services(
344342
user_project: dict[str, Any],
345343
template_project: dict[str, Any],
346344
expected: HTTPStatus,
347-
catalog_subsystem_mock: Callable[[list[ProjectDict]], None],
348345
director_v2_service_mock: aioresponses,
349346
postgres_db: sa.engine.Engine,
350347
s4l_product_headers: dict[str, Any],
@@ -374,7 +371,6 @@ async def test_list_projects_with_innaccessible_services(
374371

375372
# use-case 4: give user access to services
376373
# shall return the projects for any product
377-
catalog_subsystem_mock([user_project, template_project])
378374
data, *_ = await _list_and_assert_projects(
379375
client, expected, headers=s4l_product_headers
380376
)
@@ -403,10 +399,7 @@ async def test_get_project(
403399
user_project: ProjectDict,
404400
template_project: ProjectDict,
405401
expected,
406-
catalog_subsystem_mock: Callable[[list[ProjectDict]], None],
407402
):
408-
catalog_subsystem_mock([user_project, template_project])
409-
410403
# standard project
411404
await _assert_get_same_project(client, user_project, expected)
412405

@@ -444,7 +437,6 @@ async def test_create_get_and_patch_project_ui_field(
444437
logged_user: UserInfoDict,
445438
primary_group: dict[str, str],
446439
request_create_project: Callable[..., Awaitable[ProjectDict]],
447-
catalog_subsystem_mock: Callable[[list[ProjectDict]], None],
448440
project_db_cleaner,
449441
):
450442
assert client.app
@@ -462,8 +454,6 @@ async def test_create_get_and_patch_project_ui_field(
462454
)
463455
project_id = new_project["uuid"]
464456

465-
catalog_subsystem_mock([new_project])
466-
467457
# Step 2: Get the project and check the ui.icon
468458
url = client.app.router["get_project"].url_for(project_id=project_id)
469459
resp = await client.get(f"{url}")
@@ -522,11 +512,9 @@ async def test_new_project_from_other_study(
522512
user_project: ProjectDict,
523513
expected: ExpectedResponse,
524514
storage_subsystem_mock,
525-
catalog_subsystem_mock: Callable[[list[ProjectDict]], None],
526515
project_db_cleaner,
527516
request_create_project: Callable[..., Awaitable[ProjectDict]],
528517
):
529-
catalog_subsystem_mock([user_project])
530518
new_project = await request_create_project(
531519
client,
532520
expected.accepted,
@@ -608,7 +596,6 @@ async def test_new_template_from_project(
608596
user_project: dict[str, Any],
609597
expected: ExpectedResponse,
610598
storage_subsystem_mock: MockedStorageSubsystem,
611-
catalog_subsystem_mock: Callable[[list[ProjectDict]], None],
612599
project_db_cleaner: None,
613600
request_create_project: Callable[..., Awaitable[ProjectDict]],
614601
):
@@ -625,7 +612,6 @@ async def test_new_template_from_project(
625612

626613
if new_template_prj:
627614
template_project = new_template_prj
628-
catalog_subsystem_mock([template_project])
629615

630616
templates, *_ = await _list_and_assert_projects(
631617
client, status.HTTP_200_OK, {"type": "template"}

services/web/server/tests/unit/with_dbs/02/test_projects_crud_handlers__delete.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ async def test_delete_project(
6161
expected: ExpectedResponse,
6262
storage_subsystem_mock: MockedStorageSubsystem,
6363
mocked_dynamic_services_interface: dict[str, MagicMock],
64-
catalog_subsystem_mock: Callable[[list[ProjectDict]], None],
6564
fake_services: Callable[..., Awaitable[list[DynamicServiceGet]]],
6665
assert_get_same_project_caller: Callable,
6766
mock_dynamic_scheduler_rabbitmq: None,

services/web/server/tests/unit/with_dbs/02/test_projects_crud_handlers__list.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ async def test_list_projects_with_invalid_pagination_parameters(
133133
primary_group: dict[str, str],
134134
expected: ExpectedResponse,
135135
storage_subsystem_mock,
136-
catalog_subsystem_mock: Callable[[list[ProjectDict]], None],
137136
director_v2_service_mock: aioresponses,
138137
project_db_cleaner,
139138
limit: int,
@@ -158,7 +157,6 @@ async def test_list_projects_with_pagination(
158157
primary_group: dict[str, str],
159158
expected: ExpectedResponse,
160159
storage_subsystem_mock,
161-
catalog_subsystem_mock: Callable[[list[ProjectDict]], None],
162160
director_v2_service_mock: aioresponses,
163161
project_db_cleaner,
164162
limit: int,
@@ -175,7 +173,6 @@ async def test_list_projects_with_pagination(
175173
]
176174
)
177175
if expected.created == status.HTTP_201_CREATED:
178-
catalog_subsystem_mock(created_projects)
179176

180177
assert len(created_projects) == NUM_PROJECTS
181178
NUMBER_OF_CALLS = ceil(NUM_PROJECTS / limit)

0 commit comments

Comments
 (0)