diff --git a/src/sentry/api/urls.py b/src/sentry/api/urls.py index 84cc6c793f0e86..211694e0c95b68 100644 --- a/src/sentry/api/urls.py +++ b/src/sentry/api/urls.py @@ -377,6 +377,9 @@ from sentry.uptime.endpoints.organiation_uptime_alert_index import ( OrganizationUptimeAlertIndexEndpoint, ) +from sentry.uptime.endpoints.organization_uptime_alert_index_count import ( + OrganizationUptimeAlertIndexCountEndpoint, +) from sentry.uptime.endpoints.organization_uptime_stats import OrganizationUptimeStatsEndpoint from sentry.uptime.endpoints.project_uptime_alert_checks_index import ( ProjectUptimeAlertCheckIndexEndpoint, @@ -2335,6 +2338,11 @@ def create_group_urls(name_prefix: str) -> list[URLPattern | URLResolver]: OrganizationUptimeAlertIndexEndpoint.as_view(), name="sentry-api-0-organization-uptime-alert-index", ), + re_path( + r"^(?P[^\/]+)/uptime-count/$", + OrganizationUptimeAlertIndexCountEndpoint.as_view(), + name="sentry-api-0-organization-uptime-alert-index-count", + ), re_path( r"^(?P[^\/]+)/uptime-stats/$", OrganizationUptimeStatsEndpoint.as_view(), diff --git a/src/sentry/monitors/endpoints/organization_monitor_index_count.py b/src/sentry/monitors/endpoints/organization_monitor_index_count.py index 4b964edf1621ba..56522a69769d93 100644 --- a/src/sentry/monitors/endpoints/organization_monitor_index_count.py +++ b/src/sentry/monitors/endpoints/organization_monitor_index_count.py @@ -29,7 +29,15 @@ def get(self, request: AuthenticatedHttpRequest, organization: Organization) -> try: filter_params = self.get_filter_params(request, organization, date_filter_optional=True) except NoProjects: - return self.respond([]) + return self.respond( + { + "counts": { + "total": 0, + "active": 0, + "disabled": 0, + }, + } + ) queryset = Monitor.objects.filter( organization_id=organization.id, project_id__in=filter_params["project_id"] diff --git a/src/sentry/uptime/endpoints/organization_uptime_alert_index_count.py b/src/sentry/uptime/endpoints/organization_uptime_alert_index_count.py new file mode 100644 index 00000000000000..e6ece15e7ddd89 --- /dev/null +++ b/src/sentry/uptime/endpoints/organization_uptime_alert_index_count.py @@ -0,0 +1,61 @@ +from drf_spectacular.utils import extend_schema +from rest_framework.response import Response + +from sentry.api.api_owners import ApiOwner +from sentry.api.api_publish_status import ApiPublishStatus +from sentry.api.base import region_silo_endpoint +from sentry.api.bases import NoProjects +from sentry.api.bases.organization import OrganizationEndpoint, OrganizationPermission +from sentry.models.organization import Organization +from sentry.uptime.types import GROUP_TYPE_UPTIME_DOMAIN_CHECK_FAILURE +from sentry.utils.auth import AuthenticatedHttpRequest +from sentry.workflow_engine.models import Detector + + +@region_silo_endpoint +@extend_schema(tags=["Uptime Monitors"]) +class OrganizationUptimeAlertIndexCountEndpoint(OrganizationEndpoint): + publish_status = { + "GET": ApiPublishStatus.PRIVATE, + } + owner = ApiOwner.CRONS + permission_classes = (OrganizationPermission,) + + def get(self, request: AuthenticatedHttpRequest, organization: Organization) -> Response: + """ + Retrieves the count of uptime monitors for an organization. + """ + try: + filter_params = self.get_filter_params(request, organization, date_filter_optional=True) + except NoProjects: + return self.respond( + { + "counts": { + "total": 0, + "active": 0, + "disabled": 0, + }, + } + ) + + queryset = Detector.objects.filter( + type=GROUP_TYPE_UPTIME_DOMAIN_CHECK_FAILURE, + project__organization_id=organization.id, + project_id__in=filter_params["project_id"], + ) + + if "environment" in filter_params: + queryset = queryset.filter(config__environment__in=filter_params["environment"]) + + enabled_uptime_alerts_count = queryset.filter(enabled=True).count() + disabled_uptime_alerts_count = queryset.filter(enabled=False).count() + + return self.respond( + { + "counts": { + "total": enabled_uptime_alerts_count + disabled_uptime_alerts_count, + "active": enabled_uptime_alerts_count, + "disabled": disabled_uptime_alerts_count, + }, + } + ) diff --git a/tests/sentry/uptime/endpoints/test_organization_uptime_alert_index_count.py b/tests/sentry/uptime/endpoints/test_organization_uptime_alert_index_count.py new file mode 100644 index 00000000000000..96f8adbadcb1c5 --- /dev/null +++ b/tests/sentry/uptime/endpoints/test_organization_uptime_alert_index_count.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from sentry.uptime.types import GROUP_TYPE_UPTIME_DOMAIN_CHECK_FAILURE +from tests.sentry.uptime.endpoints import UptimeAlertBaseEndpointTest + + +class OrganizationUptimeAlertCountTest(UptimeAlertBaseEndpointTest): + endpoint = "sentry-api-0-organization-uptime-alert-index-count" + + def setUp(self): + super().setUp() + self.login_as(self.user) + + def test_simple(self): + self.create_detector( + name="Active Alert 1", + type=GROUP_TYPE_UPTIME_DOMAIN_CHECK_FAILURE, + enabled=True, + config={"environment": self.environment.name, "mode": 1}, + ) + self.create_detector( + name="Active Alert 2", + type=GROUP_TYPE_UPTIME_DOMAIN_CHECK_FAILURE, + enabled=True, + config={"environment": self.environment.name, "mode": 1}, + ) + self.create_detector( + name="Disabled Alert", + type=GROUP_TYPE_UPTIME_DOMAIN_CHECK_FAILURE, + enabled=False, + config={"environment": self.environment.name, "mode": 1}, + ) + + response = self.get_success_response(self.organization.slug) + + assert response.data == { + "counts": { + "total": 3, + "active": 2, + "disabled": 1, + }, + } + + def test_filtered_by_environment(self): + env1 = self.create_environment(name="production") + env2 = self.create_environment(name="staging") + + self.create_detector( + name="Alert 1", + type=GROUP_TYPE_UPTIME_DOMAIN_CHECK_FAILURE, + enabled=True, + config={"environment": env1.name, "mode": 1}, + ) + self.create_detector( + name="Alert 2", + type=GROUP_TYPE_UPTIME_DOMAIN_CHECK_FAILURE, + enabled=True, + config={"environment": env2.name, "mode": 1}, + ) + self.create_detector( + name="Alert 3", + type=GROUP_TYPE_UPTIME_DOMAIN_CHECK_FAILURE, + enabled=False, + config={"environment": env1.name, "mode": 1}, + ) + + response = self.get_success_response(self.organization.slug, environment=["production"]) + + assert response.data == { + "counts": { + "total": 2, + "active": 1, + "disabled": 1, + }, + } + + response = self.get_success_response(self.organization.slug, environment=["staging"]) + + assert response.data == { + "counts": { + "total": 1, + "active": 1, + "disabled": 0, + }, + }