Fix routes and schedules public api endpoints (#3751)

# 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
https://github.com/grafana/oncall-private/issues/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)
This commit is contained in:
Yulya Artyukhina 2024-01-25 13:52:55 +01:00 committed by GitHub
parent 21f0e2db89
commit e18dafa650
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 156 additions and 0 deletions

View file

@ -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)

View file

@ -86,6 +86,8 @@ class BaseChannelFilterSerializer(OrderedModelSerializer):
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:

View file

@ -45,6 +45,9 @@ class ScheduleBaseSerializer(serializers.ModelSerializer):
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:

View file

@ -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

View file

@ -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,

View file

@ -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()