Skip to content

Commit f93e3d0

Browse files
committed
Merge branch '1848-add-permission-rights-to-async-jobs' of github.com:bisgaard-itis/osparc-simcore into 1848-add-permission-rights-to-async-jobs
2 parents fcc1e32 + 0910137 commit f93e3d0

File tree

195 files changed

+2527
-1595
lines changed

Some content is hidden

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

195 files changed

+2527
-1595
lines changed

api/specs/web-server/_products.py

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,17 @@
77

88
from typing import Annotated
99

10-
from fastapi import APIRouter, Depends, status
10+
from fastapi import APIRouter, Depends
1111
from models_library.api_schemas_webserver.product import (
12-
GenerateInvitation,
13-
GetCreditPrice,
12+
CreditPriceGet,
13+
InvitationGenerate,
1414
InvitationGenerated,
1515
ProductGet,
1616
ProductUIGet,
17-
UpdateProductTemplate,
1817
)
1918
from models_library.generics import Envelope
2019
from simcore_service_webserver._meta import API_VTAG
21-
from simcore_service_webserver.products._handlers import (
22-
_ProductsRequestParams,
23-
_ProductTemplateParams,
24-
)
20+
from simcore_service_webserver.products._rest_schemas import ProductsRequestParams
2521

2622
router = APIRouter(
2723
prefix=f"/{API_VTAG}",
@@ -33,7 +29,7 @@
3329

3430
@router.get(
3531
"/credits-price",
36-
response_model=Envelope[GetCreditPrice],
32+
response_model=Envelope[CreditPriceGet],
3733
)
3834
async def get_current_product_price():
3935
...
@@ -47,7 +43,7 @@ async def get_current_product_price():
4743
"po",
4844
],
4945
)
50-
async def get_product(_params: Annotated[_ProductsRequestParams, Depends()]):
46+
async def get_product(_params: Annotated[ProductsRequestParams, Depends()]):
5147
...
5248

5349

@@ -59,25 +55,12 @@ async def get_current_product_ui():
5955
...
6056

6157

62-
@router.put(
63-
"/products/{product_name}/templates/{template_id}",
64-
status_code=status.HTTP_204_NO_CONTENT,
65-
tags=[
66-
"po",
67-
],
68-
)
69-
async def update_product_template(
70-
_params: Annotated[_ProductTemplateParams, Depends()], _body: UpdateProductTemplate
71-
):
72-
...
73-
74-
7558
@router.post(
7659
"/invitation:generate",
7760
response_model=Envelope[InvitationGenerated],
7861
tags=[
7962
"po",
8063
],
8164
)
82-
async def generate_invitation(_body: GenerateInvitation):
65+
async def generate_invitation(_body: InvitationGenerate):
8366
...

api/specs/web-server/_statics.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from fastapi import APIRouter
1010
from fastapi.responses import HTMLResponse
11-
from simcore_service_webserver._constants import INDEX_RESOURCE_NAME
11+
from simcore_service_webserver.constants import INDEX_RESOURCE_NAME
1212
from simcore_service_webserver.statics.settings import FrontEndInfoDict
1313

1414
router = APIRouter(

packages/models-library/src/models_library/api_schemas_resource_usage_tracker/pricing_plans.py

Lines changed: 87 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,24 @@
22
from decimal import Decimal
33
from typing import NamedTuple
44

5-
from pydantic import BaseModel, ConfigDict, PositiveInt
5+
from pydantic import BaseModel, ConfigDict, PositiveInt, model_validator
66

77
from ..resource_tracker import (
88
HardwareInfo,
99
PricingPlanClassification,
1010
PricingPlanId,
1111
PricingUnitCostId,
1212
PricingUnitId,
13-
UnitExtraInfo,
13+
UnitExtraInfoLicense,
14+
UnitExtraInfoTier,
1415
)
1516
from ..services_types import ServiceKey, ServiceVersion
1617

1718

18-
class PricingUnitGet(BaseModel):
19+
class RutPricingUnitGet(BaseModel):
1920
pricing_unit_id: PricingUnitId
2021
unit_name: str
21-
unit_extra_info: UnitExtraInfo
22+
unit_extra_info: UnitExtraInfoTier | UnitExtraInfoLicense
2223
current_cost_per_unit: Decimal
2324
current_cost_per_unit_id: PricingUnitCostId
2425
default: bool
@@ -30,30 +31,68 @@ class PricingUnitGet(BaseModel):
3031
{
3132
"pricing_unit_id": 1,
3233
"unit_name": "SMALL",
33-
"unit_extra_info": UnitExtraInfo.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
34+
"unit_extra_info": UnitExtraInfoTier.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
3435
"current_cost_per_unit": 5.7,
3536
"current_cost_per_unit_id": 1,
3637
"default": True,
37-
"specific_info": hw_config_example,
38-
}
39-
for hw_config_example in HardwareInfo.model_config["json_schema_extra"][
40-
"examples"
41-
] # type: ignore[index,union-attr]
38+
"specific_info": HardwareInfo.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
39+
},
40+
{
41+
"pricing_unit_id": 1,
42+
"unit_name": "SMALL",
43+
"unit_extra_info": UnitExtraInfoTier.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
44+
"current_cost_per_unit": 5.7,
45+
"current_cost_per_unit_id": 1,
46+
"default": True,
47+
"specific_info": HardwareInfo.model_config["json_schema_extra"]["examples"][1], # type: ignore [index]
48+
},
49+
{
50+
"pricing_unit_id": 2,
51+
"unit_name": "5 seats",
52+
"unit_extra_info": UnitExtraInfoLicense.model_config["json_schema_extra"]["examples"][0], # type: ignore [index]
53+
"current_cost_per_unit": 10.5,
54+
"current_cost_per_unit_id": 2,
55+
"default": False,
56+
"specific_info": HardwareInfo.model_config["json_schema_extra"]["examples"][1], # type: ignore [index]
57+
},
4258
]
4359
}
4460
)
4561

