Skip to content

Commit 9775aa8

Browse files
review @pcrespov - adding back trashing
1 parent 44d43b4 commit 9775aa8

File tree

4 files changed

+122
-2
lines changed

4 files changed

+122
-2
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ class LicensedItemPatchDB(BaseModel):
8888
pricing_plan_id: PricingPlanId | None = None
8989

9090

91+
class LicensedResourcePatchDB(BaseModel):
92+
trash: bool | None = None
93+
94+
9195
class LicensedResourceDB(BaseModel):
9296
licensed_resource_id: LicensedResourceID
9397
display_name: str

services/web/server/src/simcore_service_webserver/licenses/_licensed_resources_repository.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22
from typing import Any
33

44
from aiohttp import web
5-
from models_library.licenses import LicensedResourceDB, LicensedResourceType
5+
from models_library.licenses import (
6+
LicensedResourceDB,
7+
LicensedResourceID,
8+
LicensedResourcePatchDB,
9+
LicensedResourceType,
10+
)
611
from simcore_postgres_database.models.licensed_resources import licensed_resources
712
from simcore_postgres_database.utils_repos import (
813
get_columns_from_db_model,
@@ -102,3 +107,31 @@ async def get_by_resource_identifier(
102107
licensed_resource_type=licensed_resource_type,
103108
)
104109
return LicensedResourceDB.model_validate(row)
110+
111+
112+
async def update(
113+
app: web.Application,
114+
connection: AsyncConnection | None = None,
115+
*,
116+
licensed_resource_id: LicensedResourceID,
117+
updates: LicensedResourcePatchDB,
118+
) -> LicensedResourceDB:
119+
# NOTE: at least 'touch' if updated_values is empty
120+
_updates = {
121+
**updates.model_dump(exclude_unset=True),
122+
licensed_resources.c.modified.name: func.now(),
123+
}
124+
125+
async with transaction_context(get_asyncpg_engine(app), connection) as conn:
126+
result = await conn.execute(
127+
licensed_resources.update()
128+
.values(**_updates)
129+
.where(licensed_resources.c.licensed_resource_id == licensed_resource_id)
130+
.returning(*_SELECTION_ARGS)
131+
)
132+
row = result.one_or_none()
133+
if row is None:
134+
raise LicensedResourceNotFoundError(
135+
licensed_resource_id=licensed_resource_id
136+
)
137+
return LicensedResourceDB.model_validate(row)

services/web/server/src/simcore_service_webserver/licenses/_licensed_resources_service.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@
77

88
from aiohttp import web
99
from deepdiff import DeepDiff # type: ignore[attr-defined]
10-
from models_library.licenses import LicensedResourceDB, LicensedResourceType
10+
from models_library.licenses import (
11+
LicensedResourceDB,
12+
LicensedResourceID,
13+
LicensedResourcePatchDB,
14+
LicensedResourceType,
15+
)
1116
from pydantic import BaseModel
1217

1318
from . import _licensed_resources_repository
@@ -93,3 +98,27 @@ async def register_licensed_resource(
9398
RegistrationState.NEWLY_REGISTERED,
9499
f"NEWLY_REGISTERED: {resource_key=} registered with licensed_resource_id={licensed_resource.licensed_resource_id}",
95100
)
101+
102+
103+
async def trash_licensed_resource(
104+
app: web.Application,
105+
*,
106+
licensed_resource_id: LicensedResourceID,
107+
) -> None:
108+
await _licensed_resources_repository.update(
109+
app,
110+
licensed_resource_id=licensed_resource_id,
111+
updates=LicensedResourcePatchDB(trash=True),
112+
)
113+
114+
115+
async def untrash_licensed_resource(
116+
app: web.Application,
117+
*,
118+
licensed_resource_id: LicensedResourceID,
119+
) -> None:
120+
await _licensed_resources_repository.update(
121+
app,
122+
licensed_resource_id=licensed_resource_id,
123+
updates=LicensedResourcePatchDB(trash=True),
124+
)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import arrow
2+
import pytest
3+
from aiohttp.test_utils import TestClient
4+
from models_library.licenses import (
5+
VIP_DETAILS_EXAMPLE,
6+
LicensedResourcePatchDB,
7+
LicensedResourceType,
8+
)
9+
from pytest_simcore.helpers.webserver_login import UserInfoDict
10+
from simcore_service_webserver.db.models import UserRole
11+
from simcore_service_webserver.licenses import _licensed_resources_repository
12+
from simcore_service_webserver.projects.models import ProjectDict
13+
14+
15+
@pytest.fixture
16+
def user_role() -> UserRole:
17+
return UserRole.USER
18+
19+
20+
async def test_licensed_items_db_trash(
21+
client: TestClient,
22+
logged_user: UserInfoDict,
23+
user_project: ProjectDict,
24+
osparc_product_name: str,
25+
pricing_plan_id: int,
26+
):
27+
assert client.app
28+
29+
# Create two licensed items
30+
licensed_resource_ids = []
31+
for name in ["Model A", "Model B"]:
32+
licensed_resource_db = (
33+
await _licensed_resources_repository.create_if_not_exists(
34+
client.app,
35+
display_name="Model A Display Name",
36+
licensed_resource_name=name,
37+
licensed_resource_type=LicensedResourceType.VIP_MODEL,
38+
licensed_resource_data=VIP_DETAILS_EXAMPLE,
39+
)
40+
)
41+
licensed_resource_ids.append(licensed_resource_db.licensed_resource_id)
42+
43+
# Trash one licensed item
44+
trashing_at = arrow.now().datetime
45+
trashed_item = await _licensed_resources_repository.update(
46+
client.app,
47+
licensed_resource_id=licensed_resource_ids[0],
48+
updates=LicensedResourcePatchDB(trash=True),
49+
)
50+
51+
assert trashed_item.licensed_resource_id == licensed_resource_ids[0]
52+
assert trashed_item.trashed
53+
assert trashing_at < trashed_item.trashed
54+
assert trashed_item.trashed < arrow.now().datetime

0 commit comments

Comments
 (0)