diff --git a/app/commands/helpers/incident_helper.py b/app/commands/helpers/incident_helper.py index 8273bc15..a89a70d4 100644 --- a/app/commands/helpers/incident_helper.py +++ b/app/commands/helpers/incident_helper.py @@ -281,7 +281,7 @@ def stale_incidents(client, body, ack): "type": "section", "text": { "type": "mrkdwn", - "text": "Loading stale incident list ...", + "text": "Loading stale incident list ...(this may take a minute)", }, } ], diff --git a/app/commands/utils.py b/app/commands/utils.py index df673125..53b95a64 100644 --- a/app/commands/utils.py +++ b/app/commands/utils.py @@ -6,15 +6,36 @@ logging.basicConfig(level=logging.INFO) +# Get all incident channels def get_incident_channels(client): channels = [] - response = client.conversations_list( - exclude_archived=True, limit=1000, types="public_channel" - ) - if response["ok"]: - channels = list( - filter(lambda x: x["name"].startswith("incident-20"), response["channels"]) + cursor = None + + # Execute while the next_cursor is not empty. We need to iterate through the collection limiting to a max of 100 channels + # at a time. The cursor is used to keep track of the current position in the collection. This is due to Slack's pagination + # and the way it hanles retrieval of channels. + while True: + response = client.conversations_list( + exclude_archived=True, limit=100, types="public_channel", cursor=cursor ) + + # if we did not get a successful response, break out of the loop + if not response.get("ok"): + break + + # filter the channels to only include incident channels + for channel in response.get("channels", []): + if channel["name"].startswith("incident-20"): + channels.append(channel) + + # get the next cursor + cursor = response.get("response_metadata", {}).get("next_cursor") + + # if the cursor is empty, break out of the loop + if not cursor: + break + + # return the list of incident channels return channels diff --git a/app/tests/commands/test_utils.py b/app/tests/commands/test_utils.py index 7f8313c5..6582435e 100644 --- a/app/tests/commands/test_utils.py +++ b/app/tests/commands/test_utils.py @@ -15,6 +15,7 @@ def test_get_incident_channels(): "name": "incident-2022-channel", }, ], + "response_metadata": {"next_cursor": ""}, } assert utils.get_incident_channels(client) == [ { @@ -23,6 +24,41 @@ def test_get_incident_channels(): ] +# Test get_incident_channels with multiple pages of results +def test_get_incident_channels_with_multiple_pages(): + client = MagicMock() + + # Define mock responses + mock_response_page_1 = { + "ok": True, + "channels": [ + {"name": "incident-2021-alpha"}, + {"name": "general"}, + {"name": "incident-2020-beta"}, + ], + "response_metadata": {"next_cursor": "cursor123"}, + } + mock_response_page_2 = { + "ok": True, + "channels": [{"name": "random"}, {"name": "incident-2022-gamma"}], + "response_metadata": {"next_cursor": ""}, + } + + # Set the side_effect of the conversations_list method + client.conversations_list.side_effect = [mock_response_page_1, mock_response_page_2] + + # Call the function + result = utils.get_incident_channels(client) + + # Verify results + expected_channels = [ + {"name": "incident-2021-alpha"}, + {"name": "incident-2020-beta"}, + {"name": "incident-2022-gamma"}, + ] + assert result == expected_channels + + def test_get_messages_in_time_period(): client = MagicMock() client.conversations_history.return_value = {