Repository: auth0/auth0-python
Pull request #236 (2020-08-26 21:41:14)

Add support for Log Streams API
### Changes
Adds support for the Log Streams API.


### References

https://auth0.com/docs/api/management/v2/#!/Log_Streams/get_log_streams

### Testing
I manually tested the endpoints, using the following code (Tweak if necessary)

```python
    def testList(self):
        api = LogStreams('lbalmaceda.auth0.com', self.token)
        res = api.list()
        print("\n", res)

    def testGetId(self):
        api = LogStreams('lbalmaceda.auth0.com', self.token)
        res = api.get("lst_0000000000001834")
        print("\n", res)

    def testDeleteId(self):
        api = LogStreams('lbalmaceda.auth0.com', self.token)
        res = api.delete("lst_0000000000001835")
        print("\n", res)

    def testPatchId(self):
        api = LogStreams('lbalmaceda.auth0.com', self.token)
        res = api.update("lst_0000000000001835", {"name": "nombrecito"})
        print("\n", res)

    def testCreate(self):
        api = LogStreams('lbalmaceda.auth0.com', self.token)
        res = api.create({
            "name": "string",
            "type": "http",
            "sink": {
                "httpEndpoint": "https://mycompany.com",
                "httpContentType": "string",
                "httpContentFormat": "JSONLINES",
                "httpAuthorization": "string"
            }
        })
        print("\n", res)
```

- [x] This change adds unit test coverage
- [x] This change adds integration test coverage
- [ ] This change has been tested on the latest version of the platform/language or why not

### Checklist

- [x] I have read the [Auth0 general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md)
- [x] I have read the [Auth0 Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md)
- [x] All existing and new tests complete without errors



Patch:
diff --git a/README.rst b/README.rst
index d405e16..38e1436 100644
--- a/README.rst
+++ b/README.rst
@@ -238,6 +238,7 @@ Available Management Endpoints
 - Guardian() ( ``Auth0().guardian`` )
 - Jobs() ( ``Auth0().jobs`` )
 - Logs() ( ``Auth0().logs`` )
+- LogStreams() ( ``Auth0().log_streams`` )
 - ResourceServers() (``Auth0().resource_servers`` )
 - Roles() ( ``Auth0().roles`` )
 - Rules() ( ``Auth0().rules`` )
diff --git a/auth0/v3/management/auth0.py b/auth0/v3/management/auth0.py
index 850e599..262760d 100644
--- a/auth0/v3/management/auth0.py
+++ b/auth0/v3/management/auth0.py
@@ -10,6 +10,7 @@ from .grants import Grants
 from .guardian import Guardian
 from .hooks import Hooks
 from .jobs import Jobs
+from .log_streams import LogStreams
 from .logs import Logs
 from .resource_servers import ResourceServers
 from .roles import Roles
@@ -46,6 +47,7 @@ class Auth0(object):
         self.hooks = Hooks(domain, token)
         self.jobs = Jobs(domain, token)
         self.logs = Logs(domain, token)
+        self.log_streams = LogStreams(domain, token)
         self.resource_servers = ResourceServers(domain, token)
         self.roles = Roles(domain, token)
         self.rules = Rules(domain, token)
diff --git a/auth0/v3/management/log_streams.py b/auth0/v3/management/log_streams.py
new file mode 100644
index 0000000..deddeb3
--- /dev/null
+++ b/auth0/v3/management/log_streams.py
@@ -0,0 +1,81 @@
+from .rest import RestClient
+
+
+class LogStreams(object):
+    """Auth0 log streams 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)
+    """
+
+    def __init__(self, domain, token, telemetry=True, timeout=5.0):
+        self.domain = domain
+        self.client = RestClient(jwt=token, telemetry=telemetry, timeout=timeout)
+
+    def _url(self, id=None):
+        url = 'https://{}/api/v2/log-streams'.format(self.domain)
+        if id is not None:
+            return '{}/{}'.format(url, id)
+        return url
+
+    def list(self):
+        """Search log events.
+
+        Args:
+        See: https://auth0.com/docs/api/management/v2/#!/Log_Streams/get_log_streams
+        """
+
+        return self.client.get(self._url())
+
+    def get(self, id):
+        """Retrieves the data related to the log stream entry identified by id.
+
+        Args:
+            id (str): The id of the log stream to retrieve.
+
+        See: https://auth0.com/docs/api/management/v2/#!/Log_Streams/get_log_streams_by_id
+        """
+
+        return self.client.get(self._url(id))
+
+    def create(self, body):
+        """Creates a new log stream.
+
+        Args:
+            body (dict): the attributes for the role to create.
+
+        See: https://auth0.com/docs/api/management/v2/#!/Log_Streams/post_log_streams
+        """
+        return self.client.post(self._url(), data=body)
+
+    def delete(self, id):
+        """Delete a log stream.
+
+        Args:
+            id (str): The id of the log ste to delete.
+
+        See: https://auth0.com/docs/api/management/v2/#!/Log_Streams/delete_log_streams_by_id
+        """
+        return self.client.delete(self._url(id))
+
+    def update(self, id, body):
+        """Update a log stream with the attributes passed in 'body'
+
+        Args:
+            id (str): The id of the log stream to update.
+
+            body (dict): the attributes to update on the log stream.
+
+        See: https://auth0.com/docs/api/management/v2/#!/Log_Streams/patch_log_streams_by_id
+        """
+        return self.client.patch(self._url(id), data=body)


