Skip to content

Commit ce96a9b

Browse files
authored
✨ Add Optional Contact Information Fields to get_profile Response (#8300)
1 parent 1ccb606 commit ce96a9b

File tree

16 files changed

+344
-27
lines changed

16 files changed

+344
-27
lines changed

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

services/web/server/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.76.0
1+
0.77.0

services/web/server/setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 0.76.0
2+
current_version = 0.77.0
33
commit = True
44
message = services/webserver api version: {current_version} → {new_version}
55
tag = False

services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ openapi: 3.1.0
22
info:
33
title: simcore-service-webserver
44
description: Main service with an interface (http-API & websockets) to the web front-end
5-
version: 0.76.0
5+
version: 0.77.0
66
servers:
77
- url: ''
88
description: webserver
@@ -13717,6 +13717,49 @@ components:
1371713717
required:
1371813718
- phone
1371913719
title: MyPhoneRegister
13720+
MyProfileAddressGet:
13721+
properties:
13722+
institution:
13723+
anyOf:
13724+
- type: string
13725+
- type: 'null'
13726+
title: Institution
13727+
address:
13728+
anyOf:
13729+
- type: string
13730+
- type: 'null'
13731+
title: Address
13732+
city:
13733+
anyOf:
13734+
- type: string
13735+
- type: 'null'
13736+
title: City
13737+
state:
13738+
anyOf:
13739+
- type: string
13740+
- type: 'null'
13741+
title: State
13742+
description: State, province, canton, ...
13743+
postalCode:
13744+
anyOf:
13745+
- type: string
13746+
- type: 'null'
13747+
title: Postalcode
13748+
country:
13749+
anyOf:
13750+
- type: string
13751+
- type: 'null'
13752+
title: Country
13753+
type: object
13754+
required:
13755+
- institution
13756+
- address
13757+
- city
13758+
- state
13759+
- postalCode
13760+
- country
13761+
title: MyProfileAddressGet
13762+
description: Details provided upon registration and used e.g. for invoicing
1372013763
MyProfilePrivacyGet:
1372113764
properties:
1372213765
hideUsername:
@@ -13822,6 +13865,10 @@ components:
1382213865
$ref: '#/components/schemas/Preference'
1382313866
type: object
1382413867
title: Preferences
13868+
contact:
13869+
anyOf:
13870+
- $ref: '#/components/schemas/MyProfileAddressGet'
13871+
- type: 'null'
1382513872
type: object
1382613873
required:
1382713874
- id

services/web/server/src/simcore_service_webserver/payments/_onetime_api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ async def init_creation_of_wallet_payment(
298298
# user info
299299
user = await users_service.get_user_display_and_id_names(app, user_id=user_id)
300300
user_invoice_address = await users_service.get_user_invoice_address(
301-
app, user_id=user_id
301+
app, user_id=user_id, product_name=product_name
302302
)
303303

304304
# stripe info
@@ -393,7 +393,7 @@ async def pay_with_payment_method(
393393
# user info
394394
user_info = await users_service.get_user_display_and_id_names(app, user_id=user_id)
395395
user_invoice_address = await users_service.get_user_invoice_address(
396-
app, user_id=user_id
396+
app, user_id=user_id, product_name=product_name
397397
)
398398

399399
settings: PaymentsSettings = get_plugin_settings(app)

services/web/server/src/simcore_service_webserver/payments/_rpc_invoice.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ async def get_invoice_data(
3131
app, product_name=product_name
3232
)
3333
user_invoice_address: UserInvoiceAddress = (
34-
await users_service.get_user_invoice_address(app, user_id=user_id)
34+
await users_service.get_user_invoice_address(
35+
app, product_name=product_name, user_id=user_id
36+
)
3537
)
3638
user_info = await users_service.get_user_display_and_id_names(app, user_id=user_id)
3739

services/web/server/src/simcore_service_webserver/studies_dispatcher/_repository.py

Whitespace-only changes.

0 commit comments

Comments
 (0)