4662

47-
class PricingPlanGet(BaseModel):
63+
class RutPricingPlanGet(BaseModel):
4864
pricing_plan_id: PricingPlanId
4965
display_name: str
5066
description: str
5167
classification: PricingPlanClassification
5268
created_at: datetime
5369
pricing_plan_key: str
54-
pricing_units: list[PricingUnitGet] | None
70+
pricing_units: list[RutPricingUnitGet] | None
5571
is_active: bool
5672

73+
@model_validator(mode="after")
74+
def ensure_classification_matches_extra_info(self):
75+
"""Enforce that all PricingUnitGet.unit_extra_info match the plan's classification."""
76+
if not self.pricing_units:
77+
return self # No units to check
78+
79+
for unit in self.pricing_units:
80+
if (
81+
self.classification == PricingPlanClassification.TIER
82+
and not isinstance(unit.unit_extra_info, UnitExtraInfoTier)
83+
):
84+
error_message = (
85+
"For TIER classification, unit_extra_info must be UnitExtraInfoTier"
86+
)
87+
raise ValueError(error_message)
88+
if (
89+
self.classification == PricingPlanClassification.LICENSE
90+
and not isinstance(unit.unit_extra_info, UnitExtraInfoLicense)
91+
):
92+
error_message = "For LICENSE classification, unit_extra_info must be UnitExtraInfoLicense"
93+
raise ValueError(error_message)
94+
return self
95+
5796
model_config = ConfigDict(
5897
json_schema_extra={
5998
"examples": [
@@ -64,21 +103,48 @@ class PricingPlanGet(BaseModel):
64103
"classification": "TIER",
65104
"created_at": "2023-01-11 13:11:47.293595",
66105
"pricing_plan_key": "pricing-plan-sleeper",
67-
"pricing_units": [pricing_unit_get_example],
106+
"pricing_units": [
107+
RutPricingUnitGet.model_config["json_schema_extra"]["examples"][ # type: ignore [index]
108+
0 # type: ignore [index]
109+
]
110+
],
68111
"is_active": True,
69-
}
70-
for pricing_unit_get_example in PricingUnitGet.model_config[
71-
"json_schema_extra"
72-
][
73-
"examples"
74-
] # type: ignore[index,union-attr]
112+
},
113+
{
114+
"pricing_plan_id": 1,
115+
"display_name": "Pricing Plan for Sleeper",
116+
"description": "Special Pricing Plan for Sleeper",
117+
"classification": "TIER",
118+
"created_at": "2023-01-11 13:11:47.293595",
119+
"pricing_plan_key": "pricing-plan-sleeper",
120+
"pricing_units": [
121+
RutPricingUnitGet.model_config["json_schema_extra"]["examples"][ # type: ignore [index]
122+
1 # type: ignore [index]
123+
]
124+
],
125+
"is_active": True,
126+
},
127+
{
128+
"pricing_plan_id": 2,
129+
"display_name": "VIP model A",
130+
"description": "Special Pricing Plan for VIP",
131+
"classification": "LICENSE",
132+
"created_at": "2023-01-11 13:11:47.293595",
133+
"pricing_plan_key": "vip-model-a",
134+
"pricing_units": [
135+
RutPricingUnitGet.model_config["json_schema_extra"]["examples"][ # type: ignore [index]
136+
2 # type: ignore [index]
137+
]
138+
],
139+
"is_active": True,
140+
},
75141
]
76142
}
77143
)
78144

