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

feat(feedback): create deleted attachment activity for screenshots (#69878)

Fixes https://github.com/getsentry/sentry/issues/68907

Relates to https://github.com/getsentry/sentry/pull/69880 (frontend
changes)

---------

Co-authored-by: Ryan Albrecht <ryan.albrecht@sentry.io>
Andrew Liu 10 месяцев назад
Родитель
Сommit
badbd46746

+ 11 - 0
src/sentry/api/endpoints/event_attachment_details.py

@@ -13,8 +13,10 @@ from sentry.api.serializers import serialize
 from sentry.auth.superuser import superuser_has_permission
 from sentry.auth.system import is_system_auth
 from sentry.constants import ATTACHMENTS_ROLE_DEFAULT
+from sentry.models.activity import Activity
 from sentry.models.eventattachment import EventAttachment
 from sentry.models.organizationmember import OrganizationMember
+from sentry.types.activity import ActivityType
 
 
 class EventAttachmentDetailsPermission(ProjectPermission):
@@ -128,5 +130,14 @@ class EventAttachmentDetailsEndpoint(ProjectEndpoint):
         except EventAttachment.DoesNotExist:
             return self.respond({"detail": "Attachment not found"}, status=404)
 
+        # an activity with no group cannot be associated with an issue or displayed in an issue details page
+        if attachment.group_id is not None:
+            Activity.objects.create(
+                group_id=attachment.group_id,
+                project=project,
+                type=ActivityType.DELETED_ATTACHMENT.value,
+                user_id=request.user.id,
+                data={},
+            )
         attachment.delete()
         return self.respond(status=204)

+ 2 - 0
src/sentry/types/activity.py

@@ -31,6 +31,7 @@ class ActivityType(Enum):
     SET_ESCALATING = 25
 
     SET_PRIORITY = 26
+    DELETED_ATTACHMENT = 27
 
 
 # Warning: This must remain in this EXACT order.
@@ -63,5 +64,6 @@ CHOICES = tuple(
         ActivityType.AUTO_SET_ONGOING,  # 24
         ActivityType.SET_ESCALATING,  # 25
         ActivityType.SET_PRIORITY,  # 26
+        ActivityType.DELETED_ATTACHMENT,  # 27
     ]
 )

+ 33 - 1
tests/sentry/api/endpoints/test_event_attachment_details.py

@@ -1,12 +1,15 @@
+import pytest
 from django.test import override_settings
 
 from sentry.attachments.base import CachedAttachment
+from sentry.models.activity import Activity
 from sentry.models.eventattachment import EventAttachment
 from sentry.testutils.cases import APITestCase, PermissionTestCase
 from sentry.testutils.helpers.datetime import before_now, iso_format
 from sentry.testutils.helpers.features import with_feature
 from sentry.testutils.helpers.response import close_streaming_response
 from sentry.testutils.skips import requires_snuba
+from sentry.types.activity import ActivityType
 
 pytestmark = [requires_snuba]
 
@@ -14,7 +17,7 @@ ATTACHMENT_CONTENT = b"File contents here" * 10_000
 
 
 class CreateAttachmentMixin:
-    def create_attachment(self, content: bytes | None = None):
+    def create_attachment(self, content: bytes | None = None, group_id: int | None = None):
         self.project = self.create_project()
         self.release = self.create_release(self.project, self.user)
         min_ago = iso_format(before_now(minutes=1))
@@ -39,6 +42,7 @@ class CreateAttachmentMixin:
         self.attachment = EventAttachment.objects.create(
             event_id=self.event.event_id,
             project_id=self.event.project_id,
+            group_id=group_id,
             type=attachment.type,
             name=attachment.name,
             content_type=file.content_type,
@@ -138,6 +142,34 @@ class EventAttachmentDetailsTest(APITestCase, CreateAttachmentMixin):
         assert response.status_code == 204, response.content
         assert EventAttachment.objects.count() == 0
 
+    @with_feature("organizations:event-attachments")
+    def test_delete_activity_no_group(self):
+        self.login_as(user=self.user)
+
+        self.create_attachment(group_id=None)
+        path = f"/api/0/projects/{self.organization.slug}/{self.project.slug}/events/{self.event.event_id}/attachments/{self.attachment.id}/"
+        response = self.client.delete(path)
+        assert response.status_code == 204
+
+        # an activity with no group cannot be associated with an issue or displayed in an issue details page
+        with pytest.raises(Activity.DoesNotExist):
+            Activity.objects.get(type=ActivityType.DELETED_ATTACHMENT.value)
+
+    @with_feature("organizations:event-attachments")
+    def test_delete_activity_with_group(self):
+        self.login_as(user=self.user)
+
+        group_id = self.create_group().id
+        self.create_attachment(group_id=group_id)
+        path = f"/api/0/projects/{self.organization.slug}/{self.project.slug}/events/{self.event.event_id}/attachments/{self.attachment.id}/"
+        response = self.client.delete(path)
+        assert response.status_code == 204
+
+        delete_activity = Activity.objects.get(type=ActivityType.DELETED_ATTACHMENT.value)
+        assert delete_activity.project == self.project
+        assert delete_activity.group_id == group_id
+        assert delete_activity.group.id == group_id
+
 
 class EventAttachmentDetailsPermissionTest(PermissionTestCase, CreateAttachmentMixin):
     def setUp(self):