Skip to content

Commit 9699b93

Browse files
committed
@sanderegg review: access-rights
1 parent 8c1b1ba commit 9699b93

File tree

7 files changed

+80
-60
lines changed

7 files changed

+80
-60
lines changed

api/specs/web-server/_projects_groups.py renamed to api/specs/web-server/_projects_access_rights.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@
77
from typing import Annotated
88

99
from fastapi import APIRouter, Depends, status
10-
from models_library.api_schemas_webserver.groups import ProjectShare
10+
from models_library.api_schemas_webserver.projects_access_rights import (
11+
ProjectsGroupsBodyParams,
12+
ProjectsGroupsPathParams,
13+
ProjectShare,
14+
ProjectShareAccepted,
15+
)
1116
from models_library.generics import Envelope
1217
from simcore_service_webserver._meta import API_VTAG
1318
from simcore_service_webserver.projects._controller._rest_schemas import (
1419
ProjectPathParams,
1520
)
16-
from simcore_service_webserver.projects._controller.groups_rest import (
17-
ProjectShareAccepted,
18-
_ProjectsGroupsBodyParams,
19-
_ProjectsGroupsPathParams,
20-
)
2121
from simcore_service_webserver.projects._groups_service import ProjectGroupGet
2222

2323
router = APIRouter(
@@ -48,8 +48,8 @@ async def share_project(
4848
status_code=status.HTTP_201_CREATED,
4949
)
5050
async def create_project_group(
51-
_path: Annotated[_ProjectsGroupsPathParams, Depends()],
52-
_body: _ProjectsGroupsBodyParams,
51+
_path: Annotated[ProjectsGroupsPathParams, Depends()],
52+
_body: ProjectsGroupsBodyParams,
5353
): ...
5454

5555

@@ -65,8 +65,8 @@ async def list_project_groups(_path: Annotated[ProjectPathParams, Depends()]): .
6565
response_model=Envelope[ProjectGroupGet],
6666
)
6767
async def replace_project_group(
68-
_path: Annotated[_ProjectsGroupsPathParams, Depends()],
69-
_body: _ProjectsGroupsBodyParams,
68+
_path: Annotated[ProjectsGroupsPathParams, Depends()],
69+
_body: ProjectsGroupsBodyParams,
7070
): ...
7171

7272

@@ -75,5 +75,5 @@ async def replace_project_group(
7575
status_code=status.HTTP_204_NO_CONTENT,
7676
)
7777
async def delete_project_group(
78-
_path: Annotated[_ProjectsGroupsPathParams, Depends()],
78+
_path: Annotated[ProjectsGroupsPathParams, Depends()],
7979
): ...

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

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@
88
AnyUrl,
99
BaseModel,
1010
ConfigDict,
11-
EmailStr,
1211
Field,
13-
HttpUrl,
1412
TypeAdapter,
1513
ValidationError,
1614
field_validator,
@@ -385,17 +383,3 @@ class GroupUserUpdate(InputSchema):
385383
}
386384
}
387385
)
388-
389-
390-
class ProjectShare(InputSchema):
391-
sharee_email: EmailStr
392-
393-
# sharing access
394-
read: bool
395-
write: bool
396-
delete: bool
397-
398-
399-
class ProjectShareAccepted(OutputSchema):
400-
sharee_email: EmailStr
401-
confirmation_link: HttpUrl
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from typing import Annotated
2+
3+
from models_library.groups import GroupID
4+
from models_library.projects import ProjectID
5+
from pydantic import (
6+
BaseModel,
7+
ConfigDict,
8+
EmailStr,
9+
HttpUrl,
10+
StringConstraints,
11+
)
12+
13+
from ._base import InputSchema, OutputSchema
14+
15+
16+
class ProjectsGroupsPathParams(BaseModel):
17+
project_id: ProjectID
18+
group_id: GroupID
19+
model_config = ConfigDict(extra="forbid")
20+
21+
22+
class ProjectsGroupsBodyParams(InputSchema):
23+
read: bool
24+
write: bool
25+
delete: bool
26+
27+
28+
class ProjectShare(InputSchema):
29+
sharee_email: EmailStr
30+
sharer_message: Annotated[str, StringConstraints(max_length=500)]
31+
32+
# sharing access
33+
read: bool
34+
write: bool
35+
delete: bool
36+
37+
38+
class ProjectShareAccepted(OutputSchema):
39+
sharee_email: EmailStr
40+
confirmation_link: HttpUrl