79145

80-
class PricingPlanPage(NamedTuple):
81-
items: list[PricingPlanGet]
146+
class RutPricingPlanPage(NamedTuple):
147+
items: list[RutPricingPlanGet]
82148
total: PositiveInt
83149

84150

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

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,20 @@
1919
from ._base import InputSchema, OutputSchema
2020

2121

22-
class GetCreditPrice(OutputSchema):
22+
class CreditPriceGet(OutputSchema):
2323
product_name: str
2424
usd_per_credit: Annotated[
25-
NonNegativeDecimal,
26-
PlainSerializer(float, return_type=NonNegativeFloat, when_used="json"),
27-
] | None = Field(
28-
...,
29-
description="Price of a credit in USD. "
30-
"If None, then this product's price is UNDEFINED",
31-
)
25+
Annotated[
26+
NonNegativeDecimal,
27+
PlainSerializer(float, return_type=NonNegativeFloat, when_used="json"),
28+
]
29+
| None,
30+
Field(
31+
description="Price of a credit in USD. "
32+
"If None, then this product's price is UNDEFINED",
33+
),
34+
]
35+
3236
min_payment_amount_usd: Annotated[
3337
NonNegativeInt | None,
3438
Field(
@@ -61,15 +65,11 @@ def _update_json_schema_extra(schema: JsonDict) -> None:
6165
)
6266

6367

64-
class GetProductTemplate(OutputSchema):
68+
class ProductTemplateGet(OutputSchema):
6569
id_: Annotated[IDStr, Field(alias="id")]
6670
content: str
6771

6872

69-
class UpdateProductTemplate(InputSchema):
70-
content: str
71-
72-
7373
class ProductGet(OutputSchema):
7474
name: ProductName
7575
display_name: str
@@ -92,7 +92,7 @@ class ProductGet(OutputSchema):
9292
credits_per_usd: NonNegativeDecimal | None
9393

9494
templates: Annotated[
95-
list[GetProductTemplate],
95+
list[ProductTemplateGet],
9696
Field(
9797
description="List of templates available to this product for communications (e.g. emails, sms, etc)",
9898
default_factory=list,
@@ -111,7 +111,7 @@ class ProductUIGet(OutputSchema):
111111
ExtraCreditsUsdRangeInt: TypeAlias = Annotated[int, Field(ge=0, lt=500)]
112112

113113

114-
class GenerateInvitation(InputSchema):
114+
class InvitationGenerate(InputSchema):
115115
guest: LowerCaseEmailStr
116116
trial_account_days: PositiveInt | None = None
117117
extra_credits_in_usd: ExtraCreditsUsdRangeInt | None = None

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
PricingUnitId,
1414
ServiceRunStatus,
1515
SpecificInfo,
16-
UnitExtraInfo,
16+
UnitExtraInfoLicense,
17+
UnitExtraInfoTier,
1718
)
1819
from ..services import ServiceKey, ServiceVersion
1920
from ..services_types import ServiceRunID
@@ -48,7 +49,7 @@ class ServiceRunGet(
4849
class PricingUnitGet(OutputSchema):
4950
pricing_unit_id: PricingUnitId
5051
unit_name: str
51-
unit_extra_info: UnitExtraInfo
52+
unit_extra_info: UnitExtraInfoTier | UnitExtraInfoLicense
5253
current_cost_per_unit: Decimal
5354
default: bool
5455

@@ -114,7 +115,7 @@ class UpdatePricingPlanBodyParams(InputSchema):
114115

115116
class CreatePricingUnitBodyParams(InputSchema):
116117
unit_name: str
117-
unit_extra_info: UnitExtraInfo
118+
unit_extra_info: UnitExtraInfoTier | UnitExtraInfoLicense
118119
default: bool
119120
specific_info: SpecificInfo
120121
cost_per_unit: Decimal
@@ -128,7 +129,7 @@ class CreatePricingUnitBodyParams(InputSchema):
128129

129130
class UpdatePricingUnitBodyParams(InputSchema):
130131
unit_name: str
131-
unit_extra_info: UnitExtraInfo
132+
unit_extra_info: UnitExtraInfoTier | UnitExtraInfoLicense
132133
default: bool
133134
specific_info: SpecificInfo
134135
pricing_unit_cost_update: PricingUnitCostUpdate | None = Field(default=None)

0 commit comments

Comments
 (0)