Skip to content

Commit 8035601

Browse files
Merge branch 'master' into make-api-server-celery-concurrency-configurable
2 parents 3e3331c + 9149e41 commit 8035601

File tree

84 files changed

+2731
-1175
lines changed

Some content is hidden

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

84 files changed

+2731
-1175
lines changed

api/specs/web-server/_nih_sparc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from fastapi import APIRouter
99
from models_library.generics import Envelope
1010
from simcore_service_webserver._meta import API_VTAG
11-
from simcore_service_webserver.studies_dispatcher._rest_handlers import (
11+
from simcore_service_webserver.studies_dispatcher._controller.rest.nih_schemas import (
1212
ServiceGet,
1313
Viewer,
1414
)

api/specs/web-server/_nih_sparc_redirections.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
""" Helper script to generate OAS automatically NIH-sparc portal API section
2-
"""
1+
"""Helper script to generate OAS automatically NIH-sparc portal API section"""
32

43
# pylint: disable=protected-access
54
# pylint: disable=redefined-outer-name
@@ -11,7 +10,7 @@
1110
from fastapi import APIRouter, status
1211
from fastapi.responses import RedirectResponse
1312
from models_library.projects import ProjectID
14-
from models_library.services import ServiceKey, ServiceKeyVersion
13+
from models_library.services_types import ServiceKey, ServiceVersion
1514
from pydantic import HttpUrl, PositiveInt
1615

1716
router = APIRouter(
@@ -31,7 +30,7 @@
3130
async def get_redirection_to_viewer(
3231
file_type: str,
3332
viewer_key: ServiceKey,
34-
viewer_version: ServiceKeyVersion,
33+
viewer_version: ServiceVersion,
3534
file_size: PositiveInt,
3635
download_link: HttpUrl,
3736
file_name: str | None = "unknown",

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

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,17 @@ class MyProfilePrivacyPatch(InputSchema):
6262
hide_email: bool | None = None
6363

6464

65+
class MyProfileAddressGet(OutputSchema):
66+
"""Details provided upon registration and used e.g. for invoicing"""
67+
68+
institution: str | None
69+
address: str | None
70+
city: str | None
71+
state: Annotated[str | None, Field(description="State, province, canton, ...")]
72+
postal_code: str | None
73+
country: str | None
74+
75+
6576
class MyProfileRestGet(OutputSchemaWithoutCamelCase):
6677
id: UserID
6778
user_name: Annotated[
@@ -86,6 +97,7 @@ class MyProfileRestGet(OutputSchemaWithoutCamelCase):
8697

8798
privacy: MyProfilePrivacyGet
8899
preferences: AggregatedPreferences
100+
contact: MyProfileAddressGet | None = None
89101

90102
@staticmethod
91103
def _update_json_schema_extra(schema: JsonDict) -> None:
@@ -105,6 +117,25 @@ def _update_json_schema_extra(schema: JsonDict) -> None:
105117
"hide_email": 1,
106118
},
107119
},
120+
{
121+
"id": 1,
122+
"login": "[email protected]",
123+
"userName": "minuser",
124+
"role": "USER",
125+
"preferences": {},
126+
"privacy": {
127+
"hide_username": False,
128+
"hide_fullname": False,
129+
"hide_email": False,
130+
},
131+
"provided": {
132+
"address": "123 Main St",
133+
"city": "Sampleville",
134+
"state": "CA",
135+
"postal_code": "12345",
136+
"country": "Wonderland",
137+
},
138+
},
108139
]
109140
}
110141
)
@@ -133,8 +164,9 @@ def from_domain_model(
133164
my_product_group: tuple[Group, AccessRightsDict] | None,
134165
my_preferences: AggregatedPreferences,
135166
my_support_group: Group | None,
167+
profile_contact: MyProfileAddressGet | None = None,
136168
) -> Self:
137-
data = remap_keys(
169+
profile_data = remap_keys(
138170
my_profile.model_dump(
139171
include={
140172
"id",
@@ -152,11 +184,12 @@ def from_domain_model(
152184
rename={"email": "login"},
153185
)
154186
return cls(
155-
**data,
187+
**profile_data,
156188
groups=MyGroupsGet.from_domain_model(
157189
my_groups_by_type, my_product_group, my_support_group
158190
),
159191
preferences=my_preferences,
192+
contact=profile_contact,
160193
)
161194

162195

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,11 @@ class UserBillingDetails(BaseModel):
7171
institution: str | None
7272
address: str | None
7373
city: str | None
74-
state: str | None = Field(description="State, province, canton, ...")
75-
country: str # Required for taxes
74+
state: Annotated[str | None, Field(description="State, province, canton, ...")]
75+
country: Annotated[
76+
str,
77+
Field(description="Billing country (with standardize name) required for taxes"),
78+
]
7679
postal_code: str | None
7780
phone: str | None
7881

packages/postgres-database/src/simcore_postgres_database/utils_users.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,8 +318,17 @@ async def is_email_used(
318318
return bool(pre_registered)
319319

320320
async def get_billing_details(
321-
self, connection: AsyncConnection | None = None, *, user_id: int
321+
self,
322+
connection: AsyncConnection | None = None,
323+
*,
324+
product_name: str,
325+
user_id: int,
322326
) -> Any | None:
327+
"""Returns billing details for the specified user and product.
328+
329+
- If the user is registered without a product, returns details for that registration.
330+
- Returns None if no billing details are found.
331+
"""
323332
async with pass_or_acquire_connection(self._engine, connection) as conn:
324333
result = await conn.execute(
325334
sa.select(
@@ -339,7 +348,13 @@ async def get_billing_details(
339348
users.c.id == users_pre_registration_details.c.user_id,
340349
)
341350
)
342-
.where(users.c.id == user_id)
351+
.where(
352+
(users.c.id == user_id)
353+
& (
354+
(users_pre_registration_details.c.product_name == product_name)
355+
| (users_pre_registration_details.c.product_name.is_(None))
356+
)
357+
)
343358
.order_by(users_pre_registration_details.c.created.desc())
344359
.limit(1)
345360
# NOTE: might want to copy billing details to users table??

packages/postgres-database/tests/test_users_details.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ async def test_create_and_link_user_from_pre_registration(
288288
async def test_get_billing_details_from_pre_registration(
289289
asyncpg_engine: AsyncEngine,
290290
pre_registered_user: tuple[str, dict[str, Any]],
291+
product: dict[str, Any],
291292
):
292293
"""Test that billing details can be retrieved from pre-registration data."""
293294
pre_email, fake_pre_registration_data = pre_registered_user
@@ -309,7 +310,9 @@ async def test_get_billing_details_from_pre_registration(
309310
)
310311

311312
# Get billing details
312-
invoice_data = await repo.get_billing_details(user_id=new_user.id)
313+
invoice_data = await repo.get_billing_details(
314+
user_id=new_user.id, product_name=product["name"]
315+
)
313316
assert invoice_data is not None
314317

315318
# Test UserAddress model conversion

packages/pytest-simcore/src/pytest_simcore/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def keep_docker_up(request: pytest.FixtureRequest) -> bool:
2525
return flag
2626

2727

28-
@pytest.fixture
28+
@pytest.fixture(scope="session")
2929
def is_pdb_enabled(request: pytest.FixtureRequest):
3030
"""Returns true if tests are set to use interactive debugger, i.e. --pdb"""
3131
options = request.config.option

packages/pytest-simcore/src/pytest_simcore/helpers/faker_factories.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,3 +571,32 @@ def random_itis_vip_available_download_item(
571571

572572
data.update(**overrides)
573573
return data
574+
575+
576+
def random_service_consume_filetype(
577+
*,
578+
service_key: str,
579+
service_version: str,
580+
fake: Faker = DEFAULT_FAKER,
581+
**overrides,
582+
) -> dict[str, Any]:
583+
from simcore_postgres_database.models.services_consume_filetypes import (
584+
services_consume_filetypes,
585+
)
586+
587+
data = {
588+
"service_key": service_key,
589+
"service_version": service_version,
590+
"service_display_name": fake.company(),
591+
"service_input_port": fake.word(),
592+
"filetype": fake.random_element(["CSV", "VTK", "H5", "JSON", "TXT"]),
593+
"preference_order": fake.pyint(min_value=0, max_value=10),
594+
"is_guest_allowed": fake.pybool(),
595+
}
596+
597+
assert set(data.keys()).issubset( # nosec
598+
{c.name for c in services_consume_filetypes.columns}
599+
)
600+
601+
data.update(overrides)
602+
return data

0 commit comments

Comments
 (0)