packages/notifications-library/src/notifications_library/_repository.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,17 @@
33
import sqlalchemy as sa
44
from models_library.products import ProductName
55
from models_library.users import UserID
6-
from notifications_library._models import (
7-
JinjaTemplateDbGet,
8-
UserData,
9-
)
106
from simcore_postgres_database.models.jinja2_templates import jinja2_templates
117
from simcore_postgres_database.models.products_to_templates import products_to_templates
128
from simcore_postgres_database.models.users import users
139
from simcore_postgres_database.utils_repos import pass_or_acquire_connection
1410
from sqlalchemy.ext.asyncio import AsyncEngine
1511

12+
from ._models import (
13+
JinjaTemplateDbGet,
14+
UserData,
15+
)
16+
1617

1718
class _BaseRepo:
1819
def __init__(self, db_engine: AsyncEngine):

services/web/server/src/simcore_service_webserver/projects/_controller/groups_rest.py renamed to services/web/server/src/simcore_service_webserver/projects/_controller/access_rights_rest.py

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
import logging
22

33
from aiohttp import web
4-
from models_library.api_schemas_webserver.groups import (
4+
from common_library.json_serialization import json_dumps
5+
from models_library.api_schemas_webserver.projects_access_rights import (
6+
ProjectsGroupsBodyParams,
7+
ProjectsGroupsPathParams,
58
ProjectShare,
69
ProjectShareAccepted,
710
)
811
from models_library.basic_types import IDStr
9-
from models_library.groups import GroupID
10-
from models_library.projects import ProjectID
11-
from pydantic import BaseModel, ConfigDict
12+
from models_library.generics import Envelope
1213
from servicelib.aiohttp import status
1314
from servicelib.aiohttp.requests_validation import (
1415
parse_request_body_as,
1516
parse_request_path_parameters_as,
1617
)
1718
from servicelib.logging_utils import log_context
18-
from simcore_service_webserver.login._login_service import envelope_response
1919

2020
from ..._meta import api_version_prefix as VTAG
2121
from ...application_settings_utils import requires_dev_feature_enabled
@@ -77,25 +77,15 @@ async def share_project(request: web.Request):
7777
body_params.sharee_email,
7878
)
7979

