Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 40 additions & 9 deletions src/sentry/api/endpoints/event_attachments.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from drf_spectacular.utils import OpenApiParameter, extend_schema
from rest_framework.request import Request
from rest_framework.response import Response

Expand All @@ -8,29 +9,59 @@
from sentry.api.bases.project import ProjectEndpoint
from sentry.api.paginator import OffsetPaginator
from sentry.api.serializers import serialize
from sentry.api.serializers.models.eventattachment import EventAttachmentSerializerResponse
from sentry.apidocs.constants import RESPONSE_FORBIDDEN, RESPONSE_NOT_FOUND, RESPONSE_UNAUTHORIZED
from sentry.apidocs.examples.event_attachment_examples import EventAttachmentExamples
from sentry.apidocs.parameters import CursorQueryParam, EventParams, GlobalParams
from sentry.apidocs.utils import inline_sentry_response_serializer
from sentry.models.eventattachment import EventAttachment, event_attachment_screenshot_filter
from sentry.search.utils import tokenize_query
from sentry.services import eventstore

EVENT_ATTACHMENTS_QUERY_PARAM = OpenApiParameter(
name="query",
location="query",
required=False,
type=str,
description=(
"Filter the attachments by name (substring match) or by attachment kind. "
"Use `is:screenshot` to restrict the results to screenshot attachments."
),
)


@extend_schema(tags=["Events"])
@cell_silo_endpoint
class EventAttachmentsEndpoint(ProjectEndpoint):
owner = ApiOwner.OWNERS_INGEST
publish_status = {
"GET": ApiPublishStatus.PRIVATE,
"GET": ApiPublishStatus.PUBLIC,
}

@extend_schema(
operation_id="List an Event's Attachments",
parameters=[
GlobalParams.ORG_ID_OR_SLUG,
GlobalParams.PROJECT_ID_OR_SLUG,
EventParams.EVENT_ID,
EVENT_ATTACHMENTS_QUERY_PARAM,
CursorQueryParam,
],
responses={
200: inline_sentry_response_serializer(
"ListEventAttachmentsResponse", list[EventAttachmentSerializerResponse]
),
401: RESPONSE_UNAUTHORIZED,
403: RESPONSE_FORBIDDEN,
404: RESPONSE_NOT_FOUND,
},
examples=EventAttachmentExamples.LIST_EVENT_ATTACHMENTS,
)
def get(self, request: Request, project, event_id) -> Response:
"""
Retrieve attachments for an event
`````````````````````````````````
Retrieve a list of attachments uploaded for a given event.

:pparam string organization_id_or_slug: the id or slug of the organization the
issues belong to.
:pparam string project_id_or_slug: the id or slug of the project the event
belongs to.
:pparam string event_id: the id of the event.
:auth: required
Requires the `event-attachments` organization feature.
"""
if not features.has(
"organizations:event-attachments", project.organization, actor=request.user
Expand Down
42 changes: 42 additions & 0 deletions tests/apidocs/endpoints/events/test_event_attachments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from django.test.client import RequestFactory
from django.urls import reverse

from fixtures.apidocs_test_case import APIDocsTestCase
from sentry.models.eventattachment import EventAttachment
from sentry.testutils.helpers.datetime import before_now


class ProjectEventAttachmentsDocs(APIDocsTestCase):
def setUp(self) -> None:
event = self.store_event(
data={"fingerprint": ["group1"], "timestamp": before_now(minutes=1).isoformat()},
project_id=self.project.id,
)
EventAttachment.objects.create(
project_id=event.project_id,
event_id=event.event_id,
type="event.attachment",
name="hello.png",
content_type="image/png",
size=18,
sha1="d3f299af02d6abbe92dd8368bab781824a9702ed",
blob_path=":File contents here",
)

self.url = reverse(
"sentry-api-0-event-attachments",
kwargs={
"organization_id_or_slug": self.project.organization.slug,
"project_id_or_slug": self.project.slug,
"event_id": event.event_id,
},
)

self.login_as(user=self.user)

def test_get(self) -> None:
with self.feature("organizations:event-attachments"):
response = self.client.get(self.url)
request = RequestFactory().get(self.url)

self.validate_schema(request, response)
Loading