Skip to content

Commit cf949ac

Browse files
authored
Revert "Revert slack org does not exist changes breaking escalate command (#2057)" (#2096)
# What this PR does Closes grafana/oncall-private#1836 - Revert "Revert slack org does not exist changes breaking escalate command (#2057)" + add some unit tests to ensure we don't break the `/escalate` command in the future - cleanup how we destructure the `payload` dict in the endpoint handler ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [ ] Documentation added (or `pr:no public docs` PR label added if not required) - [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not required)
1 parent f1a8cd2 commit cf949ac

File tree

3 files changed

+312
-122
lines changed

3 files changed

+312
-122
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Allow mobile app to consume "internal" schedules API endpoints by @joeyorlando ([#2109](https://github.com/grafana/oncall/pull/2109))
1313

14+
### Fixed
15+
16+
- Fix + revert [#2057](https://github.com/grafana/oncall/pull/2057) which reverted a change which properly handles
17+
`Organization.DoesNotExist` exceptions for Slack events by @joeyorlando ([#TBD](https://github.com/grafana/oncall/pull/TBD))
18+
1419
## v1.2.39 (2023-06-06)
1520

1621
### Changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import json
2+
from unittest.mock import call, patch
3+
4+
import pytest
5+
from django.conf import settings
6+
from rest_framework import status
7+
from rest_framework.test import APIClient
8+
9+
from apps.slack.scenarios.scenario_step import PAYLOAD_TYPE_BLOCK_ACTIONS
10+
11+
EVENT_TRIGGER_ID = "5333959822612.4122782784722.4734ff484b2ac4d36a185bb242ee9932"
12+
WARNING_TEXT = (
13+
"OnCall is not able to process this action because one of the following scenarios: \n"
14+
"1. The Slack chatops integration was disconnected from the instance that the Alert Group belongs "
15+
"to, BUT the Slack workspace is still connected to another instance as well. In this case, simply log "
16+
"in to the OnCall web interface and re-install the Slack Integration with this workspace again.\n"
17+
"2. (Less likely) The Grafana instance belonging to this Alert Group was deleted. In this case the Alert Group is orphaned and cannot be acted upon."
18+
)
19+
20+
SLACK_TEAM_ID = "T043LP0P2M8"
21+
SLACK_ACCESS_TOKEN = "asdfasdf"
22+
SLACK_BOT_ACCESS_TOKEN = "cmncvmnvcnm"
23+
SLACK_BOT_USER_ID = "mncvnmvcmnvcmncv,,cx,"
24+
25+
SLACK_USER_ID = "iurtiurituritu"
26+
27+
28+
def _make_request(payload):
29+
return APIClient().post(
30+
"/slack/interactive_api_endpoint/",
31+
format="json",
32+
data=payload,
33+
**{
34+
"HTTP_X_SLACK_SIGNATURE": "asdfasdf",
35+
"HTTP_X_SLACK_REQUEST_TIMESTAMP": "xxcxcvx",
36+
},
37+
)
38+
39+
40+
@pytest.fixture
41+
def slack_team_identity(make_slack_team_identity):
42+
return make_slack_team_identity(
43+
slack_id=SLACK_TEAM_ID,
44+
detected_token_revoked=None,
45+
access_token=SLACK_ACCESS_TOKEN,
46+
bot_access_token=SLACK_BOT_ACCESS_TOKEN,
47+
bot_user_id=SLACK_BOT_USER_ID,
48+
)
49+
50+
51+
@patch("apps.slack.views.SlackEventApiEndpointView.verify_signature", return_value=True)
52+
@patch("apps.slack.views.SlackEventApiEndpointView._open_warning_window_if_needed")
53+
@pytest.mark.django_db
54+
def test_organization_not_found_scenario_properly_handled(
55+
mock_open_warning_window_if_needed,
56+
_mock_verify_signature,
57+
make_organization,
58+
make_slack_user_identity,
59+
slack_team_identity,
60+
):
61+
# SCENARIO 1
62+
# two orgs connected to same slack workspace, the one belonging to the alert group/slack message
63+
# is no longer connected to the slack workspace, but another org still is
64+
make_slack_user_identity(slack_team_identity=slack_team_identity, slack_id=SLACK_USER_ID)
65+
66+
make_organization(slack_team_identity=slack_team_identity)
67+
org2 = make_organization()
68+
event_payload_actions = [
69+
{
70+
"value": json.dumps({"organization_id": org2.id}),
71+
}
72+
]
73+
74+
event_payload = {
75+
"type": PAYLOAD_TYPE_BLOCK_ACTIONS,
76+
"trigger_id": EVENT_TRIGGER_ID,
77+
"user": {
78+
"id": SLACK_USER_ID,
79+
},
80+
"team": {
81+
"id": SLACK_TEAM_ID,
82+
},
83+
"actions": event_payload_actions,
84+
}
85+
86+
response = _make_request(event_payload)
87+
assert response.status_code == status.HTTP_200_OK
88+
89+
# SCENARIO 2
90+
# the org that was associated w/ the alert group, has since been deleted
91+
# and the slack message is now orphaned
92+
org2.hard_delete()
93+
94+
response = _make_request(event_payload)
95+
assert response.status_code == status.HTTP_200_OK
96+
97+
mock_call = call(event_payload, slack_team_identity, WARNING_TEXT)
98+
mock_open_warning_window_if_needed.assert_has_calls([mock_call, mock_call])
99+
100+
101+
@patch("apps.slack.views.SlackEventApiEndpointView.verify_signature", return_value=True)
102+
@patch("apps.slack.views.SlackEventApiEndpointView._open_warning_window_if_needed")
103+
@pytest.mark.django_db
104+
def test_organization_not_found_scenario_doesnt_break_slash_commands(
105+
mock_open_warning_window_if_needed,
106+
_mock_verify_signature,
107+
make_organization,
108+
make_slack_user_identity,
109+
slack_team_identity,
110+
):
111+
112+
make_organization(slack_team_identity=slack_team_identity)
113+
make_slack_user_identity(slack_team_identity=slack_team_identity, slack_id=SLACK_USER_ID)
114+
115+
response = _make_request(
116+
{
117+
"token": "axvnc,mvc,mv,mcvmnxcmnxc",
118+
"team_id": SLACK_TEAM_ID,
119+
"team_domain": "testingtest-nim4013",
120+
"channel_id": "C043HQ70QMB",
121+
"channel_name": "testy-testing",
122+
"user_id": "U043HQ3VABF",
123+
"user_name": "bob.smith",
124+
"command": settings.SLACK_DIRECT_PAGING_SLASH_COMMAND,
125+
"text": "potato",
126+
"api_app_id": "A0909234092340293402934234234234234234",
127+
"is_enterprise_install": "false",
128+
"response_url": "https://hooks.slack.com/commands/cvcv/cvcv/cvcv",
129+
"trigger_id": "asdfasdf.4122782784722.cvcv",
130+
}
131+
)
132+
133+
assert response.status_code == status.HTTP_200_OK
134+
mock_open_warning_window_if_needed.assert_not_called()

0 commit comments

Comments
 (0)