80-
return envelope_response(
81-
data=ProjectShareAccepted(confirmation_link=confirmation_link), # type: ignore
80+
return web.json_response(
81+
Envelope[ProjectShareAccepted]
82+
.from_data({"confirmation_link": confirmation_link})
83+
.model_dump(),
84+
dumps=json_dumps,
8285
status=status.HTTP_202_ACCEPTED,
8386
)
8487

8588

86-
class _ProjectsGroupsPathParams(BaseModel):
87-
project_id: ProjectID
88-
group_id: GroupID
89-
model_config = ConfigDict(extra="forbid")
90-
91-
92-
class _ProjectsGroupsBodyParams(BaseModel):
93-
read: bool
94-
write: bool
95-
delete: bool
96-
model_config = ConfigDict(extra="forbid")
97-
98-
9989
@routes.post(
10090
f"/{VTAG}/projects/{{project_id}}/groups/{{group_id}}", name="create_project_group"
10191
)
@@ -104,8 +94,8 @@ class _ProjectsGroupsBodyParams(BaseModel):
10494
@handle_plugin_requests_exceptions
10595
async def create_project_group(request: web.Request):
10696
req_ctx = RequestContext.model_validate(request)
107-
path_params = parse_request_path_parameters_as(_ProjectsGroupsPathParams, request)
108-
body_params = await parse_request_body_as(_ProjectsGroupsBodyParams, request)
97+
path_params = parse_request_path_parameters_as(ProjectsGroupsPathParams, request)
98+
body_params = await parse_request_body_as(ProjectsGroupsBodyParams, request)
10999

110100
project_groups: ProjectGroupGet = await _groups_service.create_project_group(
111101
request.app,
@@ -150,8 +140,8 @@ async def list_project_groups(request: web.Request):
150140
@handle_plugin_requests_exceptions
151141
async def replace_project_group(request: web.Request):
152142
req_ctx = RequestContext.model_validate(request)
153-
path_params = parse_request_path_parameters_as(_ProjectsGroupsPathParams, request)
154-
body_params = await parse_request_body_as(_ProjectsGroupsBodyParams, request)
143+
path_params = parse_request_path_parameters_as(ProjectsGroupsPathParams, request)
144+
body_params = await parse_request_body_as(ProjectsGroupsBodyParams, request)
155145

156146
new_project_group = await _groups_service.replace_project_group(
157147
app=request.app,
@@ -175,7 +165,7 @@ async def replace_project_group(request: web.Request):
175165
@handle_plugin_requests_exceptions
176166
async def delete_project_group(request: web.Request):
177167
req_ctx = RequestContext.model_validate(request)
178-
path_params = parse_request_path_parameters_as(_ProjectsGroupsPathParams, request)
168+
path_params = parse_request_path_parameters_as(ProjectsGroupsPathParams, request)
179169

180170
await _groups_service.delete_project_group(
181171
app=request.app,

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
from ..constants import APP_SETTINGS_KEY
1313
from ..rabbitmq import setup_rabbitmq
1414
from ._controller import (
15+
access_rights_rest,
1516
comments_rest,
1617
folders_rest,
17-
groups_rest,
1818
metadata_rest,
1919
nodes_pricing_unit_rest,
2020
nodes_rest,
@@ -62,7 +62,7 @@ def setup_projects(app: web.Application) -> bool:
6262
app.router.add_routes(projects_states_rest.routes)
6363
app.router.add_routes(projects_rest.routes)
6464
app.router.add_routes(comments_rest.routes)
65-
app.router.add_routes(groups_rest.routes)
65+
app.router.add_routes(access_rights_rest.routes)
6666
app.router.add_routes(metadata_rest.routes)
6767
app.router.add_routes(ports_rest.routes)
6868
app.router.add_routes(nodes_rest.routes)

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99

1010
import pytest
1111
from aiohttp.test_utils import TestClient
12+
from models_library.api_schemas_webserver.projects_access_rights import (
13+
ProjectShareAccepted,
14+
)
1215
from pytest_mock.plugin import MockerFixture
1316
from pytest_simcore.helpers.assert_checks import assert_status
1417
from pytest_simcore.helpers.webserver_login import NewUser, UserInfoDict
@@ -271,14 +274,16 @@ async def test_share_project(
271274
f"{url}",
272275
json={
273276
"shareeEmail": "[email protected]",
277+
"sharerMessage": "hi there, this is the project we talked about",
274278
"read": True,
275279
"write": False,
276280
"delete": False,
277281
},
278282
)
279283
data, error = await assert_status(resp, status.HTTP_202_ACCEPTED)
280-
assert data["shareeEmail"] == "[email protected]"
281-
assert data["confirmationLink"]
284+
shared = ProjectShareAccepted.model_validate(data)
285+
assert shared.sharee_email == "[email protected]"
286+
assert shared.confirmation_link
282287
assert not error
283288

284289
# Verify that only logged_user["primary_gid"] has access to the project

0 commit comments

Comments
 (0)