diff --git a/engine/apps/alerts/migrations/0008_alter_alertgrouplogrecord_type.py b/engine/apps/alerts/migrations/0008_alter_alertgrouplogrecord_type.py new file mode 100644 index 00000000..f805f599 --- /dev/null +++ b/engine/apps/alerts/migrations/0008_alter_alertgrouplogrecord_type.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.16 on 2023-01-19 18:06 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('alerts', '0007_populate_web_title_cache'), + ] + + operations = [ + migrations.AlterField( + model_name='alertgrouplogrecord', + name='type', + field=models.IntegerField(choices=[(0, 'Acknowledged'), (1, 'Unacknowledged'), (2, 'Invite'), (3, 'Stop invitation'), (4, 'Re-invite'), (5, 'Escalation triggered'), (6, 'Invitation triggered'), (16, 'Escalation finished'), (7, 'Silenced'), (15, 'Unsilenced'), (8, 'Attached'), (9, 'Unattached'), (10, 'Custom button triggered'), (11, 'Unacknowledged by timeout'), (12, 'Failed attachment'), (13, 'Incident resolved'), (14, 'Incident unresolved'), (17, 'Escalation failed'), (18, 'Acknowledge reminder triggered'), (19, 'Wiped'), (20, 'Deleted'), (21, 'Incident registered'), (22, 'A route is assigned to the incident'), (23, 'Trigger direct paging escalation'), (24, 'Unpage a user')]), + ), + ] diff --git a/engine/apps/api/serializers/paging.py b/engine/apps/api/serializers/paging.py index 99631618..452f4eb4 100644 --- a/engine/apps/api/serializers/paging.py +++ b/engine/apps/api/serializers/paging.py @@ -40,6 +40,9 @@ class DirectPagingSerializer(serializers.Serializer): users = UserReferenceSerializer(many=True, required=False, default=list) schedules = ScheduleReferenceSerializer(many=True, required=False, default=list) + escalation_chain_id = serializers.CharField(required=False, default=None) + escalation_chain = serializers.HiddenField(default=None) # set in DirectPagingSerializer.validate + alert_group_id = serializers.CharField(required=False, default=None) alert_group = serializers.HiddenField(default=None) # set in DirectPagingSerializer.validate @@ -47,19 +50,37 @@ class DirectPagingSerializer(serializers.Serializer): message = serializers.CharField(required=False, default=None) def validate(self, attrs): - if len(attrs["users"]) == 0 and len(attrs["schedules"]) == 0: - raise serializers.ValidationError("Provide at least one user or schedule") + organization = self.context["organization"] - if attrs["alert_group_id"] and (attrs["title"] or attrs["message"]): + users = attrs["users"] + schedules = attrs["schedules"] + escalation_chain_id = attrs["escalation_chain_id"] + + alert_group_id = attrs["alert_group_id"] + title = attrs["title"] + message = attrs["message"] + + if len(users) == 0 and len(schedules) == 0 and not escalation_chain_id: + raise serializers.ValidationError("Provide users, schedules, or an escalation chain") + + if alert_group_id and (title or message): raise serializers.ValidationError("alert_group_id and (title, message) are mutually exclusive") - if attrs["alert_group_id"]: - organization = self.context["organization"] + if alert_group_id and escalation_chain_id: + raise serializers.ValidationError("escalation_chain_id is not supported for existing alert groups") + + if alert_group_id: try: attrs["alert_group"] = AlertGroup.unarchived_objects.get( - public_primary_key=attrs["alert_group_id"], channel__organization=organization + public_primary_key=alert_group_id, channel__organization=organization ) except ObjectDoesNotExist: - raise serializers.ValidationError("Alert group {} does not exist".format(attrs["alert_group_id"])) + raise serializers.ValidationError("Alert group {} does not exist".format(alert_group_id)) + + if escalation_chain_id: + try: + attrs["escalation_chain"] = organization.escalation_chains.get(public_primary_key=escalation_chain_id) + except ObjectDoesNotExist: + raise serializers.ValidationError("Escalation chain {} does not exist".format(escalation_chain_id)) return attrs diff --git a/engine/apps/api/tests/test_paging.py b/engine/apps/api/tests/test_paging.py index a76f5c60..33b66c09 100644 --- a/engine/apps/api/tests/test_paging.py +++ b/engine/apps/api/tests/test_paging.py @@ -9,7 +9,11 @@ from apps.schedules.models import OnCallScheduleCalendar, OnCallScheduleICal @pytest.mark.django_db def test_direct_paging_new_alert_group( - make_organization_and_user_with_plugin_token, make_user, make_schedule, make_user_auth_headers + make_organization_and_user_with_plugin_token, + make_user, + make_schedule, + make_escalation_chain, + make_user_auth_headers, ): organization, user, token = make_organization_and_user_with_plugin_token(role=LegacyAccessControlRole.EDITOR) @@ -32,6 +36,8 @@ def test_direct_paging_new_alert_group( }, ] + escalation_chain_to_page = make_escalation_chain(organization) + title = "Test Alert Group" message = "Testing direct paging with new alert group" @@ -40,7 +46,13 @@ def test_direct_paging_new_alert_group( response = client.post( url, - data={"users": users_to_page, "schedules": schedules_to_page, "title": title, "message": message}, + data={ + "users": users_to_page, + "schedules": schedules_to_page, + "escalation_chain_id": escalation_chain_to_page.public_primary_key, + "title": title, + "message": message, + }, format="json", **make_user_auth_headers(user, token), ) @@ -94,6 +106,38 @@ def test_direct_paging_existing_alert_group( assert response.status_code == status.HTTP_200_OK +@pytest.mark.django_db +def test_direct_paging_existing_alert_group_and_escalation_chain( + make_organization_and_user_with_plugin_token, + make_user, + make_schedule, + make_escalation_chain, + make_alert_receive_channel, + make_alert_group, + make_user_auth_headers, +): + organization, user, token = make_organization_and_user_with_plugin_token(role=LegacyAccessControlRole.EDITOR) + escalation_chain_to_page = make_escalation_chain(organization) + + alert_receive_channel = make_alert_receive_channel(organization) + alert_group = make_alert_group(alert_receive_channel) + + client = APIClient() + url = reverse("api-internal:direct_paging") + + response = client.post( + url, + data={ + "escalation_chain_id": escalation_chain_to_page.public_primary_key, + "alert_group_id": alert_group.public_primary_key, + }, + format="json", + **make_user_auth_headers(user, token), + ) + + assert response.status_code == status.HTTP_400_BAD_REQUEST + + @pytest.mark.django_db def test_direct_paging_no_title( make_organization_and_user_with_plugin_token, diff --git a/engine/apps/api/views/paging.py b/engine/apps/api/views/paging.py index f1e07d67..b0fcfd1d 100644 --- a/engine/apps/api/views/paging.py +++ b/engine/apps/api/views/paging.py @@ -38,6 +38,7 @@ class DirectPagingAPIView(APIView): message=serializer.validated_data["message"], users=users, schedules=schedules, + escalation_chain=serializer.validated_data["escalation_chain"], alert_group=serializer.validated_data["alert_group"], )