Skip to content

Commit

Permalink
Fix routes and schedules public api endpoints (#3751)
Browse files Browse the repository at this point in the history
# What this PR does
Add check whether organization has Slack connection on update Slack
related field using public api endpoints
## Which issue(s) this PR fixes
grafana/oncall-private#1611
## Checklist

- [x] Unit, integration, and e2e (if applicable) tests updated
- [x] 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)
  • Loading branch information
Ferril authored and iskhakov committed Feb 20, 2024
1 parent 64e6508 commit a93b2be
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed

- Fixed too frequent retry of `perform_notification` task on Telegram ratelimit error by @Ferril ([#3744](https://github.com/grafana/oncall/pull/3744))
- Add check whether organization has Slack connection on update Slack related field using public api endpoints
by @Ferril ([#3751](https://github.com/grafana/oncall/pull/3751))

## v1.3.92 (2024-01-23)

Expand Down
2 changes: 2 additions & 0 deletions engine/apps/public_api/serializers/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ def _validate_slack_channel_id(self, slack_channel_id):
slack_channel_id = slack_channel_id.upper()
organization = self.context["request"].auth.organization
slack_team_identity = organization.slack_team_identity
if not slack_team_identity:
raise BadRequest(detail="Slack isn't connected to this workspace")
try:
slack_team_identity.get_cached_channels().get(slack_id=slack_channel_id)
except SlackChannel.DoesNotExist:
Expand Down
3 changes: 3 additions & 0 deletions engine/apps/public_api/serializers/schedules_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ def validate_slack(self, slack_field):
organization = self.context["request"].auth.organization
slack_team_identity = organization.slack_team_identity

if (slack_channel_id or user_group_id) and not slack_team_identity:
raise BadRequest(detail="Slack isn't connected to this workspace")

if slack_channel_id is not None:
slack_channel_id = slack_channel_id.upper()
try:
Expand Down
44 changes: 44 additions & 0 deletions engine/apps/public_api/tests/test_integrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,50 @@ def test_update_integration_default_route(
assert response.data["default_route"]["escalation_chain_id"] == escalation_chain.public_primary_key


@pytest.mark.django_db
def test_create_integration_default_route_with_slack_field(
make_organization_and_user_with_token,
make_escalation_chain,
):
organization, _, token = make_organization_and_user_with_token()
escalation_chain = make_escalation_chain(organization)

client = APIClient()
data_for_create = {
"type": "grafana",
"name": "grafana_created",
"team_id": None,
"default_route": {
"escalation_chain_id": escalation_chain.public_primary_key,
"slack": {"channel_id": "TEST_SLACK_ID"},
},
}
url = reverse("api-public:integrations-list")
response = client.post(url, data=data_for_create, format="json", HTTP_AUTHORIZATION=f"{token}")
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.data["detail"] == "Slack isn't connected to this workspace"


@pytest.mark.django_db
def test_update_integration_default_route_with_slack_field(
make_organization_and_user_with_token, make_alert_receive_channel, make_channel_filter
):
organization, _, token = make_organization_and_user_with_token()
integration = make_alert_receive_channel(organization)
make_channel_filter(integration, is_default=True)

client = APIClient()
data_for_update = {
"default_route": {"slack": {"channel_id": "TEST_SLACK_ID"}},
}

url = reverse("api-public:integrations-detail", args=[integration.public_primary_key])
response = client.put(url, data=data_for_update, format="json", HTTP_AUTHORIZATION=f"{token}")

assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.data["detail"] == "Slack isn't connected to this workspace"


@pytest.mark.django_db
def test_cant_create_integrations_direct_paging(
make_organization_and_user_with_token, make_team, make_alert_receive_channel, make_user_auth_headers
Expand Down
46 changes: 46 additions & 0 deletions engine/apps/public_api/tests/test_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,52 @@ def test_delete_route(
new_channel_filter.refresh_from_db()


@pytest.mark.django_db
def test_create_route_slack_error(
route_public_api_setup,
):
_, _, token, alert_receive_channel, escalation_chain, _ = route_public_api_setup

client = APIClient()

url = reverse("api-public:routes-list")
data_for_create = {
"integration_id": alert_receive_channel.public_primary_key,
"routing_regex": "testreg",
"escalation_chain_id": escalation_chain.public_primary_key,
"slack": {"channel_id": "TEST_SLACK_ID"},
}
response = client.post(url, format="json", HTTP_AUTHORIZATION=token, data=data_for_create)

assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.data["detail"] == "Slack isn't connected to this workspace"


@pytest.mark.django_db
def test_update_route_slack_error(
route_public_api_setup,
make_channel_filter,
):
_, _, token, alert_receive_channel, escalation_chain, _ = route_public_api_setup
new_channel_filter = make_channel_filter(
alert_receive_channel,
is_default=False,
filtering_term="testreg",
)

client = APIClient()

url = reverse("api-public:routes-detail", kwargs={"pk": new_channel_filter.public_primary_key})
data_to_update = {
"slack": {"channel_id": "TEST_SLACK_ID"},
}

response = client.put(url, format="json", HTTP_AUTHORIZATION=token, data=data_to_update)

assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.data["detail"] == "Slack isn't connected to this workspace"


@pytest.mark.django_db
def test_create_route_with_messaging_backend(
route_public_api_setup,
Expand Down
59 changes: 59 additions & 0 deletions engine/apps/public_api/tests/test_schedules.py
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,65 @@ def test_create_schedule_invalid_timezone(make_organization_and_user_with_token,
assert response.json() == {"time_zone": ["Invalid timezone"]}


@pytest.mark.django_db
def test_create_calendar_schedule_slack_error(make_organization_and_user_with_token):
organization, user, token = make_organization_and_user_with_token()
client = APIClient()

url = reverse("api-public:schedules-list")
# with slack channel id
data = {
"team_id": None,
"name": "schedule test name",
"time_zone": "Europe/Moscow",
"type": "calendar",
"slack": {
"channel_id": "TEST_SLACK_ID",
},
}

response = client.post(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.data["detail"] == "Slack isn't connected to this workspace"
# with slack user group id
data = {
"team_id": None,
"name": "schedule test name",
"time_zone": "Europe/Moscow",
"type": "calendar",
"slack": {
"user_group_id": "TEST_SLACK_ID",
},
}

response = client.post(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.data["detail"] == "Slack isn't connected to this workspace"


@pytest.mark.django_db
def test_update_calendar_schedule_slack_error(
make_organization_and_user_with_token,
make_schedule,
):
organization, user, token = make_organization_and_user_with_token()
client = APIClient()
schedule = make_schedule(organization, schedule_class=OnCallScheduleCalendar)
url = reverse("api-public:schedules-detail", kwargs={"pk": schedule.public_primary_key})

data = {"slack": {"channel_id": "TEST_SLACK_ID"}}

response = client.put(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.data["detail"] == "Slack isn't connected to this workspace"

data = {"slack": {"user_group_id": "TEST_SLACK_ID"}}

response = client.put(url, data=data, format="json", HTTP_AUTHORIZATION=f"{token}")
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert response.data["detail"] == "Slack isn't connected to this workspace"


@pytest.mark.django_db
def test_create_ical_schedule_without_ical_url(make_organization_and_user_with_token):
_, _, token = make_organization_and_user_with_token()
Expand Down

0 comments on commit a93b2be

Please sign in to comment.