diff --git a/CHANGELOG.md b/CHANGELOG.md index 79fed934..4927aedb 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 + +### Added + +- Optimize alert and alert group public api endpoints and add filter by id ([1274](https://github.com/grafana/oncall/pull/1274) + ## v1.1.21 (2023-02-02) ### Added @@ -12,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add [`django-dbconn-retry` library](https://github.com/jdelic/django-dbconn-retry) to `INSTALLED_APPS` to attempt to alleviate occasional `django.db.utils.OperationalError` errors - Improve alerts and alert group endpoint response time in internal API with caching ([1261](https://github.com/grafana/oncall/pull/1261)) +- Optimize alert and alert group public api endpoints and add filter by id ([1274](https://github.com/grafana/oncall/pull/1274) - Added Coming Soon for iOS on Mobile App screen ### Fixed diff --git a/docs/sources/oncall-api-reference/alertgroups.md b/docs/sources/oncall-api-reference/alertgroups.md index 0d756a5a..5f5addf8 100644 --- a/docs/sources/oncall-api-reference/alertgroups.md +++ b/docs/sources/oncall-api-reference/alertgroups.md @@ -44,6 +44,7 @@ The above command returns JSON structured in the following way: These available filter parameters should be provided as `GET` arguments: +- `id` - `route_id` - `integration_id` - `state` diff --git a/docs/sources/oncall-api-reference/alerts.md b/docs/sources/oncall-api-reference/alerts.md index d67f8e14..ab4b6a3a 100644 --- a/docs/sources/oncall-api-reference/alerts.md +++ b/docs/sources/oncall-api-reference/alerts.md @@ -104,6 +104,7 @@ The above command returns JSON structured in the following way: The following available filter parameters should be provided as `GET` arguments: +- `id` - `alert_group_id` - `search`—string-based inclusion search by alert payload diff --git a/engine/apps/public_api/serializers/incidents.py b/engine/apps/public_api/serializers/incidents.py index 00ec64f6..8c1dd842 100644 --- a/engine/apps/public_api/serializers/incidents.py +++ b/engine/apps/public_api/serializers/incidents.py @@ -13,12 +13,11 @@ class IncidentSerializer(EagerLoadingMixin, serializers.ModelSerializer): route_id = serializers.SerializerMethodField() created_at = serializers.DateTimeField(source="started_at") alerts_count = serializers.SerializerMethodField() - title = serializers.SerializerMethodField() + title = serializers.CharField(source="web_title_cache") state = serializers.SerializerMethodField() - SELECT_RELATED = ["channel", "channel_filter", "slack_message"] + SELECT_RELATED = ["channel", "channel_filter", "slack_message", "channel__organization"] PREFETCH_RELATED = [ - "alerts", Prefetch( "telegram_messages", TelegramMessage.objects.filter(chat_id__startswith="-", message_type=TelegramMessage.ALERT_GROUP_MESSAGE), @@ -42,10 +41,8 @@ class IncidentSerializer(EagerLoadingMixin, serializers.ModelSerializer): ] def get_alerts_count(self, obj): - return len(obj.alerts.all()) - - def get_title(self, obj): - return obj.alerts.all()[0].title + # alerts_count is an annotated field added in get_queryset + return obj.alerts_count def get_state(self, obj): return obj.state diff --git a/engine/apps/public_api/views/alerts.py b/engine/apps/public_api/views/alerts.py index da332176..b4be1c73 100644 --- a/engine/apps/public_api/views/alerts.py +++ b/engine/apps/public_api/views/alerts.py @@ -1,5 +1,6 @@ from django.db.models import CharField from django.db.models.functions import Cast +from django_filters import rest_framework as filters from rest_framework import mixins from rest_framework.permissions import IsAuthenticated from rest_framework.viewsets import GenericViewSet @@ -12,6 +13,10 @@ from common.api_helpers.mixins import RateLimitHeadersMixin from common.api_helpers.paginators import FiftyPageSizePaginator +class AlertFilter(filters.FilterSet): + id = filters.CharFilter(field_name="public_primary_key") + + class AlertView(RateLimitHeadersMixin, mixins.ListModelMixin, GenericViewSet): authentication_classes = (ApiTokenAuthentication,) permission_classes = (IsAuthenticated,) @@ -22,6 +27,9 @@ class AlertView(RateLimitHeadersMixin, mixins.ListModelMixin, GenericViewSet): serializer_class = AlertSerializer pagination_class = FiftyPageSizePaginator + filter_backends = (filters.DjangoFilterBackend,) + filterset_class = AlertFilter + def get_queryset(self): alert_group_id = self.request.query_params.get("alert_group_id", None) search = self.request.query_params.get("search", None) diff --git a/engine/apps/public_api/views/incidents.py b/engine/apps/public_api/views/incidents.py index b771da28..dc70c15a 100644 --- a/engine/apps/public_api/views/incidents.py +++ b/engine/apps/public_api/views/incidents.py @@ -1,4 +1,4 @@ -from django.db.models import Q +from django.db.models import Count, Q from django_filters import rest_framework as filters from rest_framework import mixins, status from rest_framework.exceptions import NotFound @@ -29,6 +29,8 @@ class IncidentByTeamFilter(ByTeamModelFieldFilterMixin, filters.FilterSet): method=ByTeamModelFieldFilterMixin.filter_model_field_with_single_value.__name__, ) + id = filters.CharFilter(field_name="public_primary_key") + class IncidentView(RateLimitHeadersMixin, mixins.ListModelMixin, mixins.DestroyModelMixin, GenericViewSet): authentication_classes = (ApiTokenAuthentication,) @@ -77,7 +79,7 @@ class IncidentView(RateLimitHeadersMixin, mixins.ListModelMixin, mixins.DestroyM raise BadRequest(detail={"state": f"Must be one of the following: {valid_choices_text}"}) queryset = self.serializer_class.setup_eager_loading(queryset) - + queryset = queryset.annotate(alerts_count=Count("alerts")) return queryset def get_object(self):