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

fix(alerts): Encode combined-rule string cursor (#33856)

Scott Cooper 2 лет назад
Родитель
Сommit
1808c18daf

+ 7 - 1
src/sentry/api/paginator.py

@@ -2,6 +2,7 @@ import bisect
 import functools
 import math
 from datetime import datetime
+from urllib.parse import quote, unquote
 
 from django.core.exceptions import ObjectDoesNotExist
 from django.db import connections
@@ -579,12 +580,15 @@ class CombinedQuerysetPaginator:
         return self.model_key_map.get(type(item))[0]
 
     def _prep_value(self, item, key, for_prev):
+        """
+        Formats values for use in the cursor
+        """
         value = getattr(item, key)
         value_type = type(value)
         if isinstance(value, float):
             return math.floor(value) if self._is_asc(for_prev) else math.ceil(value)
         elif value_type is str and self.case_insensitive:
-            return value.lower()
+            return quote(value.lower())
         return value
 
     def get_item_key(self, item, for_prev=False):
@@ -604,6 +608,8 @@ class CombinedQuerysetPaginator:
             value = cursor.value
             if isinstance(value, float):
                 return math.floor(value) if self._is_asc(cursor.is_prev) else math.ceil(value)
+            if isinstance(value, str):
+                return unquote(value)
             return value
 
     def _is_asc(self, is_prev):

+ 56 - 0
tests/sentry/incidents/endpoints/test_organization_alert_rule_index.py

@@ -480,6 +480,62 @@ class OrganizationCombinedRuleIndexEndpointTest(BaseAlertRuleSerializerTest, API
         assert result[0]["id"] == str(self.issue_rule.id)
         assert result[0]["type"] == "rule"
 
+    def test_limit_as_1_with_paging_sort_name_urlencode(self):
+        self.org = self.create_organization(owner=self.user, name="Rowdy Tiger")
+        self.team = self.create_team(
+            organization=self.org, name="Mariachi Band", members=[self.user]
+        )
+        self.project = self.create_project(organization=self.org, teams=[self.team], name="Bengal")
+        self.login_as(self.user)
+        alert_rule = self.create_alert_rule(
+            name="!1?",
+            organization=self.org,
+            projects=[self.project],
+            date_added=before_now(minutes=6).replace(tzinfo=pytz.UTC),
+            owner=self.team.actor.get_actor_tuple(),
+        )
+        alert_rule1 = self.create_alert_rule(
+            name="!1?zz",
+            organization=self.org,
+            projects=[self.project],
+            date_added=before_now(minutes=6).replace(tzinfo=pytz.UTC),
+            owner=self.team.actor.get_actor_tuple(),
+        )
+
+        # Test Limit as 1, no cursor:
+        url = f"/api/0/organizations/{self.org.slug}/combined-rules/"
+        with self.feature(["organizations:incidents", "organizations:performance-view"]):
+            request_data = {"per_page": "1", "project": self.project.id, "sort": "name", "asc": 1}
+            response = self.client.get(
+                path=url,
+                data=request_data,
+                content_type="application/json",
+            )
+        assert response.status_code == 200, response.content
+        result = json.loads(response.content)
+        assert len(result) == 1
+        self.assert_alert_rule_serialized(alert_rule, result[0], skip_dates=True)
+        links = requests.utils.parse_header_links(
+            response.get("link").rstrip(">").replace(">,<", ",<")
+        )
+        next_cursor = links[1]["cursor"]
+        # Cursor should have the title encoded
+        assert next_cursor == "%211%3Fzz:0:0"
+
+        with self.feature(["organizations:incidents", "organizations:performance-view"]):
+            request_data = {
+                "cursor": next_cursor,
+                "per_page": "1",
+                "project": self.project.id,
+                "sort": "name",
+                "asc": 1,
+            }
+            response = self.client.get(path=url, data=request_data, content_type="application/json")
+        assert response.status_code == 200
+        result = json.loads(response.content)
+        assert len(result) == 1
+        assert result[0]["id"] == str(alert_rule1.id)
+
     def test_limit_as_1_with_paging(self):
         self.setup_project_and_rules()