Repository: getsentry/sentry

Issue:
Add rule status to response for individual rule and combined rules
Add the rule's `status` to the GET response for an individual rule and the combined rule endpoint (for this one, just do it for `Rule` objects and not `AlertRule` objects which don't have a `status` column) so that the front end can read and display it.


Discussion:

Resolving patch:
diff --git a/src/sentry/api/endpoints/project_rule_details.py b/src/sentry/api/endpoints/project_rule_details.py
--- a/src/sentry/api/endpoints/project_rule_details.py
+++ b/src/sentry/api/endpoints/project_rule_details.py
@@ -1,6 +1,5 @@
 from __future__ import annotations
 
-from django.db.models import Q
 from rest_framework import status
 from rest_framework.request import Request
 from rest_framework.response import Response
@@ -26,9 +25,7 @@
     SentryAppInstallation,
     prepare_ui_component,
 )
-from sentry.models.rulesnooze import RuleSnooze
 from sentry.rules.actions import trigger_sentry_app_action_creators_for_issues
-from sentry.services.hybrid_cloud.user.service import user_service
 from sentry.signals import alert_rule_edited
 from sentry.tasks.integrations.slack import find_channel_id_for_rule
 from sentry.web.decorators import transaction_start
@@ -90,22 +87,6 @@ def get(self, request: Request, project, rule) -> Response:
         if len(errors):
             serialized_rule["errors"] = errors
 
-        rule_snooze = RuleSnooze.objects.filter(
-            Q(user_id=request.user.id) | Q(user_id=None), rule=rule
-        )
-        if rule_snooze.exists():
-            serialized_rule["snooze"] = True
-            snooze = rule_snooze[0]
-            if request.user.id == snooze.owner_id:
-                created_by = "You"
-            else:
-                creator_name = user_service.get_user(snooze.owner_id).get_display_name()
-                created_by = creator_name
-            serialized_rule["snoozeCreatedBy"] = created_by
-            serialized_rule["snoozeForEveryone"] = snooze.user_id is None
-        else:
-            serialized_rule["snooze"] = False
-
         return Response(serialized_rule)
 
     @transaction_start("ProjectRuleDetailsEndpoint")
diff --git a/src/sentry/api/serializers/models/rule.py b/src/sentry/api/serializers/models/rule.py
--- a/src/sentry/api/serializers/models/rule.py
+++ b/src/sentry/api/serializers/models/rule.py
@@ -1,7 +1,7 @@
 from collections import defaultdict
 from typing import List
 
-from django.db.models import Max, prefetch_related_objects
+from django.db.models import Max, Q, prefetch_related_objects
 from rest_framework import serializers
 
 from sentry.api.serializers import Serializer, register
@@ -15,6 +15,7 @@
 )
 from sentry.models.actor import Actor
 from sentry.models.rulefirehistory import RuleFireHistory
+from sentry.models.rulesnooze import RuleSnooze
 from sentry.services.hybrid_cloud.user.service import user_service
 
 
@@ -174,7 +175,23 @@ def serialize(self, obj, attrs, user, **kwargs):
             "createdBy": attrs.get("created_by", None),
             "environment": environment.name if environment is not None else None,
             "projects": [obj.project.slug],
+            "status": obj.status,
         }
         if "last_triggered" in attrs:
             d["lastTriggered"] = attrs["last_triggered"]
+
+        rule_snooze = RuleSnooze.objects.filter(Q(user_id=user.id) | Q(user_id=None), rule=obj)
+        if rule_snooze.exists():
+            d["snooze"] = True
+            snooze = rule_snooze[0]
+            if user.id == snooze.owner_id:
+                created_by = "You"
+            else:
+                creator_name = user_service.get_user(snooze.owner_id).get_display_name()
+                created_by = creator_name
+            d["snoozeCreatedBy"] = created_by
+            d["snoozeForEveryone"] = snooze.user_id is None
+        else:
+            d["snooze"] = False
+
         return d


Test patch:
diff --git a/tests/sentry/api/endpoints/test_project_rule_details.py b/tests/sentry/api/endpoints/test_project_rule_details.py
--- a/tests/sentry/api/endpoints/test_project_rule_details.py
+++ b/tests/sentry/api/endpoints/test_project_rule_details.py
@@ -116,6 +116,7 @@ def test_with_environment(self):
         )
         assert response.data["id"] == str(self.rule.id)
         assert response.data["environment"] == self.environment.name
+        assert response.data["status"] == ObjectStatus.ACTIVE
 
     def test_with_filters(self):
         conditions: list[dict[str, Any]] = [
diff --git a/tests/sentry/api/serializers/test_alert_rule.py b/tests/sentry/api/serializers/test_alert_rule.py
--- a/tests/sentry/api/serializers/test_alert_rule.py
+++ b/tests/sentry/api/serializers/test_alert_rule.py
@@ -3,6 +3,7 @@
     CombinedRuleSerializer,
     DetailedAlertRuleSerializer,
 )
+from sentry.constants import ObjectStatus
 from sentry.incidents.logic import create_alert_rule_trigger
 from sentry.incidents.models import AlertRule, AlertRuleThresholdType
 from sentry.models import Rule
@@ -220,4 +221,6 @@ def test_combined_serializer(self):
 
         self.assert_alert_rule_serialized(alert_rule, result[0])
         assert result[1]["id"] == str(issue_rule.id)
+        assert result[1]["status"] == ObjectStatus.ACTIVE
+        assert not result[1]["snooze"]
         self.assert_alert_rule_serialized(other_alert_rule, result[2])