diff --git a/packages/models-library/src/models_library/api_schemas_resource_usage_tracker/licensed_items_checkouts.py b/packages/models-library/src/models_library/api_schemas_resource_usage_tracker/license_checkouts.py similarity index 66% rename from packages/models-library/src/models_library/api_schemas_resource_usage_tracker/licensed_items_checkouts.py rename to packages/models-library/src/models_library/api_schemas_resource_usage_tracker/license_checkouts.py index 0fe1df76816..82a2c4ca9c1 100644 --- a/packages/models-library/src/models_library/api_schemas_resource_usage_tracker/licensed_items_checkouts.py +++ b/packages/models-library/src/models_library/api_schemas_resource_usage_tracker/license_checkouts.py @@ -1,20 +1,18 @@ from datetime import datetime from typing import NamedTuple -from models_library.licenses import LicensedItemID +from models_library.licenses import LicenseID from models_library.products import ProductName -from models_library.resource_tracker_licensed_items_checkouts import ( - LicensedItemCheckoutID, -) +from models_library.resource_tracker_license_checkouts import LicenseCheckoutID from models_library.services_types import ServiceRunID from models_library.users import UserID from models_library.wallets import WalletID from pydantic import BaseModel, ConfigDict, PositiveInt -class LicensedItemCheckoutGet(BaseModel): - licensed_item_checkout_id: LicensedItemCheckoutID - licensed_item_id: LicensedItemID +class LicenseCheckoutGet(BaseModel): + license_checkout_id: LicenseCheckoutID + license_id: LicenseID wallet_id: WalletID user_id: UserID user_email: str @@ -28,8 +26,8 @@ class LicensedItemCheckoutGet(BaseModel): json_schema_extra={ "examples": [ { - "licensed_item_checkout_id": "beb16d18-d57d-44aa-a638-9727fa4a72ef", - "licensed_item_id": "303942ef-6d31-4ba8-afbe-dbb1fce2a953", + "license_checkout_id": "beb16d18-d57d-44aa-a638-9727fa4a72ef", + "license_id": "303942ef-6d31-4ba8-afbe-dbb1fce2a953", "wallet_id": 1, "user_id": 1, "user_email": "test@test.com", @@ -44,6 +42,6 @@ class LicensedItemCheckoutGet(BaseModel): ) -class LicensedItemsCheckoutsPage(NamedTuple): - items: list[LicensedItemCheckoutGet] +class LicenseCheckoutsPage(NamedTuple): + items: list[LicenseCheckoutGet] total: PositiveInt diff --git a/packages/models-library/src/models_library/api_schemas_resource_usage_tracker/licensed_items_purchases.py b/packages/models-library/src/models_library/api_schemas_resource_usage_tracker/license_purchases.py similarity index 77% rename from packages/models-library/src/models_library/api_schemas_resource_usage_tracker/licensed_items_purchases.py rename to packages/models-library/src/models_library/api_schemas_resource_usage_tracker/license_purchases.py index 5c8d08df5cc..9d771af52ed 100644 --- a/packages/models-library/src/models_library/api_schemas_resource_usage_tracker/licensed_items_purchases.py +++ b/packages/models-library/src/models_library/api_schemas_resource_usage_tracker/license_purchases.py @@ -2,21 +2,19 @@ from decimal import Decimal from typing import NamedTuple -from models_library.licenses import LicensedItemID +from models_library.licenses import LicenseID from models_library.products import ProductName from models_library.resource_tracker import PricingUnitCostId -from models_library.resource_tracker_licensed_items_purchases import ( - LicensedItemPurchaseID, -) +from models_library.resource_tracker_license_purchases import LicensePurchaseID from models_library.users import UserID from models_library.wallets import WalletID from pydantic import BaseModel, ConfigDict, PositiveInt -class LicensedItemPurchaseGet(BaseModel): - licensed_item_purchase_id: LicensedItemPurchaseID +class LicensePurchaseGet(BaseModel): + licensed_item_purchase_id: LicensePurchaseID product_name: ProductName - licensed_item_id: LicensedItemID + license_id: LicenseID wallet_id: WalletID wallet_name: str pricing_unit_cost_id: PricingUnitCostId @@ -35,7 +33,7 @@ class LicensedItemPurchaseGet(BaseModel): { "licensed_item_purchase_id": "beb16d18-d57d-44aa-a638-9727fa4a72ef", "product_name": "osparc", - "licensed_item_id": "303942ef-6d31-4ba8-afbe-dbb1fce2a953", + "license_id": "303942ef-6d31-4ba8-afbe-dbb1fce2a953", "wallet_id": 1, "wallet_name": "My Wallet", "pricing_unit_cost_id": 1, @@ -53,6 +51,6 @@ class LicensedItemPurchaseGet(BaseModel): ) -class LicensedItemsPurchasesPage(NamedTuple): - items: list[LicensedItemPurchaseGet] +class LicensesPurchasesPage(NamedTuple): + items: list[LicensePurchaseGet] total: PositiveInt diff --git a/packages/models-library/src/models_library/api_schemas_webserver/licensed_items_checkouts.py b/packages/models-library/src/models_library/api_schemas_webserver/licensed_items_checkouts.py index 38e6a0025f8..b0fdfd7729c 100644 --- a/packages/models-library/src/models_library/api_schemas_webserver/licensed_items_checkouts.py +++ b/packages/models-library/src/models_library/api_schemas_webserver/licensed_items_checkouts.py @@ -6,7 +6,7 @@ from ..licenses import LicensedItemID from ..products import ProductName -from ..resource_tracker_licensed_items_checkouts import LicensedItemCheckoutID +from ..resource_tracker_license_checkouts import LicenseCheckoutID from ..users import UserID from ..wallets import WalletID from ._base import OutputSchema @@ -15,7 +15,7 @@ class LicensedItemCheckoutRpcGet(BaseModel): - licensed_item_checkout_id: LicensedItemCheckoutID + licensed_item_checkout_id: LicenseCheckoutID licensed_item_id: LicensedItemID wallet_id: WalletID user_id: UserID @@ -50,7 +50,7 @@ class LicensedItemCheckoutRpcGetPage(NamedTuple): class LicensedItemCheckoutRestGet(OutputSchema): - licensed_item_checkout_id: LicensedItemCheckoutID + licensed_item_checkout_id: LicenseCheckoutID licensed_item_id: LicensedItemID wallet_id: WalletID user_id: UserID diff --git a/packages/models-library/src/models_library/api_schemas_webserver/licensed_items_purchases.py b/packages/models-library/src/models_library/api_schemas_webserver/licensed_items_purchases.py index 67f6cdd6740..7ba48aff765 100644 --- a/packages/models-library/src/models_library/api_schemas_webserver/licensed_items_purchases.py +++ b/packages/models-library/src/models_library/api_schemas_webserver/licensed_items_purchases.py @@ -8,14 +8,14 @@ from ..licenses import LicensedItemID from ..products import ProductName from ..resource_tracker import PricingUnitCostId -from ..resource_tracker_licensed_items_purchases import LicensedItemPurchaseID +from ..resource_tracker_license_purchases import LicensePurchaseID from ..users import UserID from ..wallets import WalletID from ._base import OutputSchema class LicensedItemPurchaseGet(OutputSchema): - licensed_item_purchase_id: LicensedItemPurchaseID + licensed_item_purchase_id: LicensePurchaseID product_name: ProductName licensed_item_id: LicensedItemID wallet_id: WalletID diff --git a/packages/models-library/src/models_library/licenses.py b/packages/models-library/src/models_library/licenses.py index 16f162fad85..8a9232be7f5 100644 --- a/packages/models-library/src/models_library/licenses.py +++ b/packages/models-library/src/models_library/licenses.py @@ -13,6 +13,8 @@ from .utils.enums import StrAutoEnum LicensedItemID: TypeAlias = UUID +LicenseID: TypeAlias = UUID +LicensedResourceID: TypeAlias = UUID class LicensedResourceType(StrAutoEnum): diff --git a/packages/models-library/src/models_library/resource_tracker_licensed_items_checkouts.py b/packages/models-library/src/models_library/resource_tracker_license_checkouts.py similarity index 55% rename from packages/models-library/src/models_library/resource_tracker_licensed_items_checkouts.py rename to packages/models-library/src/models_library/resource_tracker_license_checkouts.py index cd09440b822..7ae53ee5139 100644 --- a/packages/models-library/src/models_library/resource_tracker_licensed_items_checkouts.py +++ b/packages/models-library/src/models_library/resource_tracker_license_checkouts.py @@ -1,4 +1,4 @@ from typing import TypeAlias from uuid import UUID -LicensedItemCheckoutID: TypeAlias = UUID +LicenseCheckoutID: TypeAlias = UUID diff --git a/packages/models-library/src/models_library/resource_tracker_licensed_items_purchases.py b/packages/models-library/src/models_library/resource_tracker_license_purchases.py similarity index 82% rename from packages/models-library/src/models_library/resource_tracker_licensed_items_purchases.py rename to packages/models-library/src/models_library/resource_tracker_license_purchases.py index bc0eecfa381..57f94eed84c 100644 --- a/packages/models-library/src/models_library/resource_tracker_licensed_items_purchases.py +++ b/packages/models-library/src/models_library/resource_tracker_license_purchases.py @@ -5,18 +5,18 @@ from pydantic import BaseModel, ConfigDict -from .licenses import LicensedItemID +from .licenses import LicenseID from .products import ProductName from .resource_tracker import PricingPlanId, PricingUnitCostId, PricingUnitId from .users import UserID from .wallets import WalletID -LicensedItemPurchaseID: TypeAlias = UUID +LicensePurchaseID: TypeAlias = UUID -class LicensedItemsPurchasesCreate(BaseModel): +class LicensePurchasesCreate(BaseModel): product_name: ProductName - licensed_item_id: LicensedItemID + license_id: LicenseID wallet_id: WalletID wallet_name: str pricing_plan_id: PricingPlanId diff --git a/packages/models-library/tests/test_licenses.py b/packages/models-library/tests/test_licenses.py index 19c00efa715..81a2f9ce5ac 100644 --- a/packages/models-library/tests/test_licenses.py +++ b/packages/models-library/tests/test_licenses.py @@ -1,13 +1,13 @@ -from models_library.api_schemas_webserver.licensed_items import LicensedItemRestGet -from models_library.licenses import LicensedItem +from models_library.api_schemas_webserver.licensed_items import LicenseRestGet +from models_library.licenses import LicensedResource from pydantic import ConfigDict def test_licensed_item_from_domain_model(): - for example in LicensedItem.model_json_schema()["examples"]: - item = LicensedItem.model_validate(example) + for example in LicensedResource.model_json_schema()["examples"]: + item = LicensedResource.model_validate(example) - got = LicensedItemRestGet.from_domain_model(item) + got = LicenseRestGet.from_domain_model(item) assert item.display_name == got.display_name @@ -31,8 +31,8 @@ def test_licensed_item_from_domain_model(): def test_strict_check_of_examples(): - class TestLicensedItemRestGet(LicensedItemRestGet): + class TestLicenseRestGet(LicenseRestGet): model_config = ConfigDict(extra="forbid") - for example in LicensedItemRestGet.model_json_schema()["examples"]: - TestLicensedItemRestGet.model_validate(example) + for example in LicenseRestGet.model_json_schema()["examples"]: + TestLicenseRestGet.model_validate(example) diff --git a/packages/postgres-database/src/simcore_postgres_database/migration/versions/eb74758a8761_add_licenses_and_license_resources.py b/packages/postgres-database/src/simcore_postgres_database/migration/versions/eb74758a8761_add_licenses_and_license_resources.py new file mode 100644 index 00000000000..5919495edb5 --- /dev/null +++ b/packages/postgres-database/src/simcore_postgres_database/migration/versions/eb74758a8761_add_licenses_and_license_resources.py @@ -0,0 +1,364 @@ +"""add licenses and license resources + +Revision ID: eb74758a8761 +Revises: e71ea59858f4 +Create Date: 2025-02-07 15:59:49.201845+00:00 + +""" +import sqlalchemy as sa +from alembic import op +from sqlalchemy.dialects import postgresql + +# revision identifiers, used by Alembic. +revision = "eb74758a8761" +down_revision = "e71ea59858f4" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "licensed_resources", + sa.Column( + "licensed_resource_id", + postgresql.UUID(as_uuid=True), + server_default=sa.text("gen_random_uuid()"), + nullable=False, + ), + sa.Column("display_name", sa.String(), nullable=False), + sa.Column("licensed_resource_name", sa.String(), nullable=False), + sa.Column( + "licensed_resource_type", + sa.Enum("VIP_MODEL", name="licensedresourcetype"), + nullable=False, + ), + sa.Column( + "licensed_resource_data", + postgresql.JSONB(astext_type=sa.Text()), + nullable=True, + ), + sa.Column( + "created", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=False, + ), + sa.Column( + "modified", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=False, + ), + sa.Column( + "trashed", + sa.DateTime(timezone=True), + nullable=True, + comment="The date and time when the licensed_item was marked as trashed. Null if the licensed_item has not been trashed [default].", + ), + sa.PrimaryKeyConstraint("licensed_resource_id"), + sa.UniqueConstraint( + "licensed_resource_name", + "licensed_resource_type", + name="uq_licensed_resource_name_type2", + ), + ) + op.create_table( + "resource_tracker_license_purchases", + sa.Column( + "licensed_item_purchase_id", + postgresql.UUID(as_uuid=True), + server_default=sa.text("gen_random_uuid()"), + nullable=False, + ), + sa.Column("product_name", sa.String(), nullable=False), + sa.Column("license_id", postgresql.UUID(as_uuid=True), nullable=False), + sa.Column("wallet_id", sa.BigInteger(), nullable=False), + sa.Column("wallet_name", sa.String(), nullable=False), + sa.Column("pricing_unit_cost_id", sa.BigInteger(), nullable=False), + sa.Column("pricing_unit_cost", sa.Numeric(scale=2), nullable=True), + sa.Column( + "start_at", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=False, + ), + sa.Column( + "expire_at", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=False, + ), + sa.Column("num_of_seats", sa.SmallInteger(), nullable=False), + sa.Column("purchased_by_user", sa.BigInteger(), nullable=False), + sa.Column("user_email", sa.String(), nullable=True), + sa.Column( + "purchased_at", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=False, + ), + sa.Column( + "modified", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=False, + ), + sa.PrimaryKeyConstraint("licensed_item_purchase_id"), + ) + op.create_table( + "resource_tracker_license_checkouts", + sa.Column( + "license_checkout_id", + postgresql.UUID(as_uuid=True), + server_default=sa.text("gen_random_uuid()"), + nullable=False, + ), + sa.Column("license_id", postgresql.UUID(as_uuid=True), nullable=True), + sa.Column("wallet_id", sa.BigInteger(), nullable=False), + sa.Column("user_id", sa.BigInteger(), nullable=False), + sa.Column("user_email", sa.String(), nullable=True), + sa.Column("product_name", sa.String(), nullable=False), + sa.Column("service_run_id", sa.String(), nullable=True), + sa.Column("started_at", sa.DateTime(timezone=True), nullable=False), + sa.Column("stopped_at", sa.DateTime(timezone=True), nullable=True), + sa.Column("num_of_seats", sa.SmallInteger(), nullable=False), + sa.Column( + "modified", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=False, + ), + sa.ForeignKeyConstraint( + ["product_name", "service_run_id"], + [ + "resource_tracker_service_runs.product_name", + "resource_tracker_service_runs.service_run_id", + ], + name="resource_tracker_license_checkouts_service_run_id_fkey", + onupdate="CASCADE", + ondelete="RESTRICT", + ), + sa.PrimaryKeyConstraint("license_checkout_id"), + ) + op.create_index( + op.f("ix_resource_tracker_license_checkouts_wallet_id"), + "resource_tracker_license_checkouts", + ["wallet_id"], + unique=False, + ) + op.create_table( + "licenses", + sa.Column( + "license_id", + postgresql.UUID(as_uuid=True), + server_default=sa.text("gen_random_uuid()"), + nullable=False, + ), + sa.Column("display_name", sa.String(), nullable=False), + sa.Column( + "licensed_resource_type", + sa.Enum("VIP_MODEL", name="licensedresourcetype"), + nullable=False, + ), + sa.Column("pricing_plan_id", sa.BigInteger(), nullable=False), + sa.Column("product_name", sa.String(), nullable=False), + sa.Column( + "created", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=False, + ), + sa.Column( + "modified", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=False, + ), + sa.ForeignKeyConstraint( + ["pricing_plan_id"], + ["resource_tracker_pricing_plans.pricing_plan_id"], + name="fk_resource_tracker_license_packages_pricing_plan_id", + onupdate="CASCADE", + ondelete="RESTRICT", + ), + sa.ForeignKeyConstraint( + ["product_name"], + ["products.name"], + name="fk_resource_tracker_license_packages_product_name", + onupdate="CASCADE", + ondelete="CASCADE", + ), + sa.PrimaryKeyConstraint("license_id"), + ) + op.create_table( + "license_to_resource", + sa.Column("license_id", postgresql.UUID(as_uuid=True), nullable=False), + sa.Column( + "licensed_resource_id", postgresql.UUID(as_uuid=True), nullable=False + ), + sa.Column( + "created", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=False, + ), + sa.Column( + "modified", + sa.DateTime(timezone=True), + server_default=sa.text("now()"), + nullable=False, + ), + sa.ForeignKeyConstraint( + ["license_id"], + ["licenses.license_id"], + name="fk_license_to_resource_license_id", + onupdate="CASCADE", + ondelete="CASCADE", + ), + sa.ForeignKeyConstraint( + ["licensed_resource_id"], + ["licensed_resources.licensed_resource_id"], + name="fk_license_to_resource_licensed_resource_id", + onupdate="CASCADE", + ondelete="CASCADE", + ), + ) + op.drop_table("resource_tracker_licensed_items_purchases") + op.drop_index( + "ix_resource_tracker_licensed_items_checkouts_wallet_id", + table_name="resource_tracker_licensed_items_checkouts", + ) + op.drop_table("resource_tracker_licensed_items_checkouts") + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table( + "resource_tracker_licensed_items_checkouts", + sa.Column( + "licensed_item_checkout_id", + postgresql.UUID(), + server_default=sa.text("gen_random_uuid()"), + autoincrement=False, + nullable=False, + ), + sa.Column( + "licensed_item_id", postgresql.UUID(), autoincrement=False, nullable=True + ), + sa.Column("wallet_id", sa.BIGINT(), autoincrement=False, nullable=False), + sa.Column("user_id", sa.BIGINT(), autoincrement=False, nullable=False), + sa.Column("user_email", sa.VARCHAR(), autoincrement=False, nullable=True), + sa.Column("product_name", sa.VARCHAR(), autoincrement=False, nullable=False), + sa.Column("service_run_id", sa.VARCHAR(), autoincrement=False, nullable=True), + sa.Column( + "started_at", + postgresql.TIMESTAMP(timezone=True), + autoincrement=False, + nullable=False, + ), + sa.Column( + "stopped_at", + postgresql.TIMESTAMP(timezone=True), + autoincrement=False, + nullable=True, + ), + sa.Column("num_of_seats", sa.SMALLINT(), autoincrement=False, nullable=False), + sa.Column( + "modified", + postgresql.TIMESTAMP(timezone=True), + server_default=sa.text("now()"), + autoincrement=False, + nullable=False, + ), + sa.ForeignKeyConstraint( + ["product_name", "service_run_id"], + [ + "resource_tracker_service_runs.product_name", + "resource_tracker_service_runs.service_run_id", + ], + name="resource_tracker_license_checkouts_service_run_id_fkey", + onupdate="CASCADE", + ondelete="RESTRICT", + ), + sa.PrimaryKeyConstraint( + "licensed_item_checkout_id", + name="resource_tracker_licensed_items_checkouts_pkey", + ), + ) + op.create_index( + "ix_resource_tracker_licensed_items_checkouts_wallet_id", + "resource_tracker_licensed_items_checkouts", + ["wallet_id"], + unique=False, + ) + op.create_table( + "resource_tracker_licensed_items_purchases", + sa.Column( + "licensed_item_purchase_id", + postgresql.UUID(), + server_default=sa.text("gen_random_uuid()"), + autoincrement=False, + nullable=False, + ), + sa.Column("product_name", sa.VARCHAR(), autoincrement=False, nullable=False), + sa.Column("wallet_id", sa.BIGINT(), autoincrement=False, nullable=False), + sa.Column( + "start_at", + postgresql.TIMESTAMP(timezone=True), + server_default=sa.text("now()"), + autoincrement=False, + nullable=False, + ), + sa.Column( + "expire_at", + postgresql.TIMESTAMP(timezone=True), + server_default=sa.text("now()"), + autoincrement=False, + nullable=False, + ), + sa.Column( + "purchased_by_user", sa.BIGINT(), autoincrement=False, nullable=False + ), + sa.Column( + "purchased_at", + postgresql.TIMESTAMP(timezone=True), + server_default=sa.text("now()"), + autoincrement=False, + nullable=False, + ), + sa.Column( + "modified", + postgresql.TIMESTAMP(timezone=True), + server_default=sa.text("now()"), + autoincrement=False, + nullable=False, + ), + sa.Column("wallet_name", sa.VARCHAR(), autoincrement=False, nullable=False), + sa.Column( + "pricing_unit_cost_id", sa.BIGINT(), autoincrement=False, nullable=False + ), + sa.Column( + "pricing_unit_cost", sa.NUMERIC(), autoincrement=False, nullable=True + ), + sa.Column("num_of_seats", sa.SMALLINT(), autoincrement=False, nullable=False), + sa.Column( + "licensed_item_id", postgresql.UUID(), autoincrement=False, nullable=False + ), + sa.Column("user_email", sa.VARCHAR(), autoincrement=False, nullable=True), + sa.PrimaryKeyConstraint( + "licensed_item_purchase_id", + name="resource_tracker_licensed_items_purchases_pkey", + ), + ) + op.drop_table("license_to_resource") + op.drop_table("licenses") + op.drop_index( + op.f("ix_resource_tracker_license_checkouts_wallet_id"), + table_name="resource_tracker_license_checkouts", + ) + op.drop_table("resource_tracker_license_checkouts") + op.drop_table("resource_tracker_license_purchases") + op.drop_table("licensed_resources") + # ### end Alembic commands ### diff --git a/packages/postgres-database/src/simcore_postgres_database/models/license_to_resource.py b/packages/postgres-database/src/simcore_postgres_database/models/license_to_resource.py new file mode 100644 index 00000000000..9106742a66f --- /dev/null +++ b/packages/postgres-database/src/simcore_postgres_database/models/license_to_resource.py @@ -0,0 +1,34 @@ +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +from ._common import RefActions, column_created_datetime, column_modified_datetime +from .base import metadata + +license_to_resource = sa.Table( + "license_to_resource", + metadata, + sa.Column( + "license_id", + postgresql.UUID(as_uuid=True), + sa.ForeignKey( + "licenses.license_id", + name="fk_license_to_resource_license_id", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, + ), + nullable=False, + ), + sa.Column( + "licensed_resource_id", # <-- This will be renamed to "licensed_resource_id" + postgresql.UUID(as_uuid=True), + sa.ForeignKey( + "licensed_resources.licensed_resource_id", # <-- This will be renamed to "licensed_resource_id" + name="fk_license_to_resource_licensed_resource_id", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, + ), + nullable=False, + ), + column_created_datetime(timezone=True), + column_modified_datetime(timezone=True), +) diff --git a/packages/postgres-database/src/simcore_postgres_database/models/licensed_items.py b/packages/postgres-database/src/simcore_postgres_database/models/licensed_items.py index f625a2d1be6..71859bbb508 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/licensed_items.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/licensed_items.py @@ -1,7 +1,6 @@ """ resource_tracker_service_runs table """ -import enum import sqlalchemy as sa from sqlalchemy.dialects import postgresql @@ -13,11 +12,7 @@ column_trashed_datetime, ) from .base import metadata - - -class LicensedResourceType(str, enum.Enum): - VIP_MODEL = "VIP_MODEL" - +from .licenses import LicensedResourceType licensed_items = sa.Table( "licensed_items", diff --git a/packages/postgres-database/src/simcore_postgres_database/models/licensed_resources.py b/packages/postgres-database/src/simcore_postgres_database/models/licensed_resources.py new file mode 100644 index 00000000000..a9c20740e56 --- /dev/null +++ b/packages/postgres-database/src/simcore_postgres_database/models/licensed_resources.py @@ -0,0 +1,58 @@ +""" resource_tracker_service_runs table +""" + + +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +from ._common import ( + column_created_datetime, + column_modified_datetime, + column_trashed_datetime, +) +from .base import metadata +from .licenses import LicensedResourceType + +licensed_resources = sa.Table( + "licensed_resources", + metadata, + sa.Column( + "licensed_resource_id", + postgresql.UUID(as_uuid=True), + nullable=False, + primary_key=True, + server_default=sa.text("gen_random_uuid()"), + ), + sa.Column( + "display_name", + sa.String, + nullable=False, + doc="Display name for front-end", + ), + sa.Column( + "licensed_resource_name", + sa.String, + nullable=False, + doc="Resource name identifier", + ), + sa.Column( + "licensed_resource_type", + sa.Enum(LicensedResourceType), + nullable=False, + doc="Resource type, ex. VIP_MODEL", + ), + sa.Column( + "licensed_resource_data", + postgresql.JSONB, + nullable=True, + doc="Resource metadata. Used for read-only purposes", + ), + column_created_datetime(timezone=True), + column_modified_datetime(timezone=True), + column_trashed_datetime("licensed_item"), + sa.UniqueConstraint( + "licensed_resource_name", + "licensed_resource_type", + name="uq_licensed_resource_name_type2", + ), +) diff --git a/packages/postgres-database/src/simcore_postgres_database/models/licenses.py b/packages/postgres-database/src/simcore_postgres_database/models/licenses.py new file mode 100644 index 00000000000..14af962dc09 --- /dev/null +++ b/packages/postgres-database/src/simcore_postgres_database/models/licenses.py @@ -0,0 +1,60 @@ +import enum + +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +from ._common import RefActions, column_created_datetime, column_modified_datetime +from .base import metadata + + +class LicensedResourceType(str, enum.Enum): + VIP_MODEL = "VIP_MODEL" + + +licenses = sa.Table( + "licenses", + metadata, + sa.Column( + "license_id", + postgresql.UUID(as_uuid=True), + nullable=False, + primary_key=True, + server_default=sa.text("gen_random_uuid()"), + ), + sa.Column( + "display_name", + sa.String, + nullable=False, + doc="Display name for front-end", + ), + sa.Column( + "licensed_resource_type", + sa.Enum(LicensedResourceType), + nullable=False, + doc="Resource type, ex. VIP_MODEL", + ), + sa.Column( + "pricing_plan_id", + sa.BigInteger, + sa.ForeignKey( + "resource_tracker_pricing_plans.pricing_plan_id", + name="fk_resource_tracker_license_packages_pricing_plan_id", + onupdate=RefActions.CASCADE, + ondelete=RefActions.RESTRICT, + ), + nullable=False, + ), + sa.Column( + "product_name", + sa.String, + sa.ForeignKey( + "products.name", + onupdate=RefActions.CASCADE, + ondelete=RefActions.CASCADE, + name="fk_resource_tracker_license_packages_product_name", + ), + nullable=False, + ), + column_created_datetime(timezone=True), + column_modified_datetime(timezone=True), +) diff --git a/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_licensed_items_checkouts.py b/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_license_checkouts.py similarity index 91% rename from packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_licensed_items_checkouts.py rename to packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_license_checkouts.py index e3cabb899f7..1733e1f3452 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_licensed_items_checkouts.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_license_checkouts.py @@ -7,18 +7,18 @@ from ._common import RefActions, column_modified_datetime from .base import metadata -resource_tracker_licensed_items_checkouts = sa.Table( - "resource_tracker_licensed_items_checkouts", +resource_tracker_license_checkouts = sa.Table( + "resource_tracker_license_checkouts", metadata, sa.Column( - "licensed_item_checkout_id", + "license_checkout_id", UUID(as_uuid=True), nullable=False, primary_key=True, server_default=sa.text("gen_random_uuid()"), ), sa.Column( - "licensed_item_id", + "license_id", UUID(as_uuid=True), nullable=True, ), diff --git a/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_licensed_items_purchases.py b/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_license_purchases.py similarity index 93% rename from packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_licensed_items_purchases.py rename to packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_license_purchases.py index 51944f7089e..34866cb9015 100644 --- a/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_licensed_items_purchases.py +++ b/packages/postgres-database/src/simcore_postgres_database/models/resource_tracker_license_purchases.py @@ -8,8 +8,8 @@ from ._common import NUMERIC_KWARGS, column_modified_datetime from .base import metadata -resource_tracker_licensed_items_purchases = sa.Table( - "resource_tracker_licensed_items_purchases", +resource_tracker_license_purchases = sa.Table( + "resource_tracker_license_purchases", metadata, sa.Column( "licensed_item_purchase_id", @@ -25,7 +25,7 @@ doc="Product name", ), sa.Column( - "licensed_item_id", + "license_id", UUID(as_uuid=True), nullable=False, ), diff --git a/packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/resource_usage_tracker/errors.py b/packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/resource_usage_tracker/errors.py index 4e24b323edc..9f6f8251b27 100644 --- a/packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/resource_usage_tracker/errors.py +++ b/packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/resource_usage_tracker/errors.py @@ -10,22 +10,22 @@ class NotEnoughAvailableSeatsError(LicensesBaseError): class CanNotCheckoutNotEnoughAvailableSeatsError(LicensesBaseError): - msg_template = "Can not checkout license item {licensed_item_id} with num of seats {num_of_seats}. Currently available seats {available_num_of_seats}" + msg_template = "Can not checkout license item {license_id} with num of seats {num_of_seats}. Currently available seats {available_num_of_seats}" class CanNotCheckoutServiceIsNotRunningError(LicensesBaseError): - msg_template = "Can not checkout license item {licensed_item_id} as dynamic service is not running. Current service {service_run}" + msg_template = "Can not checkout license item {license_id} as dynamic service is not running. Current service {service_run}" -class LicensedItemCheckoutNotFoundError(LicensesBaseError): - msg_template = "Licensed item checkout {licensed_item_checkout_id} not found." +class LicenseCheckoutNotFoundError(LicensesBaseError): + msg_template = "Licensed item checkout {license_checkout_id} not found." LICENSES_ERRORS = ( NotEnoughAvailableSeatsError, CanNotCheckoutNotEnoughAvailableSeatsError, CanNotCheckoutServiceIsNotRunningError, - LicensedItemCheckoutNotFoundError, + LicenseCheckoutNotFoundError, ) diff --git a/packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/resource_usage_tracker/licensed_items_checkouts.py b/packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/resource_usage_tracker/license_checkouts.py similarity index 64% rename from packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/resource_usage_tracker/licensed_items_checkouts.py rename to packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/resource_usage_tracker/license_checkouts.py index e6d43c47caf..657802a9d61 100644 --- a/packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/resource_usage_tracker/licensed_items_checkouts.py +++ b/packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/resource_usage_tracker/license_checkouts.py @@ -4,17 +4,15 @@ from models_library.api_schemas_resource_usage_tracker import ( RESOURCE_USAGE_TRACKER_RPC_NAMESPACE, ) -from models_library.api_schemas_resource_usage_tracker.licensed_items_checkouts import ( - LicensedItemCheckoutGet, - LicensedItemsCheckoutsPage, +from models_library.api_schemas_resource_usage_tracker.license_checkouts import ( + LicenseCheckoutGet, + LicenseCheckoutsPage, ) from models_library.basic_types import IDStr -from models_library.licenses import LicensedItemID +from models_library.licenses import LicenseID from models_library.products import ProductName from models_library.rabbitmq_basic_types import RPCMethodName -from models_library.resource_tracker_licensed_items_checkouts import ( - LicensedItemCheckoutID, -) +from models_library.resource_tracker_license_checkouts import LicenseCheckoutID from models_library.rest_ordering import OrderBy from models_library.services_types import ServiceRunID from models_library.users import UserID @@ -33,25 +31,25 @@ @log_decorator(_logger, level=logging.DEBUG) -async def get_licensed_item_checkout( +async def get_license_checkout( rabbitmq_rpc_client: RabbitMQRPCClient, *, product_name: ProductName, - licensed_item_checkout_id: LicensedItemCheckoutID, -) -> LicensedItemCheckoutGet: + license_checkout_id: LicenseCheckoutID, +) -> LicenseCheckoutGet: result = await rabbitmq_rpc_client.request( RESOURCE_USAGE_TRACKER_RPC_NAMESPACE, - _RPC_METHOD_NAME_ADAPTER.validate_python("get_licensed_item_checkout"), + _RPC_METHOD_NAME_ADAPTER.validate_python("get_license_checkout"), product_name=product_name, - licensed_item_checkout_id=licensed_item_checkout_id, + license_checkout_id=license_checkout_id, timeout_s=_DEFAULT_TIMEOUT_S, ) - assert isinstance(result, LicensedItemCheckoutGet) # nosec + assert isinstance(result, LicenseCheckoutGet) # nosec return result @log_decorator(_logger, level=logging.DEBUG) -async def get_licensed_items_checkouts_page( +async def get_license_checkouts_page( rabbitmq_rpc_client: RabbitMQRPCClient, *, product_name: ProductName, @@ -59,7 +57,7 @@ async def get_licensed_items_checkouts_page( offset: int = 0, limit: int = 20, order_by: OrderBy | None = None, -) -> LicensedItemsCheckoutsPage: +) -> LicenseCheckoutsPage: """ Default order_by field is "started_at" """ @@ -68,7 +66,7 @@ async def get_licensed_items_checkouts_page( result = await rabbitmq_rpc_client.request( RESOURCE_USAGE_TRACKER_RPC_NAMESPACE, - _RPC_METHOD_NAME_ADAPTER.validate_python("get_licensed_items_checkouts_page"), + _RPC_METHOD_NAME_ADAPTER.validate_python("get_license_checkouts_page"), product_name=product_name, filter_wallet_id=filter_wallet_id, limit=limit, @@ -76,26 +74,26 @@ async def get_licensed_items_checkouts_page( order_by=order_by, timeout_s=_DEFAULT_TIMEOUT_S, ) - assert isinstance(result, LicensedItemsCheckoutsPage) # nosec + assert isinstance(result, LicenseCheckoutsPage) # nosec return result @log_decorator(_logger, level=logging.DEBUG) -async def checkout_licensed_item( +async def checkout_license( rabbitmq_rpc_client: RabbitMQRPCClient, *, - licensed_item_id: LicensedItemID, + license_id: LicenseID, wallet_id: WalletID, product_name: ProductName, num_of_seats: int, service_run_id: ServiceRunID, user_id: UserID, user_email: str, -) -> LicensedItemCheckoutGet: - result: LicensedItemCheckoutGet = await rabbitmq_rpc_client.request( +) -> LicenseCheckoutGet: + result: LicenseCheckoutGet = await rabbitmq_rpc_client.request( RESOURCE_USAGE_TRACKER_RPC_NAMESPACE, - _RPC_METHOD_NAME_ADAPTER.validate_python("checkout_licensed_item"), - licensed_item_id=licensed_item_id, + _RPC_METHOD_NAME_ADAPTER.validate_python("checkout_license"), + license_id=license_id, wallet_id=wallet_id, product_name=product_name, num_of_seats=num_of_seats, @@ -104,23 +102,23 @@ async def checkout_licensed_item( user_email=user_email, timeout_s=_DEFAULT_TIMEOUT_S, ) - assert isinstance(result, LicensedItemCheckoutGet) # nosec + assert isinstance(result, LicenseCheckoutGet) # nosec return result @log_decorator(_logger, level=logging.DEBUG) -async def release_licensed_item( +async def release_license( rabbitmq_rpc_client: RabbitMQRPCClient, *, - licensed_item_checkout_id: LicensedItemCheckoutID, + license_checkout_id: LicenseCheckoutID, product_name: ProductName, -) -> LicensedItemCheckoutGet: - result: LicensedItemCheckoutGet = await rabbitmq_rpc_client.request( +) -> LicenseCheckoutGet: + result: LicenseCheckoutGet = await rabbitmq_rpc_client.request( RESOURCE_USAGE_TRACKER_RPC_NAMESPACE, - _RPC_METHOD_NAME_ADAPTER.validate_python("release_licensed_item"), - licensed_item_checkout_id=licensed_item_checkout_id, + _RPC_METHOD_NAME_ADAPTER.validate_python("release_license"), + license_checkout_id=license_checkout_id, product_name=product_name, timeout_s=_DEFAULT_TIMEOUT_S, ) - assert isinstance(result, LicensedItemCheckoutGet) # nosec + assert isinstance(result, LicenseCheckoutGet) # nosec return result diff --git a/packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/resource_usage_tracker/licensed_items_purchases.py b/packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/resource_usage_tracker/license_purchases.py similarity index 65% rename from packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/resource_usage_tracker/licensed_items_purchases.py rename to packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/resource_usage_tracker/license_purchases.py index 125dbe655a0..fccf80eba01 100644 --- a/packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/resource_usage_tracker/licensed_items_purchases.py +++ b/packages/service-library/src/servicelib/rabbitmq/rpc_interfaces/resource_usage_tracker/license_purchases.py @@ -4,23 +4,23 @@ from models_library.api_schemas_resource_usage_tracker import ( RESOURCE_USAGE_TRACKER_RPC_NAMESPACE, ) -from models_library.api_schemas_resource_usage_tracker.licensed_items_purchases import ( - LicensedItemPurchaseGet, - LicensedItemsPurchasesPage, +from models_library.api_schemas_resource_usage_tracker.license_purchases import ( + LicensePurchaseGet, + LicensesPurchasesPage, ) from models_library.basic_types import IDStr from models_library.products import ProductName from models_library.rabbitmq_basic_types import RPCMethodName -from models_library.resource_tracker_licensed_items_purchases import ( - LicensedItemPurchaseID, - LicensedItemsPurchasesCreate, +from models_library.resource_tracker_license_purchases import ( + LicensePurchaseID, + LicensePurchasesCreate, ) from models_library.rest_ordering import OrderBy from models_library.wallets import WalletID from pydantic import NonNegativeInt, TypeAdapter from ....logging_utils import log_decorator -from ....rabbitmq import RabbitMQRPCClient +from ... import RabbitMQRPCClient _logger = logging.getLogger(__name__) @@ -31,7 +31,7 @@ @log_decorator(_logger, level=logging.DEBUG) -async def get_licensed_items_purchases_page( +async def get_license_purchases_page( rabbitmq_rpc_client: RabbitMQRPCClient, *, product_name: ProductName, @@ -39,7 +39,7 @@ async def get_licensed_items_purchases_page( offset: int = 0, limit: int = 20, order_by: OrderBy | None = None, -) -> LicensedItemsPurchasesPage: +) -> LicensesPurchasesPage: """ Default order_by field is "purchased_at" """ @@ -48,7 +48,7 @@ async def get_licensed_items_purchases_page( result = await rabbitmq_rpc_client.request( RESOURCE_USAGE_TRACKER_RPC_NAMESPACE, - _RPC_METHOD_NAME_ADAPTER.validate_python("get_licensed_items_purchases_page"), + _RPC_METHOD_NAME_ADAPTER.validate_python("get_license_purchases_page"), product_name=product_name, wallet_id=wallet_id, limit=limit, @@ -56,37 +56,37 @@ async def get_licensed_items_purchases_page( order_by=order_by, timeout_s=_DEFAULT_TIMEOUT_S, ) - assert isinstance(result, LicensedItemsPurchasesPage) # nosec + assert isinstance(result, LicensesPurchasesPage) # nosec return result @log_decorator(_logger, level=logging.DEBUG) -async def get_licensed_item_purchase( +async def get_license_purchase( rabbitmq_rpc_client: RabbitMQRPCClient, *, product_name: ProductName, - licensed_item_purchase_id: LicensedItemPurchaseID, -) -> LicensedItemPurchaseGet: + licensed_item_purchase_id: LicensePurchaseID, +) -> LicensePurchaseGet: result = await rabbitmq_rpc_client.request( RESOURCE_USAGE_TRACKER_RPC_NAMESPACE, - _RPC_METHOD_NAME_ADAPTER.validate_python("get_licensed_item_purchase"), + _RPC_METHOD_NAME_ADAPTER.validate_python("get_license_purchase"), product_name=product_name, licensed_item_purchase_id=licensed_item_purchase_id, timeout_s=_DEFAULT_TIMEOUT_S, ) - assert isinstance(result, LicensedItemPurchaseGet) # nosec + assert isinstance(result, LicensePurchaseGet) # nosec return result @log_decorator(_logger, level=logging.DEBUG) -async def create_licensed_item_purchase( - rabbitmq_rpc_client: RabbitMQRPCClient, *, data: LicensedItemsPurchasesCreate -) -> LicensedItemPurchaseGet: +async def create_license_purchase( + rabbitmq_rpc_client: RabbitMQRPCClient, *, data: LicensePurchasesCreate +) -> LicensePurchaseGet: result = await rabbitmq_rpc_client.request( RESOURCE_USAGE_TRACKER_RPC_NAMESPACE, - _RPC_METHOD_NAME_ADAPTER.validate_python("create_licensed_item_purchase"), + _RPC_METHOD_NAME_ADAPTER.validate_python("create_license_purchase"), data=data, timeout_s=_DEFAULT_TIMEOUT_S, ) - assert isinstance(result, LicensedItemPurchaseGet) # nosec + assert isinstance(result, LicensePurchaseGet) # nosec return result diff --git a/services/api-server/src/simcore_service_api_server/api/routes/licensed_items.py b/services/api-server/src/simcore_service_api_server/api/routes/licensed_items.py index 39d5dbc4394..a97f6033f03 100644 --- a/services/api-server/src/simcore_service_api_server/api/routes/licensed_items.py +++ b/services/api-server/src/simcore_service_api_server/api/routes/licensed_items.py @@ -2,9 +2,7 @@ from fastapi import APIRouter, Depends, HTTPException, status from models_library.licenses import LicensedItemID -from models_library.resource_tracker_licensed_items_checkouts import ( - LicensedItemCheckoutID, -) +from models_library.resource_tracker_license_checkouts import LicenseCheckoutID from pydantic import PositiveInt from simcore_service_api_server.api.dependencies.resource_usage_tracker_rpc import ( get_resource_usage_tracker_client, @@ -57,7 +55,7 @@ async def release_licensed_item( product_name: Annotated[str, Depends(get_product_name)], user_id: Annotated[PositiveInt, Depends(get_current_user_id)], licensed_item_id: LicensedItemID, - licensed_item_checkout_id: LicensedItemCheckoutID, + licensed_item_checkout_id: LicenseCheckoutID, ): _licensed_item_checkout = await rut_rpc.get_licensed_item_checkout( product_name=product_name, licensed_item_checkout_id=licensed_item_checkout_id diff --git a/services/api-server/src/simcore_service_api_server/services_rpc/resource_usage_tracker.py b/services/api-server/src/simcore_service_api_server/services_rpc/resource_usage_tracker.py index 371263a9880..39e2bfbf990 100644 --- a/services/api-server/src/simcore_service_api_server/services_rpc/resource_usage_tracker.py +++ b/services/api-server/src/simcore_service_api_server/services_rpc/resource_usage_tracker.py @@ -2,16 +2,14 @@ from functools import partial from fastapi import FastAPI -from models_library.resource_tracker_licensed_items_checkouts import ( - LicensedItemCheckoutID, -) +from models_library.resource_tracker_license_checkouts import LicenseCheckoutID from servicelib.fastapi.app_state import SingletonInAppStateMixin from servicelib.rabbitmq._client_rpc import RabbitMQRPCClient from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker.errors import ( - LicensedItemCheckoutNotFoundError as _LicensedItemCheckoutNotFoundError, + LicenseCheckoutNotFoundError as _LicensedItemCheckoutNotFoundError, ) -from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker.licensed_items_checkouts import ( - get_licensed_item_checkout as _get_licensed_item_checkout, +from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker.license_checkouts import ( + get_license_checkout as _get_licensed_item_checkout, ) from ..exceptions.backend_errors import LicensedItemCheckoutNotFoundError @@ -34,16 +32,16 @@ class ResourceUsageTrackerClient(SingletonInAppStateMixin): } ) async def get_licensed_item_checkout( - self, *, product_name: str, licensed_item_checkout_id: LicensedItemCheckoutID + self, *, product_name: str, licensed_item_checkout_id: LicenseCheckoutID ) -> LicensedItemCheckoutGet: _licensed_item_checkout = await _get_licensed_item_checkout( rabbitmq_rpc_client=self._client, product_name=product_name, - licensed_item_checkout_id=licensed_item_checkout_id, + license_checkout_id=licensed_item_checkout_id, ) return LicensedItemCheckoutGet( - licensed_item_checkout_id=_licensed_item_checkout.licensed_item_checkout_id, - licensed_item_id=_licensed_item_checkout.licensed_item_id, + licensed_item_checkout_id=_licensed_item_checkout.license_checkout_id, + licensed_item_id=_licensed_item_checkout.license_id, wallet_id=_licensed_item_checkout.wallet_id, user_id=_licensed_item_checkout.user_id, product_name=_licensed_item_checkout.product_name, diff --git a/services/api-server/src/simcore_service_api_server/services_rpc/wb_api_server.py b/services/api-server/src/simcore_service_api_server/services_rpc/wb_api_server.py index 0165a0e0148..ee8f7c4db7b 100644 --- a/services/api-server/src/simcore_service_api_server/services_rpc/wb_api_server.py +++ b/services/api-server/src/simcore_service_api_server/services_rpc/wb_api_server.py @@ -6,9 +6,7 @@ from fastapi_pagination import create_page from models_library.api_schemas_webserver.licensed_items import LicensedItemRpcGetPage from models_library.licenses import LicensedItemID -from models_library.resource_tracker_licensed_items_checkouts import ( - LicensedItemCheckoutID, -) +from models_library.resource_tracker_license_checkouts import LicenseCheckoutID from models_library.services_types import ServiceRunID from models_library.users import UserID from models_library.wallets import WalletID @@ -21,7 +19,7 @@ CanNotCheckoutServiceIsNotRunningError as _CanNotCheckoutServiceIsNotRunningError, ) from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker.errors import ( - LicensedItemCheckoutNotFoundError as _LicensedItemCheckoutNotFoundError, + LicenseCheckoutNotFoundError as _LicensedItemCheckoutNotFoundError, ) from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker.errors import ( NotEnoughAvailableSeatsError, @@ -160,7 +158,7 @@ async def release_licensed_item_for_wallet( *, product_name: str, user_id: UserID, - licensed_item_checkout_id: LicensedItemCheckoutID, + licensed_item_checkout_id: LicenseCheckoutID, ) -> LicensedItemCheckoutGet: licensed_item_checkout_get = await _release_licensed_item_for_wallet( self._client, diff --git a/services/api-server/tests/unit/test_licensed_items.py b/services/api-server/tests/unit/test_licensed_items.py index f396f1f397b..55e495cf326 100644 --- a/services/api-server/tests/unit/test_licensed_items.py +++ b/services/api-server/tests/unit/test_licensed_items.py @@ -11,8 +11,8 @@ from faker import Faker from fastapi import FastAPI, status from httpx import AsyncClient, BasicAuth -from models_library.api_schemas_resource_usage_tracker.licensed_items_checkouts import ( - LicensedItemCheckoutGet, +from models_library.api_schemas_resource_usage_tracker.license_checkouts import ( + LicenseCheckoutGet, ) from models_library.api_schemas_webserver.licensed_items import ( LicensedItemRpcGet, @@ -22,9 +22,7 @@ LicensedItemCheckoutRpcGet, ) from models_library.licenses import LicensedItemID -from models_library.resource_tracker_licensed_items_checkouts import ( - LicensedItemCheckoutID, -) +from models_library.resource_tracker_license_checkouts import LicenseCheckoutID from models_library.services_types import ServiceRunID from models_library.users import UserID from models_library.wallets import WalletID @@ -35,7 +33,7 @@ from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker.errors import ( CanNotCheckoutNotEnoughAvailableSeatsError, CanNotCheckoutServiceIsNotRunningError, - LicensedItemCheckoutNotFoundError, + LicenseCheckoutNotFoundError, NotEnoughAvailableSeatsError, ) from simcore_service_api_server._meta import API_VTAG @@ -245,8 +243,8 @@ async def side_effect( @pytest.mark.parametrize( "wb_api_exception_to_raise,rut_exception_to_raise,expected_api_server_status_code,valid_license_checkout_id", [ - (LicensedItemCheckoutNotFoundError, None, status.HTTP_404_NOT_FOUND, True), - (None, LicensedItemCheckoutNotFoundError, status.HTTP_404_NOT_FOUND, True), + (LicenseCheckoutNotFoundError, None, status.HTTP_404_NOT_FOUND, True), + (None, LicenseCheckoutNotFoundError, status.HTTP_404_NOT_FOUND, True), (None, None, status.HTTP_200_OK, True), (None, None, status.HTTP_422_UNPROCESSABLE_ENTITY, False), ], @@ -262,33 +260,33 @@ async def test_release_checked_out_licensed_item( valid_license_checkout_id: bool, faker: Faker, ): - _licensed_item_id = cast(UUID, faker.uuid4()) - _licensed_item_checkout_id = cast(UUID, faker.uuid4()) + _license_id = cast(UUID, faker.uuid4()) + _licensed_checkout_id = cast(UUID, faker.uuid4()) async def get_licensed_item_checkout( rabbitmq_rpc_client: RabbitMQRPCClient, product_name: str, - licensed_item_checkout_id: LicensedItemCheckoutID, - ) -> LicensedItemCheckoutGet: + licensed_item_checkout_id: LicenseCheckoutID, + ) -> LicenseCheckoutGet: if rut_exception_to_raise is not None: raise rut_exception_to_raise - extra = LicensedItemCheckoutGet.model_config.get("json_schema_extra") + extra = LicenseCheckoutGet.model_config.get("json_schema_extra") assert isinstance(extra, dict) examples = extra.get("examples") assert isinstance(examples, list) assert len(examples) > 0 example = examples[0] assert isinstance(example, dict) - licensed_item_checkout_get = LicensedItemCheckoutGet.model_validate(example) + licensed_item_checkout_get = LicenseCheckoutGet.model_validate(example) if valid_license_checkout_id: - licensed_item_checkout_get.licensed_item_id = _licensed_item_id + licensed_item_checkout_get.license_id = _license_id return licensed_item_checkout_get async def release_licensed_item_for_wallet( rabbitmq_rpc_client: RabbitMQRPCClient, product_name: str, user_id: int, - licensed_item_checkout_id: LicensedItemCheckoutID, + licensed_item_checkout_id: LicenseCheckoutID, ) -> LicensedItemCheckoutRpcGet: if wb_api_exception_to_raise is not None: raise wb_api_exception_to_raise @@ -311,7 +309,7 @@ async def release_licensed_item_for_wallet( ) resp = await client.post( - f"{API_VTAG}/licensed-items/{_licensed_item_id}/checked-out-items/{_licensed_item_checkout_id}/release", + f"{API_VTAG}/licensed-items/{_license_id}/checked-out-items/{_licensed_checkout_id}/release", auth=auth, ) assert resp.status_code == expected_api_server_status_code diff --git a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/api/rpc/_licensed_items_checkouts.py b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/api/rpc/_license_checkouts.py similarity index 55% rename from services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/api/rpc/_licensed_items_checkouts.py rename to services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/api/rpc/_license_checkouts.py index 3ab6e5a4e61..ee32f0068a9 100644 --- a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/api/rpc/_licensed_items_checkouts.py +++ b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/api/rpc/_license_checkouts.py @@ -1,13 +1,11 @@ from fastapi import FastAPI -from models_library.api_schemas_resource_usage_tracker.licensed_items_checkouts import ( - LicensedItemCheckoutGet, - LicensedItemsCheckoutsPage, +from models_library.api_schemas_resource_usage_tracker.license_checkouts import ( + LicenseCheckoutGet, + LicenseCheckoutsPage, ) -from models_library.licenses import LicensedItemID +from models_library.licenses import LicenseID from models_library.products import ProductName -from models_library.resource_tracker_licensed_items_checkouts import ( - LicensedItemCheckoutID, -) +from models_library.resource_tracker_license_checkouts import LicenseCheckoutID from models_library.rest_ordering import OrderBy from models_library.services_types import ServiceRunID from models_library.users import UserID @@ -15,30 +13,30 @@ from servicelib.rabbitmq import RPCRouter from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker.errors import ( LICENSES_ERRORS, - LicensedItemCheckoutNotFoundError, + LicenseCheckoutNotFoundError, ) -from ...services import licensed_items_checkouts +from ...services import license_checkouts router = RPCRouter() -@router.expose(reraise_if_error_type=(LicensedItemCheckoutNotFoundError,)) -async def get_licensed_item_checkout( +@router.expose(reraise_if_error_type=(LicenseCheckoutNotFoundError,)) +async def get_license_checkout( app: FastAPI, *, product_name: ProductName, - licensed_item_checkout_id: LicensedItemCheckoutID, -) -> LicensedItemCheckoutGet: - return await licensed_items_checkouts.get_licensed_item_checkout( + license_checkout_id: LicenseCheckoutID, +) -> LicenseCheckoutGet: + return await license_checkouts.get_license_checkout( db_engine=app.state.engine, product_name=product_name, - licensed_item_checkout_id=licensed_item_checkout_id, + license_checkout_id=license_checkout_id, ) @router.expose(reraise_if_error_type=LICENSES_ERRORS) -async def get_licensed_items_checkouts_page( +async def get_license_checkouts_page( app: FastAPI, *, product_name: ProductName, @@ -46,8 +44,8 @@ async def get_licensed_items_checkouts_page( offset: int = 0, limit: int = 20, order_by: OrderBy, -) -> LicensedItemsCheckoutsPage: - return await licensed_items_checkouts.list_licensed_items_checkouts( +) -> LicenseCheckoutsPage: + return await license_checkouts.list_license_checkouts( db_engine=app.state.engine, product_name=product_name, filter_wallet_id=filter_wallet_id, @@ -58,20 +56,20 @@ async def get_licensed_items_checkouts_page( @router.expose(reraise_if_error_type=LICENSES_ERRORS) -async def checkout_licensed_item( +async def checkout_license( app: FastAPI, *, - licensed_item_id: LicensedItemID, + license_id: LicenseID, wallet_id: WalletID, product_name: ProductName, num_of_seats: int, service_run_id: ServiceRunID, user_id: UserID, user_email: str, -) -> LicensedItemCheckoutGet: - return await licensed_items_checkouts.checkout_licensed_item( +) -> LicenseCheckoutGet: + return await license_checkouts.checkout_license( db_engine=app.state.engine, - licensed_item_id=licensed_item_id, + license_id=license_id, wallet_id=wallet_id, product_name=product_name, num_of_seats=num_of_seats, @@ -82,14 +80,14 @@ async def checkout_licensed_item( @router.expose(reraise_if_error_type=LICENSES_ERRORS) -async def release_licensed_item( +async def release_license( app: FastAPI, *, - licensed_item_checkout_id: LicensedItemCheckoutID, + license_checkout_id: LicenseCheckoutID, product_name: ProductName, -) -> LicensedItemCheckoutGet: - return await licensed_items_checkouts.release_licensed_item( +) -> LicenseCheckoutGet: + return await license_checkouts.release_license( db_engine=app.state.engine, - licensed_item_checkout_id=licensed_item_checkout_id, + license_checkout_id=license_checkout_id, product_name=product_name, ) diff --git a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/api/rpc/_licensed_items_purchases.py b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/api/rpc/_license_purchases.py similarity index 54% rename from services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/api/rpc/_licensed_items_purchases.py rename to services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/api/rpc/_license_purchases.py index e8f71dfb97d..1a620314cf3 100644 --- a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/api/rpc/_licensed_items_purchases.py +++ b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/api/rpc/_license_purchases.py @@ -1,25 +1,25 @@ from fastapi import FastAPI -from models_library.api_schemas_resource_usage_tracker.licensed_items_purchases import ( - LicensedItemPurchaseGet, - LicensedItemsPurchasesPage, +from models_library.api_schemas_resource_usage_tracker.license_purchases import ( + LicensePurchaseGet, + LicensesPurchasesPage, ) from models_library.basic_types import IDStr from models_library.products import ProductName -from models_library.resource_tracker_licensed_items_purchases import ( - LicensedItemPurchaseID, - LicensedItemsPurchasesCreate, +from models_library.resource_tracker_license_purchases import ( + LicensePurchaseID, + LicensePurchasesCreate, ) from models_library.rest_ordering import OrderBy from models_library.wallets import WalletID from servicelib.rabbitmq import RPCRouter -from ...services import licensed_items_purchases +from ...services import license_purchases router = RPCRouter() @router.expose(reraise_if_error_type=()) -async def get_licensed_items_purchases_page( +async def get_license_purchases_page( app: FastAPI, *, product_name: ProductName, @@ -27,8 +27,8 @@ async def get_licensed_items_purchases_page( offset: int = 0, limit: int = 20, order_by: OrderBy = OrderBy(field=IDStr("purchased_at")), -) -> LicensedItemsPurchasesPage: - return await licensed_items_purchases.list_licensed_items_purchases( +) -> LicensesPurchasesPage: + return await license_purchases.list_license_purchases( db_engine=app.state.engine, product_name=product_name, offset=offset, @@ -39,13 +39,13 @@ async def get_licensed_items_purchases_page( @router.expose(reraise_if_error_type=()) -async def get_licensed_item_purchase( +async def get_license_purchase( app: FastAPI, *, product_name: ProductName, - licensed_item_purchase_id: LicensedItemPurchaseID, -) -> LicensedItemPurchaseGet: - return await licensed_items_purchases.get_licensed_item_purchase( + licensed_item_purchase_id: LicensePurchaseID, +) -> LicensePurchaseGet: + return await license_purchases.get_license_purchase( db_engine=app.state.engine, product_name=product_name, licensed_item_purchase_id=licensed_item_purchase_id, @@ -53,9 +53,9 @@ async def get_licensed_item_purchase( @router.expose(reraise_if_error_type=()) -async def create_licensed_item_purchase( - app: FastAPI, *, data: LicensedItemsPurchasesCreate -) -> LicensedItemPurchaseGet: - return await licensed_items_purchases.create_licensed_item_purchase( +async def create_license_purchase( + app: FastAPI, *, data: LicensePurchasesCreate +) -> LicensePurchaseGet: + return await license_purchases.create_license_purchase( rabbitmq_client=app.state.rabbitmq_client, db_engine=app.state.engine, data=data ) diff --git a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/api/rpc/routes.py b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/api/rpc/routes.py index 42767b19525..334df3690ec 100644 --- a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/api/rpc/routes.py +++ b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/api/rpc/routes.py @@ -10,8 +10,8 @@ from ...services.modules.rabbitmq import get_rabbitmq_rpc_server from . import ( _credit_transactions, - _licensed_items_checkouts, - _licensed_items_purchases, + _license_checkouts, + _license_purchases, _pricing_plans, _service_runs, ) @@ -23,8 +23,8 @@ _credit_transactions.router, _service_runs.router, _pricing_plans.router, - _licensed_items_purchases.router, - _licensed_items_checkouts.router, + _license_purchases.router, + _license_checkouts.router, ] diff --git a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/exceptions/errors.py b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/exceptions/errors.py index 55fde04b0f6..1034b49407e 100644 --- a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/exceptions/errors.py +++ b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/exceptions/errors.py @@ -1,7 +1,5 @@ from common_library.errors_classes import OsparcErrorMixin -from models_library.resource_tracker_licensed_items_purchases import ( - LicensedItemPurchaseID, -) +from models_library.resource_tracker_license_purchases import LicensePurchaseID class ResourceUsageTrackerBaseError(OsparcErrorMixin, Exception): @@ -73,5 +71,5 @@ class PricingPlanNotFoundForServiceError(RutNotFoundError): ) -class LicensedItemPurchaseNotFoundError(RutNotFoundError): - licensed_item_purchase_id: LicensedItemPurchaseID +class LicensePurchaseNotFoundError(RutNotFoundError): + licensed_item_purchase_id: LicensePurchaseID diff --git a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/models/credit_transactions.py b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/models/credit_transactions.py index 564b12ce1d4..b5d34df7bc5 100644 --- a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/models/credit_transactions.py +++ b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/models/credit_transactions.py @@ -10,9 +10,7 @@ PricingUnitCostId, PricingUnitId, ) -from models_library.resource_tracker_licensed_items_purchases import ( - LicensedItemPurchaseID, -) +from models_library.resource_tracker_license_purchases import LicensePurchaseID from models_library.services_types import ServiceRunID from models_library.users import UserID from models_library.wallets import WalletID @@ -35,7 +33,7 @@ class CreditTransactionCreate(BaseModel): payment_transaction_id: str | None created_at: datetime last_heartbeat_at: datetime - licensed_item_purchase_id: LicensedItemPurchaseID | None + licensed_item_purchase_id: LicensePurchaseID | None class CreditTransactionCreditsUpdate(BaseModel): diff --git a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/models/licensed_items_checkouts.py b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/models/license_checkouts.py similarity index 67% rename from services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/models/licensed_items_checkouts.py rename to services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/models/license_checkouts.py index 8f2d2c1371a..1391065b8ac 100644 --- a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/models/licensed_items_checkouts.py +++ b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/models/license_checkouts.py @@ -1,19 +1,17 @@ from datetime import datetime -from models_library.licenses import LicensedItemID +from models_library.licenses import LicenseID from models_library.products import ProductName -from models_library.resource_tracker_licensed_items_checkouts import ( - LicensedItemCheckoutID, -) +from models_library.resource_tracker_license_checkouts import LicenseCheckoutID from models_library.services_types import ServiceRunID from models_library.users import UserID from models_library.wallets import WalletID from pydantic import BaseModel, ConfigDict -class LicensedItemCheckoutDB(BaseModel): - licensed_item_checkout_id: LicensedItemCheckoutID - licensed_item_id: LicensedItemID +class LicenseCheckoutDB(BaseModel): + license_checkout_id: LicenseCheckoutID + license_id: LicenseID wallet_id: WalletID user_id: UserID user_email: str @@ -27,8 +25,8 @@ class LicensedItemCheckoutDB(BaseModel): model_config = ConfigDict(from_attributes=True) -class CreateLicensedItemCheckoutDB(BaseModel): - licensed_item_id: LicensedItemID +class CreateLicenseCheckoutDB(BaseModel): + license_id: LicenseID wallet_id: WalletID user_id: UserID user_email: str @@ -40,7 +38,7 @@ class CreateLicensedItemCheckoutDB(BaseModel): model_config = ConfigDict(from_attributes=True) -class UpdateLicensedItemCheckoutDB(BaseModel): +class UpdateLicenseCheckoutDB(BaseModel): stopped_at: datetime model_config = ConfigDict(from_attributes=True) diff --git a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/models/licensed_items_purchases.py b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/models/license_purchases.py similarity index 74% rename from services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/models/licensed_items_purchases.py rename to services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/models/license_purchases.py index c5a752dafb9..5cf202c9e9a 100644 --- a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/models/licensed_items_purchases.py +++ b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/models/license_purchases.py @@ -2,21 +2,19 @@ from decimal import Decimal from models_library.emails import LowerCaseEmailStr -from models_library.licenses import LicensedItemID +from models_library.licenses import LicenseID from models_library.products import ProductName from models_library.resource_tracker import PricingUnitCostId -from models_library.resource_tracker_licensed_items_purchases import ( - LicensedItemPurchaseID, -) +from models_library.resource_tracker_license_purchases import LicensePurchaseID from models_library.users import UserID from models_library.wallets import WalletID from pydantic import BaseModel, ConfigDict -class LicensedItemsPurchasesDB(BaseModel): - licensed_item_purchase_id: LicensedItemPurchaseID +class LicensesPurchasesDB(BaseModel): + licensed_item_purchase_id: LicensePurchaseID product_name: ProductName - licensed_item_id: LicensedItemID + license_id: LicenseID wallet_id: WalletID wallet_name: str pricing_unit_cost_id: PricingUnitCostId @@ -32,9 +30,9 @@ class LicensedItemsPurchasesDB(BaseModel): model_config = ConfigDict(from_attributes=True) -class CreateLicensedItemsPurchasesDB(BaseModel): +class CreateLicensesPurchasesDB(BaseModel): product_name: ProductName - licensed_item_id: LicensedItemID + license_id: LicenseID wallet_id: WalletID wallet_name: str pricing_unit_cost_id: PricingUnitCostId diff --git a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/background_task_periodic_heartbeat_check.py b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/background_task_periodic_heartbeat_check.py index 4f61fda9879..fa777a123c0 100644 --- a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/background_task_periodic_heartbeat_check.py +++ b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/background_task_periodic_heartbeat_check.py @@ -15,11 +15,7 @@ from ..core.settings import ApplicationSettings from ..models.credit_transactions import CreditTransactionCreditsAndStatusUpdate from ..models.service_runs import ServiceRunStoppedAtUpdate -from .modules.db import ( - credit_transactions_db, - licensed_items_checkouts_db, - service_runs_db, -) +from .modules.db import credit_transactions_db, license_checkouts_db, service_runs_db from .utils import compute_service_run_credit_costs, make_negative _logger = logging.getLogger(__name__) @@ -149,7 +145,7 @@ async def _close_unhealthy_service( ) # 4. Release license seats in case some were checked out but not properly released. - await licensed_items_checkouts_db.force_release_license_seats_by_run_id( + await license_checkouts_db.force_release_license_seats_by_run_id( db_engine, service_run_id=service_run_id ) diff --git a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/licensed_items_checkouts.py b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/license_checkouts.py similarity index 61% rename from services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/licensed_items_checkouts.py rename to services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/license_checkouts.py index 8ccc4d8c237..4ceedb1de69 100644 --- a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/licensed_items_checkouts.py +++ b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/license_checkouts.py @@ -2,16 +2,14 @@ from typing import Annotated from fastapi import Depends -from models_library.api_schemas_resource_usage_tracker.licensed_items_checkouts import ( - LicensedItemCheckoutGet, - LicensedItemsCheckoutsPage, +from models_library.api_schemas_resource_usage_tracker.license_checkouts import ( + LicenseCheckoutGet, + LicenseCheckoutsPage, ) -from models_library.licenses import LicensedItemID +from models_library.licenses import LicenseID from models_library.products import ProductName from models_library.resource_tracker import ServiceRunStatus -from models_library.resource_tracker_licensed_items_checkouts import ( - LicensedItemCheckoutID, -) +from models_library.resource_tracker_license_checkouts import LicenseCheckoutID from models_library.rest_ordering import OrderBy from models_library.services_types import ServiceRunID from models_library.users import UserID @@ -24,18 +22,11 @@ from sqlalchemy.ext.asyncio import AsyncEngine from ..api.rest.dependencies import get_resource_tracker_db_engine -from ..models.licensed_items_checkouts import ( - CreateLicensedItemCheckoutDB, - LicensedItemCheckoutDB, -) -from .modules.db import ( - licensed_items_checkouts_db, - licensed_items_purchases_db, - service_runs_db, -) +from ..models.license_checkouts import CreateLicenseCheckoutDB, LicenseCheckoutDB +from .modules.db import license_checkouts_db, license_purchases_db, service_runs_db -async def list_licensed_items_checkouts( +async def list_license_checkouts( db_engine: Annotated[AsyncEngine, Depends(get_resource_tracker_db_engine)], *, product_name: ProductName, @@ -43,8 +34,8 @@ async def list_licensed_items_checkouts( offset: int, limit: int, order_by: OrderBy, -) -> LicensedItemsCheckoutsPage: - total, licensed_items_checkouts_list_db = await licensed_items_checkouts_db.list_( +) -> LicenseCheckoutsPage: + total, license_checkouts_list_db = await license_checkouts_db.list_( db_engine, product_name=product_name, filter_wallet_id=filter_wallet_id, @@ -52,12 +43,12 @@ async def list_licensed_items_checkouts( limit=limit, order_by=order_by, ) - return LicensedItemsCheckoutsPage( + return LicenseCheckoutsPage( total=total, items=[ - LicensedItemCheckoutGet( - licensed_item_checkout_id=licensed_item_checkout_db.licensed_item_checkout_id, - licensed_item_id=licensed_item_checkout_db.licensed_item_id, + LicenseCheckoutGet( + license_checkout_id=licensed_item_checkout_db.license_checkout_id, + license_id=licensed_item_checkout_db.license_id, wallet_id=licensed_item_checkout_db.wallet_id, user_id=licensed_item_checkout_db.user_id, user_email=licensed_item_checkout_db.user_email, @@ -67,28 +58,26 @@ async def list_licensed_items_checkouts( stopped_at=licensed_item_checkout_db.stopped_at, num_of_seats=licensed_item_checkout_db.num_of_seats, ) - for licensed_item_checkout_db in licensed_items_checkouts_list_db + for licensed_item_checkout_db in license_checkouts_list_db ], ) -async def get_licensed_item_checkout( +async def get_license_checkout( db_engine: Annotated[AsyncEngine, Depends(get_resource_tracker_db_engine)], *, product_name: ProductName, - licensed_item_checkout_id: LicensedItemCheckoutID, -) -> LicensedItemCheckoutGet: - licensed_item_checkout_db: LicensedItemCheckoutDB = ( - await licensed_items_checkouts_db.get( - db_engine, - product_name=product_name, - licensed_item_checkout_id=licensed_item_checkout_id, - ) + license_checkout_id: LicenseCheckoutID, +) -> LicenseCheckoutGet: + licensed_item_checkout_db: LicenseCheckoutDB = await license_checkouts_db.get( + db_engine, + product_name=product_name, + license_checkout_id=license_checkout_id, ) - return LicensedItemCheckoutGet( - licensed_item_checkout_id=licensed_item_checkout_db.licensed_item_checkout_id, - licensed_item_id=licensed_item_checkout_db.licensed_item_id, + return LicenseCheckoutGet( + license_checkout_id=licensed_item_checkout_db.license_checkout_id, + license_id=licensed_item_checkout_db.license_id, wallet_id=licensed_item_checkout_db.wallet_id, user_id=licensed_item_checkout_db.user_id, user_email=licensed_item_checkout_db.user_email, @@ -100,29 +89,31 @@ async def get_licensed_item_checkout( ) -async def checkout_licensed_item( +async def checkout_license( db_engine: Annotated[AsyncEngine, Depends(get_resource_tracker_db_engine)], *, - licensed_item_id: LicensedItemID, + license_id: LicenseID, wallet_id: WalletID, product_name: ProductName, num_of_seats: int, service_run_id: ServiceRunID, user_id: UserID, user_email: str, -) -> LicensedItemCheckoutGet: +) -> LicenseCheckoutGet: - _active_purchased_seats: int = await licensed_items_purchases_db.get_active_purchased_seats_for_item_and_wallet( - db_engine, - licensed_item_id=licensed_item_id, - wallet_id=wallet_id, - product_name=product_name, + _active_purchased_seats: int = ( + await license_purchases_db.get_active_purchased_seats_for_item_and_wallet( + db_engine, + license_id=license_id, + wallet_id=wallet_id, + product_name=product_name, + ) ) _currently_used_seats = ( - await licensed_items_checkouts_db.get_currently_used_seats_for_item_and_wallet( + await license_checkouts_db.get_currently_used_seats_for_item_and_wallet( db_engine, - licensed_item_id=licensed_item_id, + license_id=license_id, wallet_id=wallet_id, product_name=product_name, ) @@ -131,12 +122,12 @@ async def checkout_licensed_item( available_seats = _active_purchased_seats - _currently_used_seats if available_seats <= 0: raise NotEnoughAvailableSeatsError( - license_item_id=licensed_item_id, available_num_of_seats=available_seats + license_id=license_id, available_num_of_seats=available_seats ) if available_seats - num_of_seats < 0: raise CanNotCheckoutNotEnoughAvailableSeatsError( - license_item_id=licensed_item_id, + license_id=license_id, available_num_of_seats=available_seats, num_of_seats=num_of_seats, ) @@ -150,11 +141,11 @@ async def checkout_licensed_item( or service_run.service_run_status != ServiceRunStatus.RUNNING ): raise CanNotCheckoutServiceIsNotRunningError( - license_item_id=licensed_item_id, service_run=service_run + license_id=license_id, service_run=service_run ) - _create_item_checkout = CreateLicensedItemCheckoutDB( - licensed_item_id=licensed_item_id, + _create_item_checkout = CreateLicenseCheckoutDB( + license_id=license_id, wallet_id=wallet_id, user_id=user_id, user_email=user_email, @@ -163,14 +154,14 @@ async def checkout_licensed_item( started_at=datetime.now(tz=UTC), num_of_seats=num_of_seats, ) - licensed_item_checkout_db = await licensed_items_checkouts_db.create( + licensed_item_checkout_db = await license_checkouts_db.create( db_engine, data=_create_item_checkout ) # Return checkout ID - return LicensedItemCheckoutGet( - licensed_item_checkout_id=licensed_item_checkout_db.licensed_item_checkout_id, - licensed_item_id=licensed_item_checkout_db.licensed_item_id, + return LicenseCheckoutGet( + license_checkout_id=licensed_item_checkout_db.license_checkout_id, + license_id=licensed_item_checkout_db.license_id, wallet_id=licensed_item_checkout_db.wallet_id, user_id=licensed_item_checkout_db.user_id, user_email=licensed_item_checkout_db.user_email, @@ -182,25 +173,23 @@ async def checkout_licensed_item( ) -async def release_licensed_item( +async def release_license( db_engine: Annotated[AsyncEngine, Depends(get_resource_tracker_db_engine)], *, - licensed_item_checkout_id: LicensedItemCheckoutID, + license_checkout_id: LicenseCheckoutID, product_name: ProductName, -) -> LicensedItemCheckoutGet: +) -> LicenseCheckoutGet: - licensed_item_checkout_db: LicensedItemCheckoutDB = ( - await licensed_items_checkouts_db.update( - db_engine, - licensed_item_checkout_id=licensed_item_checkout_id, - product_name=product_name, - stopped_at=datetime.now(tz=UTC), - ) + licensed_item_checkout_db: LicenseCheckoutDB = await license_checkouts_db.update( + db_engine, + license_checkout_id=license_checkout_id, + product_name=product_name, + stopped_at=datetime.now(tz=UTC), ) - return LicensedItemCheckoutGet( - licensed_item_checkout_id=licensed_item_checkout_db.licensed_item_checkout_id, - licensed_item_id=licensed_item_checkout_db.licensed_item_id, + return LicenseCheckoutGet( + license_checkout_id=licensed_item_checkout_db.license_checkout_id, + license_id=licensed_item_checkout_db.license_id, wallet_id=licensed_item_checkout_db.wallet_id, user_id=licensed_item_checkout_db.user_id, user_email=licensed_item_checkout_db.user_email, diff --git a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/licensed_items_purchases.py b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/license_purchases.py similarity index 77% rename from services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/licensed_items_purchases.py rename to services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/license_purchases.py index f085de18406..00f97cab513 100644 --- a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/licensed_items_purchases.py +++ b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/license_purchases.py @@ -1,18 +1,18 @@ from typing import Annotated from fastapi import Depends -from models_library.api_schemas_resource_usage_tracker.licensed_items_purchases import ( - LicensedItemPurchaseGet, - LicensedItemsPurchasesPage, +from models_library.api_schemas_resource_usage_tracker.license_purchases import ( + LicensePurchaseGet, + LicensesPurchasesPage, ) from models_library.products import ProductName from models_library.resource_tracker import ( CreditClassification, CreditTransactionStatus, ) -from models_library.resource_tracker_licensed_items_purchases import ( - LicensedItemPurchaseID, - LicensedItemsPurchasesCreate, +from models_library.resource_tracker_license_purchases import ( + LicensePurchaseID, + LicensePurchasesCreate, ) from models_library.rest_ordering import OrderBy from models_library.wallets import WalletID @@ -21,16 +21,13 @@ from ..api.rest.dependencies import get_resource_tracker_db_engine from ..models.credit_transactions import CreditTransactionCreate -from ..models.licensed_items_purchases import ( - CreateLicensedItemsPurchasesDB, - LicensedItemsPurchasesDB, -) -from .modules.db import credit_transactions_db, licensed_items_purchases_db +from ..models.license_purchases import CreateLicensesPurchasesDB, LicensesPurchasesDB +from .modules.db import credit_transactions_db, license_purchases_db from .modules.rabbitmq import RabbitMQClient, get_rabbitmq_client from .utils import make_negative, sum_credit_transactions_and_publish_to_rabbitmq -async def list_licensed_items_purchases( +async def list_license_purchases( db_engine: Annotated[AsyncEngine, Depends(get_resource_tracker_db_engine)], *, product_name: ProductName, @@ -38,8 +35,8 @@ async def list_licensed_items_purchases( offset: int = 0, limit: int = 20, order_by: OrderBy, -) -> LicensedItemsPurchasesPage: - total, licensed_items_purchases_list_db = await licensed_items_purchases_db.list_( +) -> LicensesPurchasesPage: + total, license_purchases_list_db = await license_purchases_db.list_( db_engine, product_name=product_name, filter_wallet_id=filter_wallet_id, @@ -47,13 +44,13 @@ async def list_licensed_items_purchases( limit=limit, order_by=order_by, ) - return LicensedItemsPurchasesPage( + return LicensesPurchasesPage( total=total, items=[ - LicensedItemPurchaseGet( + LicensePurchaseGet( licensed_item_purchase_id=licensed_item_purchase_db.licensed_item_purchase_id, product_name=licensed_item_purchase_db.product_name, - licensed_item_id=licensed_item_purchase_db.licensed_item_id, + license_id=licensed_item_purchase_db.license_id, wallet_id=licensed_item_purchase_db.wallet_id, wallet_name=licensed_item_purchase_db.wallet_name, pricing_unit_cost_id=licensed_item_purchase_db.pricing_unit_cost_id, @@ -66,29 +63,27 @@ async def list_licensed_items_purchases( purchased_at=licensed_item_purchase_db.purchased_at, modified=licensed_item_purchase_db.modified, ) - for licensed_item_purchase_db in licensed_items_purchases_list_db + for licensed_item_purchase_db in license_purchases_list_db ], ) -async def get_licensed_item_purchase( +async def get_license_purchase( db_engine: Annotated[AsyncEngine, Depends(get_resource_tracker_db_engine)], *, product_name: ProductName, - licensed_item_purchase_id: LicensedItemPurchaseID, -) -> LicensedItemPurchaseGet: - licensed_item_purchase_db: LicensedItemsPurchasesDB = ( - await licensed_items_purchases_db.get( - db_engine, - product_name=product_name, - licensed_item_purchase_id=licensed_item_purchase_id, - ) + licensed_item_purchase_id: LicensePurchaseID, +) -> LicensePurchaseGet: + licensed_item_purchase_db: LicensesPurchasesDB = await license_purchases_db.get( + db_engine, + product_name=product_name, + licensed_item_purchase_id=licensed_item_purchase_id, ) - return LicensedItemPurchaseGet( + return LicensePurchaseGet( licensed_item_purchase_id=licensed_item_purchase_db.licensed_item_purchase_id, product_name=licensed_item_purchase_db.product_name, - licensed_item_id=licensed_item_purchase_db.licensed_item_id, + license_id=licensed_item_purchase_db.license_id, wallet_id=licensed_item_purchase_db.wallet_id, wallet_name=licensed_item_purchase_db.wallet_name, pricing_unit_cost_id=licensed_item_purchase_db.pricing_unit_cost_id, @@ -103,17 +98,17 @@ async def get_licensed_item_purchase( ) -async def create_licensed_item_purchase( +async def create_license_purchase( rabbitmq_client: Annotated[RabbitMQClient, Depends(get_rabbitmq_client)], db_engine: Annotated[AsyncEngine, Depends(get_resource_tracker_db_engine)], *, - data: LicensedItemsPurchasesCreate, -) -> LicensedItemPurchaseGet: + data: LicensePurchasesCreate, +) -> LicensePurchaseGet: async with transaction_context(db_engine) as conn: - item_purchase_create = CreateLicensedItemsPurchasesDB( + item_purchase_create = CreateLicensesPurchasesDB( product_name=data.product_name, - licensed_item_id=data.licensed_item_id, + license_id=data.license_id, wallet_id=data.wallet_id, wallet_name=data.wallet_name, pricing_unit_cost_id=data.pricing_unit_cost_id, @@ -126,8 +121,8 @@ async def create_licensed_item_purchase( purchased_at=data.purchased_at, ) - licensed_item_purchase_db: LicensedItemsPurchasesDB = ( - await licensed_items_purchases_db.create( + licensed_item_purchase_db: LicensesPurchasesDB = ( + await license_purchases_db.create( db_engine, connection=conn, data=item_purchase_create ) ) @@ -163,10 +158,10 @@ async def create_licensed_item_purchase( wallet_id=data.wallet_id, ) - return LicensedItemPurchaseGet( + return LicensePurchaseGet( licensed_item_purchase_id=licensed_item_purchase_db.licensed_item_purchase_id, product_name=licensed_item_purchase_db.product_name, - licensed_item_id=licensed_item_purchase_db.licensed_item_id, + license_id=licensed_item_purchase_db.license_id, wallet_id=licensed_item_purchase_db.wallet_id, wallet_name=licensed_item_purchase_db.wallet_name, pricing_unit_cost_id=licensed_item_purchase_db.pricing_unit_cost_id, diff --git a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/modules/db/licensed_items_checkouts_db.py b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/modules/db/license_checkouts_db.py similarity index 54% rename from services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/modules/db/licensed_items_checkouts_db.py rename to services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/modules/db/license_checkouts_db.py index 244ecb89230..b7d6f195930 100644 --- a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/modules/db/licensed_items_checkouts_db.py +++ b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/modules/db/license_checkouts_db.py @@ -3,20 +3,18 @@ from typing import cast import sqlalchemy as sa -from models_library.licenses import LicensedItemID +from models_library.licenses import LicenseID from models_library.products import ProductName -from models_library.resource_tracker_licensed_items_checkouts import ( - LicensedItemCheckoutID, -) +from models_library.resource_tracker_license_checkouts import LicenseCheckoutID from models_library.rest_ordering import OrderBy, OrderDirection from models_library.services_types import ServiceRunID from models_library.wallets import WalletID from pydantic import NonNegativeInt from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker.errors import ( - LicensedItemCheckoutNotFoundError, + LicenseCheckoutNotFoundError, ) -from simcore_postgres_database.models.resource_tracker_licensed_items_checkouts import ( - resource_tracker_licensed_items_checkouts, +from simcore_postgres_database.models.resource_tracker_license_checkouts import ( + resource_tracker_license_checkouts, ) from simcore_postgres_database.utils_repos import ( pass_or_acquire_connection, @@ -24,44 +22,39 @@ ) from sqlalchemy.ext.asyncio import AsyncConnection, AsyncEngine -from ....models.licensed_items_checkouts import ( - CreateLicensedItemCheckoutDB, - LicensedItemCheckoutDB, -) +from ....models.license_checkouts import CreateLicenseCheckoutDB, LicenseCheckoutDB _logger = logging.getLogger(__name__) _SELECTION_ARGS = ( - resource_tracker_licensed_items_checkouts.c.licensed_item_checkout_id, - resource_tracker_licensed_items_checkouts.c.licensed_item_id, - resource_tracker_licensed_items_checkouts.c.wallet_id, - resource_tracker_licensed_items_checkouts.c.user_id, - resource_tracker_licensed_items_checkouts.c.user_email, - resource_tracker_licensed_items_checkouts.c.product_name, - resource_tracker_licensed_items_checkouts.c.service_run_id, - resource_tracker_licensed_items_checkouts.c.started_at, - resource_tracker_licensed_items_checkouts.c.stopped_at, - resource_tracker_licensed_items_checkouts.c.num_of_seats, - resource_tracker_licensed_items_checkouts.c.modified, + resource_tracker_license_checkouts.c.license_checkout_id, + resource_tracker_license_checkouts.c.license_id, + resource_tracker_license_checkouts.c.wallet_id, + resource_tracker_license_checkouts.c.user_id, + resource_tracker_license_checkouts.c.user_email, + resource_tracker_license_checkouts.c.product_name, + resource_tracker_license_checkouts.c.service_run_id, + resource_tracker_license_checkouts.c.started_at, + resource_tracker_license_checkouts.c.stopped_at, + resource_tracker_license_checkouts.c.num_of_seats, + resource_tracker_license_checkouts.c.modified, ) -assert set(LicensedItemCheckoutDB.model_fields) == { - c.name for c in _SELECTION_ARGS -} # nosec +assert set(LicenseCheckoutDB.model_fields) == {c.name for c in _SELECTION_ARGS} # nosec async def create( engine: AsyncEngine, connection: AsyncConnection | None = None, *, - data: CreateLicensedItemCheckoutDB, -) -> LicensedItemCheckoutDB: + data: CreateLicenseCheckoutDB, +) -> LicenseCheckoutDB: async with transaction_context(engine, connection) as conn: result = await conn.execute( - resource_tracker_licensed_items_checkouts.insert() + resource_tracker_license_checkouts.insert() .values( - licensed_item_id=data.licensed_item_id, + license_id=data.license_id, wallet_id=data.wallet_id, user_id=data.user_id, user_email=data.user_email, @@ -75,7 +68,7 @@ async def create( .returning(*_SELECTION_ARGS) ) row = result.first() - return LicensedItemCheckoutDB.model_validate(row) + return LicenseCheckoutDB.model_validate(row) async def list_( @@ -87,16 +80,13 @@ async def list_( offset: NonNegativeInt, limit: NonNegativeInt, order_by: OrderBy, -) -> tuple[int, list[LicensedItemCheckoutDB]]: +) -> tuple[int, list[LicenseCheckoutDB]]: base_query = ( sa.select(*_SELECTION_ARGS) - .select_from(resource_tracker_licensed_items_checkouts) + .select_from(resource_tracker_license_checkouts) .where( - (resource_tracker_licensed_items_checkouts.c.product_name == product_name) - & ( - resource_tracker_licensed_items_checkouts.c.wallet_id - == filter_wallet_id - ) + (resource_tracker_license_checkouts.c.product_name == product_name) + & (resource_tracker_license_checkouts.c.wallet_id == filter_wallet_id) ) ) @@ -107,13 +97,11 @@ async def list_( # Ordering and pagination if order_by.direction == OrderDirection.ASC: list_query = base_query.order_by( - sa.asc(getattr(resource_tracker_licensed_items_checkouts.c, order_by.field)) + sa.asc(getattr(resource_tracker_license_checkouts.c, order_by.field)) ) else: list_query = base_query.order_by( - sa.desc( - getattr(resource_tracker_licensed_items_checkouts.c, order_by.field) - ) + sa.desc(getattr(resource_tracker_license_checkouts.c, order_by.field)) ) list_query = list_query.offset(offset).limit(limit) @@ -123,8 +111,8 @@ async def list_( total_count = 0 result = await conn.stream(list_query) - items: list[LicensedItemCheckoutDB] = [ - LicensedItemCheckoutDB.model_validate(row) async for row in result + items: list[LicenseCheckoutDB] = [ + LicenseCheckoutDB.model_validate(row) async for row in result ] return cast(int, total_count), items @@ -134,18 +122,18 @@ async def get( engine: AsyncEngine, connection: AsyncConnection | None = None, *, - licensed_item_checkout_id: LicensedItemCheckoutID, + license_checkout_id: LicenseCheckoutID, product_name: ProductName, -) -> LicensedItemCheckoutDB: +) -> LicenseCheckoutDB: base_query = ( sa.select(*_SELECTION_ARGS) - .select_from(resource_tracker_licensed_items_checkouts) + .select_from(resource_tracker_license_checkouts) .where( ( - resource_tracker_licensed_items_checkouts.c.licensed_item_checkout_id - == licensed_item_checkout_id + resource_tracker_license_checkouts.c.license_checkout_id + == license_checkout_id ) - & (resource_tracker_licensed_items_checkouts.c.product_name == product_name) + & (resource_tracker_license_checkouts.c.product_name == product_name) ) ) @@ -153,33 +141,31 @@ async def get( result = await conn.stream(base_query) row = await result.first() if row is None: - raise LicensedItemCheckoutNotFoundError( - licensed_item_checkout_id=licensed_item_checkout_id - ) - return LicensedItemCheckoutDB.model_validate(row) + raise LicenseCheckoutNotFoundError(license_checkout_id=license_checkout_id) + return LicenseCheckoutDB.model_validate(row) async def update( engine: AsyncEngine, connection: AsyncConnection | None = None, *, - licensed_item_checkout_id: LicensedItemCheckoutID, + license_checkout_id: LicenseCheckoutID, product_name: ProductName, stopped_at: datetime, -) -> LicensedItemCheckoutDB: +) -> LicenseCheckoutDB: update_stmt = ( - resource_tracker_licensed_items_checkouts.update() + resource_tracker_license_checkouts.update() .values( modified=sa.func.now(), stopped_at=stopped_at, ) .where( ( - resource_tracker_licensed_items_checkouts.c.licensed_item_checkout_id - == licensed_item_checkout_id + resource_tracker_license_checkouts.c.license_checkout_id + == license_checkout_id ) - & (resource_tracker_licensed_items_checkouts.c.product_name == product_name) - & (resource_tracker_licensed_items_checkouts.c.stopped_at.is_(None)) + & (resource_tracker_license_checkouts.c.product_name == product_name) + & (resource_tracker_license_checkouts.c.stopped_at.is_(None)) ) .returning(sa.literal_column("*")) ) @@ -188,30 +174,25 @@ async def update( result = await conn.execute(update_stmt) row = result.first() if row is None: - raise LicensedItemCheckoutNotFoundError( - licensed_item_checkout_id=licensed_item_checkout_id - ) - return LicensedItemCheckoutDB.model_validate(row) + raise LicenseCheckoutNotFoundError(license_checkout_id=license_checkout_id) + return LicenseCheckoutDB.model_validate(row) async def get_currently_used_seats_for_item_and_wallet( engine: AsyncEngine, connection: AsyncConnection | None = None, *, - licensed_item_id: LicensedItemID, + license_id: LicenseID, wallet_id: WalletID, product_name: ProductName, ) -> int: sum_stmt = sa.select( - sa.func.sum(resource_tracker_licensed_items_checkouts.c.num_of_seats) + sa.func.sum(resource_tracker_license_checkouts.c.num_of_seats) ).where( - (resource_tracker_licensed_items_checkouts.c.wallet_id == wallet_id) - & ( - resource_tracker_licensed_items_checkouts.c.licensed_item_id - == licensed_item_id - ) - & (resource_tracker_licensed_items_checkouts.c.product_name == product_name) - & (resource_tracker_licensed_items_checkouts.c.stopped_at.is_(None)) + (resource_tracker_license_checkouts.c.wallet_id == wallet_id) + & (resource_tracker_license_checkouts.c.license_id == license_id) + & (resource_tracker_license_checkouts.c.product_name == product_name) + & (resource_tracker_license_checkouts.c.stopped_at.is_(None)) ) async with pass_or_acquire_connection(engine, connection) as conn: @@ -235,17 +216,14 @@ async def force_release_license_seats_by_run_id( Currently, this functionality is primarily used to handle the release of a single seat allocated to the VIP model. """ update_stmt = ( - resource_tracker_licensed_items_checkouts.update() + resource_tracker_license_checkouts.update() .values( modified=sa.func.now(), stopped_at=sa.func.now(), ) .where( - ( - resource_tracker_licensed_items_checkouts.c.service_run_id - == service_run_id - ) - & (resource_tracker_licensed_items_checkouts.c.stopped_at.is_(None)) + (resource_tracker_license_checkouts.c.service_run_id == service_run_id) + & (resource_tracker_license_checkouts.c.stopped_at.is_(None)) ) .returning(sa.literal_column("*")) ) diff --git a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/modules/db/licensed_items_purchases_db.py b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/modules/db/license_purchases_db.py similarity index 51% rename from services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/modules/db/licensed_items_purchases_db.py rename to services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/modules/db/license_purchases_db.py index 4c1daf581db..3af20041900 100644 --- a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/modules/db/licensed_items_purchases_db.py +++ b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/modules/db/license_purchases_db.py @@ -2,16 +2,14 @@ from typing import cast import sqlalchemy as sa -from models_library.licenses import LicensedItemID +from models_library.licenses import LicenseID from models_library.products import ProductName -from models_library.resource_tracker_licensed_items_purchases import ( - LicensedItemPurchaseID, -) +from models_library.resource_tracker_license_purchases import LicensePurchaseID from models_library.rest_ordering import OrderBy, OrderDirection from models_library.wallets import WalletID from pydantic import NonNegativeInt -from simcore_postgres_database.models.resource_tracker_licensed_items_purchases import ( - resource_tracker_licensed_items_purchases, +from simcore_postgres_database.models.resource_tracker_license_purchases import ( + resource_tracker_license_purchases, ) from simcore_postgres_database.utils_repos import ( pass_or_acquire_connection, @@ -19,30 +17,27 @@ ) from sqlalchemy.ext.asyncio import AsyncConnection, AsyncEngine -from ....exceptions.errors import LicensedItemPurchaseNotFoundError -from ....models.licensed_items_purchases import ( - CreateLicensedItemsPurchasesDB, - LicensedItemsPurchasesDB, -) +from ....exceptions.errors import LicensePurchaseNotFoundError +from ....models.license_purchases import CreateLicensesPurchasesDB, LicensesPurchasesDB _SELECTION_ARGS = ( - resource_tracker_licensed_items_purchases.c.licensed_item_purchase_id, - resource_tracker_licensed_items_purchases.c.product_name, - resource_tracker_licensed_items_purchases.c.licensed_item_id, - resource_tracker_licensed_items_purchases.c.wallet_id, - resource_tracker_licensed_items_purchases.c.wallet_name, - resource_tracker_licensed_items_purchases.c.pricing_unit_cost_id, - resource_tracker_licensed_items_purchases.c.pricing_unit_cost, - resource_tracker_licensed_items_purchases.c.start_at, - resource_tracker_licensed_items_purchases.c.expire_at, - resource_tracker_licensed_items_purchases.c.num_of_seats, - resource_tracker_licensed_items_purchases.c.purchased_by_user, - resource_tracker_licensed_items_purchases.c.user_email, - resource_tracker_licensed_items_purchases.c.purchased_at, - resource_tracker_licensed_items_purchases.c.modified, + resource_tracker_license_purchases.c.licensed_item_purchase_id, + resource_tracker_license_purchases.c.product_name, + resource_tracker_license_purchases.c.license_id, + resource_tracker_license_purchases.c.wallet_id, + resource_tracker_license_purchases.c.wallet_name, + resource_tracker_license_purchases.c.pricing_unit_cost_id, + resource_tracker_license_purchases.c.pricing_unit_cost, + resource_tracker_license_purchases.c.start_at, + resource_tracker_license_purchases.c.expire_at, + resource_tracker_license_purchases.c.num_of_seats, + resource_tracker_license_purchases.c.purchased_by_user, + resource_tracker_license_purchases.c.user_email, + resource_tracker_license_purchases.c.purchased_at, + resource_tracker_license_purchases.c.modified, ) -assert set(LicensedItemsPurchasesDB.model_fields) == { +assert set(LicensesPurchasesDB.model_fields) == { c.name for c in _SELECTION_ARGS } # nosec @@ -51,14 +46,14 @@ async def create( engine: AsyncEngine, connection: AsyncConnection | None = None, *, - data: CreateLicensedItemsPurchasesDB, -) -> LicensedItemsPurchasesDB: + data: CreateLicensesPurchasesDB, +) -> LicensesPurchasesDB: async with transaction_context(engine, connection) as conn: result = await conn.execute( - resource_tracker_licensed_items_purchases.insert() + resource_tracker_license_purchases.insert() .values( product_name=data.product_name, - licensed_item_id=data.licensed_item_id, + license_id=data.license_id, wallet_id=data.wallet_id, wallet_name=data.wallet_name, pricing_unit_cost_id=data.pricing_unit_cost_id, @@ -74,7 +69,7 @@ async def create( .returning(*_SELECTION_ARGS) ) row = result.first() - return LicensedItemsPurchasesDB.model_validate(row) + return LicensesPurchasesDB.model_validate(row) async def list_( @@ -86,16 +81,13 @@ async def list_( offset: NonNegativeInt, limit: NonNegativeInt, order_by: OrderBy, -) -> tuple[int, list[LicensedItemsPurchasesDB]]: +) -> tuple[int, list[LicensesPurchasesDB]]: base_query = ( sa.select(*_SELECTION_ARGS) - .select_from(resource_tracker_licensed_items_purchases) + .select_from(resource_tracker_license_purchases) .where( - (resource_tracker_licensed_items_purchases.c.product_name == product_name) - & ( - resource_tracker_licensed_items_purchases.c.wallet_id - == filter_wallet_id - ) + (resource_tracker_license_purchases.c.product_name == product_name) + & (resource_tracker_license_purchases.c.wallet_id == filter_wallet_id) ) ) @@ -106,13 +98,11 @@ async def list_( # Ordering and pagination if order_by.direction == OrderDirection.ASC: list_query = base_query.order_by( - sa.asc(getattr(resource_tracker_licensed_items_purchases.c, order_by.field)) + sa.asc(getattr(resource_tracker_license_purchases.c, order_by.field)) ) else: list_query = base_query.order_by( - sa.desc( - getattr(resource_tracker_licensed_items_purchases.c, order_by.field) - ) + sa.desc(getattr(resource_tracker_license_purchases.c, order_by.field)) ) list_query = list_query.offset(offset).limit(limit) @@ -122,8 +112,8 @@ async def list_( total_count = 0 result = await conn.stream(list_query) - items: list[LicensedItemsPurchasesDB] = [ - LicensedItemsPurchasesDB.model_validate(row) async for row in result + items: list[LicensesPurchasesDB] = [ + LicensesPurchasesDB.model_validate(row) async for row in result ] return cast(int, total_count), items @@ -133,18 +123,18 @@ async def get( engine: AsyncEngine, connection: AsyncConnection | None = None, *, - licensed_item_purchase_id: LicensedItemPurchaseID, + licensed_item_purchase_id: LicensePurchaseID, product_name: ProductName, -) -> LicensedItemsPurchasesDB: +) -> LicensesPurchasesDB: base_query = ( sa.select(*_SELECTION_ARGS) - .select_from(resource_tracker_licensed_items_purchases) + .select_from(resource_tracker_license_purchases) .where( ( - resource_tracker_licensed_items_purchases.c.licensed_item_purchase_id + resource_tracker_license_purchases.c.licensed_item_purchase_id == licensed_item_purchase_id ) - & (resource_tracker_licensed_items_purchases.c.product_name == product_name) + & (resource_tracker_license_purchases.c.product_name == product_name) ) ) @@ -152,17 +142,17 @@ async def get( result = await conn.stream(base_query) row = await result.first() if row is None: - raise LicensedItemPurchaseNotFoundError( + raise LicensePurchaseNotFoundError( licensed_item_purchase_id=licensed_item_purchase_id ) - return LicensedItemsPurchasesDB.model_validate(row) + return LicensesPurchasesDB.model_validate(row) async def get_active_purchased_seats_for_item_and_wallet( engine: AsyncEngine, connection: AsyncConnection | None = None, *, - licensed_item_id: LicensedItemID, + license_id: LicenseID, wallet_id: WalletID, product_name: ProductName, ) -> int: @@ -172,16 +162,13 @@ async def get_active_purchased_seats_for_item_and_wallet( _current_time = datetime.now(tz=UTC) sum_stmt = sa.select( - sa.func.sum(resource_tracker_licensed_items_purchases.c.num_of_seats) + sa.func.sum(resource_tracker_license_purchases.c.num_of_seats) ).where( - (resource_tracker_licensed_items_purchases.c.wallet_id == wallet_id) - & ( - resource_tracker_licensed_items_purchases.c.licensed_item_id - == licensed_item_id - ) - & (resource_tracker_licensed_items_purchases.c.product_name == product_name) - & (resource_tracker_licensed_items_purchases.c.start_at <= _current_time) - & (resource_tracker_licensed_items_purchases.c.expire_at >= _current_time) + (resource_tracker_license_purchases.c.wallet_id == wallet_id) + & (resource_tracker_license_purchases.c.license_id == license_id) + & (resource_tracker_license_purchases.c.product_name == product_name) + & (resource_tracker_license_purchases.c.start_at <= _current_time) + & (resource_tracker_license_purchases.c.expire_at >= _current_time) ) async with pass_or_acquire_connection(engine, connection) as conn: diff --git a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/process_message_running_service.py b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/process_message_running_service.py index b1d82d825b8..daff63b1e70 100644 --- a/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/process_message_running_service.py +++ b/services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/services/process_message_running_service.py @@ -35,7 +35,7 @@ ) from .modules.db import ( credit_transactions_db, - licensed_items_checkouts_db, + license_checkouts_db, pricing_plans_db, service_runs_db, ) @@ -277,7 +277,7 @@ async def _process_stop_event( running_service = await service_runs_db.update_service_run_stopped_at( db_engine, data=update_service_run_stopped_at ) - await licensed_items_checkouts_db.force_release_license_seats_by_run_id( + await license_checkouts_db.force_release_license_seats_by_run_id( db_engine, service_run_id=msg.service_run_id ) diff --git a/services/resource-usage-tracker/tests/unit/with_dbs/test_api_licensed_items_checkouts.py b/services/resource-usage-tracker/tests/unit/with_dbs/test_api_license_checkouts.py similarity index 66% rename from services/resource-usage-tracker/tests/unit/with_dbs/test_api_licensed_items_checkouts.py rename to services/resource-usage-tracker/tests/unit/with_dbs/test_api_license_checkouts.py index b1036c49aef..d72679922ff 100644 --- a/services/resource-usage-tracker/tests/unit/with_dbs/test_api_licensed_items_checkouts.py +++ b/services/resource-usage-tracker/tests/unit/with_dbs/test_api_license_checkouts.py @@ -10,20 +10,18 @@ import pytest import sqlalchemy as sa -from models_library.api_schemas_resource_usage_tracker.licensed_items_checkouts import ( - LicensedItemCheckoutGet, - LicensedItemsCheckoutsPage, -) -from models_library.resource_tracker_licensed_items_purchases import ( - LicensedItemsPurchasesCreate, +from models_library.api_schemas_resource_usage_tracker.license_checkouts import ( + LicenseCheckoutGet, + LicenseCheckoutsPage, ) +from models_library.resource_tracker_license_purchases import LicensePurchasesCreate from servicelib.rabbitmq import RabbitMQRPCClient from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker import ( - licensed_items_checkouts, - licensed_items_purchases, + license_checkouts, + license_purchases, ) -from simcore_postgres_database.models.resource_tracker_licensed_items_checkouts import ( - resource_tracker_licensed_items_checkouts, +from simcore_postgres_database.models.resource_tracker_license_checkouts import ( + resource_tracker_license_checkouts, ) from simcore_postgres_database.models.resource_tracker_service_runs import ( resource_tracker_service_runs, @@ -61,17 +59,17 @@ def resource_tracker_service_run_id( yield row[0] - con.execute(resource_tracker_licensed_items_checkouts.delete()) + con.execute(resource_tracker_license_checkouts.delete()) con.execute(resource_tracker_service_runs.delete()) -async def test_rpc_licensed_items_checkouts_workflow( +async def test_rpc_license_checkouts_workflow( mocked_redis_server: None, resource_tracker_service_run_id: str, rpc_client: RabbitMQRPCClient, ): # List licensed items checkouts - output = await licensed_items_checkouts.get_licensed_items_checkouts_page( + output = await license_checkouts.get_license_checkouts_page( rpc_client, product_name="osparc", filter_wallet_id=_WALLET_ID, @@ -80,9 +78,9 @@ async def test_rpc_licensed_items_checkouts_workflow( assert output.items == [] # Purchase license item - _create_data = LicensedItemsPurchasesCreate( + _create_data = LicensePurchasesCreate( product_name="osparc", - licensed_item_id="beb16d18-d57d-44aa-a638-9727fa4a72ef", + license_id="beb16d18-d57d-44aa-a638-9727fa4a72ef", wallet_id=_WALLET_ID, wallet_name="My Wallet", pricing_plan_id=1, @@ -96,14 +94,14 @@ async def test_rpc_licensed_items_checkouts_workflow( user_email="test@test.com", purchased_at=datetime.now(tz=UTC), ) - created_item = await licensed_items_purchases.create_licensed_item_purchase( + created_item = await license_purchases.create_license_purchase( rpc_client, data=_create_data ) # Checkout with num of seats - checkout = await licensed_items_checkouts.checkout_licensed_item( + checkout = await license_checkouts.checkout_license( rpc_client, - licensed_item_id=created_item.licensed_item_id, + license_id=created_item.license_id, wallet_id=_WALLET_ID, product_name="osparc", num_of_seats=3, @@ -113,26 +111,26 @@ async def test_rpc_licensed_items_checkouts_workflow( ) # List licensed items checkouts - output = await licensed_items_checkouts.get_licensed_items_checkouts_page( + output = await license_checkouts.get_license_checkouts_page( rpc_client, product_name="osparc", filter_wallet_id=_WALLET_ID, ) assert output.total == 1 - assert isinstance(output, LicensedItemsCheckoutsPage) + assert isinstance(output, LicenseCheckoutsPage) # Get licensed items checkouts - output = await licensed_items_checkouts.get_licensed_item_checkout( + output = await license_checkouts.get_license_checkout( rpc_client, product_name="osparc", - licensed_item_checkout_id=output.items[0].licensed_item_checkout_id, + license_checkout_id=output.items[0].license_checkout_id, ) - assert isinstance(output, LicensedItemCheckoutGet) + assert isinstance(output, LicenseCheckoutGet) # Release num of seats - license_item_checkout = await licensed_items_checkouts.release_licensed_item( + license_item_checkout = await license_checkouts.release_license( rpc_client, - licensed_item_checkout_id=checkout.licensed_item_checkout_id, + license_checkout_id=checkout.license_checkout_id, product_name="osparc", ) assert license_item_checkout diff --git a/services/resource-usage-tracker/tests/unit/with_dbs/test_api_licensed_items_purchases.py b/services/resource-usage-tracker/tests/unit/with_dbs/test_api_license_purchases.py similarity index 59% rename from services/resource-usage-tracker/tests/unit/with_dbs/test_api_licensed_items_purchases.py rename to services/resource-usage-tracker/tests/unit/with_dbs/test_api_license_purchases.py index e5920728d3c..d100faa1125 100644 --- a/services/resource-usage-tracker/tests/unit/with_dbs/test_api_licensed_items_purchases.py +++ b/services/resource-usage-tracker/tests/unit/with_dbs/test_api_license_purchases.py @@ -7,17 +7,13 @@ from decimal import Decimal import sqlalchemy as sa -from models_library.api_schemas_resource_usage_tracker.licensed_items_purchases import ( - LicensedItemPurchaseGet, - LicensedItemsPurchasesPage, -) -from models_library.resource_tracker_licensed_items_purchases import ( - LicensedItemsPurchasesCreate, +from models_library.api_schemas_resource_usage_tracker.license_purchases import ( + LicensePurchaseGet, + LicensesPurchasesPage, ) +from models_library.resource_tracker_license_purchases import LicensePurchasesCreate from servicelib.rabbitmq import RabbitMQRPCClient -from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker import ( - licensed_items_purchases, -) +from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker import license_purchases pytest_simcore_core_services_selection = [ "postgres", @@ -28,21 +24,21 @@ ] -async def test_rpc_licensed_items_purchases_workflow( +async def test_rpc_license_purchases_workflow( mocked_redis_server: None, postgres_db: sa.engine.Engine, rpc_client: RabbitMQRPCClient, ): - result = await licensed_items_purchases.get_licensed_items_purchases_page( + result = await license_purchases.get_license_purchases_page( rpc_client, product_name="osparc", wallet_id=1 ) - assert isinstance(result, LicensedItemsPurchasesPage) # nosec + assert isinstance(result, LicensesPurchasesPage) # nosec assert result.items == [] assert result.total == 0 - _create_data = LicensedItemsPurchasesCreate( + _create_data = LicensePurchasesCreate( product_name="osparc", - licensed_item_id="beb16d18-d57d-44aa-a638-9727fa4a72ef", + license_id="beb16d18-d57d-44aa-a638-9727fa4a72ef", wallet_id=1, wallet_name="My Wallet", pricing_plan_id=1, @@ -57,22 +53,22 @@ async def test_rpc_licensed_items_purchases_workflow( purchased_at=datetime.now(tz=UTC), ) - created_item = await licensed_items_purchases.create_licensed_item_purchase( + created_item = await license_purchases.create_license_purchase( rpc_client, data=_create_data ) - assert isinstance(created_item, LicensedItemPurchaseGet) # nosec + assert isinstance(created_item, LicensePurchaseGet) # nosec - result = await licensed_items_purchases.get_licensed_item_purchase( + result = await license_purchases.get_license_purchase( rpc_client, product_name="osparc", licensed_item_purchase_id=created_item.licensed_item_purchase_id, ) - assert isinstance(result, LicensedItemPurchaseGet) # nosec + assert isinstance(result, LicensePurchaseGet) # nosec assert result.licensed_item_purchase_id == created_item.licensed_item_purchase_id - result = await licensed_items_purchases.get_licensed_items_purchases_page( + result = await license_purchases.get_license_purchases_page( rpc_client, product_name="osparc", wallet_id=_create_data.wallet_id ) - assert isinstance(result, LicensedItemsPurchasesPage) # nosec + assert isinstance(result, LicensesPurchasesPage) # nosec assert len(result.items) == 1 assert result.total == 1 diff --git a/services/resource-usage-tracker/tests/unit/with_dbs/test_licensed_items_checkouts_db.py b/services/resource-usage-tracker/tests/unit/with_dbs/test_license_checkouts_db.py similarity index 71% rename from services/resource-usage-tracker/tests/unit/with_dbs/test_licensed_items_checkouts_db.py rename to services/resource-usage-tracker/tests/unit/with_dbs/test_license_checkouts_db.py index 5f0fc5a1f5b..703459340b8 100644 --- a/services/resource-usage-tracker/tests/unit/with_dbs/test_licensed_items_checkouts_db.py +++ b/services/resource-usage-tracker/tests/unit/with_dbs/test_license_checkouts_db.py @@ -12,17 +12,17 @@ import sqlalchemy as sa from models_library.basic_types import IDStr from models_library.rest_ordering import OrderBy -from simcore_postgres_database.models.resource_tracker_licensed_items_checkouts import ( - resource_tracker_licensed_items_checkouts, +from simcore_postgres_database.models.resource_tracker_license_checkouts import ( + resource_tracker_license_checkouts, ) from simcore_postgres_database.models.resource_tracker_service_runs import ( resource_tracker_service_runs, ) -from simcore_service_resource_usage_tracker.models.licensed_items_checkouts import ( - CreateLicensedItemCheckoutDB, +from simcore_service_resource_usage_tracker.models.license_checkouts import ( + CreateLicenseCheckoutDB, ) from simcore_service_resource_usage_tracker.services.modules.db import ( - licensed_items_checkouts_db, + license_checkouts_db, ) pytest_simcore_core_services_selection = [ @@ -56,11 +56,11 @@ def resource_tracker_service_run_id( yield row[0] - con.execute(resource_tracker_licensed_items_checkouts.delete()) + con.execute(resource_tracker_license_checkouts.delete()) con.execute(resource_tracker_service_runs.delete()) -async def test_licensed_items_checkouts_db__force_release_license_seats_by_run_id( +async def test_license_checkouts_db__force_release_license_seats_by_run_id( mocked_redis_server: None, mocked_setup_rabbitmq: mock.Mock, resource_tracker_service_run_id, @@ -69,8 +69,8 @@ async def test_licensed_items_checkouts_db__force_release_license_seats_by_run_i engine = initialized_app.state.engine # SETUP - _create_license_item_checkout_db_1 = CreateLicensedItemCheckoutDB( - licensed_item_id="beb16d18-d57d-44aa-a638-9727fa4a72ef", + _create_license_item_checkout_db_1 = CreateLicenseCheckoutDB( + license_id="beb16d18-d57d-44aa-a638-9727fa4a72ef", wallet_id=_WALLET_ID, user_id=_USER_ID_1, user_email="test@test.com", @@ -79,47 +79,45 @@ async def test_licensed_items_checkouts_db__force_release_license_seats_by_run_i started_at=datetime.now(tz=UTC), num_of_seats=1, ) - await licensed_items_checkouts_db.create( - engine, data=_create_license_item_checkout_db_1 - ) + await license_checkouts_db.create(engine, data=_create_license_item_checkout_db_1) _create_license_item_checkout_db_2 = _create_license_item_checkout_db_1.model_dump() _create_license_item_checkout_db_2[ - "licensed_item_id" + "license_id" ] = "b1b96583-333f-44d6-b1e0-5c0a8af555bf" - await licensed_items_checkouts_db.create( + await license_checkouts_db.create( engine, - data=CreateLicensedItemCheckoutDB.model_construct( + data=CreateLicenseCheckoutDB.model_construct( **_create_license_item_checkout_db_2 ), ) _create_license_item_checkout_db_3 = _create_license_item_checkout_db_1.model_dump() _create_license_item_checkout_db_3[ - "licensed_item_id" + "license_id" ] = "38a5ce59-876f-482a-ace1-d3b2636feac6" - checkout = await licensed_items_checkouts_db.create( + checkout = await license_checkouts_db.create( engine, - data=CreateLicensedItemCheckoutDB.model_construct( + data=CreateLicenseCheckoutDB.model_construct( **_create_license_item_checkout_db_3 ), ) _helper_time = datetime.now(UTC) - await licensed_items_checkouts_db.update( + await license_checkouts_db.update( engine, - licensed_item_checkout_id=checkout.licensed_item_checkout_id, + license_checkout_id=checkout.license_checkout_id, product_name="osparc", stopped_at=_helper_time, ) # TEST FORCE RELEASE LICENSE SEATS - await licensed_items_checkouts_db.force_release_license_seats_by_run_id( + await license_checkouts_db.force_release_license_seats_by_run_id( engine, service_run_id=resource_tracker_service_run_id ) # ASSERT - total, items = await licensed_items_checkouts_db.list_( + total, items = await license_checkouts_db.list_( engine, product_name="osparc", filter_wallet_id=_WALLET_ID, diff --git a/services/web/server/src/simcore_service_webserver/licenses/_common/models.py b/services/web/server/src/simcore_service_webserver/licenses/_common/models.py index 94a74d686f4..4d212da29f1 100644 --- a/services/web/server/src/simcore_service_webserver/licenses/_common/models.py +++ b/services/web/server/src/simcore_service_webserver/licenses/_common/models.py @@ -1,9 +1,7 @@ from models_library.basic_types import IDStr from models_library.licenses import LicensedItemID from models_library.resource_tracker import PricingPlanId, PricingUnitId -from models_library.resource_tracker_licensed_items_purchases import ( - LicensedItemPurchaseID, -) +from models_library.resource_tracker_license_purchases import LicensePurchaseID from models_library.rest_base import RequestParameters, StrictRequestParameters from models_library.rest_ordering import ( OrderBy, @@ -57,7 +55,7 @@ class LicensedItemsBodyParams(BaseModel): class LicensedItemsPurchasesPathParams(StrictRequestParameters): - licensed_item_purchase_id: LicensedItemPurchaseID + licensed_item_purchase_id: LicensePurchaseID _LicensedItemsPurchasesListOrderQueryParams: type[ diff --git a/services/web/server/src/simcore_service_webserver/licenses/_licensed_items_checkouts_models.py b/services/web/server/src/simcore_service_webserver/licenses/_licensed_items_checkouts_models.py index 19b72835d0e..2d53d8dd80f 100644 --- a/services/web/server/src/simcore_service_webserver/licenses/_licensed_items_checkouts_models.py +++ b/services/web/server/src/simcore_service_webserver/licenses/_licensed_items_checkouts_models.py @@ -4,9 +4,7 @@ from models_library.basic_types import IDStr from models_library.licenses import LicensedItemID from models_library.products import ProductName -from models_library.resource_tracker_licensed_items_checkouts import ( - LicensedItemCheckoutID, -) +from models_library.resource_tracker_license_checkouts import LicenseCheckoutID from models_library.rest_base import RequestParameters, StrictRequestParameters from models_library.rest_ordering import ( OrderBy, @@ -20,7 +18,7 @@ class LicensedItemCheckoutGet(BaseModel): - licensed_item_checkout_id: LicensedItemCheckoutID + licensed_item_checkout_id: LicenseCheckoutID licensed_item_id: LicensedItemID wallet_id: WalletID user_id: UserID @@ -37,7 +35,7 @@ class LicensedItemCheckoutGetPage(NamedTuple): class LicensedItemCheckoutPathParams(StrictRequestParameters): - licensed_item_checkout_id: LicensedItemCheckoutID + licensed_item_checkout_id: LicenseCheckoutID _LicensedItemsCheckoutsListOrderQueryParams: type[ diff --git a/services/web/server/src/simcore_service_webserver/licenses/_licensed_items_checkouts_service.py b/services/web/server/src/simcore_service_webserver/licenses/_licensed_items_checkouts_service.py index 14959d241d1..4d7f005ee4c 100644 --- a/services/web/server/src/simcore_service_webserver/licenses/_licensed_items_checkouts_service.py +++ b/services/web/server/src/simcore_service_webserver/licenses/_licensed_items_checkouts_service.py @@ -1,19 +1,15 @@ from aiohttp import web from models_library.api_schemas_resource_usage_tracker import ( - licensed_items_checkouts as rut_licensed_items_checkouts, + license_checkouts as rut_license_checkouts, ) from models_library.licenses import LicensedItemID from models_library.products import ProductName -from models_library.resource_tracker_licensed_items_checkouts import ( - LicensedItemCheckoutID, -) +from models_library.resource_tracker_license_checkouts import LicenseCheckoutID from models_library.rest_ordering import OrderBy from models_library.services_types import ServiceRunID from models_library.users import UserID from models_library.wallets import WalletID -from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker import ( - licensed_items_checkouts, -) +from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker import license_checkouts from ..rabbitmq import get_rabbitmq_rpc_client from ..users.api import get_user @@ -45,7 +41,7 @@ async def list_licensed_items_checkouts_for_wallet( rpc_client = get_rabbitmq_rpc_client(app) - result = await licensed_items_checkouts.get_licensed_items_checkouts_page( + result = await license_checkouts.get_license_checkouts_page( rpc_client, product_name=product_name, filter_wallet_id=wallet_id, @@ -58,8 +54,8 @@ async def list_licensed_items_checkouts_for_wallet( total=result.total, items=[ LicensedItemCheckoutGet.model_construct( - licensed_item_checkout_id=checkout_item.licensed_item_checkout_id, - licensed_item_id=checkout_item.licensed_item_id, + licensed_item_checkout_id=checkout_item.license_checkout_id, # <-- mapping license_checkout_id <-> licensed_item_checkout_id + licensed_item_id=checkout_item.license_id, # <-- mapping license_id <-> licensed_item_id wallet_id=checkout_item.wallet_id, user_id=checkout_item.user_id, user_email=checkout_item.user_email, @@ -79,14 +75,14 @@ async def get_licensed_item_checkout( # access context product_name: ProductName, user_id: UserID, - licensed_item_checkout_id: LicensedItemCheckoutID, + licensed_item_checkout_id: LicenseCheckoutID, ) -> LicensedItemCheckoutGet: rpc_client = get_rabbitmq_rpc_client(app) - checkout_item = await licensed_items_checkouts.get_licensed_item_checkout( + checkout_item = await license_checkouts.get_license_checkout( rpc_client, product_name=product_name, - licensed_item_checkout_id=licensed_item_checkout_id, + license_checkout_id=licensed_item_checkout_id, ) # Check whether user has access to the wallet @@ -98,8 +94,8 @@ async def get_licensed_item_checkout( ) return LicensedItemCheckoutGet.model_construct( - licensed_item_checkout_id=checkout_item.licensed_item_checkout_id, - licensed_item_id=checkout_item.licensed_item_id, + licensed_item_checkout_id=checkout_item.license_checkout_id, + licensed_item_id=checkout_item.license_id, wallet_id=checkout_item.wallet_id, user_id=checkout_item.user_id, user_email=checkout_item.user_email, @@ -133,10 +129,10 @@ async def checkout_licensed_item_for_wallet( user = await get_user(app, user_id=user_id) rpc_client = get_rabbitmq_rpc_client(app) - licensed_item_get: rut_licensed_items_checkouts.LicensedItemCheckoutGet = ( - await licensed_items_checkouts.checkout_licensed_item( + licensed_item_get: rut_license_checkouts.LicenseCheckoutGet = ( + await license_checkouts.checkout_license( rpc_client, - licensed_item_id=licensed_item_id, + license_id=licensed_item_id, # <-- mapping license_id <-> licensed_item_id wallet_id=wallet_id, product_name=product_name, num_of_seats=num_of_seats, @@ -147,8 +143,8 @@ async def checkout_licensed_item_for_wallet( ) return LicensedItemCheckoutGet.model_construct( - licensed_item_checkout_id=licensed_item_get.licensed_item_checkout_id, - licensed_item_id=licensed_item_get.licensed_item_id, + licensed_item_checkout_id=licensed_item_get.license_checkout_id, # <-- mapping license_checkout_id <-> licensed_item_checkout_id + licensed_item_id=licensed_item_get.license_id, # <-- mapping license_id <-> licensed_item_id wallet_id=licensed_item_get.wallet_id, user_id=licensed_item_get.user_id, user_email=licensed_item_get.user_email, @@ -166,14 +162,14 @@ async def release_licensed_item_for_wallet( product_name: ProductName, user_id: UserID, # release args - licensed_item_checkout_id: LicensedItemCheckoutID, + licensed_item_checkout_id: LicenseCheckoutID, ) -> LicensedItemCheckoutGet: rpc_client = get_rabbitmq_rpc_client(app) - checkout_item = await licensed_items_checkouts.get_licensed_item_checkout( + checkout_item = await license_checkouts.get_license_checkout( rpc_client, product_name=product_name, - licensed_item_checkout_id=licensed_item_checkout_id, + license_checkout_id=licensed_item_checkout_id, # <-- mapping license_checkout_id <-> licensed_item_checkout_id ) # Check whether user has access to the wallet @@ -184,17 +180,15 @@ async def release_licensed_item_for_wallet( product_name=product_name, ) - licensed_item_get: rut_licensed_items_checkouts.LicensedItemCheckoutGet = ( - await licensed_items_checkouts.release_licensed_item( - rpc_client, - product_name=product_name, - licensed_item_checkout_id=licensed_item_checkout_id, - ) + licensed_item_get: rut_license_checkouts.LicenseCheckoutGet = await license_checkouts.release_license( + rpc_client, + product_name=product_name, + license_checkout_id=licensed_item_checkout_id, # <-- mapping license_checkout_id <-> licensed_item_checkout_id ) return LicensedItemCheckoutGet.model_construct( - licensed_item_checkout_id=licensed_item_get.licensed_item_checkout_id, - licensed_item_id=licensed_item_get.licensed_item_id, + licensed_item_checkout_id=licensed_item_get.license_checkout_id, # <-- mapping license_checkout_id <-> licensed_item_checkout_id + licensed_item_id=licensed_item_get.license_id, # <-- mapping license_id <-> licensed_item_id wallet_id=licensed_item_get.wallet_id, user_id=licensed_item_get.user_id, user_email=licensed_item_get.user_email, diff --git a/services/web/server/src/simcore_service_webserver/licenses/_licensed_items_purchases_service.py b/services/web/server/src/simcore_service_webserver/licenses/_licensed_items_purchases_service.py index d42ad904851..4d5d19b2702 100644 --- a/services/web/server/src/simcore_service_webserver/licenses/_licensed_items_purchases_service.py +++ b/services/web/server/src/simcore_service_webserver/licenses/_licensed_items_purchases_service.py @@ -2,21 +2,17 @@ from aiohttp import web from models_library.api_schemas_resource_usage_tracker import ( - licensed_items_purchases as rut_licensed_items_purchases, + license_purchases as rut_license_purchases, ) from models_library.api_schemas_webserver import ( licensed_items_purchases as webserver_licensed_items_purchases, ) from models_library.products import ProductName -from models_library.resource_tracker_licensed_items_purchases import ( - LicensedItemPurchaseID, -) +from models_library.resource_tracker_license_purchases import LicensePurchaseID from models_library.rest_ordering import OrderBy from models_library.users import UserID from models_library.wallets import WalletID -from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker import ( - licensed_items_purchases, -) +from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker import license_purchases from ..rabbitmq import get_rabbitmq_rpc_client from ..wallets.api import get_wallet_by_user @@ -41,8 +37,8 @@ async def list_licensed_items_purchases( ) rpc_client = get_rabbitmq_rpc_client(app) - result: rut_licensed_items_purchases.LicensedItemsPurchasesPage = ( - await licensed_items_purchases.get_licensed_items_purchases_page( + result: rut_license_purchases.LicensesPurchasesPage = ( + await license_purchases.get_license_purchases_page( rpc_client, product_name=product_name, wallet_id=wallet_id, @@ -57,7 +53,7 @@ async def list_licensed_items_purchases( webserver_licensed_items_purchases.LicensedItemPurchaseGet( licensed_item_purchase_id=item.licensed_item_purchase_id, product_name=item.product_name, - licensed_item_id=item.licensed_item_id, + licensed_item_id=item.license_id, # <-- mapping license_id <-> licensed_item_id wallet_id=item.wallet_id, pricing_unit_cost_id=item.pricing_unit_cost_id, pricing_unit_cost=item.pricing_unit_cost, @@ -79,14 +75,14 @@ async def get_licensed_item_purchase( *, product_name: ProductName, user_id: UserID, - licensed_item_purchase_id: LicensedItemPurchaseID, + licensed_item_purchase_id: LicensePurchaseID, ) -> webserver_licensed_items_purchases.LicensedItemPurchaseGet: rpc_client = get_rabbitmq_rpc_client(app) - licensed_item_get: rut_licensed_items_purchases.LicensedItemPurchaseGet = ( - await licensed_items_purchases.get_licensed_item_purchase( + licensed_item_get: rut_license_purchases.LicensePurchaseGet = ( + await license_purchases.get_license_purchase( rpc_client, product_name=product_name, - licensed_item_purchase_id=licensed_item_purchase_id, + licensed_purchase_id=licensed_item_purchase_id, ) ) diff --git a/services/web/server/src/simcore_service_webserver/licenses/_licensed_items_service.py b/services/web/server/src/simcore_service_webserver/licenses/_licensed_items_service.py index a44c25f89e0..3001fecd072 100644 --- a/services/web/server/src/simcore_service_webserver/licenses/_licensed_items_service.py +++ b/services/web/server/src/simcore_service_webserver/licenses/_licensed_items_service.py @@ -17,15 +17,11 @@ LicensedResourceType, ) from models_library.products import ProductName -from models_library.resource_tracker_licensed_items_purchases import ( - LicensedItemsPurchasesCreate, -) +from models_library.resource_tracker_license_purchases import LicensePurchasesCreate from models_library.rest_ordering import OrderBy from models_library.users import UserID from pydantic import BaseModel, NonNegativeInt -from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker import ( - licensed_items_purchases, -) +from servicelib.rabbitmq.rpc_interfaces.resource_usage_tracker import license_purchases from ..rabbitmq import get_rabbitmq_rpc_client from ..resource_usage.service import get_pricing_plan_unit @@ -241,9 +237,9 @@ async def purchase_licensed_item( user = await get_user(app, user_id=user_id) - _data = LicensedItemsPurchasesCreate( + _data = LicensePurchasesCreate( product_name=product_name, - licensed_item_id=licensed_item_id, + license_id=licensed_item_id, # <-- mapping license_id <-> licensed_item_id wallet_id=wallet.wallet_id, wallet_name=wallet.name, pricing_plan_id=body_params.pricing_plan_id, @@ -259,4 +255,4 @@ async def purchase_licensed_item( purchased_at=datetime.now(tz=UTC), ) rpc_client = get_rabbitmq_rpc_client(app) - await licensed_items_purchases.create_licensed_item_purchase(rpc_client, data=_data) + await license_purchases.create_license_purchase(rpc_client, data=_data) diff --git a/services/web/server/src/simcore_service_webserver/licenses/_rpc.py b/services/web/server/src/simcore_service_webserver/licenses/_rpc.py index 2646420bd49..648b1c20cfe 100644 --- a/services/web/server/src/simcore_service_webserver/licenses/_rpc.py +++ b/services/web/server/src/simcore_service_webserver/licenses/_rpc.py @@ -10,9 +10,7 @@ from models_library.basic_types import IDStr from models_library.licenses import LicensedItemID, LicensedItemPage from models_library.products import ProductName -from models_library.resource_tracker_licensed_items_checkouts import ( - LicensedItemCheckoutID, -) +from models_library.resource_tracker_license_checkouts import LicenseCheckoutID from models_library.rest_ordering import OrderBy from models_library.services_types import ServiceRunID from models_library.users import UserID @@ -22,7 +20,7 @@ LICENSES_ERRORS, CanNotCheckoutNotEnoughAvailableSeatsError, CanNotCheckoutServiceIsNotRunningError, - LicensedItemCheckoutNotFoundError, + LicenseCheckoutNotFoundError, NotEnoughAvailableSeatsError, ) @@ -121,13 +119,13 @@ async def checkout_licensed_item_for_wallet( ) -@router.expose(reraise_if_error_type=(LicensedItemCheckoutNotFoundError,)) +@router.expose(reraise_if_error_type=(LicenseCheckoutNotFoundError,)) async def release_licensed_item_for_wallet( app: web.Application, *, product_name: ProductName, user_id: UserID, - licensed_item_checkout_id: LicensedItemCheckoutID, + licensed_item_checkout_id: LicenseCheckoutID, ) -> LicensedItemCheckoutRpcGet: licensed_item_get = ( await _licensed_items_checkouts_service.release_licensed_item_for_wallet( diff --git a/services/web/server/tests/unit/with_dbs/04/licenses/test_licensed_items_checkouts_rest.py b/services/web/server/tests/unit/with_dbs/04/licenses/test_licensed_items_checkouts_rest.py index 1a6a81e76f4..03706e2d391 100644 --- a/services/web/server/tests/unit/with_dbs/04/licenses/test_licensed_items_checkouts_rest.py +++ b/services/web/server/tests/unit/with_dbs/04/licenses/test_licensed_items_checkouts_rest.py @@ -7,9 +7,9 @@ import pytest from aiohttp.test_utils import TestClient -from models_library.api_schemas_resource_usage_tracker.licensed_items_checkouts import ( - LicensedItemCheckoutGet, - LicensedItemsCheckoutsPage, +from models_library.api_schemas_resource_usage_tracker.license_checkouts import ( + LicenseCheckoutGet, + LicenseCheckoutsPage, ) from models_library.api_schemas_webserver.licensed_items_checkouts import ( LicensedItemCheckoutRestGet, @@ -20,11 +20,11 @@ from servicelib.aiohttp import status from simcore_service_webserver.db.models import UserRole -_LICENSED_ITEM_CHECKOUT_GET = LicensedItemCheckoutGet.model_validate( - LicensedItemCheckoutGet.model_config["json_schema_extra"]["examples"][0] +_LICENSED_ITEM_CHECKOUT_GET = LicenseCheckoutGet.model_validate( + LicenseCheckoutGet.model_config["json_schema_extra"]["examples"][0] ) -_LICENSED_ITEM_CHECKOUT_PAGE = LicensedItemsCheckoutsPage( +_LICENSED_ITEM_CHECKOUT_PAGE = LicenseCheckoutsPage( items=[_LICENSED_ITEM_CHECKOUT_GET], total=1, ) @@ -33,7 +33,7 @@ @pytest.fixture def mock_get_licensed_items_checkouts_page(mocker: MockerFixture) -> tuple: return mocker.patch( - "simcore_service_webserver.licenses._licensed_items_checkouts_service.licensed_items_checkouts.get_licensed_items_checkouts_page", + "simcore_service_webserver.licenses._licensed_items_checkouts_service.licensed_items_checkouts.get_license_checkouts_page", spec=True, return_value=_LICENSED_ITEM_CHECKOUT_PAGE, ) @@ -42,7 +42,7 @@ def mock_get_licensed_items_checkouts_page(mocker: MockerFixture) -> tuple: @pytest.fixture def mock_get_licensed_item_checkout(mocker: MockerFixture) -> tuple: return mocker.patch( - "simcore_service_webserver.licenses._licensed_items_checkouts_service.licensed_items_checkouts.get_licensed_item_checkout", + "simcore_service_webserver.licenses._licensed_items_checkouts_service.licensed_items_checkouts.get_license_checkouts_page", spec=True, return_value=_LICENSED_ITEM_CHECKOUT_GET, ) @@ -78,7 +78,7 @@ async def test_licensed_items_checkouts_handlers( # get url = client.app.router["get_licensed_item_checkout"].url_for( - licensed_item_checkout_id=f"{_LICENSED_ITEM_CHECKOUT_PAGE.items[0].licensed_item_checkout_id}" + licensed_item_checkout_id=f"{_LICENSED_ITEM_CHECKOUT_PAGE.items[0].license_checkout_id}" ) resp = await client.get(f"{url}") data, _ = await assert_status(resp, status.HTTP_200_OK)