Test patch:
diff --git a/auth0/v3/test/management/test_auth0.py b/auth0/v3/test/management/test_auth0.py
index a3fa8b5..da4d550 100644
--- a/auth0/v3/test/management/test_auth0.py
+++ b/auth0/v3/test/management/test_auth0.py
@@ -1,17 +1,19 @@
 import unittest
+
 from ...management.auth0 import Auth0
 from ...management.blacklists import Blacklists
-from ...management.clients import Clients
 from ...management.client_grants import ClientGrants
+from ...management.clients import Clients
 from ...management.connections import Connections
 from ...management.custom_domains import CustomDomains
 from ...management.device_credentials import DeviceCredentials
-from ...management.emails import Emails
 from ...management.email_templates import EmailTemplates
+from ...management.emails import Emails
 from ...management.grants import Grants
 from ...management.guardian import Guardian
 from ...management.hooks import Hooks
 from ...management.jobs import Jobs
+from ...management.log_streams import LogStreams
 from ...management.logs import Logs
 from ...management.resource_servers import ResourceServers
 from ...management.roles import Roles
@@ -71,6 +73,9 @@ class TestAuth0(unittest.TestCase):
     def test_logs(self):
         self.assertIsInstance(self.a0.logs, Logs)
 
+    def test_log_streams(self):
+        self.assertIsInstance(self.a0.log_streams, LogStreams)
+
     def test_resource_servers(self):
         self.assertIsInstance(self.a0.resource_servers, ResourceServers)
 
diff --git a/auth0/v3/test/management/test_log_streams.py b/auth0/v3/test/management/test_log_streams.py
new file mode 100644
index 0000000..94f3d36
--- /dev/null
+++ b/auth0/v3/test/management/test_log_streams.py
@@ -0,0 +1,86 @@
+import unittest
+
+import mock
+
+from ...management.log_streams import LogStreams
+
+
+class TestLogStreams(unittest.TestCase):
+
+    def test_init_with_optionals(self):
+        t = LogStreams(domain='domain', token='jwttoken', telemetry=False, timeout=(10, 2))
+        self.assertEqual(t.client.timeout, (10, 2))
+        telemetry_header = t.client.base_headers.get('Auth0-Client', None)
+        self.assertEqual(telemetry_header, None)
+
+    @mock.patch('auth0.v3.management.log_streams.RestClient')
+    def test_list(self, mock_rc):
+        mock_instance = mock_rc.return_value
+
+        c = LogStreams(domain='domain', token='jwttoken')
+
+        c.list()
+
+        args, kwargs = mock_instance.get.call_args
+
+        self.assertEqual('https://domain/api/v2/log-streams', args[0])
+        
+    @mock.patch('auth0.v3.management.log_streams.RestClient')
+    def test_get(self, mock_rc):
+        mock_instance = mock_rc.return_value
+
+        c = LogStreams(domain='domain', token='jwttoken')
+        c.get('an-id')
+
+        args, kwargs = mock_instance.get.call_args
+
+        self.assertEqual('https://domain/api/v2/log-streams/an-id', args[0])
+
+    @mock.patch('auth0.v3.management.log_streams.RestClient')
+    def test_create(self, mock_rc):
+        mock_instance = mock_rc.return_value
+
+        c = LogStreams(domain='domain', token='jwttoken')
+        # Sample data belongs to an `http` stream
+        log_stream_data = {
+            "name": "string",
+            "type": "http",
+            "sink": {
+                "httpEndpoint": "string",
+                "httpContentType": "string",
+                "httpContentFormat": "JSONLINES|JSONARRAY",
+                "httpAuthorization": "string"
+            }
+        }
+        c.create(log_stream_data)
+
+        args, kwargs = mock_instance.post.call_args
+
+        self.assertEqual('https://domain/api/v2/log-streams', args[0])
+        self.assertEqual(kwargs['data'], log_stream_data)
+
+    @mock.patch('auth0.v3.management.log_streams.RestClient')
+    def test_delete(self, mock_rc):
+        mock_instance = mock_rc.return_value
+
+        c = LogStreams(domain='domain', token='jwttoken')
+        c.delete('an-id')
+
+        mock_instance.delete.assert_called_with(
+            'https://domain/api/v2/log-streams/an-id'
+        )
+
+    @mock.patch('auth0.v3.management.log_streams.RestClient')
+    def test_update(self, mock_rc):
+        mock_instance = mock_rc.return_value
+        log_stream_update = {
+            "name": "string"
+        }
+
+        c = LogStreams(domain='domain', token='jwttoken')
+        c.update('an-id', log_stream_update)
+
+        args, kwargs = mock_instance.patch.call_args
+
+        self.assertEqual('https://domain/api/v2/log-streams/an-id', args[0])
+        self.assertEqual(kwargs['data'], log_stream_update)