Просмотр исходного кода

feat(workflow): Add team & name filtering to incident history (#25952)

Scott Cooper 3 лет назад
Родитель
Сommit
461c09ff19

+ 13 - 42
src/sentry/incidents/endpoints/organization_alert_rule_index.py

@@ -15,13 +15,15 @@ from sentry.api.paginator import (
 )
 from sentry.api.serializers import serialize
 from sentry.api.serializers.models.alert_rule import CombinedRuleSerializer
-from sentry.auth.superuser import is_active_superuser
+from sentry.api.utils import InvalidParams
 from sentry.incidents.endpoints.serializers import AlertRuleSerializer
 from sentry.incidents.models import AlertRule, Incident
-from sentry.models import OrganizationMemberTeam, Project, Rule, RuleStatus, Team, TeamStatus
+from sentry.models import OrganizationMemberTeam, Project, Rule, RuleStatus, Team
 from sentry.snuba.dataset import Dataset
 from sentry.utils.cursors import Cursor, StringCursor
 
+from .utils import parse_team_params
+
 
 class OrganizationCombinedRuleIndexEndpoint(OrganizationEndpoint):
     def get(self, request, organization):
@@ -44,48 +46,17 @@ class OrganizationCombinedRuleIndexEndpoint(OrganizationEndpoint):
                 "id", flat=True
             )
 
-        teams = set(request.GET.getlist("team", []))
+        teams = request.GET.getlist("team", [])
         team_filter_query = None
-        if teams:
-            # do normal teams lookup based on request params
-            verified_ids = set()
-            unassigned = None
-            if "unassigned" in teams:
-                teams.remove("unassigned")
-                unassigned = Q(owner_id=None)
-
-            if "myteams" in teams:
-                teams.remove("myteams")
-                if is_active_superuser(request):
-                    # retrieve all teams within the organization
-                    myteams = Team.objects.filter(
-                        organization=organization, status=TeamStatus.VISIBLE
-                    ).values_list("id", flat=True)
-                    verified_ids.update(myteams)
-                else:
-                    myteams = [t.id for t in request.access.teams]
-                    verified_ids.update(myteams)
-
-            for team_id in teams:  # Verify each passed Team id is numeric
-                if type(team_id) is not int and not team_id.isdigit():
-                    return Response(
-                        f"Invalid Team ID: {team_id}", status=status.HTTP_400_BAD_REQUEST
-                    )
-            teams.update(verified_ids)
-
-            teams = Team.objects.filter(id__in=teams)
-            for team in teams:
-                if team.id in verified_ids:
-                    continue
-
-                if not request.access.has_team_access(team):
-                    return Response(
-                        f"Error: You do not have permission to access {team.name}",
-                        status=status.HTTP_400_BAD_REQUEST,
-                    )
-            team_filter_query = Q(owner_id__in=teams.values_list("actor_id", flat=True))
+        if len(teams) > 0:
+            try:
+                teams_query, unassigned = parse_team_params(request, organization, teams)
+            except InvalidParams as err:
+                return Response(str(err), status=status.HTTP_400_BAD_REQUEST)
+
+            team_filter_query = Q(owner_id__in=teams_query.values_list("actor_id", flat=True))
             if unassigned:
-                team_filter_query = team_filter_query | unassigned
+                team_filter_query = team_filter_query | Q(owner_id=None)
 
         alert_rules = AlertRule.objects.fetch_for_organization(organization, project_ids)
         if not features.has("organizations:performance-view", organization):

+ 26 - 0
src/sentry/incidents/endpoints/organization_incident_index.py

@@ -1,3 +1,7 @@
+from django.db.models import Q
+from rest_framework import status
+from rest_framework.response import Response
+
 from sentry import features
 from sentry.api.bases.incident import IncidentPermission
 from sentry.api.bases.organization import OrganizationEndpoint
@@ -5,6 +9,7 @@ from sentry.api.exceptions import ResourceDoesNotExist
 from sentry.api.paginator import OffsetPaginator
 from sentry.api.serializers import serialize
 from sentry.api.serializers.models.incident import IncidentSerializer
