From d44f2d197430c8a07e3ab9b7d5482c8c4541c015 Mon Sep 17 00:00:00 2001 From: Mateus Silva Date: Fri, 12 Dec 2025 15:24:32 -0300 Subject: [PATCH 1/4] feat: add comprehensive documentation and tests for Run class Add detailed docstrings for all Run class methods with usage examples and authorization policy references. Include new EmailTestData type for email testing functionality. Implement comprehensive test suite covering all Run methods with mocked API responses. --- src/tagoio_sdk/modules/Resources/Run.py | 338 ++++++++++++--- src/tagoio_sdk/modules/Resources/Run_Type.py | 11 + tests/Resources/test_run.py | 421 +++++++++++++++++++ 3 files changed, 721 insertions(+), 49 deletions(-) create mode 100644 tests/Resources/test_run.py diff --git a/src/tagoio_sdk/modules/Resources/Run.py b/src/tagoio_sdk/modules/Resources/Run.py index 63d7f8e..1bf0d51 100644 --- a/src/tagoio_sdk/modules/Resources/Run.py +++ b/src/tagoio_sdk/modules/Resources/Run.py @@ -1,5 +1,5 @@ +from typing import Dict from typing import Optional -from typing import TypedDict from tagoio_sdk.common.Common_Type import GenericID from tagoio_sdk.common.Common_Type import Query @@ -9,6 +9,7 @@ from tagoio_sdk.modules.Resources.Notification_Type import NotificationInfo from tagoio_sdk.modules.Resources.Run_Type import CustomDomainCreate from tagoio_sdk.modules.Resources.Run_Type import CustomDomainInfo +from tagoio_sdk.modules.Resources.Run_Type import EmailTestData from tagoio_sdk.modules.Resources.Run_Type import LoginAsUserOptions from tagoio_sdk.modules.Resources.Run_Type import LoginResponse from tagoio_sdk.modules.Resources.Run_Type import RunInfo @@ -21,13 +22,23 @@ class Run(TagoIOModule): - """ - Manage services in account - Be sure to use an account token with “write” permissions when using - functions like create, edit and delete. - """ - def info(self) -> RunInfo: + """ + @description: + Retrieves information about the current Run environment configuration. + + @see: + https://help.tago.io/portal/en/kb/articles/191-tagorun TagoRun + https://help.tago.io/portal/en/kb/articles/run-themes Run Themes + + @example: + If receive an error "Authorization Denied", check policy **Profile** / **Access TagoRun settings** in Access Management. + ```python + resources = Resources() + result = resources.run.info() + print(result) # {'name': 'My Run Environment', 'logo': 'https://example.com/logo.png', ...} + ``` + """ result = self.doRequest( { "path": "/run", @@ -37,7 +48,23 @@ def info(self) -> RunInfo: return result - def edit(self, data: RunInfo) -> str: + def edit(self, data: Dict) -> str: + """ + @description: + Updates the Run environment configuration settings. + + @see: + https://help.tago.io/portal/en/kb/articles/191-tagorun TagoRun + https://help.tago.io/portal/en/kb/articles/run-themes Run Themes + + @example: + If receive an error "Authorization Denied", check policy **Profile** / **Edit TagoRun settings** in Access Management. + ```python + resources = Resources() + result = resources.run.edit({"name": "My Run Environment", "logo": "https://example.com/logo.png"}) + print(result) # TagoIO Run Successfully Updated + ``` + """ result = self.doRequest( { "path": "/run", @@ -49,6 +76,25 @@ def edit(self, data: RunInfo) -> str: return result def listUsers(self, query: Query) -> list[UserInfo]: + """ + @description: + Retrieves a paginated list of Run users with customizable fields and filtering options. + + @see: + https://help.tago.io/portal/en/kb/articles/191-tagorun TagoRun + + @example: + If receive an error "Authorization Denied", or return empty list check policy **Run User** / **Access** in Access Management. + ```python + resources = Resources() + result = resources.run.listUsers({ + "page": 1, + "fields": ["id", "name", "email"], + "amount": 20 + }) + print(result) # [{'id': 'user-id-123', 'name': 'John Doe', 'email': 'example@email.com'}] + ``` + """ if "orderBy" in query: firstArgument = query["orderBy"][0] secondArgument = query["orderBy"][1] @@ -74,6 +120,21 @@ def listUsers(self, query: Query) -> list[UserInfo]: return result def userInfo(self, userID: GenericID) -> UserInfo: + """ + @description: + Retrieves detailed information about a specific Run user. + + @see: + https://help.tago.io/portal/en/kb/articles/191-tagorun TagoRun + + @example: + If receive an error "Authorization Denied", check policy **Run User** / **Access** in Access Management. + ```python + resources = Resources() + result = resources.run.userInfo("user-id-123") + print(result) # {'id': 'user-id-123', 'name': 'John Doe', 'email': 'example@email.com', ...} + ``` + """ result = self.doRequest( { "path": f"/run/users/{userID}", @@ -85,7 +146,27 @@ def userInfo(self, userID: GenericID) -> UserInfo: return result - def userCreate(self, data: UserCreateInfo) -> str: + def userCreate(self, data: UserCreateInfo) -> Dict[str, str]: + """ + @description: + Creates a new user in the Run environment. + + @see: + https://help.tago.io/portal/en/kb/articles/191-tagorun TagoRun + + @example: + If receive an error "Authorization Denied", check policy **Run User** / **Create** in Access Management. + ```python + resources = Resources() + result = resources.run.userCreate({ + "name": "John Doe", + "email": "john@example.com", + "password": "secure123", + "timezone": "America/New_York" + }) + print(result) # {'user': 'user-id-123'} + ``` + """ result = self.doRequest( { "path": "/run/users", @@ -96,7 +177,22 @@ def userCreate(self, data: UserCreateInfo) -> str: return result - def userEdit(self, userID: GenericID, data: UserInfo) -> str: + def userEdit(self, userID: GenericID, data: Dict) -> str: + """ + @description: + Updates information for an existing Run user. + + @see: + https://help.tago.io/portal/en/kb/articles/191-tagorun TagoRun + + @example: + If receive an error "Authorization Denied", check policy **Run User** / **Edit** in Access Management. + ```python + resources = Resources() + result = resources.run.userEdit("user-id-123", {"name": "Updated Name"}) + print(result) # TagoIO Run User Successfully Updated + ``` + """ result = self.doRequest( { "path": f"/run/users/{userID}", @@ -108,6 +204,21 @@ def userEdit(self, userID: GenericID, data: UserInfo) -> str: return result def userDelete(self, userID: GenericID) -> str: + """ + @description: + Permanently deletes a user from the Run environment. + + @see: + https://help.tago.io/portal/en/kb/articles/191-tagorun TagoRun + + @example: + If receive an error "Authorization Denied", check policy **Run User** / **Delete** in Access Management. + ```python + resources = Resources() + result = resources.run.userDelete("user-id-123") + print(result) # Successfully Removed + ``` + """ result = self.doRequest( { "path": f"/run/users/{userID}", @@ -117,9 +228,19 @@ def userDelete(self, userID: GenericID) -> str: return result - def loginAsUser( - self, userID: GenericID, options: Optional[LoginAsUserOptions] - ) -> LoginResponse: + def loginAsUser(self, userID: GenericID, options: Optional[LoginAsUserOptions] = None) -> LoginResponse: + """ + @description: + Generates a login token to authenticate as a specific Run user. + + @example: + If receive an error "Authorization Denied", check policy **Run User** / **Login as user** in Access Management. + ```python + resources = Resources() + result = resources.run.loginAsUser("user-id-123") + print(result["token"]) # eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + ``` + """ result = self.doRequest( { "path": f"/run/users/{userID}/login", @@ -132,11 +253,18 @@ def loginAsUser( return result - class emailData(TypedDict): - subject: str - body: str - - def emailTest(self, data: emailData) -> str: + def emailTest(self, data: EmailTestData) -> str: + """ + @description: + Tests the email configuration by sending a test message. + + @example: + ```python + resources = Resources({"token": "YOUR-PROFILE-TOKEN"}) + result = resources.run.emailTest({"subject": "Test Email", "body": "This is a test message"}) + print(result) # E-mail sent to example@email.com + ``` + """ result = self.doRequest( { "path": "/run/email_test", @@ -148,6 +276,21 @@ def emailTest(self, data: emailData) -> str: return result def notificationList(self, userID: GenericID) -> list[NotificationInfo]: + """ + @description: + Retrieves a list of notifications for a specific Run user. + + @see: + https://help.tago.io/portal/en/kb/articles/223-notifications-for-users Notifications for Users + + @example: + If receive an error "Authorization Denied", check policy **Run User** / **Access notification** in Access Management. + ```python + resources = Resources() + result = resources.run.notificationList("user-id-123") + print(result) # [{'id': 'notification-id-123', 'title': 'System Update', 'message': 'Features', ...}] + ``` + """ result = self.doRequest( { "path": f"/run/notification/{userID}", @@ -157,9 +300,25 @@ def notificationList(self, userID: GenericID) -> list[NotificationInfo]: return result - def notificationCreate( - self, userID: GenericID, data: NotificationCreate - ) -> NotificationCreateReturn: + def notificationCreate(self, userID: GenericID, data: NotificationCreate) -> NotificationCreateReturn: + """ + @description: + Creates a new notification for a Run user. + + @see: + https://help.tago.io/portal/en/kb/articles/223-notifications-for-users Notifications for Users + + @example: + If receive an error "Authorization Denied", check policy **Run User** / **Create notification** in Access Management. + ```python + resources = Resources() + result = resources.run.notificationCreate("user-id-123", { + "title": "Update", + "message": "New feature available" + }) + print(result) # {'id': 'notification-id-123'} + ``` + """ result = self.doRequest( { "path": "/run/notification/", @@ -173,9 +332,22 @@ def notificationCreate( return result - def notificationEdit( - self, notificationID: GenericID, data: NotificationCreate - ) -> str: + def notificationEdit(self, notificationID: GenericID, data: Dict) -> str: + """ + @description: + Updates an existing notification in the Run environment. + + @see: + https://help.tago.io/portal/en/kb/articles/223-notifications-for-users Notifications for Users + + @example: + If receive an error "Authorization Denied", check policy **Run User** / **Edit notification** in Access Management. + ```python + resources = Resources() + result = resources.run.notificationEdit("notification-id-123", {"title": "Updated Title"}) + print(result) # TagoIO Notification User Successfully Updated + ``` + """ result = self.doRequest( { "path": f"/run/notification/{notificationID}", @@ -187,6 +359,21 @@ def notificationEdit( return result def notificationDelete(self, notificationID: GenericID) -> str: + """ + @description: + Deletes a notification from the Run environment. + + @see: + https://help.tago.io/portal/en/kb/articles/223-notifications-for-users Notifications for Users + + @example: + If receive an error "Authorization Denied", check policy **Run User** / **Delete notification** in Access Management. + ```python + resources = Resources() + result = resources.run.notificationDelete("notification-id-123") + print(result) # Successfully Removed + ``` + """ result = self.doRequest( { "path": f"/run/notification/{notificationID}", @@ -198,9 +385,19 @@ def notificationDelete(self, notificationID: GenericID) -> str: def ssoSAMLInfo(self) -> RunSAMLInfo: """ - Get the SAML Single Sign-On information for the account's RUN. + @description: + Retrieves the SAML Single Sign-On configuration information for the Run environment. + + @see: + https://help.tago.io/portal/en/kb/articles/491-single-sign-on-sso Single Sign-On (SSO) + + @example: + ```python + resources = Resources({"token": "YOUR-PROFILE-TOKEN"}) + result = resources.run.ssoSAMLInfo() + print(result) # {'sp': {'entity_id': 'https://example.com', ...}, ...} + ``` """ - result = self.doRequest( { "path": "/run/sso/saml", @@ -212,10 +409,22 @@ def ssoSAMLInfo(self) -> RunSAMLInfo: def ssoSAMLEdit(self, data: RunSAMLEditInfo) -> str: """ - Edit the SAML Single Sign-On metadata and mappings for the account's RUN. - :param: data Updated data for a RUN's SAML Single Sign-On configuration. + @description: + Updates the SAML SSO configuration for the Run environment. + + @see: + https://help.tago.io/portal/en/kb/articles/491-single-sign-on-sso Single Sign-On (SSO) + + @example: + ```python + resources = Resources({"token": "YOUR-PROFILE-TOKEN"}) + result = resources.run.ssoSAMLEdit({ + "active": True, + "idp_metadata": "..." + }) + print(result) # TagoIO Run SAML SSO Successfully Updated + ``` """ - result = self.doRequest( { "path": "/run/sso/saml", @@ -226,16 +435,23 @@ def ssoSAMLEdit(self, data: RunSAMLEditInfo) -> str: return result - def createCustomDomain( - self, profile_id: str, customDomainData: CustomDomainCreate - ) -> str: + def createCustomDomain(self, profile_id: str, customDomainData: CustomDomainCreate) -> str: """ - Create a TagoRUN custom domain for the profile. - :param: profile_id ID of the profile - :param: customDomainData query params - :returns: Success message. + @description: + Creates a custom domain configuration for the Run environment. + + @see: + https://help.tago.io/portal/en/kb/articles/custom-domain-configuration Custom Domain Configuration + + @example: + ```python + resources = Resources({"token": "YOUR-PROFILE-TOKEN"}) + result = resources.run.createCustomDomain("profile-id-123", { + "domain": "app.mycompany.com" + }) + print(result) # Custom domain created successfully + ``` """ - result = self.doRequest( { "path": f"/run/customdomain/{profile_id}", @@ -248,11 +464,19 @@ def createCustomDomain( def getCustomDomain(self, profile_id: str) -> CustomDomainInfo: """ - set details of TagoRun custom domain for the profile. - :param: profile_id ID of the profile - :returns: Data for the profile's custom DNS configuration. + @description: + Retrieves the custom domain configuration for a Run profile. + + @see: + https://help.tago.io/portal/en/kb/articles/custom-domain-configuration Custom Domain Configuration + + @example: + ```python + resources = Resources({"token": "YOUR-PROFILE-TOKEN"}) + result = resources.run.getCustomDomain("profile-id-123") + print(result) # {'domain': 'app.mycompany.com', 'verified': True, ...} + ``` """ - result = self.doRequest( { "path": f"/run/customdomain/{profile_id}", @@ -266,11 +490,19 @@ def getCustomDomain(self, profile_id: str) -> CustomDomainInfo: def deleteCustomDomain(self, profile_id: str) -> str: """ - delete a TagoRUN custom domain for the profile. - :param: profile_id ID of the profile - :returns: Success message. + @description: + Removes the custom domain configuration from a Run profile. + + @see: + https://help.tago.io/portal/en/kb/articles/custom-domain-configuration Custom Domain Configuration + + @example: + ```python + resources = Resources({"token": "YOUR-PROFILE-TOKEN"}) + result = resources.run.deleteCustomDomain("profile-id-123") + print(result) # Custom domain deleted successfully + ``` """ - result = self.doRequest( { "path": f"/run/customdomain/{profile_id}", @@ -281,11 +513,19 @@ def deleteCustomDomain(self, profile_id: str) -> str: def regenerateCustomDomain(self, profile_id: str) -> str: """ - Regenerate a TagoRUN custom domain for the profile. - :param: profile_id ID of the profile - :returns: Success message. + @description: + Regenerates the custom domain configuration for a Run profile. + + @see: + https://help.tago.io/portal/en/kb/articles/custom-domain-configuration Custom Domain Configuration + + @example: + ```python + resources = Resources({"token": "YOUR-PROFILE-TOKEN"}) + result = resources.run.regenerateCustomDomain("profile-id-123") + print(result) # Custom domain regenerated successfully + ``` """ - result = self.doRequest( { "path": f"/run/customdomain/regenerate/{profile_id}", diff --git a/src/tagoio_sdk/modules/Resources/Run_Type.py b/src/tagoio_sdk/modules/Resources/Run_Type.py index e18dcb8..6e22b66 100644 --- a/src/tagoio_sdk/modules/Resources/Run_Type.py +++ b/src/tagoio_sdk/modules/Resources/Run_Type.py @@ -255,6 +255,17 @@ class LoginAsUserOptions(TypedDict): """ +class EmailTestData(TypedDict): + subject: str + """ + Subject of the test email. + """ + body: str + """ + Body content of the test email. + """ + + class SAMLAttributeMappings(TypedDict): email: str firstName: str diff --git a/tests/Resources/test_run.py b/tests/Resources/test_run.py new file mode 100644 index 0000000..67216d8 --- /dev/null +++ b/tests/Resources/test_run.py @@ -0,0 +1,421 @@ +import os + +from requests_mock.mocker import Mocker + +from tagoio_sdk.modules.Resources.Resources import Resources + + +os.environ["T_ANALYSIS_TOKEN"] = "your_token_value" + + +def mockRunInfo() -> dict: + return { + "status": True, + "result": { + "profile": "profile_id_123", + "active": True, + "name": "My Run Environment", + "sub_title": "IoT Application", + "url": "myapp.run.tago.io", + "email_domain": None, + "signup_method": "default", + "favicon": None, + "logo": "https://example.com/logo.png", + "signup_logo": None, + "signup_logo_options": {}, + "sidebar_buttons": [], + "signup_fields": [], + "email_templates": {}, + "feature_devicewifisetup": {}, + "feature_geolocation": {}, + "theme": {}, + "integration": {}, + "sso_saml_active": False, + "security": {}, + }, + } + + +def mockRunEdit() -> dict: + return {"status": True, "result": "TagoIO Run Successfully Updated"} + + +def mockUserList() -> dict: + return { + "status": True, + "result": [ + { + "id": "user_id_1", + "name": "John Doe", + "email": "john@example.com", + "timezone": "America/New_York", + "created_at": "2023-02-21T15:17:35.759Z", + "updated_at": "2023-02-21T15:17:35.759Z", + "last_login": "2023-02-21T15:17:35.759Z", + }, + { + "id": "user_id_2", + "name": "Jane Smith", + "email": "jane@example.com", + "timezone": "America/Los_Angeles", + "created_at": "2023-02-21T16:17:35.759Z", + "updated_at": "2023-02-21T16:17:35.759Z", + "last_login": "2023-02-21T16:17:35.759Z", + }, + ], + } + + +def mockUserInfo() -> dict: + return { + "status": True, + "result": { + "id": "user_id_1", + "name": "John Doe", + "email": "john@example.com", + "timezone": "America/New_York", + "company": "ACME Corp", + "phone": "+1234567890", + "language": "en-US", + "profile": "profile_id_123", + "active": True, + "newsletter": False, + "last_login": "2023-02-21T15:17:35.759Z", + "created_at": "2023-02-21T15:17:35.759Z", + "updated_at": "2023-02-21T15:17:35.759Z", + "options": {}, + "tags": [{"key": "role", "value": "admin"}], + }, + } + + +def mockUserCreate() -> dict: + return {"status": True, "result": {"user": "user_id_new"}} + + +def mockUserEdit() -> dict: + return {"status": True, "result": "TagoIO Run User Successfully Updated"} + + +def mockUserDelete() -> dict: + return {"status": True, "result": "Successfully Removed"} + + +def mockLoginAsUser() -> dict: + return { + "status": True, + "result": { + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...", + "expire_date": "2024-02-21T15:17:35.759Z", + }, + } + + +def mockEmailTest() -> dict: + return {"status": True, "result": "E-mail sent to example@email.com"} + + +def mockNotificationList() -> dict: + return { + "status": True, + "result": [ + { + "id": "notification_id_1", + "title": "System Update", + "message": "New features available", + }, + { + "id": "notification_id_2", + "title": "Maintenance", + "message": "Scheduled maintenance tonight", + }, + ], + } + + +def mockNotificationCreate() -> dict: + return {"status": True, "result": {"id": "notification_id_new"}} + + +def mockNotificationEdit() -> dict: + return {"status": True, "result": "TagoIO Notification User Successfully Updated"} + + +def mockNotificationDelete() -> dict: + return {"status": True, "result": "Successfully Removed"} + + +def mockSSOSAMLInfo() -> dict: + return { + "status": True, + "result": { + "sp": { + "entity_id": "https://example.com", + "acs_url": "https://example.com/acs", + "metadata": "...", + }, + "idp": {"issuer": "https://idp.example.com"}, + "mapping": {"email": "email", "firstName": "firstName"}, + }, + } + + +def mockSSOSAMLEdit() -> dict: + return {"status": True, "result": "TagoIO Run SAML SSO Successfully Updated"} + + +def mockCustomDomainCreate() -> dict: + return {"status": True, "result": "Custom domain created successfully"} + + +def mockCustomDomainInfo() -> dict: + return { + "status": True, + "result": { + "active": True, + "domain": "mycompany.com", + "subdomain": "app", + "email": "app.mycompany.com", + "dns_ssl": {"status": True, "type": "TXT", "key": "key1", "value": "value1"}, + "dns_page": {"status": True, "type": "CNAME", "key": "key2", "value": "value2"}, + "dns_email_1": {"status": True, "type": "MX", "key": "key3", "value": "value3"}, + "dns_email_2": {"status": True, "type": "TXT", "key": "key4", "value": "value4"}, + "dns_email_3": {"status": True, "type": "TXT", "key": "key5", "value": "value5"}, + "created_at": "2023-02-21T15:17:35.759Z", + }, + } + + +def mockCustomDomainDelete() -> dict: + return {"status": True, "result": "Custom domain deleted successfully"} + + +def mockCustomDomainRegenerate() -> dict: + return {"status": True, "result": "Custom domain regenerated successfully"} + + +def testRunMethodInfo(requests_mock: Mocker) -> None: + """Test info method of Run class.""" + mock_response = mockRunInfo() + requests_mock.get("https://api.tago.io/run", json=mock_response) + + resources = Resources({"token": "your_token_value"}) + result = resources.run.info() + + assert result["name"] == "My Run Environment" + assert result["active"] is True + + +def testRunMethodEdit(requests_mock: Mocker) -> None: + """Test edit method of Run class.""" + mock_response = mockRunEdit() + requests_mock.put("https://api.tago.io/run", json=mock_response) + + resources = Resources({"token": "your_token_value"}) + result = resources.run.edit({"name": "Updated Name"}) + + assert result == "TagoIO Run Successfully Updated" + + +def testRunMethodListUsers(requests_mock: Mocker) -> None: + """Test listUsers method of Run class.""" + mock_response = mockUserList() + requests_mock.get("https://api.tago.io/run/users", json=mock_response) + + resources = Resources({"token": "your_token_value"}) + result = resources.run.listUsers({"page": 1, "amount": 20}) + + assert isinstance(result, list) + assert len(result) == 2 + assert result[0]["id"] == "user_id_1" + assert result[1]["id"] == "user_id_2" + + +def testRunMethodUserInfo(requests_mock: Mocker) -> None: + """Test userInfo method of Run class.""" + mock_response = mockUserInfo() + requests_mock.get("https://api.tago.io/run/users/user_id_1", json=mock_response) + + resources = Resources({"token": "your_token_value"}) + result = resources.run.userInfo("user_id_1") + + assert result["id"] == "user_id_1" + assert result["name"] == "John Doe" + assert result["email"] == "john@example.com" + + +def testRunMethodUserCreate(requests_mock: Mocker) -> None: + """Test userCreate method of Run class.""" + mock_response = mockUserCreate() + requests_mock.post("https://api.tago.io/run/users", json=mock_response) + + resources = Resources({"token": "your_token_value"}) + result = resources.run.userCreate( + { + "name": "New User", + "email": "newuser@example.com", + "password": "secure123", + "timezone": "America/New_York", + } + ) + + assert result["user"] == "user_id_new" + + +def testRunMethodUserEdit(requests_mock: Mocker) -> None: + """Test userEdit method of Run class.""" + mock_response = mockUserEdit() + requests_mock.put("https://api.tago.io/run/users/user_id_1", json=mock_response) + + resources = Resources({"token": "your_token_value"}) + result = resources.run.userEdit("user_id_1", {"name": "Updated Name"}) + + assert result == "TagoIO Run User Successfully Updated" + + +def testRunMethodUserDelete(requests_mock: Mocker) -> None: + """Test userDelete method of Run class.""" + mock_response = mockUserDelete() + requests_mock.delete("https://api.tago.io/run/users/user_id_1", json=mock_response) + + resources = Resources({"token": "your_token_value"}) + result = resources.run.userDelete("user_id_1") + + assert result == "Successfully Removed" + + +def testRunMethodLoginAsUser(requests_mock: Mocker) -> None: + """Test loginAsUser method of Run class.""" + mock_response = mockLoginAsUser() + requests_mock.get("https://api.tago.io/run/users/user_id_1/login", json=mock_response) + + resources = Resources({"token": "your_token_value"}) + result = resources.run.loginAsUser("user_id_1") + + assert "token" in result + assert result["token"].startswith("eyJ") + + +def testRunMethodEmailTest(requests_mock: Mocker) -> None: + """Test emailTest method of Run class.""" + mock_response = mockEmailTest() + requests_mock.post("https://api.tago.io/run/email_test", json=mock_response) + + resources = Resources({"token": "your_token_value"}) + result = resources.run.emailTest({"subject": "Test", "body": "Test message"}) + + assert result == "E-mail sent to example@email.com" + + +def testRunMethodNotificationList(requests_mock: Mocker) -> None: + """Test notificationList method of Run class.""" + mock_response = mockNotificationList() + requests_mock.get("https://api.tago.io/run/notification/user_id_1", json=mock_response) + + resources = Resources({"token": "your_token_value"}) + result = resources.run.notificationList("user_id_1") + + assert isinstance(result, list) + assert len(result) == 2 + assert result[0]["id"] == "notification_id_1" + + +def testRunMethodNotificationCreate(requests_mock: Mocker) -> None: + """Test notificationCreate method of Run class.""" + mock_response = mockNotificationCreate() + requests_mock.post("https://api.tago.io/run/notification/", json=mock_response) + + resources = Resources({"token": "your_token_value"}) + result = resources.run.notificationCreate("user_id_1", {"title": "Alert", "message": "Important message"}) + + assert result["id"] == "notification_id_new" + + +def testRunMethodNotificationEdit(requests_mock: Mocker) -> None: + """Test notificationEdit method of Run class.""" + mock_response = mockNotificationEdit() + requests_mock.put("https://api.tago.io/run/notification/notification_id_1", json=mock_response) + + resources = Resources({"token": "your_token_value"}) + result = resources.run.notificationEdit("notification_id_1", {"title": "Updated Title"}) + + assert result == "TagoIO Notification User Successfully Updated" + + +def testRunMethodNotificationDelete(requests_mock: Mocker) -> None: + """Test notificationDelete method of Run class.""" + mock_response = mockNotificationDelete() + requests_mock.delete("https://api.tago.io/run/notification/notification_id_1", json=mock_response) + + resources = Resources({"token": "your_token_value"}) + result = resources.run.notificationDelete("notification_id_1") + + assert result == "Successfully Removed" + + +def testRunMethodSSOSAMLInfo(requests_mock: Mocker) -> None: + """Test ssoSAMLInfo method of Run class.""" + mock_response = mockSSOSAMLInfo() + requests_mock.get("https://api.tago.io/run/sso/saml", json=mock_response) + + resources = Resources({"token": "your_token_value"}) + result = resources.run.ssoSAMLInfo() + + assert "sp" in result + assert "idp" in result + + +def testRunMethodSSOSAMLEdit(requests_mock: Mocker) -> None: + """Test ssoSAMLEdit method of Run class.""" + mock_response = mockSSOSAMLEdit() + requests_mock.put("https://api.tago.io/run/sso/saml", json=mock_response) + + resources = Resources({"token": "your_token_value"}) + result = resources.run.ssoSAMLEdit({"active": True, "idp_metadata": "..."}) + + assert result == "TagoIO Run SAML SSO Successfully Updated" + + +def testRunMethodCreateCustomDomain(requests_mock: Mocker) -> None: + """Test createCustomDomain method of Run class.""" + mock_response = mockCustomDomainCreate() + requests_mock.post("https://api.tago.io/run/customdomain/profile_id_123", json=mock_response) + + resources = Resources({"token": "your_token_value"}) + result = resources.run.createCustomDomain("profile_id_123", {"domain": "mycompany.com", "subdomain": "app"}) + + assert result == "Custom domain created successfully" + + +def testRunMethodGetCustomDomain(requests_mock: Mocker) -> None: + """Test getCustomDomain method of Run class.""" + mock_response = mockCustomDomainInfo() + requests_mock.get("https://api.tago.io/run/customdomain/profile_id_123", json=mock_response) + + resources = Resources({"token": "your_token_value"}) + result = resources.run.getCustomDomain("profile_id_123") + + assert result["domain"] == "mycompany.com" + assert result["active"] is True + + +def testRunMethodDeleteCustomDomain(requests_mock: Mocker) -> None: + """Test deleteCustomDomain method of Run class.""" + mock_response = mockCustomDomainDelete() + requests_mock.delete("https://api.tago.io/run/customdomain/profile_id_123", json=mock_response) + + resources = Resources({"token": "your_token_value"}) + result = resources.run.deleteCustomDomain("profile_id_123") + + assert result == "Custom domain deleted successfully" + + +def testRunMethodRegenerateCustomDomain(requests_mock: Mocker) -> None: + """Test regenerateCustomDomain method of Run class.""" + mock_response = mockCustomDomainRegenerate() + requests_mock.put("https://api.tago.io/run/customdomain/regenerate/profile_id_123", json=mock_response) + + resources = Resources({"token": "your_token_value"}) + result = resources.run.regenerateCustomDomain("profile_id_123") + + assert result == "Custom domain regenerated successfully" From d06c8844f875437344c5ad5b4baeb315379d9666 Mon Sep 17 00:00:00 2001 From: Mateus Silva Date: Fri, 12 Dec 2025 15:25:09 -0300 Subject: [PATCH 2/4] docs: update Sphinx documentation for Run class methods Update RST documentation with detailed method descriptions, usage examples, and authorization policy references. Add EmailTestData type documentation and restructure all Run method docs with consistent formatting and Help Center links. --- docs/source/Resources/Run/Run_Types.rst | 15 + docs/source/Resources/Run/index.rst | 495 +++++++++++++++++------- 2 files changed, 374 insertions(+), 136 deletions(-) diff --git a/docs/source/Resources/Run/Run_Types.rst b/docs/source/Resources/Run/Run_Types.rst index 588da9b..0620063 100644 --- a/docs/source/Resources/Run/Run_Types.rst +++ b/docs/source/Resources/Run/Run_Types.rst @@ -319,6 +319,21 @@ LoginAsUserOptions | :default: "8 hours" +.. _EmailTestData: + +EmailTestData +------------- + +Type for the email test data. + + **Attributes:** + + | **subject**: str + | Subject of the test email. + + | **body**: str + | Body content of the test email. + .. _SAMLAttributeMappings: diff --git a/docs/source/Resources/Run/index.rst b/docs/source/Resources/Run/index.rst index 3a27538..ce60e23 100644 --- a/docs/source/Resources/Run/index.rst +++ b/docs/source/Resources/Run/index.rst @@ -1,320 +1,543 @@ - **Run** -======== +======= -Manage services in account. +Manage TagoRUN environment configuration and users. -======= +==== info -======= +==== -Get information about the TagoRUN service. +Retrieves information about the current Run environment configuration. - **Returns** +See: `TagoRun `_ | `Run Themes `_ - | **result**: :ref:`RunInfo` - | Information about the TagoRUN service. + **Returns:** + | :ref:`RunInfo` -======= + .. code-block:: python + + # If receive an error "Authorization Denied", check policy **Profile** / **Access TagoRun settings** in Access Management. + from tagoio_sdk import Resources + + resources = Resources() + result = resources.run.info() + print(result) # {'name': 'My Run Environment', 'logo': 'https://example.com/logo.png', ...} + + +==== edit -======= +==== + +Updates the Run environment configuration settings. -Edit the TagoRUN service information. +See: `TagoRun `_ | `Run Themes `_ **Parameters:** - | **data**: :ref:`RunInfo` - | Updated information for the TagoRUN service. + | **data**: dict + | Run configuration data to update **Returns:** - | **result**: str - | Success message. + | str + + .. code-block:: python + + # If receive an error "Authorization Denied", check policy **Profile** / **Edit TagoRun settings** in Access Management. + from tagoio_sdk import Resources + resources = Resources() + result = resources.run.edit({"name": "My Run Environment", "logo": "https://example.com/logo.png"}) + print(result) # TagoIO Run Successfully Updated -============ + +========= listUsers -============ +========= + +Retrieves a paginated list of Run users with customizable fields and filtering options. -List users in the TagoRUN service. +See: `TagoRun `_ **Parameters:** | **query**: :ref:`Query` - | Query parameters for filtering and sorting the user list. + | Query parameters for filtering and sorting - **Returns:** + .. code-block:: + :caption: **Default query:** - | **result**: list[:ref:`UserInfo`] - | List of user information. + query = { + "page": 1, + "fields": ["id", "name"], + "filter": {}, + "amount": 20, + "orderBy": ["name", "asc"] + } + **Returns:** -============ -userInfo -============ - -Get information about a specific user in the TagoRUN service. + | list[:ref:`UserInfo`] - **Parameters:** + .. code-block:: python - | **userID**: :ref:`GenericID` - | ID of the user. + # If receive an error "Authorization Denied", or return empty list check policy **Run User** / **Access** in Access Management. + from tagoio_sdk import Resources - **Returns:** + resources = Resources() + result = resources.run.listUsers({ + "page": 1, + "fields": ["id", "name", "email"], + "amount": 20 + }) + print(result) # [{'id': 'user-id-123', 'name': 'John Doe', 'email': 'example@email.com'}] - | **result**: :ref:`UserInfo` - | Information about the user. +======== +userInfo +======== -================ -userCreate -================ +Retrieves detailed information about a specific Run user. -Create a new user in the TagoRUN service. +See: `TagoRun `_ **Parameters:** - | **data**: :ref:`UserCreateInfo` - | Information for creating the user. + | **userID**: :ref:`GenericID` + | User identification **Returns:** - | **result**: str - | Success message. + | :ref:`UserInfo` + .. code-block:: python -================ + # If receive an error "Authorization Denied", check policy **Run User** / **Access** in Access Management. + from tagoio_sdk import Resources + + resources = Resources() + result = resources.run.userInfo("user-id-123") + print(result) # {'id': 'user-id-123', 'name': 'John Doe', 'email': 'example@email.com', ...} + + +========== userCreate -================ +========== + +Creates a new user in the Run environment. -Create a new user in the TagoRUN service. +See: `TagoRun `_ **Parameters:** | **data**: :ref:`UserCreateInfo` - | Information for creating the user. + | User creation data **Returns:** - | **result**: str - | Success message. + | dict + .. code-block:: python -================ + # If receive an error "Authorization Denied", check policy **Run User** / **Create** in Access Management. + from tagoio_sdk import Resources + + resources = Resources() + result = resources.run.userCreate({ + "name": "John Doe", + "email": "john@example.com", + "password": "secure123", + "timezone": "America/New_York" + }) + print(result) # {'user': 'user-id-123'} + + +======== userEdit -================ +======== -Edit information about a specific user in the TagoRUN service. +Updates information for an existing Run user. + +See: `TagoRun `_ **Parameters:** | **userID**: :ref:`GenericID` - | ID of the user. + | User identification - | **data**: :ref:`UserInfo` - | Updated information for the user. + | **data**: dict + | User data to update **Returns:** - | **result**: str - | Success message. + | str + .. code-block:: python -================== + # If receive an error "Authorization Denied", check policy **Run User** / **Edit** in Access Management. + from tagoio_sdk import Resources + + resources = Resources() + result = resources.run.userEdit("user-id-123", {"name": "Updated Name"}) + print(result) # TagoIO Run User Successfully Updated + + +========== userDelete -================== +========== + +Permanently deletes a user from the Run environment. -Delete a specific user from the TagoRUN service. +See: `TagoRun `_ **Parameters:** | **userID**: :ref:`GenericID` - | ID of the user. + | User identification **Returns:** - | **result**: str - | Success message. + | str + .. code-block:: python -================== + # If receive an error "Authorization Denied", check policy **Run User** / **Delete** in Access Management. + from tagoio_sdk import Resources + + resources = Resources() + result = resources.run.userDelete("user-id-123") + print(result) # Successfully Removed + + +=========== loginAsUser -================== +=========== -Log in as a specific user in the TagoRUN service. +Generates a login token to authenticate as a specific Run user. **Parameters:** | **userID**: :ref:`GenericID` - | ID of the user. + | User identification - | **options**: Optional[:ref:`LoginAsUserOptions`] - | Additional options for the login. + | *Optional* **options**: :ref:`LoginAsUserOptions` + | Login options (e.g., expire_time) **Returns:** - | **result**: :ref:`LoginResponseRunUser` - | Login response. + | :ref:`LoginResponse` + .. code-block:: python -================ + # If receive an error "Authorization Denied", check policy **Run User** / **Login as user** in Access Management. + from tagoio_sdk import Resources + + resources = Resources() + result = resources.run.loginAsUser("user-id-123") + print(result["token"]) # eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ... + + +========= emailTest -================ +========= -Send a test email from the TagoRUN service. +Tests the email configuration by sending a test message. **Parameters:** - | **data**: :ref:`EmailBase` - | Email data including subject and body. + | **data**: :ref:`EmailTestData` + | Email test data with subject and body **Returns:** - | **result**: str - | Success message. + | str + .. code-block:: python -====================== + from tagoio_sdk import Resources + + resources = Resources({"token": "YOUR-PROFILE-TOKEN"}) + result = resources.run.emailTest({"subject": "Test Email", "body": "This is a test message"}) + print(result) # E-mail sent to example@email.com + + +================ notificationList -====================== +================ + +Retrieves a list of notifications for a specific Run user. -List notifications for a specific user in the TagoRUN service. +See: `Notifications for Users `_ **Parameters:** | **userID**: :ref:`GenericID` - | ID of the user. + | User identification **Returns:** - | **result**: list[:ref:`NotificationInfo`] - | List of notification information. + | list[:ref:`NotificationInfo`] + .. code-block:: python -====================== + # If receive an error "Authorization Denied", check policy **Run User** / **Access notification** in Access Management. + from tagoio_sdk import Resources + + resources = Resources() + result = resources.run.notificationList("user-id-123") + print(result) # [{'id': 'notification-id-123', 'title': 'System Update', 'message': 'Features', ...}] + + +================== notificationCreate -====================== +================== -Create a new notification for a specific user in the TagoRUN service. +Creates a new notification for a Run user. + +See: `Notifications for Users `_ **Parameters:** | **userID**: :ref:`GenericID` - | ID of the user. + | User identification | **data**: :ref:`NotificationCreate` - | Information for creating the notification. + | Notification data **Returns:** - | **result**: :ref:`NotificationCreateReturn` - | Information about the created notification. + | :ref:`NotificationCreateReturn` + .. code-block:: python -====================== + # If receive an error "Authorization Denied", check policy **Run User** / **Create notification** in Access Management. + from tagoio_sdk import Resources + + resources = Resources() + result = resources.run.notificationCreate("user-id-123", { + "title": "Update", + "message": "New feature available" + }) + print(result) # {'id': 'notification-id-123'} + + +================ notificationEdit -====================== +================ + +Updates an existing notification in the Run environment. -Edit information about a specific notification in the TagoRUN service. +See: `Notifications for Users `_ **Parameters:** | **notificationID**: :ref:`GenericID` - | ID of the notification. + | Notification identification - | **data**: :ref:`NotificationCreate` - | Updated information for the notification. + | **data**: dict + | Notification data to update **Returns:** - | **result**: str - | Success message. + | str + .. code-block:: python -====================== + # If receive an error "Authorization Denied", check policy **Run User** / **Edit notification** in Access Management. + from tagoio_sdk import Resources + + resources = Resources() + result = resources.run.notificationEdit("notification-id-123", {"title": "Updated Title"}) + print(result) # TagoIO Notification User Successfully Updated + + +================== notificationDelete -====================== +================== -Delete a specific notification from the TagoRUN service. +Deletes a notification from the Run environment. + +See: `Notifications for Users `_ **Parameters:** | **notificationID**: :ref:`GenericID` - | ID of the notification. + | Notification identification **Returns:** - | **result**: str - | Success message. + | str + + .. code-block:: python + + # If receive an error "Authorization Denied", check policy **Run User** / **Delete notification** in Access Management. + from tagoio_sdk import Resources + resources = Resources() + result = resources.run.notificationDelete("notification-id-123") + print(result) # Successfully Removed -============ + +=========== ssoSAMLInfo -============ +=========== -Get the SAML Single Sign-On information for the account's RUN. +Retrieves the SAML Single Sign-On configuration information for the Run environment. +See: `Single Sign-On (SSO) `_ -============ + **Returns:** + + | :ref:`RunSAMLInfo` + + .. code-block:: python + + from tagoio_sdk import Resources + + resources = Resources({"token": "YOUR-PROFILE-TOKEN"}) + result = resources.run.ssoSAMLInfo() + print(result) # {'sp': {'entity_id': 'https://example.com', ...}, ...} + + +=========== ssoSAMLEdit -============ +=========== + +Updates the SAML SSO configuration for the Run environment. -Edit the SAML Single Sign-On metadata and mappings for the account's RUN. +See: `Single Sign-On (SSO) `_ **Parameters:** | **data**: :ref:`RunSAMLEditInfo` - | Updated data for a RUN's SAML Single Sign-On configuration. + | SAML SSO configuration data + + **Returns:** + + | str + .. code-block:: python -=================== + from tagoio_sdk import Resources + + resources = Resources({"token": "YOUR-PROFILE-TOKEN"}) + result = resources.run.ssoSAMLEdit({ + "active": True, + "idp_metadata": "..." + }) + print(result) # TagoIO Run SAML SSO Successfully Updated + + +================== createCustomDomain -=================== +================== -Create a TagoRUN custom domain for the profile. +Creates a custom domain configuration for the Run environment. + +See: `Custom Domain Configuration `_ **Parameters:** - | **profile_id**: str - | ID of the profile + | **profile_id**: str + | Profile identification -.. toctree:: + | **customDomainData**: :ref:`CustomDomainCreate` + | Custom domain configuration data - Run_Types + **Returns:** + | str -================ + .. code-block:: python + + from tagoio_sdk import Resources + + resources = Resources({"token": "YOUR-PROFILE-TOKEN"}) + result = resources.run.createCustomDomain("profile-id-123", { + "domain": "app.mycompany.com" + }) + print(result) # Custom domain created successfully + + +=============== getCustomDomain -================ +=============== + +Retrieves the custom domain configuration for a Run profile. + +See: `Custom Domain Configuration `_ + + **Parameters:** -Set details of TagoRun custom domain for the profile. + | **profile_id**: str + | Profile identification - **Parameters** + **Returns:** + + | :ref:`CustomDomainInfo` + + .. code-block:: python - | **profile_id**: str - | ID of the profile + from tagoio_sdk import Resources + resources = Resources({"token": "YOUR-PROFILE-TOKEN"}) + result = resources.run.getCustomDomain("profile-id-123") + print(result) # {'domain': 'app.mycompany.com', 'verified': True, ...} -=================== + +================== deleteCustomDomain -=================== +================== + +Removes the custom domain configuration from a Run profile. -Delete a TagoRUN custom domain for the profile. +See: `Custom Domain Configuration `_ - **Parameters** + **Parameters:** - | **profile_id**: str - | ID of the profile + | **profile_id**: str + | Profile identification + + **Returns:** + | str -======================= + .. code-block:: python + + from tagoio_sdk import Resources + + resources = Resources({"token": "YOUR-PROFILE-TOKEN"}) + result = resources.run.deleteCustomDomain("profile-id-123") + print(result) # Custom domain deleted successfully + + +====================== regenerateCustomDomain -======================= +====================== + +Regenerates the custom domain configuration for a Run profile. -Regenerate a TagoRUN custom domain for the profile. +See: `Custom Domain Configuration `_ - **Parameters** + **Parameters:** - | **profile_id**: str - | ID of the profile + | **profile_id**: str + | Profile identification + + **Returns:** + + | str + + .. code-block:: python + + from tagoio_sdk import Resources + + resources = Resources({"token": "YOUR-PROFILE-TOKEN"}) + result = resources.run.regenerateCustomDomain("profile-id-123") + print(result) # Custom domain regenerated successfully + + +.. toctree:: + + Run_Types From 3d6b16641e0a21cb4274ce391046933ba6cec7cc Mon Sep 17 00:00:00 2001 From: Mateus Silva Date: Mon, 12 Jan 2026 14:15:39 -0300 Subject: [PATCH 3/4] feat: make query parameter optional in Run.listUsers method The query parameter is now optional with an empty dict as default value, making it easier to retrieve all users without specifying query filters. --- src/tagoio_sdk/modules/Resources/Run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tagoio_sdk/modules/Resources/Run.py b/src/tagoio_sdk/modules/Resources/Run.py index 1bf0d51..bc34c7a 100644 --- a/src/tagoio_sdk/modules/Resources/Run.py +++ b/src/tagoio_sdk/modules/Resources/Run.py @@ -75,7 +75,7 @@ def edit(self, data: Dict) -> str: return result - def listUsers(self, query: Query) -> list[UserInfo]: + def listUsers(self, query: Optional[Query] = {}) -> list[UserInfo]: """ @description: Retrieves a paginated list of Run users with customizable fields and filtering options. From 1a774550ae58b3d5234ac9b269c49f6a1e40b2a7 Mon Sep 17 00:00:00 2001 From: Mateus Silva Date: Mon, 12 Jan 2026 14:20:14 -0300 Subject: [PATCH 4/4] feat: update listUsers method to use None as default for query parameter --- src/tagoio_sdk/modules/Resources/Run.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tagoio_sdk/modules/Resources/Run.py b/src/tagoio_sdk/modules/Resources/Run.py index bc34c7a..e7c4bf2 100644 --- a/src/tagoio_sdk/modules/Resources/Run.py +++ b/src/tagoio_sdk/modules/Resources/Run.py @@ -75,7 +75,7 @@ def edit(self, data: Dict) -> str: return result - def listUsers(self, query: Optional[Query] = {}) -> list[UserInfo]: + def listUsers(self, query: Optional[Query] = None) -> list[UserInfo]: """ @description: Retrieves a paginated list of Run users with customizable fields and filtering options. @@ -95,6 +95,8 @@ def listUsers(self, query: Optional[Query] = {}) -> list[UserInfo]: print(result) # [{'id': 'user-id-123', 'name': 'John Doe', 'email': 'example@email.com'}] ``` """ + if query is None: + query = {} if "orderBy" in query: firstArgument = query["orderBy"][0] secondArgument = query["orderBy"][1]