diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ee1b6ad..b8891a89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,8 @@ - **Feature:** Add new methods to manage snapshots: `create_snapshot`, `delete_snapshot`, `get_snapshot`, `list_snapshot`, `update_snapshot` - `serverupdate`: [v0.1.1](services/serverupdate/CHANGELOG.md#v011-2024-12-23) - **Bugfix:** `Id` field of `Update` model is now of type `int64` (was `string`) +- `stackitmarketplace`: [v0.1.0](services/stackitmarketplace/CHANGELOG.md#v010-2025-01-13) + - **New**: STACKIT Marketplace module can be used to manage the STACKIT Marketplace. ## Release (2024-12-04) diff --git a/services/stackitmarketplace/CHANGELOG.md b/services/stackitmarketplace/CHANGELOG.md new file mode 100644 index 00000000..cc9ba7a4 --- /dev/null +++ b/services/stackitmarketplace/CHANGELOG.md @@ -0,0 +1,3 @@ +## v0.1.0 (2025-01-13) + + - **New**: STACKIT Marketplace module can be used to manage the STACKIT Marketplace. diff --git a/services/stackitmarketplace/README.md b/services/stackitmarketplace/README.md new file mode 100644 index 00000000..f3b4cedb --- /dev/null +++ b/services/stackitmarketplace/README.md @@ -0,0 +1,22 @@ +# stackit.stackitmarketplace +API to manage STACKIT Marketplace. + + +This package is part of the STACKIT Python SDK. For additional information, please visit the [GitHub repository](https://github.com/stackitcloud/stackit-sdk-python) of the SDK. + + +## Installation & Usage +### pip install + +```sh +pip install stackit-stackitmarketplace +``` + +Then import the package: +```python +import stackit.stackitmarketplace +``` + +## Getting Started + +[Examples](https://github.com/stackitcloud/stackit-sdk-python/tree/main/examples) for the usage of the package can be found in the [GitHub repository](https://github.com/stackitcloud/stackit-sdk-python) of the SDK. \ No newline at end of file diff --git a/services/stackitmarketplace/pyproject.toml b/services/stackitmarketplace/pyproject.toml new file mode 100644 index 00000000..fcda5781 --- /dev/null +++ b/services/stackitmarketplace/pyproject.toml @@ -0,0 +1,108 @@ +[project] +name = "stackit-stackitmarketplace" + +[tool.poetry] +name = "stackit-stackitmarketplace" +version = "v0.1.0" +authors = [ + "STACKIT Developer Tools ", +] +description = "STACKIT Marketplace API" +readme = "README.md" +#license = "NoLicense" +classifiers = [ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", +] +packages = [ + { include = "stackit", from="src" } +] + +[tool.poetry.dependencies] +python = ">=3.8,<4.0" +stackit-core = ">=0.0.1a" +requests = ">=2.32.3" +pydantic = ">=2.9.2" +python-dateutil = ">=2.9.0.post0" + +[tool.poetry.group.dev.dependencies] +black = ">=24.8.0" +pytest = ">=8.3.3" +flake8 = [ + { version= ">=5.0.3", python="<3.12"}, + { version= ">=6.0.1", python=">=3.12"} +] +flake8-black = ">=0.3.6" +flake8-pyproject = ">=1.2.3" +autoimport = ">=1.6.1" +flake8-eol = ">=0.0.8" +flake8-eradicate = ">=1.5.0" +flake8-bandit = ">=4.1.1" +flake8-bugbear = ">=23.1.14" +flake8-quotes = ">=3.4.0" +isort = ">=5.13.2" + +[project.urls] +Homepage = "https://github.com/stackitcloud/stackit-sdk-python" +Issues = "https://github.com/stackitcloud/stackit-sdk-python/issues" + +[build-system] +requires = ["setuptools", "poetry-core"] +build-backend = "poetry.core.masonry.api" + +[tool.pytest.ini_options] +pythonpath = [ + "src" +] +testpaths = [ + "tests" +] + +[tool.black] +line-length = 120 +exclude = """ +/( + .eggs + | .git + | .hg + | .mypy_cache + | .nox + | .pants.d + | .tox + | .venv + | _build + | buck-out + | build + | dist + | node_modules + | venv +)/ +""" + +[tool.isort] +profile = 'black' + +[tool.flake8] +exclude= [".eggs", ".git", ".hg", ".mypy_cache", ".tox", ".venv", ".devcontainer", "venv", "_build", "buck-out", "build", "dist"] +statistics = true +show-source = false +max-line-length = 120 +# E203,W503 and E704 are incompatible with the formatter black +# W291 needs to be disabled because some doc-strings get generated with trailing whitespace but black won't re-format comments +ignore = ["E203", "W503", "E704", "W291"] +inline-quotes = '"' +docstring-quotes = '"""' +multiline-quotes = '"""' +ban-relative-imports = true +per-file-ignores = """ + # asserts are fine in tests, tests shouldn't be build optimized + ./tests/*: S101, + # F841: some variables get generated but may not be used, depending on the api-spec + # E501: long descriptions/string values might lead to lines that are too long + ./src/stackit/*/models/*: F841,E501 + # F841: some variables get generated but may not be used, depending on the api-spec + # E501: long descriptions/string values might lead to lines that are too long + # B028: stacklevel for deprecation warning is irrelevant + ./src/stackit/*/api/default_api.py: F841,B028,E501 +""" \ No newline at end of file diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/__init__.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/__init__.py new file mode 100644 index 00000000..e1f15fc6 --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/__init__.py @@ -0,0 +1,84 @@ +# coding: utf-8 + +# flake8: noqa + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + + +__version__ = "1.0.0" + +# import apis into sdk package +from stackit.stackitmarketplace.api.default_api import DefaultApi +from stackit.stackitmarketplace.api_client import ApiClient + +# import ApiClient +from stackit.stackitmarketplace.api_response import ApiResponse +from stackit.stackitmarketplace.configuration import HostConfiguration +from stackit.stackitmarketplace.exceptions import ( + ApiAttributeError, + ApiException, + ApiKeyError, + ApiTypeError, + ApiValueError, + OpenApiException, +) + +# import models into sdk package +from stackit.stackitmarketplace.models.catalog_pricing_option_highlight import ( + CatalogPricingOptionHighlight, +) +from stackit.stackitmarketplace.models.catalog_product_detail import ( + CatalogProductDetail, +) +from stackit.stackitmarketplace.models.catalog_product_details_vendor import ( + CatalogProductDetailsVendor, +) +from stackit.stackitmarketplace.models.catalog_product_highlight import ( + CatalogProductHighlight, +) +from stackit.stackitmarketplace.models.catalog_product_overview import ( + CatalogProductOverview, +) +from stackit.stackitmarketplace.models.catalog_product_overview_vendor import ( + CatalogProductOverviewVendor, +) +from stackit.stackitmarketplace.models.catalog_product_pricing_option import ( + CatalogProductPricingOption, +) +from stackit.stackitmarketplace.models.catalog_product_support_resource import ( + CatalogProductSupportResource, +) +from stackit.stackitmarketplace.models.catalog_product_vendor_terms import ( + CatalogProductVendorTerms, +) +from stackit.stackitmarketplace.models.current_subscription_state_response import ( + CurrentSubscriptionStateResponse, +) +from stackit.stackitmarketplace.models.error_response import ErrorResponse +from stackit.stackitmarketplace.models.list_catalog_products_response import ( + ListCatalogProductsResponse, +) +from stackit.stackitmarketplace.models.list_vendor_subscriptions_response import ( + ListVendorSubscriptionsResponse, +) +from stackit.stackitmarketplace.models.requested_subscription_state_response import ( + RequestedSubscriptionStateResponse, +) +from stackit.stackitmarketplace.models.resolve_customer_payload import ( + ResolveCustomerPayload, +) +from stackit.stackitmarketplace.models.subscription_cancel_response import ( + SubscriptionCancelResponse, +) +from stackit.stackitmarketplace.models.subscription_product import SubscriptionProduct +from stackit.stackitmarketplace.models.vendor_subscription import VendorSubscription diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/api/__init__.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/api/__init__.py new file mode 100644 index 00000000..9d8e0e21 --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/api/__init__.py @@ -0,0 +1,4 @@ +# flake8: noqa + +# import apis into api package +from stackit.stackitmarketplace.api.default_api import DefaultApi diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/api/default_api.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/api/default_api.py new file mode 100644 index 00000000..c004d0df --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/api/default_api.py @@ -0,0 +1,1719 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from typing import Any, Dict, List, Optional, Tuple, Union + +from pydantic import ( + Field, + StrictFloat, + StrictInt, + StrictStr, + validate_call, +) +from stackit.core.configuration import Configuration +from typing_extensions import Annotated + +from stackit.stackitmarketplace.api_client import ApiClient, RequestSerialized +from stackit.stackitmarketplace.api_response import ApiResponse +from stackit.stackitmarketplace.models.catalog_product_detail import ( + CatalogProductDetail, +) +from stackit.stackitmarketplace.models.list_catalog_products_response import ( + ListCatalogProductsResponse, +) +from stackit.stackitmarketplace.models.list_vendor_subscriptions_response import ( + ListVendorSubscriptionsResponse, +) +from stackit.stackitmarketplace.models.resolve_customer_payload import ( + ResolveCustomerPayload, +) +from stackit.stackitmarketplace.models.vendor_subscription import VendorSubscription +from stackit.stackitmarketplace.rest import RESTResponseType + + +class DefaultApi: + """NOTE: This class is auto generated by OpenAPI Generator + Ref: https://openapi-generator.tech + + Do not edit the class manually. + """ + + def __init__(self, configuration: Configuration = None) -> None: + if configuration is None: + configuration = Configuration() + self.configuration = configuration + self.api_client = ApiClient(self.configuration) + + @validate_call + def approve_subscription( + self, + project_id: Annotated[StrictStr, Field(description="The project ID.")], + subscription_id: Annotated[StrictStr, Field(description="The subscription ID.")], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> None: + """Approve a subscription + + Approve a pending subscription. + + :param project_id: The project ID. (required) + :type project_id: str + :param subscription_id: The subscription ID. (required) + :type subscription_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 docstring might be too long + + _param = self._approve_subscription_serialize( + project_id=project_id, + subscription_id=subscription_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "204": None, + "400": "ErrorResponse", + "401": "ErrorResponse", + "403": "ErrorResponse", + "404": "ErrorResponse", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + @validate_call + def approve_subscription_with_http_info( + self, + project_id: Annotated[StrictStr, Field(description="The project ID.")], + subscription_id: Annotated[StrictStr, Field(description="The subscription ID.")], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[None]: + """Approve a subscription + + Approve a pending subscription. + + :param project_id: The project ID. (required) + :type project_id: str + :param subscription_id: The subscription ID. (required) + :type subscription_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 docstring might be too long + + _param = self._approve_subscription_serialize( + project_id=project_id, + subscription_id=subscription_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "204": None, + "400": "ErrorResponse", + "401": "ErrorResponse", + "403": "ErrorResponse", + "404": "ErrorResponse", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + @validate_call + def approve_subscription_without_preload_content( + self, + project_id: Annotated[StrictStr, Field(description="The project ID.")], + subscription_id: Annotated[StrictStr, Field(description="The subscription ID.")], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Approve a subscription + + Approve a pending subscription. + + :param project_id: The project ID. (required) + :type project_id: str + :param subscription_id: The subscription ID. (required) + :type subscription_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 docstring might be too long + + _param = self._approve_subscription_serialize( + project_id=project_id, + subscription_id=subscription_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "204": None, + "400": "ErrorResponse", + "401": "ErrorResponse", + "403": "ErrorResponse", + "404": "ErrorResponse", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + return response_data.response + + def _approve_subscription_serialize( + self, + project_id, + subscription_id, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = {} + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[str, Union[str, bytes]] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if project_id is not None: + _path_params["projectId"] = project_id + if subscription_id is not None: + _path_params["subscriptionId"] = subscription_id + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + + # set the HTTP header `Accept` + if "Accept" not in _header_params: + _header_params["Accept"] = self.api_client.select_header_accept(["application/json"]) + + # authentication setting + _auth_settings: List[str] = [] + + return self.api_client.param_serialize( + method="POST", + resource_path="/v1/vendors/projects/{projectId}/subscriptions/{subscriptionId}/approve", + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth, + ) + + @validate_call + def get_catalog_product( + self, + product_id: Annotated[StrictStr, Field(description="The product ID.")], + locale: Annotated[Optional[StrictStr], Field(description="The language of the response.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> CatalogProductDetail: + """Get a product + + Get a product. + + :param product_id: The product ID. (required) + :type product_id: str + :param locale: The language of the response. + :type locale: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 docstring might be too long + + _param = self._get_catalog_product_serialize( + product_id=product_id, + locale=locale, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "200": "CatalogProductDetail", + "400": "ErrorResponse", + "401": "ErrorResponse", + "403": "ErrorResponse", + "404": "ErrorResponse", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + @validate_call + def get_catalog_product_with_http_info( + self, + product_id: Annotated[StrictStr, Field(description="The product ID.")], + locale: Annotated[Optional[StrictStr], Field(description="The language of the response.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[CatalogProductDetail]: + """Get a product + + Get a product. + + :param product_id: The product ID. (required) + :type product_id: str + :param locale: The language of the response. + :type locale: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 docstring might be too long + + _param = self._get_catalog_product_serialize( + product_id=product_id, + locale=locale, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "200": "CatalogProductDetail", + "400": "ErrorResponse", + "401": "ErrorResponse", + "403": "ErrorResponse", + "404": "ErrorResponse", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + @validate_call + def get_catalog_product_without_preload_content( + self, + product_id: Annotated[StrictStr, Field(description="The product ID.")], + locale: Annotated[Optional[StrictStr], Field(description="The language of the response.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Get a product + + Get a product. + + :param product_id: The product ID. (required) + :type product_id: str + :param locale: The language of the response. + :type locale: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 docstring might be too long + + _param = self._get_catalog_product_serialize( + product_id=product_id, + locale=locale, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "200": "CatalogProductDetail", + "400": "ErrorResponse", + "401": "ErrorResponse", + "403": "ErrorResponse", + "404": "ErrorResponse", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + return response_data.response + + def _get_catalog_product_serialize( + self, + product_id, + locale, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = {} + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[str, Union[str, bytes]] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if product_id is not None: + _path_params["productId"] = product_id + # process the query parameters + if locale is not None: + + _query_params.append(("locale", locale)) + + # process the header parameters + # process the form parameters + # process the body parameter + + # set the HTTP header `Accept` + if "Accept" not in _header_params: + _header_params["Accept"] = self.api_client.select_header_accept(["application/json"]) + + # authentication setting + _auth_settings: List[str] = [] + + return self.api_client.param_serialize( + method="GET", + resource_path="/v1/catalog/products/{productId}", + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth, + ) + + @validate_call + def get_vendor_subscription( + self, + project_id: Annotated[StrictStr, Field(description="The project ID.")], + subscription_id: Annotated[StrictStr, Field(description="The subscription ID.")], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> VendorSubscription: + """Get a subscription + + Get a subscription. + + :param project_id: The project ID. (required) + :type project_id: str + :param subscription_id: The subscription ID. (required) + :type subscription_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 docstring might be too long + + _param = self._get_vendor_subscription_serialize( + project_id=project_id, + subscription_id=subscription_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "200": "VendorSubscription", + "400": "ErrorResponse", + "401": "ErrorResponse", + "403": "ErrorResponse", + "404": "ErrorResponse", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + @validate_call + def get_vendor_subscription_with_http_info( + self, + project_id: Annotated[StrictStr, Field(description="The project ID.")], + subscription_id: Annotated[StrictStr, Field(description="The subscription ID.")], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[VendorSubscription]: + """Get a subscription + + Get a subscription. + + :param project_id: The project ID. (required) + :type project_id: str + :param subscription_id: The subscription ID. (required) + :type subscription_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 docstring might be too long + + _param = self._get_vendor_subscription_serialize( + project_id=project_id, + subscription_id=subscription_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "200": "VendorSubscription", + "400": "ErrorResponse", + "401": "ErrorResponse", + "403": "ErrorResponse", + "404": "ErrorResponse", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + @validate_call + def get_vendor_subscription_without_preload_content( + self, + project_id: Annotated[StrictStr, Field(description="The project ID.")], + subscription_id: Annotated[StrictStr, Field(description="The subscription ID.")], + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Get a subscription + + Get a subscription. + + :param project_id: The project ID. (required) + :type project_id: str + :param subscription_id: The subscription ID. (required) + :type subscription_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 docstring might be too long + + _param = self._get_vendor_subscription_serialize( + project_id=project_id, + subscription_id=subscription_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "200": "VendorSubscription", + "400": "ErrorResponse", + "401": "ErrorResponse", + "403": "ErrorResponse", + "404": "ErrorResponse", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + return response_data.response + + def _get_vendor_subscription_serialize( + self, + project_id, + subscription_id, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = {} + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[str, Union[str, bytes]] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if project_id is not None: + _path_params["projectId"] = project_id + if subscription_id is not None: + _path_params["subscriptionId"] = subscription_id + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + + # set the HTTP header `Accept` + if "Accept" not in _header_params: + _header_params["Accept"] = self.api_client.select_header_accept(["application/json"]) + + # authentication setting + _auth_settings: List[str] = [] + + return self.api_client.param_serialize( + method="GET", + resource_path="/v1/vendors/projects/{projectId}/subscriptions/{subscriptionId}", + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth, + ) + + @validate_call + def list_catalog_products( + self, + cursor: Annotated[ + Optional[StrictStr], + Field( + description="A pagination cursor that represents a position in the dataset. If given, results will be returned from the item after the cursor. If not given, results will be returned from the beginning." + ), + ] = None, + limit: Annotated[ + Optional[ + Union[ + Annotated[float, Field(le=100, strict=True, ge=0)], Annotated[int, Field(le=100, strict=True, ge=0)] + ] + ], + Field( + description="The maximum number of items to return in the response. If maximum is exceeded, maximum is used." + ), + ] = None, + locale: Annotated[Optional[StrictStr], Field(description="The language of the response.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ListCatalogProductsResponse: + """List all products + + List all products. + + :param cursor: A pagination cursor that represents a position in the dataset. If given, results will be returned from the item after the cursor. If not given, results will be returned from the beginning. + :type cursor: str + :param limit: The maximum number of items to return in the response. If maximum is exceeded, maximum is used. + :type limit: float + :param locale: The language of the response. + :type locale: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 docstring might be too long + + _param = self._list_catalog_products_serialize( + cursor=cursor, + limit=limit, + locale=locale, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "200": "ListCatalogProductsResponse", + "400": "ErrorResponse", + "401": "ErrorResponse", + "403": "ErrorResponse", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + @validate_call + def list_catalog_products_with_http_info( + self, + cursor: Annotated[ + Optional[StrictStr], + Field( + description="A pagination cursor that represents a position in the dataset. If given, results will be returned from the item after the cursor. If not given, results will be returned from the beginning." + ), + ] = None, + limit: Annotated[ + Optional[ + Union[ + Annotated[float, Field(le=100, strict=True, ge=0)], Annotated[int, Field(le=100, strict=True, ge=0)] + ] + ], + Field( + description="The maximum number of items to return in the response. If maximum is exceeded, maximum is used." + ), + ] = None, + locale: Annotated[Optional[StrictStr], Field(description="The language of the response.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[ListCatalogProductsResponse]: + """List all products + + List all products. + + :param cursor: A pagination cursor that represents a position in the dataset. If given, results will be returned from the item after the cursor. If not given, results will be returned from the beginning. + :type cursor: str + :param limit: The maximum number of items to return in the response. If maximum is exceeded, maximum is used. + :type limit: float + :param locale: The language of the response. + :type locale: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 docstring might be too long + + _param = self._list_catalog_products_serialize( + cursor=cursor, + limit=limit, + locale=locale, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "200": "ListCatalogProductsResponse", + "400": "ErrorResponse", + "401": "ErrorResponse", + "403": "ErrorResponse", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + @validate_call + def list_catalog_products_without_preload_content( + self, + cursor: Annotated[ + Optional[StrictStr], + Field( + description="A pagination cursor that represents a position in the dataset. If given, results will be returned from the item after the cursor. If not given, results will be returned from the beginning." + ), + ] = None, + limit: Annotated[ + Optional[ + Union[ + Annotated[float, Field(le=100, strict=True, ge=0)], Annotated[int, Field(le=100, strict=True, ge=0)] + ] + ], + Field( + description="The maximum number of items to return in the response. If maximum is exceeded, maximum is used." + ), + ] = None, + locale: Annotated[Optional[StrictStr], Field(description="The language of the response.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """List all products + + List all products. + + :param cursor: A pagination cursor that represents a position in the dataset. If given, results will be returned from the item after the cursor. If not given, results will be returned from the beginning. + :type cursor: str + :param limit: The maximum number of items to return in the response. If maximum is exceeded, maximum is used. + :type limit: float + :param locale: The language of the response. + :type locale: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 docstring might be too long + + _param = self._list_catalog_products_serialize( + cursor=cursor, + limit=limit, + locale=locale, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "200": "ListCatalogProductsResponse", + "400": "ErrorResponse", + "401": "ErrorResponse", + "403": "ErrorResponse", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + return response_data.response + + def _list_catalog_products_serialize( + self, + cursor, + limit, + locale, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = {} + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[str, Union[str, bytes]] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + # process the query parameters + if cursor is not None: + + _query_params.append(("cursor", cursor)) + + if limit is not None: + + _query_params.append(("limit", limit)) + + if locale is not None: + + _query_params.append(("locale", locale)) + + # process the header parameters + # process the form parameters + # process the body parameter + + # set the HTTP header `Accept` + if "Accept" not in _header_params: + _header_params["Accept"] = self.api_client.select_header_accept(["application/json"]) + + # authentication setting + _auth_settings: List[str] = [] + + return self.api_client.param_serialize( + method="GET", + resource_path="/v1/catalog/products", + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth, + ) + + @validate_call + def list_vendor_subscriptions( + self, + project_id: Annotated[StrictStr, Field(description="The project ID.")], + cursor: Annotated[ + Optional[StrictStr], + Field( + description="A pagination cursor that represents a position in the dataset. If given, results will be returned from the item after the cursor. If not given, results will be returned from the beginning." + ), + ] = None, + limit: Annotated[ + Optional[ + Union[ + Annotated[float, Field(le=100, strict=True, ge=0)], Annotated[int, Field(le=100, strict=True, ge=0)] + ] + ], + Field( + description="The maximum number of items to return in the response. If maximum is exceeded, maximum is used." + ), + ] = None, + product_id: Annotated[Optional[StrictStr], Field(description="The product ID.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ListVendorSubscriptionsResponse: + """List all subscriptions + + List all subscriptions. + + :param project_id: The project ID. (required) + :type project_id: str + :param cursor: A pagination cursor that represents a position in the dataset. If given, results will be returned from the item after the cursor. If not given, results will be returned from the beginning. + :type cursor: str + :param limit: The maximum number of items to return in the response. If maximum is exceeded, maximum is used. + :type limit: float + :param product_id: The product ID. + :type product_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 docstring might be too long + + _param = self._list_vendor_subscriptions_serialize( + project_id=project_id, + cursor=cursor, + limit=limit, + product_id=product_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "200": "ListVendorSubscriptionsResponse", + "400": "ErrorResponse", + "401": "ErrorResponse", + "403": "ErrorResponse", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + @validate_call + def list_vendor_subscriptions_with_http_info( + self, + project_id: Annotated[StrictStr, Field(description="The project ID.")], + cursor: Annotated[ + Optional[StrictStr], + Field( + description="A pagination cursor that represents a position in the dataset. If given, results will be returned from the item after the cursor. If not given, results will be returned from the beginning." + ), + ] = None, + limit: Annotated[ + Optional[ + Union[ + Annotated[float, Field(le=100, strict=True, ge=0)], Annotated[int, Field(le=100, strict=True, ge=0)] + ] + ], + Field( + description="The maximum number of items to return in the response. If maximum is exceeded, maximum is used." + ), + ] = None, + product_id: Annotated[Optional[StrictStr], Field(description="The product ID.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[ListVendorSubscriptionsResponse]: + """List all subscriptions + + List all subscriptions. + + :param project_id: The project ID. (required) + :type project_id: str + :param cursor: A pagination cursor that represents a position in the dataset. If given, results will be returned from the item after the cursor. If not given, results will be returned from the beginning. + :type cursor: str + :param limit: The maximum number of items to return in the response. If maximum is exceeded, maximum is used. + :type limit: float + :param product_id: The product ID. + :type product_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 docstring might be too long + + _param = self._list_vendor_subscriptions_serialize( + project_id=project_id, + cursor=cursor, + limit=limit, + product_id=product_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "200": "ListVendorSubscriptionsResponse", + "400": "ErrorResponse", + "401": "ErrorResponse", + "403": "ErrorResponse", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + @validate_call + def list_vendor_subscriptions_without_preload_content( + self, + project_id: Annotated[StrictStr, Field(description="The project ID.")], + cursor: Annotated[ + Optional[StrictStr], + Field( + description="A pagination cursor that represents a position in the dataset. If given, results will be returned from the item after the cursor. If not given, results will be returned from the beginning." + ), + ] = None, + limit: Annotated[ + Optional[ + Union[ + Annotated[float, Field(le=100, strict=True, ge=0)], Annotated[int, Field(le=100, strict=True, ge=0)] + ] + ], + Field( + description="The maximum number of items to return in the response. If maximum is exceeded, maximum is used." + ), + ] = None, + product_id: Annotated[Optional[StrictStr], Field(description="The product ID.")] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """List all subscriptions + + List all subscriptions. + + :param project_id: The project ID. (required) + :type project_id: str + :param cursor: A pagination cursor that represents a position in the dataset. If given, results will be returned from the item after the cursor. If not given, results will be returned from the beginning. + :type cursor: str + :param limit: The maximum number of items to return in the response. If maximum is exceeded, maximum is used. + :type limit: float + :param product_id: The product ID. + :type product_id: str + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 docstring might be too long + + _param = self._list_vendor_subscriptions_serialize( + project_id=project_id, + cursor=cursor, + limit=limit, + product_id=product_id, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "200": "ListVendorSubscriptionsResponse", + "400": "ErrorResponse", + "401": "ErrorResponse", + "403": "ErrorResponse", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + return response_data.response + + def _list_vendor_subscriptions_serialize( + self, + project_id, + cursor, + limit, + product_id, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = {} + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[str, Union[str, bytes]] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if project_id is not None: + _path_params["projectId"] = project_id + # process the query parameters + if cursor is not None: + + _query_params.append(("cursor", cursor)) + + if limit is not None: + + _query_params.append(("limit", limit)) + + if product_id is not None: + + _query_params.append(("productId", product_id)) + + # process the header parameters + # process the form parameters + # process the body parameter + + # set the HTTP header `Accept` + if "Accept" not in _header_params: + _header_params["Accept"] = self.api_client.select_header_accept(["application/json"]) + + # authentication setting + _auth_settings: List[str] = [] + + return self.api_client.param_serialize( + method="GET", + resource_path="/v1/vendors/projects/{projectId}/subscriptions", + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth, + ) + + @validate_call + def resolve_customer( + self, + project_id: Annotated[StrictStr, Field(description="The project ID.")], + resolve_customer_payload: ResolveCustomerPayload, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> VendorSubscription: + """Resolve customer + + Get details about the requested subscription. + + :param project_id: The project ID. (required) + :type project_id: str + :param resolve_customer_payload: (required) + :type resolve_customer_payload: ResolveCustomerPayload + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 docstring might be too long + + _param = self._resolve_customer_serialize( + project_id=project_id, + resolve_customer_payload=resolve_customer_payload, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "200": "VendorSubscription", + "400": "ErrorResponse", + "401": "ErrorResponse", + "403": "ErrorResponse", + "404": "ErrorResponse", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + @validate_call + def resolve_customer_with_http_info( + self, + project_id: Annotated[StrictStr, Field(description="The project ID.")], + resolve_customer_payload: ResolveCustomerPayload, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[VendorSubscription]: + """Resolve customer + + Get details about the requested subscription. + + :param project_id: The project ID. (required) + :type project_id: str + :param resolve_customer_payload: (required) + :type resolve_customer_payload: ResolveCustomerPayload + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 docstring might be too long + + _param = self._resolve_customer_serialize( + project_id=project_id, + resolve_customer_payload=resolve_customer_payload, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "200": "VendorSubscription", + "400": "ErrorResponse", + "401": "ErrorResponse", + "403": "ErrorResponse", + "404": "ErrorResponse", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + @validate_call + def resolve_customer_without_preload_content( + self, + project_id: Annotated[StrictStr, Field(description="The project ID.")], + resolve_customer_payload: ResolveCustomerPayload, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[Annotated[StrictFloat, Field(gt=0)], Annotated[StrictFloat, Field(gt=0)]], + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Resolve customer + + Get details about the requested subscription. + + :param project_id: The project ID. (required) + :type project_id: str + :param resolve_customer_payload: (required) + :type resolve_customer_payload: ResolveCustomerPayload + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 docstring might be too long + + _param = self._resolve_customer_serialize( + project_id=project_id, + resolve_customer_payload=resolve_customer_payload, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index, + ) + + _response_types_map: Dict[str, Optional[str]] = { + "200": "VendorSubscription", + "400": "ErrorResponse", + "401": "ErrorResponse", + "403": "ErrorResponse", + "404": "ErrorResponse", + } + response_data = self.api_client.call_api(*_param, _request_timeout=_request_timeout) + return response_data.response + + def _resolve_customer_serialize( + self, + project_id, + resolve_customer_payload, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = {} + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[str, Union[str, bytes]] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if project_id is not None: + _path_params["projectId"] = project_id + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + if resolve_customer_payload is not None: + _body_params = resolve_customer_payload + + # set the HTTP header `Accept` + if "Accept" not in _header_params: + _header_params["Accept"] = self.api_client.select_header_accept(["application/json"]) + + # set the HTTP header `Content-Type` + if _content_type: + _header_params["Content-Type"] = _content_type + else: + _default_content_type = self.api_client.select_header_content_type(["application/json"]) + if _default_content_type is not None: + _header_params["Content-Type"] = _default_content_type + + # authentication setting + _auth_settings: List[str] = [] + + return self.api_client.param_serialize( + method="POST", + resource_path="/v1/vendors/projects/{projectId}/resolve-customer", + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth, + ) diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/api_client.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/api_client.py new file mode 100644 index 00000000..d6a3695d --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/api_client.py @@ -0,0 +1,627 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +import datetime +import json +import mimetypes +import os +import re +import tempfile +from enum import Enum +from typing import Dict, List, Optional, Tuple, Union +from urllib.parse import quote + +from dateutil.parser import parse +from pydantic import SecretStr +from stackit.core.configuration import Configuration + +import stackit.stackitmarketplace.models +from stackit.stackitmarketplace import rest +from stackit.stackitmarketplace.api_response import ApiResponse +from stackit.stackitmarketplace.api_response import T as ApiResponseT +from stackit.stackitmarketplace.configuration import HostConfiguration +from stackit.stackitmarketplace.exceptions import ( + ApiException, +) + + +RequestSerialized = Tuple[str, str, Dict[str, str], Optional[str], List[str]] + + +class ApiClient: + """Generic API client for OpenAPI client library builds. + + OpenAPI generic API client. This client handles the client- + server communication, and is invariant across implementations. Specifics of + the methods and models for each application are generated from the OpenAPI + templates. + + :param configuration: .Configuration object for this client + :param header_name: a header to pass when making calls to the API. + :param header_value: a header value to pass when making calls to + the API. + :param cookie: a cookie to include in the header when making calls + to the API + """ + + PRIMITIVE_TYPES = (float, bool, bytes, str, int) + NATIVE_TYPES_MAPPING = { + "int": int, + "long": int, # TODO remove as only py3 is supported? + "float": float, + "str": str, + "bool": bool, + "date": datetime.date, + "datetime": datetime.datetime, + "object": object, + } + + def __init__(self, configuration, header_name=None, header_value=None, cookie=None) -> None: + self.config: Configuration = configuration + + if self.config.custom_endpoint is None: + host_config = HostConfiguration(region=self.config.region, server_index=self.config.server_index) + self.host = host_config.host + else: + self.host = self.config.custom_endpoint + + self.rest_client = rest.RESTClientObject(self.config) + self.default_headers = {} + if header_name is not None: + self.default_headers[header_name] = header_value + self.cookie = cookie + # Set default User-Agent. + self.user_agent = "OpenAPI-Generator/1.0.0/python" + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + pass + + @property + def user_agent(self): + """User agent for this API client""" + return self.default_headers["User-Agent"] + + @user_agent.setter + def user_agent(self, value): + self.default_headers["User-Agent"] = value + + def set_default_header(self, header_name, header_value): + self.default_headers[header_name] = header_value + + _default = None + + @classmethod + def get_default(cls): + """Return new instance of ApiClient. + + This method returns newly created, based on default constructor, + object of ApiClient class or returns a copy of default + ApiClient. + + :return: The ApiClient object. + """ + if cls._default is None: + cls._default = ApiClient() + return cls._default + + @classmethod + def set_default(cls, default): + """Set default instance of ApiClient. + + It stores default ApiClient. + + :param default: object of ApiClient. + """ + cls._default = default + + def param_serialize( + self, + method, + resource_path, + path_params=None, + query_params=None, + header_params=None, + body=None, + post_params=None, + files=None, + auth_settings=None, + collection_formats=None, + _host=None, + _request_auth=None, + ) -> RequestSerialized: + """Builds the HTTP request params needed by the request. + :param method: Method to call. + :param resource_path: Path to method endpoint. + :param path_params: Path parameters in the url. + :param query_params: Query parameters in the url. + :param header_params: Header parameters to be + placed in the request header. + :param body: Request body. + :param post_params dict: Request post form parameters, + for `application/x-www-form-urlencoded`, `multipart/form-data`. + :param auth_settings list: Auth Settings names for the request. + :param files dict: key -> filename, value -> filepath, + for `multipart/form-data`. + :param collection_formats: dict of collection formats for path, query, + header, and post parameters. + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the authentication + in the spec for a single request. + :return: tuple of form (path, http_method, query_params, header_params, + body, post_params, files) + """ + + # header parameters + header_params = header_params or {} + header_params.update(self.default_headers) + if self.cookie: + header_params["Cookie"] = self.cookie + if header_params: + header_params = self.sanitize_for_serialization(header_params) + header_params = dict(self.parameters_to_tuples(header_params, collection_formats)) + + # path parameters + if path_params: + path_params = self.sanitize_for_serialization(path_params) + path_params = self.parameters_to_tuples(path_params, collection_formats) + for k, v in path_params: + # specified safe chars, encode everything + resource_path = resource_path.replace("{%s}" % k, quote(str(v))) + + # post parameters + if post_params or files: + post_params = post_params if post_params else [] + post_params = self.sanitize_for_serialization(post_params) + post_params = self.parameters_to_tuples(post_params, collection_formats) + if files: + post_params.extend(self.files_parameters(files)) + + # body + if body: + body = self.sanitize_for_serialization(body) + + # request url + if _host is None: + url = self.host + resource_path + else: + # use server/host defined in path or operation instead + url = _host + resource_path + + # query parameters + if query_params: + query_params = self.sanitize_for_serialization(query_params) + url_query = self.parameters_to_url_query(query_params, collection_formats) + url += "?" + url_query + + return method, url, header_params, body, post_params + + def call_api( + self, method, url, header_params=None, body=None, post_params=None, _request_timeout=None + ) -> rest.RESTResponse: + """Makes the HTTP request (synchronous) + :param method: Method to call. + :param url: Path to method endpoint. + :param header_params: Header parameters to be + placed in the request header. + :param body: Request body. + :param post_params dict: Request post form parameters, + for `application/x-www-form-urlencoded`, `multipart/form-data`. + :param _request_timeout: timeout setting for this request. + :return: RESTResponse + """ + + try: + # perform request and return response + response_data = self.rest_client.request( + method, + url, + headers=header_params, + body=body, + post_params=post_params, + _request_timeout=_request_timeout, + ) + + except ApiException as e: + raise e + + return response_data + + def response_deserialize( + self, response_data: rest.RESTResponse, response_types_map: Optional[Dict[str, ApiResponseT]] = None + ) -> ApiResponse[ApiResponseT]: + """Deserializes response into an object. + :param response_data: RESTResponse object to be deserialized. + :param response_types_map: dict of response types. + :return: ApiResponse + """ + + msg = "RESTResponse.read() must be called before passing it to response_deserialize()" + if response_data.data is None: + raise ValueError(msg) + + response_type = response_types_map.get(str(response_data.status), None) + if not response_type and isinstance(response_data.status, int) and 100 <= response_data.status <= 599: + # if not found, look for '1XX', '2XX', etc. + response_type = response_types_map.get(str(response_data.status)[0] + "XX", None) + + # deserialize response data + response_text = None + return_data = None + try: + if response_type == "bytearray": + return_data = response_data.data + elif response_type == "file": + return_data = self.__deserialize_file(response_data) + elif response_type is not None: + match = None + content_type = response_data.getheader("content-type") + if content_type is not None: + match = re.search(r"charset=([a-zA-Z\-\d]+)[\s;]?", content_type) + encoding = match.group(1) if match else "utf-8" + response_text = response_data.data.decode(encoding) + return_data = self.deserialize(response_text, response_type, content_type) + finally: + if not 200 <= response_data.status <= 299: + raise ApiException.from_response( + http_resp=response_data, + body=response_text, + data=return_data, + ) + + return ApiResponse( + status_code=response_data.status, + data=return_data, + headers=response_data.getheaders(), + raw_data=response_data.data, + ) + + def sanitize_for_serialization(self, obj): + """Builds a JSON POST object. + + If obj is None, return None. + If obj is SecretStr, return obj.get_secret_value() + If obj is str, int, long, float, bool, return directly. + If obj is datetime.datetime, datetime.date + convert to string in iso8601 format. + If obj is list, sanitize each element in the list. + If obj is dict, return the dict. + If obj is OpenAPI model, return the properties dict. + + :param obj: The data to serialize. + :return: The serialized form of data. + """ + if obj is None: + return None + elif isinstance(obj, Enum): + return obj.value + elif isinstance(obj, SecretStr): + return obj.get_secret_value() + elif isinstance(obj, self.PRIMITIVE_TYPES): + return obj + elif isinstance(obj, list): + return [self.sanitize_for_serialization(sub_obj) for sub_obj in obj] + elif isinstance(obj, tuple): + return tuple(self.sanitize_for_serialization(sub_obj) for sub_obj in obj) + elif isinstance(obj, (datetime.datetime, datetime.date)): + return obj.isoformat() + + elif isinstance(obj, dict): + obj_dict = obj + else: + # Convert model obj to dict except + # attributes `openapi_types`, `attribute_map` + # and attributes which value is not None. + # Convert attribute name to json key in + # model definition for request. + if hasattr(obj, "to_dict") and callable(obj.to_dict): + obj_dict = obj.to_dict() + else: + obj_dict = obj.__dict__ + + return {key: self.sanitize_for_serialization(val) for key, val in obj_dict.items()} + + def deserialize(self, response_text: str, response_type: str, content_type: Optional[str]): + """Deserializes response into an object. + + :param response: RESTResponse object to be deserialized. + :param response_type: class literal for + deserialized object, or string of class name. + :param content_type: content type of response. + + :return: deserialized object. + """ + + # fetch data from response object + if content_type is None: + try: + data = json.loads(response_text) + except ValueError: + data = response_text + elif content_type.startswith("application/json"): + if response_text == "": + data = "" + else: + data = json.loads(response_text) + elif content_type.startswith("text/plain"): + data = response_text + else: + raise ApiException(status=0, reason="Unsupported content type: {0}".format(content_type)) + + return self.__deserialize(data, response_type) + + def __deserialize(self, data, klass): + """Deserializes dict, list, str into an object. + + :param data: dict, list or str. + :param klass: class literal, or string of class name. + + :return: object. + """ + if data is None: + return None + + if isinstance(klass, str): + if klass.startswith("List["): + m = re.match(r"List\[(.*)]", klass) + if m is None: + raise ValueError("Malformed List type definition") + sub_kls = m.group(1) + return [self.__deserialize(sub_data, sub_kls) for sub_data in data] + + if klass.startswith("Dict["): + m = re.match(r"Dict\[([^,]*), (.*)]", klass) + if m is None: + raise ValueError("Malformed Dict type definition") + sub_kls = m.group(2) + return {k: self.__deserialize(v, sub_kls) for k, v in data.items()} + + # convert str to class + if klass in self.NATIVE_TYPES_MAPPING: + klass = self.NATIVE_TYPES_MAPPING[klass] + else: + klass = getattr(stackit.stackitmarketplace.models, klass) + + if klass in self.PRIMITIVE_TYPES: + return self.__deserialize_primitive(data, klass) + elif klass == object: + return self.__deserialize_object(data) + elif klass == datetime.date: + return self.__deserialize_date(data) + elif klass == datetime.datetime: + return self.__deserialize_datetime(data) + elif issubclass(klass, Enum): + return self.__deserialize_enum(data, klass) + else: + return self.__deserialize_model(data, klass) + + def parameters_to_tuples(self, params, collection_formats): + """Get parameters as list of tuples, formatting collections. + + :param params: Parameters as dict or list of two-tuples + :param dict collection_formats: Parameter collection formats + :return: Parameters as list of tuples, collections formatted + """ + new_params: List[Tuple[str, str]] = [] + if collection_formats is None: + collection_formats = {} + for k, v in params.items() if isinstance(params, dict) else params: + if k in collection_formats: + collection_format = collection_formats[k] + if collection_format == "multi": + new_params.extend((k, value) for value in v) + else: + if collection_format == "ssv": + delimiter = " " + elif collection_format == "tsv": + delimiter = "\t" + elif collection_format == "pipes": + delimiter = "|" + else: # csv is the default + delimiter = "," + new_params.append((k, delimiter.join(str(value) for value in v))) + else: + new_params.append((k, v)) + return new_params + + def parameters_to_url_query(self, params, collection_formats): + """Get parameters as list of tuples, formatting collections. + + :param params: Parameters as dict or list of two-tuples + :param dict collection_formats: Parameter collection formats + :return: URL query string (e.g. a=Hello%20World&b=123) + """ + new_params: List[Tuple[str, str]] = [] + if collection_formats is None: + collection_formats = {} + for k, v in params.items() if isinstance(params, dict) else params: + if isinstance(v, bool): + v = str(v).lower() + if isinstance(v, (int, float)): + v = str(v) + if isinstance(v, dict): + v = json.dumps(v) + + if k in collection_formats: + collection_format = collection_formats[k] + if collection_format == "multi": + new_params.extend((k, str(value)) for value in v) + else: + if collection_format == "ssv": + delimiter = " " + elif collection_format == "tsv": + delimiter = "\t" + elif collection_format == "pipes": + delimiter = "|" + else: # csv is the default + delimiter = "," + new_params.append((k, delimiter.join(quote(str(value)) for value in v))) + else: + new_params.append((k, quote(str(v)))) + + return "&".join(["=".join(map(str, item)) for item in new_params]) + + def files_parameters(self, files: Dict[str, Union[str, bytes]]): + """Builds form parameters. + + :param files: File parameters. + :return: Form parameters with files. + """ + params = [] + for k, v in files.items(): + if isinstance(v, str): + with open(v, "rb") as f: + filename = os.path.basename(f.name) + filedata = f.read() + elif isinstance(v, bytes): + filename = k + filedata = v + else: + raise ValueError("Unsupported file value") + mimetype = mimetypes.guess_type(filename)[0] or "application/octet-stream" + params.append(tuple([k, tuple([filename, filedata, mimetype])])) + return params + + def select_header_accept(self, accepts: List[str]) -> Optional[str]: + """Returns `Accept` based on an array of accepts provided. + + :param accepts: List of headers. + :return: Accept (e.g. application/json). + """ + if not accepts: + return None + + for accept in accepts: + if re.search("json", accept, re.IGNORECASE): + return accept + + return accepts[0] + + def select_header_content_type(self, content_types): + """Returns `Content-Type` based on an array of content_types provided. + + :param content_types: List of content-types. + :return: Content-Type (e.g. application/json). + """ + if not content_types: + return None + + for content_type in content_types: + if re.search("json", content_type, re.IGNORECASE): + return content_type + + return content_types[0] + + def __deserialize_file(self, response): + """Deserializes body to file + + Saves response body into a file in a temporary folder, + using the filename from the `Content-Disposition` header if provided. + + handle file downloading + save response body into a tmp file and return the instance + + :param response: RESTResponse. + :return: file path. + """ + fd, path = tempfile.mkstemp(dir=self.configuration.temp_folder_path) + os.close(fd) + os.remove(path) + + content_disposition = response.getheader("Content-Disposition") + if content_disposition: + m = re.search(r'filename=[\'"]?([^\'"\s]+)[\'"]?', content_disposition) + if m is None: + raise ValueError("Unexpected 'content-disposition' header value") + filename = m.group(1) + path = os.path.join(os.path.dirname(path), filename) + + with open(path, "wb") as f: + f.write(response.data) + + return path + + def __deserialize_primitive(self, data, klass): + """Deserializes string to primitive type. + + :param data: str. + :param klass: class literal. + + :return: int, long, float, str, bool. + """ + try: + return klass(data) + except UnicodeEncodeError: + return str(data) + except TypeError: + return data + + def __deserialize_object(self, value): + """Return an original value. + + :return: object. + """ + return value + + def __deserialize_date(self, string): + """Deserializes string to date. + + :param string: str. + :return: date. + """ + try: + return parse(string).date() + except ImportError: + return string + except ValueError: + raise rest.ApiException(status=0, reason="Failed to parse `{0}` as date object".format(string)) + + def __deserialize_datetime(self, string): + """Deserializes string to datetime. + + The string should be in iso8601 datetime format. + + :param string: str. + :return: datetime. + """ + try: + return parse(string) + except ImportError: + return string + except ValueError: + raise rest.ApiException(status=0, reason=("Failed to parse `{0}` as datetime object".format(string))) + + def __deserialize_enum(self, data, klass): + """Deserializes primitive type to enum. + + :param data: primitive type. + :param klass: class literal. + :return: enum value. + """ + try: + return klass(data) + except ValueError: + raise rest.ApiException(status=0, reason=("Failed to parse `{0}` as `{1}`".format(data, klass))) + + def __deserialize_model(self, data, klass): + """Deserializes list or dict to model. + + :param data: dict, list. + :param klass: class literal. + :return: model object. + """ + + return klass.from_dict(data) diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/api_response.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/api_response.py new file mode 100644 index 00000000..b3ba14a1 --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/api_response.py @@ -0,0 +1,23 @@ +"""API response object.""" + +from __future__ import annotations + +from typing import Generic, Mapping, Optional, TypeVar + +from pydantic import BaseModel, Field, StrictBytes, StrictInt + + +T = TypeVar("T") + + +class ApiResponse(BaseModel, Generic[T]): + """ + API response object + """ + + status_code: StrictInt = Field(description="HTTP status code") + headers: Optional[Mapping[str, str]] = Field(None, description="HTTP headers") + data: T = Field(description="Deserialized data given the data type") + raw_data: StrictBytes = Field(description="Raw data (HTTP response body)") + + model_config = {"arbitrary_types_allowed": True} diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/configuration.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/configuration.py new file mode 100644 index 00000000..1cdb77a8 --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/configuration.py @@ -0,0 +1,138 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +import os + + +class HostConfiguration: + def __init__( + self, + region=None, + server_index=None, + server_variables=None, + server_operation_index=None, + server_operation_variables=None, + ignore_operation_servers=False, + ) -> None: + print( + "WARNING: STACKIT will move to a new way of specifying regions, where the region is provided\n", + "as a function argument instead of being set in the client configuration.\n" + "Once all services have migrated, the methods to specify the region in the client configuration " + "will be removed.", + ) + """Constructor + """ + self._base_path = "https://stackit-marketplace.api.stackit.cloud" + """Default Base url + """ + self.server_index = 0 if server_index is None else server_index + self.server_operation_index = server_operation_index or {} + """Default server index + """ + self.server_variables = server_variables or {} + if region: + self.server_variables["region"] = "{}.".format(region) + self.server_operation_variables = server_operation_variables or {} + """Default server variables + """ + self.ignore_operation_servers = ignore_operation_servers + """Ignore operation servers + """ + + def get_host_settings(self): + """Gets an array of host settings + + :return: An array of host settings + """ + return [ + { + "url": "https://stackit-marketplace.api.stackit.cloud", + "description": "No description provided", + "variables": { + "region": { + "description": "No description provided", + "default_value": "global", + } + }, + } + ] + + def get_host_from_settings(self, index, variables=None, servers=None): + """Gets host URL based on the index and variables + :param index: array index of the host settings + :param variables: hash of variable and the corresponding value + :param servers: an array of host settings or None + :error: if a region is given for a global url + :return: URL based on host settings + """ + if index is None: + return self._base_path + + variables = {} if variables is None else variables + servers = self.get_host_settings() if servers is None else servers + + try: + server = servers[index] + except IndexError: + raise ValueError( + "Invalid index {0} when selecting the host settings. " + "Must be less than {1}".format(index, len(servers)) + ) + + url = server["url"] + + # check if environment variable was provided for region + # if nothing was set this is None + region_env = os.environ.get("STACKIT_REGION") + + # go through variables and replace placeholders + for variable_name, variable in server.get("variables", {}).items(): + # If a region is provided by the user for a global url + # return an error (except for providing via environment variable). + # The region is provided as a function argument instead of being set in the client configuration. + if ( + variable_name == "region" + and (variable["default_value"] == "global" or variable["default_value"] == "") + and region_env is None + and variables.get(variable_name) is not None + ): + raise ValueError( + "this API does not support setting a region in the the client configuration, " + "please check if the region can be specified as a function parameter" + ) + used_value = variables.get(variable_name, variable["default_value"]) + + if "enum_values" in variable and used_value not in variable["enum_values"]: + given_value = variables[variable_name].replace(".", "") + valid_values = [v.replace(".", "") for v in variable["enum_values"]] + raise ValueError( + "The variable `{0}` in the host URL has invalid value '{1}'. Must be '{2}'.".format( + variable_name, given_value, valid_values + ) + ) + + url = url.replace("{" + variable_name + "}", used_value) + + return url + + @property + def host(self): + """Return generated host.""" + return self.get_host_from_settings(self.server_index, variables=self.server_variables) + + @host.setter + def host(self, value): + """Fix base path.""" + self._base_path = value + self.server_index = None diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/exceptions.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/exceptions.py new file mode 100644 index 00000000..ef4997b3 --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/exceptions.py @@ -0,0 +1,199 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from typing import Any, Optional + +from typing_extensions import Self + + +class OpenApiException(Exception): + """The base exception class for all OpenAPIExceptions""" + + +class ApiTypeError(OpenApiException, TypeError): + def __init__(self, msg, path_to_item=None, valid_classes=None, key_type=None) -> None: + """Raises an exception for TypeErrors + + Args: + msg (str): the exception message + + Keyword Args: + path_to_item (list): a list of keys an indices to get to the + current_item + None if unset + valid_classes (tuple): the primitive classes that current item + should be an instance of + None if unset + key_type (bool): False if our value is a value in a dict + True if it is a key in a dict + False if our item is an item in a list + None if unset + """ + self.path_to_item = path_to_item + self.valid_classes = valid_classes + self.key_type = key_type + full_msg = msg + if path_to_item: + full_msg = "{0} at {1}".format(msg, render_path(path_to_item)) + super(ApiTypeError, self).__init__(full_msg) + + +class ApiValueError(OpenApiException, ValueError): + def __init__(self, msg, path_to_item=None) -> None: + """ + Args: + msg (str): the exception message + + Keyword Args: + path_to_item (list) the path to the exception in the + received_data dict. None if unset + """ + + self.path_to_item = path_to_item + full_msg = msg + if path_to_item: + full_msg = "{0} at {1}".format(msg, render_path(path_to_item)) + super(ApiValueError, self).__init__(full_msg) + + +class ApiAttributeError(OpenApiException, AttributeError): + def __init__(self, msg, path_to_item=None) -> None: + """ + Raised when an attribute reference or assignment fails. + + Args: + msg (str): the exception message + + Keyword Args: + path_to_item (None/list) the path to the exception in the + received_data dict + """ + self.path_to_item = path_to_item + full_msg = msg + if path_to_item: + full_msg = "{0} at {1}".format(msg, render_path(path_to_item)) + super(ApiAttributeError, self).__init__(full_msg) + + +class ApiKeyError(OpenApiException, KeyError): + def __init__(self, msg, path_to_item=None) -> None: + """ + Args: + msg (str): the exception message + + Keyword Args: + path_to_item (None/list) the path to the exception in the + received_data dict + """ + self.path_to_item = path_to_item + full_msg = msg + if path_to_item: + full_msg = "{0} at {1}".format(msg, render_path(path_to_item)) + super(ApiKeyError, self).__init__(full_msg) + + +class ApiException(OpenApiException): + + def __init__( + self, + status=None, + reason=None, + http_resp=None, + *, + body: Optional[str] = None, + data: Optional[Any] = None, + ) -> None: + self.status = status + self.reason = reason + self.body = body + self.data = data + self.headers = None + + if http_resp: + if self.status is None: + self.status = http_resp.status + if self.reason is None: + self.reason = http_resp.reason + if self.body is None: + try: + self.body = http_resp.data.decode("utf-8") + except Exception: # noqa: S110 + pass + self.headers = http_resp.getheaders() + + @classmethod + def from_response( + cls, + *, + http_resp, + body: Optional[str], + data: Optional[Any], + ) -> Self: + if http_resp.status == 400: + raise BadRequestException(http_resp=http_resp, body=body, data=data) + + if http_resp.status == 401: + raise UnauthorizedException(http_resp=http_resp, body=body, data=data) + + if http_resp.status == 403: + raise ForbiddenException(http_resp=http_resp, body=body, data=data) + + if http_resp.status == 404: + raise NotFoundException(http_resp=http_resp, body=body, data=data) + + if 500 <= http_resp.status <= 599: + raise ServiceException(http_resp=http_resp, body=body, data=data) + raise ApiException(http_resp=http_resp, body=body, data=data) + + def __str__(self): + """Custom error messages for exception""" + error_message = "({0})\n" "Reason: {1}\n".format(self.status, self.reason) + if self.headers: + error_message += "HTTP response headers: {0}\n".format(self.headers) + + if self.data or self.body: + error_message += "HTTP response body: {0}\n".format(self.data or self.body) + + return error_message + + +class BadRequestException(ApiException): + pass + + +class NotFoundException(ApiException): + pass + + +class UnauthorizedException(ApiException): + pass + + +class ForbiddenException(ApiException): + pass + + +class ServiceException(ApiException): + pass + + +def render_path(path_to_item): + """Returns a string representation of a path""" + result = "" + for pth in path_to_item: + if isinstance(pth, int): + result += "[{0}]".format(pth) + else: + result += "['{0}']".format(pth) + return result diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/models/__init__.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/__init__.py new file mode 100644 index 00000000..ce52d668 --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/__init__.py @@ -0,0 +1,65 @@ +# coding: utf-8 + +# flake8: noqa +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + + +# import models into model package +from stackit.stackitmarketplace.models.catalog_pricing_option_highlight import ( + CatalogPricingOptionHighlight, +) +from stackit.stackitmarketplace.models.catalog_product_detail import ( + CatalogProductDetail, +) +from stackit.stackitmarketplace.models.catalog_product_details_vendor import ( + CatalogProductDetailsVendor, +) +from stackit.stackitmarketplace.models.catalog_product_highlight import ( + CatalogProductHighlight, +) +from stackit.stackitmarketplace.models.catalog_product_overview import ( + CatalogProductOverview, +) +from stackit.stackitmarketplace.models.catalog_product_overview_vendor import ( + CatalogProductOverviewVendor, +) +from stackit.stackitmarketplace.models.catalog_product_pricing_option import ( + CatalogProductPricingOption, +) +from stackit.stackitmarketplace.models.catalog_product_support_resource import ( + CatalogProductSupportResource, +) +from stackit.stackitmarketplace.models.catalog_product_vendor_terms import ( + CatalogProductVendorTerms, +) +from stackit.stackitmarketplace.models.current_subscription_state_response import ( + CurrentSubscriptionStateResponse, +) +from stackit.stackitmarketplace.models.error_response import ErrorResponse +from stackit.stackitmarketplace.models.list_catalog_products_response import ( + ListCatalogProductsResponse, +) +from stackit.stackitmarketplace.models.list_vendor_subscriptions_response import ( + ListVendorSubscriptionsResponse, +) +from stackit.stackitmarketplace.models.requested_subscription_state_response import ( + RequestedSubscriptionStateResponse, +) +from stackit.stackitmarketplace.models.resolve_customer_payload import ( + ResolveCustomerPayload, +) +from stackit.stackitmarketplace.models.subscription_cancel_response import ( + SubscriptionCancelResponse, +) +from stackit.stackitmarketplace.models.subscription_product import SubscriptionProduct +from stackit.stackitmarketplace.models.vendor_subscription import VendorSubscription diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_pricing_option_highlight.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_pricing_option_highlight.py new file mode 100644 index 00000000..c284710f --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_pricing_option_highlight.py @@ -0,0 +1,84 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from __future__ import annotations + +import json +import pprint +from typing import Any, ClassVar, Dict, List, Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictStr +from typing_extensions import Self + + +class CatalogPricingOptionHighlight(BaseModel): + """ + CatalogPricingOptionHighlight + """ + + highlight_content: Optional[StrictStr] = Field( + default=None, description="The highlight content.", alias="highlightContent" + ) + __properties: ClassVar[List[str]] = ["highlightContent"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of CatalogPricingOptionHighlight from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of CatalogPricingOptionHighlight from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({"highlightContent": obj.get("highlightContent")}) + return _obj diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_detail.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_detail.py new file mode 100644 index 00000000..8ad6e1a8 --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_detail.py @@ -0,0 +1,246 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from __future__ import annotations + +import json +import pprint +from typing import Any, ClassVar, Dict, List, Optional, Set + +from pydantic import ( + BaseModel, + ConfigDict, + Field, + StrictBool, + StrictStr, + field_validator, +) +from typing_extensions import Self + +from stackit.stackitmarketplace.models.catalog_product_details_vendor import ( + CatalogProductDetailsVendor, +) +from stackit.stackitmarketplace.models.catalog_product_highlight import ( + CatalogProductHighlight, +) +from stackit.stackitmarketplace.models.catalog_product_pricing_option import ( + CatalogProductPricingOption, +) +from stackit.stackitmarketplace.models.catalog_product_support_resource import ( + CatalogProductSupportResource, +) +from stackit.stackitmarketplace.models.catalog_product_vendor_terms import ( + CatalogProductVendorTerms, +) + + +class CatalogProductDetail(BaseModel): + """ + CatalogProductDetail + """ + + categories: Optional[List[StrictStr]] = Field( + default=None, description="The list of categories associated to the product." + ) + delivery_method: StrictStr = Field( + description="The product type. For reference: SAAS - Software as a Service, SAI - STACKIT Application Image", + alias="deliveryMethod", + ) + description: StrictStr = Field(description="The product description.") + documentation_url: StrictStr = Field(description="The documentation URL.", alias="documentationUrl") + highlights: List[CatalogProductHighlight] = Field(description="The list of highlights.") + is_product_listing: StrictBool = Field( + description="If true, the product is not fully integrated but only listed. Product listings may not have prices and support information.", + alias="isProductListing", + ) + lifecycle_state: StrictStr = Field(description="The lifecycle state of the product.", alias="lifecycleState") + logo: StrictStr = Field(description="The logo base64 encoded.") + name: StrictStr = Field(description="The product name.") + pricing_options: List[CatalogProductPricingOption] = Field( + description="The list of pricing options.", alias="pricingOptions" + ) + product_id: StrictStr = Field(description="The product ID.", alias="productId") + summary: StrictStr = Field(description="The short summary of the product.") + support_email: Optional[StrictStr] = Field( + default=None, description="The e-mail address for support inquiries.", alias="supportEmail" + ) + support_faq: Optional[StrictStr] = Field(default=None, description="The support FAQ URL.", alias="supportFaq") + support_phone: Optional[StrictStr] = Field( + default=None, description="The phone number for support inquiries.", alias="supportPhone" + ) + support_resources: Optional[List[CatalogProductSupportResource]] = Field( + default=None, description="The list of support resources.", alias="supportResources" + ) + vendor: CatalogProductDetailsVendor + vendor_terms: Optional[List[CatalogProductVendorTerms]] = Field( + default=None, description="The list of terms of use.", alias="vendorTerms" + ) + video_url: StrictStr = Field(description="The video URL.", alias="videoUrl") + __properties: ClassVar[List[str]] = [ + "categories", + "deliveryMethod", + "description", + "documentationUrl", + "highlights", + "isProductListing", + "lifecycleState", + "logo", + "name", + "pricingOptions", + "productId", + "summary", + "supportEmail", + "supportFaq", + "supportPhone", + "supportResources", + "vendor", + "vendorTerms", + "videoUrl", + ] + + @field_validator("delivery_method") + def delivery_method_validate_enum(cls, value): + """Validates the enum""" + if value not in set(["SAAS", "KUBERNETES", "SAI", "PROFESSIONAL_SERVICE"]): + raise ValueError("must be one of enum values ('SAAS', 'KUBERNETES', 'SAI', 'PROFESSIONAL_SERVICE')") + return value + + @field_validator("lifecycle_state") + def lifecycle_state_validate_enum(cls, value): + """Validates the enum""" + if value not in set(["PRODUCT_LIVE", "PRODUCT_PREVIEW"]): + raise ValueError("must be one of enum values ('PRODUCT_LIVE', 'PRODUCT_PREVIEW')") + return value + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of CatalogProductDetail from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # override the default output from pydantic by calling `to_dict()` of each item in highlights (list) + _items = [] + if self.highlights: + for _item in self.highlights: + if _item: + _items.append(_item.to_dict()) + _dict["highlights"] = _items + # override the default output from pydantic by calling `to_dict()` of each item in pricing_options (list) + _items = [] + if self.pricing_options: + for _item in self.pricing_options: + if _item: + _items.append(_item.to_dict()) + _dict["pricingOptions"] = _items + # override the default output from pydantic by calling `to_dict()` of each item in support_resources (list) + _items = [] + if self.support_resources: + for _item in self.support_resources: + if _item: + _items.append(_item.to_dict()) + _dict["supportResources"] = _items + # override the default output from pydantic by calling `to_dict()` of vendor + if self.vendor: + _dict["vendor"] = self.vendor.to_dict() + # override the default output from pydantic by calling `to_dict()` of each item in vendor_terms (list) + _items = [] + if self.vendor_terms: + for _item in self.vendor_terms: + if _item: + _items.append(_item.to_dict()) + _dict["vendorTerms"] = _items + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of CatalogProductDetail from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + { + "categories": obj.get("categories"), + "deliveryMethod": obj.get("deliveryMethod"), + "description": obj.get("description"), + "documentationUrl": obj.get("documentationUrl"), + "highlights": ( + [CatalogProductHighlight.from_dict(_item) for _item in obj["highlights"]] + if obj.get("highlights") is not None + else None + ), + "isProductListing": obj.get("isProductListing"), + "lifecycleState": obj.get("lifecycleState"), + "logo": obj.get("logo"), + "name": obj.get("name"), + "pricingOptions": ( + [CatalogProductPricingOption.from_dict(_item) for _item in obj["pricingOptions"]] + if obj.get("pricingOptions") is not None + else None + ), + "productId": obj.get("productId"), + "summary": obj.get("summary"), + "supportEmail": obj.get("supportEmail"), + "supportFaq": obj.get("supportFaq"), + "supportPhone": obj.get("supportPhone"), + "supportResources": ( + [CatalogProductSupportResource.from_dict(_item) for _item in obj["supportResources"]] + if obj.get("supportResources") is not None + else None + ), + "vendor": ( + CatalogProductDetailsVendor.from_dict(obj["vendor"]) if obj.get("vendor") is not None else None + ), + "vendorTerms": ( + [CatalogProductVendorTerms.from_dict(_item) for _item in obj["vendorTerms"]] + if obj.get("vendorTerms") is not None + else None + ), + "videoUrl": obj.get("videoUrl"), + } + ) + return _obj diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_details_vendor.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_details_vendor.py new file mode 100644 index 00000000..d47a235d --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_details_vendor.py @@ -0,0 +1,96 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from __future__ import annotations + +import json +import pprint +from typing import Any, ClassVar, Dict, List, Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictStr +from typing_extensions import Self + + +class CatalogProductDetailsVendor(BaseModel): + """ + CatalogProductDetailsVendor + """ + + description: StrictStr = Field(description="The vendor description.") + logo: StrictStr = Field(description="The vendor logo base64 encoded.") + name: StrictStr = Field(description="The vendor name.") + vendor_id: StrictStr = Field(description="The vendor ID.", alias="vendorId") + video_url: StrictStr = Field(description="The vendor video URL.", alias="videoUrl") + website_url: StrictStr = Field(description="The vendor website URL.", alias="websiteUrl") + __properties: ClassVar[List[str]] = ["description", "logo", "name", "vendorId", "videoUrl", "websiteUrl"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of CatalogProductDetailsVendor from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of CatalogProductDetailsVendor from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + { + "description": obj.get("description"), + "logo": obj.get("logo"), + "name": obj.get("name"), + "vendorId": obj.get("vendorId"), + "videoUrl": obj.get("videoUrl"), + "websiteUrl": obj.get("websiteUrl"), + } + ) + return _obj diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_highlight.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_highlight.py new file mode 100644 index 00000000..0bf81737 --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_highlight.py @@ -0,0 +1,94 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from __future__ import annotations + +import json +import pprint +from typing import Any, ClassVar, Dict, List, Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictStr +from typing_extensions import Self + + +class CatalogProductHighlight(BaseModel): + """ + CatalogProductHighlight + """ + + highlight_content: Optional[StrictStr] = Field( + default=None, description="The highlight content.", alias="highlightContent" + ) + highlight_icon: Optional[StrictStr] = Field(default=None, description="The highlight icon.", alias="highlightIcon") + highlight_title: Optional[StrictStr] = Field( + default=None, description="The highlight title.", alias="highlightTitle" + ) + __properties: ClassVar[List[str]] = ["highlightContent", "highlightIcon", "highlightTitle"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of CatalogProductHighlight from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of CatalogProductHighlight from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + { + "highlightContent": obj.get("highlightContent"), + "highlightIcon": obj.get("highlightIcon"), + "highlightTitle": obj.get("highlightTitle"), + } + ) + return _obj diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_overview.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_overview.py new file mode 100644 index 00000000..4811f40f --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_overview.py @@ -0,0 +1,132 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from __future__ import annotations + +import json +import pprint +from typing import Any, ClassVar, Dict, List, Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator +from typing_extensions import Self + +from stackit.stackitmarketplace.models.catalog_product_overview_vendor import ( + CatalogProductOverviewVendor, +) + + +class CatalogProductOverview(BaseModel): + """ + CatalogProductOverview + """ + + delivery_method: StrictStr = Field( + description="The product type. For reference: SAAS - Software as a Service, SAI - STACKIT Application Image", + alias="deliveryMethod", + ) + lifecycle_state: StrictStr = Field(description="The lifecycle state of the product.", alias="lifecycleState") + logo: Optional[StrictStr] = Field(default=None, description="The logo base64 encoded.") + name: StrictStr = Field(description="The product name.") + product_id: StrictStr = Field(description="The product ID.", alias="productId") + summary: StrictStr = Field(description="The short summary of the product.") + vendor: CatalogProductOverviewVendor + __properties: ClassVar[List[str]] = [ + "deliveryMethod", + "lifecycleState", + "logo", + "name", + "productId", + "summary", + "vendor", + ] + + @field_validator("delivery_method") + def delivery_method_validate_enum(cls, value): + """Validates the enum""" + if value not in set(["SAAS", "KUBERNETES", "SAI", "PROFESSIONAL_SERVICE"]): + raise ValueError("must be one of enum values ('SAAS', 'KUBERNETES', 'SAI', 'PROFESSIONAL_SERVICE')") + return value + + @field_validator("lifecycle_state") + def lifecycle_state_validate_enum(cls, value): + """Validates the enum""" + if value not in set(["PRODUCT_LIVE", "PRODUCT_PREVIEW"]): + raise ValueError("must be one of enum values ('PRODUCT_LIVE', 'PRODUCT_PREVIEW')") + return value + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of CatalogProductOverview from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # override the default output from pydantic by calling `to_dict()` of vendor + if self.vendor: + _dict["vendor"] = self.vendor.to_dict() + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of CatalogProductOverview from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + { + "deliveryMethod": obj.get("deliveryMethod"), + "lifecycleState": obj.get("lifecycleState"), + "logo": obj.get("logo"), + "name": obj.get("name"), + "productId": obj.get("productId"), + "summary": obj.get("summary"), + "vendor": ( + CatalogProductOverviewVendor.from_dict(obj["vendor"]) if obj.get("vendor") is not None else None + ), + } + ) + return _obj diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_overview_vendor.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_overview_vendor.py new file mode 100644 index 00000000..50049775 --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_overview_vendor.py @@ -0,0 +1,86 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from __future__ import annotations + +import json +import pprint +from typing import Any, ClassVar, Dict, List, Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictStr +from typing_extensions import Self + + +class CatalogProductOverviewVendor(BaseModel): + """ + CatalogProductOverviewVendor + """ + + name: StrictStr = Field(description="The vendor name.") + vendor_id: StrictStr = Field(description="The vendor ID.", alias="vendorId") + website_url: StrictStr = Field(description="The vendor website URL.", alias="websiteUrl") + __properties: ClassVar[List[str]] = ["name", "vendorId", "websiteUrl"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of CatalogProductOverviewVendor from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of CatalogProductOverviewVendor from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + {"name": obj.get("name"), "vendorId": obj.get("vendorId"), "websiteUrl": obj.get("websiteUrl")} + ) + return _obj diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_pricing_option.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_pricing_option.py new file mode 100644 index 00000000..a7608c40 --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_pricing_option.py @@ -0,0 +1,146 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from __future__ import annotations + +import json +import pprint +from typing import Any, ClassVar, Dict, List, Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator +from typing_extensions import Self + +from stackit.stackitmarketplace.models.catalog_pricing_option_highlight import ( + CatalogPricingOptionHighlight, +) + + +class CatalogProductPricingOption(BaseModel): + """ + CatalogProductPricingOption + """ + + description: StrictStr = Field(description="The pricing option description.") + highlights: List[CatalogPricingOptionHighlight] = Field(description="The list of highlights.") + name: StrictStr = Field(description="The pricing option name.") + price_type: Optional[StrictStr] = Field( + default=None, description="The price type / pricing model.", alias="priceType" + ) + pricing_plan: Optional[StrictStr] = Field( + default=None, description="Additional price type information.", alias="pricingPlan" + ) + rate: Optional[StrictStr] = Field(default=None, description="The price of the product (per unit).") + sku: StrictStr = Field(description="The concrete variant of the product.") + sku_info: StrictStr = Field(description="Short description of this offering.", alias="skuInfo") + sku_info_details: StrictStr = Field( + description="More details about what this offering entails.", alias="skuInfoDetails" + ) + unit: Optional[StrictStr] = Field(default=None, description="The interval to which the rate applies.") + __properties: ClassVar[List[str]] = [ + "description", + "highlights", + "name", + "priceType", + "pricingPlan", + "rate", + "sku", + "skuInfo", + "skuInfoDetails", + "unit", + ] + + @field_validator("price_type") + def price_type_validate_enum(cls, value): + """Validates the enum""" + if value is None: + return value + + if value not in set(["CONTRACT", "FREE", "FREE_TRIAL", "BYOL", "PAYG"]): + raise ValueError("must be one of enum values ('CONTRACT', 'FREE', 'FREE_TRIAL', 'BYOL', 'PAYG')") + return value + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of CatalogProductPricingOption from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # override the default output from pydantic by calling `to_dict()` of each item in highlights (list) + _items = [] + if self.highlights: + for _item in self.highlights: + if _item: + _items.append(_item.to_dict()) + _dict["highlights"] = _items + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of CatalogProductPricingOption from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + { + "description": obj.get("description"), + "highlights": ( + [CatalogPricingOptionHighlight.from_dict(_item) for _item in obj["highlights"]] + if obj.get("highlights") is not None + else None + ), + "name": obj.get("name"), + "priceType": obj.get("priceType"), + "pricingPlan": obj.get("pricingPlan"), + "rate": obj.get("rate"), + "sku": obj.get("sku"), + "skuInfo": obj.get("skuInfo"), + "skuInfoDetails": obj.get("skuInfoDetails"), + "unit": obj.get("unit"), + } + ) + return _obj diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_support_resource.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_support_resource.py new file mode 100644 index 00000000..6bc35ba8 --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_support_resource.py @@ -0,0 +1,89 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from __future__ import annotations + +import json +import pprint +from typing import Any, ClassVar, Dict, List, Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictStr +from typing_extensions import Self + + +class CatalogProductSupportResource(BaseModel): + """ + CatalogProductSupportResource + """ + + support_link: Optional[StrictStr] = Field( + default=None, description="The support resource link.", alias="supportLink" + ) + support_link_title: Optional[StrictStr] = Field( + default=None, description="The support resource link title.", alias="supportLinkTitle" + ) + __properties: ClassVar[List[str]] = ["supportLink", "supportLinkTitle"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of CatalogProductSupportResource from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of CatalogProductSupportResource from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + {"supportLink": obj.get("supportLink"), "supportLinkTitle": obj.get("supportLinkTitle")} + ) + return _obj diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_vendor_terms.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_vendor_terms.py new file mode 100644 index 00000000..98522f58 --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/catalog_product_vendor_terms.py @@ -0,0 +1,86 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from __future__ import annotations + +import json +import pprint +from typing import Any, ClassVar, Dict, List, Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictStr +from typing_extensions import Self + + +class CatalogProductVendorTerms(BaseModel): + """ + CatalogProductVendorTerms + """ + + description: StrictStr = Field(description="The terms of use description.") + title: StrictStr = Field(description="The terms of use title.") + url: StrictStr = Field(description="The terms of use url.") + __properties: ClassVar[List[str]] = ["description", "title", "url"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of CatalogProductVendorTerms from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of CatalogProductVendorTerms from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + {"description": obj.get("description"), "title": obj.get("title"), "url": obj.get("url")} + ) + return _obj diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/models/current_subscription_state_response.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/current_subscription_state_response.py new file mode 100644 index 00000000..c762659d --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/current_subscription_state_response.py @@ -0,0 +1,103 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from __future__ import annotations + +import json +import pprint +from typing import Any, ClassVar, Dict, List, Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator +from typing_extensions import Self + + +class CurrentSubscriptionStateResponse(BaseModel): + """ + CurrentSubscriptionStateResponse + """ + + lifecycle_state: StrictStr = Field(description="Lifecycle state of the subscription.", alias="lifecycleState") + subscription_id: StrictStr = Field(description="The subscription ID.", alias="subscriptionId") + __properties: ClassVar[List[str]] = ["lifecycleState", "subscriptionId"] + + @field_validator("lifecycle_state") + def lifecycle_state_validate_enum(cls, value): + """Validates the enum""" + if value not in set( + [ + "SUBSCRIPTION_PENDING", + "SUBSCRIPTION_ACTIVE", + "SUBSCRIPTION_INACTIVE", + "SUBSCRIPTION_CANCELLING", + "SUBSCRIPTION_CANCELLED", + "SUBSCRIPTION_REJECTED", + ] + ): + raise ValueError( + "must be one of enum values ('SUBSCRIPTION_PENDING', 'SUBSCRIPTION_ACTIVE', 'SUBSCRIPTION_INACTIVE', 'SUBSCRIPTION_CANCELLING', 'SUBSCRIPTION_CANCELLED', 'SUBSCRIPTION_REJECTED')" + ) + return value + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of CurrentSubscriptionStateResponse from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of CurrentSubscriptionStateResponse from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + {"lifecycleState": obj.get("lifecycleState"), "subscriptionId": obj.get("subscriptionId")} + ) + return _obj diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/models/error_response.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/error_response.py new file mode 100644 index 00000000..f048befc --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/error_response.py @@ -0,0 +1,95 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from __future__ import annotations + +import json +import pprint +from datetime import datetime +from typing import Any, ClassVar, Dict, List, Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr +from typing_extensions import Self + + +class ErrorResponse(BaseModel): + """ + ErrorResponse + """ + + error: StrictStr = Field(description="Reason phrase of the status code.") + message: StrictStr = Field(description="Description of the error.") + path: StrictStr = Field(description="Path which was called.") + status: StrictInt = Field(description="HTTP response status code.") + time_stamp: datetime = Field(description="Timestamp at which the error occurred.", alias="timeStamp") + __properties: ClassVar[List[str]] = ["error", "message", "path", "status", "timeStamp"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of ErrorResponse from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of ErrorResponse from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + { + "error": obj.get("error"), + "message": obj.get("message"), + "path": obj.get("path"), + "status": obj.get("status"), + "timeStamp": obj.get("timeStamp"), + } + ) + return _obj diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/models/list_catalog_products_response.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/list_catalog_products_response.py new file mode 100644 index 00000000..ea73476a --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/list_catalog_products_response.py @@ -0,0 +1,109 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from __future__ import annotations + +import json +import pprint +from typing import Any, ClassVar, Dict, List, Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictStr +from typing_extensions import Annotated, Self + +from stackit.stackitmarketplace.models.catalog_product_overview import ( + CatalogProductOverview, +) + + +class ListCatalogProductsResponse(BaseModel): + """ + ListCatalogProductsResponse + """ + + cursor: StrictStr = Field( + description="A pagination cursor that represents a position in the dataset. Use it in subsequent requests to continue retrieving data from this position. If `null`, there are no more results to retrieve." + ) + items: List[CatalogProductOverview] + limit: Annotated[int, Field(le=100, strict=True, ge=0)] = Field( + description="The maximum number of items to return in the response. If not present, an appropriate default will be used. If maximum is exceeded, maximum is used." + ) + __properties: ClassVar[List[str]] = ["cursor", "items", "limit"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of ListCatalogProductsResponse from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # override the default output from pydantic by calling `to_dict()` of each item in items (list) + _items = [] + if self.items: + for _item in self.items: + if _item: + _items.append(_item.to_dict()) + _dict["items"] = _items + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of ListCatalogProductsResponse from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + { + "cursor": obj.get("cursor"), + "items": ( + [CatalogProductOverview.from_dict(_item) for _item in obj["items"]] + if obj.get("items") is not None + else None + ), + "limit": obj.get("limit") if obj.get("limit") is not None else 50, + } + ) + return _obj diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/models/list_vendor_subscriptions_response.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/list_vendor_subscriptions_response.py new file mode 100644 index 00000000..13962904 --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/list_vendor_subscriptions_response.py @@ -0,0 +1,107 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from __future__ import annotations + +import json +import pprint +from typing import Any, ClassVar, Dict, List, Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictStr +from typing_extensions import Annotated, Self + +from stackit.stackitmarketplace.models.vendor_subscription import VendorSubscription + + +class ListVendorSubscriptionsResponse(BaseModel): + """ + ListVendorSubscriptionsResponse + """ + + cursor: StrictStr = Field( + description="A pagination cursor that represents a position in the dataset. Use it in subsequent requests to continue retrieving data from this position. If `null`, there are no more results to retrieve." + ) + items: List[VendorSubscription] = Field(description="List of subscriptions.") + limit: Annotated[int, Field(le=100, strict=True, ge=0)] = Field( + description="Number of subscriptions returned for a single request." + ) + __properties: ClassVar[List[str]] = ["cursor", "items", "limit"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of ListVendorSubscriptionsResponse from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # override the default output from pydantic by calling `to_dict()` of each item in items (list) + _items = [] + if self.items: + for _item in self.items: + if _item: + _items.append(_item.to_dict()) + _dict["items"] = _items + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of ListVendorSubscriptionsResponse from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + { + "cursor": obj.get("cursor"), + "items": ( + [VendorSubscription.from_dict(_item) for _item in obj["items"]] + if obj.get("items") is not None + else None + ), + "limit": obj.get("limit") if obj.get("limit") is not None else 50, + } + ) + return _obj diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/models/requested_subscription_state_response.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/requested_subscription_state_response.py new file mode 100644 index 00000000..a305a469 --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/requested_subscription_state_response.py @@ -0,0 +1,103 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from __future__ import annotations + +import json +import pprint +from typing import Any, ClassVar, Dict, List, Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator +from typing_extensions import Self + + +class RequestedSubscriptionStateResponse(BaseModel): + """ + RequestedSubscriptionStateResponse + """ + + lifecycle_state: StrictStr = Field(description="Lifecycle state of the subscription.", alias="lifecycleState") + subscription_id: StrictStr = Field(description="The subscription ID.", alias="subscriptionId") + __properties: ClassVar[List[str]] = ["lifecycleState", "subscriptionId"] + + @field_validator("lifecycle_state") + def lifecycle_state_validate_enum(cls, value): + """Validates the enum""" + if value not in set( + [ + "SUBSCRIPTION_PENDING", + "SUBSCRIPTION_ACTIVE", + "SUBSCRIPTION_INACTIVE", + "SUBSCRIPTION_CANCELLING", + "SUBSCRIPTION_CANCELLED", + "SUBSCRIPTION_REJECTED", + ] + ): + raise ValueError( + "must be one of enum values ('SUBSCRIPTION_PENDING', 'SUBSCRIPTION_ACTIVE', 'SUBSCRIPTION_INACTIVE', 'SUBSCRIPTION_CANCELLING', 'SUBSCRIPTION_CANCELLED', 'SUBSCRIPTION_REJECTED')" + ) + return value + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of RequestedSubscriptionStateResponse from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of RequestedSubscriptionStateResponse from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + {"lifecycleState": obj.get("lifecycleState"), "subscriptionId": obj.get("subscriptionId")} + ) + return _obj diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/models/resolve_customer_payload.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/resolve_customer_payload.py new file mode 100644 index 00000000..3194510b --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/resolve_customer_payload.py @@ -0,0 +1,82 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from __future__ import annotations + +import json +import pprint +from typing import Any, ClassVar, Dict, List, Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictStr +from typing_extensions import Self + + +class ResolveCustomerPayload(BaseModel): + """ + ResolveCustomerPayload + """ + + token: StrictStr = Field(description="Opaque token exchangeable for subscription details.") + __properties: ClassVar[List[str]] = ["token"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of ResolveCustomerPayload from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of ResolveCustomerPayload from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({"token": obj.get("token")}) + return _obj diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/models/subscription_cancel_response.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/subscription_cancel_response.py new file mode 100644 index 00000000..eabf198d --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/subscription_cancel_response.py @@ -0,0 +1,109 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from __future__ import annotations + +import json +import pprint +from typing import Any, ClassVar, Dict, List, Optional, Set + +from pydantic import BaseModel, ConfigDict, Field +from typing_extensions import Self + +from stackit.stackitmarketplace.models.current_subscription_state_response import ( + CurrentSubscriptionStateResponse, +) +from stackit.stackitmarketplace.models.requested_subscription_state_response import ( + RequestedSubscriptionStateResponse, +) + + +class SubscriptionCancelResponse(BaseModel): + """ + SubscriptionCancelResponse + """ + + current_subscription: CurrentSubscriptionStateResponse = Field(alias="currentSubscription") + requested_subscription: RequestedSubscriptionStateResponse = Field(alias="requestedSubscription") + __properties: ClassVar[List[str]] = ["currentSubscription", "requestedSubscription"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of SubscriptionCancelResponse from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # override the default output from pydantic by calling `to_dict()` of current_subscription + if self.current_subscription: + _dict["currentSubscription"] = self.current_subscription.to_dict() + # override the default output from pydantic by calling `to_dict()` of requested_subscription + if self.requested_subscription: + _dict["requestedSubscription"] = self.requested_subscription.to_dict() + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of SubscriptionCancelResponse from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + { + "currentSubscription": ( + CurrentSubscriptionStateResponse.from_dict(obj["currentSubscription"]) + if obj.get("currentSubscription") is not None + else None + ), + "requestedSubscription": ( + RequestedSubscriptionStateResponse.from_dict(obj["requestedSubscription"]) + if obj.get("requestedSubscription") is not None + else None + ), + } + ) + return _obj diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/models/subscription_product.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/subscription_product.py new file mode 100644 index 00000000..b542501a --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/subscription_product.py @@ -0,0 +1,130 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from __future__ import annotations + +import json +import pprint +from typing import Any, ClassVar, Dict, List, Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator +from typing_extensions import Self + + +class SubscriptionProduct(BaseModel): + """ + SubscriptionProduct + """ + + delivery_method: StrictStr = Field(description="The product's delivery method.", alias="deliveryMethod") + lifecycle_state: StrictStr = Field(description="The lifecycle state of the product.", alias="lifecycleState") + price_type: StrictStr = Field(description="The product's price type.", alias="priceType") + pricing_plan: StrictStr = Field(description="The product's pricing plan.", alias="pricingPlan") + product_id: StrictStr = Field(description="The product ID.", alias="productId") + product_name: StrictStr = Field(description="The name of the product.", alias="productName") + vendor_name: StrictStr = Field(description="The product's vendor name.", alias="vendorName") + vendor_website_url: StrictStr = Field(description="The vendor's website.", alias="vendorWebsiteUrl") + __properties: ClassVar[List[str]] = [ + "deliveryMethod", + "lifecycleState", + "priceType", + "pricingPlan", + "productId", + "productName", + "vendorName", + "vendorWebsiteUrl", + ] + + @field_validator("delivery_method") + def delivery_method_validate_enum(cls, value): + """Validates the enum""" + if value not in set(["SAAS"]): + raise ValueError("must be one of enum values ('SAAS')") + return value + + @field_validator("lifecycle_state") + def lifecycle_state_validate_enum(cls, value): + """Validates the enum""" + if value not in set(["PRODUCT_LIVE", "PRODUCT_PREVIEW"]): + raise ValueError("must be one of enum values ('PRODUCT_LIVE', 'PRODUCT_PREVIEW')") + return value + + @field_validator("price_type") + def price_type_validate_enum(cls, value): + """Validates the enum""" + if value not in set(["CONTRACT", "FREE", "FREE_TRIAL", "BYOL", "PAYG"]): + raise ValueError("must be one of enum values ('CONTRACT', 'FREE', 'FREE_TRIAL', 'BYOL', 'PAYG')") + return value + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of SubscriptionProduct from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of SubscriptionProduct from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + { + "deliveryMethod": obj.get("deliveryMethod"), + "lifecycleState": obj.get("lifecycleState"), + "priceType": obj.get("priceType"), + "pricingPlan": obj.get("pricingPlan"), + "productId": obj.get("productId"), + "productName": obj.get("productName"), + "vendorName": obj.get("vendorName"), + "vendorWebsiteUrl": obj.get("vendorWebsiteUrl"), + } + ) + return _obj diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/models/vendor_subscription.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/vendor_subscription.py new file mode 100644 index 00000000..31855dce --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/models/vendor_subscription.py @@ -0,0 +1,115 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +from __future__ import annotations + +import json +import pprint +from typing import Any, ClassVar, Dict, List, Optional, Set + +from pydantic import BaseModel, ConfigDict, Field, StrictStr, field_validator +from typing_extensions import Self + +from stackit.stackitmarketplace.models.subscription_product import SubscriptionProduct + + +class VendorSubscription(BaseModel): + """ + VendorSubscription + """ + + lifecycle_state: StrictStr = Field(description="Lifecycle state of the subscription.", alias="lifecycleState") + product: SubscriptionProduct + project_id: StrictStr = Field(description="The associated consumer project ID.", alias="projectId") + subscription_id: StrictStr = Field(description="The subscription ID.", alias="subscriptionId") + __properties: ClassVar[List[str]] = ["lifecycleState", "product", "projectId", "subscriptionId"] + + @field_validator("lifecycle_state") + def lifecycle_state_validate_enum(cls, value): + """Validates the enum""" + if value not in set( + [ + "SUBSCRIPTION_PENDING", + "SUBSCRIPTION_ACTIVE", + "SUBSCRIPTION_INACTIVE", + "SUBSCRIPTION_CANCELLING", + "SUBSCRIPTION_CANCELLED", + "SUBSCRIPTION_REJECTED", + ] + ): + raise ValueError( + "must be one of enum values ('SUBSCRIPTION_PENDING', 'SUBSCRIPTION_ACTIVE', 'SUBSCRIPTION_INACTIVE', 'SUBSCRIPTION_CANCELLING', 'SUBSCRIPTION_CANCELLED', 'SUBSCRIPTION_REJECTED')" + ) + return value + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of VendorSubscription from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # override the default output from pydantic by calling `to_dict()` of product + if self.product: + _dict["product"] = self.product.to_dict() + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of VendorSubscription from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate( + { + "lifecycleState": obj.get("lifecycleState"), + "product": SubscriptionProduct.from_dict(obj["product"]) if obj.get("product") is not None else None, + "projectId": obj.get("projectId"), + "subscriptionId": obj.get("subscriptionId"), + } + ) + return _obj diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/py.typed b/services/stackitmarketplace/src/stackit/stackitmarketplace/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/services/stackitmarketplace/src/stackit/stackitmarketplace/rest.py b/services/stackitmarketplace/src/stackit/stackitmarketplace/rest.py new file mode 100644 index 00000000..a5b6119f --- /dev/null +++ b/services/stackitmarketplace/src/stackit/stackitmarketplace/rest.py @@ -0,0 +1,149 @@ +# coding: utf-8 + +""" + STACKIT Marketplace API + + API to manage STACKIT Marketplace. + + The version of the OpenAPI document: 1 + Contact: marketplace@stackit.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 docstring might be too long + +import io +import json +import re + +import requests +from stackit.core.authorization import Authorization +from stackit.core.configuration import Configuration + +from stackit.stackitmarketplace.exceptions import ApiException, ApiValueError + + +RESTResponseType = requests.Response + + +class RESTResponse(io.IOBase): + + def __init__(self, resp) -> None: + self.response = resp + self.status = resp.status_code + self.reason = resp.reason + self.data = None + + def read(self): + if self.data is None: + self.data = self.response.content + return self.data + + def getheaders(self): + """Returns a dictionary of the response headers.""" + return self.response.headers + + def getheader(self, name, default=None): + """Returns a given response header.""" + return self.response.headers.get(name, default) + + +class RESTClientObject: + def __init__(self, config: Configuration) -> None: + self.session = config.custom_http_session if config.custom_http_session else requests.Session() + authorization = Authorization(config) + self.session.auth = authorization.auth_method + + def request(self, method, url, headers=None, body=None, post_params=None, _request_timeout=None): + """Perform requests. + + :param method: http request method + :param url: http request url + :param headers: http request headers + :param body: request json body, for `application/json` + :param post_params: request post parameters, + `application/x-www-form-urlencoded` + and `multipart/form-data` + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + """ + method = method.upper() + if method not in ["GET", "HEAD", "DELETE", "POST", "PUT", "PATCH", "OPTIONS"]: + raise ValueError("Method %s not allowed", method) + + if post_params and body: + raise ApiValueError("body parameter cannot be used with post_params parameter.") + + post_params = post_params or {} + headers = headers or {} + + try: + # For `POST`, `PUT`, `PATCH`, `OPTIONS`, `DELETE` + if method in ["POST", "PUT", "PATCH", "OPTIONS", "DELETE"]: + + # no content type provided or payload is json + content_type = headers.get("Content-Type") + if not content_type or re.search("json", content_type, re.IGNORECASE): + request_body = None + if body is not None: + request_body = json.dumps(body) + r = self.session.request( + method, + url, + data=request_body, + headers=headers, + ) + elif content_type == "application/x-www-form-urlencoded": + r = self.session.request( + method, + url, + params=post_params, + headers=headers, + ) + elif content_type == "multipart/form-data": + # must del headers['Content-Type'], or the correct + # Content-Type which generated by urllib3 will be + # overwritten. + del headers["Content-Type"] + # Ensures that dict objects are serialized + post_params = [(a, json.dumps(b)) if isinstance(b, dict) else (a, b) for a, b in post_params] + r = self.session.request( + method, + url, + files=post_params, + headers=headers, + ) + # Pass a `string` parameter directly in the body to support + # other content types than JSON when `body` argument is + # provided in serialized form. + elif isinstance(body, str) or isinstance(body, bytes): + r = self.session.request( + method, + url, + data=body, + headers=headers, + ) + elif headers["Content-Type"] == "text/plain" and isinstance(body, bool): + request_body = "true" if body else "false" + r = self.session.request(method, url, data=request_body, headers=headers) + else: + # Cannot generate the request from given parameters + msg = """Cannot prepare a request message for provided + arguments. Please check that your arguments match + declared content type.""" + raise ApiException(status=0, reason=msg) + # For `GET`, `HEAD` + else: + r = self.session.request( + method, + url, + params={}, + headers=headers, + ) + except requests.exceptions.SSLError as e: + msg = "\n".join([type(e).__name__, str(e)]) + raise ApiException(status=0, reason=msg) + + return RESTResponse(r)