diff --git a/mpt_api_client/resources/accounts/account_users.py b/mpt_api_client/resources/accounts/account_users.py new file mode 100644 index 00000000..947486b6 --- /dev/null +++ b/mpt_api_client/resources/accounts/account_users.py @@ -0,0 +1,73 @@ +from mpt_api_client.http import AsyncService, Service +from mpt_api_client.http.mixins import ( + AsyncCollectionMixin, + AsyncCreateMixin, + AsyncDeleteMixin, + AsyncGetMixin, + CollectionMixin, + CreateMixin, + DeleteMixin, + GetMixin, +) +from mpt_api_client.models import Model +from mpt_api_client.models.model import BaseModel +from mpt_api_client.resources.accounts.mixins import ( + AsyncInvitableMixin, + InvitableMixin, +) + + +class AccountUser(Model): + """Account User resource. + + Attributes: + user: Reference to the platform user. + account: Reference to the account the user belongs to. + groups: User groups the account user belongs to. + buyers: Buyers the account user is scoped to. + modules: Modules the account user has access to. + invitation: Invitation details for the account user. + last_login_at: Timestamp of the last successful login. + audit: Audit information. + """ + + user: BaseModel | None + account: BaseModel | None + groups: list[BaseModel] | None + buyers: list[BaseModel] | None + modules: list[BaseModel] | None + invitation: BaseModel | None + last_login_at: str | None + audit: BaseModel | None + + +class AccountUsersServiceConfig: + """Account Users Service Configuration.""" + + _endpoint = "/public/v1/accounts/account-users" + _model_class = AccountUser + _collection_key = "data" + + +class AccountUsersService( + CreateMixin[AccountUser], + GetMixin[AccountUser], + DeleteMixin, + InvitableMixin[AccountUser], + CollectionMixin[AccountUser], + Service[AccountUser], + AccountUsersServiceConfig, +): + """Account Users Service.""" + + +class AsyncAccountUsersService( + AsyncCreateMixin[AccountUser], + AsyncGetMixin[AccountUser], + AsyncDeleteMixin, + AsyncInvitableMixin[AccountUser], + AsyncCollectionMixin[AccountUser], + AsyncService[AccountUser], + AccountUsersServiceConfig, +): + """Asynchronous Account Users Service.""" diff --git a/mpt_api_client/resources/accounts/accounts.py b/mpt_api_client/resources/accounts/accounts.py index fc46a61e..7547de8f 100644 --- a/mpt_api_client/resources/accounts/accounts.py +++ b/mpt_api_client/resources/accounts/accounts.py @@ -1,5 +1,9 @@ from mpt_api_client.http import AsyncHTTPClient, HTTPClient from mpt_api_client.resources.accounts.account import AccountsService, AsyncAccountsService +from mpt_api_client.resources.accounts.account_users import ( + AccountUsersService, + AsyncAccountUsersService, +) from mpt_api_client.resources.accounts.api_tokens import ApiTokensService, AsyncApiTokensService from mpt_api_client.resources.accounts.buyers import AsyncBuyersService, BuyersService from mpt_api_client.resources.accounts.cloud_tenants import ( @@ -10,6 +14,7 @@ from mpt_api_client.resources.accounts.licensees import AsyncLicenseesService, LicenseesService from mpt_api_client.resources.accounts.modules import AsyncModulesService, ModulesService from mpt_api_client.resources.accounts.sellers import AsyncSellersService, SellersService +from mpt_api_client.resources.accounts.services import AsyncServicesService, ServicesService from mpt_api_client.resources.accounts.user_groups import ( AsyncUserGroupsService, UserGroupsService, @@ -73,6 +78,16 @@ def erp_links(self) -> ErpLinksService: """ERP Links service.""" return ErpLinksService(http_client=self.http_client) + @property + def account_users(self) -> AccountUsersService: + """Account Users service.""" + return AccountUsersService(http_client=self.http_client) + + @property + def services(self) -> ServicesService: + """Services service.""" + return ServicesService(http_client=self.http_client) + class AsyncAccounts: """Async Accounts MPT API Module.""" @@ -129,3 +144,13 @@ def buyers(self) -> AsyncBuyersService: def erp_links(self) -> AsyncErpLinksService: """ERP Links service.""" return AsyncErpLinksService(http_client=self.http_client) + + @property + def account_users(self) -> AsyncAccountUsersService: + """Account Users service.""" + return AsyncAccountUsersService(http_client=self.http_client) + + @property + def services(self) -> AsyncServicesService: + """Services service.""" + return AsyncServicesService(http_client=self.http_client) diff --git a/mpt_api_client/resources/accounts/services.py b/mpt_api_client/resources/accounts/services.py new file mode 100644 index 00000000..b9bc3d41 --- /dev/null +++ b/mpt_api_client/resources/accounts/services.py @@ -0,0 +1,53 @@ +from mpt_api_client.http import AsyncService, Service +from mpt_api_client.http.mixins import ( + AsyncCollectionMixin, + AsyncGetMixin, + CollectionMixin, + GetMixin, +) +from mpt_api_client.models import Model +from mpt_api_client.models.model import BaseModel + + +class ServiceIdentity(Model): + """Service identity resource exposed by the accounts services endpoint. + + Attributes: + name: Service identity name. + status: Service identity status. + description: Service identity description. + icon: URL or identifier for the service identity icon. + audit: Audit information. + """ + + name: str | None + status: str | None + description: str | None + icon: str | None + audit: BaseModel | None + + +class ServicesServiceConfig: + """Services Service Configuration.""" + + _endpoint = "/public/v1/accounts/services" + _model_class = ServiceIdentity + _collection_key = "data" + + +class ServicesService( + GetMixin[ServiceIdentity], + CollectionMixin[ServiceIdentity], + Service[ServiceIdentity], + ServicesServiceConfig, +): + """Services Service.""" + + +class AsyncServicesService( + AsyncGetMixin[ServiceIdentity], + AsyncCollectionMixin[ServiceIdentity], + AsyncService[ServiceIdentity], + ServicesServiceConfig, +): + """Asynchronous Services Service.""" diff --git a/tests/unit/resources/accounts/test_account_users.py b/tests/unit/resources/accounts/test_account_users.py new file mode 100644 index 00000000..46c089f9 --- /dev/null +++ b/tests/unit/resources/accounts/test_account_users.py @@ -0,0 +1,64 @@ +import pytest + +from mpt_api_client.resources.accounts.account_users import ( + AccountUsersService, + AsyncAccountUsersService, +) + +ACCOUNT_USERS_PATH = "/public/v1/accounts/account-users" + + +@pytest.fixture +def account_users_service(http_client): + return AccountUsersService(http_client=http_client) + + +@pytest.fixture +def async_account_users_service(async_http_client): + return AsyncAccountUsersService(http_client=async_http_client) + + +def test_endpoint(account_users_service): + result = account_users_service.build_path() + + assert result == ACCOUNT_USERS_PATH + + +def test_async_endpoint(async_account_users_service): + result = async_account_users_service.build_path() + + assert result == ACCOUNT_USERS_PATH + + +@pytest.mark.parametrize( + "method", + ["get", "create", "delete", "accept_invite", "resend_invite", "send_new_invite"], +) +def test_methods_present(account_users_service, method): + result = hasattr(account_users_service, method) + + assert result is True + + +@pytest.mark.parametrize( + "method", + ["get", "create", "delete", "accept_invite", "resend_invite", "send_new_invite"], +) +def test_async_methods_present(async_account_users_service, method): + result = hasattr(async_account_users_service, method) + + assert result is True + + +@pytest.mark.parametrize("method", ["update"]) +def test_undocumented_methods_absent(account_users_service, method): + result = hasattr(account_users_service, method) + + assert result is False + + +@pytest.mark.parametrize("method", ["update"]) +def test_async_undocumented_methods_absent(async_account_users_service, method): + result = hasattr(async_account_users_service, method) + + assert result is False diff --git a/tests/unit/resources/accounts/test_accounts.py b/tests/unit/resources/accounts/test_accounts.py index 91aa72d1..42c88147 100644 --- a/tests/unit/resources/accounts/test_accounts.py +++ b/tests/unit/resources/accounts/test_accounts.py @@ -1,6 +1,10 @@ import pytest from mpt_api_client.resources.accounts.account import AccountsService, AsyncAccountsService +from mpt_api_client.resources.accounts.account_users import ( + AccountUsersService, + AsyncAccountUsersService, +) from mpt_api_client.resources.accounts.accounts import Accounts, AsyncAccounts from mpt_api_client.resources.accounts.api_tokens import ( ApiTokensService, @@ -15,6 +19,7 @@ from mpt_api_client.resources.accounts.licensees import AsyncLicenseesService, LicenseesService from mpt_api_client.resources.accounts.modules import AsyncModulesService, ModulesService from mpt_api_client.resources.accounts.sellers import AsyncSellersService, SellersService +from mpt_api_client.resources.accounts.services import AsyncServicesService, ServicesService from mpt_api_client.resources.accounts.user_groups import ( AsyncUserGroupsService, UserGroupsService, @@ -45,6 +50,8 @@ def async_accounts(async_http_client): ("cloud_tenants", CloudTenantsService), ("buyers", BuyersService), ("erp_links", ErpLinksService), + ("account_users", AccountUsersService), + ("services", ServicesService), ], ) def test_accounts_properties(accounts, property_name, expected_service_class): @@ -67,6 +74,8 @@ def test_accounts_properties(accounts, property_name, expected_service_class): ("cloud_tenants", AsyncCloudTenantsService), ("buyers", AsyncBuyersService), ("erp_links", AsyncErpLinksService), + ("account_users", AsyncAccountUsersService), + ("services", AsyncServicesService), ], ) def test_async_accounts_properties(async_accounts, property_name, expected_service_class): diff --git a/tests/unit/resources/accounts/test_services.py b/tests/unit/resources/accounts/test_services.py new file mode 100644 index 00000000..48cf000a --- /dev/null +++ b/tests/unit/resources/accounts/test_services.py @@ -0,0 +1,55 @@ +import pytest + +from mpt_api_client.resources.accounts.services import AsyncServicesService, ServicesService + +SERVICES_PATH = "/public/v1/accounts/services" + + +@pytest.fixture +def services_service(http_client): + return ServicesService(http_client=http_client) + + +@pytest.fixture +def async_services_service(async_http_client): + return AsyncServicesService(http_client=async_http_client) + + +def test_endpoint(services_service): + result = services_service.build_path() + + assert result == SERVICES_PATH + + +def test_async_endpoint(async_services_service): + result = async_services_service.build_path() + + assert result == SERVICES_PATH + + +@pytest.mark.parametrize("method", ["get"]) +def test_methods_present(services_service, method): + result = hasattr(services_service, method) + + assert result is True + + +@pytest.mark.parametrize("method", ["get"]) +def test_async_methods_present(async_services_service, method): + result = hasattr(async_services_service, method) + + assert result is True + + +@pytest.mark.parametrize("method", ["create", "update", "delete"]) +def test_undocumented_methods_absent(services_service, method): + result = hasattr(services_service, method) + + assert result is False + + +@pytest.mark.parametrize("method", ["create", "update", "delete"]) +def test_async_undocumented_methods_absent(async_services_service, method): + result = hasattr(async_services_service, method) + + assert result is False