diff --git a/README.rst b/README.rst index 181bf2a2..db6c18c5 100644 --- a/README.rst +++ b/README.rst @@ -340,6 +340,7 @@ Authentication Endpoints Management Endpoints ******************** +- Actions() (``Auth0().actions``) - Blacklists() ( ``Auth0().blacklists`` ) - ClientGrants() ( ``Auth0().client_grants`` ) - Clients() ( ``Auth0().clients`` ) diff --git a/auth0/v3/management/__init__.py b/auth0/v3/management/__init__.py index e01a5ce9..e805744c 100644 --- a/auth0/v3/management/__init__.py +++ b/auth0/v3/management/__init__.py @@ -1,4 +1,5 @@ from .auth0 import Auth0 +from .actions import Actions from .blacklists import Blacklists from .client_grants import ClientGrants from .clients import Clients diff --git a/auth0/v3/management/actions.py b/auth0/v3/management/actions.py new file mode 100644 index 00000000..8c7e7e6a --- /dev/null +++ b/auth0/v3/management/actions.py @@ -0,0 +1,234 @@ +from .rest import RestClient + + +class Actions(object): + """Auth0 Actions endpoints + + Args: + domain (str): Your Auth0 domain, e.g: 'username.auth0.com' + + token (str): Management API v2 Token + + telemetry (bool, optional): Enable or disable Telemetry + (defaults to True) + + timeout (float or tuple, optional): Change the requests + connect and read timeout. Pass a tuple to specify + both values separately or a float to set both to it. + (defaults to 5.0 for both) + + rest_options (RestClientOptions): Pass an instance of + RestClientOptions to configure additional RestClient + options, such as rate-limit retries. + (defaults to None) + """ + + def __init__(self, domain, token, telemetry=True, timeout=5.0, protocol="https", rest_options=None): + self.domain = domain + self.protocol = protocol + self.client = RestClient(jwt=token, telemetry=telemetry, timeout=timeout, options=rest_options) + + def _url(self, *args): + url = '{}://{}/api/v2/actions'.format(self.protocol, self.domain) + for p in args: + if p is not None: + url = '{}/{}'.format(url, p) + return url + + def get_actions(self, trigger_id=None, action_name=None, deployed=False, installed=False, page=None, per_page=None): + """Get all actions. + + Args: + trigger_id (str, optional): Filter the results to only actions associated + with this trigger ID. + + action_name (str, optional): Filter the results to only actions with this name. + + deployed (bool, optional): True to filter the results to only deployed actions. + Defaults to False. + + installed (bool, optional): True to filter the results to only installed actions. + Defaults to False. + + page (int, optional): The result's page number (zero based). When not set, + the default value is up to the server. + + per_page (int, optional): The amount of entries per page. When not set, + the default value is up to the server. + + See: https://auth0.com/docs/api/management/v2#!/Actions/get_actions + """ + params = { + 'triggerId': trigger_id, + 'actionName': action_name, + 'deployed': str(deployed).lower(), + 'installed': str(installed).lower(), + 'page': page, + 'per_page': per_page + } + + return self.client.get(self._url('actions'), params=params) + + def create_action(self, body): + """Create a new action. + + Args: + body (dict): Attributes for the new action. + + See: https://auth0.com/docs/api/management/v2#!/Actions/post_action + """ + + return self.client.post(self._url('actions'), data=body) + + def update_action(self, id, body): + """Updates an action. + + Args: + id (str): the ID of the action. + + body (dict): Attributes to modify. + + See: https://auth0.com/docs/api/management/v2#!/Actions/patch_action + """ + + return self.client.patch(self._url('actions', id), data=body) + + def get_action(self, id): + """Retrieves an action by its ID. + + Args: + id (str): Id of action to retrieve. + + See: https://auth0.com/docs/api/management/v2#!/Actions/get_action + """ + params = {} + + return self.client.get(self._url('actions', id), params=params) + + def delete_action(self, id, force=False): + """Deletes an action and all of its associated versions. + + Args: + id (str): ID of the action to delete. + + force (bool, optional): True to force action deletion detaching bindings, + False otherwise. Defaults to False. + + See: https://auth0.com/docs/api/management/v2#!/Actions/delete_action + """ + params = { + 'force': str(force).lower() + } + + return self.client.delete(self._url('actions', id), params=params) + + def get_triggers(self): + """Retrieve the set of triggers currently available within actions. + + See: https://auth0.com/docs/api/management/v2#!/Actions/get_triggers + """ + params = {} + + return self.client.get(self._url('triggers'), params=params) + + def get_execution(self, id): + """Get information about a specific execution of a trigger. + + Args: + id (str): The ID of the execution to retrieve. + + See: https://auth0.com/docs/api/management/v2#!/Actions/get_execution + """ + params = {} + + return self.client.get(self._url('executions', id), params=params) + + def get_action_versions(self, id, page=None, per_page=None): + """Get all of an action's versions. + + Args: + id (str): The ID of the action. + + page (int, optional): The result's page number (zero based). When not set, + the default value is up to the server. + + per_page (int, optional): The amount of entries per page. When not set, + the default value is up to the server. + + See: https://auth0.com/docs/api/management/v2#!/Actions/get_action_versions + """ + params = { + 'page': page, + 'per_page': per_page + } + + return self.client.get(self._url('actions', id, 'versions'), params=params) + + def get_trigger_bindings(self, id, page=None, per_page=None): + """Get the actions that are bound to a trigger. + + Args: + id (str): The trigger ID. + + page (int, optional): The result's page number (zero based). When not set, + the default value is up to the server. + + per_page (int, optional): The amount of entries per page. When not set, + the default value is up to the server. + + See: https://auth0.com/docs/api/management/v2#!/Actions/get_bindings + """ + params = { + 'page': page, + 'per_page': per_page + } + return self.client.get(self._url('triggers', id, 'bindings'), params=params) + + def get_action_version(self, action_id, version_id): + """Retrieve a specific version of an action. + + Args: + action_id (str): The ID of the action. + + version_id (str): The ID of the version to retrieve. + + See: https://auth0.com/docs/api/management/v2#!/Actions/get_action_version + """ + params = {} + + return self.client.get(self._url('actions', action_id, 'versions', version_id), params=params) + + def deploy_action(self, id): + """Deploy an action. + + Args: + id (str): The ID of the action to deploy. + + See: https://auth0.com/docs/api/management/v2#!/Actions/post_deploy_action + """ + return self.client.post(self._url('actions', id, 'deploy')) + + def rollback_action_version(self, action_id, version_id): + """Roll back to a previous version of an action. + + Args: + action_id (str): The ID of the action. + + version_id (str): The ID of the version. + + See: https://auth0.com/docs/api/management/v2#!/Actions/post_deploy_draft_version + """ + params = {} + return self.client.post(self._url('actions', action_id, 'versions', version_id, 'deploy'), data={}) + + def update_trigger_bindings(self, id, body): + """Update a trigger's bindings. + + Args: + id (str): The ID of the trigger to update. + + body (dict): Attributes for the updated trigger binding. + + See: https://auth0.com/docs/api/management/v2#!/Actions/patch_bindings + """ + return self.client.patch(self._url('triggers', id, 'bindings'), data=body) \ No newline at end of file diff --git a/auth0/v3/test/management/test_actions.py b/auth0/v3/test/management/test_actions.py new file mode 100644 index 00000000..753474c7 --- /dev/null +++ b/auth0/v3/test/management/test_actions.py @@ -0,0 +1,210 @@ +import unittest +import mock +from ...management.actions import Actions + + +class TestActions(unittest.TestCase): + + def test_init_with_optionals(self): + t = Actions(domain='domain', token='jwttoken', telemetry=False, timeout=(10, 2)) + self.assertEqual(t.client.options.timeout, (10, 2)) + telemetry_header = t.client.base_headers.get('Auth0-Client', None) + self.assertEqual(telemetry_header, None) + + @mock.patch('auth0.v3.management.actions.RestClient') + def test_get_actions(self, mock_rc): + mock_instance = mock_rc.return_value + + c = Actions(domain='domain', token='jwttoken') + c.get_actions() + + args, kwargs = mock_instance.get.call_args + + self.assertEqual('https://domain/api/v2/actions/actions', args[0]) + self.assertEqual(kwargs['params'], {'triggerId': None, + 'actionName': None, + 'deployed': 'false', + 'installed': 'false', + 'page': None, + 'per_page': None}) + + c.get_actions('trigger-id', 'action-name', True, True, 0, 5) + + args, kwargs = mock_instance.get.call_args + + self.assertEqual('https://domain/api/v2/actions/actions', args[0]) + self.assertEqual(kwargs['params'], {'triggerId': 'trigger-id', + 'actionName': 'action-name', + 'deployed': 'true', + 'installed': 'true', + 'page': 0, + 'per_page': 5}) + + @mock.patch('auth0.v3.management.actions.RestClient') + def test_create_action(self, mock_rc): + mock_instance = mock_rc.return_value + + c = Actions(domain='domain', token='jwttoken') + c.create_action({'a': 'b', 'c': 'd'}) + + mock_instance.post.assert_called_with( + 'https://domain/api/v2/actions/actions', + data={'a': 'b', 'c': 'd'} + ) + + @mock.patch('auth0.v3.management.actions.RestClient') + def test_update_action(self, mock_rc): + mock_instance = mock_rc.return_value + + c = Actions(domain='domain', token='jwttoken') + c.update_action('action-id', {'a': 'b', 'c': 'd'}) + + args, kwargs = mock_instance.patch.call_args + + self.assertEqual('https://domain/api/v2/actions/actions/action-id', args[0]) + self.assertEqual(kwargs['data'], {'a': 'b', 'c': 'd'}) + + @mock.patch('auth0.v3.management.actions.RestClient') + def test_get_action(self, mock_rc): + mock_instance = mock_rc.return_value + + c = Actions(domain='domain', token='jwttoken') + c.get_action('action-id') + + args, kwargs = mock_instance.get.call_args + + self.assertEqual('https://domain/api/v2/actions/actions/action-id', args[0]) + self.assertEqual(kwargs['params'], {}) + + @mock.patch('auth0.v3.management.actions.RestClient') + def test_get_triggers(self, mock_rc): + mock_instance = mock_rc.return_value + + c = Actions(domain='domain', token='jwttoken') + c.get_triggers() + + args, kwargs = mock_instance.get.call_args + + self.assertEqual('https://domain/api/v2/actions/triggers', args[0]) + self.assertEqual(kwargs['params'], {}) + + @mock.patch('auth0.v3.management.actions.RestClient') + def test_delete_action(self, mock_rc): + mock_instance = mock_rc.return_value + + c = Actions(domain='domain', token='jwttoken') + c.delete_action('action-id') + + args, kwargs = mock_instance.delete.call_args + + self.assertEqual('https://domain/api/v2/actions/actions/action-id', args[0]) + self.assertEqual(kwargs['params'], {'force': 'false'}) + + c.delete_action('action-id', True) + + args, kwargs = mock_instance.delete.call_args + + self.assertEqual('https://domain/api/v2/actions/actions/action-id', args[0]) + self.assertEqual(kwargs['params'], {'force': 'true'}) + + @mock.patch('auth0.v3.management.actions.RestClient') + def test_get_execution(self, mock_rc): + mock_instance = mock_rc.return_value + + c = Actions(domain='domain', token='jwttoken') + c.get_execution('execution-id') + + args, kwargs = mock_instance.get.call_args + + self.assertEqual('https://domain/api/v2/actions/executions/execution-id', args[0]) + self.assertEqual(kwargs['params'], {}) + + + @mock.patch('auth0.v3.management.actions.RestClient') + def test_get_action_versions(self, mock_rc): + mock_instance = mock_rc.return_value + + c = Actions(domain='domain', token='jwttoken') + c.get_action_versions('action-id') + + args, kwargs = mock_instance.get.call_args + + self.assertEqual('https://domain/api/v2/actions/actions/action-id/versions', args[0]) + self.assertEqual(kwargs['params'], {'page': None, + 'per_page': None}) + + c.get_action_versions('action-id', 0, 5) + + args, kwargs = mock_instance.get.call_args + + self.assertEqual('https://domain/api/v2/actions/actions/action-id/versions', args[0]) + self.assertEqual(kwargs['params'], {'page': 0, + 'per_page': 5}) + + @mock.patch('auth0.v3.management.actions.RestClient') + def test_get_trigger_bindings(self, mock_rc): + mock_instance = mock_rc.return_value + + c = Actions(domain='domain', token='jwttoken') + c.get_trigger_bindings('trigger-id') + + args, kwargs = mock_instance.get.call_args + + self.assertEqual('https://domain/api/v2/actions/triggers/trigger-id/bindings', args[0]) + self.assertEqual(kwargs['params'], {'page': None, + 'per_page': None}) + + c.get_trigger_bindings('trigger-id', 0, 5) + + args, kwargs = mock_instance.get.call_args + + self.assertEqual('https://domain/api/v2/actions/triggers/trigger-id/bindings', args[0]) + self.assertEqual(kwargs['params'], {'page': 0, + 'per_page': 5}) + + @mock.patch('auth0.v3.management.actions.RestClient') + def test_get_action_version(self, mock_rc): + mock_instance = mock_rc.return_value + + c = Actions(domain='domain', token='jwttoken') + c.get_action_version('action-id', 'version-id') + + args, kwargs = mock_instance.get.call_args + + self.assertEqual('https://domain/api/v2/actions/actions/action-id/versions/version-id', args[0]) + self.assertEqual(kwargs['params'], {}) + + @mock.patch('auth0.v3.management.actions.RestClient') + def test_deploy_action(self, mock_rc): + mock_instance = mock_rc.return_value + + c = Actions(domain='domain', token='jwttoken') + c.deploy_action('action-id') + + args, kwargs = mock_instance.post.call_args + + self.assertEqual('https://domain/api/v2/actions/actions/action-id/deploy', args[0]) + + @mock.patch('auth0.v3.management.actions.RestClient') + def test_rollback_action(self, mock_rc): + mock_instance = mock_rc.return_value + + c = Actions(domain='domain', token='jwttoken') + c.rollback_action_version('action-id', 'version-id') + + args, kwargs = mock_instance.post.call_args + + self.assertEqual('https://domain/api/v2/actions/actions/action-id/versions/version-id/deploy', args[0]) + self.assertEqual(kwargs['data'], {}) + + @mock.patch('auth0.v3.management.actions.RestClient') + def test_update_trigger_bindings(self, mock_rc): + mock_instance = mock_rc.return_value + + c = Actions(domain='domain', token='jwttoken') + c.update_trigger_bindings('trigger-id', {'a': 'b', 'c': 'd'}) + + args, kwargs = mock_instance.patch.call_args + + self.assertEqual('https://domain/api/v2/actions/triggers/trigger-id/bindings', args[0]) + self.assertEqual(kwargs['data'], {'a': 'b', 'c': 'd'})