diff --git a/CHANGELOG.md b/CHANGELOG.md index dfb8758c..a7562498 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Changed + +- Allow passing `null` as a value for `escalation_chain` when creating routes via the public API ([1557](https://github.com/grafana/oncall/pull/1557)) + ## v1.1.39 (2023-03-16) ### Added diff --git a/docs/sources/oncall-api-reference/routes.md b/docs/sources/oncall-api-reference/routes.md index 3ffa32e9..49dfc25a 100644 --- a/docs/sources/oncall-api-reference/routes.md +++ b/docs/sources/oncall-api-reference/routes.md @@ -51,7 +51,7 @@ Routes allow you to direct different alerts to different messenger channels and | Parameter | Unique | Required | Description | |-----------------------| :----: |:--------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `integration_id` | No | Yes | Each route is assigned to a specific integration. | -| `escalation_chain_id` | No | Yes | Each route is assigned a specific escalation chain. | +| `escalation_chain_id` | No | Yes | Each route is assigned a specific escalation chain. Explicitly pass `null` to create a route without an escalation chain assigned. | | `routing_type` | Yes | No | Routing type that can be either `jinja2` or `regex`(default value) | | `routing_regex` | Yes | Yes | Jinja2 template or Python Regex query (use for debugging). OnCall chooses the route for an alert in case there is a match inside the whole alert payload. | | `position` | Yes | Optional | Route matching is performed one after another starting from position=`0`. Position=`-1` will put the route to the end of the list before `is_the_last_route`. A new route created with a position of an existing route will move the old route (and all following routes) down in the list. | diff --git a/engine/apps/public_api/serializers/routes.py b/engine/apps/public_api/serializers/routes.py index abbc9f4f..07d2b398 100644 --- a/engine/apps/public_api/serializers/routes.py +++ b/engine/apps/public_api/serializers/routes.py @@ -155,6 +155,7 @@ class ChannelFilterSerializer(BaseChannelFilterSerializer): escalation_chain_id = OrganizationFilteredPrimaryKeyRelatedField( queryset=EscalationChain.objects, source="escalation_chain", + allow_null=True, ) is_the_last_route = serializers.BooleanField(read_only=True, source="is_default") diff --git a/engine/apps/public_api/tests/test_routes.py b/engine/apps/public_api/tests/test_routes.py index 5f0db22d..300a943a 100644 --- a/engine/apps/public_api/tests/test_routes.py +++ b/engine/apps/public_api/tests/test_routes.py @@ -162,6 +162,37 @@ def test_create_route( assert response.json() == expected_response +@pytest.mark.django_db +def test_create_route_without_escalation_chain(route_public_api_setup): + _, _, token, alert_receive_channel, escalation_chain, _ = route_public_api_setup + + client = APIClient() + url = reverse("api-public:routes-list") + + data = { + "integration_id": alert_receive_channel.public_primary_key, + "routing_regex": "testreg", + "escalation_chain_id": None, + } + response = client.post(url, format="json", HTTP_AUTHORIZATION=token, data=data) + + expected_response = { + "id": response.data["id"], + "integration_id": alert_receive_channel.public_primary_key, + "escalation_chain_id": None, + "routing_type": "regex", + "routing_regex": data["routing_regex"], + "position": 0, + "is_the_last_route": False, + "slack": {"channel_id": None, "enabled": True}, + "telegram": {"id": None, "enabled": False}, + TEST_MESSAGING_BACKEND_FIELD: {"id": None, "enabled": False}, + } + + assert response.status_code == status.HTTP_201_CREATED + assert response.json() == expected_response + + @pytest.mark.django_db def test_invalid_route_data( route_public_api_setup,