+from sentry.api.utils import InvalidParams
 from sentry.incidents.models import (
     AlertRuleActivity,
     AlertRuleActivityType,
@@ -13,6 +18,8 @@ from sentry.incidents.models import (
 )
 from sentry.snuba.dataset import Dataset
 
+from .utils import parse_team_params
+
 
 class OrganizationIncidentIndexEndpoint(OrganizationEndpoint):
     permission_classes = (IncidentPermission,)
@@ -36,6 +43,7 @@ class OrganizationIncidentIndexEndpoint(OrganizationEndpoint):
         if envs:
             incidents = incidents.filter(alert_rule__snuba_query__environment__in=envs)
 
+        title = request.GET.get("title", None)
         expand = request.GET.getlist("expand", [])
         query_alert_rule = request.GET.get("alertRule")
         query_include_snapshots = request.GET.get("includeSnapshots")
@@ -73,6 +81,24 @@ class OrganizationIncidentIndexEndpoint(OrganizationEndpoint):
             elif query_status == "closed":
                 incidents = incidents.filter(status=IncidentStatus.CLOSED.value)
 
+        teams = request.GET.getlist("team", [])
+        if len(teams) > 0:
+            try:
+                teams_query, unassigned = parse_team_params(request, organization, teams)
+            except InvalidParams as err:
+                return Response(str(err), status=status.HTTP_400_BAD_REQUEST)
+
+            team_filter_query = Q(
+                alert_rule__owner_id__in=teams_query.values_list("actor_id", flat=True)
+            )
+            if unassigned:
+                team_filter_query = team_filter_query | Q(alert_rule__owner_id=None)
+
+            incidents = incidents.filter(team_filter_query)
+
+        if title:
+            incidents = incidents.filter(Q(title__icontains=title))
+
         if not features.has("organizations:performance-view", organization):
             # Filter to only error alerts
             incidents = incidents.filter(alert_rule__snuba_query__dataset=Dataset.Events.value)

+ 42 - 0
src/sentry/incidents/endpoints/utils.py

@@ -0,0 +1,42 @@
+from sentry.api.utils import InvalidParams
+from sentry.auth.superuser import is_active_superuser
+from sentry.models import Team, TeamStatus
+
+
+def parse_team_params(request, organization, teams):
+    teams_set = set(teams)
+    # do normal teams lookup based on request params
+    verified_ids = set()
+    unassigned = False
+    if "unassigned" in teams_set:
+        teams_set.remove("unassigned")
+        unassigned = True
+
+    if "myteams" in teams_set:
+        teams_set.remove("myteams")
+        if is_active_superuser(request):
+            # retrieve all teams within the organization
+            myteams = Team.objects.filter(
+                organization=organization, status=TeamStatus.VISIBLE
+            ).values_list("id", flat=True)
+            verified_ids.update(myteams)
+        else:
+            myteams = [t.id for t in request.access.teams]
+            verified_ids.update(myteams)
+
+    for team_id in teams_set:  # Verify each passed Team id is numeric
+        if type(team_id) is not int and not team_id.isdigit():
+            raise InvalidParams(f"Invalid Team ID: {team_id}")
+    teams_set.update(verified_ids)
+
+    teams_query = Team.objects.filter(id__in=teams_set)
+    for team in teams_query:
+        if team.id in verified_ids:
+            continue
+
+        if not request.access.has_team_access(team):
+            raise InvalidParams(
+                f"Error: You do not have permission to access {team.name}",
+            )
+
+    return (teams_query, unassigned)

+ 57 - 0
tests/sentry/incidents/endpoints/test_organization_incident_index.py

@@ -126,3 +126,60 @@ class IncidentListEndpointTest(APITestCase):
         assert resp_all.data == serialize([new_incident, old_incident])
         assert resp_new.data == serialize([new_incident])
         assert resp_old.data == serialize([old_incident])
+
+    def test_filter_name(self):
+        self.create_team(organization=self.organization, members=[self.user])
+        incident = self.create_incident(title="yet another alert rule")
+        self.login_as(self.user)
+
+        with self.feature(["organizations:incidents", "organizations:performance-view"]):
+            results = self.get_valid_response(self.organization.slug, title="yet")
+            no_results = self.get_valid_response(self.organization.slug, title="no results")
+
+        assert len(results.data) == 1
+        assert len(no_results.data) == 0
+        assert results.data == serialize([incident])
+
+    def test_rule_teams(self):
+        team = self.create_team(organization=self.organization, members=[self.user])
+        alert_rule = self.create_alert_rule(
+            name="alert rule",
+            organization=self.organization,
+            projects=[self.project],
+            owner=team.actor.get_actor_tuple(),
+        )
+        other_team = self.create_team(organization=self.organization, members=[self.user])
+        other_alert_rule = self.create_alert_rule(
+            name="rule 2",
+            organization=self.organization,
+            projects=[self.project],
+            owner=other_team.actor.get_actor_tuple(),
+        )
+        unassigned_alert_rule = self.create_alert_rule(
+            name="rule 66",
+            organization=self.organization,
+            projects=[self.project],
+        )
+        self.create_incident(alert_rule=alert_rule)
+        self.create_incident(alert_rule=other_alert_rule)
+        self.create_incident(alert_rule=unassigned_alert_rule)
+        self.login_as(self.user)
+
+        with self.feature(["organizations:incidents", "organizations:performance-view"]):
+            results = self.get_valid_response(self.organization.slug, project=[self.project.id])
+        assert results.status_code == 200
+        assert len(results.data) == 3
+
+        with self.feature(["organizations:incidents", "organizations:performance-view"]):
+            results = self.get_valid_response(
+                self.organization.slug, project=[self.project.id], team=[team.id]
+            )
+        assert results.status_code == 200
+        assert len(results.data) == 1
+
+        with self.feature(["organizations:incidents", "organizations:performance-view"]):
+            results = self.get_valid_response(
+                self.organization.slug, project=[self.project.id], team=[team.id, other_team.id]
+            )
+        assert results.status_code == 200
+        assert len(results.data) == 2