Skip to content

Commit bcaee74

Browse files
authored
Add cursor parameter to Audit Logs API method (#1147)
1 parent a58ab92 commit bcaee74

File tree

7 files changed

+56
-1
lines changed

7 files changed

+56
-1
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import logging
2+
import os
3+
import unittest
4+
5+
from integration_tests.env_variable_names import (
6+
SLACK_SDK_TEST_GRID_ORG_ADMIN_USER_TOKEN,
7+
)
8+
from slack_sdk.audit_logs import AuditLogsClient
9+
10+
11+
class TestAuditLogsClient(unittest.TestCase):
12+
def setUp(self):
13+
self.client = AuditLogsClient(
14+
token=os.environ[SLACK_SDK_TEST_GRID_ORG_ADMIN_USER_TOKEN]
15+
)
16+
17+
def tearDown(self):
18+
pass
19+
20+
def test_pagination(self):
21+
call_count = 0
22+
response = None
23+
ids = []
24+
while call_count < 10 and (response is None or response.status_code != 429):
25+
cursor = response.body["response_metadata"]["next_cursor"] if response is not None else None
26+
response = self.client.logs(action="user_login", limit=1, cursor=cursor)
27+
ids += map(lambda v: v["id"], response.body.get("entries", []))
28+
call_count += 1
29+
self.assertGreaterEqual(len(set(ids)), 10)

slack_sdk/audit_logs/v1/async_client.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ async def logs(
151151
action: Optional[str] = None,
152152
actor: Optional[str] = None,
153153
entity: Optional[str] = None,
154+
cursor: Optional[str] = None,
154155
additional_query_params: Optional[Dict[str, Any]] = None,
155156
headers: Optional[Dict[str, str]] = None,
156157
) -> AuditLogsResponse:
@@ -171,6 +172,7 @@ async def logs(
171172
action: Name of the action.
172173
actor: User ID who initiated the action.
173174
entity: ID of the target entity of the action (such as a channel, workspace, organization, file).
175+
cursor: The next page cursor of pagination
174176
additional_query_params: Add anything else if you need to use the ones this library does not support
175177
headers: Additional request headers
176178
@@ -184,6 +186,7 @@ async def logs(
184186
"action": action,
185187
"actor": actor,
186188
"entity": entity,
189+
"cursor": cursor,
187190
}
188191
if additional_query_params is not None:
189192
query_params.update(additional_query_params)

slack_sdk/audit_logs/v1/client.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ def logs(
140140
action: Optional[str] = None,
141141
actor: Optional[str] = None,
142142
entity: Optional[str] = None,
143+
cursor: Optional[str] = None,
143144
additional_query_params: Optional[Dict[str, Any]] = None,
144145
headers: Optional[Dict[str, str]] = None,
145146
) -> AuditLogsResponse:
@@ -160,6 +161,7 @@ def logs(
160161
action: Name of the action.
161162
actor: User ID who initiated the action.
162163
entity: ID of the target entity of the action (such as a channel, workspace, organization, file).
164+
cursor: The next page cursor of pagination
163165
additional_query_params: Add anything else if you need to use the ones this library does not support
164166
headers: Additional request headers
165167
@@ -173,6 +175,7 @@ def logs(
173175
"action": action,
174176
"actor": actor,
175177
"entity": entity,
178+
"cursor": cursor,
176179
}
177180
if additional_query_params is not None:
178181
query_params.update(additional_query_params)

slack_sdk/audit_logs/v1/response.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from slack_sdk.audit_logs.v1.logs import LogsResponse
55

66

7+
# TODO: Unlike WebClient's responses, this class has not yet provided __iter__ method
78
class AuditLogsResponse:
89
url: str
910
status_code: int

tests/slack_sdk/audit_logs/mock_web_api_server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def do_GET(self):
4949
return
5050
if "ratelimited" in pattern:
5151
self.send_response(429)
52-
self.send_header("Retry-After", 1)
52+
self.send_header("retry-after", 1)
5353
self.set_common_headers()
5454
self.wfile.write(
5555
"""{"ok": false, "error": "ratelimited"}""".encode("utf-8")

tests/slack_sdk/audit_logs/test_client.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@ def test_logs(self):
2323

2424
self.assertEqual(resp.typed_body.entries[0].id, "xxx-yyy-zzz-111")
2525

26+
def test_logs_pagination(self):
27+
resp: AuditLogsResponse = self.client.logs(
28+
limit=1, action="user_login", cursor="xxxxxxx"
29+
)
30+
self.assertEqual(200, resp.status_code)
31+
self.assertIsNotNone(resp.body.get("entries"))
32+
33+
self.assertEqual(resp.typed_body.entries[0].id, "xxx-yyy-zzz-111")
34+
2635
def test_actions(self):
2736
resp: AuditLogsResponse = self.client.actions()
2837
self.assertEqual(200, resp.status_code)

tests/slack_sdk_async/audit_logs/test_async_client.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ async def test_logs(self):
2727

2828
self.assertEqual(resp.typed_body.entries[0].id, "xxx-yyy-zzz-111")
2929

30+
@async_test
31+
async def test_logs_pagination(self):
32+
resp: AuditLogsResponse = await self.client.logs(
33+
limit=1, action="user_login", cursor="XXXXXXXXXXX"
34+
)
35+
self.assertEqual(200, resp.status_code)
36+
self.assertIsNotNone(resp.body.get("entries"))
37+
38+
self.assertEqual(resp.typed_body.entries[0].id, "xxx-yyy-zzz-111")
39+
3040
@async_test
3141
async def test_actions(self):
3242
resp: AuditLogsResponse = await self.client.actions()

0 commit comments

Comments
 (0)